From: Date: July 3 2009 2:26pm Subject: bzr commit into mysql-5.4 branch (guilhem:2814) List-Archive: http://lists.mysql.com/commits/77943 Message-Id: <20090703122732.98D241C01@guilhem-laptop> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3573626575237685878==" --===============3573626575237685878== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/mysql_src/bzrrepos/mysql-azalea-guilhem/ based on revid:alik@stripped 2814 Guilhem Bichot 2009-07-03 [merge] merge of Summit into Azalea (merging the result of Mikael's summit->azalea merge, into the latest azalea). removed: config/ac-macros/dtrace.m4 sql/probes.d added: config/ac-macros/dtrace.m4 include/atomic/solaris.h include/probes_mysql.d.base include/probes_mysql.h include/probes_mysql_nodtrace.h scripts/dheadgen.pl storage/innobase/win_atomics32_test.c storage/innobase/win_atomics64_test.c support-files/dtrace/ support-files/dtrace/locktime.d support-files/dtrace/query-execandqc.d support-files/dtrace/query-filesort-time.d support-files/dtrace/query-network-time.d support-files/dtrace/query-parse-time.d support-files/dtrace/query-rowops.d support-files/dtrace/query-time.d support-files/dtrace/statement-time.d support-files/dtrace/statement-type-aggregate.d modified: .bzr-mysql/default.conf BUILD/build_mccge.sh BUILD/check-cpu configure.in include/Makefile.am include/atomic/nolock.h include/atomic/x86-gcc.h include/my_atomic.h libmysql/Makefile.shared libmysqld/Makefile.am mysql-test/include/default_mysqld.cnf mysql-test/r/innodb.result mysql-test/r/merge.result mysql-test/r/partition_innodb.result mysql-test/suite/sys_vars/r/innodb_autoextend_increment_basic.result mysql-test/suite/sys_vars/r/innodb_file_io_threads_basic.result mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result mysql-test/suite/sys_vars/r/innodb_thread_concurrency_basic.result mysql-test/suite/sys_vars/r/table_definition_cache_basic.result mysql-test/suite/sys_vars/r/table_open_cache_basic.result mysql-test/suite/sys_vars/t/innodb_file_io_threads_basic.test mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test mysql-test/suite/sys_vars/t/innodb_thread_concurrency_basic.test mysql-test/suite/sys_vars/t/table_definition_cache_basic.test mysql-test/suite/sys_vars/t/table_open_cache_basic.test mysql-test/t/merge.test mysql-test/t/partition_innodb.test mysys/Makefile.am mysys/mf_keycache.c scripts/Makefile.am scripts/make_binary_distribution.sh sql/Makefile.am sql/filesort.cc sql/ha_ndbcluster.cc sql/handler.cc sql/mysql_priv.h sql/mysqld.cc sql/net_serv.cc sql/sp_head.cc sql/sql_cache.cc sql/sql_class.h sql/sql_connect.cc sql/sql_cursor.cc sql/sql_insert.cc sql/sql_parse.cc sql/sql_prepare.cc sql/sql_select.cc sql/sql_update.cc storage/archive/Makefile.am storage/archive/ha_archive.cc storage/blackhole/Makefile.am storage/blackhole/ha_blackhole.cc storage/csv/Makefile.am storage/csv/ha_tina.cc storage/example/Makefile.am storage/example/ha_example.cc storage/federated/Makefile.am storage/federated/ha_federated.cc storage/federated/ha_federated.h storage/heap/Makefile.am storage/heap/ha_heap.cc storage/innobase/CMakeLists.txt storage/innobase/Makefile.am storage/innobase/btr/btr0cur.c storage/innobase/btr/btr0sea.c storage/innobase/buf/buf0buf.c storage/innobase/handler/ha_innodb.cc storage/innobase/include/buf0buf.ic storage/innobase/include/log0log.h storage/innobase/include/os0file.h storage/innobase/include/os0sync.h storage/innobase/include/os0sync.ic storage/innobase/include/srv0srv.h storage/innobase/include/sync0rw.h storage/innobase/include/sync0rw.ic storage/innobase/include/sync0sync.h storage/innobase/include/sync0sync.ic storage/innobase/include/univ.i storage/innobase/include/ut0ut.h storage/innobase/log/log0log.c storage/innobase/mem/mem0pool.c storage/innobase/os/os0file.c storage/innobase/row/row0sel.c storage/innobase/srv/srv0srv.c storage/innobase/srv/srv0start.c storage/innobase/sync/sync0arr.c storage/innobase/sync/sync0rw.c storage/innobase/sync/sync0sync.c storage/innobase/ut/ut0ut.c storage/myisam/Makefile.am storage/myisam/ha_myisam.cc storage/myisammrg/Makefile.am storage/myisammrg/ha_myisammrg.cc storage/ndb/include/portlib/prefetch.h support-files/Makefile.am support-files/my-innodb-heavy-4G.cnf.sh win/README win/configure.js === modified file '.bzr-mysql/default.conf' --- a/.bzr-mysql/default.conf 2009-06-25 14:37:27 +0000 +++ b/.bzr-mysql/default.conf 2009-07-02 14:23:36 +0000 @@ -2,4 +2,4 @@ tree_location = "bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-azalea" post_commit_to = "commits@stripped" post_push_to = "commits@stripped" -tree_name = "mysql-5.4" +tree_name = "mysql-5.4" === modified file 'BUILD/build_mccge.sh' --- a/BUILD/build_mccge.sh 2009-05-25 22:01:59 +0000 +++ b/BUILD/build_mccge.sh 2009-07-02 14:23:36 +0000 @@ -63,10 +63,12 @@ sysadmin_usage() cat < 32-bit binary - x86_64 => 64 bit binary unless Mac OS X + --compiler=[gcc|icc|forte|SunStudio] Select compiler + --cpu=[x86|x86_64|sparc|itanium] Select CPU type + x86 => x86 and 32-bit binary + x86_64 => x86 and 64 bit binary --warning-mode=[extra|pedantic|normal|no] Set warning mode level --warnings Set warning mode to normal --32 Build a 32-bit binary even if CPU is 64-bit @@ -170,8 +179,9 @@ Usage: $0 [options] --error-inject Enable error injection into MySQL Server and data nodes --valgrind Build with valgrind - --fast Optimise for CPU architecture buildt on + --fast Optimise for CPU architecture built on --static-linking Statically link system libraries into binaries + --use-tcmalloc Link with tcmalloc instead of standard malloc (Linux only) --with-flags * Pass extra --with-xxx options to configure EOF if test "x$1" != "x" ; then @@ -186,13 +196,14 @@ extended_usage() Extended help text for this script: ----------------------------------- This script is intended to make it easier for customers using MySQL - Cluster Carrier Grade Edition to build the product from source on - these platforms/compilers: Linux/x86 (32-bit and 64-bit), - Solaris 10 and 11/x86/gcc, Solaris 9/Sparc/Forte, and MacOSX/x86/gcc. - The script automatically detects CPU type and operating system; in - most cases this also determines which compiler to use, the exception - being Linux/x86 where you can choose between gcc and icc (gcc is the - default). + Cluster Carrier Grade Edition, customers using performance-optimised + MySQL versions and developers to build the product from source on + these platforms/compilers: Linux/x86 (32-bit and 64-bit) (either using + gcc or icc), Linux Itanium, Solaris 8,9,10 and 11 x86 and SPARC using + gcc or SunStudio and MacOSX/x86/gcc. + + The script automatically detects CPU type and operating system; The + default compiler is always gcc. To build on other platforms you can use the --print-only option on a supported platform and edit the output for a proper set of commands on @@ -213,7 +224,7 @@ extended_usage() --package=cge storage engines: - ARCHIVE, BLACKHOLE, CSV, EXAMPLE, FEDERATED, MYISAM, NDB + ARCHIVE, BLACKHOLE, CSV, FEDERATED, MYISAM, NDB (All storage engines except InnoDB) comment: MySQL Cluster Carrier Grade Edition GPL/Commercial version built from source @@ -221,7 +232,7 @@ extended_usage() --package=extended storage engines: - ARCHIVE, BLACKHOLE, CSV, EXAMPLE, FEDERATED, MYISAM, INNODB, NDB + ARCHIVE, BLACKHOLE, CSV, FEDERATED, MYISAM, INNODB, NDB (All storage engines) comment: MySQL Cluster Carrier Grade Extended Edition GPL/Commercial version built from source @@ -229,7 +240,7 @@ extended_usage() --package=pro storage engines: - ARCHIVE, BLACKHOLE, CSV, EXAMPLE, FEDERATED, INNODB, MYISAM + ARCHIVE, BLACKHOLE, CSV, FEDERATED, INNODB, MYISAM (All storage engines except NDB) comment: MySQL Pro GPL/Commercial version built from source @@ -296,6 +307,10 @@ extended_usage() --with-pic: Build all binaries using position independent assembler to avoid problems with dynamic linkers (cannot be overridden). + --without-example-engine: Ensure that the example engine isn't built, + it cannot do any useful things, it's merely intended as documentation. + (cannot be overridden) + --with-csv-storage-engine: Ensure that the CSV storage engine is included in all builds. Since CSV is required for log tables in MySQL 5.1, this option cannot be overridden. @@ -314,10 +329,6 @@ extended_usage() In addition there are some configure options that are specific to Linux operating systems: - --with-fast-mutexes - Include an alternative implementation of mutexes that is faster on - Linux systems - --enable-assembler Include assembler code optimisations for a number of mostly string methods. Used for x86 processors only. @@ -364,18 +375,25 @@ extended_usage() --with-mysqld-libs=-lmtmalloc Used on Solaris to ensure that the proper malloc library is used. + Investigations have shown mtmalloc to be the best choice on Solaris, + also umem has good performance on Solaris but better debugging + capabilities. Compiler options: ----------------- This section describes the compiler options for each of the different - platforms supported by thisscript. + platforms supported by this script. The --fast option adds -mtune=cpu_arg to the C/C++ flags (provides support for Nocona, K8, and other processors). Use of the --debug option adds -g to the C/C++ flags. + In all cases it is possible to override the definition of CC and CXX + by calling the script as follows: + CC="/usr/local/bin/gcc" CXX="/usr/local/bin/gcc" BUILD/build_mccge.sh + FreeBSD/x86/gcc --------------- No flags are used. Instead, configure determines the proper flags to @@ -383,8 +401,7 @@ extended_usage() Linux/x86+Itanium/gcc ------------- - No flags are used. Instead the configure script determines the - proper flags to use for both normal and debug builds. Discovery of a + For debug builds -O is used and otherwise -O3 is used.Discovery of a Nocona or Core 2 Duo CPU causes a 64-bit binary to be built; otherwise, the binary is 32-bit. To build a 64-bit binary, -m64 is added to the C/C++ flags. (To build a 32-bit binary on a 64-bit CPU, @@ -393,11 +410,11 @@ extended_usage() Linux/x86+Itanium/icc ------------- Flags used: - CC = icc -static-libgcc -static-libcxa -i-static - C++ = icpc -static-libgcc -static-libcxa -i-static + CC = icc -static-libgcc -static-intel + C++ = icpc -static-libgcc -static-intel C/C++ flags = -mp -restrict - On Itanium we also add -no-ftz and -no-prefetch to CC and C++ flags. + On Itanium we also add -no-ftz and to CC and C++ flags. The non-debug versions also add the following: C/C++ flags += -O3 unroll2 -ip @@ -411,20 +428,60 @@ extended_usage() Solaris/x86/gcc --------------- - All builds on Solaris are 64-bit, so -m64 is always used in the - C/C++ flags. LDFLAGS is set to -m64 -static-libgcc -O/-O2. + All builds on Solaris are by default 64-bit, so -m64 is always used in + the C/C++ flags. LDFLAGS is set to -m64 -O/-O2/-O3. If for + some reason a 32-bit Solaris is used it is necessary to add the flag + --32 to the script invocation. Due to bugs in compiling with -O3 on + Solaris only -O2 is used by default, when --fast flag is used -O3 will + be used instead. + + Sets -m64 (default) or -m32 (if specifically set) in LDFLAGS and + C/C++ flags. Solaris/Sparc/Forte ------------------- - Uses cc-5.0 as CC - Sets ASFLAGS=LDFLAGS=xarch=v9, so that we compile Sparc v9 binaries - C flags = -Xa -strconst -xc99=none - C++ flags = -noex - C/C++ flags = -mt -D_FORTEC -xarch=v9 + Uses cc as CC and CC as CXX + Note that SunStudio uses different binaries for C and C++ compilers. - For non-debug builds, the following flags are also used: + Set -m64 (default) or -m32 (if specifically set) in ASFLAGS, + LDFLAGS and C/C++ flags. - C/C++ flags = -xO3 + Sets ASFLAGS=LDFLAGS=compiler flags=xarch=sparc, so that we compile + Sparc v9 binaries, also -mt is set in all those since we're always + building a multithreaded program. + + C flags = -xstrconst + C++ flags = -noex + + Set the following C/C++ flags: + -fsimple=1 + -ftrap=%none + -nofstore This flag is set only on x86 + -xbuiltin=%all + -xlibmil + -xlibmopt + + Set the C++ flag: + -noex + + When compiling with fast we set: + C/C++ flags: -xtarget=native -xunroll=3 -xipo + LDFLAGS: -xipo + + When not compiling with fast we always set -xtarget=generic + + When compiling with fast on SPARC we also set: + C/C++ flags: -xbinopt=prepare + LDFLAGS: -xbinopt=prepare + + When compiling with fast on x86 we also set: + C/C++ flags: -xregs=frameptr + + The optimisation level is + -xO Debug builds + -xO2 Production build on SPARC + -xO3 Production build on x86 + -xO4 Fast builds on SPARC/x86 MacOSX/x86/gcc -------------- @@ -433,6 +490,10 @@ extended_usage() Non-debug versions also add -Os -felide-constructors, where "-Os" means the build is space-optimised as long as the space optimisations do not negatively affect performance. Debug versions use -O. + + Mac OS X builds will always be 32-bit by default, when --64 is added + the build will be 64 bit instead. Thus the flag --m64 is added only + when specifically given as an option. EOF } with_usage() @@ -537,11 +598,15 @@ parse_cpu_type() case "$cpu_type" in x86 ) cpu_type="x86" - m32="yes" + if test "x$m64" != "x" ; then + m64="no" + fi ;; x86_64 ) cpu_type="x86" - m64="yes" + if test "x$m64" != "x" ; then + m64="yes" + fi ;; itanium ) cpu_type="itanium" @@ -572,6 +637,9 @@ parse_compiler() forte ) compiler="forte" ;; + SunStudio | sunstudio ) + compiler="forte" + ;; *) echo "Unknown compiler '$compiler'" exit 1 @@ -601,6 +669,9 @@ parse_options() fast_flag="generic" fi ;; + --use-tcmalloc) + use_tcmalloc="yes" + ;; --with-debug) with_debug_flag="yes" fast_flag="no" @@ -636,17 +707,19 @@ parse_options() warning_mode="normal" ;; --32) - if test "x$m64" != "x" ; then + if test "x$explicit_size_set" != "x" ; then echo "Cannot set both --32 and --64" exit 1 fi - m32="yes" + explicit_size_set="yes" + m64="no" ;; --64) - if test "x$m32" != "x" ; then + if test "x$explicit_size_set" != "x" ; then echo "Cannot set both --32 and --64" exit 1 fi + explicit_size_set="yes" m64="yes" ;; --package=*) @@ -750,7 +823,7 @@ set_cpu_base() if test "x$cpu_type" = "x" ; then if test "x$cpu_arg" = "x" ; then usage "CPU type not discovered, cannot proceed" - return 1 + exit 1 fi case "$cpu_arg" in core2 | nocona | prescott | pentium* | i*86 ) @@ -775,18 +848,20 @@ set_cpu_base() check_cpu_cflags="" fi if test "x$os" = "xMacOSX" ; then - m64="no" + if test "x$m64" = "x" ; then + m64="no" + fi elif test "x$os" = "xSolaris" ; then - m64="yes" - elif test "x$m32" = "x" ; then + if test "x$m64" = "x" ; then + m64="yes" + fi + elif test "x$m64" = "x" ; then if test "x$cpu_arg" = "xnocona" || test "x$cpu_arg" = "xcore2" || \ test "x$cpu_arg" = "xathlon64" || test "x$cpu_arg" = "xopteron" ; then m64="yes" - elif test "x$m64" != "xyes" ; then + else m64="no" fi - else - m64="no" fi echo "Discovered CPU of type $cpu_base_type ($cpu_arg) on $os" if test "x$m64" = "xyes" ; then @@ -806,18 +881,15 @@ init_configure_commands() cxxflags="$cxx_warnings $base_cxxflags $compiler_flags" configure="./configure $base_configs $with_flags" - commands="$commands - CC=\"$CC\" CFLAGS=\"$cflags\" CXX=\"$CXX\" CXXFLAGS=\"$cxxflags\"" + flags="CC=\"$CC\" CFLAGS=\"$cflags\" CXX=\"$CXX\" CXXFLAGS=\"$cxxflags\"" if test "x$LDFLAGS" != "x" ; then - commands="$commands - LDFLAGS=\"$LDFLAGS\"" + flags="$flags LDFLAGS=\"$LDFLAGS\"" fi if test "x$ASFLAGS" != "x" ; then - commands="$commands - ASFLAGS=\"$ASFLAGS\"" + flags="$flags ASFLAGS=\"$ASFLAGS\"" fi commands="$commands - $configure" + $flags $configure" } # @@ -920,7 +992,7 @@ set_libtoolize_version() # We do not use ccache when gcov is used. Also only when # gcc is used. # -set_up_ccache() +set_ccache_usage() { if test "x$compiler" = "xgcc" ; then if ccache -V > /dev/null 2>&1 && test "$USING_GCOV" != "1" @@ -993,7 +1065,7 @@ set_with_debug_flags() if test "x$with_debug_flag" = "xyes" ; then if test "x$developer_flag" = "xyes" ; then loc_debug_flags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS " - loc_debug_flags="$loc_debug_cflags -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC" + loc_debug_flags="$loc_debug_flags -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC" compiler_flags="$compiler_flags $loc_debug_flags" fi fi @@ -1046,7 +1118,7 @@ set_base_configs() base_configs="$base_configs --enable-local-infile" base_configs="$base_configs --enable-thread-safe-client" base_configs="$base_configs --with-big-tables" - base_configs="$base_configs --with-extra-charsets=all" + base_configs="$base_configs --with-extra-charsets=complex" base_configs="$base_configs --with-ssl" base_configs="$base_configs --with-pic" base_configs="$base_configs --with-csv-storage-engine" @@ -1059,17 +1131,27 @@ set_base_configs() # set_base_engines() { - engine_configs="$engine_configs --with-archive-storage-engine" + engine_configs="--with-archive-storage-engine" engine_configs="$engine_configs --with-blackhole-storage-engine" - engine_configs="$engine_configs --with-example-storage-engine" + engine_configs="$engine_configs --without-example-storage-engine" engine_configs="$engine_configs --with-federated-storage-engine" engine_configs="$engine_configs --with-partition" + base_configs="$base_configs $engine_configs" } -set_pro_package() +set_innodb_engine() { - base_configs="$base_configs $engine_configs" base_configs="$base_configs --with-innodb" +} + +set_ndb_engine() +{ + base_configs="$base_configs --with-ndbcluster" + base_configs="$base_configs --without-ndb-debug" +} + +set_pro_package() +{ base_configs="$base_configs --with-comment=\"MySQL Pro $version_text built from source\"" if test "x$with_debug_flag" = "xyes" ; then base_configs="$base_configs --with-server-suffix=\"-debug\"" @@ -1081,10 +1163,6 @@ set_cge_extended_package() if test "x$gpl" = "xno" ; then echo "Cannot build Extended Carrier Grade Edition as Commercial version" fi - base_configs="$base_configs --with-ndbcluster" - base_configs="$base_configs --without-ndb-debug" - base_configs="$base_configs $engine_configs" - base_configs="$base_configs --with-innodb" base_configs="$base_configs --with-comment=\"MySQL Cluster Carrier Grade Extended Edition $version_text built from source\"" if test "x$with_debug_flag" = "xyes" ; then base_configs="$base_configs --with-server-suffix=\"-cge-extended-debug\"" @@ -1095,9 +1173,6 @@ set_cge_extended_package() set_cge_package() { - base_configs="$base_configs --with-ndbcluster" - base_configs="$base_configs --without-ndb-debug" - base_configs="$base_configs $engine_configs" base_configs="$base_configs --with-comment=\"MySQL Cluster Carrier Grade Edition $version_text built from source\"" if test "x$with_debug_flag" = "xyes" ; then base_configs="$base_configs --with-server-suffix=\"-cge-debug\"" @@ -1139,6 +1214,36 @@ set_gcc_special_options() fi } +set_cc_and_cxx_for_gcc() +{ + if test "x$CC" = "x" ; then + CC="gcc -static-libgcc" + fi + if test "x$CXX" = "x" ; then + CXX="gcc -static-libgcc" + fi +} + +set_cc_and_cxx_for_icc() +{ + if test "x$CC" = "x" ; then + CC="icc -static-intel -static-libgcc" + fi + if test "x$CXX" = "x" ; then + CXX="icpc -static-intel -static-libgcc" + fi +} + +set_cc_and_cxx_for_forte() +{ + if test "x$CC" = "x" ; then + CC="cc" + fi + if test "x$CXX" = "x" ; then + CXX="CC" + fi +} + # # If we discover a Core 2 Duo architecture and we have enabled the fast # flag, we enable a compile especially optimised for Core 2 Duo. This @@ -1166,8 +1271,12 @@ set_bsd_configs() exit 1 fi base_configs="$base_configs --enable-assembler" - CC="gcc" - CXX="gcc" + if test "x$fast_flag" != "xno" ; then + compiler_flags="$compiler_flags -O3" + else + compiler_flags="$compiler_flags -O" + fi + set_cc_and_cxx_for_gcc } # @@ -1177,24 +1286,31 @@ set_linux_configs() { if test "x$cpu_base_type" != "xx86" && \ test "x$cpu_base_type" != "xitanium" ; then - usage "Only x86 and Itanium CPUs supported for 32-bit Linux" + usage "Only x86 and Itanium CPUs supported for Linux" exit 1 fi - base_configs="$base_configs --with-fast-mutexes" + if test "x$use_tcmalloc" = "xyes" ; then + base_configs="$base_configs --with-mysqld-libs=-ltcmalloc_minimal" + fi if test "x$cpu_base_type" = "xx86" ; then base_configs="$base_configs --enable-assembler" fi if test "x$compiler" = "xgcc" ; then - CC="gcc" - CXX="gcc" + set_cc_and_cxx_for_gcc if test "x$m64" = "xyes" ; then compiler_flags="$compiler_flags -m64" + else + compiler_flags="$compiler_flags -m32" + fi + if test "x$fast_flag" != "xno" ; then + compiler_flags="$compiler_flags -O2" + else + compiler_flags="$compiler_flags -O" fi # configure will set proper compiler flags for gcc on Linux elif test "x$compiler" = "xicc" ; then compiler_flags="$compiler_flags -mp -restrict" - CC="icc -static-intel" - CXX="icpc -static-intel" + set_cc_and_cxx_for_icc if test "x$cpu_base_type" = "xitanium" ; then compiler_flags="$compiler_flags -no-ftz" fi @@ -1215,53 +1331,99 @@ set_linux_configs() # set_solaris_configs() { +# Use mtmalloc as malloc, see Tim Cook blog base_configs="$base_configs --with-mysqld-libs=-lmtmalloc" + base_configs="$base_configs --with-named-curses=-lcurses" case "`uname -a`" in - *5.10*|*5.11*) + *5.8* | *5.9* | *5.10* | *5.11*) + ;; *) - die "Only versions 10 and 11 supported for Solaris" + usage "Only versions 8,9, 10 and 11 supported for Solaris" + exit 1 esac if test "x$cpu_base_type" != "xx86" && \ test "x$cpu_base_type" != "xsparc" ; then usage "Only x86 and Sparc CPUs supported for Solaris" exit 1 fi + if test "x$compiler" != "xgcc" && \ + test "x$compiler" != "xforte" ; then + usage "Only gcc and Forte compilers supported for Solaris" + exit 1 + fi + if test "x$m64" = "xyes" ; then + compiler_flags="$compiler_flags -m64" + LDFLAGS="-m64" + ASFLAGS="$ASFLAGS -m64" + else + compiler_flags="$compiler_flags -m32" + LDFLAGS="-m32" + ASFLAGS="$ASFLAGS -m32" + fi if test "x$compiler" = "xgcc" ; then - CC="gcc" - CXX="gcc" + set_cc_and_cxx_for_gcc if test "x$cpu_base_type" != "xx86" ; then - usage "Only gcc supported for Solaris 10/11 on SPARC" + usage "gcc currently not supported for Solaris on SPARC" + exit 1 fi - compiler_flags="$compiler_flags -m64 -DMY_ATOMIC_MODE_RWLOCKS" - LDFLAGS="-m64 -static-libgcc" - if test "x$fast_flag" != "xno" ; then - LDFLAGS="$LDFLAGS -O2" - compiler_flags="$compiler_flags -O2" + if test "x$fast_flag" = "xyes" ; then + LDFLAGS="$LDFLAGS -O3" + compiler_flags="$compiler_flags -O3" else - LDFLAGS="$LDFLAGS -O" - compiler_flags="$compiler_flags -O" - fi - elif test "x$compiler" = "xforte" ; then - if test "x$cpu_base_type" = "xx86" ; then - usage "Only gcc supported for Solaris/x86" - fi - if test "x$cpu_base_type" != "xsparc" ; then - usage "Forte compiler supported for Solaris 9/SPARC only" + if test "x$fast_flag" = "xgeneric" ; then + LDFLAGS="$LDFLAGS -O2" + compiler_flags="$compiler_flags -O2" + else + LDFLAGS="$LDFLAGS -O" + compiler_flags="$compiler_flags -O" + fi fi - CC="cc-5.0" - CXX=CC - ASFLAGS="xarch=v9" - LDFLAGS="xarch=v9" - base_cflags="$base_cflags -Xa -xstrconst -xc99=none" + else +#Using Forte compiler (SunStudio) + set_cc_and_cxx_for_forte + base_cflags="$base_cflags -xstrconst" + compiler_flags="$compiler_flags -mt" + LD_FLAGS="$LD_FLAGS -mt" + compiler_flags="$compiler_flags -fsimple=1" + compiler_flags="$compiler_flags -ftrap=%none" + compiler_flags="$compiler_flags -xbuiltin=%all" + compiler_flags="$compiler_flags -xlibmil" + compiler_flags="$compiler_flags -xlibmopt" base_cxxflags="$base_cxxflags -noex" - compiler_flags="$compiler_flags -mt -D_FORTEC -xarch=v9" - if test "x$fast_flag" != "xno" ; then - compiler_flags="$compiler_flags -xO3" + if test "x$fast_flag" = "xyes" ; then + compiler_flags="$compiler_flags -xtarget=native" + compiler_flags="$compiler_flags -xipo" + compiler_flags="$compiler_flags -xunroll=3" + LD_FLAGS="$LD_FLAGS -xipo" + else + compiler_flags="$compiler_flags -xtarget=generic" + fi + if test "x$cpu_base_type" = "xx86" ; then + compiler_flags="$compiler_flags -nofstore" + if test "x$fast_flag" = "xyes" ; then + compiler_flags="$compiler_flags -xregs=frameptr" + compiler_flags="$compiler_flags -xO4" + elif test "x$fast_flag" = "xgeneric" ; then + compiler_flags="$compiler_flags -xO2" + else + compiler_flags="$compiler_flags -xO" + fi + else +#Using SPARC cpu with SunStudio (Forte) compiler + ASFLAGS="$ASFLAGS -xarch=sparc" + LDFLAGS="$LDFLAGS -xarch=sparc" + compiler_flags="$compiler_flags -xarch=sparc" + if test "x$fast_flag" = "xyes" ; then + compiler_flags="$compiler_flags -xbinopt=prepare" + LDFLAGS="$LDFLAGS -xbinopt=prepare" + compiler_flags="$compiler_flags -xO4" + elif test "x$fast_flag" = "xgeneric" ; then + compiler_flags="$compiler_flags -xO2" + else + compiler_flags="$compiler_flags -xO" + fi fi - else - usage "Only gcc and Forte compilers supported for Solaris" - exit 1 fi } @@ -1270,10 +1432,7 @@ set_solaris_configs() # set_macosx_configs() { - base_cxxflags="$base_cxxflags -fno-common" - if test "x$cpu_base_type" = "xx86" && test "x$compiler" = "xgcc" ; then - compiler_flags="$compiler_flags -arch i386" - else + if test "x$cpu_base_type" != "xx86" || test "x$compiler" != "xgcc" ; then usage "Only gcc/x86 supported for Mac OS X" exit 1 fi @@ -1281,14 +1440,21 @@ set_macosx_configs() # Optimize for space as long as it doesn't affect performance, use some # optimisations also when not in fast mode. # + base_cxxflags="$base_cxxflags -felide-constructors" + base_cxxflags="$base_cxxflags -fno-common" + if test "x$m64" = "xyes" ; then + compiler_flags="$compiler_flags -m64" + compiler_flags="$compiler_flags -arch x86_64" + else + compiler_flags="$compiler_flags -m32" + compiler_flags="$compiler_flags -arch i386" + fi if test "x$fast_flag" != "xno" ; then compiler_flags="$compiler_flags -Os" - base_cxxflags="$base_cxxflags -felide-constructors" else compiler_flags="$compiler_flags -O" fi - CC="gcc" - CXX="gcc" + set_cc_and_cxx_for_gcc } # @@ -1397,11 +1563,15 @@ base_cxxflags= base_configs= debug_flags= cxxflags= -m32= m64= +explicit_size_set= datadir= commands= use_autotools= +engine_configs= +ASFLAGS= +LDFLAGS= +use_tcmalloc= set_defaults_based_on_environment @@ -1418,7 +1588,14 @@ set -e # This call sets the cpu_arg and check_cpu_args parameters # path=`dirname $0` +if test "x$compiler" = "xgcc" ; then + compiler= +fi . "$path/check-cpu" +if test "x$compiler" = "x" ; then + compiler="gcc" +fi +check_os set_cpu_base if test "x$?" = "x1" ; then exit 1 @@ -1446,17 +1623,23 @@ set_icc_special_options # including all storage engines except InnoDB, and to use GPL libraries. # set_base_configs -set_base_engines if test "x$gpl" = "xyes" ; then version_text="GPL version" else version_text="Commercial version" fi if test "x$package" = "xpro" ; then + set_base_engines + set_innodb_engine set_pro_package elif test "x$package" = "xextended" ; then + set_base_engines + set_ndb_engine + set_innodb_engine set_cge_extended_package elif test "x$package" = "xcge" ; then + set_base_engines + set_ndb_engine set_cge_package elif test "x$package" = "xclassic" ; then set_classic_package @@ -1472,7 +1655,6 @@ set_error_inject_configs # operating systems, and processors. # -check_os if test "x$os" = "xlinux" ; then set_linux_configs elif test "x$os" = "xSolaris" ; then @@ -1490,7 +1672,7 @@ fi # proper libtoolize versions, and to determine whether to use ccache. # set_make_version -set_up_ccache +set_ccache_usage # # Set up commands variable from variables prepared for base === modified file 'BUILD/check-cpu' --- a/BUILD/check-cpu 2008-08-18 17:33:00 +0000 +++ b/BUILD/check-cpu 2009-02-03 12:09:35 +0000 @@ -16,6 +16,9 @@ check_cpu () { # on Linux (and others?) we can get detailed CPU information out of /proc cpuinfo="cat $CPUINFO" + # detect CPU architecture + cpu_arch=`$cpuinfo | grep 'arch' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` + # detect CPU family cpu_family=`$cpuinfo | grep 'family' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` if test -z "$cpu_family" ; then @@ -51,8 +54,8 @@ check_cpu () { model_name=`machine` ;; *) - cpu_family=`uname -m`; - model_name=`uname -p`; + cpu_family=`uname -p`; + model_name=`uname -m`; ;; esac fi @@ -60,7 +63,7 @@ check_cpu () { # detect CPU shortname as used by gcc options # this list is not complete, feel free to add further entries cpu_arg="" - case "$cpu_family--$model_name" in + case "$cpu_family--$model_name--$spu_arch" in # DEC Alpha Alpha*EV6*) cpu_arg="ev6"; @@ -137,8 +140,11 @@ check_cpu () { *Itanium*) cpu_arg="itanium" ;; + *IA-64*) + cpu_arg="itanium" + ;; # Solaris Sparc - *sparc*sun4u*) + *sparc*sun4[uv]*) cpu_arg="sparc" ;; # Power PC @@ -175,67 +181,69 @@ check_cpu () { cc=$CC fi - cc_ver=`$cc --version | sed 1q` - cc_verno=`echo $cc_ver | sed -e 's/^.*(GCC)//g; s/[^0-9. ]//g; s/^ *//g; s/ .*//g'` - set -- `echo $cc_verno | tr '.' ' '` - cc_major=$1 - cc_minor=$2 - cc_patch=$3 - cc_comp=`expr $cc_major '*' 100 '+' $cc_minor` + if test "x$compiler" = "x" ; then + cc_ver=`$cc --version | sed 1q` + cc_verno=`echo $cc_ver | sed -e 's/^.*(GCC)//g; s/[^0-9. ]//g; s/^ *//g; s/ .*//g'` + set -- `echo $cc_verno | tr '.' ' '` + cc_major=$1 + cc_minor=$2 + cc_patch=$3 + cc_comp=`expr $cc_major '*' 100 '+' $cc_minor` - case "$cc_ver--$cc_verno" in - *GCC*) - # different gcc backends (and versions) have different CPU flags - case `gcc -dumpmachine` in - i?86-* | x86_64-*) - if test "$cc_comp" -lt 304 ; then - check_cpu_cflags="-mcpu=${cpu_arg}" - elif test "$cc_comp" -ge 402 ; then - check_cpu_cflags="-mtune=native" - else - check_cpu_cflags="-mtune=${cpu_arg}" - fi - ;; - ppc-*) - check_cpu_cflags="-mcpu=${cpu_arg} -mtune=${cpu_arg}" - ;; - *) - check_cpu_cflags="" - return - ;; - esac - ;; - 2.95.*) - # GCC 2.95 doesn't expose its name in --version output - check_cpu_cflags="-m${cpu_arg}" - ;; - *) - check_cpu_cflags="" - return - ;; - esac + case "$cc_ver--$cc_verno" in + *GCC*) + # different gcc backends (and versions) have different CPU flags + case `gcc -dumpmachine` in + i?86-* | x86_64-*) + if test "$cc_comp" -lt 304 ; then + check_cpu_cflags="-mcpu=${cpu_arg}" + elif test "$cc_comp" -ge 402 ; then + check_cpu_cflags="-mtune=native" + else + check_cpu_cflags="-mtune=${cpu_arg}" + fi + ;; + ppc-*) + check_cpu_cflags="-mcpu=${cpu_arg} -mtune=${cpu_arg}" + ;; + *) + check_cpu_cflags="" + return + ;; + esac + ;; + 2.95.*) + # GCC 2.95 doesn't expose its name in --version output + check_cpu_cflags="-m${cpu_arg}" + ;; + *) + check_cpu_cflags="" + return + ;; + esac + # now we check whether the compiler really understands the cpu type + touch __test.c - # now we check whether the compiler really understands the cpu type - touch __test.c + while [ "$cpu_arg" ] ; do + printf "testing $cpu_arg ... " >&2 + + # compile check + eval "$cc -c $check_cpu_cflags __test.c" 2>/dev/null + if test "x$?" = "x0" ; then + echo ok >&2 + break; + fi + echo failed >&2 + check_cpu_cflags="" + break; + done + rm __test.* + fi if test "x$core2" = "xyes" ; then cpu_arg="core2" fi - while [ "$cpu_arg" ] ; do - printf "testing $cpu_arg ... " >&2 - - # compile check - eval "$cc -c $check_cpu_cflags __test.c" 2>/dev/null - if test "x$?" = "x0" ; then - echo ok >&2 - break; - fi - - echo failed >&2 - check_cpu_cflags="" - break; - done - rm __test.* + return 0 } check_cpu === added file 'config/ac-macros/dtrace.m4' --- a/config/ac-macros/dtrace.m4 1970-01-01 00:00:00 +0000 +++ b/config/ac-macros/dtrace.m4 2009-03-06 12:10:58 +0000 @@ -0,0 +1,38 @@ +dnl --------------------------------------------------------------------------- +dnl Macro: DTRACE_TEST +dnl --------------------------------------------------------------------------- +AC_ARG_ENABLE(dtrace, + AC_HELP_STRING([--enable-dtrace],[Build with support for the DTRACE.]), + [ + ENABLE_DTRACE="$enable_dtrace" + ], + [ + ENABLE_DTRACE="yes" + ] +) +DTRACEFLAGS="" +HAVE_DTRACE="" +HAVE_DTRACE_DASH_G="" +if test "$ENABLE_DTRACE" = "yes"; then + AC_CHECK_PROGS(DTRACE, dtrace, [not found], [$PATH:/usr/sbin]) + if test "$DTRACE" = "not found"; then + ENABLE_DTRACE="no" + else + AC_DEFINE([HAVE_DTRACE], [1], [Defined to 1 if DTrace support is enabled]) + case "$target_os" in + *solaris*) + HAVE_DTRACE_DASH_G="yes" + ;; + *) + HAVE_DTRACE_DASH_G="no" + ;; + esac + fi +fi +AC_SUBST(DTRACEFLAGS) +AC_SUBST(HAVE_DTRACE) +AM_CONDITIONAL([HAVE_DTRACE], [ test "$ENABLE_DTRACE" = "yes" ]) +AM_CONDITIONAL([HAVE_DTRACE_DASH_G], [ test "$HAVE_DTRACE_DASH_G" = "yes" ]) +dnl --------------------------------------------------------------------------- +dnl End Macro: DTRACE_TEST +dnl --------------------------------------------------------------------------- === removed file 'config/ac-macros/dtrace.m4' --- a/config/ac-macros/dtrace.m4 2007-09-12 04:16:59 +0000 +++ b/config/ac-macros/dtrace.m4 1970-01-01 00:00:00 +0000 @@ -1,20 +0,0 @@ -dnl --------------------------------------------------------------------------- -dnl Macro: DTRACE_TEST -dnl --------------------------------------------------------------------------- -AC_ARG_ENABLE(dtrace, - [ --enable-dtrace Build with support for the DTRACE.], - [ - AC_DEFINE([HAVE_DTRACE], [1], [Enables DTRACE Support]) - AC_CHECK_PROGS(DTRACE, dtrace) - ENABLE_DTRACE="yes" - AC_SUBST(DTRACEFLAGS) - AC_SUBST(HAVE_DTRACE) - ], - [ - ENABLE_DTRACE="no" - ] - ) -AM_CONDITIONAL([HAVE_DTRACE], [ test "$ENABLE_DTRACE" = "yes" ]) -dnl --------------------------------------------------------------------------- -dnl End Macro: DTRACE_TEST -dnl --------------------------------------------------------------------------- === modified file 'configure.in' --- a/configure.in 2009-06-17 07:30:19 +0000 +++ b/configure.in 2009-07-02 14:23:36 +0000 @@ -58,8 +58,8 @@ sinclude(config/ac-macros/alloca.m4) sinclude(config/ac-macros/check_cpu.m4) sinclude(config/ac-macros/character_sets.m4) sinclude(config/ac-macros/compiler_flag.m4) -sinclude(config/ac-macros/dtrace.m4) sinclude(config/ac-macros/plugins.m4) +sinclude(config/ac-macros/dtrace.m4) sinclude(config/ac-macros/ha_ndbcluster.m4) sinclude(config/ac-macros/large_file.m4) sinclude(config/ac-macros/misc.m4) @@ -866,6 +866,8 @@ then AC_CHECK_DECLS(SHM_HUGETLB, AC_DEFINE([HAVE_LARGE_PAGES], [1], [Define if you have large pages support]) + AC_DEFINE([HAVE_LARGE_PAGE_OPTION], [1], + [Define if you have large page option]) AC_DEFINE([HUGETLB_USE_PROC_MEMINFO], [1], [Define if /proc/meminfo shows the huge page size (Linux only)]) , , @@ -873,6 +875,20 @@ then #include ] ) +else +# For large pages support on Solaris +AC_CHECK_DECLS(MHA_MAPSIZE_VA, + AC_DEFINE([HAVE_SOLARIS_LARGE_PAGES], [1], + [Define to 1 if you have large pages support]) + AC_DEFINE([HAVE_LARGE_PAGE_OPTION], [1], + [Define if you have large page option]) + , , + [ +#include + ] +) + + fi #-------------------------------------------------------------------- @@ -1803,6 +1819,64 @@ case "$with_atomic_ops" in *) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;; esac +AC_CACHE_CHECK([whether the compiler provides atomic builtins], + [mysql_cv_gcc_atomic_builtins], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [ + #include + ] + [[ + int foo= -10; int bar= 10; + if (!__sync_fetch_and_add(&foo, bar) || foo) + return -1; + bar= __sync_lock_test_and_set(&foo, bar); + if (bar || foo != 10) + return -1; + bar= __sync_val_compare_and_swap(&bar, foo, 15); + if (bar) + return -1; + return 0; + ]] + )], + [mysql_cv_gcc_atomic_builtins=yes], + [mysql_cv_gcc_atomic_builtins=no], + [mysql_cv_gcc_atomic_builtins=no] +)]) +if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then + AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1, + [Define to 1 if compiler provides atomic builtins.]) +fi + +AC_CACHE_CHECK([whether the OS provides atomic_* functions like Solaris], + [mysql_cv_solaris_atomic], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [ + #include + ] + [[ + int foo = -10; int bar = 10; + if (atomic_add_int_nv((uint_t *)&foo, bar) || foo) + return -1; + bar = atomic_swap_uint((uint_t *)&foo, (uint_t)bar); + if (bar || foo != 10) + return -1; + bar = atomic_cas_uint((uint_t *)&bar, (uint_t)foo, 15); + if (bar) + return -1; + return 0; + ]] + )], + [mysql_cv_solaris_atomic=yes], + [mysql_cv_solaris_atomic=no], + [mysql_cv_solaris_atomic=no] +)]) +if test "x$mysql_cv_solaris_atomic" = xyes; then + AC_DEFINE(HAVE_SOLARIS_ATOMIC, 1, + [Define to 1 if OS provides atomic_* functions like Solaris.]) +fi + # Force static compilation to avoid linking problems/get more speed AC_ARG_WITH(mysqld-ldflags, [ --with-mysqld-ldflags Extra linking arguments for mysqld], @@ -2452,6 +2526,44 @@ fi fi #---END: +#Check for x86 PAUSE instruction +AC_MSG_CHECKING("for x86 PAUSE instruction") +# We have to actually try running the test program, because of a bug +# in Solaris on x86_64, where it wrongly reports that PAUSE is not +# supported when trying to run an application. See +# http://bugs.opensolaris.org/bugdatabase/printableBug.do?bug_id=6478684 +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([], + [[ + __asm__ __volatile__ ("pause"); + return 0; + ]] + )], + [x86_pause_exists=yes], + [x86_pause_exists=no], + [x86_pause_exists=no] # Cross-compile, assume no PAUSE instruction +) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([], + [[ + __asm__ __volatile__ ("rep; nop"); + return 0; + ]] + )], + [x86_fake_pause_exists=yes], + [x86_fake_pause_exists=no], + [x86_fake_pause_exists=no] # Cross-compile, assume no x86 NOP instruction +) +if test "$x86_pause_exists" = "yes" +then + AC_DEFINE([HAVE_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) +else + if test "$x86_fake_pause_exists" = "yes" + then + AC_DEFINE([HAVE_FAKE_PAUSE_INSTRUCTION], [1], [Does x86 NOP instruction exist]) + fi +fi + # Check if pthread_attr_setscope() exists AC_CACHE_CHECK("for pthread_attr_setscope", mysql_cv_pthread_attr_setscope, AC_LINK_IFELSE( === modified file 'include/Makefile.am' --- a/include/Makefile.am 2009-06-30 08:03:05 +0000 +++ b/include/Makefile.am 2009-07-03 12:25:24 +0000 @@ -15,7 +15,7 @@ # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA -BUILT_SOURCES = $(HEADERS_GEN_MAKE) link_sources +BUILT_SOURCES = $(HEADERS_GEN_MAKE) link_sources probes_mysql_nodtrace.h HEADERS_GEN_CONFIGURE = mysql_version.h HEADERS_GEN_MAKE = my_config.h HEADERS_ABI = mysql.h mysql_com.h mysql_time.h \ @@ -29,7 +29,7 @@ pkginclude_HEADERS = $(HEADERS_ABI) my_d my_getopt.h sslopt-longopts.h my_dir.h \ sslopt-vars.h sslopt-case.h sql_common.h keycache.h \ m_ctype.h my_attribute.h $(HEADERS_GEN_CONFIGURE) \ - $(HEADERS_GEN_MAKE) + $(HEADERS_GEN_MAKE) probes_mysql.h probes_mysql_nodtrace.h noinst_HEADERS = config-win.h config-netware.h lf.h my_bit.h \ heap.h myisamchk.h my_bitmap.h my_uctype.h \ myisam.h myisampack.h myisammrg.h ft_global.h\ @@ -41,11 +41,12 @@ noinst_HEADERS = config-win.h config-net my_vle.h my_user.h my_atomic.h atomic/nolock.h \ atomic/rwlock.h atomic/x86-gcc.h atomic/generic-msvc.h \ atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h \ + atomic/solaris.h \ wqueue.h waiting_threads.h -EXTRA_DIST = mysql.h.pp mysql/plugin.h.pp +EXTRA_DIST = mysql.h.pp mysql/plugin.h.pp probes_mysql.d.base # Remove built files and the symlinked directories -CLEANFILES = $(BUILT_SOURCES) readline openssl +CLEANFILES = $(BUILT_SOURCES) readline openssl probes_mysql.d probes_mysql_nodtrace.h # Some include files that may be moved and patched by configure @@ -67,3 +68,24 @@ my_config.h: config.h # generated by configure from the .h.in files dist-hook: $(RM) -f $(distdir)/mysql_version.h $(distdir)/my_config.h + +probes_mysql.d: + if ! test -f probes_mysql.d ; then \ + $(CP) -f $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d; \ + fi + +DTRACEPROVIDER = probes_mysql.d +if HAVE_DTRACE +BUILT_SOURCES += probes_mysql_dtrace.h +CLEANFILES += $(DTRACEPROVIDER) + +# Fake for creating the probes file. If we are building a separate directory +# then we copy the probes from the source location and use that +# If we are building in the same directory as the source, we do not copy + +probes_mysql_dtrace.h: $(DTRACEPROVIDER) + $(DTRACE) $(DTRACEFLAGS) -h -s $(DTRACEPROVIDER) -o $@ +endif + +probes_mysql_nodtrace.h: $(DTRACEPROVIDER) + @PERL@ $(top_srcdir)/scripts/dheadgen.pl -f $(DTRACEPROVIDER) > $@ === modified file 'include/atomic/nolock.h' --- a/include/atomic/nolock.h 2008-07-09 07:12:43 +0000 +++ b/include/atomic/nolock.h 2009-07-02 14:23:36 +0000 @@ -29,9 +29,15 @@ # elif defined(_MSC_VER) # include "generic-msvc.h" # endif +#elif defined(HAVE_SOLARIS_ATOMIC) +#include "solaris.h" #endif -#ifdef make_atomic_cas_body +#if defined(make_atomic_cas_body) || defined(MY_ATOMICS_MADE) +/* + * We have atomics that require no locking + */ +#define MY_ATOMIC_NOLOCK /* Type not used so minimal size (emptry struct has different size between C and C++, zero-length array is gcc-specific). === added file 'include/atomic/solaris.h' --- a/include/atomic/solaris.h 1970-01-01 00:00:00 +0000 +++ b/include/atomic/solaris.h 2008-10-16 19:12:16 +0000 @@ -0,0 +1,210 @@ +/* Copyright (C) 2008 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include + +#define MY_ATOMIC_MODE "solaris-atomic" + +/* + * This is defined to indicate we fully define the my_atomic_* (inline) + * functions here, so there is no need to "make" them in my_atomic.h + * using make_atomic_* and make_atomic_*_body. + */ +#define MY_ATOMICS_MADE + +STATIC_INLINE int +my_atomic_cas8(int8 volatile *a, int8 *cmp, int8 set) +{ + int ret; + int8 sav; + sav = (int8) atomic_cas_8((volatile uint8_t *)a, (uint8_t)*cmp, + (uint8_t)set); + if (! (ret = (sav == *cmp))) + *cmp = sav; + return ret; +} + +STATIC_INLINE int +my_atomic_cas16(int16 volatile *a, int16 *cmp, int16 set) +{ + int ret; + int16 sav; + sav = (int16) atomic_cas_16((volatile uint16_t *)a, (uint16_t)*cmp, + (uint16_t)set); + if (! (ret = (sav == *cmp))) + *cmp = sav; + return ret; +} + +STATIC_INLINE int +my_atomic_cas32(int32 volatile *a, int32 *cmp, int32 set) +{ + int ret; + int32 sav; + sav = (int32) atomic_cas_32((volatile uint32_t *)a, (uint32_t)*cmp, + (uint32_t)set); + if (! (ret = (sav == *cmp))) + *cmp = sav; + return ret; +} + +STATIC_INLINE int +my_atomic_casptr(void * volatile *a, void **cmp, void *set) +{ + int ret; + void *sav; + sav = atomic_cas_ptr(a, *cmp, set); + if (! (ret = (sav == *cmp))) + *cmp = sav; + return ret; +} + +/* ------------------------------------------------------------------------ */ + +STATIC_INLINE int8 +my_atomic_add8(int8 volatile *a, int8 v) +{ + int8 nv; + nv = atomic_add_8_nv((volatile uint8_t *)a, v); + return (nv - v); +} + +STATIC_INLINE int16 +my_atomic_add16(int16 volatile *a, int16 v) +{ + int16 nv; + nv = atomic_add_16_nv((volatile uint16_t *)a, v); + return (nv - v); +} + +STATIC_INLINE int32 +my_atomic_add32(int32 volatile *a, int32 v) +{ + int32 nv; + nv = atomic_add_32_nv((volatile uint32_t *)a, v); + return (nv - v); +} + +/* ------------------------------------------------------------------------ */ + +#ifdef MY_ATOMIC_MODE_DUMMY + +STATIC_INLINE int8 +my_atomic_load8(int8 volatile *a) { return (*a); } + +STATIC_INLINE int16 +my_atomic_load16(int16 volatile *a) { return (*a); } + +STATIC_INLINE int32 +my_atomic_load32(int32 volatile *a) { return (*a); } + +STATIC_INLINE void * +my_atomic_loadptr(void * volatile *a) { return (*a); } + +/* ------------------------------------------------------------------------ */ + +STATIC_INLINE void +my_atomic_store8(int8 volatile *a, int8 v) { *a = v; } + +STATIC_INLINE void +my_atomic_store16(int16 volatile *a, int16 v) { *a = v; } + +STATIC_INLINE void +my_atomic_store32(int32 volatile *a, int32 v) { *a = v; } + +STATIC_INLINE void +my_atomic_storeptr(void * volatile *a, void *v) { *a = v; } + +/* ------------------------------------------------------------------------ */ + +#else /* MY_ATOMIC_MODE_DUMMY */ + +STATIC_INLINE int8 +my_atomic_load8(int8 volatile *a) +{ + return ((int8) atomic_or_8_nv((volatile uint8_t *)a, 0)); +} + +STATIC_INLINE int16 +my_atomic_load16(int16 volatile *a) +{ + return ((int16) atomic_or_16_nv((volatile uint16_t *)a, 0)); +} + +STATIC_INLINE int32 +my_atomic_load32(int32 volatile *a) +{ + return ((int32) atomic_or_32_nv((volatile uint32_t *)a, 0)); +} + +STATIC_INLINE void * +my_atomic_loadptr(void * volatile *a) +{ + return ((void *) atomic_or_ulong_nv((volatile ulong_t *)a, 0)); +} + +/* ------------------------------------------------------------------------ */ + +STATIC_INLINE void +my_atomic_store8(int8 volatile *a, int8 v) +{ + (void) atomic_swap_8((volatile uint8_t *)a, (uint8_t)v); +} + +STATIC_INLINE void +my_atomic_store16(int16 volatile *a, int16 v) +{ + (void) atomic_swap_16((volatile uint16_t *)a, (uint16_t)v); +} + +STATIC_INLINE void +my_atomic_store32(int32 volatile *a, int32 v) +{ + (void) atomic_swap_32((volatile uint32_t *)a, (uint32_t)v); +} + +STATIC_INLINE void +my_atomic_storeptr(void * volatile *a, void *v) +{ + (void) atomic_swap_ptr(a, v); +} + +#endif + +/* ------------------------------------------------------------------------ */ + +STATIC_INLINE int8 +my_atomic_swap8(int8 volatile *a, int8 v) +{ + return ((int8) atomic_swap_8((volatile uint8_t *)a, (uint8_t)v)); +} + +STATIC_INLINE int16 +my_atomic_swap16(int16 volatile *a, int16 v) +{ + return ((int16) atomic_swap_16((volatile uint16_t *)a, (uint16_t)v)); +} + +STATIC_INLINE int32 +my_atomic_swap32(int32 volatile *a, int32 v) +{ + return ((int32) atomic_swap_32((volatile uint32_t *)a, (uint32_t)v)); +} + +STATIC_INLINE void * +my_atomic_swapptr(void * volatile *a, void *v) +{ + return (atomic_swap_ptr(a, v)); +} === modified file 'include/atomic/x86-gcc.h' --- a/include/atomic/x86-gcc.h 2008-05-29 15:44:11 +0000 +++ b/include/atomic/x86-gcc.h 2009-07-02 14:23:36 +0000 @@ -43,7 +43,7 @@ asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a)) #endif #define make_atomic_fas_body(S) \ - asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (*a)) + asm volatile ("xchg %0, %1;" : "+q" (v) , "+m" (*a)) #define make_atomic_cas_body(S) \ asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \ : "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set)) === modified file 'include/my_atomic.h' --- a/include/my_atomic.h 2008-07-22 14:16:22 +0000 +++ b/include/my_atomic.h 2009-07-02 14:23:36 +0000 @@ -54,6 +54,9 @@ #define intptr void * #ifndef MY_ATOMIC_MODE_RWLOCKS +/* + * Attempt to do atomic ops without locks + */ #include "atomic/nolock.h" #endif @@ -194,7 +197,7 @@ extern int ## S my_atomic_load ## S(Uv_ #define make_atomic_store(S) \ extern void my_atomic_store ## S(Uv_ ## S U_a, U_ ## S U_v); -#endif +#endif /* HAVE_INLINE */ make_atomic_cas(32) make_atomic_cas(ptr) === added file 'include/probes_mysql.d.base' --- a/include/probes_mysql.d.base 1970-01-01 00:00:00 +0000 +++ b/include/probes_mysql.d.base 2009-03-18 10:04:15 +0000 @@ -0,0 +1,176 @@ +/* Copyright (C) 2008 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + The actual probe names in DTrace scripts will replace '__' by '-'. Thus + insert__row__start will be insert-row-start. + + Recommendations for adding new probes: + + - each probe should have the minimal set of arguments required to + unambiguously identify the context in which the probe fires. Redundant + arguments (i.e. the ones that can be obtained in user scripts from previous + probes' arguments or otherwise) may be added for convenience. + + - try to avoid computationally expensive probe arguments. If impossible, + use *_ENABLED() macros to check if the probe is activated before + performing expensive calculations for a probe argument. + + - all *-done probes should have a status argument wherever applicable to make + it possible for user scripts to figure out whether the completed operation + was successful or not. + + - for all status arguments, a non-zero value should be returned on error or + failure, 0 should be returned on success. +*/ + +provider mysql { + + /* The following ones fire when creating or closing a client connection */ + probe connection__start(unsigned long conn_id, char *user, char *host); + probe connection__done(int status, unsigned long conn_id); + + /* + Fire at the start/end of any client command processing (including SQL + queries). + */ + probe command__start(unsigned long conn_id, int command, + char *user, char *host); + probe command__done(int status); + + /* + The following probes fire at the start/end of any SQL query processing, + respectively. + + query_start() has a lot of parameters that can be used to pick up + parameters for a lot of other probes here. For simplicity reasons we also + add the query string to most other DTrace probes as well. Hostname is + either the hostname or the IP address of the MySQL Client. + */ + probe query__start(char *query, + unsigned long conn_id, + char *db_name, + char *user, + char *host); + probe query__done(int status); + + /* Fire at the start/end of SQL query parsing */ + probe query__parse__start(char *query); + probe query__parse__done(int status); + + /* Track whether the query hits the query cache or not */ + probe query__cache__hit(char *query, unsigned long rows); + probe query__cache__miss(char *query); + + /* + This probe fires when the actual query execution starts, i.e. after + parsing and checking the query cache, but before privilege checks, + optimizing, etc. + + Query means also all independent queries of a stored procedure and prepared + statements. Also the stored procedure itself is a query. + + exec_type is: + 0: Executed query from sql_parse, top-level query (sql_parse.cc) + 1: Executed prepared statement (sql_prepare.cc) + 2: Executed cursor statement (sql_cursor.cc) + 3: Executed query in stored procedure (sp_head.cc) + */ + probe query__exec__start(char *query, + unsigned long connid, + char *db_name, + char *user, + char *host, + int exec_type); + probe query__exec__done(int status); + + /* These probes fire when performing row operations towards any handler */ + probe insert__row__start(char *db, char *table); + probe insert__row__done(int status); + probe update__row__start(char *db, char *table); + probe update__row__done(int status); + probe delete__row__start(char *db, char *table); + probe delete__row__done(int status); + probe read__row__start(char *db, char *table, int scan_flag); + probe read__row__done(int status); + probe index__read__row__start(char *db, char *table); + probe index__read__row__done(int status); + + /* + These probes fire when calling external_lock for any handler + depending on the lock type being acquired or released. + */ + probe handler__rdlock__start(char *db, char *table); + probe handler__wrlock__start(char *db, char *table); + probe handler__unlock__start(char *db, char *table); + probe handler__rdlock__done(int status); + probe handler__wrlock__done(int status); + probe handler__unlock__done(int status); + + /* + These probes fire when a filesort activity happens in a query. + */ + probe filesort__start(char *db, char *table); + probe filesort__done(int status, unsigned long rows); + /* + The query types SELECT, INSERT, INSERT AS SELECT, UPDATE, UPDATE with + multiple tables, DELETE, DELETE with multiple tables are all probed. + The start probe always contains the query text. + */ + probe select__start(char *query); + probe select__done(int status, unsigned long rows); + probe insert__start(char *query); + probe insert__done(int status, unsigned long rows); + probe insert__select__start(char *query); + probe insert__select__done(int status, unsigned long rows); + probe update__start(char *query); + probe update__done(int status, + unsigned long rowsmatches, unsigned long rowschanged); + probe multi__update__start(char *query); + probe multi__update__done(int status, + unsigned long rowsmatches, + unsigned long rowschanged); + probe delete__start(char *query); + probe delete__done(int status, unsigned long rows); + probe multi__delete__start(char *query); + probe multi__delete__done(int status, unsigned long rows); + + /* + These probes can be used to measure the time waiting for network traffic + or identify network-related problems. + */ + probe net__read__start(); + probe net__read__done(int status, unsigned long bytes); + probe net__write__start(unsigned long bytes); + probe net__write__done(int status); + + /* MyISAM Key cache probes */ + probe keycache__read__start(char *filepath, unsigned long bytes, + unsigned long mem_used, unsigned long mem_free); + probe keycache__read__block(unsigned long bytes); + probe keycache__read__hit(); + probe keycache__read__miss(); + probe keycache__read__done(unsigned long mem_used, unsigned long mem_free); + probe keycache__write__start(char *filepath, unsigned long bytes, + unsigned long mem_used, unsigned long mem_free); + probe keycache__write__block(unsigned long bytes); + probe keycache__write__done(unsigned long mem_used, unsigned long mem_free); +}; + +#pragma D attributes Evolving/Evolving/Common provider mysql provider +#pragma D attributes Evolving/Evolving/Common provider mysql module +#pragma D attributes Evolving/Evolving/Common provider mysql function +#pragma D attributes Evolving/Evolving/Common provider mysql name +#pragma D attributes Evolving/Evolving/Common provider mysql args === added file 'include/probes_mysql.h' --- a/include/probes_mysql.h 1970-01-01 00:00:00 +0000 +++ b/include/probes_mysql.h 2008-12-20 10:01:41 +0000 @@ -0,0 +1,13 @@ +#ifndef PROBES_MYSQL_H + +#define PROBES_MYSQL_H + +#include + +#if defined(HAVE_DTRACE) && !defined(DISABLE_DTRACE) +#include "probes_mysql_dtrace.h" +#else +#include "probes_mysql_nodtrace.h" +#endif + +#endif /* PROBES_MYSQL_H */ === added file 'include/probes_mysql_nodtrace.h' --- a/include/probes_mysql_nodtrace.h 1970-01-01 00:00:00 +0000 +++ b/include/probes_mysql_nodtrace.h 2008-12-23 09:05:30 +0000 @@ -0,0 +1,129 @@ +/* + * Generated by dheadgen(1). + */ + +#ifndef _PROBES_MYSQL_D +#define _PROBES_MYSQL_D + +#ifdef __cplusplus +extern "C" { +#endif + +#define MYSQL_CONNECTION_START(arg0, arg1, arg2) +#define MYSQL_CONNECTION_START_ENABLED() (0) +#define MYSQL_CONNECTION_DONE(arg0, arg1) +#define MYSQL_CONNECTION_DONE_ENABLED() (0) +#define MYSQL_COMMAND_START(arg0, arg1, arg2, arg3) +#define MYSQL_COMMAND_START_ENABLED() (0) +#define MYSQL_COMMAND_DONE(arg0) +#define MYSQL_COMMAND_DONE_ENABLED() (0) +#define MYSQL_QUERY_START(arg0, arg1, arg2, arg3, arg4) +#define MYSQL_QUERY_START_ENABLED() (0) +#define MYSQL_QUERY_DONE(arg0) +#define MYSQL_QUERY_DONE_ENABLED() (0) +#define MYSQL_QUERY_PARSE_START(arg0) +#define MYSQL_QUERY_PARSE_START_ENABLED() (0) +#define MYSQL_QUERY_PARSE_DONE(arg0) +#define MYSQL_QUERY_PARSE_DONE_ENABLED() (0) +#define MYSQL_QUERY_CACHE_HIT(arg0, arg1) +#define MYSQL_QUERY_CACHE_HIT_ENABLED() (0) +#define MYSQL_QUERY_CACHE_MISS(arg0) +#define MYSQL_QUERY_CACHE_MISS_ENABLED() (0) +#define MYSQL_QUERY_EXEC_START(arg0, arg1, arg2, arg3, arg4, arg5) +#define MYSQL_QUERY_EXEC_START_ENABLED() (0) +#define MYSQL_QUERY_EXEC_DONE(arg0) +#define MYSQL_QUERY_EXEC_DONE_ENABLED() (0) +#define MYSQL_INSERT_ROW_START(arg0, arg1) +#define MYSQL_INSERT_ROW_START_ENABLED() (0) +#define MYSQL_INSERT_ROW_DONE(arg0) +#define MYSQL_INSERT_ROW_DONE_ENABLED() (0) +#define MYSQL_UPDATE_ROW_START(arg0, arg1) +#define MYSQL_UPDATE_ROW_START_ENABLED() (0) +#define MYSQL_UPDATE_ROW_DONE(arg0) +#define MYSQL_UPDATE_ROW_DONE_ENABLED() (0) +#define MYSQL_DELETE_ROW_START(arg0, arg1) +#define MYSQL_DELETE_ROW_START_ENABLED() (0) +#define MYSQL_DELETE_ROW_DONE(arg0) +#define MYSQL_DELETE_ROW_DONE_ENABLED() (0) +#define MYSQL_READ_ROW_START(arg0, arg1, arg2) +#define MYSQL_READ_ROW_START_ENABLED() (0) +#define MYSQL_READ_ROW_DONE(arg0) +#define MYSQL_READ_ROW_DONE_ENABLED() (0) +#define MYSQL_INDEX_READ_ROW_START(arg0, arg1) +#define MYSQL_INDEX_READ_ROW_START_ENABLED() (0) +#define MYSQL_INDEX_READ_ROW_DONE(arg0) +#define MYSQL_INDEX_READ_ROW_DONE_ENABLED() (0) +#define MYSQL_HANDLER_RDLOCK_START(arg0, arg1) +#define MYSQL_HANDLER_RDLOCK_START_ENABLED() (0) +#define MYSQL_HANDLER_WRLOCK_START(arg0, arg1) +#define MYSQL_HANDLER_WRLOCK_START_ENABLED() (0) +#define MYSQL_HANDLER_UNLOCK_START(arg0, arg1) +#define MYSQL_HANDLER_UNLOCK_START_ENABLED() (0) +#define MYSQL_HANDLER_RDLOCK_DONE(arg0) +#define MYSQL_HANDLER_RDLOCK_DONE_ENABLED() (0) +#define MYSQL_HANDLER_WRLOCK_DONE(arg0) +#define MYSQL_HANDLER_WRLOCK_DONE_ENABLED() (0) +#define MYSQL_HANDLER_UNLOCK_DONE(arg0) +#define MYSQL_HANDLER_UNLOCK_DONE_ENABLED() (0) +#define MYSQL_FILESORT_START(arg0, arg1) +#define MYSQL_FILESORT_START_ENABLED() (0) +#define MYSQL_FILESORT_DONE(arg0, arg1) +#define MYSQL_FILESORT_DONE_ENABLED() (0) +#define MYSQL_SELECT_START(arg0) +#define MYSQL_SELECT_START_ENABLED() (0) +#define MYSQL_SELECT_DONE(arg0, arg1) +#define MYSQL_SELECT_DONE_ENABLED() (0) +#define MYSQL_INSERT_START(arg0) +#define MYSQL_INSERT_START_ENABLED() (0) +#define MYSQL_INSERT_DONE(arg0, arg1) +#define MYSQL_INSERT_DONE_ENABLED() (0) +#define MYSQL_INSERT_SELECT_START(arg0) +#define MYSQL_INSERT_SELECT_START_ENABLED() (0) +#define MYSQL_INSERT_SELECT_DONE(arg0, arg1) +#define MYSQL_INSERT_SELECT_DONE_ENABLED() (0) +#define MYSQL_UPDATE_START(arg0) +#define MYSQL_UPDATE_START_ENABLED() (0) +#define MYSQL_UPDATE_DONE(arg0, arg1, arg2) +#define MYSQL_UPDATE_DONE_ENABLED() (0) +#define MYSQL_MULTI_UPDATE_START(arg0) +#define MYSQL_MULTI_UPDATE_START_ENABLED() (0) +#define MYSQL_MULTI_UPDATE_DONE(arg0, arg1, arg2) +#define MYSQL_MULTI_UPDATE_DONE_ENABLED() (0) +#define MYSQL_DELETE_START(arg0) +#define MYSQL_DELETE_START_ENABLED() (0) +#define MYSQL_DELETE_DONE(arg0, arg1) +#define MYSQL_DELETE_DONE_ENABLED() (0) +#define MYSQL_MULTI_DELETE_START(arg0) +#define MYSQL_MULTI_DELETE_START_ENABLED() (0) +#define MYSQL_MULTI_DELETE_DONE(arg0, arg1) +#define MYSQL_MULTI_DELETE_DONE_ENABLED() (0) +#define MYSQL_NET_READ_START() +#define MYSQL_NET_READ_START_ENABLED() (0) +#define MYSQL_NET_READ_DONE(arg0, arg1) +#define MYSQL_NET_READ_DONE_ENABLED() (0) +#define MYSQL_NET_WRITE_START(arg0) +#define MYSQL_NET_WRITE_START_ENABLED() (0) +#define MYSQL_NET_WRITE_DONE(arg0) +#define MYSQL_NET_WRITE_DONE_ENABLED() (0) +#define MYSQL_KEYCACHE_READ_START(arg0, arg1, arg2, arg3) +#define MYSQL_KEYCACHE_READ_START_ENABLED() (0) +#define MYSQL_KEYCACHE_READ_BLOCK(arg0) +#define MYSQL_KEYCACHE_READ_BLOCK_ENABLED() (0) +#define MYSQL_KEYCACHE_READ_HIT() +#define MYSQL_KEYCACHE_READ_HIT_ENABLED() (0) +#define MYSQL_KEYCACHE_READ_MISS() +#define MYSQL_KEYCACHE_READ_MISS_ENABLED() (0) +#define MYSQL_KEYCACHE_READ_DONE(arg0, arg1) +#define MYSQL_KEYCACHE_READ_DONE_ENABLED() (0) +#define MYSQL_KEYCACHE_WRITE_START(arg0, arg1, arg2, arg3) +#define MYSQL_KEYCACHE_WRITE_START_ENABLED() (0) +#define MYSQL_KEYCACHE_WRITE_BLOCK(arg0) +#define MYSQL_KEYCACHE_WRITE_BLOCK_ENABLED() (0) +#define MYSQL_KEYCACHE_WRITE_DONE(arg0, arg1) +#define MYSQL_KEYCACHE_WRITE_DONE_ENABLED() (0) + +#ifdef __cplusplus +} +#endif + +#endif /* _PROBES_MYSQL_D */ === modified file 'libmysql/Makefile.shared' --- a/libmysql/Makefile.shared 2009-03-16 17:00:38 +0000 +++ b/libmysql/Makefile.shared 2009-07-02 14:23:36 +0000 @@ -73,7 +73,8 @@ DEFS = -DDEFAULT_CHARSET_HOME="\"$(MYS -DDEFAULT_HOME_ENV=MYSQL_HOME \ -DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX \ -DDEFAULT_SYSCONFDIR="\"$(sysconfdir)\"" \ - -DSHAREDIR="\"$(MYSQLSHAREdir)\"" $(target_defs) + -DSHAREDIR="\"$(MYSQLSHAREdir)\"" -DDISABLE_DTRACE \ + $(target_defs) if HAVE_YASSL yassl_las = $(top_builddir)/extra/yassl/src/libyassl.la \ === modified file 'libmysqld/Makefile.am' --- a/libmysqld/Makefile.am 2009-05-04 15:51:55 +0000 +++ b/libmysqld/Makefile.am 2009-07-02 14:23:36 +0000 @@ -30,7 +30,8 @@ DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERV -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \ @DEFS@ \ -DLIBDIR="\"$(MYSQLLIBdir)\"" \ - -DPLUGINDIR="\"$(pkgplugindir)\"" + -DPLUGINDIR="\"$(pkgplugindir)\"" \ + -DDISABLE_DTRACE AM_CPPFLAGS = -I$(top_srcdir)/include \ -I$(top_builddir)/sql -I$(top_srcdir)/sql \ -I$(top_srcdir)/sql/examples \ === modified file 'mysql-test/include/default_mysqld.cnf' --- a/mysql-test/include/default_mysqld.cnf 2009-02-02 15:58:48 +0000 +++ b/mysql-test/include/default_mysqld.cnf 2009-07-02 14:23:36 +0000 @@ -14,6 +14,11 @@ sort_buffer= 256K max_heap_table_size= 1M loose-innodb_data_file_path= ibdata1:10M:autoextend +loose-innodb_buffer_pool_size= 64M +loose-innodb_write_io_threads= 2 +loose-innodb_read_io_threads= 2 +loose-innodb_log_buffer_size= 4M +loose-innodb_log_file_size= 32M slave-net-timeout=120 === modified file 'mysql-test/r/innodb.result' --- a/mysql-test/r/innodb.result 2009-06-19 09:12:06 +0000 +++ b/mysql-test/r/innodb.result 2009-07-02 14:23:36 +0000 @@ -1725,7 +1725,7 @@ count(*) drop table t1; show status like "Innodb_buffer_pool_pages_total"; Variable_name Value -Innodb_buffer_pool_pages_total 512 +Innodb_buffer_pool_pages_total 4096 show status like "Innodb_page_size"; Variable_name Value Innodb_page_size 16384 @@ -1771,7 +1771,7 @@ innodb_sync_spin_loops 20 SET @old_innodb_thread_concurrency= @@global.innodb_thread_concurrency; show variables like "innodb_thread_concurrency"; Variable_name Value -innodb_thread_concurrency 8 +innodb_thread_concurrency 0 set global innodb_thread_concurrency=1001; Warnings: Warning 1292 Truncated incorrect thread_concurrency value: '1001' === modified file 'mysql-test/r/merge.result' --- a/mysql-test/r/merge.result 2009-04-22 10:02:28 +0000 +++ b/mysql-test/r/merge.result 2009-07-02 16:13:21 +0000 @@ -2039,10 +2039,10 @@ set @save_table_definition_cache=@@globa # # Set @@global.table_definition_cache to minimum # -set @@global.table_definition_cache=256; +set @@global.table_definition_cache=400; set @a=null; # -# Create 256 merge children +# Create 400 merge children # set @a=concat("create table t_parent (a int) union(", @a, ") insert_method=first engine=mrg_myisam"); === modified file 'mysql-test/r/partition_innodb.result' --- a/mysql-test/r/partition_innodb.result 2008-12-13 11:02:16 +0000 +++ b/mysql-test/r/partition_innodb.result 2009-07-02 14:23:36 +0000 @@ -11,13 +11,7 @@ SET @old_tx_isolation := @@session.tx_is SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SET autocommit = 0; UPDATE t1 SET DATA = data*2 WHERE id = 3; -SHOW ENGINE InnoDB STATUS; -Type Name Status -InnoDB 2 lock struct(s) 1 row lock(s) UPDATE t1 SET data = data*2 WHERE data = 2; -SHOW ENGINE InnoDB STATUS; -Type Name Status -InnoDB 6 lock struct(s) 2 row lock(s) SET @@session.tx_isolation = @old_tx_isolation; DROP TABLE t1; # Bug#37721, test of ORDER BY on PK and WHERE on INDEX === modified file 'mysql-test/suite/sys_vars/r/innodb_autoextend_increment_basic.result' --- a/mysql-test/suite/sys_vars/r/innodb_autoextend_increment_basic.result 2009-02-03 09:16:53 +0000 +++ b/mysql-test/suite/sys_vars/r/innodb_autoextend_increment_basic.result 2009-07-02 14:23:36 +0000 @@ -6,13 +6,13 @@ Warning 1292 Truncated incorrect autoext SET @@global.innodb_autoextend_increment = DEFAULT; SELECT @@global.innodb_autoextend_increment ; @@global.innodb_autoextend_increment -8 +64 '#---------------------FN_DYNVARS_046_02-------------------------#' SET innodb_autoextend_increment = 1; ERROR HY000: Variable 'innodb_autoextend_increment' is a GLOBAL variable and should be set with SET GLOBAL SELECT @@innodb_autoextend_increment ; @@innodb_autoextend_increment -8 +64 SELECT local.innodb_autoextend_increment ; ERROR 42S02: Unknown table 'local' in field list SET global innodb_autoextend_increment = 0; === modified file 'mysql-test/suite/sys_vars/r/innodb_file_io_threads_basic.result' --- a/mysql-test/suite/sys_vars/r/innodb_file_io_threads_basic.result 2008-12-19 15:12:15 +0000 +++ b/mysql-test/suite/sys_vars/r/innodb_file_io_threads_basic.result 2009-02-17 12:24:09 +0000 @@ -1,53 +1,101 @@ '#---------------------BS_STVARS_027_01----------------------#' -SELECT COUNT(@@GLOBAL.innodb_file_io_threads); -COUNT(@@GLOBAL.innodb_file_io_threads) +SELECT COUNT(@@GLOBAL.innodb_read_io_threads); +COUNT(@@GLOBAL.innodb_read_io_threads) +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_write_io_threads); +COUNT(@@GLOBAL.innodb_write_io_threads) 1 1 Expected '#---------------------BS_STVARS_027_02----------------------#' -SET @@GLOBAL.innodb_file_io_threads=1; -ERROR HY000: Variable 'innodb_file_io_threads' is a read only variable +SET @@GLOBAL.innodb_read_io_threads=1; +ERROR HY000: Variable 'innodb_read_io_threads' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.innodb_read_io_threads); +COUNT(@@GLOBAL.innodb_read_io_threads) +1 +1 Expected +SET @@GLOBAL.innodb_write_io_threads=1; +ERROR HY000: Variable 'innodb_write_io_threads' is a read only variable Expected error 'Read only variable' -SELECT COUNT(@@GLOBAL.innodb_file_io_threads); -COUNT(@@GLOBAL.innodb_file_io_threads) +SELECT COUNT(@@GLOBAL.innodb_write_io_threads); +COUNT(@@GLOBAL.innodb_write_io_threads) 1 1 Expected '#---------------------BS_STVARS_027_03----------------------#' -SELECT @@GLOBAL.innodb_file_io_threads = VARIABLE_VALUE +SELECT @@GLOBAL.innodb_read_io_threads = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_read_io_threads'; +@@GLOBAL.innodb_read_io_threads = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_read_io_threads); +COUNT(@@GLOBAL.innodb_read_io_threads) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_read_io_threads'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@GLOBAL.innodb_write_io_threads = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='innodb_file_io_threads'; -@@GLOBAL.innodb_file_io_threads = VARIABLE_VALUE +WHERE VARIABLE_NAME='innodb_write_io_threads'; +@@GLOBAL.innodb_write_io_threads = VARIABLE_VALUE 1 1 Expected -SELECT COUNT(@@GLOBAL.innodb_file_io_threads); -COUNT(@@GLOBAL.innodb_file_io_threads) +SELECT COUNT(@@GLOBAL.innodb_write_io_threads); +COUNT(@@GLOBAL.innodb_write_io_threads) 1 1 Expected SELECT COUNT(VARIABLE_VALUE) FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='innodb_file_io_threads'; +WHERE VARIABLE_NAME='innodb_write_io_threads'; COUNT(VARIABLE_VALUE) 1 1 Expected '#---------------------BS_STVARS_027_04----------------------#' -SELECT @@innodb_file_io_threads = @@GLOBAL.innodb_file_io_threads; -@@innodb_file_io_threads = @@GLOBAL.innodb_file_io_threads +SELECT @@innodb_read_io_threads = @@GLOBAL.innodb_read_io_threads; +@@innodb_read_io_threads = @@GLOBAL.innodb_read_io_threads +1 +1 Expected +SELECT @@innodb_write_io_threads = @@GLOBAL.innodb_write_io_threads; +@@innodb_write_io_threads = @@GLOBAL.innodb_write_io_threads 1 1 Expected '#---------------------BS_STVARS_027_05----------------------#' -SELECT COUNT(@@innodb_file_io_threads); -COUNT(@@innodb_file_io_threads) +SELECT COUNT(@@innodb_read_io_threads); +COUNT(@@innodb_read_io_threads) +1 +1 Expected +SELECT COUNT(@@local.innodb_read_io_threads); +ERROR HY000: Variable 'innodb_read_io_threads' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_read_io_threads); +ERROR HY000: Variable 'innodb_read_io_threads' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.innodb_read_io_threads); +COUNT(@@GLOBAL.innodb_read_io_threads) +1 +1 Expected +SELECT innodb_read_io_threads = @@SESSION.innodb_read_io_threads; +ERROR 42S22: Unknown column 'innodb_read_io_threads' in 'field list' +Expected error 'Readonly variable' +SELECT COUNT(@@innodb_write_io_threads); +COUNT(@@innodb_write_io_threads) 1 1 Expected -SELECT COUNT(@@local.innodb_file_io_threads); -ERROR HY000: Variable 'innodb_file_io_threads' is a GLOBAL variable +SELECT COUNT(@@local.innodb_write_io_threads); +ERROR HY000: Variable 'innodb_write_io_threads' is a GLOBAL variable Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@SESSION.innodb_file_io_threads); -ERROR HY000: Variable 'innodb_file_io_threads' is a GLOBAL variable +SELECT COUNT(@@SESSION.innodb_write_io_threads); +ERROR HY000: Variable 'innodb_write_io_threads' is a GLOBAL variable Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@GLOBAL.innodb_file_io_threads); -COUNT(@@GLOBAL.innodb_file_io_threads) +SELECT COUNT(@@GLOBAL.innodb_write_io_threads); +COUNT(@@GLOBAL.innodb_write_io_threads) 1 1 Expected -SELECT innodb_file_io_threads = @@SESSION.innodb_file_io_threads; -ERROR 42S22: Unknown column 'innodb_file_io_threads' in 'field list' +SELECT innodb_write_io_threads = @@SESSION.innodb_write_io_threads; +ERROR 42S22: Unknown column 'innodb_write_io_threads' in 'field list' Expected error 'Readonly variable' === modified file 'mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result' --- a/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result 2008-12-19 15:12:15 +0000 +++ b/mysql-test/suite/sys_vars/r/innodb_max_dirty_pages_pct_basic.result 2009-02-17 12:24:09 +0000 @@ -1,19 +1,19 @@ SET @global_start_value = @@global.innodb_max_dirty_pages_pct; SELECT @global_start_value; @global_start_value -90 +75 '#--------------------FN_DYNVARS_046_01------------------------#' SET @@global.innodb_max_dirty_pages_pct = 0; SET @@global.innodb_max_dirty_pages_pct = DEFAULT; SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -90 +75 '#---------------------FN_DYNVARS_046_02-------------------------#' SET innodb_max_dirty_pages_pct = 1; ERROR HY000: Variable 'innodb_max_dirty_pages_pct' is a GLOBAL variable and should be set with SET GLOBAL SELECT @@innodb_max_dirty_pages_pct; @@innodb_max_dirty_pages_pct -90 +75 SELECT local.innodb_max_dirty_pages_pct; ERROR 42S02: Unknown table 'local' in field list SET global innodb_max_dirty_pages_pct = 0; @@ -29,33 +29,33 @@ SET @@global.innodb_max_dirty_pages_pct SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct 1 -SET @@global.innodb_max_dirty_pages_pct = 100; +SET @@global.innodb_max_dirty_pages_pct = 99; SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -100 +99 '#--------------------FN_DYNVARS_046_04-------------------------#' SET @@global.innodb_max_dirty_pages_pct = -1; Warnings: Warning 1292 Truncated incorrect max_dirty_pages_pct value: '18446744073709551615' SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -100 +99 SET @@global.innodb_max_dirty_pages_pct = "T"; ERROR 42000: Incorrect argument type to variable 'innodb_max_dirty_pages_pct' SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -100 +99 SET @@global.innodb_max_dirty_pages_pct = "Y"; ERROR 42000: Incorrect argument type to variable 'innodb_max_dirty_pages_pct' SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -100 +99 SET @@global.innodb_max_dirty_pages_pct = 1001; Warnings: Warning 1292 Truncated incorrect max_dirty_pages_pct value: '1001' SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -100 +99 '#----------------------FN_DYNVARS_046_05------------------------#' SELECT @@global.innodb_max_dirty_pages_pct = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -65,22 +65,22 @@ VARIABLE_VALUE 1 SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -100 +99 SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='innodb_max_dirty_pages_pct'; VARIABLE_VALUE -100 +99 '#---------------------FN_DYNVARS_046_06-------------------------#' SET @@global.innodb_max_dirty_pages_pct = OFF; ERROR 42000: Incorrect argument type to variable 'innodb_max_dirty_pages_pct' SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -100 +99 SET @@global.innodb_max_dirty_pages_pct = ON; ERROR 42000: Incorrect argument type to variable 'innodb_max_dirty_pages_pct' SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -100 +99 '#---------------------FN_DYNVARS_046_07----------------------#' SET @@global.innodb_max_dirty_pages_pct = TRUE; SELECT @@global.innodb_max_dirty_pages_pct; @@ -93,4 +93,4 @@ SELECT @@global.innodb_max_dirty_pages_p SET @@global.innodb_max_dirty_pages_pct = @global_start_value; SELECT @@global.innodb_max_dirty_pages_pct; @@global.innodb_max_dirty_pages_pct -90 +75 === modified file 'mysql-test/suite/sys_vars/r/innodb_thread_concurrency_basic.result' --- a/mysql-test/suite/sys_vars/r/innodb_thread_concurrency_basic.result 2008-12-19 15:12:15 +0000 +++ b/mysql-test/suite/sys_vars/r/innodb_thread_concurrency_basic.result 2009-02-17 12:24:09 +0000 @@ -1,19 +1,19 @@ SET @global_start_value = @@global.innodb_thread_concurrency; SELECT @global_start_value; @global_start_value -8 +0 '#--------------------FN_DYNVARS_046_01------------------------#' SET @@global.innodb_thread_concurrency = 0; SET @@global.innodb_thread_concurrency = DEFAULT; SELECT @@global.innodb_thread_concurrency; @@global.innodb_thread_concurrency -8 +0 '#---------------------FN_DYNVARS_046_02-------------------------#' SET innodb_thread_concurrency = 1; ERROR HY000: Variable 'innodb_thread_concurrency' is a GLOBAL variable and should be set with SET GLOBAL SELECT @@innodb_thread_concurrency; @@innodb_thread_concurrency -8 +0 SELECT local.innodb_thread_concurrency; ERROR 42S02: Unknown table 'local' in field list SET global innodb_thread_concurrency = 0; @@ -93,4 +93,4 @@ SELECT @@global.innodb_thread_concurrenc SET @@global.innodb_thread_concurrency = @global_start_value; SELECT @@global.innodb_thread_concurrency; @@global.innodb_thread_concurrency -8 +0 === modified file 'mysql-test/suite/sys_vars/r/table_definition_cache_basic.result' --- a/mysql-test/suite/sys_vars/r/table_definition_cache_basic.result 2009-02-27 20:43:43 +0000 +++ b/mysql-test/suite/sys_vars/r/table_definition_cache_basic.result 2009-06-11 10:07:59 +0000 @@ -1,7 +1,7 @@ SET @start_value = @@global.table_definition_cache; SELECT @start_value; @start_value -256 +400 '#--------------------FN_DYNVARS_019_01------------------------#' SET @@global.table_definition_cache = 100; Warnings: @@ -9,12 +9,12 @@ Warning 1292 Truncated incorrect table_d SET @@global.table_definition_cache = DEFAULT; SELECT @@global.table_definition_cache; @@global.table_definition_cache -256 +400 '#---------------------FN_DYNVARS_019_02-------------------------#' SET @@global.table_definition_cache = DEFAULT; -SELECT @@global.table_definition_cache = 128; -@@global.table_definition_cache = 128 -0 +SELECT @@global.table_definition_cache = 400; +@@global.table_definition_cache = 400 +1 '#--------------------FN_DYNVARS_019_03------------------------#' SET @@global.table_definition_cache = 1; Warnings: @@ -109,4 +109,4 @@ ERROR 42S22: Unknown column 'table_defin SET @@global.table_definition_cache = @start_value; SELECT @@global.table_definition_cache; @@global.table_definition_cache -256 +400 === modified file 'mysql-test/suite/sys_vars/r/table_open_cache_basic.result' --- a/mysql-test/suite/sys_vars/r/table_open_cache_basic.result 2009-02-27 20:43:43 +0000 +++ b/mysql-test/suite/sys_vars/r/table_open_cache_basic.result 2009-06-11 10:07:59 +0000 @@ -1,17 +1,17 @@ SET @start_value = @@global.table_open_cache ; SELECT @start_value; @start_value -64 +400 '#--------------------FN_DYNVARS_001_01------------------------#' SET @@global.table_open_cache = 99; SET @@global.table_open_cache = DeFAULT; SELECT @@global.table_open_cache; @@global.table_open_cache -64 +400 '#---------------------FN_DYNVARS_001_02-------------------------#' SET @@global.table_open_cache = Default; -SELECT @@global.table_open_cache = 64; -@@global.table_open_cache = 64 +SELECT @@global.table_open_cache = 400; +@@global.table_open_cache = 400 1 '#--------------------FN_DYNVARS_001_03------------------------#' SET @@global.table_open_cache = 8; @@ -105,4 +105,4 @@ ERROR 42S22: Unknown column 'table_open_ SET @@global.table_open_cache = @start_value; SELECT @@global.table_open_cache ; @@global.table_open_cache -64 +400 === modified file 'mysql-test/suite/sys_vars/t/innodb_file_io_threads_basic.test' --- a/mysql-test/suite/sys_vars/t/innodb_file_io_threads_basic.test 2008-12-19 15:12:15 +0000 +++ b/mysql-test/suite/sys_vars/t/innodb_file_io_threads_basic.test 2009-02-17 12:24:09 +0000 @@ -28,7 +28,9 @@ #################################################################### # Displaying default value # #################################################################### -SELECT COUNT(@@GLOBAL.innodb_file_io_threads); +SELECT COUNT(@@GLOBAL.innodb_read_io_threads); +--echo 1 Expected +SELECT COUNT(@@GLOBAL.innodb_write_io_threads); --echo 1 Expected @@ -38,10 +40,17 @@ SELECT COUNT(@@GLOBAL.innodb_file_io_thr #################################################################### --error ER_INCORRECT_GLOBAL_LOCAL_VAR -SET @@GLOBAL.innodb_file_io_threads=1; +SET @@GLOBAL.innodb_read_io_threads=1; --echo Expected error 'Read only variable' -SELECT COUNT(@@GLOBAL.innodb_file_io_threads); +SELECT COUNT(@@GLOBAL.innodb_read_io_threads); +--echo 1 Expected + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.innodb_write_io_threads=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.innodb_write_io_threads); --echo 1 Expected @@ -52,51 +61,84 @@ SELECT COUNT(@@GLOBAL.innodb_file_io_thr # Check if the value in GLOBAL Table matches value in variable # ################################################################# -SELECT @@GLOBAL.innodb_file_io_threads = VARIABLE_VALUE +SELECT @@GLOBAL.innodb_read_io_threads = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='innodb_file_io_threads'; +WHERE VARIABLE_NAME='innodb_read_io_threads'; --echo 1 Expected -SELECT COUNT(@@GLOBAL.innodb_file_io_threads); +SELECT COUNT(@@GLOBAL.innodb_read_io_threads); --echo 1 Expected SELECT COUNT(VARIABLE_VALUE) FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='innodb_file_io_threads'; +WHERE VARIABLE_NAME='innodb_read_io_threads'; +--echo 1 Expected + +SELECT @@GLOBAL.innodb_write_io_threads = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_write_io_threads'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.innodb_write_io_threads); --echo 1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_write_io_threads'; +--echo 1 Expected --echo '#---------------------BS_STVARS_027_04----------------------#' ################################################################################ # Check if accessing variable with and without GLOBAL point to same variable # ################################################################################ -SELECT @@innodb_file_io_threads = @@GLOBAL.innodb_file_io_threads; +SELECT @@innodb_read_io_threads = @@GLOBAL.innodb_read_io_threads; --echo 1 Expected +SELECT @@innodb_write_io_threads = @@GLOBAL.innodb_write_io_threads; +--echo 1 Expected --echo '#---------------------BS_STVARS_027_05----------------------#' ################################################################################ -# Check if innodb_file_io_threads can be accessed with and without @@ sign # +# Check if innodb_read_io_threads can be accessed with and without @@ sign # +# Check if innodb_write_io_threads can be accessed with and without @@ sign # ################################################################################ -SELECT COUNT(@@innodb_file_io_threads); +SELECT COUNT(@@innodb_read_io_threads); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_read_io_threads); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_read_io_threads); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.innodb_read_io_threads); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT innodb_read_io_threads = @@SESSION.innodb_read_io_threads; +--echo Expected error 'Readonly variable' + +SELECT COUNT(@@innodb_write_io_threads); --echo 1 Expected --Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@local.innodb_file_io_threads); +SELECT COUNT(@@local.innodb_write_io_threads); --echo Expected error 'Variable is a GLOBAL variable' --Error ER_INCORRECT_GLOBAL_LOCAL_VAR -SELECT COUNT(@@SESSION.innodb_file_io_threads); +SELECT COUNT(@@SESSION.innodb_write_io_threads); --echo Expected error 'Variable is a GLOBAL variable' -SELECT COUNT(@@GLOBAL.innodb_file_io_threads); +SELECT COUNT(@@GLOBAL.innodb_write_io_threads); --echo 1 Expected --Error ER_BAD_FIELD_ERROR -SELECT innodb_file_io_threads = @@SESSION.innodb_file_io_threads; +SELECT innodb_write_io_threads = @@SESSION.innodb_write_io_threads; --echo Expected error 'Readonly variable' === modified file 'mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test' --- a/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test 2008-12-19 15:12:15 +0000 +++ b/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test 2009-02-17 12:24:09 +0000 @@ -72,7 +72,7 @@ SELECT @@global.innodb_max_dirty_pages_p SET @@global.innodb_max_dirty_pages_pct = 1; SELECT @@global.innodb_max_dirty_pages_pct; -SET @@global.innodb_max_dirty_pages_pct = 100; +SET @@global.innodb_max_dirty_pages_pct = 99; SELECT @@global.innodb_max_dirty_pages_pct; --echo '#--------------------FN_DYNVARS_046_04-------------------------#' === modified file 'mysql-test/suite/sys_vars/t/innodb_thread_concurrency_basic.test' --- a/mysql-test/suite/sys_vars/t/innodb_thread_concurrency_basic.test 2008-12-19 15:12:15 +0000 +++ b/mysql-test/suite/sys_vars/t/innodb_thread_concurrency_basic.test 2009-02-17 12:24:09 +0000 @@ -4,7 +4,7 @@ # Scope: GLOBAL # # Access Type: Dynamic # # Data Type: Numeric # -# Default Value: 8 # +# Default Value: 0 # # Range: 0-1000 # # # # # === modified file 'mysql-test/suite/sys_vars/t/table_definition_cache_basic.test' --- a/mysql-test/suite/sys_vars/t/table_definition_cache_basic.test 2008-12-19 15:12:15 +0000 +++ b/mysql-test/suite/sys_vars/t/table_definition_cache_basic.test 2009-02-17 12:24:09 +0000 @@ -4,7 +4,7 @@ # Scope: GLOBAL # # Access Type: Dynamic # # Data Type: Numeric # -# Default Value: 128 # +# Default Value: 400 # # Range: 1 - 524288 # # # # # @@ -52,7 +52,7 @@ SELECT @@global.table_definition_cache; ############################################### SET @@global.table_definition_cache = DEFAULT; -SELECT @@global.table_definition_cache = 128; +SELECT @@global.table_definition_cache = 400; --echo '#--------------------FN_DYNVARS_019_03------------------------#' === modified file 'mysql-test/suite/sys_vars/t/table_open_cache_basic.test' --- a/mysql-test/suite/sys_vars/t/table_open_cache_basic.test 2008-12-19 15:12:15 +0000 +++ b/mysql-test/suite/sys_vars/t/table_open_cache_basic.test 2009-02-17 12:24:09 +0000 @@ -4,8 +4,8 @@ # Scope: GLOBAL # # Access Type: Dynamic # # Data Type: numeric # -# Default Value: 64 # -# Range: 1-524288 # +# Default Value: 400 # +# Range: 64-524288 # # # # # # Creation Date: 2008-02-13 # @@ -54,7 +54,7 @@ SELECT @@global.table_open_cache; ############################################### SET @@global.table_open_cache = Default; -SELECT @@global.table_open_cache = 64; +SELECT @@global.table_open_cache = 400; --echo '#--------------------FN_DYNVARS_001_03------------------------#' ######################################################################## === modified file 'mysql-test/t/merge.test' --- a/mysql-test/t/merge.test 2009-04-22 10:02:28 +0000 +++ b/mysql-test/t/merge.test 2009-07-02 16:13:21 +0000 @@ -1412,11 +1412,11 @@ set @save_table_definition_cache=@@globa --echo # --echo # Set @@global.table_definition_cache to minimum --echo # -set @@global.table_definition_cache=256; +set @@global.table_definition_cache=400; set @a=null; -let $1 = 256; +let $1 = 400; --echo # ---echo # Create 256 merge children +--echo # Create 400 merge children --echo # --disable_query_log while ($1) @@ -1448,7 +1448,7 @@ deallocate prepare stmt; --echo # --echo # Cleanup --echo # -let $1 = 256; +let $1 = 400; --disable_query_log while ($1) { === modified file 'mysql-test/t/partition_innodb.test' --- a/mysql-test/t/partition_innodb.test 2008-12-13 11:02:16 +0000 +++ b/mysql-test/t/partition_innodb.test 2009-07-02 14:23:36 +0000 @@ -25,17 +25,21 @@ SET autocommit = 0; UPDATE t1 SET DATA = data*2 WHERE id = 3; +# SHOW ENGINE InnoDB STATUS does not show transaction info in +# PERFORMANCE-VERSION # grouping/referencing in replace_regex is very slow on long strings, # removing all before/after the interesting row before grouping/referencing ---replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ -SHOW ENGINE InnoDB STATUS; +#--replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+) lock struct\(s\), heap size [0-9]+, ([0-9]+) row lock\(s\).*/\1 lock struct(s) \2 row lock(s)/ +#SHOW ENGINE InnoDB STATUS; UPDATE t1 SET data = data*2 WHERE data = 2; +# SHOW ENGINE InnoDB STATUS does not show transaction info in +# PERFORMANCE-VERSION # grouping/referencing in replace_regex is very slow on long strings, # removing all before/after the interesting row before grouping/referencing ---replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ -SHOW ENGINE InnoDB STATUS; +#--replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ +#SHOW ENGINE InnoDB STATUS; SET @@session.tx_isolation = @old_tx_isolation; === modified file 'mysys/Makefile.am' --- a/mysys/Makefile.am 2009-02-07 15:47:14 +0000 +++ b/mysys/Makefile.am 2009-07-02 14:23:36 +0000 @@ -25,6 +25,7 @@ LDADD = $(top_builddir)/strings/libmys pkglib_LTLIBRARIES = libmysys.la libmysys_la_LDFLAGS = -static libmysys_la_SOURCES = +libmysys_la_DEPENDENCIES = # This can't be listed here as $(top_builddir)/mysys/libmysyslt.la # or it breaks make's dependency track for -j builds libmysys_la_LIBADD = libmysyslt.la libmysyswrap.la @@ -87,3 +88,24 @@ DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" -DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX \ -DDEFAULT_SYSCONFDIR="\"$(sysconfdir)\"" \ @DEFS@ + +if HAVE_DTRACE_DASH_G +libmysys_la_LIBADD += probes_mysql.o +libmysys_la_DEPENDENCIES += probes_mysql.o dtrace_files dtrace_providers +CLEANFILES = probes_mysql.o dtrace_files dtrace_providers +DTRACEFILES = mf_keycache.o +DTRACEPROVIDER = probes_mysql.d +CLEANFILES += $(DTRACEPROVIDER) dtrace_sources + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'mysys/mf_keycache.c' --- a/mysys/mf_keycache.c 2009-04-30 14:35:36 +0000 +++ b/mysys/mf_keycache.c 2009-07-02 14:23:36 +0000 @@ -112,6 +112,7 @@ #include #include #include +#include "probes_mysql.h" /* Some compilation flags have been added specifically for this module @@ -2581,6 +2582,15 @@ uchar *key_cache_read(KEY_CACHE *keycach uint offset; int page_st; + if (MYSQL_KEYCACHE_READ_START_ENABLED()) + { + MYSQL_KEYCACHE_READ_START(my_filename(file), length, + (ulong) (keycache->blocks_used * + keycache->key_cache_block_size), + (ulong) (keycache->blocks_unused * + keycache->key_cache_block_size)); + } + /* When the key cache is once initialized, we use the cache_lock to reliably distinguish the cases of normal operation, resizing, and @@ -2633,6 +2643,9 @@ uchar *key_cache_read(KEY_CACHE *keycach /* Request the cache block that matches file/pos. */ keycache->global_cache_r_requests++; + + MYSQL_KEYCACHE_READ_BLOCK(keycache->key_cache_block_size); + block=find_key_block(keycache, file, filepos, level, 0, &page_st); if (!block) { @@ -2652,6 +2665,7 @@ uchar *key_cache_read(KEY_CACHE *keycach { if (page_st != PAGE_READ) { + MYSQL_KEYCACHE_READ_MISS(); /* The requested page is to be read into the block buffer */ read_block(keycache, block, keycache->key_cache_block_size, read_length+offset, @@ -2676,6 +2690,10 @@ uchar *key_cache_read(KEY_CACHE *keycach my_errno= -1; block->status|= BLOCK_ERROR; } + else + { + MYSQL_KEYCACHE_READ_HIT(); + } } /* block status may have added BLOCK_ERROR in the above 'if'. */ @@ -2728,7 +2746,16 @@ uchar *key_cache_read(KEY_CACHE *keycach #ifndef THREAD /* This is only true if we where able to read everything in one block */ if (return_buffer) + { + if (MYSQL_KEYCACHE_READ_DONE_ENABLED()) + { + MYSQL_KEYCACHE_READ_DONE((ulong) (keycache->blocks_used * + keycache->key_cache_block_size), + (ulong) (keycache->blocks_unused * + keycache->key_cache_block_size)); + } DBUG_RETURN(block->buffer); + } #endif next_block: buff+= read_length; @@ -2736,6 +2763,13 @@ uchar *key_cache_read(KEY_CACHE *keycach offset= 0; } while ((length-= read_length)); + if (MYSQL_KEYCACHE_READ_DONE_ENABLED()) + { + MYSQL_KEYCACHE_READ_DONE((ulong) (keycache->blocks_used * + keycache->key_cache_block_size), + (ulong) (keycache->blocks_unused * + keycache->key_cache_block_size)); + } goto end; } KEYCACHE_DBUG_PRINT("key_cache_read", ("keycache not initialized")); @@ -3080,6 +3114,15 @@ int key_cache_write(KEY_CACHE *keycache, uint offset; int page_st; + if (MYSQL_KEYCACHE_WRITE_START_ENABLED()) + { + MYSQL_KEYCACHE_WRITE_START(my_filename(file), length, + (ulong) (keycache->blocks_used * + keycache->key_cache_block_size), + (ulong) (keycache->blocks_unused * + keycache->key_cache_block_size)); + } + /* When the key cache is once initialized, we use the cache_lock to reliably distinguish the cases of normal operation, resizing, and @@ -3115,6 +3158,8 @@ int key_cache_write(KEY_CACHE *keycache, /* Cache could be disabled in a later iteration. */ if (!keycache->can_be_used) goto no_key_cache; + + MYSQL_KEYCACHE_WRITE_BLOCK(keycache->key_cache_block_size); /* Start writing at the beginning of the cache block. */ filepos-= offset; /* Do not write beyond the end of the cache block. */ @@ -3332,6 +3377,15 @@ end: dec_counter_for_resize_op(keycache); keycache_pthread_mutex_unlock(&keycache->cache_lock); } + + if (MYSQL_KEYCACHE_WRITE_DONE_ENABLED()) + { + MYSQL_KEYCACHE_WRITE_DONE((ulong) (keycache->blocks_used * + keycache->key_cache_block_size), + (ulong) (keycache->blocks_unused * + keycache->key_cache_block_size)); + } + #if !defined(DBUG_OFF) && defined(EXTRA_DEBUG) DBUG_EXECUTE("exec", test_key_cache(keycache, "end of key_cache_write", 1);); === modified file 'scripts/Makefile.am' --- a/scripts/Makefile.am 2009-03-20 16:14:49 +0000 +++ b/scripts/Makefile.am 2009-07-02 14:23:36 +0000 @@ -36,7 +36,8 @@ bin_SCRIPTS = @server_scripts@ \ mysqld_multi noinst_SCRIPTS = make_binary_distribution \ - make_sharedlib_distribution + make_sharedlib_distribution \ + dheadgen.pl EXTRA_SCRIPTS = make_binary_distribution.sh \ make_sharedlib_distribution.sh \ @@ -57,7 +58,8 @@ EXTRA_SCRIPTS = make_binary_distributio mysqlhotcopy.sh \ mysqldumpslow.sh \ mysqld_multi.sh \ - mysqld_safe.sh + mysqld_safe.sh \ + dheadgen.pl EXTRA_DIST = $(EXTRA_SCRIPTS) \ mysqlaccess.conf \ @@ -121,7 +123,7 @@ mysql_fix_privilege_tables_sql.c: comp_s sleep 2 $(top_builddir)/scripts/comp_sql$(EXEEXT) \ mysql_fix_privilege_tables \ - $(top_srcdir)/scripts/mysql_fix_privilege_tables.sql $@ + $(top_builddir)/scripts/mysql_fix_privilege_tables.sql $@ SUFFIXES = .sh === added file 'scripts/dheadgen.pl' --- a/scripts/dheadgen.pl 1970-01-01 00:00:00 +0000 +++ b/scripts/dheadgen.pl 2009-06-04 16:47:38 +0000 @@ -0,0 +1,338 @@ +#!/usr/bin/perl -w + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of the above-listed copyright holders nor the names +# of its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ident "@(#)dheadgen.pl 1.4 07/06/24 SMI" + +# +# DTrace Header Generator +# ----------------------- +# +# This script is meant to mimic the output of dtrace(1M) with the -h +# (headergen) flag on system that lack native support for DTrace. This script +# is intended to be integrated into projects that use DTrace's static tracing +# facilities (USDT), and invoked as part of the build process to have a +# common build process on all target systems. To facilitate this, this script +# is licensed under a BSD license. On system with native DTrace support, the +# dtrace(1M) command will be invoked to create the full header file; on other +# systems, this script will generated a stub header file. +# +# Normally, generated macros take the form PROVIDER_PROBENAME(). It may be +# desirable to customize the output of this script and of dtrace(1M) to +# tailor the precise macro name. To do this, edit the emit_dtrace() subroutine +# to pattern match for the lines you want to customize. +# + +use strict; + +my @lines; +my @tokens = (); +my $lineno = 0; +my $newline = 1; +my $eof = 0; +my $infile; +my $outfile; +my $force = 0; + +sub emit_dtrace { + my ($line) = @_; + + # + # Insert customization here. For example, if you want to change the + # name of the macros you may do something like this: + # + # $line =~ s/(\s)[A-Z]+_/\1TRACE_MOZILLA_/; + # + + print $line; +} + +# +# The remaining code deals with parsing D provider definitions and emitting +# the stub header file. There should be no need to edit this absent a bug. +# + +# +# Emit the two relevant macros for each probe in the given provider: +# PROVIDER_PROBENAME() +# PROVIDER_PROBENAME_ENABLED() (0) +# +sub emit_provider { + my ($provname, @probes) = @_; + + $provname = uc($provname); + + foreach my $probe (@probes) { + my $probename = uc($$probe{'name'}); + my $argc = $$probe{'argc'}; + my $line; + + $probename =~ s/__/_/g; + + $line = "#define\t${provname}_${probename}("; + for (my $i = 0; $i < $argc; $i++) { + $line .= ($i == 0 ? '' : ', '); + $line .= "arg$i"; + } + $line .= ")\n"; + emit_dtrace($line); + + $line = "#define\t${provname}_${probename}_ENABLED() (0)\n"; + emit_dtrace($line); + } + + emit_dtrace("\n"); +} + +sub emit_prologue { + my ($filename) = @_; + + $filename =~ s/.*\///g; + $filename = uc($filename); + $filename =~ s/\./_/g; + + emit_dtrace <<"EOF"; +/* + * Generated by dheadgen(1). + */ + +#ifndef\t_${filename} +#define\t_${filename} + +#ifdef\t__cplusplus +extern "C" { +#endif + +EOF +} + +sub emit_epilogue { + my ($filename) = @_; + + $filename =~ s/.*\///g; + $filename = uc($filename); + $filename =~ s/\./_/g; + + emit_dtrace <<"EOF"; +#ifdef __cplusplus +} +#endif + +#endif /* _$filename */ +EOF +} + +# +# Get the next token from the file keeping track of the line number. +# +sub get_token { + my ($eof_ok) = @_; + my $tok; + + while (1) { + while (scalar(@tokens) == 0) { + if (scalar(@lines) == 0) { + $eof = 1; + return if ($eof_ok); + die "expected more data at line $lineno"; + } + + $lineno++; + push(@tokens, split(/(\s+|\n|[(){},#;]|\/\*|\*\/)/, + shift(@lines))); + } + + $tok = shift(@tokens); + next if ($tok eq ''); + next if ($tok =~ /^[ \t]+$/); + + return ($tok); + } +} + +# +# Ignore newlines, comments and typedefs +# +sub next_token { + my ($eof_ok) = @_; + my $tok; + + while (1) { + $tok = get_token($eof_ok); + return if ($eof_ok && $eof); + if ($tok eq "typedef" or $tok =~ /^#/) { + while (1) { + $tok = get_token(0); + last if ($tok eq "\n"); + } + next; + } elsif ($tok eq '/*') { + while (get_token(0) ne '*/') { + next; + } + next; + } elsif ($tok eq "\n") { + next; + } + + last; + } + + return ($tok); +} + +sub expect_token { + my ($t) = @_; + my $tok; + + while (($tok = next_token(0)) eq "\n") { + next; + } + + die "expected '$t' at line $lineno rather than '$tok'" if ($t ne $tok); +} + +sub get_args { + expect_token('('); + + my $tok = next_token(0); + my @args = (); + + return (@args) if ($tok eq ')'); + + if ($tok eq 'void') { + expect_token(')'); + return (@args); + } + + my $arg = $tok; + + while (1) { + $tok = next_token(0); + if ($tok eq ',' || $tok eq ')') { + push(@args, $arg); + $arg = ''; + last if ($tok eq ')'); + } else { + $arg = "$arg $tok"; + } + } + + return (@args); +} + +sub usage { + die "usage: $0 [-f] \n"; +} + +usage() if (scalar(@ARGV) < 1); +if ($ARGV[0] eq '-f') { + usage() if (scalar(@ARGV < 2)); + $force = 1; + shift; +} +$infile = $ARGV[0]; +usage() if ($infile !~ /(.+)\.d$/); + +# +# If the system has native support for DTrace, we'll use that binary instead. +# +if (-x '/usr/sbin/dtrace' && !$force) { + open(DTRACE, "-| /usr/sbin/dtrace -C -h -s $infile -o /dev/stdout") + or die "can't invoke dtrace(1M)"; + + while () { + emit_dtrace($_); + } + + close(DTRACE); + + exit(0); +} + +emit_prologue($infile); + +open(D, "< $infile") or die "couldn't open $infile"; +@lines = ; +close(D); + +while (1) { + my $nl = 0; + my $tok = next_token(1); + last if $eof; + + if ($newline && $tok eq '#') { + while (1) { + $tok = get_token(0); + + last if ($tok eq "\n"); + } + $nl = 1; + } elsif ($tok eq "\n") { + $nl = 1; + } elsif ($tok eq 'provider') { + my $provname = next_token(0); + my @probes = (); + expect_token('{'); + + while (1) { + $tok = next_token(0); + if ($tok eq 'probe') { + my $probename = next_token(0); + my @args = get_args(); + + next while (next_token(0) ne ';'); + + push(@probes, { + 'name' => $probename, + 'argc' => scalar(@args) + }); + + } elsif ($tok eq '}') { + expect_token(';'); + + emit_provider($provname, @probes); + + last; + } + } + + } else { + die "syntax error at line $lineno near '$tok'\n"; + } + + $newline = $nl; +} + +emit_epilogue($infile); + +exit(0); === modified file 'scripts/make_binary_distribution.sh' --- a/scripts/make_binary_distribution.sh 2009-04-14 21:07:28 +0000 +++ b/scripts/make_binary_distribution.sh 2009-07-02 14:23:36 +0000 @@ -342,7 +342,6 @@ BIN_FILES="extra/comp_err$BS extra/repla storage/myisam/myisamlog$BS storage/myisam/myisam_ftdump$BS \ sql/mysqld$BS sql/mysqld-debug$BS \ sql/mysql_tzinfo_to_sql$BS \ - server-tools/instance-manager/mysqlmanager$BS \ client/mysql$BS client/mysqlshow$BS client/mysqladmin$BS \ client/mysqlslap$BS \ client/mysqldump$BS client/mysqlimport$BS \ === modified file 'sql/Makefile.am' --- a/sql/Makefile.am 2009-06-08 14:58:33 +0000 +++ b/sql/Makefile.am 2009-07-02 15:02:45 +0000 @@ -28,23 +28,40 @@ SUBDIRS = share backup libexec_PROGRAMS = mysqld EXTRA_PROGRAMS = gen_lex_hash bin_PROGRAMS = mysql_tzinfo_to_sql -DTRACE = @DTRACE@ -DTRACEFLAGS = @DTRACEFLAGS@ DTRACEFILES = filesort.o \ - handler.o \ - mysqld.o \ - net_serv.o \ - scheduler.o \ - sp_head.o \ - sql_cache.o \ - sql_connect.o \ - sql_cursor.o \ - sql_delete.o \ - sql_insert.o \ - sql_parse.o \ - sql_prepare.o \ - sql_select.o \ - sql_update.o + .libs/libndb_la-ha_ndbcluster.o \ + handler.o \ + mysqld.o \ + net_serv.o \ + scheduler.o \ + sp_head.o \ + sql_cache.o \ + sql_connect.o \ + sql_cursor.o \ + sql_delete.o \ + sql_insert.o \ + sql_parse.o \ + sql_prepare.o \ + sql_select.o \ + sql_update.o + +DTRACEFILES_DEPEND = filesort.o \ + libndb_la-ha_ndbcluster.lo \ + handler.o \ + mysqld.o \ + net_serv.o \ + scheduler.o \ + sp_head.o \ + sql_cache.o \ + sql_connect.o \ + sql_cursor.o \ + sql_delete.o \ + sql_insert.o \ + sql_parse.o \ + sql_prepare.o \ + sql_select.o \ + sql_update.o + noinst_LTLIBRARIES= libndb.la \ udf_example.la @@ -100,7 +117,7 @@ noinst_HEADERS = item.h item_func.h item sql_plugin.h authors.h event_parse_data.h \ event_data_objects.h event_scheduler.h \ sql_partition.h partition_info.h partition_element.h \ - probes.h sql_audit.h transaction.h \ + sql_audit.h transaction.h \ contributors.h sql_servers.h bml.h \ si_objects.h si_logs.h sql_plist.h mdl.h records.h \ sql_signal.h \ @@ -157,10 +174,6 @@ mysqld_SOURCES = sql_lex.cc sql_handler. sql_signal.cc \ rpl_handler.cc -if HAVE_DTRACE - mysqld_SOURCES += probes.d -endif - nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c libndb_la_CPPFLAGS= @ndbcluster_includes@ $(AM_CPPFLAGS) @@ -223,12 +236,6 @@ lex_hash.h: gen_lex_hash.cc lex.h udf_example_la_SOURCES= udf_example.c udf_example_la_LDFLAGS= -module -rpath $(pkglibdir) -probes.h: probes.d - $(DTRACE) $(DTRACEFLAGS) -h -s probes.d - mv probes.h probes.h.bak - sed "s/#include //g" probes.h.bak > probes.h - rm probes.h.bak - # We might have some stuff not built in this build, but that we want to install install-exec-hook: $(mkinstalldirs) $(DESTDIR)$(libexecdir) $(DESTDIR)$(pkglibdir) @@ -236,9 +243,38 @@ install-exec-hook: test ! -f mysqld-debug.sym.gz || $(INSTALL_DATA) mysqld-debug.sym.gz $(DESTDIR)$(pkglibdir) test ! -f mysqld.sym.gz || $(INSTALL_DATA) mysqld.sym.gz $(DESTDIR)$(pkglibdir) -SUFFIXES : .d - -.d.o : - $(DTRACE) $(DTRACEFLAGS) -G -s $< $(DTRACEFILES) +if HAVE_DTRACE_DASH_G +libndb_la_LIBADD = probes_libndb.o +libndb_la_DEPENDENCIES = dtrace_files dtrace_providers probes_libndb.o +mysqld_LDADD += probes_all.o +mysqld_DEPENDENCIES += dtrace_files dtrace_providers probes_all.o +CLEANFILES += dtrace_files dtrace_providers probes_all.o +DTRACEPROVIDER = probes_mysql.d +CLEANFILES += $(DTRACEPROVIDER) + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + +DTRACEDIRS = . ../mysys $(patsubst %,$(top_builddir)/storage/%,@mysql_se_dirs@) + +probes_all.o: probes_mysql.d $(DTRACEFILES_DEPEND) + providers=`(for i in $(DTRACEDIRS); do cat $$i/dtrace_providers 2>/dev/null; done) | tr " " "\n" | sort | uniq | sed -e '/^$$/d' -e 's/^/-s /'`; \ + objects=`for i in $(DTRACEDIRS); do f=\`cat $$i/dtrace_files 2>/dev/null\`; for j in $$f; do test -f $$i/$$j && echo "$$i/$$j "; done; done`; \ + $(DTRACE) $(DTRACEFLAGS) -G $$providers $$objects -o $@ + +# Can't depend directly on .libs/*.o, because there is no generated rule for +# that in the Makefile; it is a byproduct of *.lo +probes_libndb.o: probes_mysql.d libndb_la-ha_ndbcluster.lo + if test -f .libs/libndb_la-ha_ndbcluster.o ; then \ + $(DTRACE) $(DTRACEFLAGS) -G -s probes_mysql.d .libs/libndb_la-ha_ndbcluster.o -o $@; \ + fi; \ + if test -f libndb_la-ha_ndbcluster.o ; then \ + $(DTRACE) $(DTRACEFLAGS) -G -s probes_mysql.d libndb_la-ha_ndbcluster.o -o $@; \ + fi -probes.o : $(DTRACEFILES) +endif === modified file 'sql/filesort.cc' --- a/sql/filesort.cc 2009-02-13 16:30:54 +0000 +++ b/sql/filesort.cc 2009-07-02 14:23:36 +0000 @@ -27,6 +27,7 @@ #endif #include #include "sql_sort.h" +#include "probes_mysql.h" #ifndef THREAD #define SKIP_DBUG_IN_FILESORT === modified file 'sql/ha_ndbcluster.cc' --- a/sql/ha_ndbcluster.cc 2009-05-15 13:45:06 +0000 +++ b/sql/ha_ndbcluster.cc 2009-07-02 14:23:36 +0000 @@ -29,6 +29,14 @@ #include "mysql_priv.h" #include "rpl_mi.h" +/* + There is an incompatibility between GNU ar and the Solaris linker + which makes the Solaris linker return an elf error when compiling + without NDB support (which makes libndb.a an empty library). + To avoid this we add a dummy declaration of a static variable + which makes us avoid this bug. +*/ +int ha_ndb_dummy; #include #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE #include "ha_ndbcluster.h" @@ -42,6 +50,7 @@ #include "ha_ndbcluster_connection.h" #include +#include "probes_mysql.h" #ifdef ndb_dynamite #undef assert @@ -141,6 +150,13 @@ static uint ndbcluster_alter_partition_f DBUG_RETURN(ndb_to_mysql_error(&tmp)); \ } +#define ERR_RETURN_PREPARE(rc, err) \ +{ \ + const NdbError& tmp= err; \ + set_ndb_err(current_thd, tmp); \ + rc= ndb_to_mysql_error(&tmp); \ +} + #define ERR_BREAK(err, code) \ { \ const NdbError& tmp= err; \ @@ -3707,9 +3723,11 @@ int ha_ndbcluster::index_read(uchar *buf { key_range start_key; bool descending= FALSE; + int rc; DBUG_ENTER("ha_ndbcluster::index_read"); DBUG_PRINT("enter", ("active_index: %u, key_len: %u, find_flag: %d", active_index, key_len, find_flag)); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); start_key.key= key; start_key.length= key_len; @@ -3725,43 +3743,61 @@ int ha_ndbcluster::index_read(uchar *buf default: break; } - DBUG_RETURN(read_range_first_to_buf(&start_key, 0, descending, - m_sorted, buf)); + rc= read_range_first_to_buf(&start_key, 0, descending, + m_sorted, buf); + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_ndbcluster::index_next(uchar *buf) { + int rc; DBUG_ENTER("ha_ndbcluster::index_next"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_next_count); - DBUG_RETURN(next_result(buf)); + rc= next_result(buf); + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_ndbcluster::index_prev(uchar *buf) { + int rc; DBUG_ENTER("ha_ndbcluster::index_prev"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_prev_count); - DBUG_RETURN(next_result(buf)); + rc= next_result(buf); + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_ndbcluster::index_first(uchar *buf) { + int rc; DBUG_ENTER("ha_ndbcluster::index_first"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_first_count); // Start the ordered index scan and fetch the first row // Only HA_READ_ORDER indexes get called by index_first - DBUG_RETURN(ordered_index_scan(0, 0, TRUE, FALSE, buf, NULL)); + rc= ordered_index_scan(0, 0, TRUE, FALSE, buf, NULL); + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_ndbcluster::index_last(uchar *buf) { + int rc; DBUG_ENTER("ha_ndbcluster::index_last"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_last_count); - DBUG_RETURN(ordered_index_scan(0, 0, TRUE, TRUE, buf, NULL)); + rc= ordered_index_scan(0, 0, TRUE, TRUE, buf, NULL); + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_ndbcluster::index_read_last(uchar * buf, const uchar * key, uint key_len) @@ -3852,16 +3888,24 @@ int ha_ndbcluster::read_range_first(cons const key_range *end_key, bool eq_r, bool sorted) { + int rc; uchar* buf= table->record[0]; DBUG_ENTER("ha_ndbcluster::read_range_first"); - DBUG_RETURN(read_range_first_to_buf(start_key, end_key, FALSE, - sorted, buf)); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= read_range_first_to_buf(start_key, end_key, FALSE, + sorted, buf); + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_ndbcluster::read_range_next() { + int rc; DBUG_ENTER("ha_ndbcluster::read_range_next"); - DBUG_RETURN(next_result(table->record[0])); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= next_result(table->record[0]); + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -3932,12 +3976,18 @@ int ha_ndbcluster::rnd_end() int ha_ndbcluster::rnd_next(uchar *buf) { + int rc; DBUG_ENTER("rnd_next"); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); ha_statistic_increment(&SSV::ha_read_rnd_next_count); if (!m_active_cursor) - DBUG_RETURN(full_table_scan(NULL, NULL, 0, buf)); - DBUG_RETURN(next_result(buf)); + rc= full_table_scan(NULL, NULL, 0, buf); + else + rc= next_result(buf); + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -3949,7 +3999,10 @@ int ha_ndbcluster::rnd_next(uchar *buf) int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos) { + int rc; DBUG_ENTER("rnd_pos"); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + FALSE); ha_statistic_increment(&SSV::ha_read_rnd_count); // The primary key for the record is stored in pos // Perform a pk_read using primary key "index" @@ -3982,7 +4035,9 @@ int ha_ndbcluster::rnd_pos(uchar *buf, u DBUG_PRINT("info", ("partition id %u", part_spec.start_part)); } DBUG_DUMP("key", pos, key_length); - DBUG_RETURN(pk_read(pos, key_length, buf, part_spec.start_part)); + rc= pk_read(pos, key_length, buf, part_spec.start_part); + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } } @@ -9516,7 +9571,7 @@ int ha_ndbcluster::multi_range_read_init DBUG_RETURN(handler::multi_range_read_init(seq_funcs, seq_init_param, n_ranges, mode, buffer)); } - + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); m_disable_multi_read= FALSE; mrr_is_output_sorted= test(mode & HA_MRR_SORTED); @@ -9563,6 +9618,7 @@ int ha_ndbcluster::multi_range_start_ret NDB_INDEX_TYPE cur_index_type= get_index_type(active_index); const NdbOperation *oplist[MRR_MAX_RANGES]; uint num_keyops= 0; + int res; DBUG_ENTER("multi_range_start_retrievals"); /* @@ -9695,7 +9751,11 @@ int ha_ndbcluster::multi_range_start_ret get_hidden_fields_scan(&options, gets); if (m_cond && m_cond->generate_scan_filter(&code, &options)) - ERR_RETURN(code.getNdbError()); + { + ERR_RETURN_PREPARE(res, code.getNdbError()); + MYSQL_READ_ROW_DONE(res); + DBUG_RETURN(res); + } /* Define scan */ NdbIndexScanOperation *scanOp= m_thd_ndb->trans->scanIndex @@ -9708,8 +9768,11 @@ int ha_ndbcluster::multi_range_start_ret sizeof(NdbScanOperation::ScanOptions)); if (!scanOp) - ERR_RETURN(m_thd_ndb->trans->getNdbError()); - + { + ERR_RETURN_PREPARE(res, m_thd_ndb->trans->getNdbError()); + MYSQL_READ_ROW_DONE(res); + DBUG_RETURN(res); + } m_multi_cursor= scanOp; /* @@ -9731,7 +9794,9 @@ int ha_ndbcluster::multi_range_start_ret if (m_multi_cursor->setBound(m_index[active_index].ndb_record_key, bound)) { - ERR_RETURN(m_thd_ndb->trans->getNdbError()); + ERR_RETURN_PREPARE(res, m_thd_ndb->trans->getNdbError()); + MYSQL_READ_ROW_DONE(res); + DBUG_RETURN(res); } multi_range_entry_type(row_buf)= enum_ordered_range; @@ -9756,14 +9821,22 @@ int ha_ndbcluster::multi_range_start_ret mrr_cur_range.start_key.key, multi_range_row(row_buf), lm, ppartitionId))) - ERR_RETURN(m_thd_ndb->trans->getNdbError()); + { + ERR_RETURN_PREPARE(res, m_thd_ndb->trans->getNdbError()); + MYSQL_READ_ROW_DONE(res); + DBUG_RETURN(res); + } oplist[num_keyops++]= op; row_buf= multi_range_next_entry(row_buf, reclength); } } if (execute_no_commit_ie(this, m_thd_ndb->trans)) - ERR_RETURN(m_thd_ndb->trans->getNdbError()); + { + ERR_RETURN_PREPARE(res, m_thd_ndb->trans->getNdbError()); + MYSQL_READ_ROW_DONE(res); + DBUG_RETURN(res); + } if (!m_range_res) { @@ -9823,25 +9896,27 @@ int ha_ndbcluster::multi_range_start_ret (But we can still safely return an error code in non-debug builds). */ DBUG_ASSERT(FALSE); + MYSQL_READ_ROW_DONE(error.code); ERR_RETURN(error); /* purecov: deadcode */ } } op_idx++; } - + MYSQL_READ_ROW_DONE(0); DBUG_RETURN(0); } int ha_ndbcluster::multi_range_read_next(char **range_info) { int res; - DBUG_ENTER("ha_ndbcluster::multi_range_read_next"); + DBUG_ENTER("ha_ndbcluster::read_multi_range_next"); if (m_disable_multi_read) { DBUG_RETURN(handler::multi_range_read_next(range_info)); } + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); for(;;) { @@ -9880,12 +9955,12 @@ int ha_ndbcluster::multi_range_read_next expected_range_no, range_info); memcpy(table->record[0], multi_range_row(row_buf), table_share->reclength); + MYSQL_INDEX_READ_ROW_DONE(0); DBUG_RETURN(0); case enum_ordered_range: /* An index scan range. */ { - int res; if ((res= read_multi_range_fetch_next()) != 0) { multi_range_get_custom(multi_range_buffer, @@ -9894,6 +9969,7 @@ int ha_ndbcluster::multi_range_read_next m_multi_range_result_ptr= multi_range_next_entry(m_multi_range_result_ptr, table_share->reclength); + MYSQL_INDEX_READ_ROW_DONE(res); DBUG_RETURN(res); } } @@ -9935,7 +10011,7 @@ int ha_ndbcluster::multi_range_read_next pk operation. */ m_active_cursor= m_multi_cursor; - + MYSQL_INDEX_READ_ROW_DONE(0); DBUG_RETURN(0); } else if (current_range_no > expected_range_no) @@ -9963,15 +10039,20 @@ int ha_ndbcluster::multi_range_read_next multi_range_next_entry(m_multi_range_result_ptr, table_share->reclength); } - if (first_running_range == ranges_in_seq) - DBUG_RETURN(HA_ERR_END_OF_FILE); - - /* - Read remaining ranges - */ - if ((res= multi_range_start_retrievals(first_running_range))) - DBUG_RETURN(res); + if (first_running_range == ranges_in_seq) + { + MYSQL_INDEX_READ_ROW_DONE(HA_ERR_END_OF_FILE); + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + /* + Read remaining ranges + */ + if ((res= multi_range_start_retrievals(first_running_range))) + { + MYSQL_INDEX_READ_ROW_DONE(res); + DBUG_RETURN(res); + } } } === modified file 'sql/handler.cc' --- a/sql/handler.cc 2009-06-09 16:53:34 +0000 +++ b/sql/handler.cc 2009-07-02 14:23:36 +0000 @@ -29,6 +29,7 @@ #include #include "myisam.h" #include "transaction.h" +#include "probes_mysql.h" #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" @@ -5465,6 +5466,9 @@ int handler::ha_external_lock(THD *thd, */ int error= external_lock(thd, lock_type); + if (error == 0) + cached_table_flags= table_flags(); + if (MYSQL_HANDLER_RDLOCK_DONE_ENABLED() || MYSQL_HANDLER_WRLOCK_DONE_ENABLED() || MYSQL_HANDLER_UNLOCK_DONE_ENABLED()) @@ -5482,9 +5486,6 @@ int handler::ha_external_lock(THD *thd, MYSQL_HANDLER_UNLOCK_DONE(error); } } - - if (error == 0) - cached_table_flags= table_flags(); DBUG_RETURN(error); } @@ -5524,6 +5525,7 @@ int handler::ha_write_row(uchar *buf) if (unlikely(error != 0)) DBUG_RETURN(error); + if (unlikely(error= binlog_log_row(table, 0, buf, log_func))) DBUG_RETURN(error); /* purecov: inspected */ DBUG_RETURN(0); === modified file 'sql/mysql_priv.h' --- a/sql/mysql_priv.h 2009-06-24 08:14:35 +0000 +++ b/sql/mysql_priv.h 2009-07-03 12:25:24 +0000 @@ -330,9 +330,9 @@ enum open_table_mode #define MAX_ACCEPT_RETRY 10 // Test accept this many times #define MAX_FIELDS_BEFORE_HASH 32 #define USER_VARS_HASH_SIZE 16 -#define TABLE_OPEN_CACHE_MIN 64 -#define TABLE_OPEN_CACHE_DEFAULT 64 -#define TABLE_DEF_CACHE_DEFAULT 256 +#define TABLE_OPEN_CACHE_MIN 400 +#define TABLE_OPEN_CACHE_DEFAULT 400 +#define TABLE_DEF_CACHE_DEFAULT 400 /** We must have room for at least 256 table definitions in the table cache, since otherwise there is no chance prepared @@ -346,7 +346,7 @@ enum open_table_mode for now the only solution is to ensure that the table definition cache can contain at least all tables of a given statement. */ -#define TABLE_DEF_CACHE_MIN 256 +#define TABLE_DEF_CACHE_MIN 400 /* Stack reservation. @@ -1202,12 +1202,14 @@ bool mysql_prepare_update(THD *thd, TABL int mysql_update(THD *thd,TABLE_LIST *tables,List &fields, List &values,COND *conds, uint order_num, ORDER *order, ha_rows limit, - enum enum_duplicates handle_duplicates, bool ignore); + enum enum_duplicates handle_duplicates, bool ignore, + ha_rows *found_return, ha_rows *updated_return); bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, List *values, COND *conds, ulonglong options, enum enum_duplicates handle_duplicates, bool ignore, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, + multi_update **result); bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2009-07-02 08:12:35 +0000 +++ b/sql/mysqld.cc 2009-07-03 12:25:24 +0000 @@ -30,6 +30,7 @@ #include "sql_audit.h" #include "debug_sync.h" #include +#include "probes_mysql.h" #include "../storage/myisam/ha_myisam.h" @@ -130,6 +131,16 @@ extern "C" { // Because of SCO 3.2V4 #define SIGNAL_FMT "signal %d" #endif +#ifdef HAVE_SOLARIS_LARGE_PAGES +#include +#if defined(__sun__) && defined(__GNUC__) && defined(__cplusplus) \ + && defined(_XOPEN_SOURCE) +extern int getpagesizes(size_t *, int); +extern int getpagesizes2(size_t *, int); +extern int memcntl(caddr_t, size_t, int, caddr_t, int, int); +#endif /* __sun__ ... */ +#endif /* HAVE_SOLARIS_LARGE_PAGES */ + #ifdef __NETWARE__ #define zVOLSTATE_ACTIVE 6 #define zVOLSTATE_DEACTIVE 2 @@ -524,6 +535,7 @@ my_bool opt_log_slow_admin_statements= 0 my_bool opt_log_slow_slave_statements= 0; my_bool lower_case_file_system= 0; my_bool opt_large_pages= 0; +my_bool opt_super_large_pages= 0; my_bool opt_myisam_use_mmap= 0; uint opt_large_page_size= 0; #if defined(ENABLED_DEBUG_SYNC) @@ -1990,6 +2002,10 @@ void close_connection(THD *thd, uint err if (lock) (void) pthread_mutex_unlock(&LOCK_thread_count); MYSQL_CONNECTION_DONE((int) errcode, thd->thread_id); + if (MYSQL_CONNECTION_DONE_ENABLED()) + { + sleep(0); /* Workaround to avoid tailcall optimisation */ + } DBUG_VOID_RETURN; } #endif /* EMBEDDED_LIBRARY */ @@ -3429,10 +3445,71 @@ static int init_common_variables(const c /* Initialize large page size */ if (opt_large_pages && (opt_large_page_size= my_get_large_page_size())) { + DBUG_PRINT("info", ("Large page set, large_page_size = %d", + opt_large_page_size)); my_use_large_pages= 1; my_large_page_size= opt_large_page_size; } + else + { + opt_large_pages= 0; + /* + Either not configured to use large pages or Linux haven't + been compiled with large page support + */ + } #endif /* HAVE_LARGE_PAGES */ +#ifdef HAVE_SOLARIS_LARGE_PAGES +#define LARGE_PAGESIZE (4*1024*1024) /* 4MB */ +#define SUPER_LARGE_PAGESIZE (256*1024*1024) /* 256MB */ + if (opt_large_pages) + { + /* + tell the kernel that we want to use 4/256MB page for heap storage + and also for the stack. We use 4 MByte as default and if the + super-large-page is set we increase it to 256 MByte. 256 MByte + is for server installations with GBytes of RAM memory where + the MySQL Server will have page caches and other memory regions + measured in a number of GBytes. + We use as big pages as possible which isn't bigger than the above + desired page sizes. + */ + int nelem; + int max_desired_page_size; + int max_page_size; + if (opt_super_large_pages) + max_page_size= SUPER_LARGE_PAGESIZE; + else + max_page_size= LARGE_PAGESIZE; + nelem = getpagesizes(NULL, 0); + if (nelem > 0) + { + size_t *pagesize = (size_t *) malloc(sizeof(size_t) * nelem); + if (pagesize != NULL && getpagesizes(pagesize, nelem) > 0) + { + size_t i, max_page_size= 0; + for (i= 0; i < nelem; i++) + { + if (pagesize[i] > max_page_size && + pagesize[i] <= max_desired_page_size) + max_page_size= pagesize[i]; + } + free(pagesize); + if (max_page_size > 0) + { + struct memcntl_mha mpss; + + mpss.mha_cmd= MHA_MAPSIZE_BSSBRK; + mpss.mha_pagesize= max_page_size; + mpss.mha_flags= 0; + memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t)&mpss, 0, 0); + mpss.mha_cmd= MHA_MAPSIZE_STACK; + memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t)&mpss, 0, 0); + } + } + } + } +#endif /* HAVE_SOLARIS_LARGE_PAGES */ /* connections and databases needs lots of files */ { @@ -3700,7 +3777,6 @@ You should consider changing lower_case_ table_alias_charset= (lower_case_table_names ? files_charset_info : &my_charset_bin); - return 0; } @@ -5865,6 +5941,7 @@ enum options_mysqld OPT_MAX_SP_RECURSION_DEPTH, OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET, OPT_ENABLE_LARGE_PAGES, + OPT_ENABLE_SUPER_LARGE_PAGES, OPT_TIMED_MUTEXES, OPT_OLD_STYLE_USER_LIMITS, OPT_LOG_SLOW_ADMIN_STATEMENTS, @@ -6135,11 +6212,16 @@ struct my_option my_long_options[] = {"general_log", OPT_GENERAL_LOG, "Enable|disable general log", (uchar**) &opt_log, (uchar**) &opt_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef HAVE_LARGE_PAGES +#ifdef HAVE_LARGE_PAGE_OPTION {"large-pages", OPT_ENABLE_LARGE_PAGES, "Enable support for large pages. \ Disable with --skip-large-pages.", - (uchar**) &opt_large_pages, (uchar**) &opt_large_pages, 0, GET_BOOL, NO_ARG, 0, 0, 0, - 0, 0, 0}, + (uchar**) &opt_large_pages, (uchar**) &opt_large_pages, 0, GET_BOOL, + NO_ARG, 0, 0, 1, 0, 1, 0}, + {"super-large-pages", OPT_ENABLE_SUPER_LARGE_PAGES, + "Enable support for super large pages. \ +Disable with --skip-super-large-pages.", + (uchar**) &opt_super_large_pages, (uchar**) &opt_super_large_pages, 0, + GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, #endif {"ignore-builtin-innodb", OPT_IGNORE_BUILTIN_INNODB , "Disable initialization of builtin InnoDB plugin", @@ -7129,13 +7211,11 @@ The minimum value for this variable is 4 "minimal size of unit in wich space for results is allocated (last unit will be trimed after writing all result data.", (uchar**) &query_cache_min_res_unit, (uchar**) &query_cache_min_res_unit, 0, GET_ULONG, REQUIRED_ARG, QUERY_CACHE_MIN_RESULT_DATA_SIZE, - 0, (longlong) ULONG_MAX, 0, 1, 0}, -#endif /*HAVE_QUERY_CACHE*/ + 0, ULONG_MAX, 0, 1, 0}, {"query_cache_size", OPT_QUERY_CACHE_SIZE, "The memory allocated to store results from old queries.", (uchar**) &query_cache_size, (uchar**) &query_cache_size, 0, GET_ULONG, REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1024, 0}, -#ifdef HAVE_QUERY_CACHE {"query_cache_type", OPT_QUERY_CACHE_TYPE, "0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results except SELECT SQL_NO_CACHE ... queries. 2 = DEMAND = Cache only SELECT SQL_CACHE ... queries.", (uchar**) &global_system_variables.query_cache_type, @@ -7994,6 +8074,7 @@ static int mysql_init_variables(void) #if defined(ENABLED_DEBUG_SYNC) opt_debug_sync_timeout= 0; #endif /* defined(ENABLED_DEBUG_SYNC) */ + opt_super_large_pages= 0; key_map_full.set_all(); /* Character sets */ === modified file 'sql/net_serv.cc' --- a/sql/net_serv.cc 2009-03-17 20:07:27 +0000 +++ b/sql/net_serv.cc 2009-07-02 15:02:45 +0000 @@ -48,6 +48,7 @@ #include #include #include +#include "probes_mysql.h" #ifdef __NETWARE__ #include #endif @@ -371,6 +372,7 @@ my_net_write(NET *net,const uchar *packe { uchar buff[NET_HEADER_SIZE]; my_bool rc; + if (unlikely(!net->vio)) /* nowhere to write */ return 0; @@ -1012,7 +1014,7 @@ my_net_read(NET *net) size_t len, complen; MYSQL_NET_READ_START(); - + #ifdef HAVE_COMPRESS if (!net->compress) { === removed file 'sql/probes.d' --- a/sql/probes.d 2008-10-02 12:08:09 +0000 +++ b/sql/probes.d 1970-01-01 00:00:00 +0000 @@ -1,154 +0,0 @@ -/* Copyright (C) 2008 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - The actual probe names in DTrace scripts will replace '__' by '-'. Thus - insert__row__start will be insert-row-start. - - Recommendations for adding new probes: - - - each probe should have the minimal set of arguments required to - unambiguously identify the context in which the probe fires. Redundant - probes (i.e. the ones that can be obtained in user scripts from previous - probes' arguments or otherwise) may be added for convenience. - - - try to avoid computationally expensive probe arguments. If impossible, - use *_ENABLED() macros to check if the probe is activated before - performing expensive calculations for a probe argument. - - - all *-done probes should have a status argument wherever applicable to make - it possible for user scripts to figure out whether the completed operation - was successful or not. - - - for all status arguments, a non-zero value should be returned on error or - failure, 0 should be returned on success. -*/ - -provider mysql { - - /* The following ones fire when creating or closing a client connection */ - probe connection__start(unsigned long conn_id, char *user, char *host); - probe connection__done(int status, unsigned long conn_id); - - /* - Fire at the start/end of any client command processing (including SQL - queries). - */ - probe command__start(unsigned long conn_id, int command, - char *user, char *host); - probe command__done(int status); - - /* - The following probes fire at the start/end of any SQL query processing, - respectively. - - query_start() has a lot of parameters that can be used to pick up - parameters for a lot of other probes here. For simplicity reasons we also - add the query string to most other DTrace probes as well. Hostname is - either the hostname or the IP address of the MySQL Client. - */ - probe query__start(char *query, - unsigned long conn_id, - char *db_name, - char *user, - char *host); - probe query__done(int status); - - /* Fire at the start/end of SQL query parsing */ - probe query__parse__start(char *query); - probe query__parse__done(int status); - - /* Track whether the query hits the query cache or not */ - probe query__cache__hit(char *query, unsigned long rows); - probe query__cache__miss(char *query); - - /* - This probe fires when the actual query execution starts, i.e. after - parsing and checking the query cache, but before privilege checks, - optimizing, etc. - - Query means also all independent queries of a stored procedure and prepared - statements. Also the stored procedure itself is a query. - - exec_type is: - 0: Executed query from sql_parse, top-level query (sql_parse.cc) - 1: Executed prepared statement (sql_prepare.cc) - 2: Executed cursor statement (sql_cursor.cc) - 3: Executed query in stored procedure (sp_head.cc) - */ - probe query__exec__start(char *query, - unsigned long connid, - char *db_name, - char *user, - char *host, - int exec_type); - probe query__exec__done(int status); - - /* These probes fire when performing write operations towards any handler */ - probe insert__row__start(char *db, char *table); - probe insert__row__done(int status); - probe update__row__start(char *db, char *table); - probe update__row__done(int status); - probe delete__row__start(char *db, char *table); - probe delete__row__done(int status); - - /* - These probes fire when calling external_lock for any handler - depending on the lock type being acquired or released. - */ - probe handler__rdlock__start(char *db, char *table); - probe handler__wrlock__start(char *db, char *table); - probe handler__unlock__start(char *db, char *table); - probe handler__rdlock__done(int status); - probe handler__wrlock__done(int status); - probe handler__unlock__done(int status); - - /* - These probes fire when a filesort activity happens in a query. - */ - probe filesort__start(char *db, char *table); - probe filesort__done(int status, unsigned long rows); - /* - The query types SELECT, INSERT, INSERT AS SELECT, UPDATE, UPDATE with - multiple tables, DELETE, DELETE with multiple tables are all probed. - The start probe always contains the query text. - */ - probe select__start(char *query); - probe select__done(int status, unsigned long rows); - probe insert__start(char *query); - probe insert__done(int status, unsigned long rows); - probe insert__select__start(char *query); - probe insert__select__done(int status, unsigned long rows); - probe update__start(char *query); - probe update__done(int status, - unsigned long rowsmatches, unsigned long rowschanged); - probe multi__update__start(char *query); - probe multi__update__done(int status, - unsigned long rowsmatches, unsigned long rowschanged); - probe delete__start(char *query); - probe delete__done(int status, unsigned long rows); - probe multi__delete__start(char *query); - probe multi__delete__done(int status, unsigned long rows); - - /* - These probes can be used to measure the time waiting for network traffic - or identify network-related problems. - */ - probe net__read__start(); - probe net__read__done(int status, unsigned long bytes); - probe net__write__start(unsigned long bytes); - probe net__write__done(int status); - -}; === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2009-06-12 02:01:08 +0000 +++ b/sql/sp_head.cc 2009-07-02 15:02:45 +0000 @@ -15,6 +15,7 @@ #include "mysql_priv.h" #include "sql_prepare.h" +#include "probes_mysql.h" #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation #endif @@ -2924,7 +2925,7 @@ sp_instr_stmt::exec_core(THD *thd, uint { MYSQL_QUERY_EXEC_START(thd->query, thd->thread_id, - (char *) (thd->db ? thd->db: ""), + (char *) (thd->db ? thd->db : ""), thd->security_ctx->priv_user, (char *) thd->security_ctx->host_or_ip, 3); === modified file 'sql/sql_cache.cc' --- a/sql/sql_cache.cc 2009-05-15 13:45:06 +0000 +++ b/sql/sql_cache.cc 2009-07-02 14:23:36 +0000 @@ -334,6 +334,7 @@ TODO list: #include #include "../storage/myisammrg/ha_myisammrg.h" #include "../storage/myisammrg/myrg_def.h" +#include "probes_mysql.h" #ifdef EMBEDDED_LIBRARY #include "emb_qcache.h" @@ -1224,11 +1225,16 @@ end: Check if the query is in the cache. If it was cached, send it to the user. - RESULTS - 1 The query was cached and user was sent the result. - 0 Query was not cached. - -1 The query was cached but we didn't have rights to use it. - No error is sent to the client yet. + @param thd Pointer to the thread handler + @param sql A pointer to the sql statement * + @param query_length Length of the statement in characters + + @return status code + @retval 0 Query was not cached. + @retval 1 The query was cached and user was sent the result. + @retval -1 The query was cached but we didn't have rights to use it. + + In case of -1, no error is sent to the client. NOTE This method requires that sql points to allocated memory of size: @@ -1544,8 +1550,8 @@ def_week_frmt: %lu, in_trans: %d, autoco thd->status_var.last_query_cost= 0.0; thd->stmt_da->disable_status(); - MYSQL_QUERY_CACHE_HIT(thd->query, (ulong) thd->limit_found_rows); BLOCK_UNLOCK_RD(query_block); + MYSQL_QUERY_CACHE_HIT(thd->query, (ulong) thd->limit_found_rows); DBUG_RETURN(1); // Result sent to client err_unlock: === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2009-06-30 08:03:05 +0000 +++ b/sql/sql_class.h 2009-07-03 12:25:24 +0000 @@ -3108,6 +3108,10 @@ public: void send_error(uint errcode,const char *err); int do_deletes(); bool send_eof(); + inline ha_rows num_deleted() + { + return deleted; + } virtual void abort(); }; @@ -3151,6 +3155,14 @@ public: void send_error(uint errcode,const char *err); int do_updates(); bool send_eof(); + inline ha_rows num_found() + { + return found; + } + inline ha_rows num_updated() + { + return updated; + } virtual void abort(); }; === modified file 'sql/sql_connect.cc' --- a/sql/sql_connect.cc 2009-06-09 14:36:52 +0000 +++ b/sql/sql_connect.cc 2009-07-02 14:23:36 +0000 @@ -20,6 +20,7 @@ #include "mysql_priv.h" #include "sql_audit.h" +#include "probes_mysql.h" #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) /* @@ -1148,7 +1149,7 @@ pthread_handler_t handle_one_connection( MYSQL_CONNECTION_START(thd->thread_id, thd->security_ctx->priv_user, (char *) thd->security_ctx->host_or_ip); - + prepare_new_connection_state(thd); while (!net->error && net->vio != 0 && === modified file 'sql/sql_cursor.cc' --- a/sql/sql_cursor.cc 2009-01-26 16:03:39 +0000 +++ b/sql/sql_cursor.cc 2009-07-02 14:23:36 +0000 @@ -19,6 +19,7 @@ #include "mysql_priv.h" #include "sql_cursor.h" #include "sql_select.h" +#include "probes_mysql.h" /**************************************************************************** Declarations. === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc 2009-06-17 07:30:19 +0000 +++ b/sql/sql_insert.cc 2009-07-02 14:23:36 +0000 @@ -3184,6 +3184,9 @@ bool select_insert::send_data(List DBUG_RETURN(1); } } + + // Release latches in case bulk insert takes a long time + ha_release_temporary_latches(thd); // Release latches in case bulk insert takes a long time ha_release_temporary_latches(thd); === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2009-06-30 08:03:05 +0000 +++ b/sql/sql_parse.cc 2009-07-03 12:25:24 +0000 @@ -37,6 +37,7 @@ #ifdef BACKUP_TEST #include "backup/backup_test.h" #endif +#include "probes_mysql.h" /** @defgroup Runtime_Environment Runtime Environment @@ -1085,7 +1086,6 @@ bool dispatch_command(enum enum_server_c { MYSQL_QUERY_DONE(thd->is_error()); } - #if defined(ENABLED_PROFILING) thd->profiling.finish_current_query(); thd->profiling.start_new_query("continuing"); @@ -1488,7 +1488,6 @@ bool dispatch_command(enum enum_server_c } MYSQL_COMMAND_DONE(res); } - DBUG_RETURN(error); } @@ -3129,6 +3128,8 @@ end_with_restore_list: break; } case SQLCOM_UPDATE: + { + ha_rows found= 0, updated= 0; DBUG_ASSERT(first_table == all_tables && first_table != 0); if (update_precheck(thd, all_tables)) break; @@ -3145,7 +3146,9 @@ end_with_restore_list: select_lex->order_list.elements, (ORDER *) select_lex->order_list.first, unit->select_limit_cnt, - lex->duplicates, lex->ignore)); + lex->duplicates, lex->ignore, + &found, &updated)); + MYSQL_UPDATE_DONE(res, found, updated); /* mysql_update return 2 if we need to switch to multi-update */ if (up_result != 2) { @@ -3153,6 +3156,7 @@ end_with_restore_list: break; } /* Fall through */ + } case SQLCOM_UPDATE_MULTI: { DBUG_ASSERT(first_table == all_tables && first_table != 0); @@ -3209,14 +3213,32 @@ end_with_restore_list: #ifdef HAVE_REPLICATION } /* unlikely */ #endif - MYSQL_MULTI_UPDATE_START(thd->query); - res= mysql_multi_update(thd, all_tables, - &select_lex->item_list, - &lex->value_list, - select_lex->where, - select_lex->options, - lex->duplicates, lex->ignore, unit, select_lex); - DEBUG_SYNC(thd, "after_update"); + { + multi_update *result_obj; + MYSQL_MULTI_UPDATE_START(thd->query); + res= mysql_multi_update(thd, all_tables, + &select_lex->item_list, + &lex->value_list, + select_lex->where, + select_lex->options, + lex->duplicates, + lex->ignore, + unit, + select_lex, + &result_obj); + DEBUG_SYNC(thd, "after_update"); + if (result_obj) + { + MYSQL_MULTI_UPDATE_DONE(res, result_obj->num_found(), + result_obj->num_updated()); + res= FALSE; /* Ignore errors here */ + delete result_obj; + } + else + { + MYSQL_MULTI_UPDATE_DONE(1, 0, 0); + } + } break; } case SQLCOM_REPLACE: @@ -3267,7 +3289,7 @@ end_with_restore_list: res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, lex->update_list, lex->value_list, lex->duplicates, lex->ignore); - + MYSQL_INSERT_DONE(res, (ulong) thd->row_count_func); /* If we have inserted into a VIEW, and the base table has AUTO_INCREMENT column, but this column is not accessible through @@ -3304,13 +3326,12 @@ end_with_restore_list: res= 1; break; } - if (!(res= open_and_lock_tables(thd, all_tables))) { - MYSQL_INSERT_SELECT_START(thd->query); - /* Skip first table, which is the table we are inserting in */ TABLE_LIST *second_table= first_table->next_local; + + MYSQL_INSERT_SELECT_START(thd->query); select_lex->table_list.first= (uchar*) second_table; select_lex->context.table_list= select_lex->context.first_name_resolution_table= second_table; @@ -3342,9 +3363,9 @@ end_with_restore_list: delete sel_result; } /* revert changes for SP */ + MYSQL_INSERT_SELECT_DONE(res, (ulong) thd->row_count_func); select_lex->table_list.first= (uchar*) first_table; } - /* If we have inserted into a VIEW, and the base table has AUTO_INCREMENT column, but this column is not accessible through @@ -3396,6 +3417,7 @@ end_with_restore_list: &select_lex->order_list, unit->select_limit_cnt, select_lex->options, FALSE); + MYSQL_DELETE_DONE(res, (ulong) thd->row_count_func); break; } case SQLCOM_DELETE_MULTI: @@ -3426,8 +3448,12 @@ end_with_restore_list: if ((res= open_and_lock_tables(thd, all_tables))) break; + MYSQL_MULTI_DELETE_START(thd->query); if ((res= mysql_multi_delete_prepare(thd))) + { + MYSQL_MULTI_DELETE_DONE(1, 0); goto error; + } if (!thd->is_fatal_error && (del_result= new multi_delete(aux_tables, lex->table_count))) @@ -3444,12 +3470,16 @@ end_with_restore_list: OPTION_SETUP_TABLES_DONE, del_result, unit, select_lex); res|= thd->is_error(); + MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted()); if (res) del_result->abort(); delete del_result; } else + { res= TRUE; // Error + MYSQL_MULTI_DELETE_DONE(1, 0); + } break; } case SQLCOM_DROP_TABLE: @@ -5981,7 +6011,7 @@ void mysql_parse(THD *thd, const char *i thd->server_status|= SERVER_MORE_RESULTS_EXISTS; } lex->set_trg_event_type_for_tables(); - MYSQL_QUERY_EXEC_START(thd->query, + MYSQL_QUERY_EXEC_START(thd->query, thd->thread_id, (char *) (thd->db ? thd->db : ""), thd->security_ctx->priv_user, @@ -5989,7 +6019,7 @@ void mysql_parse(THD *thd, const char *i 0); error= mysql_execute_command(thd); - MYSQL_QUERY_EXEC_DONE(error); + MYSQL_QUERY_EXEC_DONE(error); } } } @@ -7958,10 +7988,10 @@ bool parse_sql(THD *thd, Object_creation_ctx *creation_ctx) { bool mysql_parse_status; + bool ret_value; DBUG_ASSERT(thd->m_parser_state == NULL); MYSQL_QUERY_PARSE_START(thd->query); - /* Backup creation context. */ Object_creation_ctx *backup_ctx= NULL; @@ -7993,9 +8023,9 @@ bool parse_sql(THD *thd, /* That's it. */ - MYSQL_QUERY_PARSE_DONE(mysql_parse_status || thd->is_fatal_error); - - return mysql_parse_status || thd->is_fatal_error; + ret_value= mysql_parse_status || thd->is_fatal_error; + MYSQL_QUERY_PARSE_DONE(ret_value); + return ret_value; } /** === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2009-06-06 00:02:04 +0000 +++ b/sql/sql_prepare.cc 2009-07-02 14:23:36 +0000 @@ -90,6 +90,7 @@ When one supplies long data for a placeh #include "sp_head.h" #include "sp.h" #include "sp_cache.h" +#include "probes_mysql.h" #ifdef EMBEDDED_LIBRARY /* include MYSQL_BIND headers */ #include === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2009-06-30 08:03:05 +0000 +++ b/sql/sql_select.cc 2009-07-03 12:25:24 +0000 @@ -31,6 +31,7 @@ #include "mysql_priv.h" #include "sql_select.h" #include "sql_cursor.h" +#include "probes_mysql.h" #include #include @@ -311,7 +312,6 @@ bool handle_select(THD *thd, LEX *lex, s result->abort(); MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows); - DBUG_RETURN(res); } === modified file 'sql/sql_update.cc' --- a/sql/sql_update.cc 2009-05-31 12:05:01 +0000 +++ b/sql/sql_update.cc 2009-07-02 15:02:45 +0000 @@ -180,7 +180,8 @@ int mysql_update(THD *thd, COND *conds, uint order_num, ORDER *order, ha_rows limit, - enum enum_duplicates handle_duplicates, bool ignore) + enum enum_duplicates handle_duplicates, bool ignore, + ha_rows *found_return, ha_rows *updated_return) { bool using_limit= limit != HA_POS_ERROR; bool safe_update= test(thd->options & OPTION_SAFE_UPDATES); @@ -210,7 +211,6 @@ int mysql_update(THD *thd, { if (open_tables(thd, &table_list, &table_count, 0)) { - MYSQL_UPDATE_DONE(1, 0, 0); DBUG_RETURN(1); } @@ -221,14 +221,12 @@ int mysql_update(THD *thd, /* pass counter value */ thd->lex->table_count= table_count; /* convert to multiupdate */ - MYSQL_UPDATE_DONE(2, 0, 0); DBUG_RETURN(2); } if (!lock_tables(thd, table_list, table_count, 0, &need_reopen)) break; if (!need_reopen) { - MYSQL_UPDATE_DONE(1, 0, 0); DBUG_RETURN(1); } close_tables_for_reopen(thd, &table_list, FALSE); @@ -238,7 +236,6 @@ int mysql_update(THD *thd, (thd->fill_derived_tables() && mysql_handle_derived(thd->lex, &mysql_derived_filling))) { - MYSQL_UPDATE_DONE(1, 0, 0); DBUG_RETURN(1); } @@ -301,7 +298,6 @@ int mysql_update(THD *thd, if (select_lex->inner_refs_list.elements && fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array)) { - MYSQL_UPDATE_DONE(1, 0, 0); DBUG_RETURN(-1); } @@ -331,7 +327,6 @@ int mysql_update(THD *thd, { free_underlaid_joins(thd, select_lex); my_ok(thd); // No matching records - MYSQL_UPDATE_DONE(0, 0, 0); DBUG_RETURN(0); } #endif @@ -348,7 +343,6 @@ int mysql_update(THD *thd, if (error) goto abort; // Error in where my_ok(thd); // No matching records - MYSQL_UPDATE_DONE(0, 0, 0); DBUG_RETURN(0); } if (!select && limit != HA_POS_ERROR) @@ -843,10 +837,9 @@ int mysql_update(THD *thd, } thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ thd->abort_on_warning= 0; - - res= (error >= 0 || thd->is_error()) ? 1 : 0; - MYSQL_UPDATE_DONE(res, (ulong) found, (ulong) updated); - DBUG_RETURN(res); + *found_return= found; + *updated_return= updated; + DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0); err: delete select; @@ -859,7 +852,6 @@ err: thd->abort_on_warning= 0; abort: - MYSQL_UPDATE_DONE(1, 0, 0); DBUG_RETURN(1); } @@ -1211,18 +1203,22 @@ bool mysql_multi_update(THD *thd, List *values, COND *conds, ulonglong options, - enum enum_duplicates handle_duplicates, bool ignore, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) + enum enum_duplicates handle_duplicates, + bool ignore, + SELECT_LEX_UNIT *unit, + SELECT_LEX *select_lex, + multi_update **result) { - multi_update *result; bool res; DBUG_ENTER("mysql_multi_update"); - if (!(result= new multi_update(table_list, + if (!(*result= new multi_update(table_list, thd->lex->select_lex.leaf_tables, fields, values, handle_duplicates, ignore))) + { DBUG_RETURN(TRUE); + } thd->abort_on_warning= test(thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | @@ -1236,19 +1232,18 @@ bool mysql_multi_update(THD *thd, (ORDER *)NULL, options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE, - result, unit, select_lex); + *result, unit, select_lex); DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error())); res|= thd->is_error(); if (unlikely(res)) { /* If we had a another error reported earlier then this will be ignored */ - result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); - result->abort(); + (*result)->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); + (*result)->abort(); } - delete result; thd->abort_on_warning= 0; - DBUG_RETURN(FALSE); + DBUG_RETURN(res); } @@ -1805,7 +1800,6 @@ bool multi_update::send_data(List } } } - MYSQL_UPDATE_DONE(0, (ulong) found, (ulong) updated); DBUG_RETURN(0); } === modified file 'storage/archive/Makefile.am' --- a/storage/archive/Makefile.am 2009-01-12 15:00:34 +0000 +++ b/storage/archive/Makefile.am 2009-07-02 14:23:36 +0000 @@ -86,3 +86,23 @@ valgrind-test: archive_test archive_perf libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes ./archive_performance EXTRA_DIST = CMakeLists.txt plug.in + +if HAVE_DTRACE_DASH_G +libarchive_a_LIBADD = probes_mysql.o +libarchive_a_DEPENDENCIES = probes_mysql.o dtrace_files dtrace_providers +CLEANFILES = probes_mysql.o dtrace_files dtrace_providers +DTRACEFILES = libarchive_a-ha_archive.o +DTRACEPROVIDER = probes_mysql.d + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'storage/archive/ha_archive.cc' --- a/storage/archive/ha_archive.cc 2009-05-15 13:45:06 +0000 +++ b/storage/archive/ha_archive.cc 2009-07-02 14:23:36 +0000 @@ -18,6 +18,7 @@ #endif #include "mysql_priv.h" +#include "probes_mysql.h" #include #include "ha_archive.h" @@ -917,7 +918,9 @@ int ha_archive::index_read(uchar *buf, c { int rc; DBUG_ENTER("ha_archive::index_read"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); rc= index_read_idx(buf, active_index, key, key_len, find_flag); + MYSQL_INDEX_READ_ROW_DONE(rc); DBUG_RETURN(rc); } @@ -964,8 +967,10 @@ error: int ha_archive::index_next(uchar * buf) { bool found= 0; + int rc; DBUG_ENTER("ha_archive::index_next"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); while (!(get_row(&archive, buf))) { @@ -976,7 +981,9 @@ int ha_archive::index_next(uchar * buf) } } - DBUG_RETURN(found ? 0 : HA_ERR_END_OF_FILE); + rc= found ? 0 : HA_ERR_END_OF_FILE; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } /* @@ -1102,12 +1109,17 @@ int ha_archive::rnd_next(uchar *buf) { int rc; DBUG_ENTER("ha_archive::rnd_next"); + MYSQL_READ_ROW_START(table_share->db.str, + table_share->table_name.str, TRUE); if (share->crashed) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); if (!scan_rows) - DBUG_RETURN(HA_ERR_END_OF_FILE); + { + rc= HA_ERR_END_OF_FILE; + goto end; + } scan_rows--; ha_statistic_increment(&SSV::ha_read_rnd_next_count); @@ -1116,6 +1128,8 @@ int ha_archive::rnd_next(uchar *buf) table->status=rc ? STATUS_NOT_FOUND: 0; +end: + MYSQL_READ_ROW_DONE(rc); DBUG_RETURN(rc); } @@ -1143,12 +1157,21 @@ void ha_archive::position(const uchar *r int ha_archive::rnd_pos(uchar * buf, uchar *pos) { + int rc; DBUG_ENTER("ha_archive::rnd_pos"); + MYSQL_READ_ROW_START(table_share->db.str, + table_share->table_name.str, FALSE); ha_statistic_increment(&SSV::ha_read_rnd_next_count); current_position= (my_off_t)my_get_ptr(pos, ref_length); if (azseek(&archive, (size_t)current_position, SEEK_SET) == (size_t)(-1L)) - DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); - DBUG_RETURN(get_row(&archive, buf)); + { + rc= HA_ERR_CRASHED_ON_USAGE; + goto end; + } + rc= get_row(&archive, buf); +end: + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } /* === modified file 'storage/blackhole/Makefile.am' --- a/storage/blackhole/Makefile.am 2009-01-07 10:58:33 +0000 +++ b/storage/blackhole/Makefile.am 2009-07-02 14:23:36 +0000 @@ -44,3 +44,23 @@ libblackhole_a_SOURCES= ha_blackhole.cc EXTRA_DIST = CMakeLists.txt plug.in + +if HAVE_DTRACE_DASH_G +libblackhole_a_LIBADD = probes_mysql.o +libblackhole_a_DEPENDENCIES = probes_mysql.o dtrace_files dtrace_providers +CLEANFILES = probes_mysql.o dtrace_files dtrace_providers +DTRACEFILES = libblackhole_a-ha_blackhole.o +DTRACEPROVIDER = probes_mysql.d + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'storage/blackhole/ha_blackhole.cc' --- a/storage/blackhole/ha_blackhole.cc 2009-01-27 02:08:48 +0000 +++ b/storage/blackhole/ha_blackhole.cc 2009-07-02 14:23:36 +0000 @@ -20,6 +20,7 @@ #define MYSQL_SERVER 1 #include "mysql_priv.h" +#include "probes_mysql.h" #include "ha_blackhole.h" /* Static declarations for handlerton */ @@ -128,18 +129,27 @@ int ha_blackhole::rnd_init(bool scan) int ha_blackhole::rnd_next(uchar *buf) { + int rc; DBUG_ENTER("ha_blackhole::rnd_next"); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); THD *thd= ha_thd(); if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) - DBUG_RETURN(0); - DBUG_RETURN(HA_ERR_END_OF_FILE); + rc= 0; + else + rc= HA_ERR_END_OF_FILE; + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_blackhole::rnd_pos(uchar * buf, uchar *pos) { DBUG_ENTER("ha_blackhole::rnd_pos"); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + FALSE); DBUG_ASSERT(0); + MYSQL_READ_ROW_DONE(0); DBUG_RETURN(0); } @@ -210,11 +220,16 @@ int ha_blackhole::index_read_map(uchar * key_part_map keypart_map, enum ha_rkey_function find_flag) { + int rc; DBUG_ENTER("ha_blackhole::index_read"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); THD *thd= ha_thd(); if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) - DBUG_RETURN(0); - DBUG_RETURN(HA_ERR_END_OF_FILE); + rc= 0; + else + rc= HA_ERR_END_OF_FILE; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -222,50 +237,77 @@ int ha_blackhole::index_read_idx_map(uch key_part_map keypart_map, enum ha_rkey_function find_flag) { + int rc; DBUG_ENTER("ha_blackhole::index_read_idx"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); THD *thd= ha_thd(); if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) - DBUG_RETURN(0); - DBUG_RETURN(HA_ERR_END_OF_FILE); + rc= 0; + else + rc= HA_ERR_END_OF_FILE; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_blackhole::index_read_last_map(uchar * buf, const uchar * key, key_part_map keypart_map) { + int rc; DBUG_ENTER("ha_blackhole::index_read_last"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); THD *thd= ha_thd(); if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) - DBUG_RETURN(0); - DBUG_RETURN(HA_ERR_END_OF_FILE); + rc= 0; + else + rc= HA_ERR_END_OF_FILE; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_blackhole::index_next(uchar * buf) { + int rc; DBUG_ENTER("ha_blackhole::index_next"); - DBUG_RETURN(HA_ERR_END_OF_FILE); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_END_OF_FILE; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_blackhole::index_prev(uchar * buf) { + int rc; DBUG_ENTER("ha_blackhole::index_prev"); - DBUG_RETURN(HA_ERR_END_OF_FILE); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_END_OF_FILE; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } int ha_blackhole::index_first(uchar * buf) { + int rc; DBUG_ENTER("ha_blackhole::index_first"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_END_OF_FILE; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); DBUG_RETURN(HA_ERR_END_OF_FILE); } int ha_blackhole::index_last(uchar * buf) { + int rc; DBUG_ENTER("ha_blackhole::index_last"); - DBUG_RETURN(HA_ERR_END_OF_FILE); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_END_OF_FILE; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } === modified file 'storage/csv/Makefile.am' --- a/storage/csv/Makefile.am 2009-01-12 15:00:34 +0000 +++ b/storage/csv/Makefile.am 2009-07-02 14:23:36 +0000 @@ -36,3 +36,24 @@ noinst_LIBRARIES = @plugin_csv_static_ta libcsv_a_SOURCES = transparent_file.cc ha_tina.cc EXTRA_DIST = CMakeLists.txt plug.in + +if HAVE_DTRACE_DASH_G +libcsv_a_LIBADD = probes_mysql.o +libcsv_a_DEPENDENCIES = probes_mysql.o dtrace_files dtrace_providers +CLEANFILES = probes_mysql.o dtrace_files dtrace_providers +DTRACEFILES = libcsv_a-ha_tina.o +DTRACEPROVIDER = probes_mysql.d +CLEANFILES += $(DTRACEPROVIDER) dtrace_sources + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'storage/csv/ha_tina.cc' --- a/storage/csv/ha_tina.cc 2009-03-24 09:23:56 +0000 +++ b/storage/csv/ha_tina.cc 2009-07-02 14:23:36 +0000 @@ -48,6 +48,7 @@ TODO: #include "mysql_priv.h" #include #include "ha_tina.h" +#include "probes_mysql.h" /* @@ -1156,9 +1157,14 @@ int ha_tina::rnd_next(uchar *buf) { int rc; DBUG_ENTER("ha_tina::rnd_next"); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); if (share->crashed) - DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); + { + rc= HA_ERR_CRASHED_ON_USAGE; + goto end; + } ha_statistic_increment(&SSV::ha_read_rnd_next_count); @@ -1166,13 +1172,19 @@ int ha_tina::rnd_next(uchar *buf) /* don't scan an empty file */ if (!local_saved_data_file_length) - DBUG_RETURN(HA_ERR_END_OF_FILE); + { + rc= HA_ERR_END_OF_FILE; + goto end; + } if ((rc= find_current_row(buf))) - DBUG_RETURN(rc); + goto end; stats.records++; - DBUG_RETURN(0); + rc= 0; +end: + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } /* @@ -1199,10 +1211,15 @@ void ha_tina::position(const uchar *reco int ha_tina::rnd_pos(uchar * buf, uchar *pos) { + int rc; DBUG_ENTER("ha_tina::rnd_pos"); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + FALSE); ha_statistic_increment(&SSV::ha_read_rnd_count); current_position= my_get_ptr(pos,ref_length); - DBUG_RETURN(find_current_row(buf)); + rc= find_current_row(buf); + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } /* === modified file 'storage/example/Makefile.am' --- a/storage/example/Makefile.am 2009-04-25 21:20:45 +0000 +++ b/storage/example/Makefile.am 2009-07-02 14:23:36 +0000 @@ -44,3 +44,24 @@ libexample_a_SOURCES= ha_example.cc EXTRA_DIST = CMakeLists.txt plug.in + +if HAVE_DTRACE_DASH_G +libexample_a_LIBADD = probes_mysql.o +libexample_a_DEPENDENCIES = probes_mysql.o +CLEANFILES = +BUILT_SOURCES = +DTRACEFILES = libexample_a-ha_example.o +DTRACEPROVIDER = probes_mysql.d + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'storage/example/ha_example.cc' --- a/storage/example/ha_example.cc 2009-04-25 21:20:45 +0000 +++ b/storage/example/ha_example.cc 2009-07-02 14:23:36 +0000 @@ -94,6 +94,7 @@ #define MYSQL_SERVER 1 #include "mysql_priv.h" #include "ha_example.h" +#include "probes_mysql.h" #include static handler *example_create_handler(handlerton *hton, @@ -428,8 +429,12 @@ int ha_example::index_read_map(uchar *bu enum ha_rkey_function find_flag __attribute__((unused))) { + int rc; DBUG_ENTER("ha_example::index_read"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_WRONG_COMMAND; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -440,8 +445,12 @@ int ha_example::index_read_map(uchar *bu int ha_example::index_next(uchar *buf) { + int rc; DBUG_ENTER("ha_example::index_next"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_WRONG_COMMAND; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -452,8 +461,12 @@ int ha_example::index_next(uchar *buf) int ha_example::index_prev(uchar *buf) { + int rc; DBUG_ENTER("ha_example::index_prev"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_WRONG_COMMAND; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -469,8 +482,12 @@ int ha_example::index_prev(uchar *buf) */ int ha_example::index_first(uchar *buf) { + int rc; DBUG_ENTER("ha_example::index_first"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_WRONG_COMMAND; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -486,8 +503,12 @@ int ha_example::index_first(uchar *buf) */ int ha_example::index_last(uchar *buf) { + int rc; DBUG_ENTER("ha_example::index_last"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + rc= HA_ERR_WRONG_COMMAND; + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -533,8 +554,13 @@ int ha_example::rnd_end() */ int ha_example::rnd_next(uchar *buf) { + int rc; DBUG_ENTER("ha_example::rnd_next"); - DBUG_RETURN(HA_ERR_END_OF_FILE); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); + rc= HA_ERR_END_OF_FILE; + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -581,8 +607,13 @@ void ha_example::position(const uchar *r */ int ha_example::rnd_pos(uchar *buf, uchar *pos) { + int rc; DBUG_ENTER("ha_example::rnd_pos"); - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); + rc= HA_ERR_WRONG_COMMAND; + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } === modified file 'storage/federated/Makefile.am' --- a/storage/federated/Makefile.am 2009-01-07 10:58:33 +0000 +++ b/storage/federated/Makefile.am 2009-07-02 14:23:36 +0000 @@ -44,3 +44,23 @@ libfederated_a_SOURCES= ha_federated.cc EXTRA_DIST = CMakeLists.txt plug.in + +if HAVE_DTRACE_DASH_G +libfederated_a_LIBADD = probes_mysql.o +libfederated_a_DEPENDENCIES = probes_mysql.o dtrace_files dtrace_providers +CLEANFILES = probes_mysql.o dtrace_files dtrace_providers +DTRACEFILES = libfederated_a-ha_federated.o +DTRACEPROVIDER = probes_mysql.d + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'storage/federated/ha_federated.cc' --- a/storage/federated/ha_federated.cc 2009-05-15 13:45:06 +0000 +++ b/storage/federated/ha_federated.cc 2009-07-02 14:23:36 +0000 @@ -380,6 +380,7 @@ #endif #include "ha_federated.h" +#include "probes_mysql.h" #include "m_string.h" @@ -2317,12 +2318,16 @@ int ha_federated::delete_row(const uchar int ha_federated::index_read(uchar *buf, const uchar *key, uint key_len, ha_rkey_function find_flag) { + int rc; DBUG_ENTER("ha_federated::index_read"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); free_result(); - DBUG_RETURN(index_read_idx_with_result_set(buf, active_index, key, - key_len, find_flag, - &stored_result)); + rc= index_read_idx_with_result_set(buf, active_index, key, + key_len, find_flag, + &stored_result); + MYSQL_INDEX_READ_ROW_DONE(rc); + DBUG_RETURN(rc); } @@ -2473,6 +2478,7 @@ int ha_federated::read_range_first(const sizeof(sql_query_buffer), &my_charset_bin); DBUG_ENTER("ha_federated::read_range_first"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(!(start_key == NULL && end_key == NULL)); @@ -2493,28 +2499,39 @@ int ha_federated::read_range_first(const retval= HA_ERR_END_OF_FILE; goto error; } - - DBUG_RETURN(read_next(table->record[0], stored_result)); + + retval= read_next(table->record[0], stored_result); + MYSQL_INDEX_READ_ROW_DONE(retval); + DBUG_RETURN(retval); error: table->status= STATUS_NOT_FOUND; + MYSQL_INDEX_READ_ROW_DONE(retval); DBUG_RETURN(retval); } int ha_federated::read_range_next() { + int retval; DBUG_ENTER("ha_federated::read_range_next"); - DBUG_RETURN(rnd_next(table->record[0])); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); + retval= rnd_next_int(table->record[0]); + MYSQL_INDEX_READ_ROW_DONE(retval); + DBUG_RETURN(retval); } /* Used to read forward through the index. */ int ha_federated::index_next(uchar *buf) { + int retval; DBUG_ENTER("ha_federated::index_next"); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_next_count); - DBUG_RETURN(read_next(buf, stored_result)); + retval= read_next(buf, stored_result); + MYSQL_INDEX_READ_ROW_DONE(retval); + DBUG_RETURN(retval); } @@ -2607,7 +2624,18 @@ int ha_federated::index_end(void) int ha_federated::rnd_next(uchar *buf) { + int rc; DBUG_ENTER("ha_federated::rnd_next"); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); + rc= rnd_next_int(buf); + MYSQL_READ_ROW_DONE(rc); + DBUG_RETURN(rc); +} + +int ha_federated::rnd_next_int(uchar *buf) +{ + DBUG_ENTER("ha_federated::rnd_next_int"); if (stored_result == 0) { @@ -2712,8 +2740,11 @@ void ha_federated::position(const uchar int ha_federated::rnd_pos(uchar *buf, uchar *pos) { MYSQL_RES *result; + int ret_val; DBUG_ENTER("ha_federated::rnd_pos"); - + + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + FALSE); ha_statistic_increment(&SSV::ha_read_rnd_count); /* Get stored result set. */ @@ -2723,7 +2754,9 @@ int ha_federated::rnd_pos(uchar *buf, uc memcpy_fixed(&result->data_cursor, pos + sizeof(MYSQL_RES *), sizeof(MYSQL_ROW_OFFSET)); /* Read a row. */ - DBUG_RETURN(read_next(buf, result)); + ret_val= read_next(buf, result); + MYSQL_READ_ROW_DONE(ret_val); + DBUG_RETURN(ret_val); } === modified file 'storage/federated/ha_federated.h' --- a/storage/federated/ha_federated.h 2009-03-17 20:07:27 +0000 +++ b/storage/federated/ha_federated.h 2009-07-02 14:23:36 +0000 @@ -237,6 +237,7 @@ public: int rnd_init(bool scan); //required int rnd_end(); int rnd_next(uchar *buf); //required + int rnd_next_int(uchar *buf); int rnd_pos(uchar *buf, uchar *pos); //required void position(const uchar *record); //required int info(uint); //required === modified file 'storage/heap/Makefile.am' --- a/storage/heap/Makefile.am 2009-01-07 10:58:33 +0000 +++ b/storage/heap/Makefile.am 2009-07-02 14:23:36 +0000 @@ -49,3 +49,24 @@ libheap_a_SOURCES = hp_open.c hp_extra.c EXTRA_DIST = CMakeLists.txt plug.in + +if HAVE_DTRACE_DASH_G +libheap_a_LIBADD = probes_mysql.o +libheap_a_DEPENDENCIES = probes_mysql.o dtrace_files dtrace_providers +CLEANFILES = probes_mysql.o dtrace_files dtrace_providers +DTRACEFILES = ha_heap.o +DTRACEPROVIDER = probes_mysql.d +CLEANFILES += $(DTRACEPROVIDER) dtrace_sources + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'storage/heap/ha_heap.cc' --- a/storage/heap/ha_heap.cc 2008-12-16 12:12:22 +0000 +++ b/storage/heap/ha_heap.cc 2009-02-17 12:24:09 +0000 @@ -20,6 +20,7 @@ #define MYSQL_SERVER 1 #include "mysql_priv.h" +#include "probes_mysql.h" #include #include "ha_heap.h" #include "heapdef.h" @@ -274,21 +275,25 @@ int ha_heap::index_read_map(uchar *buf, key_part_map keypart_map, enum ha_rkey_function find_flag) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_key_count); int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag); table->status = error ? STATUS_NOT_FOUND : 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_heap::index_read_last_map(uchar *buf, const uchar *key, key_part_map keypart_map) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_key_count); int error= heap_rkey(file, buf, active_index, key, keypart_map, HA_READ_PREFIX_LAST); table->status= error ? STATUS_NOT_FOUND : 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -296,45 +301,55 @@ int ha_heap::index_read_idx_map(uchar *b key_part_map keypart_map, enum ha_rkey_function find_flag) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_key_count); int error = heap_rkey(file, buf, index, key, keypart_map, find_flag); table->status = error ? STATUS_NOT_FOUND : 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_heap::index_next(uchar * buf) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_next_count); int error=heap_rnext(file,buf); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_heap::index_prev(uchar * buf) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_prev_count); int error=heap_rprev(file,buf); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_heap::index_first(uchar * buf) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_first_count); int error=heap_rfirst(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_heap::index_last(uchar * buf) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_last_count); int error=heap_rlast(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -345,9 +360,12 @@ int ha_heap::rnd_init(bool scan) int ha_heap::rnd_next(uchar *buf) { + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); ha_statistic_increment(&SSV::ha_read_rnd_next_count); int error=heap_scan(file, buf); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_READ_ROW_DONE(error); return error; } @@ -355,10 +373,13 @@ int ha_heap::rnd_pos(uchar * buf, uchar { int error; HEAP_PTR heap_position; + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + FALSE); ha_statistic_increment(&SSV::ha_read_rnd_count); memcpy_fixed((char*) &heap_position, pos, sizeof(HEAP_PTR)); error=heap_rrnd(file, buf, heap_position); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_READ_ROW_DONE(error); return error; } === modified file 'storage/innobase/CMakeLists.txt' --- a/storage/innobase/CMakeLists.txt 2009-03-28 00:27:25 +0000 +++ b/storage/innobase/CMakeLists.txt 2009-07-02 14:23:36 +0000 @@ -28,6 +28,28 @@ INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/storage/innobase/include ${CMAKE_SOURCE_DIR}/storage/innobase/handler ) +IF (WIN32) + IF (NOT WITHOUT_ATOMICS) +# Check if this Windows version supports atomic instructions + IF (CMAKE_SIZEOF_VOID_P MATCHES 8) +# Check for 64 bit atomics + TRY_RUN(RUN_RES COMPILE_RES ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/storage/innobase/win_atomics64_test.c) + IF (COMPILE_RES AND NOT RUN_RES) + MESSAGE("Adding support for Win64 atomics") + ADD_DEFINITIONS(-DWIN_ATOMICS64) + ENDIF (COMPILE_RES AND NOT RUN_RES) + ELSE (CMAKE_SIZEOF_VOID_P MATCHES 8) +# Check for 32 bit atomics + TRY_RUN(RUN_RES COMPILE_RES ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/storage/innobase/win_atomics32_test.c) + IF (COMPILE_RES AND NOT RUN_RES) + MESSAGE("Adding support for Win32 atomics") + ADD_DEFINITIONS(-DWIN_ATOMICS32) + ENDIF (COMPILE_RES AND NOT RUN_RES) + ENDIF (CMAKE_SIZEOF_VOID_P MATCHES 8) + ENDIF (NOT WITHOUT_ATOMICS) +ENDIF (WIN32) SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c === modified file 'storage/innobase/Makefile.am' --- a/storage/innobase/Makefile.am 2009-01-24 21:18:12 +0000 +++ b/storage/innobase/Makefile.am 2009-07-02 14:23:36 +0000 @@ -163,4 +163,5 @@ ha_innodb_la_SOURCES= $(libinnobase_a_SO EXTRA_DIST= CMakeLists.txt plug.in \ pars/make_bison.sh pars/make_flex.sh \ - pars/pars0grm.y pars/pars0lex.l + pars/pars0grm.y pars/pars0lex.l \ + win_atomics32_test.c win_atomics64_test.c === modified file 'storage/innobase/btr/btr0cur.c' --- a/storage/innobase/btr/btr0cur.c 2008-12-19 00:34:15 +0000 +++ b/storage/innobase/btr/btr0cur.c 2009-07-02 14:23:36 +0000 @@ -333,7 +333,7 @@ btr_cur_search_to_nth_level( #ifdef UNIV_SEARCH_PERF_STAT info->n_searches++; #endif - if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED + if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_NOT_LOCKED && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ && !estimate #ifdef PAGE_CUR_LE_OR_EXTENDS === modified file 'storage/innobase/btr/btr0sea.c' --- a/storage/innobase/btr/btr0sea.c 2009-04-24 12:16:40 +0000 +++ b/storage/innobase/btr/btr0sea.c 2009-07-02 14:23:36 +0000 @@ -774,8 +774,8 @@ btr_search_guess_on_hash( rw_lock_s_lock(&btr_search_latch); } - ut_ad(btr_search_latch.writer != RW_LOCK_EX); - ut_ad(btr_search_latch.reader_count > 0); + ut_ad(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_EX); + ut_ad(rw_lock_get_reader_count(&btr_search_latch) > 0); rec = ha_search_and_get_data(btr_search_sys->hash_index, fold); === modified file 'storage/innobase/buf/buf0buf.c' --- a/storage/innobase/buf/buf0buf.c 2008-09-06 07:22:50 +0000 +++ b/storage/innobase/buf/buf0buf.c 2009-07-02 14:23:36 +0000 @@ -1277,8 +1277,8 @@ loop: if (mode == BUF_GET_NOWAIT) { if (rw_latch == RW_S_LATCH) { - success = rw_lock_s_lock_func_nowait(&(block->lock), - file, line); + success = rw_lock_s_lock_nowait(&(block->lock), + file, line); fix_type = MTR_MEMO_PAGE_S_FIX; } else { ut_ad(rw_latch == RW_X_LATCH); @@ -1403,8 +1403,8 @@ buf_page_optimistic_get_func( ut_ad(!ibuf_inside() || ibuf_page(block->space, block->offset)); if (rw_latch == RW_S_LATCH) { - success = rw_lock_s_lock_func_nowait(&(block->lock), - file, line); + success = rw_lock_s_lock_nowait(&(block->lock), + file, line); fix_type = MTR_MEMO_PAGE_S_FIX; } else { success = rw_lock_x_lock_func_nowait(&(block->lock), @@ -1534,8 +1534,8 @@ buf_page_get_known_nowait( ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); if (rw_latch == RW_S_LATCH) { - success = rw_lock_s_lock_func_nowait(&(block->lock), - file, line); + success = rw_lock_s_lock_nowait(&(block->lock), + file, line); fix_type = MTR_MEMO_PAGE_S_FIX; } else { success = rw_lock_x_lock_func_nowait(&(block->lock), === modified file 'storage/innobase/handler/ha_innodb.cc' --- a/storage/innobase/handler/ha_innodb.cc 2009-06-18 08:20:27 +0000 +++ b/storage/innobase/handler/ha_innodb.cc 2009-07-02 14:23:36 +0000 @@ -104,7 +104,7 @@ static const long AUTOINC_NO_LOCKING = 2 static long innobase_mirrored_log_groups, innobase_log_files_in_group, innobase_log_buffer_size, innobase_buffer_pool_awe_mem_mb, - innobase_additional_mem_pool_size, innobase_file_io_threads, + innobase_additional_mem_pool_size, innobase_lock_wait_timeout, innobase_force_recovery, innobase_open_files, innobase_autoinc_lock_mode; @@ -139,6 +139,24 @@ static my_bool innobase_adaptive_hash_in static char* internal_innobase_data_file_path = NULL; +/* Default number of IO per second supported by server. Tunes background + IO rate. */ +static long innobase_io_capacity = 100; + +/* Write dirty pages when pct dirty is less than max pct dirty */ +static my_bool innobase_extra_dirty_writes = TRUE; + +/* Max number of IO requests merged to perform large IO in background + IO threads. +*/ +long innobase_max_merged_io = 64; + +/* Number of background IO threads for read and write. */ +long innobase_read_io_threads, innobase_write_io_threads; + +/* Use timer based InnoDB concurrency throttling flag */ +static my_bool innobase_thread_concurrency_timer_based; + /* The following counter is used to convey information to InnoDB about server activity: in selects it is not sensible to call srv_active_wake_master_thread after each fetch or search, we only do @@ -380,6 +398,10 @@ static SHOW_VAR innodb_status_variables[ (char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG}, {"dblwr_writes", (char*) &export_vars.innodb_dblwr_writes, SHOW_LONG}, + {"have_sync_atomic", + (char*) &export_vars.innodb_have_sync_atomic, SHOW_BOOL}, + {"heap_enabled", + (char*) &export_vars.innodb_heap_enabled, SHOW_BOOL}, {"log_waits", (char*) &export_vars.innodb_log_waits, SHOW_LONG}, {"log_write_requests", @@ -420,6 +442,8 @@ static SHOW_VAR innodb_status_variables[ (char*) &export_vars.innodb_rows_read, SHOW_LONG}, {"rows_updated", (char*) &export_vars.innodb_rows_updated, SHOW_LONG}, + {"wake_ups", + (char*) &export_vars.innodb_wake_ups, SHOW_LONG}, {NullS, NullS, SHOW_LONG} }; @@ -1702,11 +1726,17 @@ innobase_init( srv_n_log_files = (ulint) innobase_log_files_in_group; srv_log_file_size = (ulint) innobase_log_file_size; + srv_thread_concurrency_timer_based = + (ibool) innobase_thread_concurrency_timer_based; + #ifdef UNIV_LOG_ARCHIVE srv_log_archive_on = (ulint) innobase_log_archive; #endif /* UNIV_LOG_ARCHIVE */ srv_log_buffer_size = (ulint) innobase_log_buffer_size; + srv_io_capacity = (ulint) innobase_io_capacity; + srv_extra_dirty_writes = (ulint) innobase_extra_dirty_writes; + /* We set srv_pool_size here in units of 1 kB. InnoDB internally changes the value so that it becomes the number of database pages. */ @@ -1726,7 +1756,9 @@ innobase_init( srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size; - srv_n_file_io_threads = (ulint) innobase_file_io_threads; + srv_n_read_io_threads = (ulint) innobase_read_io_threads; + srv_n_write_io_threads = (ulint) innobase_write_io_threads; + srv_max_merged_io = (ulint) innobase_max_merged_io; srv_lock_wait_timeout = (ulint) innobase_lock_wait_timeout; srv_force_recovery = (ulint) innobase_force_recovery; @@ -7174,8 +7206,7 @@ innodb_show_status( mutex_enter_noninline(&srv_monitor_file_mutex); rewind(srv_monitor_file); - srv_printf_innodb_monitor(srv_monitor_file, - &trx_list_start, &trx_list_end); + srv_printf_innodb_monitor(srv_monitor_file); flen = ftell(srv_monitor_file); os_file_set_eof(srv_monitor_file); @@ -7244,6 +7275,7 @@ innodb_mutex_show_status( { char buf1[IO_SIZE], buf2[IO_SIZE]; mutex_t* mutex; + rw_lock_t* lock; #ifdef UNIV_DEBUG ulint rw_lock_count= 0; ulint rw_lock_count_spin_loop= 0; @@ -7314,6 +7346,31 @@ innodb_mutex_show_status( mutex_exit_noninline(&mutex_list_mutex); + mutex_enter_noninline(&rw_lock_list_mutex); + + lock = UT_LIST_GET_FIRST(rw_lock_list); + + while (lock != NULL) + { + if (lock->count_os_wait) + { + buf1len= my_snprintf(buf1, sizeof(buf1), "%s:%lu", + lock->cfile_name, (ulong) lock->cline); + buf2len= my_snprintf(buf2, sizeof(buf2), + "os_waits=%lu", lock->count_os_wait); + + if (stat_print(thd, innobase_hton_name, + hton_name_len, buf1, buf1len, + buf2, buf2len)) { + mutex_exit_noninline(&rw_lock_list_mutex); + DBUG_RETURN(1); + } + } + lock = UT_LIST_GET_NEXT(list, lock); + } + + mutex_exit_noninline(&rw_lock_list_mutex); + #ifdef UNIV_DEBUG buf2len= my_snprintf(buf2, sizeof(buf2), "count=%lu, spin_waits=%lu, spin_rounds=%lu, " @@ -7346,6 +7403,7 @@ bool innobase_show_status(handlerton *ht return FALSE; } } + rw_lock_t* lock; /**************************************************************************** @@ -8278,6 +8336,16 @@ static MYSQL_SYSVAR_BOOL(doublewrite, in "Disable with --skip-innodb-doublewrite.", NULL, NULL, TRUE); +static MYSQL_SYSVAR_BOOL(extra_dirty_writes, innobase_extra_dirty_writes, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Flush dirty buffer pages when dirty max pct is not exceeded", + NULL, NULL, TRUE); + +static MYSQL_SYSVAR_LONG(io_capacity, innobase_io_capacity, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Number of IOPs the server can do. Tunes the background IO rate", + NULL, NULL, (long)200, (long)100, LONG_MAX, (long)0); + static MYSQL_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown, PLUGIN_VAR_OPCMDARG, "Speeds up the shutdown process of the InnoDB storage engine. Possible " @@ -8288,7 +8356,8 @@ static MYSQL_SYSVAR_ULONG(fast_shutdown, */ IF_NETWARE("", " or 2 (fastest - crash-like)") ".", - NULL, NULL, 1, 0, IF_NETWARE(1,2), 0); + NULL, NULL, (unsigned long)1, (unsigned long)0, + (unsigned long)IF_NETWARE(1,2), (unsigned long)0); static MYSQL_SYSVAR_BOOL(file_per_table, innobase_file_per_table, PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, @@ -8300,7 +8369,8 @@ static MYSQL_SYSVAR_ULONG(flush_log_at_t "Set to 0 (write and flush once per second)," " 1 (write and flush at each commit)" " or 2 (write at commit, flush once per second).", - NULL, NULL, 1, 0, 2, 0); + NULL, NULL, (unsigned long)1, (unsigned long)0, (unsigned long)2, + (unsigned long)0); static MYSQL_SYSVAR_STR(flush_method, innobase_unix_file_flush_method, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, @@ -8328,12 +8398,14 @@ static MYSQL_SYSVAR_STR(log_group_home_d static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct, PLUGIN_VAR_RQCMDARG, "Percentage of dirty pages allowed in bufferpool.", - NULL, NULL, 90, 0, 100, 0); + NULL, NULL, (unsigned long)75, (unsigned long)0, (unsigned long)99, + (unsigned long)0); static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag, PLUGIN_VAR_RQCMDARG, "Desired maximum length of the purge queue (0 = no limit)", - NULL, NULL, 0, 0, ~0L, 0); + NULL, NULL, (unsigned long)0, (unsigned long)0, (unsigned long)~0L, + (unsigned long)0); static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, @@ -8359,82 +8431,106 @@ static MYSQL_SYSVAR_BOOL(adaptive_hash_i static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.", - NULL, NULL, 1*1024*1024L, 512*1024L, LONG_MAX, 1024); + NULL, NULL, (long)8*1024*1024L, (long)2*1024*1024L, LONG_MAX, (long)1024); static MYSQL_SYSVAR_ULONG(autoextend_increment, srv_auto_extend_increment, PLUGIN_VAR_RQCMDARG, "Data file autoextend increment in megabytes", - NULL, NULL, 8L, 1L, 1000L, 0); + NULL, NULL, (unsigned long)64L, (unsigned long)1L, (unsigned long)1000L, + (unsigned long)0); static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.", - NULL, NULL, 8*1024*1024L, 1024*1024L, LONGLONG_MAX, 1024*1024L); + NULL, NULL, (long long)1024*1024*1024L, (long long)64*1024*1024L, + LONGLONG_MAX, (long long)1024*1024L); static MYSQL_SYSVAR_ULONG(commit_concurrency, srv_commit_concurrency, PLUGIN_VAR_RQCMDARG, "Helps in performance tuning in heavily concurrent environments.", - NULL, NULL, 0, 0, 1000, 0); + NULL, NULL, (unsigned long)0, (unsigned long)0, (unsigned long)1000, + (unsigned long)0); static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", - NULL, NULL, 500L, 1L, ~0L, 0); + NULL, NULL, (unsigned long)500L, (unsigned long)1L, (unsigned long)~0L, + (unsigned long)0); + +static MYSQL_SYSVAR_LONG(write_io_threads, innobase_write_io_threads, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Number of write I/O threads in InnoDB.", + NULL, NULL, (long)8, (long)1, (long)64, (long)0); -static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, +static MYSQL_SYSVAR_LONG(read_io_threads, innobase_read_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Number of file I/O threads in InnoDB.", - NULL, NULL, 4, 4, 64, 0); + "Number of read I/O threads in InnoDB.", + NULL, NULL, (long)8, (long)1, (long)64, (long)0); + +static MYSQL_SYSVAR_LONG(max_merged_io, innobase_max_merged_io, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Max number of adjacent IO requests to merge in InnoDB.", + NULL, NULL, (long)64, (long)1, (long)64, (long)0); static MYSQL_SYSVAR_LONG(force_recovery, innobase_force_recovery, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Helps to save your data in case the disk image of the database becomes corrupt.", - NULL, NULL, 0, 0, 6, 0); + NULL, NULL, (long)0, (long)0, (long)6, (long)0); static MYSQL_SYSVAR_LONG(lock_wait_timeout, innobase_lock_wait_timeout, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back.", - NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0); + NULL, NULL, (long)50, (long)1, (long)(1024*1024*1024), (long)0); static MYSQL_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "The size of the buffer which InnoDB uses to write log to the log files on disk.", - NULL, NULL, 1024*1024L, 256*1024L, LONG_MAX, 1024); + NULL, NULL, (long)16*1024*1024L, (long)2*1024*1024L, LONG_MAX, (long)1024); static MYSQL_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Size of each log file in a log group.", - NULL, NULL, 5*1024*1024L, 1*1024*1024L, LONGLONG_MAX, 1024*1024L); + NULL, NULL, (long long)128*1024*1024L, (long long)32*1024*1024L, + LONGLONG_MAX, (long long)1024*1024L); static MYSQL_SYSVAR_LONG(log_files_in_group, innobase_log_files_in_group, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.", - NULL, NULL, 2, 2, 100, 0); + NULL, NULL, (long)3, (long)2, (long)100, (long)0); static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.", - NULL, NULL, 1, 1, 10, 0); + NULL, NULL, (long)1, (long)1, (long)10, (long)0); static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "How many files at the maximum InnoDB keeps open at the same time.", - NULL, NULL, 300L, 10L, LONG_MAX, 0); + NULL, NULL, (long)300L, (long)10L, LONG_MAX, (long)0L); static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, PLUGIN_VAR_RQCMDARG, "Count of spin-loop rounds in InnoDB mutexes", - NULL, NULL, 20L, 0L, ~0L, 0); + NULL, NULL, (unsigned long)20L, (unsigned long)0L, (unsigned long)~0L, + (unsigned long)0L); + +static MYSQL_SYSVAR_BOOL(thread_concurrency_timer_based, + innobase_thread_concurrency_timer_based, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Use InnoDB timer based concurrency throttling. ", + NULL, NULL, TRUE); static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, PLUGIN_VAR_RQCMDARG, "Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.", - NULL, NULL, 8, 0, 1000, 0); + NULL, NULL, (unsigned long)0, (unsigned long)0, (unsigned long)1000, + (unsigned long)0); static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay, PLUGIN_VAR_RQCMDARG, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep", - NULL, NULL, 10000L, 0L, ~0L, 0); + NULL, NULL, (unsigned long)10000L, (unsigned long)0L, (unsigned long)~0L, + (unsigned long)0); static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, @@ -8451,7 +8547,7 @@ static MYSQL_SYSVAR_LONG(autoinc_lock_mo NULL, NULL, AUTOINC_NEW_STYLE_LOCKING, /* Default setting */ AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */ - AUTOINC_NO_LOCKING, 0); /* Maximum value */ + AUTOINC_NO_LOCKING, (long)0); /* Maximum value */ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(additional_mem_pool_size), @@ -8464,7 +8560,10 @@ static struct st_mysql_sys_var* innobase MYSQL_SYSVAR(data_home_dir), MYSQL_SYSVAR(doublewrite), MYSQL_SYSVAR(fast_shutdown), - MYSQL_SYSVAR(file_io_threads), + MYSQL_SYSVAR(read_io_threads), + MYSQL_SYSVAR(write_io_threads), + MYSQL_SYSVAR(max_merged_io), + MYSQL_SYSVAR(thread_concurrency_timer_based), MYSQL_SYSVAR(file_per_table), MYSQL_SYSVAR(flush_log_at_trx_commit), MYSQL_SYSVAR(flush_method), @@ -8493,6 +8592,8 @@ static struct st_mysql_sys_var* innobase MYSQL_SYSVAR(thread_concurrency), MYSQL_SYSVAR(thread_sleep_delay), MYSQL_SYSVAR(autoinc_lock_mode), + MYSQL_SYSVAR(extra_dirty_writes), + MYSQL_SYSVAR(io_capacity), NULL }; === modified file 'storage/innobase/include/buf0buf.ic' --- a/storage/innobase/include/buf0buf.ic 2008-02-01 10:55:39 +0000 +++ b/storage/innobase/include/buf0buf.ic 2008-10-15 18:54:18 +0000 @@ -513,7 +513,7 @@ buf_block_buf_fix_inc_debug( { ibool ret; - ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line); + ret = rw_lock_s_lock_nowait(&(block->debug_latch), file, line); ut_ad(ret == TRUE); ut_ad(mutex_own(&block->mutex)); === modified file 'storage/innobase/include/log0log.h' --- a/storage/innobase/include/log0log.h 2006-03-10 16:22:21 +0000 +++ b/storage/innobase/include/log0log.h 2008-10-15 12:30:31 +0000 @@ -169,6 +169,13 @@ void log_buffer_flush_to_disk(void); /*==========================*/ /******************************************************************** +Flushes the log buffer. Forces it to disk depending on the value of +the configuration parameter innodb_flush_log_at_trx_commit. */ + +void +log_buffer_flush_maybe_sync(void); +/*==========================*/ +/******************************************************************** Advances the smallest lsn for which there are unflushed dirty blocks in the buffer pool and also may make a new checkpoint. NOTE: this function may only be called if the calling thread owns no synchronization objects! */ === modified file 'storage/innobase/include/os0file.h' --- a/storage/innobase/include/os0file.h 2007-07-10 14:34:21 +0000 +++ b/storage/innobase/include/os0file.h 2008-10-14 07:56:07 +0000 @@ -535,21 +535,19 @@ os_file_create_subdirs_if_needed( FALSE otherwise */ const char* path); /* in: path name */ /**************************************************************************** -Initializes the asynchronous io system. Creates separate aio array for -non-ibuf read and write, a third aio array for the ibuf i/o, with just one -segment, two aio arrays for log reads and writes with one segment, and a -synchronous aio array of the specified size. The combined number of segments -in the three first aio arrays is the parameter n_segments given to the -function. The caller must create an i/o handler thread for each segment in -the four first arrays, but not for the sync aio array. */ +Initializes the asynchronous io system. Creates n_read_threads segments for +read, n_write_threads segments for writes, one segment for the ibuf i/o, and +one segment for log IO. Returns the number of segments created. When async +IO is not used, and 4 threads should be created to process requests put +in the segments. */ -void +ulint os_aio_init( /*========*/ - ulint n, /* in: maximum number of pending aio operations - allowed; n must be divisible by n_segments */ - ulint n_segments, /* in: combined number of segments in the four - first aio arrays; must be >= 4 */ + ulint ios_per_array, /* in: maximum number of pending aio operations + allowed per array */ + ulint n_read_threads, /* in: number of read threads */ + ulint n_write_threads, /* in: number of write threads */ ulint n_slots_sync); /* in: number of slots in the sync aio array */ /*********************************************************************** Requests an asynchronous i/o operation. */ === modified file 'storage/innobase/include/os0sync.h' --- a/storage/innobase/include/os0sync.h 2008-06-12 00:08:07 +0000 +++ b/storage/innobase/include/os0sync.h 2009-07-02 14:23:36 +0000 @@ -12,6 +12,10 @@ Created 9/6/1995 Heikki Tuuri #include "univ.i" #include "ut0lst.h" +#ifdef HAVE_SOLARIS_ATOMIC +#include +#endif + #ifdef __WIN__ #define os_fast_mutex_t CRITICAL_SECTION @@ -261,6 +265,45 @@ os_fast_mutex_free( /*===============*/ os_fast_mutex_t* fast_mutex); /* in: mutex to free */ +#ifdef UNIV_SYNC_ATOMIC +/************************************************************** +Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins. */ +UNIV_INLINE +ibool +os_compare_and_swap( +/*================*/ + /* out: true if swapped */ + volatile lint* ptr, /* in: pointer to target */ + lint oldVal, /* in: value to compare to */ + lint newVal); /* in: value to swap in */ + +/************************************************************** +Atomic increment for InnoDB. Currently requires GCC atomic builtins. */ +UNIV_INLINE +lint +os_atomic_increment( +/*================*/ + /* out: resulting value */ + volatile lint* ptr, /* in: pointer to target */ + lint amount); /* in: amount of increment */ + +/************************************************************** +Memory barrier operations for InnoDB. +Currently requires GCC atomic builtins. */ +UNIV_INLINE +void +os_memory_barrier_load(); + +UNIV_INLINE +void +os_memory_barrier_store(); + +UNIV_INLINE +void +os_memory_barrier(); + +#endif /* UNIV_SYNC_ATOMIC */ + #ifndef UNIV_NONINL #include "os0sync.ic" #endif === modified file 'storage/innobase/include/os0sync.ic' --- a/storage/innobase/include/os0sync.ic 2006-03-10 16:22:21 +0000 +++ b/storage/innobase/include/os0sync.ic 2009-06-16 13:16:15 +0000 @@ -44,3 +44,109 @@ os_fast_mutex_trylock( #endif #endif } + +#ifdef UNIV_SYNC_ATOMIC +/************************************************************** +Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins +or Solaris atomic_* functions. */ +UNIV_INLINE +ibool +os_compare_and_swap( +/*================*/ + /* out: true if swapped */ + volatile lint* ptr, /* in: pointer to target */ + lint oldVal, /* in: value to compare to */ + lint newVal) /* in: value to swap in */ +{ +#ifdef HAVE_GCC_ATOMIC_BUILTINS + return (__sync_bool_compare_and_swap(ptr, oldVal, newVal)); +#elif HAVE_SOLARIS_ATOMIC + lint retVal = (lint)atomic_cas_ulong((volatile ulong_t *)ptr, + oldVal, newVal); + return (retVal == oldVal); +#elif WIN_ATOMICS32 + lint retVal = (lint)InterlockedCompareExchange(ptr, newVal, oldVal); + return (retVal == oldVal); +#elif WIN_ATOMICS64 + lint retVal = (lint)InterlockedCompareExchange64(ptr, newVal, oldVal); + return (retVal == oldVal); +#else +#error "Need support for atomic ops" +#endif +} + +/************************************************************** +Memory barrier for load */ +UNIV_INLINE +void +os_memory_barrier_load() +{ +#ifdef HAVE_GCC_ATOMIC_BUILTINS + __sync_synchronize(); +#elif HAVE_SOLARIS_ATOMIC + membar_consumer(); +#elif WIN_ATOMICS32 + MemoryBarrier(); +#elif WIN_ATOMICS64 + MemoryBarrier(); +#endif +} + +/************************************************************** +Memory barrier for store */ +UNIV_INLINE +void +os_memory_barrier_store() +{ +#ifdef HAVE_GCC_ATOMIC_BUILTINS + __sync_synchronize(); +#elif HAVE_SOLARIS_ATOMIC + membar_producer(); +#elif WIN_ATOMICS32 + MemoryBarrier(); +#elif WIN_ATOMICS64 + MemoryBarrier(); +#endif +} + +/************************************************************** +Memory barrier */ +UNIV_INLINE +void +os_memory_barrier() +{ +#ifdef HAVE_GCC_ATOMIC_BUILTINS + __sync_synchronize(); +#elif HAVE_SOLARIS_ATOMIC + membar_enter(); +#elif WIN_ATOMICS32 + MemoryBarrier(); +#elif WIN_ATOMICS64 + MemoryBarrier(); +#endif +} + + +/************************************************************** +Atomic increment for InnoDB. Currently requires GCC atomic builtins. */ +UNIV_INLINE +lint +os_atomic_increment( +/*================*/ + /* out: resulting value */ + volatile lint* ptr, /* in: pointer to target */ + lint amount) /* in: amount of increment */ +{ +#ifdef HAVE_GCC_ATOMIC_BUILTINS + return (__sync_add_and_fetch(ptr, amount)); +#elif HAVE_SOLARIS_ATOMIC + return ((lint)atomic_add_long_nv((volatile ulong_t *)ptr, amount)); +#elif WIN_ATOMICS32 + return ((lint)InterlockedExchangeAdd(ptr, amount) + amount); +#elif WIN_ATOMICS64 + return ((lint)InterlockedExchangeAdd64(ptr, amount) + amount); +#else +#error "Need support for atomic ops" +#endif +} +#endif /* UNIV_SYNC_ATOMIC */ === modified file 'storage/innobase/include/srv0srv.h' --- a/storage/innobase/include/srv0srv.h 2009-05-19 08:37:33 +0000 +++ b/storage/innobase/include/srv0srv.h 2009-07-02 14:23:36 +0000 @@ -89,7 +89,22 @@ extern ulint srv_awe_window_size; extern ulint srv_mem_pool_size; extern ulint srv_lock_table_size; -extern ulint srv_n_file_io_threads; +extern ibool srv_thread_concurrency_timer_based; + +/* Number of background IO threads for read and write. Replaces + * srv_n_file_io_threads. */ +extern ulint srv_n_read_io_threads; +extern ulint srv_n_write_io_threads; +/* Max number of adjacent IO requests to merge into one large request. */ +extern ulint srv_max_merged_io; + +/* Number of IO operations per second the server can do */ +extern ulint srv_io_capacity; + +/* Flush dirty pages when below max dirty percent */ +extern ibool srv_extra_dirty_writes; + + #ifdef UNIV_LOG_ARCHIVE extern ibool srv_log_archive_on; @@ -232,6 +247,9 @@ extern ulint srv_read_ahead_seq; /* variable to count the number of random read-aheads were done */ extern ulint srv_read_ahead_rnd; +/* Number of threads that may have missed a lock wait wakeup */ +extern ulint sync_wake_ups; + /* In this structure we store status variables to be passed to MySQL */ typedef struct export_var_struct export_struc; @@ -444,11 +462,7 @@ Outputs to a file the output of the Inno void srv_printf_innodb_monitor( /*======================*/ - FILE* file, /* in: output stream */ - ulint* trx_start, /* out: file position of the start of - the list of active transactions */ - ulint* trx_end); /* out: file position of the end of - the list of active transactions */ + FILE* file); /* in: output stream */ /********************************************************************** Function to pass InnoDB status variables to MySQL */ @@ -508,6 +522,8 @@ struct export_var_struct{ ulint innodb_buffer_pool_read_ahead_rnd; ulint innodb_dblwr_pages_written; ulint innodb_dblwr_writes; + ibool innodb_have_sync_atomic; + ibool innodb_heap_enabled; ulint innodb_log_waits; ulint innodb_log_write_requests; ulint innodb_log_writes; @@ -528,6 +544,7 @@ struct export_var_struct{ ulint innodb_rows_inserted; ulint innodb_rows_updated; ulint innodb_rows_deleted; + ulint innodb_wake_ups; }; /* The server system struct */ @@ -544,4 +561,3 @@ struct srv_sys_struct{ extern ulint srv_n_threads_active[]; #endif - === modified file 'storage/innobase/include/sync0rw.h' --- a/storage/innobase/include/sync0rw.h 2008-06-12 00:08:07 +0000 +++ b/storage/innobase/include/sync0rw.h 2009-07-02 14:23:36 +0000 @@ -24,6 +24,12 @@ smaller than 30 and the order of the num #define RW_X_LATCH 2 #define RW_NO_LATCH 3 +/* We decrement lock_word by this amount for each x_lock. It is also the +start value for the lock_word, meaning that it limits the maximum number +of concurrent read locks before the rw_lock breaks. The current value of +0x00100000 allows 1,048,575 concurrent readers and 2047 recursive writers.*/ +#define X_LOCK_DECR 0x00100000 + typedef struct rw_lock_struct rw_lock_t; #ifdef UNIV_SYNC_DEBUG typedef struct rw_lock_debug_struct rw_lock_debug_t; @@ -47,14 +53,14 @@ extern ibool rw_lock_debug_waiters; /* there may be waiters for the event */ #endif /* UNIV_SYNC_DEBUG */ -extern ulint rw_s_system_call_count; -extern ulint rw_s_spin_wait_count; -extern ulint rw_s_exit_count; -extern ulint rw_s_os_wait_count; -extern ulint rw_x_system_call_count; -extern ulint rw_x_spin_wait_count; -extern ulint rw_x_os_wait_count; -extern ulint rw_x_exit_count; +extern ib_longlong rw_s_spin_wait_count; +extern ib_longlong rw_s_spin_round_count; +extern ib_longlong rw_s_exit_count; +extern ib_longlong rw_s_os_wait_count; +extern ib_longlong rw_x_spin_wait_count; +extern ib_longlong rw_x_spin_round_count; +extern ib_longlong rw_x_os_wait_count; +extern ib_longlong rw_x_exit_count; /********************************************************************** Creates, or rather, initializes an rw-lock object in a specified memory @@ -111,6 +117,20 @@ rw_lock_validate( /*=============*/ rw_lock_t* lock); #endif /* UNIV_DEBUG */ +/********************************************************************** +Low-level function which tries to lock an rw-lock in s-mode. Performs no +spinning. */ +UNIV_INLINE +ibool +rw_lock_s_lock_low( +/*===============*/ + /* out: TRUE if success */ + rw_lock_t* lock, /* in: pointer to rw-lock */ + ulint pass, + /* in: pass value; != 0, if the lock will be + passed to another thread to unlock */ + const char* file_name, /* in: file name where lock requested */ + ulint line); /* in: line where requested */ /****************************************************************** NOTE! The following macros should be used in rw s-locking, not the corresponding function. */ @@ -127,8 +147,8 @@ corresponding function. */ NOTE! The following macros should be used in rw s-locking, not the corresponding function. */ -#define rw_lock_s_lock_nowait(M) rw_lock_s_lock_func_nowait(\ - (M), __FILE__, __LINE__) +#define rw_lock_s_lock_nowait(M, F, L) rw_lock_s_lock_low(\ + (M), 0, (F), (L)) /********************************************************************** NOTE! Use the corresponding macro, not directly this function, except if you supply the file name and line number. Lock an rw-lock in shared mode @@ -146,18 +166,6 @@ rw_lock_s_lock_func( const char* file_name,/* in: file name where lock requested */ ulint line); /* in: line where requested */ /********************************************************************** -NOTE! Use the corresponding macro, not directly this function, except if -you supply the file name and line number. Lock an rw-lock in shared mode -for the current thread if the lock can be acquired immediately. */ -UNIV_INLINE -ibool -rw_lock_s_lock_func_nowait( -/*=======================*/ - /* out: TRUE if success */ - rw_lock_t* lock, /* in: pointer to rw-lock */ - const char* file_name,/* in: file name where lock requested */ - ulint line); /* in: line where requested */ -/********************************************************************** NOTE! Use the corresponding macro, not directly this function! Lock an rw-lock in exclusive mode for the current thread if the lock can be obtained immediately. */ @@ -341,6 +349,23 @@ ulint rw_lock_get_reader_count( /*=====================*/ rw_lock_t* lock); +/********************************************************************** +Decrements lock_word the specified amount if it is greater than 0. +This is used by both s_lock and x_lock operations. */ +UNIV_INLINE +ibool +rw_lock_lock_word_decr( + /* out: TRUE if decr occurs */ + rw_lock_t* lock, /* in: rw-lock */ + ulint amount); /* in: amount to decrement */ +/********************************************************************** +Increments lock_word the specified amount and returns new value. */ +UNIV_INLINE +lint +rw_lock_lock_word_incr( + /* out: TRUE if decr occurs */ + rw_lock_t* lock, + ulint amount); /* in: rw-lock */ #ifdef UNIV_SYNC_DEBUG /********************************************************************** Checks if the thread has locked the rw-lock in the specified mode, with @@ -417,44 +442,28 @@ Do not use its fields directly! The stru implementation of a read-write lock. Several threads may have a shared lock simultaneously in this lock, but only one writer may have an exclusive lock, in which case no shared locks are allowed. To prevent starving of a writer -blocked by readers, a writer may queue for the lock by setting the writer -field. Then no new readers are allowed in. */ +blocked by readers, a writer may queue for x-lock by decrementing lock_word: +no new readers will be let in while the thread waits for readers to exit. */ struct rw_lock_struct { - os_event_t event; /* Used by sync0arr.c for thread queueing */ - -#ifdef __WIN__ - os_event_t wait_ex_event; /* This windows specific event is - used by the thread which has set the - lock state to RW_LOCK_WAIT_EX. The - rw_lock design guarantees that this - thread will be the next one to proceed - once the current the event gets - signalled. See LEMMA 2 in sync0sync.c */ -#endif - - ulint reader_count; /* Number of readers who have locked this - lock in the shared mode */ - ulint writer; /* This field is set to RW_LOCK_EX if there - is a writer owning the lock (in exclusive - mode), RW_LOCK_WAIT_EX if a writer is - queueing for the lock, and - RW_LOCK_NOT_LOCKED, otherwise. */ - os_thread_id_t writer_thread; - /* Thread id of a possible writer thread */ - ulint writer_count; /* Number of times the same thread has - recursively locked the lock in the exclusive - mode */ - mutex_t mutex; /* The mutex protecting rw_lock_struct */ - ulint pass; /* Default value 0. This is set to some + volatile lint lock_word; + /* Holds the state of the lock. */ + volatile ulint waiters;/* 1: there are waiters */ + volatile ulint pass; /* Default value 0. This is set to some value != 0 given by the caller of an x-lock operation, if the x-lock is to be passed to another thread to unlock (which happens in asynchronous i/o). */ - ulint waiters; /* This ulint is set to 1 if there are - waiters (readers or writers) in the global - wait array, waiting for this rw_lock. - Otherwise, == 0. */ + volatile os_thread_id_t writer_thread; + /* Thread id of writer thread */ + os_event_t event; /* Used by sync0arr.c for thread queueing */ + os_event_t wait_ex_event; + /* Event for next-writer to wait on. A thread + must decrement lock_word before waiting. */ +#ifndef UNIV_SYNC_ATOMIC + mutex_t mutex; /* The mutex protecting rw_lock_struct */ +#endif /* UNIV_SYNC_ATOMIC */ + UT_LIST_NODE_T(rw_lock_t) list; /* All allocated rw locks are put into a list */ @@ -464,7 +473,9 @@ struct rw_lock_struct { info list of the lock */ ulint level; /* Level in the global latching order. */ #endif /* UNIV_SYNC_DEBUG */ + ulint count_os_wait; /* Count of os_waits. May not be accurate */ const char* cfile_name;/* File name where lock created */ + /* last s-lock file/line is not guaranteed to be correct */ const char* last_s_file_name;/* File name where last s-locked */ const char* last_x_file_name;/* File name where last x-locked */ ibool writer_is_wait_ex; === modified file 'storage/innobase/include/sync0rw.ic' --- a/storage/innobase/include/sync0rw.ic 2008-06-12 00:08:07 +0000 +++ b/storage/innobase/include/sync0rw.ic 2009-07-02 14:23:36 +0000 @@ -57,45 +57,68 @@ UNIV_INLINE void rw_lock_set_waiters( /*================*/ - rw_lock_t* lock, - ulint flag) + rw_lock_t* lock) { - lock->waiters = flag; +#ifdef UNIV_SYNC_ATOMIC + os_compare_and_swap(&(lock->waiters), 0, 1); +#else /* UNIV_SYNC_ATOMIC */ + lock->waiters = 1; +#endif /* UNIV_SYNC_ATOMIC */ } UNIV_INLINE -ulint -rw_lock_get_writer( -/*===============*/ +void +rw_lock_reset_waiters( +/*================*/ rw_lock_t* lock) { - return(lock->writer); +#ifdef UNIV_SYNC_ATOMIC + os_compare_and_swap(&(lock->waiters), 1, 0); +#else /* UNIV_SYNC_ATOMIC */ + lock->waiters = 0; +#endif /* UNIV_SYNC_ATOMIC */ } + +/********************************************************************** +Returns the write-status of the lock - this function made more sense +with the old rw_lock implementation. + */ UNIV_INLINE -void -rw_lock_set_writer( +ulint +rw_lock_get_writer( /*===============*/ - rw_lock_t* lock, - ulint flag) + rw_lock_t* lock) { - lock->writer = flag; + lint lock_word = lock->lock_word; + if(lock_word > 0) { + /* return NOT_LOCKED in s-lock state, like the writer + member of the old lock implementation. */ + return RW_LOCK_NOT_LOCKED; + } else if (((-lock_word) % X_LOCK_DECR) == 0) { + return RW_LOCK_EX; + } else { + ut_ad(lock_word > -X_LOCK_DECR); + return RW_LOCK_WAIT_EX; + } } + UNIV_INLINE ulint rw_lock_get_reader_count( /*=====================*/ rw_lock_t* lock) { - return(lock->reader_count); -} -UNIV_INLINE -void -rw_lock_set_reader_count( -/*=====================*/ - rw_lock_t* lock, - ulint count) -{ - lock->reader_count = count; + lint lock_word = lock->lock_word; + if(lock_word > 0) { + /* s-locked, no x-waiters */ + return(X_LOCK_DECR - lock_word); + } else if (lock_word < 0 && lock_word > -X_LOCK_DECR) { + /* s-locked, with x-waiters */ + return (ulint)(-lock_word); + } + return 0; } + +#ifndef UNIV_SYNC_ATOMIC UNIV_INLINE mutex_t* rw_lock_get_mutex( @@ -104,6 +127,7 @@ rw_lock_get_mutex( { return(&(lock->mutex)); } +#endif /********************************************************************** Returns the value of writer_count for the lock. Does not reserve the lock @@ -115,7 +139,87 @@ rw_lock_get_x_lock_count( /* out: value of writer_count */ rw_lock_t* lock) /* in: rw-lock */ { - return(lock->writer_count); + lint lock_copy = lock->lock_word; + /* If there is a reader, lock_word is not divisible by X_LOCK_DECR */ + if(lock_copy > 0 || (-lock_copy) % X_LOCK_DECR != 0) { + return 0; + } + return ((-lock_copy) / X_LOCK_DECR) + 1; +} + +/********************************************************************** +Two different implementations for decrementing the lock_word of a rw_lock: +one for systems supporting atomic operations, one for others. This does +does not support recusive x-locks: they should be handled by the caller and +need not be atomic since they are performed by the current lock holder. +Returns true if the decrement was made, false if not. */ +UNIV_INLINE +ibool +rw_lock_lock_word_decr( + /* out: TRUE if decr occurs */ + rw_lock_t* lock, /* in: rw-lock */ + ulint amount) /* in: amount of decrement */ +{ + +#ifdef UNIV_SYNC_ATOMIC + + lint local_lock_word = lock->lock_word; + while (local_lock_word > 0) { + if(os_compare_and_swap(&(lock->lock_word), + local_lock_word, + local_lock_word - amount)) { + return TRUE; + } + local_lock_word = lock->lock_word; + } + return(FALSE); + +#else /* UNIV_SYNC_ATOMIC */ + + ibool success = FALSE; + mutex_enter(&(lock->mutex)); + if(lock->lock_word > 0) { + lock->lock_word -= amount; + success = TRUE; + } + mutex_exit(&(lock->mutex)); + return success; + +#endif /* UNIV_SYNC_ATOMIC */ + +} + +/********************************************************************** +Two different implementations for incrementing the lock_word of a rw_lock: +one for systems supporting atomic operations, one for others. +Returns the value of lock_word after increment. */ +UNIV_INLINE +lint +rw_lock_lock_word_incr( + /* out: lock->lock_word after increment */ + rw_lock_t* lock, /* in: rw-lock */ + ulint amount) /* in: amount of increment */ +{ + +#ifdef UNIV_SYNC_ATOMIC + + return(os_atomic_increment(&(lock->lock_word), amount)); + +#else /* UNIV_SYNC_ATOMIC */ + + lint local_lock_word; + + mutex_enter(&(lock->mutex)); + + lock->lock_word += amount; + local_lock_word = lock->lock_word; + + mutex_exit(&(lock->mutex)); + + return local_lock_word; + +#endif /* UNIV_SYNC_ATOMIC */ + } /********************************************************************** @@ -133,27 +237,24 @@ rw_lock_s_lock_low( const char* file_name, /* in: file name where lock requested */ ulint line) /* in: line where requested */ { - ut_ad(mutex_own(rw_lock_get_mutex(lock))); - - /* Check if the writer field is free */ - - if (UNIV_LIKELY(lock->writer == RW_LOCK_NOT_LOCKED)) { - /* Set the shared lock by incrementing the reader count */ - lock->reader_count++; + /* TODO: study performance of UNIV_LIKELY branch prediction hints. */ + if (!rw_lock_lock_word_decr(lock, 1)) { + /* Locking did not succeed */ + return(FALSE); + } #ifdef UNIV_SYNC_DEBUG - rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name, - line); + rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name, line); #endif - lock->last_s_file_name = file_name; - lock->last_s_line = line; - - return(TRUE); /* locking succeeded */ - } + /* These debugging values are not set safely: they may be incorrect + or even refer to a line that is invalid for the file name. */ + lock->last_s_file_name = file_name; + lock->last_s_line = line; - return(FALSE); /* locking did not succeed */ + return(TRUE); /* locking succeeded */ } +/* TODO: The "direct" functions are not used. Remove them? */ /********************************************************************** Low-level function which locks an rw-lock in s-mode when we know that it is possible and none else is currently accessing the rw-lock structure. @@ -166,11 +267,10 @@ rw_lock_s_lock_direct( const char* file_name, /* in: file name where requested */ ulint line) /* in: line where lock requested */ { - ut_ad(lock->writer == RW_LOCK_NOT_LOCKED); - ut_ad(rw_lock_get_reader_count(lock) == 0); + ut_ad(lock->lock_word == X_LOCK_DECR); - /* Set the shared lock by incrementing the reader count */ - lock->reader_count++; + /* Indicate there is a new reader by decrementing lock_word */ + lock->lock_word--; lock->last_s_file_name = file_name; lock->last_s_line = line; @@ -180,6 +280,7 @@ rw_lock_s_lock_direct( #endif } +/* TODO: The "direct" functions are not used. Remove them? */ /********************************************************************** Low-level function which locks an rw-lock in x-mode when we know that it is not locked and none else is currently accessing the rw-lock structure. @@ -193,12 +294,10 @@ rw_lock_x_lock_direct( ulint line) /* in: line where lock requested */ { ut_ad(rw_lock_validate(lock)); - ut_ad(rw_lock_get_reader_count(lock) == 0); - ut_ad(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); + ut_ad(lock->lock_word == X_LOCK_DECR); - rw_lock_set_writer(lock, RW_LOCK_EX); + lock->lock_word -= X_LOCK_DECR; lock->writer_thread = os_thread_get_curr_id(); - lock->writer_count++; lock->pass = 0; lock->last_x_file_name = file_name; @@ -240,15 +339,12 @@ rw_lock_s_lock_func( ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */ #endif /* UNIV_SYNC_DEBUG */ - mutex_enter(rw_lock_get_mutex(lock)); - - if (UNIV_LIKELY(rw_lock_s_lock_low(lock, pass, file_name, line))) { - mutex_exit(rw_lock_get_mutex(lock)); + /* TODO: study performance of UNIV_LIKELY branch prediction hints. */ + if (rw_lock_s_lock_low(lock, pass, file_name, line)) { return; /* Success */ } else { /* Did not succeed, try spin wait */ - mutex_exit(rw_lock_get_mutex(lock)); rw_lock_s_lock_spin(lock, pass, file_name, line); @@ -258,86 +354,66 @@ rw_lock_s_lock_func( /********************************************************************** NOTE! Use the corresponding macro, not directly this function! Lock an -rw-lock in shared mode for the current thread if the lock can be acquired -immediately. */ +rw-lock in exclusive mode for the current thread if the lock can be +obtained immediately. */ UNIV_INLINE ibool -rw_lock_s_lock_func_nowait( +rw_lock_x_lock_func_nowait( /*=======================*/ /* out: TRUE if success */ rw_lock_t* lock, /* in: pointer to rw-lock */ const char* file_name,/* in: file name where lock requested */ ulint line) /* in: line where requested */ { - ibool success = FALSE; - - mutex_enter(rw_lock_get_mutex(lock)); - - if (lock->writer == RW_LOCK_NOT_LOCKED) { - /* Set the shared lock by incrementing the reader count */ - lock->reader_count++; + os_thread_id_t curr_thread = os_thread_get_curr_id(); -#ifdef UNIV_SYNC_DEBUG - rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, - line); -#endif + ibool success; - lock->last_s_file_name = file_name; - lock->last_s_line = line; +#ifdef UNIV_SYNC_ATOMIC + success = os_compare_and_swap(&(lock->lock_word), X_LOCK_DECR, 0); +#else + success = FALSE; + mutex_enter(&(lock->mutex)); + if(lock->lock_word == X_LOCK_DECR) { + lock->lock_word = 0; success = TRUE; } + mutex_exit(&(lock->mutex)); - mutex_exit(rw_lock_get_mutex(lock)); - - return(success); -} - -/********************************************************************** -NOTE! Use the corresponding macro, not directly this function! Lock an -rw-lock in exclusive mode for the current thread if the lock can be -obtained immediately. */ -UNIV_INLINE -ibool -rw_lock_x_lock_func_nowait( -/*=======================*/ - /* out: TRUE if success */ - rw_lock_t* lock, /* in: pointer to rw-lock */ - const char* file_name,/* in: file name where lock requested */ - ulint line) /* in: line where requested */ -{ - ibool success = FALSE; - os_thread_id_t curr_thread = os_thread_get_curr_id(); - mutex_enter(rw_lock_get_mutex(lock)); - - if (UNIV_UNLIKELY(rw_lock_get_reader_count(lock) != 0)) { - } else if (UNIV_LIKELY(rw_lock_get_writer(lock) - == RW_LOCK_NOT_LOCKED)) { - rw_lock_set_writer(lock, RW_LOCK_EX); +#endif + if(success) { lock->writer_thread = curr_thread; lock->pass = 0; -relock: - lock->writer_count++; -#ifdef UNIV_SYNC_DEBUG - rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line); -#endif + } else if (!(lock->pass) && + os_thread_eq(lock->writer_thread, curr_thread)) { + /* Must verify pass first: otherwise another thread can + call move_ownership suddenly allowing recursive locks. + and after we have verified our thread_id matches + (though move_ownership has since changed it).*/ + + /* Relock: this lock_word modification is safe since no other + threads can modify (lock, unlock, or reserve) lock_word while + there is an exclusive writer and this is the writer thread. */ + lock->lock_word -= X_LOCK_DECR; - lock->last_x_file_name = file_name; - lock->last_x_line = line; + ut_ad(((-lock->lock_word) % X_LOCK_DECR) == 0); - success = TRUE; - } else if (rw_lock_get_writer(lock) == RW_LOCK_EX - && lock->pass == 0 - && os_thread_eq(lock->writer_thread, curr_thread)) { - goto relock; + } else { + /* Failure */ + return(FALSE); } +#ifdef UNIV_SYNC_DEBUG + rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line); +#endif - mutex_exit(rw_lock_get_mutex(lock)); + lock->last_x_file_name = file_name; + lock->last_x_line = line; ut_ad(rw_lock_validate(lock)); - return(success); + return(TRUE); } /********************************************************************** @@ -353,39 +429,21 @@ rw_lock_s_unlock_func( #endif ) { - mutex_t* mutex = &(lock->mutex); - ibool sg = FALSE; - - /* Acquire the mutex protecting the rw-lock fields */ - mutex_enter(mutex); - - /* Reset the shared lock by decrementing the reader count */ - - ut_a(lock->reader_count > 0); - lock->reader_count--; + ut_ad((lock->lock_word % X_LOCK_DECR) != 0); #ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED); #endif - /* If there may be waiters and this was the last s-lock, - signal the object */ - - if (UNIV_UNLIKELY(lock->waiters) - && lock->reader_count == 0) { - sg = TRUE; - - rw_lock_set_waiters(lock, 0); - } - - mutex_exit(mutex); + /* Increment lock_word to indicate 1 less reader */ + if(rw_lock_lock_word_incr(lock, 1) == 0) { - if (UNIV_UNLIKELY(sg)) { -#ifdef __WIN__ + /* wait_ex waiter exists. It may not be asleep, but we signal + anyway. We do not wake other waiters, because they can't + exist without wait_ex waiter and wait_ex waiter goes first.*/ os_event_set(lock->wait_ex_event); -#endif - os_event_set(lock->event); sync_array_object_signalled(sync_primary_wait_array); + } ut_ad(rw_lock_validate(lock)); @@ -395,6 +453,7 @@ rw_lock_s_unlock_func( #endif } +/* TODO: The "direct" functions are not used. Remove them? */ /********************************************************************** Releases a shared mode lock when we know there are no waiters and none else will access the lock during the time this function is executed. */ @@ -404,17 +463,16 @@ rw_lock_s_unlock_direct( /*====================*/ rw_lock_t* lock) /* in: rw-lock */ { - /* Reset the shared lock by decrementing the reader count */ - - ut_ad(lock->reader_count > 0); - - lock->reader_count--; + ut_ad(lock->lock_word < X_LOCK_DECR); #ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED); #endif - ut_ad(!lock->waiters); + /* Decrease reader count by incrementing lock_word */ + lock->lock_word++; + + ut_ad(!rw_lock_get_waiters(lock)); ut_ad(rw_lock_validate(lock)); #ifdef UNIV_SYNC_PERF_STAT rw_s_exit_count++; @@ -434,42 +492,34 @@ rw_lock_x_unlock_func( #endif ) { - ibool sg = FALSE; + uint local_pass; + ut_ad((lock->lock_word % X_LOCK_DECR) == 0); - /* Acquire the mutex protecting the rw-lock fields */ - mutex_enter(&(lock->mutex)); - - /* Reset the exclusive lock if this thread no longer has an x-mode - lock */ - - ut_ad(lock->writer_count > 0); - - lock->writer_count--; - - if (lock->writer_count == 0) { - rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); - } + /* + Must reset pass while we still have the lock. + If we are not the last unlocker, we correct it later in the function, + which is harmless since we still hold the lock. + */ + local_pass = lock->pass; + lock->pass = 1; #ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX); #endif - /* If there may be waiters, signal the lock */ - if (UNIV_UNLIKELY(lock->waiters) - && lock->writer_count == 0) { - - sg = TRUE; - rw_lock_set_waiters(lock, 0); - } - - mutex_exit(&(lock->mutex)); + if(rw_lock_lock_word_incr(lock, X_LOCK_DECR) == X_LOCK_DECR) { + /* Lock is now free. May have to signal read/write waiters. + We do not need to signal wait_ex waiters, since they cannot + exist when there is a writer. */ + if(rw_lock_get_waiters(lock)) { + rw_lock_reset_waiters(lock); + os_event_set(lock->event); + sync_array_object_signalled(sync_primary_wait_array); + } - if (UNIV_UNLIKELY(sg)) { -#ifdef __WIN__ - os_event_set(lock->wait_ex_event); -#endif - os_event_set(lock->event); - sync_array_object_signalled(sync_primary_wait_array); + } else { + /* We still hold x-lock, so we correct pass. */ + lock->pass = local_pass; } ut_ad(rw_lock_validate(lock)); @@ -479,6 +529,7 @@ rw_lock_x_unlock_func( #endif } +/* TODO: The "direct" functions are not used. Remove them? */ /********************************************************************** Releases an exclusive mode lock when we know there are no waiters, and none else will access the lock durint the time this function is executed. */ @@ -491,19 +542,15 @@ rw_lock_x_unlock_direct( /* Reset the exclusive lock if this thread no longer has an x-mode lock */ - ut_ad(lock->writer_count > 0); - - lock->writer_count--; - - if (lock->writer_count == 0) { - rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); - } + ut_ad((lock->lock_word % X_LOCK_DECR) == 0); #ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX); #endif + lock->pass = 1; + lock->lock_word += X_LOCK_DECR; - ut_ad(!lock->waiters); + ut_ad(!rw_lock_get_waiters(lock)); ut_ad(rw_lock_validate(lock)); #ifdef UNIV_SYNC_PERF_STAT === modified file 'storage/innobase/include/sync0sync.h' --- a/storage/innobase/include/sync0sync.h 2008-06-12 00:08:07 +0000 +++ b/storage/innobase/include/sync0sync.h 2009-07-02 14:23:36 +0000 @@ -16,6 +16,9 @@ Created 9/5/1995 Heikki Tuuri #include "os0thread.h" #include "os0sync.h" #include "sync0arr.h" +#ifndef WIN32 +#include "my_atomic.h" +#endif #ifndef UNIV_HOTBACKUP extern my_bool timed_mutexes; @@ -252,7 +255,7 @@ mutex_n_reserved(void); NOT to be used outside this module except in debugging! Gets the value of the lock word. */ UNIV_INLINE -ulint +byte mutex_get_lock_word( /*================*/ const mutex_t* mutex); /* in: mutex */ @@ -471,9 +474,16 @@ implementation of a mutual exclusion sem struct mutex_struct { os_event_t event; /* Used by sync0arr.c for the wait queue */ - ulint lock_word; /* This ulint is the target of the atomic - test-and-set instruction in Win32 */ -#if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) + + byte lock_word; /* This byte is the target of the atomic + test-and-set instruction in Win32 and + x86 32/64 with GCC 4.1.0 or later version */ +#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER) +#elif defined(MY_ATOMIC_NOLOCK) + /* We have my_atomic_* routines that are + intrinsically atomic, so no need for the + mutex. */ +#else os_fast_mutex_t os_fast_mutex; /* In other systems we use this OS mutex in place of lock_word */ @@ -526,8 +536,7 @@ to 20 microseconds. */ /* The number of system calls made in this module. Intended for performance monitoring. */ -extern ulint mutex_system_call_count; -extern ulint mutex_exit_count; +extern ib_longlong mutex_exit_count; #ifdef UNIV_SYNC_DEBUG /* Latching order checks start when this is set TRUE */ === modified file 'storage/innobase/include/sync0sync.ic' --- a/storage/innobase/include/sync0sync.ic 2008-12-19 00:34:15 +0000 +++ b/storage/innobase/include/sync0sync.ic 2009-07-02 14:23:36 +0000 @@ -6,16 +6,6 @@ Mutex, the basic synchronization primiti Created 9/5/1995 Heikki Tuuri *******************************************************/ -#if defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86) -/* %z0: Use the size of operand %0 which in our case is *m to determine -instruction size, it should end up as xchgl. "1" in the input constraint, -says that "in" has to go in the same place as "out".*/ -#define TAS(m, in, out) \ - asm volatile ("xchg%z0 %2, %0" \ - : "=g" (*(m)), "=r" (out) \ - : "1" (in)) /* Note: "1" here refers to "=r" (out) */ -#endif - /********************************************************************** Sets the waiters field in a mutex. */ @@ -59,7 +49,7 @@ mutex_signal_object( Performs an atomic test-and-set instruction to the lock_word field of a mutex. */ UNIV_INLINE -ulint +byte mutex_test_and_set( /*===============*/ /* out: the previous value of lock_word: 0 or @@ -67,18 +57,18 @@ mutex_test_and_set( mutex_t* mutex) /* in: mutex */ { #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER) - ulint res; - ulint* lw; /* assembler code is used to ensure that + byte res; + byte* lw; /* assembler code is used to ensure that lock_word is loaded from memory */ ut_ad(mutex); - ut_ad(sizeof(ulint) == 4); + ut_ad(sizeof(byte) == 1); lw = &(mutex->lock_word); __asm MOV ECX, lw __asm MOV EDX, 1 - __asm XCHG EDX, DWORD PTR [ECX] - __asm MOV res, EDX + __asm XCHG DL, BYTE PTR [ECX] + __asm MOV res, DL /* The fence below would prevent this thread from reading the data structure protected by the mutex @@ -98,12 +88,9 @@ mutex_test_and_set( /* mutex_fence(); */ return(res); -#elif defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86) - ulint res; - - TAS(&mutex->lock_word, 1, res); - - return(res); +#elif defined(MY_ATOMIC_NOLOCK) + return ((byte)my_atomic_swap8( + (int8 volatile *)&(mutex->lock_word), 1)); #else ibool ret; @@ -117,7 +104,7 @@ mutex_test_and_set( mutex->lock_word = 1; } - return(ret); + return((byte)ret); #endif } @@ -131,7 +118,7 @@ mutex_reset_lock_word( mutex_t* mutex) /* in: mutex */ { #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER) - ulint* lw; /* assembler code is used to ensure that + byte* lw; /* assembler code is used to ensure that lock_word is loaded from memory */ ut_ad(mutex); @@ -139,11 +126,12 @@ mutex_reset_lock_word( __asm MOV EDX, 0 __asm MOV ECX, lw - __asm XCHG EDX, DWORD PTR [ECX] -#elif defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86) - ulint res; - - TAS(&mutex->lock_word, 0, res); + __asm XCHG DL, BYTE PTR [ECX] +#elif defined(MY_ATOMIC_NOLOCK) + /* In theory __sync_lock_release should be used to release the lock. + Unfortunately, it does not work properly alone. The workaround is + that more conservative __sync_lock_test_and_set is used instead. */ + (void)my_atomic_swap8((int8 volatile *)&(mutex->lock_word), 0); #else mutex->lock_word = 0; @@ -154,12 +142,12 @@ mutex_reset_lock_word( /********************************************************************** Gets the value of the lock word. */ UNIV_INLINE -ulint +byte mutex_get_lock_word( /*================*/ const mutex_t* mutex) /* in: mutex */ { - const volatile ulint* ptr; /* declared volatile to ensure that + const volatile byte* ptr; /* declared volatile to ensure that lock_word is loaded from memory */ ut_ad(mutex); === modified file 'storage/innobase/include/univ.i' --- a/storage/innobase/include/univ.i 2008-07-08 16:01:41 +0000 +++ b/storage/innobase/include/univ.i 2009-07-02 14:23:36 +0000 @@ -9,6 +9,10 @@ Created 1/20/1994 Heikki Tuuri #ifndef univ_i #define univ_i +#ifdef __SUNPRO_C +# include +#endif + #if (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)) && !defined(MYSQL_SERVER) && !defined(__WIN__) # undef __WIN__ # define __WIN__ @@ -56,7 +60,7 @@ of the 32-bit x86 assembler in mutex ope # endif /* We only try to do explicit inlining of functions with gcc and -Microsoft Visual C++ */ + Sun Studio */ # if !defined(__GNUC__) && (!defined(__SUNPRO_C) || (__SUNPRO_C < 0x590)) # undef UNIV_MUST_NOT_INLINE /* Remove compiler warning */ @@ -116,6 +120,24 @@ by one. */ #define UNIV_SET_MEM_TO_ZERO #endif +/* Use malloc instead of innodb additional memory pool (great with tcmalloc) */ +#define UNIV_DISABLE_MEM_POOL + +#if defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMIC) +/* + * We have a full set of atomic ops available - we will use them + */ +#define UNIV_SYNC_ATOMIC +#endif + +#if defined(WIN_ATOMICS32) || defined(WIN_ATOMICS64) +/* + * We have a full set of atomic ops available - we will use them + * This is on Windows + */ +#define UNIV_SYNC_ATOMIC +#endif + /* #define UNIV_SQL_DEBUG #define UNIV_LOG_DEBUG @@ -274,6 +296,11 @@ it is read. */ /* Minimize cache-miss latency by moving data at addr into a cache before it is read or written. */ # define UNIV_PREFETCH_RW(addr) __builtin_prefetch(addr, 1, 3) +#elif defined(__SUNPRO_C) +# define UNIV_EXPECT(expr,value) (expr) +# define UNIV_LIKELY_NULL(expr) (expr) +# define UNIV_PREFETCH_R(addr) sun_prefetch_read_many(addr) +# define UNIV_PREFETCH_RW(addr) sun_prefetch_write_many(addr) #else /* Dummy versions of the macros */ # define UNIV_EXPECT(expr,value) (expr) === modified file 'storage/innobase/include/ut0ut.h' --- a/storage/innobase/include/ut0ut.h 2008-12-19 00:34:15 +0000 +++ b/storage/innobase/include/ut0ut.h 2009-07-02 14:23:36 +0000 @@ -17,6 +17,24 @@ Created 1/20/1994 Heikki Tuuri typedef time_t ib_time_t; +#ifdef HAVE_PAUSE_INSTRUCTION +#define PAUSE_INSTRUCTION() {__asm__ __volatile__ ("pause");} +#else +#ifdef HAVE_FAKE_PAUSE_INSTRUCTION +#define PAUSE_INSTRUCTION() {__asm__ __volatile__ ("rep; nop");} +#else +#ifdef UNIV_SYNC_ATOMIC +#define PAUSE_INSTRUCTION() \ + { \ + volatile lint volatile_var; \ + os_compare_and_swap(&volatile_var, 0, 1); \ + } +#else +#define PAUSE_INSTRUCTION() +#endif +#endif +#endif + /************************************************************ Gets the high 32 bits in a ulint. That is makes a shift >> 32, but since there seem to be compiler bugs in both gcc and Visual C++, @@ -156,6 +174,18 @@ ut_usectime( /* out: 0 on success, -1 otherwise */ ulint* sec, /* out: seconds since the Epoch */ ulint* ms); /* out: microseconds since the Epoch+*sec */ + +/************************************************************** +Returns diff in microseconds (end_sec,end_ms) - (start_sec,start_ms). */ + +ib_longlong +ut_usecdiff( +/*========*/ + ulint end_sec, /* in: seconds since the Epoch */ + ulint end_ms, /* in: microseconds since the Epoch+*sec1 */ + ulint start_sec, /* in: seconds since the Epoch */ + ulint start_ms); /* in: microseconds since the Epoch+*sec2 */ + /************************************************************** Returns the difference of two times in seconds. */ === modified file 'storage/innobase/log/log0log.c' --- a/storage/innobase/log/log0log.c 2007-07-10 14:34:21 +0000 +++ b/storage/innobase/log/log0log.c 2008-10-15 12:30:31 +0000 @@ -1517,6 +1517,26 @@ log_buffer_flush_to_disk(void) } /******************************************************************** +Flush the log buffer. Force it to disk depending on the value of +innodb_flush_log_at_trx_commit. */ + +void +log_buffer_flush_maybe_sync(void) +/*==========================*/ +{ + dulint lsn; + + mutex_enter(&(log_sys->mutex)); + + lsn = log_sys->lsn; + + mutex_exit(&(log_sys->mutex)); + + /* Force log buffer to disk when innodb_flush_log_at_trx_commit = 1. */ + log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, + srv_flush_log_at_trx_commit == 1 ? TRUE : FALSE); +} +/******************************************************************** Tries to establish a big enough margin of free space in the log buffer, such that a new log entry can be catenated without an immediate need for a flush. */ static === modified file 'storage/innobase/mem/mem0pool.c' --- a/storage/innobase/mem/mem0pool.c 2007-07-25 01:34:31 +0000 +++ b/storage/innobase/mem/mem0pool.c 2008-10-16 18:07:50 +0000 @@ -329,6 +329,10 @@ mem_area_alloc( minus MEM_AREA_EXTRA_SIZE */ mem_pool_t* pool) /* in: memory pool */ { +#ifdef UNIV_DISABLE_MEM_POOL + (void)pool; /* Remove compiler warning */ + return malloc(size); +#else /* UNIV_DISABLE_MEM_POOL */ mem_area_t* area; ulint n; ibool ret; @@ -407,6 +411,7 @@ mem_area_alloc( ut_2_exp(n) - MEM_AREA_EXTRA_SIZE); return((void*)(MEM_AREA_EXTRA_SIZE + ((byte*)area))); +#endif /* UNIV_DISABLE_MEM_POOL */ } /************************************************************************ @@ -459,6 +464,10 @@ mem_area_free( buffer */ mem_pool_t* pool) /* in: memory pool */ { +#ifdef UNIV_DISABLE_MEM_POOL + (void)pool; /* Remove compiler warning */ + free(ptr); +#else /* UNIV_DISABLE_MEM_POOL */ mem_area_t* area; mem_area_t* buddy; void* new_ptr; @@ -570,6 +579,7 @@ mem_area_free( mutex_exit(&(pool->mutex)); ut_ad(mem_pool_validate(pool)); +#endif /* UNIV_DISABLE_MEM_POOL */ } /************************************************************************ === modified file 'storage/innobase/os/os0file.c' --- a/storage/innobase/os/os0file.c 2009-01-26 16:03:39 +0000 +++ b/storage/innobase/os/os0file.c 2009-07-02 14:23:36 +0000 @@ -62,6 +62,28 @@ ibool os_aio_use_native_aio = FALSE; ibool os_aio_print_debug = FALSE; +/* State for the state of an IO request in simulated AIO. + Protocol for simulated aio: + client requests IO: find slot with reserved = FALSE. Add entry with + status = OS_AIO_NOT_ISSUED. + IO thread wakes: find adjacent slots with reserved = TRUE and status = + OS_AIO_NOT_ISSUED. Change status for slots to + OS_AIO_ISSUED. + IO operation completes: set status for slots to OS_AIO_DONE. set status + for the first slot to OS_AIO_CLAIMED and return + result for that slot. + When there are multiple read and write threads, they all compete to execute + the requests in the array (os_aio_array_t). This avoids the need to load + balance requests at the time the request is made at the cost of waking all + threads when a request is available. +*/ +typedef enum { + OS_AIO_NOT_ISSUED, /* Available to be processed by an IO thread. */ + OS_AIO_ISSUED, /* Being processed by an IO thread. */ + OS_AIO_DONE, /* Request processed. */ + OS_AIO_CLAIMED /* Result being returned to client. */ +} os_aio_status; + /* The aio array slot structure */ typedef struct os_aio_slot_struct os_aio_slot_t; @@ -70,6 +92,8 @@ struct os_aio_slot_struct{ ulint pos; /* index of the slot in the aio array */ ibool reserved; /* TRUE if this slot is reserved */ + os_aio_status status; /* Status for current request. Valid when reserved + is TRUE. Used only in simulated aio. */ time_t reservation_time;/* time when reserved */ ulint len; /* length of the block to read or write */ @@ -80,11 +104,6 @@ struct os_aio_slot_struct{ ulint offset_high; /* 32 high bits of file offset */ os_file_t file; /* file where to read or write */ const char* name; /* file name or path */ - ibool io_already_done;/* used only in simulated aio: - TRUE if the physical i/o already - made and only the slot message - needs to be passed to the caller - of os_aio_simulated_handle */ fil_node_t* message1; /* message which is given by the */ void* message2; /* the requester of an aio operation and which can be used to identify @@ -114,9 +133,6 @@ struct os_aio_array_struct{ in this array */ ulint n_slots; /* Total number of slots in the aio array. This must be divisible by n_threads. */ - ulint n_segments;/* Number of segments in the aio array of - pending aio requests. A thread can wait - separately for any one of the segments. */ ulint n_reserved;/* Number of reserved slots in the aio array outside the ibuf segment */ os_aio_slot_t* slots; /* Pointer to the slots in the array */ @@ -133,6 +149,17 @@ struct os_aio_array_struct{ /* Array of events used in simulated aio */ os_event_t* os_aio_segment_wait_events = NULL; +/* Number of threads for reading and writing. */ +ulint os_aio_read_threads = 0; +ulint os_aio_write_threads = 0; + +/* Number for the first global segment for reading. */ +const ulint os_aio_first_read_segment = 2; + +/* Number for the first global segment for writing. Set to +2 + os_aio_read_write_threads. */ +ulint os_aio_first_write_segment = 0; + /* The aio arrays for non-ibuf i/o and ibuf i/o, as well as sync aio. These are NULL when the module has not yet been initialized. */ static os_aio_array_t* os_aio_read_array = NULL; @@ -141,11 +168,39 @@ static os_aio_array_t* os_aio_ibuf_array static os_aio_array_t* os_aio_log_array = NULL; static os_aio_array_t* os_aio_sync_array = NULL; +/* Per thread buffer used for merged IO requests. Used by +os_aio_simulated_handle so that a buffer doesn't have to be allocated +for each request. */ +static char* os_aio_thread_buffer[SRV_MAX_N_IO_THREADS]; +static ulint os_aio_thread_buffer_size[SRV_MAX_N_IO_THREADS]; + +/* Count pages read and written per thread */ +static ulint os_aio_thread_io_reads[SRV_MAX_N_IO_THREADS]; +static ulint os_aio_thread_io_writes[SRV_MAX_N_IO_THREADS]; + +/* Number of IO operations done. One request can be for N pages. */ +static ulint os_aio_thread_io_requests[SRV_MAX_N_IO_THREADS]; + +/* usecs spent blocked on an IO request */ +static double os_aio_thread_io_wait[SRV_MAX_N_IO_THREADS]; +/* max usecs spent blocked on an IO request */ +static double os_aio_thread_max_io_wait[SRV_MAX_N_IO_THREADS]; + +/* Number of IO global segments. An IO handler thread is created for each +global segment, except for the segment associated with os_aio_sync_array. +Several segments can be associated with os_aio_{read,write}_array. One +segment is created for each of the other arrays. This is also the number +of valid entries in srv_io_thread_reads, srv_io_thread_writes, +srv_io_thread_op_info, srv_io_thread_function and os_aio_segment_wait_events. */ static ulint os_aio_n_segments = ULINT_UNDEFINED; -/* If the following is TRUE, read i/o handler threads try to -wait until a batch of new read requests have been posted */ -static ibool os_aio_recommend_sleep_for_read_threads = FALSE; +/* Set to TRUE to temporarily block reads from being scheduled while a batch +of read requests is added to allow them to be merged by the IO handler thread +if they are adjacent. Declared volatile because we don't want this to be +read from a register in a loop when another thread may change the value in +memory. +*/ +static volatile ibool os_aio_recommend_sleep_for_read_threads = FALSE; ulint os_n_file_reads = 0; ulint os_bytes_read_since_printout = 0; @@ -165,6 +220,14 @@ ulint os_file_n_pending_pwrites = 0; ulint os_n_pending_writes = 0; ulint os_n_pending_reads = 0; +static double time_usecs() { + ulint sec, ms; + if (ut_usectime(&sec, &ms)) + return 0; + else + return sec * 1000000.0 + ms; +} + /*************************************************************************** Gets the operating system version. Currently works only on Windows. */ @@ -2884,9 +2947,8 @@ os_aio_array_t* os_aio_array_create( /*================*/ /* out, own: aio array */ - ulint n, /* in: maximum number of pending aio operations - allowed; n must be divisible by n_segments */ - ulint n_segments) /* in: number of segments in the aio array */ + ulint n) /* in: maximum number of pending aio operations + allowed */ { os_aio_array_t* array; ulint i; @@ -2895,7 +2957,6 @@ os_aio_array_create( OVERLAPPED* over; #endif ut_a(n > 0); - ut_a(n_segments > 0); array = ut_malloc(sizeof(os_aio_array_t)); @@ -2906,7 +2967,6 @@ os_aio_array_create( os_event_set(array->is_empty); array->n_slots = n; - array->n_segments = n_segments; array->n_reserved = 0; array->slots = ut_malloc(n * sizeof(os_aio_slot_t)); #ifdef __WIN__ @@ -2933,70 +2993,75 @@ os_aio_array_create( /**************************************************************************** Initializes the asynchronous io system. Calls also os_io_init_simple. -Creates a separate aio array for -non-ibuf read and write, a third aio array for the ibuf i/o, with just one -segment, two aio arrays for log reads and writes with one segment, and a -synchronous aio array of the specified size. The combined number of segments -in the three first aio arrays is the parameter n_segments given to the -function. The caller must create an i/o handler thread for each segment in -the four first arrays, but not for the sync aio array. */ +Creates an aio array for each of non-ibuf read, non-ibuf write, ibuf IO, +log IO, and synchronous IO. The caller must create i/o handler thread for all +but the synchronous aio array. Multiple threads can access the same array for +the non-ibuf read (prefetch) and write (flush dirty buffer pages) arrays. +Return the number of AIO handler threads. */ -void +ulint os_aio_init( /*========*/ - ulint n, /* in: maximum number of pending aio operations - allowed; n must be divisible by n_segments */ - ulint n_segments, /* in: combined number of segments in the four - first aio arrays; must be >= 4 */ + ulint ios_per_array, /* in: maximum number of pending aio operations + allowed per array */ + ulint n_read_threads, /* in: number of read threads */ + ulint n_write_threads, /* in: number of write threads */ ulint n_slots_sync) /* in: number of slots in the sync aio array */ { - ulint n_read_segs; - ulint n_write_segs; - ulint n_per_seg; ulint i; + ulint n_segments = 2 + n_read_threads + n_write_threads; #ifdef POSIX_ASYNC_IO sigset_t sigset; #endif - ut_ad(n % n_segments == 0); - ut_ad(n_segments >= 4); + ut_a(ios_per_array >= OS_AIO_N_PENDING_IOS_PER_THREAD); + ut_a(n_read_threads >= 1 && n_read_threads <= 64); + ut_a(n_write_threads >= 1 && n_write_threads <= 64); + ut_a(n_segments < SRV_MAX_N_IO_THREADS); os_io_init_simple(); for (i = 0; i < n_segments; i++) { srv_set_io_thread_op_info(i, "not started yet"); - } + os_aio_thread_io_reads[i] = 0; + os_aio_thread_io_writes[i] = 0; + os_aio_thread_io_requests[i] = 0; + os_aio_thread_buffer[i] = 0; + os_aio_thread_buffer_size[i] = 0; + os_aio_thread_io_wait[i] = 0; + os_aio_thread_max_io_wait[i] = 0; + } + + os_aio_read_threads = n_read_threads; + os_aio_write_threads = n_write_threads; + os_aio_first_write_segment = os_aio_first_read_segment + os_aio_read_threads; + + fprintf(stderr, + "InnoDB: ios_per_array %lu read threads %lu write threads %lu\n", + ios_per_array, os_aio_read_threads, os_aio_write_threads); - n_per_seg = n / n_segments; - n_write_segs = (n_segments - 2) / 2; - n_read_segs = n_segments - 2 - n_write_segs; - - /* fprintf(stderr, "Array n per seg %lu\n", n_per_seg); */ - - os_aio_ibuf_array = os_aio_array_create(n_per_seg, 1); + os_aio_ibuf_array = os_aio_array_create(ios_per_array); srv_io_thread_function[0] = "insert buffer thread"; - os_aio_log_array = os_aio_array_create(n_per_seg, 1); + os_aio_log_array = os_aio_array_create(ios_per_array); srv_io_thread_function[1] = "log thread"; - os_aio_read_array = os_aio_array_create(n_read_segs * n_per_seg, - n_read_segs); - for (i = 2; i < 2 + n_read_segs; i++) { + os_aio_read_array = os_aio_array_create(ios_per_array); + for (i = os_aio_first_read_segment; i < os_aio_first_write_segment; i++) { ut_a(i < SRV_MAX_N_IO_THREADS); srv_io_thread_function[i] = "read thread"; } - os_aio_write_array = os_aio_array_create(n_write_segs * n_per_seg, - n_write_segs); - for (i = 2 + n_read_segs; i < n_segments; i++) { + os_aio_write_array = os_aio_array_create(ios_per_array); + for (i = os_aio_first_write_segment; i < n_segments; i++) { ut_a(i < SRV_MAX_N_IO_THREADS); srv_io_thread_function[i] = "write thread"; } - os_aio_sync_array = os_aio_array_create(n_slots_sync, 1); + os_aio_sync_array = os_aio_array_create(n_slots_sync); - os_aio_n_segments = n_segments; + os_aio_n_segments = 2 + os_aio_read_threads + os_aio_write_threads; os_aio_validate(); @@ -3024,7 +3089,8 @@ os_aio_init( pthread_sigmask(SIG_BLOCK, &sigset, NULL); */ #endif - } + return os_aio_n_segments; +} #ifdef WIN_ASYNC_IO /**************************************************************************** @@ -3082,76 +3148,28 @@ os_aio_wait_until_no_pending_writes(void } /************************************************************************** -Calculates segment number for a slot. */ +Calculates aio array from global segment number. */ static -ulint -os_aio_get_segment_no_from_slot( -/*============================*/ - /* out: segment number (which is the number - used by, for example, i/o-handler threads) */ - os_aio_array_t* array, /* in: aio wait array */ - os_aio_slot_t* slot) /* in: slot in this array */ -{ - ulint segment; - ulint seg_len; - - if (array == os_aio_ibuf_array) { - segment = 0; - - } else if (array == os_aio_log_array) { - segment = 1; - - } else if (array == os_aio_read_array) { - seg_len = os_aio_read_array->n_slots - / os_aio_read_array->n_segments; - - segment = 2 + slot->pos / seg_len; - } else { - ut_a(array == os_aio_write_array); - seg_len = os_aio_write_array->n_slots - / os_aio_write_array->n_segments; - - segment = os_aio_read_array->n_segments + 2 - + slot->pos / seg_len; - } - - return(segment); -} - -/************************************************************************** -Calculates local segment number and aio array from global segment number. */ -static -ulint -os_aio_get_array_and_local_segment( +os_aio_array_t* +os_aio_get_array( /*===============================*/ - /* out: local segment number within - the aio array */ - os_aio_array_t** array, /* out: aio wait array */ + /* out: aio wait array */ ulint global_segment)/* in: global segment number */ { - ulint segment; - ut_a(global_segment < os_aio_n_segments); if (global_segment == 0) { - *array = os_aio_ibuf_array; - segment = 0; - + return os_aio_ibuf_array; + } else if (global_segment == 1) { - *array = os_aio_log_array; - segment = 0; + return os_aio_log_array; - } else if (global_segment < os_aio_read_array->n_segments + 2) { - *array = os_aio_read_array; + } else if (global_segment < os_aio_first_write_segment) { + return os_aio_read_array; - segment = global_segment - 2; } else { - *array = os_aio_write_array; - - segment = global_segment - (os_aio_read_array->n_segments + 2); - } - - return(segment); + return os_aio_write_array; + } } /*********************************************************************** @@ -3273,7 +3291,7 @@ loop: break; } } - + ut_a(i < array->n_slots); array->n_reserved++; if (array->n_reserved == 1) { @@ -3295,7 +3313,7 @@ loop: slot->buf = buf; slot->offset = offset; slot->offset_high = offset_high; - slot->io_already_done = FALSE; + slot->status = OS_AIO_NOT_ISSUED; #ifdef WIN_ASYNC_IO control = &(slot->control); @@ -3348,6 +3366,7 @@ os_aio_array_free_slot( ut_ad(slot->reserved); slot->reserved = FALSE; + slot->status = OS_AIO_NOT_ISSUED; array->n_reserved--; @@ -3371,39 +3390,58 @@ static void os_aio_simulated_wake_handler_thread( /*=================================*/ - ulint global_segment) /* in: the number of the segment in the aio - arrays */ + os_aio_array_t* array) /* in: aio array for which wakeup is done */ { - os_aio_array_t* array; os_aio_slot_t* slot; - ulint segment; ulint n; ulint i; ut_ad(!os_aio_use_native_aio); + n = array->n_slots; - segment = os_aio_get_array_and_local_segment(&array, global_segment); - - n = array->n_slots / array->n_segments; - - /* Look through n slots after the segment * n'th slot */ + /* Look through n slots */ os_mutex_enter(array->mutex); for (i = 0; i < n; i++) { - slot = os_aio_array_get_nth_slot(array, i + segment * n); - - if (slot->reserved) { - /* Found an i/o request */ - - break; - } + slot = os_aio_array_get_nth_slot(array, i); + + if (slot->reserved && + (slot->status == OS_AIO_NOT_ISSUED || + slot->status == OS_AIO_DONE)) { + /* Found an i/o request + OS_AIO_NOT_ISSUED means the read or write request has + * yet to be done. OS_AIO_DONE means the request has been + * done but it was part of a set of requests merged into + * one read or write call and was not the first block in + * the request, so the handling of the IO completion for + * that block has not been done. */ + break; + } } os_mutex_exit(array->mutex); if (i < n) { - os_event_set(os_aio_segment_wait_events[global_segment]); + if (array == os_aio_ibuf_array) { + os_event_set(os_aio_segment_wait_events[0]); + + } else if (array == os_aio_log_array) { + os_event_set(os_aio_segment_wait_events[1]); + + } else if (array == os_aio_read_array) { + ulint x; + for (x = os_aio_first_read_segment; x < os_aio_first_write_segment; x++) + os_event_set(os_aio_segment_wait_events[x]); + + } else if (array == os_aio_write_array) { + ulint x; + for (x = os_aio_first_write_segment; x < os_aio_n_segments; x++) + os_event_set(os_aio_segment_wait_events[x]); + + } else { + ut_a(0); + } } } @@ -3414,8 +3452,6 @@ void os_aio_simulated_wake_handler_threads(void) /*=======================================*/ { - ulint i; - if (os_aio_use_native_aio) { /* We do not use simulated aio: do nothing */ @@ -3423,10 +3459,11 @@ os_aio_simulated_wake_handler_threads(vo } os_aio_recommend_sleep_for_read_threads = FALSE; - - for (i = 0; i < os_aio_n_segments; i++) { - os_aio_simulated_wake_handler_thread(i); - } + + os_aio_simulated_wake_handler_thread(os_aio_ibuf_array); + os_aio_simulated_wake_handler_thread(os_aio_log_array); + os_aio_simulated_wake_handler_thread(os_aio_read_array); + os_aio_simulated_wake_handler_thread(os_aio_write_array); } /************************************************************************** @@ -3439,18 +3476,13 @@ void os_aio_simulated_put_read_threads_to_sleep(void) /*============================================*/ { - os_aio_array_t* array; ulint g; + /* TODO(mcallaghan): provide similar function for write? */ os_aio_recommend_sleep_for_read_threads = TRUE; - - for (g = 0; g < os_aio_n_segments; g++) { - os_aio_get_array_and_local_segment(&array, g); - - if (array == os_aio_read_array) { - - os_event_reset(os_aio_segment_wait_events[g]); - } + + for (g = os_aio_first_read_segment; g < os_aio_first_write_segment; g++) { + os_event_reset(os_aio_segment_wait_events[g]); } } @@ -3580,9 +3612,7 @@ try_again: #endif } else { if (!wake_later) { - os_aio_simulated_wake_handler_thread( - os_aio_get_segment_no_from_slot( - array, slot)); + os_aio_simulated_wake_handler_thread(array); } } } else if (type == OS_FILE_WRITE) { @@ -3598,9 +3628,7 @@ try_again: #endif } else { if (!wake_later) { - os_aio_simulated_wake_handler_thread( - os_aio_get_segment_no_from_slot( - array, slot)); + os_aio_simulated_wake_handler_thread(array); } } } else { @@ -3666,7 +3694,7 @@ ibool os_aio_windows_handle( /*==================*/ /* out: TRUE if the aio operation succeeded */ - ulint segment, /* in: the number of the segment in the aio + ulint global_segment, /* in: the number of the segment in the aio arrays to wait for; segment 0 is the ibuf i/o thread, segment 1 the log i/o thread, then follow the non-ibuf read threads, and as @@ -3684,7 +3712,6 @@ os_aio_windows_handle( void** message2, ulint* type) /* out: OS_FILE_WRITE or ..._READ */ { - ulint orig_seg = segment; os_aio_array_t* array; os_aio_slot_t* slot; ulint n; @@ -3693,39 +3720,35 @@ os_aio_windows_handle( BOOL ret; DWORD len; - if (segment == ULINT_UNDEFINED) { + if (global_segment == ULINT_UNDEFINED) { array = os_aio_sync_array; - segment = 0; } else { - segment = os_aio_get_array_and_local_segment(&array, segment); + array = os_aio_get_array(global_segment); } /* NOTE! We only access constant fields in os_aio_array. Therefore we do not have to acquire the protecting mutex yet */ ut_ad(os_aio_validate()); - ut_ad(segment < array->n_segments); - n = array->n_slots / array->n_segments; + n = array->n_slots; if (array == os_aio_sync_array) { os_event_wait(os_aio_array_get_nth_slot(array, pos)->event); i = pos; } else { - srv_set_io_thread_op_info(orig_seg, "wait Windows aio"); - i = os_event_wait_multiple(n, - (array->native_events) - + segment * n); + srv_set_io_thread_op_info(global_segment, "wait Windows aio"); + i = os_event_wait_multiple(n, (array->native_events)); } os_mutex_enter(array->mutex); - slot = os_aio_array_get_nth_slot(array, i + segment * n); + slot = os_aio_array_get_nth_slot(array, i); ut_a(slot->reserved); - if (orig_seg != ULINT_UNDEFINED) { - srv_set_io_thread_op_info(orig_seg, + if (global_segment != ULINT_UNDEFINED) { + srv_set_io_thread_op_info(global_segment, "get windows aio return value"); } @@ -3898,14 +3921,16 @@ os_aio_simulated_handle( ulint* type) /* out: OS_FILE_WRITE or ..._READ */ { os_aio_array_t* array; - ulint segment; os_aio_slot_t* slot; os_aio_slot_t* slot2; os_aio_slot_t* consecutive_ios[OS_AIO_MERGE_N_CONSECUTIVE]; + os_aio_slot_t* lowest_request; + os_aio_slot_t* oldest_request; ulint n_consecutive; ulint total_len; ulint offs; ulint lowest_offset; + ulint oldest_offset; ulint biggest_age; ulint age; byte* combined_buf; @@ -3914,7 +3939,9 @@ os_aio_simulated_handle( ulint n; ulint i; - segment = os_aio_get_array_and_local_segment(&array, global_segment); + double start_usecs, stop_usecs, elapsed_usecs; + time_t now; + array = os_aio_get_array(global_segment); restart: /* NOTE! We only access constant fields in os_aio_array. Therefore @@ -3923,11 +3950,10 @@ restart: srv_set_io_thread_op_info(global_segment, "looking for i/o requests (a)"); ut_ad(os_aio_validate()); - ut_ad(segment < array->n_segments); - n = array->n_slots / array->n_segments; + n = array->n_slots; - /* Look through n slots after the segment * n'th slot */ + /* Look through n slots */ if (array == os_aio_read_array && os_aio_recommend_sleep_for_read_threads) { @@ -3947,9 +3973,9 @@ restart: done */ for (i = 0; i < n; i++) { - slot = os_aio_array_get_nth_slot(array, i + segment * n); + slot = os_aio_array_get_nth_slot(array, i); - if (slot->reserved && slot->io_already_done) { + if (slot->reserved && slot->status == OS_AIO_DONE) { if (os_aio_print_debug) { fprintf(stderr, @@ -3964,74 +3990,64 @@ restart: } } - n_consecutive = 0; - - /* If there are at least 2 seconds old requests, then pick the oldest - one to prevent starvation. If several requests have the same age, - then pick the one at the lowest offset. */ - biggest_age = 0; - lowest_offset = ULINT_MAX; + now = time(NULL); + oldest_request = lowest_request = NULL; + oldest_offset = lowest_offset = ULINT_MAX; + /* Find the oldest request and the request with the smallest offset */ for (i = 0; i < n; i++) { - slot = os_aio_array_get_nth_slot(array, i + segment * n); + slot = os_aio_array_get_nth_slot(array, i); - if (slot->reserved) { - age = (ulint)difftime(time(NULL), - slot->reservation_time); + if (slot->reserved && slot->status == OS_AIO_NOT_ISSUED) { + age = (ulint)difftime(now, slot->reservation_time); + /* If there are at least 2 seconds old requests, then pick the oldest + one to prevent starvation. If several requests have the same age, + then pick the one at the lowest offset. */ if ((age >= 2 && age > biggest_age) || (age >= 2 && age == biggest_age - && slot->offset < lowest_offset)) { - - /* Found an i/o request */ - consecutive_ios[0] = slot; - - n_consecutive = 1; + && slot->offset < oldest_offset)) { + /* Found an i/o request */ biggest_age = age; - lowest_offset = slot->offset; + oldest_request = slot; + oldest_offset = slot->offset; } - } - } - - if (n_consecutive == 0) { - /* There were no old requests. Look for an i/o request at the - lowest offset in the array (we ignore the high 32 bits of the - offset in these heuristics) */ - - lowest_offset = ULINT_MAX; - for (i = 0; i < n; i++) { - slot = os_aio_array_get_nth_slot(array, - i + segment * n); + /* Look for an i/o request at the lowest offset in the array + * (we ignore the high 32 bits of the offset) */ + if (slot->offset < lowest_offset) { + /* Found an i/o request */ + lowest_request = slot; - if (slot->reserved && slot->offset < lowest_offset) { - /* Found an i/o request */ - consecutive_ios[0] = slot; - - n_consecutive = 1; lowest_offset = slot->offset; } } } - if (n_consecutive == 0) { + if (!lowest_request && !oldest_request) { /* No i/o requested at the moment */ goto wait_for_io; } - slot = consecutive_ios[0]; - + if (oldest_request) { + slot = oldest_request; + } else { + slot = lowest_request; + } + consecutive_ios[0] = slot; + n_consecutive = 1; + /* Check if there are several consecutive blocks to read or write */ consecutive_loop: for (i = 0; i < n; i++) { - slot2 = os_aio_array_get_nth_slot(array, i + segment * n); + slot2 = os_aio_array_get_nth_slot(array, i); if (slot2->reserved && slot2 != slot && slot2->offset == slot->offset + slot->len @@ -4039,7 +4055,8 @@ consecutive_loop: && slot->offset + slot->len > slot->offset && slot2->offset_high == slot->offset_high && slot2->type == slot->type - && slot2->file == slot->file) { + && slot2->file == slot->file + && slot2->status == OS_AIO_NOT_ISSUED) { /* Found a consecutive i/o request */ @@ -4048,7 +4065,8 @@ consecutive_loop: slot = slot2; - if (n_consecutive < OS_AIO_MERGE_N_CONSECUTIVE) { + if (n_consecutive < OS_AIO_MERGE_N_CONSECUTIVE && + n_consecutive < srv_max_merged_io) { goto consecutive_loop; } else { @@ -4068,6 +4086,8 @@ consecutive_loop: for (i = 0; i < n_consecutive; i++) { total_len += consecutive_ios[i]->len; + ut_a(consecutive_ios[i]->status == OS_AIO_NOT_ISSUED); + consecutive_ios[i]->status = OS_AIO_ISSUED; } if (n_consecutive == 1) { @@ -4075,7 +4095,16 @@ consecutive_loop: combined_buf = slot->buf; combined_buf2 = NULL; } else { - combined_buf2 = ut_malloc(total_len + UNIV_PAGE_SIZE); + if ((total_len + UNIV_PAGE_SIZE) > os_aio_thread_buffer_size[global_segment]) { + + if (os_aio_thread_buffer[global_segment]) + ut_free(os_aio_thread_buffer[global_segment]); + + os_aio_thread_buffer[global_segment] = ut_malloc(total_len + UNIV_PAGE_SIZE); + + os_aio_thread_buffer_size[global_segment] = total_len + UNIV_PAGE_SIZE; + } + combined_buf2 = os_aio_thread_buffer[global_segment]; ut_a(combined_buf2); @@ -4086,6 +4115,9 @@ consecutive_loop: this assumes that there is just one i/o-handler thread serving a single segment of slots! */ + ut_a(slot->reserved); + ut_a(slot->status == OS_AIO_ISSUED); + os_mutex_exit(array->mutex); if (slot->type == OS_FILE_WRITE && n_consecutive > 1) { @@ -4112,6 +4144,7 @@ consecutive_loop: /* Do the i/o with ordinary, synchronous i/o functions: */ if (slot->type == OS_FILE_WRITE) { + os_aio_thread_io_writes[global_segment] += n_consecutive; if (array == os_aio_write_array) { if ((total_len % UNIV_PAGE_SIZE != 0) || (slot->offset % UNIV_PAGE_SIZE != 0)) { @@ -4126,18 +4159,30 @@ consecutive_loop: os_file_check_page_trailers(combined_buf, total_len); } - + start_usecs = time_usecs(); ret = os_file_write(slot->name, slot->file, combined_buf, slot->offset, slot->offset_high, total_len); + stop_usecs = time_usecs(); + elapsed_usecs = stop_usecs - start_usecs; + if (elapsed_usecs < 0) elapsed_usecs = 0; if (array == os_aio_write_array) { os_file_check_page_trailers(combined_buf, total_len); } } else { + start_usecs = time_usecs(); + os_aio_thread_io_reads[global_segment] += n_consecutive; ret = os_file_read(slot->file, combined_buf, slot->offset, slot->offset_high, total_len); - } + stop_usecs = time_usecs(); + elapsed_usecs = stop_usecs - start_usecs; + if (elapsed_usecs < 0) elapsed_usecs = 0; + } + if (elapsed_usecs > os_aio_thread_max_io_wait[global_segment]) + os_aio_thread_max_io_wait[global_segment] = elapsed_usecs; + os_aio_thread_io_wait[global_segment] += elapsed_usecs; + os_aio_thread_io_requests[global_segment]++; ut_a(ret); srv_set_io_thread_op_info(global_segment, "file i/o done"); @@ -4160,16 +4205,13 @@ consecutive_loop: } } - if (combined_buf2) { - ut_free(combined_buf2); - } - os_mutex_enter(array->mutex); /* Mark the i/os done in slots */ for (i = 0; i < n_consecutive; i++) { - consecutive_ios[i]->io_already_done = TRUE; + ut_a(consecutive_ios[i]->status == OS_AIO_ISSUED); + consecutive_ios[i]->status = OS_AIO_DONE; } /* We return the messages for the first slot now, and if there were @@ -4179,6 +4221,8 @@ consecutive_loop: slot_io_done: ut_a(slot->reserved); + ut_a(slot->status == OS_AIO_DONE); + slot->status = OS_AIO_CLAIMED; *message1 = slot->message1; *message2 = slot->message2; @@ -4188,6 +4232,7 @@ slot_io_done: os_mutex_exit(array->mutex); os_aio_array_free_slot(array, slot); + srv_set_io_thread_op_info(global_segment, "exited handler"); return(ret); @@ -4234,7 +4279,6 @@ os_aio_array_validate( os_mutex_enter(array->mutex); ut_a(array->n_slots > 0); - ut_a(array->n_segments > 0); for (i = 0; i < array->n_slots; i++) { slot = os_aio_array_get_nth_slot(array, i); @@ -4284,11 +4328,19 @@ os_aio_print( double time_elapsed; double avg_bytes_read; ulint i; - - for (i = 0; i < srv_n_file_io_threads; i++) { - fprintf(file, "I/O thread %lu state: %s (%s)", (ulong) i, - srv_io_thread_op_info[i], - srv_io_thread_function[i]); + ulint num_issued, num_done, num_claimed; + + for (i = 0; i < os_aio_n_segments; i++) { + fprintf(file, + "I/O thread %lu state: %s (%s) reads %lu writes %lu " + "requests %lu io secs %lf io msecs/request %lf max_io_wait %lf", + i, srv_io_thread_op_info[i], srv_io_thread_function[i], + os_aio_thread_io_reads[i], os_aio_thread_io_writes[i], + os_aio_thread_io_requests[i], + os_aio_thread_io_wait[i] / 1000000.0, + os_aio_thread_io_requests[i] ? + os_aio_thread_io_wait[i] / os_aio_thread_io_requests[i] / 1000.0 : 0.0, + os_aio_thread_max_io_wait[i] / 1000.0); #ifndef __WIN__ if (os_aio_segment_wait_events[i]->is_set) { @@ -4308,14 +4360,21 @@ loop: os_mutex_enter(array->mutex); ut_a(array->n_slots > 0); - ut_a(array->n_segments > 0); - n_reserved = 0; + num_done = num_issued = num_claimed = 0; for (i = 0; i < array->n_slots; i++) { slot = os_aio_array_get_nth_slot(array, i); if (slot->reserved) { + if (slot->status == OS_AIO_ISSUED) + num_issued++; + else if (slot->status == OS_AIO_DONE) + num_done++; + else { + ut_ad(slot->status == OS_AIO_CLAIMED); + num_claimed++; + } n_reserved++; #if 0 fprintf(stderr, "Reserved slot, messages %p %p\n", @@ -4361,6 +4420,13 @@ loop: goto loop; } + putc('\n', file); + fprintf(file, + "Summary of background IO slot status: %lu issued, " + "%lu done, %lu claimed, sleep set %d\n", + num_issued, num_done, num_claimed, + (int)os_aio_recommend_sleep_for_read_threads); + putc('\n', file); current_time = time(NULL); time_elapsed = 0.001 + difftime(current_time, os_last_printout); === modified file 'storage/innobase/row/row0sel.c' --- a/storage/innobase/row/row0sel.c 2009-04-15 13:06:16 +0000 +++ b/storage/innobase/row/row0sel.c 2009-07-02 14:23:36 +0000 @@ -1249,7 +1249,7 @@ table_loop: rw_lock_s_lock(&btr_search_latch); search_latch_locked = TRUE; - } else if (btr_search_latch.writer_is_wait_ex) { + } else if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_WAIT_EX) { /* There is an x-latch request waiting: release the s-latch for a moment; as an s-latch here is often @@ -3321,7 +3321,7 @@ row_search_for_mysql( /* PHASE 0: Release a possible s-latch we are holding on the adaptive hash index latch if there is someone waiting behind */ - if (UNIV_UNLIKELY(btr_search_latch.writer != RW_LOCK_NOT_LOCKED) + if (UNIV_UNLIKELY(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_NOT_LOCKED) && trx->has_search_latch) { /* There is an x-latch request on the adaptive hash index: === modified file 'storage/innobase/srv/srv0srv.c' --- a/storage/innobase/srv/srv0srv.c 2009-05-19 08:37:33 +0000 +++ b/storage/innobase/srv/srv0srv.c 2009-07-02 14:23:36 +0000 @@ -171,7 +171,16 @@ ulint srv_awe_window_size = 0; /* size ulint srv_mem_pool_size = ULINT_MAX; /* size in bytes */ ulint srv_lock_table_size = ULINT_MAX; -ulint srv_n_file_io_threads = ULINT_MAX; + +ulint srv_io_capacity = ULINT_MAX; /* Number of IO operations per + second the server can do */ + +ibool srv_extra_dirty_writes = TRUE; /* Write dirty pages to disk when pct + dirty < max dirty pct */ + +ulint srv_n_read_io_threads = ULINT_MAX; +ulint srv_n_write_io_threads = ULINT_MAX; +ulint srv_max_merged_io = 64; #ifdef UNIV_LOG_ARCHIVE ibool srv_log_archive_on = FALSE; @@ -278,6 +287,7 @@ Value 10 should be good if there are les computer. Bigger computers need bigger values. Value 0 will disable the concurrency check. */ +ibool srv_thread_concurrency_timer_based = TRUE; ulong srv_thread_concurrency = 0; ulong srv_commit_concurrency = 0; @@ -340,10 +350,10 @@ ibool srv_use_awe = FALSE; ibool srv_use_adaptive_hash_indexes = TRUE; /*-------------------------------------------*/ -ulong srv_n_spin_wait_rounds = 20; +ulong srv_n_spin_wait_rounds = 30; ulong srv_n_free_tickets_to_enter = 500; ulong srv_thread_sleep_delay = 10000; -ulint srv_spin_wait_delay = 5; +ulint srv_spin_wait_delay = 6; ibool srv_priority_boost = TRUE; ibool srv_print_thread_releases = FALSE; @@ -409,6 +419,30 @@ FILE* srv_misc_tmpfile; ulint srv_main_thread_process_no = 0; ulint srv_main_thread_id = 0; +/* The following count work done by srv_master_thread. */ + +/* Iterations by the 'once per second' loop */ +ulint srv_main_1_second_loops = 0; +/* Calls to sleep by the 'once per second' loop */ +ulint srv_main_sleeps = 0; +/* Iterations by the 'once per 10 seconds' loop */ +ulint srv_main_10_second_loops = 0; +/* Iterations of the loop bounded by the 'background_loop' label */ +ulint srv_main_background_loops = 0; +/* Iterations of the loop bounded by the 'flush_loop' label */ +ulint srv_main_flush_loops = 0; +/* Calls to log_buffer_flush_to_disk */ +ulint srv_sync_flush = 0; +/* Calls to log_buffer_flush_maybe_sync */ +ulint srv_async_flush = 0; + +/* Number of microseconds threads wait because of +innodb_thread_concurrency */ +static ib_longlong srv_thread_wait_mics = 0; + +/* Number of microseconds for spinlock delay */ +static ib_longlong srv_timed_spin_delay = 0; + /* IMPLEMENTATION OF THE SERVER MAIN PROGRAM ========================================= @@ -628,6 +662,53 @@ are indexed by the type of the thread. * ulint srv_n_threads_active[SRV_MASTER + 1]; ulint srv_n_threads[SRV_MASTER + 1]; +static void time_spin_delay() +{ + ulint start_sec, end_sec; + ulint start_usec, end_usec; + int i; + + srv_timed_spin_delay = 0; + + if (ut_usectime(&start_sec, &start_usec)) + return; + + for (i = 0; i < (int)SYNC_SPIN_ROUNDS; ++i) + ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); + + if (ut_usectime(&end_sec, &end_usec)) + return; + + srv_timed_spin_delay =ut_usecdiff(end_sec, end_usec, + start_sec, start_usec); +} + +/************************************************************************* +Prints counters for work done by srv_master_thread. */ + +static +void +srv_print_extra( +/*===================*/ + FILE *file) /* in: output stream */ +{ + fprintf(file, "srv_master_thread loops: %lu 1_second, %lu sleeps, " + "%lu 10_second, %lu background, %lu flush\n", + srv_main_1_second_loops, srv_main_sleeps, + srv_main_10_second_loops, srv_main_background_loops, + srv_main_flush_loops); + fprintf(file, "srv_master_thread log flush: %lu sync, %lu async\n", + srv_sync_flush, srv_async_flush); + fprintf(file, "srv_wait_thread_mics %lld microseconds, %.1f seconds\n", + srv_thread_wait_mics, + (double) srv_thread_wait_mics / 1000000.0); + fprintf(file, + "spinlock delay for %d delay %d rounds is %lld mics\n", + (int)srv_spin_wait_delay, + (int)SYNC_SPIN_ROUNDS, + srv_timed_spin_delay); +} + /************************************************************************* Sets the info describing an i/o thread current state. */ @@ -861,6 +942,8 @@ srv_init(void) dict_table_t* table; ulint i; + time_spin_delay(); + srv_sys = mem_alloc(sizeof(srv_sys_t)); kernel_mutex_temp = mem_alloc(sizeof(mutex_t)); @@ -976,6 +1059,95 @@ ulong srv_max_purge_lag = 0; Puts an OS thread to wait if there are too many concurrent threads (>= srv_thread_concurrency) inside InnoDB. The threads wait in a FIFO queue. */ +#ifdef UNIV_SYNC_ATOMIC +static void +inc_srv_conc_n_threads(lint *n_threads) +{ + *n_threads = os_atomic_increment(&srv_conc_n_threads, 1); +} + +static void +dec_srv_conc_n_threads() +{ + os_atomic_increment(&srv_conc_n_threads, -1); +} +#endif + +static void +print_already_in_error(trx_t* trx) +{ + ut_print_timestamp(stderr); + fputs(" InnoDB: Error: trying to declare trx" + " to enter InnoDB, but\n" + "InnoDB: it already is declared.\n", stderr); + trx_print(stderr, trx, 0); + putc('\n', stderr); + return; +} + +#ifdef UNIV_SYNC_ATOMIC +static void +enter_innodb_with_tickets(trx_t* trx) +{ + trx->declared_to_be_inside_innodb = TRUE; + trx->n_tickets_to_enter_innodb = SRV_FREE_TICKETS_TO_ENTER; + return; +} + +static void +srv_conc_enter_innodb_timer_based(trx_t* trx) +{ + lint conc_n_threads; + ibool has_yielded = FALSE; + ulint has_slept = 0; + + if (trx->declared_to_be_inside_innodb) { + print_already_in_error(trx); + } +retry: + if (srv_conc_n_threads < (lint) srv_thread_concurrency) { + inc_srv_conc_n_threads(&conc_n_threads); + if (conc_n_threads <= (lint) srv_thread_concurrency) { + enter_innodb_with_tickets(trx); + return; + } + dec_srv_conc_n_threads(&conc_n_threads); + } + if (!has_yielded) + { + has_yielded = TRUE; + os_thread_yield(); + goto retry; + } + if (trx->has_search_latch + || NULL != UT_LIST_GET_FIRST(trx->trx_locks)) { + + inc_srv_conc_n_threads(&conc_n_threads); + enter_innodb_with_tickets(trx); + return; + } + if (has_slept < 2) + { + trx->op_info = "sleeping before entering InnoDB"; + os_thread_sleep(10000); + trx->op_info = ""; + has_slept++; + } + inc_srv_conc_n_threads(&conc_n_threads); + enter_innodb_with_tickets(trx); + return; +} + +static void +srv_conc_exit_innodb_timer_based(trx_t* trx) +{ + dec_srv_conc_n_threads(); + trx->declared_to_be_inside_innodb = FALSE; + trx->n_tickets_to_enter_innodb = 0; + return; +} +#endif + void srv_conc_enter_innodb( /*==================*/ @@ -1006,15 +1178,17 @@ srv_conc_enter_innodb( return; } +#ifdef UNIV_SYNC_ATOMIC + if (srv_thread_concurrency_timer_based) { + srv_conc_enter_innodb_timer_based(trx); + return; + } +#endif + os_fast_mutex_lock(&srv_conc_mutex); retry: if (trx->declared_to_be_inside_innodb) { - ut_print_timestamp(stderr); - fputs(" InnoDB: Error: trying to declare trx" - " to enter InnoDB, but\n" - "InnoDB: it already is declared.\n", stderr); - trx_print(stderr, trx, 0); - putc('\n', stderr); + print_already_in_error(trx); os_fast_mutex_unlock(&srv_conc_mutex); return; @@ -1143,19 +1317,27 @@ srv_conc_force_enter_innodb( trx_t* trx) /* in: transaction object associated with the thread */ { + if (UNIV_LIKELY(!srv_thread_concurrency)) { return; } ut_ad(srv_conc_n_threads >= 0); - +#ifdef UNIV_SYNC_ATOMIC + if (srv_thread_concurrency_timer_based) { + lint conc_n_threads; + + inc_srv_conc_n_threads(&conc_n_threads); + trx->declared_to_be_inside_innodb = TRUE; + trx->n_tickets_to_enter_innodb = 1; + return; + } +#endif os_fast_mutex_lock(&srv_conc_mutex); - srv_conc_n_threads++; trx->declared_to_be_inside_innodb = TRUE; trx->n_tickets_to_enter_innodb = 1; - os_fast_mutex_unlock(&srv_conc_mutex); } @@ -1182,6 +1364,14 @@ srv_conc_force_exit_innodb( return; } +#ifdef UNIV_SYNC_ATOMIC + if (srv_thread_concurrency_timer_based) + { + srv_conc_exit_innodb_timer_based(trx); + return; + } +#endif + os_fast_mutex_lock(&srv_conc_mutex); ut_ad(srv_conc_n_threads > 0); @@ -1590,11 +1780,16 @@ srv_release_mysql_thread_if_suspended( /********************************************************************** Refreshes the values used to calculate per-second averages. */ static -void +ibool srv_refresh_innodb_monitor_stats(void) /*==================================*/ { - mutex_enter(&srv_innodb_monitor_mutex); + /* Sometimes we will skip stats update to avoid deadlock, since + since this function is called by the background wake-up thread */ + if (mutex_enter_nowait(&srv_innodb_monitor_mutex)) { + /* mutex_enter_nowait returns 1 on failure */ + return FALSE; + } srv_last_monitor_time = time(NULL); @@ -1613,6 +1808,7 @@ srv_refresh_innodb_monitor_stats(void) srv_n_rows_read_old = srv_n_rows_read; mutex_exit(&srv_innodb_monitor_mutex); + return TRUE; } /********************************************************************** @@ -1621,11 +1817,7 @@ Outputs to a file the output of the Inno void srv_printf_innodb_monitor( /*======================*/ - FILE* file, /* in: output stream */ - ulint* trx_start, /* out: file position of the start of - the list of active transactions */ - ulint* trx_end) /* out: file position of the end of - the list of active transactions */ + FILE* file) /* in: output stream */ { double time_elapsed; time_t current_time; @@ -1653,6 +1845,11 @@ srv_printf_innodb_monitor( "Per second averages calculated from the last %lu seconds\n", (ulong)time_elapsed); + fputs("----------\n" + "BACKGROUND THREAD\n" + "----------\n", file); + srv_print_extra(file); + fputs("----------\n" "SEMAPHORES\n" "----------\n", file); @@ -1674,24 +1871,6 @@ srv_printf_innodb_monitor( mutex_exit(&dict_foreign_err_mutex); - lock_print_info_summary(file); - if (trx_start) { - long t = ftell(file); - if (t < 0) { - *trx_start = ULINT_UNDEFINED; - } else { - *trx_start = (ulint) t; - } - } - lock_print_info_all_transactions(file); - if (trx_end) { - long t = ftell(file); - if (t < 0) { - *trx_end = ULINT_UNDEFINED; - } else { - *trx_end = (ulint) t; - } - } fputs("--------\n" "FILE I/O\n" "--------\n", file); @@ -1841,6 +2020,16 @@ srv_export_innodb_status(void) export_vars.innodb_buffer_pool_pages_misc = buf_pool->max_size - UT_LIST_GET_LEN(buf_pool->LRU) - UT_LIST_GET_LEN(buf_pool->free); +#ifdef UNIV_SYNC_ATOMIC + export_vars.innodb_have_sync_atomic = 1; +#else + export_vars.innodb_have_sync_atomic = 0; +#endif +#ifdef UNIV_DISABLE_MEM_POOL + export_vars.innodb_heap_enabled = 0; +#else + export_vars.innodb_heap_enabled = 1; +#endif export_vars.innodb_page_size = UNIV_PAGE_SIZE; export_vars.innodb_log_waits = srv_log_waits; export_vars.innodb_os_log_written = srv_os_log_written; @@ -1870,6 +2059,7 @@ srv_export_innodb_status(void) export_vars.innodb_rows_inserted = srv_n_rows_inserted; export_vars.innodb_rows_updated = srv_n_rows_updated; export_vars.innodb_rows_deleted = srv_n_rows_deleted; + export_vars.innodb_wake_ups = sync_wake_ups; mutex_exit(&srv_innodb_monitor_mutex); } @@ -1921,14 +2111,13 @@ loop: last_monitor_time = time(NULL); if (srv_print_innodb_monitor) { - srv_printf_innodb_monitor(stderr, NULL, NULL); + srv_printf_innodb_monitor(stderr); } if (srv_innodb_status) { mutex_enter(&srv_monitor_file_mutex); rewind(srv_monitor_file); - srv_printf_innodb_monitor(srv_monitor_file, NULL, - NULL); + srv_printf_innodb_monitor(srv_monitor_file); os_file_set_eof(srv_monitor_file); mutex_exit(&srv_monitor_file_mutex); } @@ -2057,7 +2246,10 @@ exit_func: /************************************************************************* A thread which prints warnings about semaphore waits which have lasted -too long. These can be used to track bugs which cause hangs. */ +too long. These can be used to track bugs which cause hangs. +NOTE: This thread should not wait for any innodb mutexes or rw_locks. +A deadlock could arise where the thread holding that lock requires waking +by this background thread while this thread is blocked on that lock. */ os_thread_ret_t srv_error_monitor_thread( @@ -2069,10 +2261,6 @@ srv_error_monitor_thread( { /* number of successive fatal timeouts observed */ ulint fatal_cnt = 0; - dulint old_lsn; - dulint new_lsn; - - old_lsn = srv_start_lsn; #ifdef UNIV_DEBUG_THREAD_CREATION fprintf(stderr, "Error monitor thread starts, id %lu\n", @@ -2081,29 +2269,8 @@ srv_error_monitor_thread( loop: srv_error_monitor_active = TRUE; - /* Try to track a strange bug reported by Harald Fuchs and others, - where the lsn seems to decrease at times */ - - new_lsn = log_get_lsn(); - - if (ut_dulint_cmp(new_lsn, old_lsn) < 0) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: old log sequence number %lu %lu" - " was greater\n" - "InnoDB: than the new log sequence number %lu %lu!\n" - "InnoDB: Please submit a bug report" - " to http://bugs.mysql.com\n", - (ulong) ut_dulint_get_high(old_lsn), - (ulong) ut_dulint_get_low(old_lsn), - (ulong) ut_dulint_get_high(new_lsn), - (ulong) ut_dulint_get_low(new_lsn)); - } - - old_lsn = new_lsn; - if (difftime(time(NULL), srv_last_monitor_time) > 60) { - /* We referesh InnoDB Monitor values so that averages are + /* We refresh InnoDB Monitor values so that averages are printed from at most 60 last seconds */ srv_refresh_innodb_monitor_stats(); @@ -2194,6 +2361,14 @@ srv_wake_master_thread(void) } /************************************************************************* +Returns the number of IO operations that is X percent of the capacity. + +PCT_IO(5) -> returns the number of IO operations that is 5% of the max +where max is srv_io_capacity. +*/ +#define PCT_IO(pct) ((ulint) (srv_io_capacity * ((double) pct / 100.0))) + +/************************************************************************* The master thread controlling the server. */ os_thread_ret_t @@ -2224,6 +2399,9 @@ srv_master_thread( fprintf(stderr, "Master thread starts, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif + fprintf(stderr, "InnoDB master thread running with io_capacity %lu\n", + srv_io_capacity); + srv_main_thread_process_no = os_proc_get_number(); srv_main_thread_id = os_thread_pf(os_thread_get_curr_id()); @@ -2265,10 +2443,12 @@ loop: n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read + buf_pool->n_pages_written; srv_main_thread_op_info = "sleeping"; + srv_main_1_second_loops++; if (!skip_sleep) { os_thread_sleep(1000000); + srv_main_sleeps++; } skip_sleep = FALSE; @@ -2294,27 +2474,28 @@ loop: srv_main_thread_op_info = "flushing log"; log_buffer_flush_to_disk(); + srv_sync_flush++; srv_main_thread_op_info = "making checkpoint"; log_free_check(); - /* If there were less than 5 i/os during the - one second sleep, we assume that there is free - disk i/o capacity available, and it makes sense to - do an insert buffer merge. */ + /* If i/os during one second sleep were less than 5% of + capacity, we assume that there is free disk i/o capacity + available, and it makes sense to do an insert buffer merge. */ n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; n_ios = log_sys->n_log_ios + buf_pool->n_pages_read + buf_pool->n_pages_written; - if (n_pend_ios < 3 && (n_ios - n_ios_old < 5)) { + if (n_pend_ios < PCT_IO(3) && (n_ios - n_ios_old < PCT_IO(5))) { srv_main_thread_op_info = "doing insert buffer merge"; - ibuf_contract_for_n_pages( - TRUE, srv_insert_buffer_batch_size / 4); + ibuf_contract_for_n_pages(TRUE, PCT_IO(20) / 4); srv_main_thread_op_info = "flushing log"; - log_buffer_flush_to_disk(); + /* No fsync when srv_flush_log_at_trx_commit != 1 */ + log_buffer_flush_maybe_sync(); + srv_async_flush++; } if (UNIV_UNLIKELY(buf_get_modified_ratio_pct() @@ -2323,7 +2504,8 @@ loop: /* Try to keep the number of modified pages in the buffer pool under the limit wished by the user */ - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, + PCT_IO(100), ut_dulint_max); /* If we had to do the flush, it may have taken @@ -2351,30 +2533,40 @@ loop: seconds */ mem_validate_all_blocks(); #endif - /* If there were less than 200 i/os during the 10 second period, - we assume that there is free disk i/o capacity available, and it - makes sense to flush 100 pages. */ + /* If i/os during the 10 second period were less than 200% of + capacity, we assume that there is free disk i/o capacity + available, and it makes sense to flush srv_io_capacity pages. + + Note that this is done regardless of the fraction of dirty + pages relative to the max requested by the user. The one second + loop above requests writes for that case. The writes done here + are not required, and may be disabled. */ n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; n_ios = log_sys->n_log_ios + buf_pool->n_pages_read + buf_pool->n_pages_written; - if (n_pend_ios < 3 && (n_ios - n_ios_very_old < 200)) { + if (srv_extra_dirty_writes && + n_pend_ios < 3 && (n_ios - n_ios_very_old < PCT_IO(200))) { srv_main_thread_op_info = "flushing buffer pool pages"; - buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); + buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(100), ut_dulint_max); srv_main_thread_op_info = "flushing log"; - log_buffer_flush_to_disk(); + /* No fsync when srv_flush_log_at_trx_commit != 1 */ + log_buffer_flush_maybe_sync(); + srv_async_flush++; } /* We run a batch of insert buffer merge every 10 seconds, even if the server were active */ srv_main_thread_op_info = "doing insert buffer merge"; - ibuf_contract_for_n_pages(TRUE, srv_insert_buffer_batch_size / 4); + ibuf_contract_for_n_pages(TRUE, PCT_IO(20) / 4); srv_main_thread_op_info = "flushing log"; - log_buffer_flush_to_disk(); + /* No fsync when srv_flush_log_at_trx_commit != 1 */ + log_buffer_flush_maybe_sync(); + srv_async_flush++; /* We run a full purge every 10 seconds, even if the server were active */ @@ -2400,6 +2592,7 @@ loop: log_buffer_flush_to_disk(); last_flush_time = current_time; + srv_sync_flush++; } } @@ -2413,14 +2606,16 @@ loop: (> 70 %), we assume we can afford reserving the disk(s) for the time it requires to flush 100 pages */ - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, + PCT_IO(100), ut_dulint_max); } else { /* Otherwise, we only flush a small number of pages so that we do not unnecessarily use much disk i/o capacity from other work */ - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 10, + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, + PCT_IO(10), ut_dulint_max); } @@ -2454,7 +2649,7 @@ background_loop: /* The server has been quiet for a while: start running background operations */ - + srv_main_background_loops++; srv_main_thread_op_info = "doing background drop tables"; n_tables_to_drop = row_drop_tables_for_mysql_in_background(); @@ -2492,6 +2687,7 @@ background_loop: log_buffer_flush_to_disk(); last_flush_time = current_time; + srv_sync_flush++; } } @@ -2509,8 +2705,11 @@ background_loop: if (srv_fast_shutdown && srv_shutdown_state > 0) { n_bytes_merged = 0; } else { - n_bytes_merged = ibuf_contract_for_n_pages( - TRUE, srv_insert_buffer_batch_size); + /* This should do an amount of IO similar to the number of + * dirty pages that will be flushed in the call to + * buf_flush_batch below. Otherwise, the system favors + * clean pages over cleanup throughput. */ + n_bytes_merged = ibuf_contract_for_n_pages(TRUE, PCT_IO(100)); } srv_main_thread_op_info = "reserving kernel mutex"; @@ -2524,9 +2723,10 @@ background_loop: flush_loop: srv_main_thread_op_info = "flushing buffer pool pages"; - + srv_main_flush_loops++; if (srv_fast_shutdown < 2) { - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, + PCT_IO(100), ut_dulint_max); } else { /* In the fastest shutdown we do not flush the buffer pool @@ -2549,7 +2749,17 @@ flush_loop: srv_main_thread_op_info = "flushing log"; - log_buffer_flush_to_disk(); + current_time = time(NULL); + if (difftime(current_time, last_flush_time) > 1) { + srv_main_thread_op_info = (char*) "flushing log"; + log_buffer_flush_to_disk(); + last_flush_time = current_time; + srv_sync_flush++; + } else { + /* No fsync when srv_flush_log_at_trx_commit != 1 */ + log_buffer_flush_maybe_sync(); + srv_async_flush++; + } srv_main_thread_op_info = "making checkpoint"; === modified file 'storage/innobase/srv/srv0start.c' --- a/storage/innobase/srv/srv0start.c 2009-01-26 16:03:39 +0000 +++ b/storage/innobase/srv/srv0start.c 2009-07-02 14:23:36 +0000 @@ -986,6 +986,7 @@ innobase_start_or_create_for_mysql(void) ulint i; ibool srv_file_per_table_original_value = srv_file_per_table; mtr_t mtr; + ulint n_threads; #ifdef HAVE_DARWIN_THREADS # ifdef F_FULLFSYNC /* This executable has been compiled on Mac OS X 10.3 or later. @@ -1063,6 +1064,16 @@ innobase_start_or_create_for_mysql(void) return(DB_ERROR); } +#ifdef UNIV_DISABLE_MEM_POOL + fprintf(stderr, + "InnoDB: The InnoDB memory heap has been disabled.\n"); +#endif + +#ifdef UNIV_SYNC_ATOMIC + fprintf(stderr, + "InnoDB: Mutex and rw_lock use atomics.\n"); +#endif + /* Since InnoDB does not currently clean up all its internal data structures in MySQL Embedded Server Library server_end(), we print an error message if someone tries to start up InnoDB a @@ -1238,25 +1249,43 @@ innobase_start_or_create_for_mysql(void) return(DB_ERROR); } +#ifdef __WIN__ + /* + Need to hardcode this to 1 read and 1 write on Windows + while searching for problem causing this to crash when + higher number of threads are supported. + */ + srv_n_read_io_threads = srv_n_write_io_threads = 1; +#endif /* Restrict the maximum number of file i/o threads */ - if (srv_n_file_io_threads > SRV_MAX_N_IO_THREADS) { - - srv_n_file_io_threads = SRV_MAX_N_IO_THREADS; + if ((srv_n_read_io_threads + srv_n_write_io_threads) > SRV_MAX_N_IO_THREADS) { + fprintf(stderr, + "InnoDB: requested too many read(%d) or write(%d) IO threads, max is %d\n", + (int)srv_n_read_io_threads, + (int)srv_n_write_io_threads, + SRV_MAX_N_IO_THREADS); + return(DB_ERROR); } if (!os_aio_use_native_aio) { - /* In simulated aio we currently have use only for 4 threads */ - srv_n_file_io_threads = 4; - - os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD - * srv_n_file_io_threads, - srv_n_file_io_threads, - SRV_MAX_N_PENDING_SYNC_IOS); + /* More than 4 threads are now supported. */ + n_threads = os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD, + srv_n_read_io_threads, + srv_n_write_io_threads, + SRV_MAX_N_PENDING_SYNC_IOS); } else { - os_aio_init(SRV_N_PENDING_IOS_PER_THREAD - * srv_n_file_io_threads, - srv_n_file_io_threads, - SRV_MAX_N_PENDING_SYNC_IOS); + /* Might need more slots here. Alas, I don't do windows. */ + n_threads = os_aio_init(SRV_N_PENDING_IOS_PER_THREAD, + srv_n_read_io_threads, + srv_n_write_io_threads, + SRV_MAX_N_PENDING_SYNC_IOS); + } + + if (n_threads > SRV_MAX_N_IO_THREADS) { + fprintf(stderr, + "InnoDB: requested too many IO threads(%d), max is %d\n", + (int)n_threads, SRV_MAX_N_IO_THREADS); + return(DB_ERROR); } fil_init(srv_max_n_open_files); @@ -1296,7 +1325,7 @@ innobase_start_or_create_for_mysql(void) /* Create i/o-handler threads: */ - for (i = 0; i < srv_n_file_io_threads; i++) { + for (i = 0; i < n_threads; i++) { n[i] = i; os_thread_create(io_handler_thread, n + i, thread_ids + i); === modified file 'storage/innobase/sync/sync0arr.c' --- a/storage/innobase/sync/sync0arr.c 2008-06-12 00:08:07 +0000 +++ b/storage/innobase/sync/sync0arr.c 2009-07-02 14:23:36 +0000 @@ -110,6 +110,10 @@ struct sync_array_struct { since creation of the array */ }; +/* Counts the number of times that sync_arr_wake_threads_if_sema_free has + * found a thread that can run because it may have missed a wakeup signal. */ +ulint sync_wake_ups = 0; + #ifdef UNIV_SYNC_DEBUG /********************************************************************** This function is called only in the debug version. Detects a deadlock @@ -295,28 +299,25 @@ sync_array_validate( } /*********************************************************************** -Puts the cell event in reset state. */ +Returns the event that the thread owning the cell waits for. */ static -ib_longlong -sync_cell_event_reset( -/*==================*/ - /* out: value of signal_count - at the time of reset. */ - ulint type, /* in: lock type mutex/rw_lock */ - void* object) /* in: the rw_lock/mutex object */ +os_event_t +sync_cell_get_event( +/*================*/ + sync_cell_t* cell) /* in: non-empty sync array cell */ { + ulint type = cell->request_type; + if (type == SYNC_MUTEX) { - return(os_event_reset(((mutex_t *) object)->event)); -#ifdef __WIN__ + return(((mutex_t *) cell->wait_object)->event); } else if (type == RW_LOCK_WAIT_EX) { - return(os_event_reset( - ((rw_lock_t *) object)->wait_ex_event)); -#endif - } else { - return(os_event_reset(((rw_lock_t *) object)->event)); + return(((rw_lock_t *) cell->wait_object)->wait_ex_event); + } else { /* RW_LOCK_SHARED and RW_LOCK_EX wait on the same event */ + return(((rw_lock_t *) cell->wait_object)->event); } } + /********************************************************************** Reserves a wait array cell for waiting for an object. The event of the cell is reset to nonsignalled state. */ @@ -332,6 +333,7 @@ sync_array_reserve_cell( ulint* index) /* out: index of the reserved cell */ { sync_cell_t* cell; + os_event_t event; ulint i; ut_a(object); @@ -370,8 +372,8 @@ sync_array_reserve_cell( /* Make sure the event is reset and also store the value of signal_count at which the event was reset. */ - cell->signal_count = sync_cell_event_reset(type, - object); + event = sync_cell_get_event(cell); + cell->signal_count = os_event_reset(event); cell->reservation_time = time(NULL); @@ -411,19 +413,7 @@ sync_array_wait_event( ut_a(!cell->waiting); ut_ad(os_thread_get_curr_id() == cell->thread); - if (cell->request_type == SYNC_MUTEX) { - event = ((mutex_t*) cell->wait_object)->event; -#ifdef __WIN__ - /* On windows if the thread about to wait is the one which - has set the state of the rw_lock to RW_LOCK_WAIT_EX, then - it waits on a special event i.e.: wait_ex_event. */ - } else if (cell->request_type == RW_LOCK_WAIT_EX) { - event = ((rw_lock_t*) cell->wait_object)->wait_ex_event; -#endif - } else { - event = ((rw_lock_t*) cell->wait_object)->event; - } - + event = sync_cell_get_event(cell); cell->waiting = TRUE; #ifdef UNIV_SYNC_DEBUG @@ -462,6 +452,7 @@ sync_array_cell_print( mutex_t* mutex; rw_lock_t* rwlock; ulint type; + ulint writer; type = cell->request_type; @@ -491,12 +482,14 @@ sync_array_cell_print( (ulong) mutex->waiters); } else if (type == RW_LOCK_EX -#ifdef __WIN__ || type == RW_LOCK_WAIT_EX -#endif || type == RW_LOCK_SHARED) { - fputs(type == RW_LOCK_EX ? "X-lock on" : "S-lock on", file); + switch(type) { + case RW_LOCK_EX: fputs("X-lock on", file); break; + case RW_LOCK_WAIT_EX: fputs("wait-X-lock on", file); break; + default: fputs("S-lock on", file); break; + } rwlock = cell->old_wait_rw_lock; @@ -504,22 +497,25 @@ sync_array_cell_print( " RW-latch at %p created in file %s line %lu\n", (void*) rwlock, rwlock->cfile_name, (ulong) rwlock->cline); - if (rwlock->writer != RW_LOCK_NOT_LOCKED) { + writer = rw_lock_get_writer(rwlock); + if (writer != RW_LOCK_NOT_LOCKED) { fprintf(file, "a writer (thread id %lu) has" " reserved it in mode %s", (ulong) os_thread_pf(rwlock->writer_thread), - rwlock->writer == RW_LOCK_EX + writer == RW_LOCK_EX ? " exclusive\n" : " wait exclusive\n"); } fprintf(file, - "number of readers %lu, waiters flag %lu\n" + "number of readers %lu, waiters flag %lu, " + "lock_word: %ld\n" "Last time read locked in file %s line %lu\n" "Last time write locked in file %s line %lu\n", - (ulong) rwlock->reader_count, + (ulong) rw_lock_get_reader_count(rwlock), (ulong) rwlock->waiters, + rwlock->lock_word, rwlock->last_s_file_name, (ulong) rwlock->last_s_line, rwlock->last_x_file_name, @@ -553,7 +549,8 @@ sync_array_find_thread( cell = sync_array_get_nth_cell(arr, i); if (cell->wait_object != NULL - && os_thread_eq(cell->thread, thread)) { + && os_thread_eq(cell->thread, thread) + && cell->waiting)) { return(cell); /* Found */ } @@ -778,28 +775,30 @@ sync_arr_cell_can_wake_up( return(TRUE); } - } else if (cell->request_type == RW_LOCK_EX - || cell->request_type == RW_LOCK_WAIT_EX) { + } else if (cell->request_type == RW_LOCK_EX) { lock = cell->wait_object; - if (rw_lock_get_reader_count(lock) == 0 - && rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { + /* X_LOCK_DECR is the unlocked state */ + if (lock->lock_word == X_LOCK_DECR) { return(TRUE); } - if (rw_lock_get_reader_count(lock) == 0 - && rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX - && os_thread_eq(lock->writer_thread, cell->thread)) { + } else if (cell->request_type == RW_LOCK_WAIT_EX) { + + lock = cell->wait_object; + + /* lock_word == 0 means all readers have left */ + if (lock->lock_word == 0) { return(TRUE); } - } else if (cell->request_type == RW_LOCK_SHARED) { lock = cell->wait_object; - if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { + /* lock_word > 0 means no writer or reserved writer */ + if (lock->lock_word > 0) { return(TRUE); } @@ -844,11 +843,15 @@ sync_array_object_signalled( /*========================*/ sync_array_t* arr) /* in: wait array */ { +#ifdef UNIV_SYNC_ATOMIC + (void)os_atomic_increment((volatile lint *)&(arr->sg_count), 1); +#else sync_array_enter(arr); arr->sg_count++; sync_array_exit(arr); +#endif } /************************************************************************** @@ -868,6 +871,7 @@ sync_arr_wake_threads_if_sema_free(void) sync_cell_t* cell; ulint count; ulint i; + os_event_t event; sync_array_enter(arr); @@ -877,36 +881,25 @@ sync_arr_wake_threads_if_sema_free(void) while (count < arr->n_reserved) { cell = sync_array_get_nth_cell(arr, i); + i++; - if (cell->wait_object != NULL) { - + if (cell->wait_object == NULL) { + continue; + } count++; - if (sync_arr_cell_can_wake_up(cell)) { - - if (cell->request_type == SYNC_MUTEX) { - mutex_t* mutex; + if (!cell->waiting) { + continue; + } - mutex = cell->wait_object; - os_event_set(mutex->event); -#ifdef __WIN__ - } else if (cell->request_type - == RW_LOCK_WAIT_EX) { - rw_lock_t* lock; + if (sync_arr_cell_can_wake_up(cell)) { - lock = cell->wait_object; - os_event_set(lock->wait_ex_event); -#endif - } else { - rw_lock_t* lock; + event = sync_cell_get_event(cell); - lock = cell->wait_object; - os_event_set(lock->event); - } - } + os_event_set(event); + sync_wake_ups++; } - i++; } sync_array_exit(arr); @@ -1026,4 +1019,3 @@ sync_array_print_info( sync_array_exit(arr); } - === modified file 'storage/innobase/sync/sync0rw.c' --- a/storage/innobase/sync/sync0rw.c 2008-06-12 00:08:07 +0000 +++ b/storage/innobase/sync/sync0rw.c 2009-07-02 14:23:36 +0000 @@ -15,35 +15,110 @@ Created 9/11/1995 Heikki Tuuri #include "mem0mem.h" #include "srv0srv.h" -/* number of system calls made during shared latching */ -ulint rw_s_system_call_count = 0; +/* + IMPLEMENTATION OF THE RW_LOCK + ============================= +The status of a rw_lock is held in lock_word. The initial value of lock_word is +X_LOCK_DECR. lock_word is decremented by 1 for each s-lock and by X_LOCK_DECR +for each x-lock. This describes the lock state for each value of lock_word: + +lock_word == X_LOCK_DECR: Unlocked. +0 < lock_word < X_LOCK_DECR: Read locked, no waiting writers. + (X_LOCK_DECR - lock_word) is the + number of readers that hold the lock. +lock_word == 0: Write locked +-X_LOCK_DECR < lock_word < 0: Read locked, with a waiting writer. + (-lock_word) is the number of readers + that hold the lock. +lock_word <= -X_LOCK_DECR: Recursively write locked. lock_word has been + decremented by X_LOCK_DECR once for each lock, + so the number of locks is: + ((-lock_word) / X_LOCK_DECR) + 1 +When lock_word <= -X_LOCK_DECR, we also know that lock_word % X_LOCK_DECR == 0: +other values of lock_word are invalid. + +The lock_word is always read and updated atomically and consistently, so that +it always represents the state of the lock, and the state of the lock changes +with a single atomic operation. This lock_word holds all of the information +that a thread needs in order to determine if it is eligible to gain the lock +or if it must spin or sleep. The one exception to this is that writer_thread +must be verified before recursive write locks: to solve this scenario, we make +writer_thread readable by all threads, but only writeable by the x-lock holder. + +The other members of the lock obey the following rules to remain consistent: + +pass: This is only set to 1 to prevent recursive x-locks. It must + be set as specified by x_lock caller after the lock_word + indicates that the thread holds the lock, but before that + thread resumes execution. It must also be set to 1 during the + final x_unlock, but before the lock_word status is updated. + When an x_lock or move_ownership call wishes to change + pass, it must first update the writer_thread appropriately. +writer_thread: Must be set to the writers thread_id after the lock_word + indicates that the thread holds the lock, but before that + thread resumes execution. writer_thread may be invalid and + should not be read when pass == 1. A thread trying to become + writer never reads its own stale writer_thread, since it sets + pass during its previous unlock call. +waiters: May be set to 1 anytime, but to avoid unnecessary wake-up + signals, it should only be set to 1 when there are threads + waiting on event. Must be 1 when a writer starts waiting to + ensure the current x-locking thread sends a wake-up signal + during unlock. May only be reset to 0 immediately before a + a wake-up signal is sent to event. +event: Threads wait on event for read or writer lock when another + thread has an x-lock or an x-lock reservation (wait_ex). A + thread may only wait on event after performing the following + actions in order: + (1) Record the counter value of event (with os_event_reset). + (2) Set waiters to 1. + (3) Verify lock_word <= 0. + (1) must come before (2) to ensure signal is not missed. + (2) must come before (3) to ensure a signal is sent. + These restrictions force the above ordering. + Immediately before sending the wake-up signal, we should: + (1) Verify lock_word == X_LOCK_DECR (unlocked) + (2) Reset waiters to 0. +wait_ex_event: A thread may only wait on the wait_ex_event after it has + performed the following actions in order: + (1) Decrement lock_word by X_LOCK_DECR. + (2) Record counter value of wait_ex_event (os_event_reset, + called from sync_array_reserve_cell). + (3) Verify that lock_word < 0. + (1) must come first to ensures no other threads become reader + or next writer, and notifies unlocker that signal must be sent. + (2) must come before (3) to ensure the signal is not missed. + These restrictions force the above ordering. + Immediately before sending the wake-up signal, we should: + Verify lock_word == 0 (waiting thread holds x_lock) +*/ + /* number of spin waits on rw-latches, resulted during shared (read) locks */ -ulint rw_s_spin_wait_count = 0; +ib_longlong rw_s_spin_wait_count = 0; +ib_longlong rw_s_spin_round_count = 0; /* number of OS waits on rw-latches, resulted during shared (read) locks */ -ulint rw_s_os_wait_count = 0; +ib_longlong rw_s_os_wait_count = 0; /* number of unlocks (that unlock shared locks), set only when UNIV_SYNC_PERF_STAT is defined */ -ulint rw_s_exit_count = 0; - -/* number of system calls made during exclusive latching */ -ulint rw_x_system_call_count = 0; +ib_longlong rw_s_exit_count = 0; /* number of spin waits on rw-latches, resulted during exclusive (write) locks */ -ulint rw_x_spin_wait_count = 0; +ib_longlong rw_x_spin_wait_count = 0; +ib_longlong rw_x_spin_round_count = 0; /* number of OS waits on rw-latches, resulted during exclusive (write) locks */ -ulint rw_x_os_wait_count = 0; +ib_longlong rw_x_os_wait_count = 0; /* number of unlocks (that unlock exclusive locks), set only when UNIV_SYNC_PERF_STAT is defined */ -ulint rw_x_exit_count = 0; +ib_longlong rw_x_exit_count = 0; /* The global list of rw-locks */ rw_lock_list_t rw_lock_list; @@ -119,6 +194,7 @@ rw_lock_create_func( /* If this is the very first time a synchronization object is created, then the following call initializes the sync system. */ +#ifndef UNIV_SYNC_ATOMIC mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK); lock->mutex.cfile_name = cfile_name; @@ -129,12 +205,12 @@ rw_lock_create_func( lock->mutex.mutex_type = 1; #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */ - rw_lock_set_waiters(lock, 0); - rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); - lock->writer_count = 0; - rw_lock_set_reader_count(lock, 0); +#endif /* UNIV_SYNC_ATOMIC */ - lock->writer_is_wait_ex = FALSE; + lock->lock_word = X_LOCK_DECR; + lock->waiters = 0; + lock->pass = 1; + /* We do not have to initialize writer_thread until pass == 0 */ #ifdef UNIV_SYNC_DEBUG UT_LIST_INIT(lock->debug_list); @@ -147,15 +223,13 @@ rw_lock_create_func( lock->cfile_name = cfile_name; lock->cline = (unsigned int) cline; + lock->count_os_wait = 0; lock->last_s_file_name = "not yet reserved"; lock->last_x_file_name = "not yet reserved"; lock->last_s_line = 0; lock->last_x_line = 0; lock->event = os_event_create(NULL); - -#ifdef __WIN__ lock->wait_ex_event = os_event_create(NULL); -#endif mutex_enter(&rw_lock_list_mutex); @@ -180,20 +254,18 @@ rw_lock_free( rw_lock_t* lock) /* in: rw-lock */ { ut_ad(rw_lock_validate(lock)); - ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); - ut_a(rw_lock_get_waiters(lock) == 0); - ut_a(rw_lock_get_reader_count(lock) == 0); + ut_a(lock->lock_word == X_LOCK_DECR); lock->magic_n = 0; +#ifndef UNIV_SYNC_ATOMIC mutex_free(rw_lock_get_mutex(lock)); +#endif /* UNIV_SYNC_ATOMIC */ mutex_enter(&rw_lock_list_mutex); os_event_free(lock->event); -#ifdef __WIN__ os_event_free(lock->wait_ex_event); -#endif if (UT_LIST_GET_PREV(list, lock)) { ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N); @@ -219,19 +291,12 @@ rw_lock_validate( { ut_a(lock); - mutex_enter(rw_lock_get_mutex(lock)); + ulint waiters = rw_lock_get_waiters(lock); + lint lock_word = lock->lock_word; ut_a(lock->magic_n == RW_LOCK_MAGIC_N); - ut_a((rw_lock_get_reader_count(lock) == 0) - || (rw_lock_get_writer(lock) != RW_LOCK_EX)); - ut_a((rw_lock_get_writer(lock) == RW_LOCK_EX) - || (rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX) - || (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED)); - ut_a((rw_lock_get_waiters(lock) == 0) - || (rw_lock_get_waiters(lock) == 1)); - ut_a((lock->writer != RW_LOCK_EX) || (lock->writer_count > 0)); - - mutex_exit(rw_lock_get_mutex(lock)); + ut_a(waiters == 0 || waiters == 1); + ut_a(lock_word > -X_LOCK_DECR ||(-lock_word) % X_LOCK_DECR == 0); return(TRUE); } @@ -253,18 +318,15 @@ rw_lock_s_lock_spin( ulint line) /* in: line where requested */ { ulint index; /* index of the reserved wait cell */ - ulint i; /* spin round count */ + ulint i = 0; /* spin round count */ ut_ad(rw_lock_validate(lock)); + rw_s_spin_wait_count++; /* Count calls to this function */ lock_loop: - rw_s_spin_wait_count++; /* Spin waiting for the writer field to become free */ - i = 0; - - while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED - && i < SYNC_SPIN_ROUNDS) { + while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); } @@ -285,28 +347,32 @@ lock_loop: lock->cfile_name, (ulong) lock->cline, (ulong) i); } - mutex_enter(rw_lock_get_mutex(lock)); - /* We try once again to obtain the lock */ - if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) { - mutex_exit(rw_lock_get_mutex(lock)); + rw_s_spin_round_count += i; return; /* Success */ } else { - /* If we get here, locking did not succeed, we may - suspend the thread to wait in the wait array */ - rw_s_system_call_count++; + if (i < SYNC_SPIN_ROUNDS) { + goto lock_loop; + } + + rw_s_spin_round_count += i; sync_array_reserve_cell(sync_primary_wait_array, lock, RW_LOCK_SHARED, file_name, line, &index); - rw_lock_set_waiters(lock, 1); - - mutex_exit(rw_lock_get_mutex(lock)); + /* Set waiters before checking lock_word to ensure wake-up + signal is sent. This may lead to some unnecessary signals. */ + rw_lock_set_waiters(lock); + + if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) { + sync_array_free_cell(sync_primary_wait_array, index); + return; /* Success */ + } if (srv_print_latch_waits) { fprintf(stderr, @@ -317,11 +383,13 @@ lock_loop: (ulong) lock->cline); } - rw_s_system_call_count++; + /* these stats may not be accurate */ + lock->count_os_wait++; rw_s_os_wait_count++; sync_array_wait_event(sync_primary_wait_array, index); + i = 0; goto lock_loop; } } @@ -343,113 +411,137 @@ rw_lock_x_lock_move_ownership( { ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX)); +#ifdef UNIV_SYNC_ATOMIC + lock->writer_thread = os_thread_get_curr_id(); + os_memory_barrier_store(); + lock->pass = 0; +#else /* UNIV_SYNC_ATOMIC */ mutex_enter(&(lock->mutex)); - lock->writer_thread = os_thread_get_curr_id(); - lock->pass = 0; - mutex_exit(&(lock->mutex)); +#endif /* UNIV_SYNC_ATOMIC */ } /********************************************************************** -Low-level function for acquiring an exclusive lock. */ +Function for the next writer to call. Waits for readers to exit. +The caller must have already decremented lock_word by X_LOCK_DECR.*/ UNIV_INLINE -ulint -rw_lock_x_lock_low( -/*===============*/ - /* out: RW_LOCK_NOT_LOCKED if did - not succeed, RW_LOCK_EX if success, - RW_LOCK_WAIT_EX, if got wait reservation */ +void +rw_lock_x_lock_wait( +/*================*/ rw_lock_t* lock, /* in: pointer to rw-lock */ +#ifdef UNIV_SYNC_DEBUG ulint pass, /* in: pass value; != 0, if the lock will be passed to another thread to unlock */ +#endif const char* file_name,/* in: file name where lock requested */ ulint line) /* in: line where requested */ { - ut_ad(mutex_own(rw_lock_get_mutex(lock))); + ulint index; + ulint i = 0; - if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { + ut_ad(lock->lock_word <= 0); - if (rw_lock_get_reader_count(lock) == 0) { + while (lock->lock_word < 0) { + if (srv_spin_wait_delay) { + ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); + } + if(i < SYNC_SPIN_ROUNDS) { + i++; + continue; + } - rw_lock_set_writer(lock, RW_LOCK_EX); - lock->writer_thread = os_thread_get_curr_id(); - lock->writer_count++; - lock->pass = pass; + /* If there is still a reader, then go to sleep.*/ + rw_x_spin_round_count += i; + i = 0; + sync_array_reserve_cell(sync_primary_wait_array, + lock, + RW_LOCK_WAIT_EX, + file_name, line, + &index); + /* Check lock_word to ensure wake-up isn't missed.*/ + if(lock->lock_word < 0) { + /* these stats may not be accurate */ + lock->count_os_wait++; + rw_x_os_wait_count++; + + /* Add debug info as it is needed to detect possible + deadlock. We must add info for WAIT_EX thread for + deadlock detection to work properly. */ #ifdef UNIV_SYNC_DEBUG - rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, + rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX, file_name, line); #endif - lock->last_x_file_name = file_name; - lock->last_x_line = (unsigned int) line; - - /* Locking succeeded, we may return */ - return(RW_LOCK_EX); - } else { - /* There are readers, we have to wait */ - rw_lock_set_writer(lock, RW_LOCK_WAIT_EX); - lock->writer_thread = os_thread_get_curr_id(); - lock->pass = pass; - lock->writer_is_wait_ex = TRUE; + sync_array_wait_event(sync_primary_wait_array, + index); #ifdef UNIV_SYNC_DEBUG - rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX, - file_name, line); + rw_lock_remove_debug_info(lock, pass, + RW_LOCK_WAIT_EX); #endif - - return(RW_LOCK_WAIT_EX); + /* It is possible to wake when lock_word < 0. + We must pass the while-loop check to proceed.*/ + } else { + sync_array_free_cell(sync_primary_wait_array, + index); } + } + rw_x_spin_round_count += i; +} - } else if ((rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX) - && os_thread_eq(lock->writer_thread, - os_thread_get_curr_id())) { - - if (rw_lock_get_reader_count(lock) == 0) { +/********************************************************************** +Low-level function for acquiring an exclusive lock. */ +UNIV_INLINE +ibool +rw_lock_x_lock_low( +/*===============*/ + /* out: RW_LOCK_NOT_LOCKED if did + not succeed, RW_LOCK_EX if success. */ + rw_lock_t* lock, /* in: pointer to rw-lock */ + ulint pass, /* in: pass value; != 0, if the lock will + be passed to another thread to unlock */ + const char* file_name,/* in: file name where lock requested */ + ulint line) /* in: line where requested */ +{ + os_thread_id_t curr_thread = os_thread_get_curr_id(); - rw_lock_set_writer(lock, RW_LOCK_EX); - lock->writer_count++; - lock->pass = pass; - lock->writer_is_wait_ex = FALSE; + if(rw_lock_lock_word_decr(lock, X_LOCK_DECR)) { + ut_ad(lock->pass); + /* Decrement occurred: we are writer or next-writer. */ + lock->writer_thread = curr_thread; + lock->pass = pass; + rw_lock_x_lock_wait(lock, #ifdef UNIV_SYNC_DEBUG - rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX); - rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, - file_name, line); + pass, #endif + file_name, line); - lock->last_x_file_name = file_name; - lock->last_x_line = (unsigned int) line; - - /* Locking succeeded, we may return */ - return(RW_LOCK_EX); + } else { + /* Decrement failed: relock or failed lock */ + /* Must verify pass first: otherwise another thread can + call move_ownership suddenly allowing recursive locks. + and after we have verified our thread_id matches + (though move_ownership has since changed it).*/ + if(!pass && !(lock->pass) && + os_thread_eq(lock->writer_thread, curr_thread)) { + /* Relock */ + lock->lock_word -= X_LOCK_DECR; + } else { + /* Another thread locked before us */ + return(FALSE); } - - return(RW_LOCK_WAIT_EX); - - } else if ((rw_lock_get_writer(lock) == RW_LOCK_EX) - && os_thread_eq(lock->writer_thread, - os_thread_get_curr_id()) - && (lock->pass == 0) - && (pass == 0)) { - - lock->writer_count++; - + } #ifdef UNIV_SYNC_DEBUG - rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name, - line); + rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, + file_name, line); #endif + lock->last_x_file_name = file_name; + lock->last_x_line = (unsigned int) line; - lock->last_x_file_name = file_name; - lock->last_x_line = (unsigned int) line; - - /* Locking succeeded, we may return */ - return(RW_LOCK_EX); - } - - /* Locking did not succeed */ - return(RW_LOCK_NOT_LOCKED); + return(TRUE); } /********************************************************************** @@ -472,47 +564,30 @@ rw_lock_x_lock_func( ulint line) /* in: line where requested */ { ulint index; /* index of the reserved wait cell */ - ulint state; /* lock state acquired */ ulint i; /* spin round count */ + ibool spinning = FALSE; ut_ad(rw_lock_validate(lock)); -lock_loop: - /* Acquire the mutex protecting the rw-lock fields */ - mutex_enter_fast(&(lock->mutex)); - - state = rw_lock_x_lock_low(lock, pass, file_name, line); + i = 0; - mutex_exit(&(lock->mutex)); +lock_loop: - if (state == RW_LOCK_EX) { + if (rw_lock_x_lock_low(lock, pass, file_name, line)) { + rw_x_spin_round_count += i; return; /* Locking succeeded */ - } else if (state == RW_LOCK_NOT_LOCKED) { - - /* Spin waiting for the writer field to become free */ - i = 0; - - while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED - && i < SYNC_SPIN_ROUNDS) { - if (srv_spin_wait_delay) { - ut_delay(ut_rnd_interval(0, - srv_spin_wait_delay)); - } + } else { - i++; - } - if (i == SYNC_SPIN_ROUNDS) { - os_thread_yield(); + if (!spinning) { + spinning = TRUE; + rw_x_spin_wait_count++; } - } else if (state == RW_LOCK_WAIT_EX) { - - /* Spin waiting for the reader count field to become zero */ - i = 0; - while (rw_lock_get_reader_count(lock) != 0 - && i < SYNC_SPIN_ROUNDS) { + /* Spin waiting for the lock_word to become free */ + while (i < SYNC_SPIN_ROUNDS + && lock->lock_word <= 0) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); @@ -522,12 +597,13 @@ lock_loop: } if (i == SYNC_SPIN_ROUNDS) { os_thread_yield(); + } else { + goto lock_loop; } - } else { - i = 0; /* Eliminate a compiler warning */ - ut_error; } + rw_x_spin_round_count += i; + if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-x-lock at %p" @@ -536,39 +612,20 @@ lock_loop: lock->cfile_name, (ulong) lock->cline, (ulong) i); } - rw_x_spin_wait_count++; - - /* We try once again to obtain the lock. Acquire the mutex protecting - the rw-lock fields */ - - mutex_enter(rw_lock_get_mutex(lock)); - - state = rw_lock_x_lock_low(lock, pass, file_name, line); - - if (state == RW_LOCK_EX) { - mutex_exit(rw_lock_get_mutex(lock)); - - return; /* Locking succeeded */ - } - - rw_x_system_call_count++; - sync_array_reserve_cell(sync_primary_wait_array, lock, -#ifdef __WIN__ - /* On windows RW_LOCK_WAIT_EX signifies - that this thread should wait on the - special wait_ex_event. */ - (state == RW_LOCK_WAIT_EX) - ? RW_LOCK_WAIT_EX : -#endif RW_LOCK_EX, file_name, line, &index); - rw_lock_set_waiters(lock, 1); - - mutex_exit(rw_lock_get_mutex(lock)); + /* Waiters must be set before checking lock_word, to ensure signal + is sent. This could lead to a few unnecessary wake-up signals. */ + rw_lock_set_waiters(lock); + + if (rw_lock_x_lock_low(lock, pass, file_name, line)) { + sync_array_free_cell(sync_primary_wait_array, index); + return; /* Locking succeeded */ + } if (srv_print_latch_waits) { fprintf(stderr, @@ -578,11 +635,13 @@ lock_loop: lock->cfile_name, (ulong) lock->cline); } - rw_x_system_call_count++; + /* these stats may not be accurate */ + lock->count_os_wait++; rw_x_os_wait_count++; sync_array_wait_event(sync_primary_wait_array, index); + i = 0; goto lock_loop; } @@ -730,7 +789,7 @@ rw_lock_own( ut_ad(lock); ut_ad(rw_lock_validate(lock)); - mutex_enter(&(lock->mutex)); + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); @@ -740,7 +799,7 @@ rw_lock_own( && (info->pass == 0) && (info->lock_type == lock_type)) { - mutex_exit(&(lock->mutex)); + rw_lock_debug_mutex_exit(); /* Found! */ return(TRUE); @@ -748,7 +807,7 @@ rw_lock_own( info = UT_LIST_GET_NEXT(list, info); } - mutex_exit(&(lock->mutex)); + rw_lock_debug_mutex_exit(); return(FALSE); } @@ -770,22 +829,18 @@ rw_lock_is_locked( ut_ad(lock); ut_ad(rw_lock_validate(lock)); - mutex_enter(&(lock->mutex)); - if (lock_type == RW_LOCK_SHARED) { - if (lock->reader_count > 0) { + if (rw_lock_get_reader_count(lock) > 0) { ret = TRUE; } } else if (lock_type == RW_LOCK_EX) { - if (lock->writer == RW_LOCK_EX) { + if (rw_lock_get_writer(lock) == RW_LOCK_EX) { ret = TRUE; } } else { ut_error; } - mutex_exit(&(lock->mutex)); - return(ret); } @@ -814,11 +869,10 @@ rw_lock_list_print_info( count++; +#ifndef UNIV_SYNC_ATOMIC mutex_enter(&(lock->mutex)); - - if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) - || (rw_lock_get_reader_count(lock) != 0) - || (rw_lock_get_waiters(lock) != 0)) { +#endif + if (lock->lock_word != X_LOCK_DECR) { fprintf(file, "RW-LOCK: %p ", (void*) lock); @@ -834,8 +888,10 @@ rw_lock_list_print_info( info = UT_LIST_GET_NEXT(list, info); } } - +#ifndef UNIV_SYNC_ATOMIC mutex_exit(&(lock->mutex)); +#endif + lock = UT_LIST_GET_NEXT(list, lock); } @@ -858,9 +914,10 @@ rw_lock_print( "RW-LATCH INFO\n" "RW-LATCH: %p ", (void*) lock); - if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) - || (rw_lock_get_reader_count(lock) != 0) - || (rw_lock_get_waiters(lock) != 0)) { +#ifndef UNIV_SYNC_ATOMIC + mutex_enter(&(lock->mutex)); +#endif + if (lock->lock_word != X_LOCK_DECR) { if (rw_lock_get_waiters(lock)) { fputs(" Waiters for the lock exist\n", stderr); @@ -874,6 +931,9 @@ rw_lock_print( info = UT_LIST_GET_NEXT(list, info); } } +#ifndef UNIV_SYNC_ATOMIC + mutex_exit(&(lock->mutex)); +#endif } /************************************************************************* @@ -922,14 +982,11 @@ rw_lock_n_locked(void) lock = UT_LIST_GET_FIRST(rw_lock_list); while (lock != NULL) { - mutex_enter(rw_lock_get_mutex(lock)); - if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) - || (rw_lock_get_reader_count(lock) != 0)) { + if (lock->lock_word != X_LOCK_DECR) { count++; } - mutex_exit(rw_lock_get_mutex(lock)); lock = UT_LIST_GET_NEXT(list, lock); } === modified file 'storage/innobase/sync/sync0sync.c' --- a/storage/innobase/sync/sync0sync.c 2008-06-12 00:08:07 +0000 +++ b/storage/innobase/sync/sync0sync.c 2009-07-02 14:23:36 +0000 @@ -138,18 +138,13 @@ Therefore, this thread is guaranteed to signalled unconditionally at the release of the lock. Q.E.D. */ -/* The number of system calls made in this module. Intended for performance -monitoring. */ - -ulint mutex_system_call_count = 0; - /* Number of spin waits on mutexes: for performance monitoring */ /* round=one iteration of a spin loop */ -ulint mutex_spin_round_count = 0; -ulint mutex_spin_wait_count = 0; -ulint mutex_os_wait_count = 0; -ulint mutex_exit_count = 0; +ib_longlong mutex_spin_round_count = 0; +ib_longlong mutex_spin_wait_count = 0; +ib_longlong mutex_os_wait_count = 0; +ib_longlong mutex_exit_count = 0; /* The global array of wait cells for implementation of the database's own mutexes and read-write locks */ @@ -243,6 +238,8 @@ mutex_create_func( { #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER) mutex_reset_lock_word(mutex); +#elif defined(MY_ATOMIC_NOLOCK) + mutex_reset_lock_word(mutex); #else os_fast_mutex_init(&(mutex->os_fast_mutex)); mutex->lock_word = 0; @@ -333,7 +330,9 @@ mutex_free( os_event_free(mutex->event); -#if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) +#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER) +#elif defined(MY_ATOMIC_NOLOCK) +#else os_fast_mutex_free(&(mutex->os_fast_mutex)); #endif /* If we free the mutex protecting the mutex list (freeing is @@ -450,6 +449,12 @@ mutex_spin_wait( #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */ ut_ad(mutex); + /* This update is not thread safe, but we don't mind if the count + isn't exact. Moved out of ifdef that follows because we are willing + to sacrifice the cost of counting this as the data is valuable. + Count the number of calls to mutex_spin_wait. */ + mutex_spin_wait_count++; + mutex_loop: i = 0; @@ -462,7 +467,6 @@ mutex_loop: spin_loop: #if defined UNIV_DEBUG && !defined UNIV_HOTBACKUP - mutex_spin_wait_count++; mutex->count_spin_loop++; #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */ @@ -527,8 +531,6 @@ spin_loop: sync_array_reserve_cell(sync_primary_wait_array, mutex, SYNC_MUTEX, file_name, line, &index); - mutex_system_call_count++; - /* The memory order of the array reservation and the change in the waiters field is important: when we suspend a thread, we first reserve the cell and then set waiters field to 1. When threads are @@ -575,7 +577,6 @@ spin_loop: mutex->cfile_name, (ulong) mutex->cline, (ulong) i); #endif - mutex_system_call_count++; mutex_os_wait_count++; #ifndef UNIV_HOTBACKUP @@ -1377,21 +1378,31 @@ sync_print_wait_info( FILE* file) /* in: file where to print */ { #ifdef UNIV_SYNC_DEBUG - fprintf(file, "Mutex exits %lu, rws exits %lu, rwx exits %lu\n", + fprintf(file, "Mutex exits %llu, rws exits %llu, rwx exits %llu\n", mutex_exit_count, rw_s_exit_count, rw_x_exit_count); #endif fprintf(file, - "Mutex spin waits %lu, rounds %lu, OS waits %lu\n" - "RW-shared spins %lu, OS waits %lu;" - " RW-excl spins %lu, OS waits %lu\n", - (ulong) mutex_spin_wait_count, - (ulong) mutex_spin_round_count, - (ulong) mutex_os_wait_count, - (ulong) rw_s_spin_wait_count, - (ulong) rw_s_os_wait_count, - (ulong) rw_x_spin_wait_count, - (ulong) rw_x_os_wait_count); + "Mutex spin waits %llu, rounds %llu, OS waits %llu\n" + "RW-shared spins %llu, OS waits %llu;" + " RW-excl spins %llu, OS waits %llu\n", + mutex_spin_wait_count, + mutex_spin_round_count, + mutex_os_wait_count, + rw_s_spin_wait_count, + rw_s_os_wait_count, + rw_x_spin_wait_count, + rw_x_os_wait_count); + + fprintf(file, + "Spin rounds per wait: %.2f mutex, %.2f RW-shared, " + "%.2f RW-excl\n", + (double) mutex_spin_round_count / + (mutex_spin_wait_count ? mutex_spin_wait_count : 1), + (double) rw_s_spin_round_count / + (rw_s_spin_wait_count ? rw_s_spin_wait_count : 1), + (double) rw_x_spin_round_count / + (rw_x_spin_wait_count ? rw_x_spin_wait_count : 1)); } /*********************************************************************** === modified file 'storage/innobase/ut/ut0ut.c' --- a/storage/innobase/ut/ut0ut.c 2008-12-19 00:34:15 +0000 +++ b/storage/innobase/ut/ut0ut.c 2009-07-02 14:23:36 +0000 @@ -154,6 +154,23 @@ ut_usectime( } /************************************************************** +Returns diff in microseconds (end_sec,end_ms) - (start_sec,start_ms) */ + +ib_longlong +ut_usecdiff( +/*========*/ + ulint end_sec, /* in: seconds since the Epoch */ + ulint end_ms, /* in: microseconds since the Epoch+*sec1 */ + ulint start_sec, /* in: seconds since the Epoch */ + ulint start_ms) /* in: microseconds since the Epoch+*sec2 */ +{ + ib_longlong end_mics = end_sec * 1000000LL + end_ms; + ib_longlong start_mics = start_sec * 1000000LL + start_ms; + + return end_mics - start_mics; +} + +/************************************************************** Returns the difference of two times in seconds. */ double @@ -348,6 +365,7 @@ ut_delay( j = 0; for (i = 0; i < delay * 50; i++) { + PAUSE_INSTRUCTION(); j += i; } === added file 'storage/innobase/win_atomics32_test.c' --- a/storage/innobase/win_atomics32_test.c 1970-01-01 00:00:00 +0000 +++ b/storage/innobase/win_atomics32_test.c 2009-06-16 13:16:15 +0000 @@ -0,0 +1,30 @@ +/* Copyright (C) 2009 Sun Microsystems AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include + +int main() +{ + volatile long var32 = 0; + long add32 = 1; + long old32 = 0; + long exch32 = 1; + long ret_value; + + ret_value = InterlockedExchangeAdd(&var32, add32); + ret_value = InterlockedCompareExchange(&var32, exch32, old32); + MemoryBarrier(); + return EXIT_SUCCESS; +} === added file 'storage/innobase/win_atomics64_test.c' --- a/storage/innobase/win_atomics64_test.c 1970-01-01 00:00:00 +0000 +++ b/storage/innobase/win_atomics64_test.c 2009-06-16 13:16:15 +0000 @@ -0,0 +1,30 @@ +/* Copyright (C) 2009 Sun Microsystems AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include + +int main() +{ + volatile long long var64 = 0; + long long add64 = 1; + long long old64 = 0; + long long exch64 = 1; + long long ret_value; + + ret_value = InterlockedExchangeAdd64(&var64, add64); + ret_value = InterlockedCompareExchange64(&var64, exch64, old64); + MemoryBarrier(); + return EXIT_SUCCESS; +} === modified file 'storage/myisam/Makefile.am' --- a/storage/myisam/Makefile.am 2009-04-06 18:36:46 +0000 +++ b/storage/myisam/Makefile.am 2009-07-02 14:23:36 +0000 @@ -146,3 +146,24 @@ SUFFIXES = .sh $< > $@-t @CHMOD@ +x $@-t @MV@ $@-t $@ + +if HAVE_DTRACE_DASH_G +libmyisam_a_LIBADD = probes_mysql.o +libmyisam_a_DEPENDENCIES = probes_mysql.o dtrace_files dtrace_providers +CLEANFILES += probes_mysql.o dtrace_files dtrace_providers +DTRACEFILES = ha_myisam.o +DTRACEPROVIDER = probes_mysql.d +CLEANFILES += $(DTRACEPROVIDER) dtrace_sources + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'storage/myisam/ha_myisam.cc' --- a/storage/myisam/ha_myisam.cc 2009-06-05 13:54:23 +0000 +++ b/storage/myisam/ha_myisam.cc 2009-07-02 14:23:36 +0000 @@ -20,6 +20,7 @@ #define MYSQL_SERVER 1 #include "mysql_priv.h" +#include "probes_mysql.h" #include #include #include @@ -978,6 +979,9 @@ int ha_myisam::repair(THD *thd, HA_CHECK // Release latches since this can take a long time ha_release_temporary_latches(thd); + // Release latches since this can take a long time + ha_release_temporary_latches(thd); + // Don't lock tables if we have used LOCK TABLE if (! thd->locked_tables_mode && mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK)) @@ -1565,10 +1569,12 @@ int ha_myisam::index_read_map(uchar *buf key_part_map keypart_map, enum ha_rkey_function find_flag) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_key_count); int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -1576,57 +1582,69 @@ int ha_myisam::index_read_idx_map(uchar key_part_map keypart_map, enum ha_rkey_function find_flag) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_key_count); int error=mi_rkey(file, buf, index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_myisam::index_read_last_map(uchar *buf, const uchar *key, key_part_map keypart_map) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ENTER("ha_myisam::index_read_last"); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_key_count); int error=mi_rkey(file, buf, active_index, key, keypart_map, HA_READ_PREFIX_LAST); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); DBUG_RETURN(error); } int ha_myisam::index_next(uchar *buf) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_next_count); int error=mi_rnext(file,buf,active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_myisam::index_prev(uchar *buf) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_prev_count); int error=mi_rprev(file,buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_myisam::index_first(uchar *buf) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_first_count); int error=mi_rfirst(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_myisam::index_last(uchar *buf) { + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); DBUG_ASSERT(inited==INDEX); ha_statistic_increment(&SSV::ha_read_last_count); int error=mi_rlast(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -1636,12 +1654,14 @@ int ha_myisam::index_next_same(uchar *bu { int error; DBUG_ASSERT(inited==INDEX); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_next_count); do { error= mi_rnext_same(file,buf); } while (error == HA_ERR_RECORD_DELETED); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -1655,9 +1675,12 @@ int ha_myisam::rnd_init(bool scan) int ha_myisam::rnd_next(uchar *buf) { + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); ha_statistic_increment(&SSV::ha_read_rnd_next_count); int error=mi_scan(file, buf); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_READ_ROW_DONE(error); return error; } @@ -1674,9 +1697,12 @@ int ha_myisam::restart_rnd_next(uchar *b int ha_myisam::rnd_pos(uchar *buf, uchar *pos) { + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + FALSE); ha_statistic_increment(&SSV::ha_read_rnd_count); int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length)); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_READ_ROW_DONE(error); return error; } === modified file 'storage/myisammrg/Makefile.am' --- a/storage/myisammrg/Makefile.am 2009-01-07 10:58:33 +0000 +++ b/storage/myisammrg/Makefile.am 2009-07-02 14:23:36 +0000 @@ -38,3 +38,24 @@ libmyisammrg_a_SOURCES = myrg_open.c myr EXTRA_DIST = CMakeLists.txt plug.in + +if HAVE_DTRACE_DASH_G +libmyisammrg_a_LIBADD = probes_mysql.o +libmyisammrg_a_DEPENDENCIES = probes_mysql.o dtrace_files dtrace_providers +CLEANFILES = probes_mysql.o dtrace_files dtrace_providers +DTRACEFILES = ha_myisammrg.o +DTRACEPROVIDER = probes_mysql.d +CLEANFILES += $(DTRACEPROVIDER) dtrace_sources + +dtrace_files: + echo $(DTRACEFILES) > $@ +dtrace_providers: probes_mysql.d + echo $(DTRACEPROVIDER) > $@ +probes_mysql.d: + -$(RM) -f probes_mysql.d + $(CP) $(top_srcdir)/include/probes_mysql.d.base probes_mysql.d + echo timestamp > dtrace_sources + +probes_mysql.o: $(DTRACEPROVIDER) $(DTRACEFILES) + $(DTRACE) $(DTRACEFLAGS) -G -s $(DTRACEPROVIDER) $(DTRACEFILES) -o $@ +endif === modified file 'storage/myisammrg/ha_myisammrg.cc' --- a/storage/myisammrg/ha_myisammrg.cc 2009-05-27 10:46:16 +0000 +++ b/storage/myisammrg/ha_myisammrg.cc 2009-07-02 14:23:36 +0000 @@ -91,6 +91,7 @@ #define MYSQL_SERVER 1 #include "mysql_priv.h" +#include "probes_mysql.h" #include #include #include "../myisam/ha_myisam.h" @@ -936,9 +937,11 @@ int ha_myisammrg::index_read_map(uchar * enum ha_rkey_function find_flag) { DBUG_ASSERT(this->file->children_attached); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_key_count); int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -947,9 +950,11 @@ int ha_myisammrg::index_read_idx_map(uch enum ha_rkey_function find_flag) { DBUG_ASSERT(this->file->children_attached); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_key_count); int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -957,46 +962,56 @@ int ha_myisammrg::index_read_last_map(uc key_part_map keypart_map) { DBUG_ASSERT(this->file->children_attached); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_key_count); int error=myrg_rkey(file,buf,active_index, key, keypart_map, HA_READ_PREFIX_LAST); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_myisammrg::index_next(uchar * buf) { DBUG_ASSERT(this->file->children_attached); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_next_count); int error=myrg_rnext(file,buf,active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_myisammrg::index_prev(uchar * buf) { DBUG_ASSERT(this->file->children_attached); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_prev_count); int error=myrg_rprev(file,buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_myisammrg::index_first(uchar * buf) { DBUG_ASSERT(this->file->children_attached); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_first_count); int error=myrg_rfirst(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } int ha_myisammrg::index_last(uchar * buf) { DBUG_ASSERT(this->file->children_attached); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_last_count); int error=myrg_rlast(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -1006,12 +1021,14 @@ int ha_myisammrg::index_next_same(uchar { int error; DBUG_ASSERT(this->file->children_attached); + MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str); ha_statistic_increment(&SSV::ha_read_next_count); do { error= myrg_rnext_same(file,buf); } while (error == HA_ERR_RECORD_DELETED); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_INDEX_READ_ROW_DONE(error); return error; } @@ -1026,9 +1043,12 @@ int ha_myisammrg::rnd_init(bool scan) int ha_myisammrg::rnd_next(uchar *buf) { DBUG_ASSERT(this->file->children_attached); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); ha_statistic_increment(&SSV::ha_read_rnd_next_count); int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_READ_ROW_DONE(error); return error; } @@ -1036,9 +1056,12 @@ int ha_myisammrg::rnd_next(uchar *buf) int ha_myisammrg::rnd_pos(uchar * buf, uchar *pos) { DBUG_ASSERT(this->file->children_attached); + MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str, + TRUE); ha_statistic_increment(&SSV::ha_read_rnd_count); int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length)); table->status=error ? STATUS_NOT_FOUND: 0; + MYSQL_READ_ROW_DONE(error); return error; } === modified file 'storage/ndb/include/portlib/prefetch.h' --- a/storage/ndb/include/portlib/prefetch.h 2006-12-23 19:20:40 +0000 +++ b/storage/ndb/include/portlib/prefetch.h 2009-01-28 21:17:20 +0000 @@ -43,7 +43,7 @@ inline void prefetch(void* p) __asm(" ldl r31,0(a0);", p); #endif /* NDB_ALPHA */ #ifdef NDB_FORTE6 - sparc_prefetch_read_once(p); + sun_prefetch_read_once(p); #else (void)p; #endif @@ -55,7 +55,7 @@ inline void writehint(void* p) __asm(" wh64 (a0);", p); #endif /* NDB_ALPHA */ #ifdef NDB_FORTE6 - sparc_prefetch_write_once(p); + sun_prefetch_write_once(p); #else (void)p; #endif === modified file 'support-files/Makefile.am' --- a/support-files/Makefile.am 2009-03-04 17:58:34 +0000 +++ b/support-files/Makefile.am 2009-07-02 14:23:36 +0000 @@ -33,7 +33,8 @@ EXTRA_DIST = mysql.spec.sh \ magic mysql.m4 \ MySQL-shared-compat.spec.sh \ ndb-config-2-node.ini.sh \ - compiler_warnings.supp + compiler_warnings.supp \ + dtrace SUBDIRS = MacOSX RHEL4-SElinux === added directory 'support-files/dtrace' === added file 'support-files/dtrace/locktime.d' --- a/support-files/dtrace/locktime.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/locktime.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,49 @@ +#!/usr/sbin/dtrace -s +# +# Shows the time that an individual lock is applied to a database and table +# Shows the time to achieve the lock, and the time the table was locked + +o#pragma D option quiet + +mysql*:::handler-rdlock-start +{ + self->rdlockstart = timestamp; + this->lockref = strjoin(copyinstr(arg0),strjoin("@",copyinstr(arg1))); + self->lockmap[this->lockref] = self->rdlockstart; + printf("Start: Lock->Read %s.%s\n",copyinstr(arg0),copyinstr(arg1)); +} + +mysql*:::handler-wrlock-start +{ + self->wrlockstart = timestamp; + this->lockref = strjoin(copyinstr(arg0),strjoin("@",copyinstr(arg1))); + self->lockmap[this->lockref] = self->rdlockstart; + printf("Start: Lock->Write %s.%s\n",copyinstr(arg0),copyinstr(arg1)); +} + +mysql*:::handler-unlock-start +{ + self->unlockstart = timestamp; + this->lockref = strjoin(copyinstr(arg0),strjoin("@",copyinstr(arg1))); + printf("Start: Lock->Unlock %s.%s (%d ms lock duration)\n", + copyinstr(arg0),copyinstr(arg1), + (timestamp - self->lockmap[this->lockref])/1000000); +} + +mysql*:::handler-rdlock-done +{ + printf("End: Lock->Read %d ms\n", + (timestamp - self->rdlockstart)/1000000); +} + +mysql*:::handler-wrlock-done +{ + printf("End: Lock->Write %d ms\n", + (timestamp - self->wrlockstart)/1000000); +} + +mysql*:::handler-unlock-done +{ + printf("End: Lock->Unlock %d ms\n", + (timestamp - self->unlockstart)/1000000); +} === added file 'support-files/dtrace/query-execandqc.d' --- a/support-files/dtrace/query-execandqc.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/query-execandqc.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,36 @@ +#!/usr/sbin/dtrace -s +# +# Show query execution times, indicating whether the query-cache was used + +#pragma D option quiet + +dtrace:::BEGIN +{ + printf("%-20s %-20s %-40s %2s %-9s\n", "Who", "Database", "Query", "QC", "Time(ms)"); +} + +mysql*:::query-start +{ + self->query = copyinstr(arg0); + self->connid = arg1; + self->db = copyinstr(arg2); + self->who = strjoin(copyinstr(arg3),strjoin("@",copyinstr(arg4))); + self->querystart = timestamp; + self->qc = 0; +} + +mysql*:::query-cache-hit +{ + self->qc = 1; +} + +mysql*:::query-cache-miss +{ + self->qc = 0; +} + +mysql*:::query-done +{ + printf("%-20s %-20s %-40s %-2s %-9d\n",self->who,self->db,self->query,(self->qc ? "Y" : "N"), + (timestamp - self->querystart) / 1000000); +} === added file 'support-files/dtrace/query-filesort-time.d' --- a/support-files/dtrace/query-filesort-time.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/query-filesort-time.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,47 @@ +#!/usr/sbin/dtrace -s +# +# Show the time taken for a query, including the time taken to +# sort the results using filesort + +#pragma D option quiet + +dtrace:::BEGIN +{ + printf("%-2s %-10s %-10s %9s %18s %-s \n", + "St", "Who", "DB", "ConnID", "Dur microsec", "Query"); +} + +mysql*:::query-start +{ + self->query = copyinstr(arg0); + self->who = strjoin(copyinstr(arg3),strjoin("@",copyinstr(arg4))); + self->db = copyinstr(arg2); + self->connid = arg1; + self->querystart = timestamp; + self->filesort = 0; + self->fsdb = ""; + self->fstable = ""; +} + +mysql*:::filesort-start +{ + self->filesort = timestamp; + self->fsdb = copyinstr(arg0); + self->fstable = copyinstr(arg1); +} + +mysql*:::filesort-done +{ + this->elapsed = (timestamp - self->filesort) /1000; + printf("%2d %-10s %-10s %9d %18d Filesort on %s\n", + arg0, self->who, self->fsdb, + self->connid, this->elapsed, self->fstable); +} + +mysql*:::query-done +{ + this->elapsed = (timestamp - self->querystart) /1000; + printf("%2d %-10s %-10s %9d %18d %s\n", + arg0, self->who, self->db, + self->connid, this->elapsed, self->query); +} === added file 'support-files/dtrace/query-network-time.d' --- a/support-files/dtrace/query-network-time.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/query-network-time.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,63 @@ +#!/usr/sbin/dtrace -s +# +# Show the time taken to execute a query, include the bytes and time taken +# to transfer the information over the network to/from the client + +#pragma D option quiet +#pragma D option dynvarsize=4m + +dtrace:::BEGIN +{ + printf("%-2s %-30s %-10s %9s %18s %-s \n", + "St", "Who", "DB", "ConnID", "Dur microsec", "Query"); +} + +mysql*:::query-start +{ + self->query = copyinstr(arg0); + self->who = strjoin(copyinstr(arg3),strjoin("@",copyinstr(arg4))); + self->db = copyinstr(arg2); + self->connid = arg1; + self->querystart = timestamp; + self->netwrite = 0; + self->netwritecum = 0; + self->netwritebase = 0; + self->netread = 0; + self->netreadcum = 0; + self->netreadbase = 0; +} + +mysql*:::net-write-start +{ + self->netwrite += arg0; + self->netwritebase = timestamp; +} + +mysql*:::net-write-done +{ + self->netwritecum += (timestamp - self->netwritebase); + self->netwritebase = 0; +} + +mysql*:::net-read-start +{ + self->netreadbase = timestamp; +} + +mysql*:::net-read-done +{ + self->netread += arg1; + self->netreadcum += (timestamp - self->netreadbase); + self->netreadbase = 0; +} + +mysql*:::query-done +{ + this->elapsed = (timestamp - self->querystart) /1000000; + printf("%2d %-30s %-10s %9d %18d %s\n", + arg0, self->who, self->db, + self->connid, this->elapsed, self->query); + printf("Net read: %d bytes (%d ms) write: %d bytes (%d ms)\n", + self->netread, (self->netreadcum/1000000), + self->netwrite, (self->netwritecum/1000000)); +} === added file 'support-files/dtrace/query-parse-time.d' --- a/support-files/dtrace/query-parse-time.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/query-parse-time.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,23 @@ +#!/usr/sbin/dtrace -s +# +# Shows time take to actually parse the query statement + +#pragma D option quiet + +mysql*:::query-parse-start +{ + self->parsestart = timestamp; + self->parsequery = copyinstr(arg0); +} + +mysql*:::query-parse-done +/arg0 == 0/ +{ + printf("Parsing %s: %d microseconds\n", self->parsequery,((timestamp - self->parsestart)/1000)); +} + +mysql*:::query-parse-done +/arg0 != 0/ +{ + printf("Error parsing %s: %d microseconds\n", self->parsequery,((timestamp - self->parsestart)/1000)); +} === added file 'support-files/dtrace/query-rowops.d' --- a/support-files/dtrace/query-rowops.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/query-rowops.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,66 @@ +#!/usr/sbin/dtrace -s +# +# Calculates the time (and operations) for accessing data from individual +# rows for each query + +#pragma D option quiet + +dtrace:::BEGIN +{ + printf("%-2s %-10s %-10s %9s %9s %-s \n", + "St", "Who", "DB", "ConnID", "Dur ms", "Query"); +} + +mysql*:::query-start +{ + self->query = copyinstr(arg0); + self->who = strjoin(copyinstr(arg3),strjoin("@",copyinstr(arg4))); + self->db = copyinstr(arg2); + self->connid = arg1; + self->querystart = timestamp; + self->rowdur = 0; +} + +mysql*:::query-done +{ + this->elapsed = (timestamp - self->querystart) /1000000; + printf("%2d %-10s %-10s %9d %9d %s\n", + arg0, self->who, self->db, + self->connid, this->elapsed, self->query); +} + +mysql*:::query-done +/ self->rowdur / +{ + printf("%34s %9d %s\n", "", (self->rowdur/1000000), "-> Row ops"); +} + +mysql*:::insert-row-start +{ + self->rowstart = timestamp; +} + +mysql*:::delete-row-start +{ + self->rowstart = timestamp; +} + +mysql*:::update-row-start +{ + self->rowstart = timestamp; +} + +mysql*:::insert-row-done +{ + self->rowdur += (timestamp-self->rowstart); +} + +mysql*:::delete-row-done +{ + self->rowdur += (timestamp-self->rowstart); +} + +mysql*:::update-row-done +{ + self->rowdur += (timestamp-self->rowstart); +} === added file 'support-files/dtrace/query-time.d' --- a/support-files/dtrace/query-time.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/query-time.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,25 @@ +#!/usr/sbin/dtrace -s +# +# Shows basic query execution time, who execute the query, and on what database + +#pragma D option quiet + +dtrace:::BEGIN +{ + printf("%-20s %-20s %-40s %-9s\n", "Who", "Database", "Query", "Time(ms)"); +} + +mysql*:::query-start +{ + self->query = copyinstr(arg0); + self->connid = arg1; + self->db = copyinstr(arg2); + self->who = strjoin(copyinstr(arg3),strjoin("@",copyinstr(arg4))); + self->querystart = timestamp; +} + +mysql*:::query-done +{ + printf("%-20s %-20s %-40s %-9d\n",self->who,self->db,self->query, + (timestamp - self->querystart) / 1000000); +} === added file 'support-files/dtrace/statement-time.d' --- a/support-files/dtrace/statement-time.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/statement-time.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,45 @@ +#!/usr/sbin/dtrace -s +# +# Creates a report on each query executed at the individual statement +# level, showing rows matched, updated, and total query time + +#pragma D option quiet + +dtrace:::BEGIN +{ + printf("%-60s %-8s %-8s %-8s\n", "Query", "RowsU", "RowsM", "Dur (ms)"); +} + +mysql*:::update-start, mysql*:::insert-start, +mysql*:::delete-start, mysql*:::multi-delete-start, +mysql*:::multi-delete-done, mysql*:::select-start, +mysql*:::insert-select-start, mysql*:::multi-update-start +{ + self->query = copyinstr(arg0); + self->querystart = timestamp; +} + +mysql*:::insert-done, mysql*:::select-done, +mysql*:::delete-done, mysql*:::multi-delete-done, mysql*:::insert-select-done +/ self->querystart / +{ + this->elapsed = ((timestamp - self->querystart)/1000000); + printf("%-60s %-8d %-8d %d\n", + self->query, + 0, + arg1, + this->elapsed); + self->querystart = 0; +} + +mysql*:::update-done, mysql*:::multi-update-done +/ self->querystart / +{ + this->elapsed = ((timestamp - self->querystart)/1000000); + printf("%-60s %-8d %-8d %d\n", + self->query, + arg1, + arg2, + this->elapsed); + self->querystart = 0; +} === added file 'support-files/dtrace/statement-type-aggregate.d' --- a/support-files/dtrace/statement-type-aggregate.d 1970-01-01 00:00:00 +0000 +++ b/support-files/dtrace/statement-type-aggregate.d 2009-03-06 12:31:03 +0000 @@ -0,0 +1,46 @@ +#!/usr/sbin/dtrace -s +# +# Creates an aggregate report of the time spent perform queries of the four main +# types (select, insert, update, delete) +# +# Report generated every 30s + +#pragma D option quiet + +dtrace:::BEGIN +{ + printf("Reporting...Control-C to stop\n"); +} + +mysql*:::update-start, mysql*:::insert-start, +mysql*:::delete-start, mysql*:::multi-delete-start, +mysql*:::multi-delete-done, mysql*:::select-start, +mysql*:::insert-select-start, mysql*:::multi-update-start +{ + self->querystart = timestamp; +} + +mysql*:::select-done +{ + @statements["select"] = sum(((timestamp - self->querystart)/1000000)); +} + +mysql*:::insert-done, mysql*:::insert-select-done +{ + @statements["insert"] = sum(((timestamp - self->querystart)/1000000)); +} + +mysql*:::update-done, mysql*:::multi-update-done +{ + @statements["update"] = sum(((timestamp - self->querystart)/1000000)); +} + +mysql*:::delete-done, mysql*:::multi-delete-done +{ + @statements["delete"] = sum(((timestamp - self->querystart)/1000000)); +} + +tick-30s +{ + printa(@statements); +} === modified file 'support-files/my-innodb-heavy-4G.cnf.sh' --- a/support-files/my-innodb-heavy-4G.cnf.sh 2009-05-07 20:48:24 +0000 +++ b/support-files/my-innodb-heavy-4G.cnf.sh 2009-07-02 14:23:36 +0000 @@ -385,9 +385,10 @@ innodb_data_file_path = ibdata1:10M:auto #innodb_data_home_dir = # Number of IO threads to use for async IO operations. This value is -# hardcoded to 4 on Unix, but on Windows disk I/O may benefit from a +# hardcoded to 8 on Unix, but on Windows disk I/O may benefit from a # larger number. -innodb_file_io_threads = 4 +innodb_write_io_threads = 8 +innodb_read_io_threads = 8 # If you run into InnoDB tablespace corruption, setting this to a nonzero # value will likely help you to dump your tables. Start from value 1 and === modified file 'win/README' --- a/win/README 2008-04-03 15:39:47 +0000 +++ b/win/README 2009-07-02 14:23:36 +0000 @@ -60,6 +60,7 @@ The options right now are: WITH_EXAMPLE_STORAGE_ENGINE WITH_FALCON_STORAGE_ENGINE WITH_FEDERATED_STORAGE_ENGINE + WITHOUT_ATOMICS Do not use atomic instructions MYSQL_SERVER_SUFFIX= Server suffix, default none COMPILATION_COMMENT= Server comment, default "Source distribution" MYSQL_TCP_PORT= Server port, default 3306 === modified file 'win/configure.js' --- a/win/configure.js 2009-05-25 22:01:59 +0000 +++ b/win/configure.js 2009-07-02 14:23:36 +0000 @@ -50,6 +50,9 @@ try configfile.WriteLine("SET (" + parts[0] + " \"" + parts[1] + "\")"); break; + case "WITHOUT_ATOMICS": + configfile.WriteLine("SET (" + args.Item(i) + " TRUE)"); + break; case "COMPILATION_COMMENT": default_comment = parts[1]; break; --===============3573626575237685878== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/guilhem@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: guilhem@stripped # target_branch: file:///home/mysql_src/bzrrepos/mysql-azalea-guilhem/ # testament_sha1: b294ce35fae4ef7d34cdb4534e2610afa4ba09d0 # timestamp: 2009-07-03 14:27:31 +0200 # source_branch: file:///home/mysql_src/bzrrepos/mysql-5.1-\ # performance-version/ # base_revision_id: alik@stripped # # Begin bundle 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 6KO33G48QSB5Yfmdpt/j+76h1Bq6dh6NL8pfC1re7b84F4bNEx9vknLM0LkkjrTlyO/16ePBAKei bfpwsXz79N7z9TsKDPpJifmkIWTg62FFyFhIcAenjo9DPtNh5Kc33xmKdXHH+rAr42U7xIgVF/Gx kj+1DfECSETiDjhnm4k0G/NQckNhN/6irQ3W/Ze6Wmb8axheZ5rx6T9x/k7f14fZnDiOH2Q7zanX PYdZuqglH/75lN81GcZE95KtX2XbTWlRVQUMMlN3tQun3H98obD7wgQW5oPAw/X93GdXeeXQeIiC H0X9MYRkEkAWApIsFkAUUBZBSLJFhFCLBRQBjIpFIjIKAjAWRiLBVAYrBiCsYERIjIqgiRRQWLIK CrESIkWAIyKAskVRZARAWSLIIgChFRBSBEVBRQWCyCMUigMRZZCEEYjIqgiLEQVQYwUFRWAxkEYj IiCKDFAWQWRiRYMggCyCKxYoCwFIoKjGJBVARARFiyRYKAoIMWKAjBQWAoIxYiIwRIiDFUSKqwWR jCMYoKoKQYggrIogyApAWLEGCxYqyCxIxGCkUVGCCKKMYsRBFYxARiMFBYoLFUWKCCAxBEYqqiis YwZFWREQYAqRIIgsIoRGQVGKAsiiigsgjBBjEUFIsiIMRQRFBBihEVJGCRAZJEYsURkQQWLEVWCy IoCAjAVZFkUBIyJGSKRSKCiRAURWKAsigIwFUVEBZFYwUYwiCRGRjFFkUBVFgiQUJBQRkRWRQQZB RSIxREgggjJGRgqkijGAKIgsiwFIwYKRYKCxRGLIoEQYAioCRkVYopBkYRSRGAopBRVGRCDIhESA ijAESAsIIDIIySLFgIxGACIRGALFBSQFhFgLCMgwikIsAUWQSJAgkSQgjAFgAgpGCkUkEYRBkiJA QGQYkjEIsWAsBiRGRGSKIiqIIRGQGRIoChEiRYKCihBEIsIsFkWKoiSCMBRZIsFkgsRgsgiQWKRV gsGMFiDAYICyMEBWJFgsWMYoL/c14j+j3lrBidDKVKVlMJQZFS2BPNJDA0ePHx8sPo192HJ2InSQ xIAxhFkgoCIGd/yoImYggSIosggivo4vL+St+ABQ+01Hn6v5YUf3Iz/DvkOZji1ox61Br928t3rX bmkYNvaGcAYbMVpV3m8zQhsq3sRTqch8yIG1OHSpmbUVma9ONrAWuxZhZLQmbZGPrEvGkbDe0rm3 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 +vosPf3xwSws4uF54H3aEXKVfdbT0OcWyz0WFl5sTkBJCwZQFi1zQnPLvYaCzuCl9Zr2sTWSiLBe aM2qNKIvtqzoXsq4Wl6RVC67BKL6WubzVovM5Q20V10a1YIyv92MSs2TYow+XlZNFE191tGHysxX uGrQgnr96vZAY+w0N60KBA+BI9ifo96mYkUP1RlUqYKKNVmVPkwyYMHLRyZVUwqrzpyteDgjwfQa CWvrtIv5hSII8DiRQAwUNwIGihay9yrwUeGPfCtWBZc8sCOaUpo76OFDWUUpNnBq1eGEx11pbTxz ZeVxT02XjGlWblYrlxaWw4ra7dVX2q6UMGTyU7Xu1xc0bvJZV0xWXO/a90yMjouUem7VYOBioMFQ VDh5W3grnILL1bV02jByER1RDVr1VgVfIaQWJrLhBCqQRavks7xXjrfihV5fEFGPhureFG8wOBvF GGL4AJGIDjM3DxlwVsurHa9KzFkrnr55aLjM6ZO12rSla48aWx8Le/Dmj2Ll+Cx8NLPqo/APZtmG hAfA+g4wS2a4rstsLigpypNt+Xlq4dOsm22nvfuwoi94W3cyVXbYLXOOMTVftnU1pnvJSuzZstoU kZ2/yIHseeTzU4+UAvkL7GosdBA7Bc1nIgeho8w0V0z0H1BxBTgPgdzZ4HfnvuXEuBQtohNbzmEC hXFVt4xsDxCYihYkkRFKg8TUUMcdJdyU0VVcNVV7KOVMXldPClzhZ6ZPDy2emDBVe4cUXuuqsWjZ kzZumbN7v4zeHUSIGsnlGdFypH5zxSeaRwxdvC/Dpqs9MHuxXsV7h6Wemq9V7Nn4FmzmZOFnLhQz Zt1HbJwuWcnLJY1X6Upk1bmzB7+/lg3YOX4kzaLKGeeTF6auWTVZZ26S9w2XM3pM17tsqbNF7I2e fBTJg1aNCjrrpi1dwJPicn/CT8dw1Seb/PvY6dNjZZ7MXKqq9oytTO1dNXffs1ZsCrBMi9w8Ji9O lHCzdqzXsWrffle6YKsGyzMRe0cN2DZVeYqqM2TJRZ0YuHs7Zs3bAzcuWzJg1c4Upiud95N3RRg2 UWVbuFzLLZm0dqtHDpw1cN1VGhgXNHZoybt1zSbtXDpmuWS8s2foj8zlM0j+UnQ+j4J48Ji8eLnp k0LWVbpXlTM9OnZmq8s3pmmTffF7tE0e6jZ7quy5so2OlnLJ0qccZNGbF0my92udLlXTty6YOHLy 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 o4XL3Z4ZuVXlieV7dwYkucvJi6cLKqtl68o/KSYt3Ki5w2cMyq5gvXs2LUyYvPnByvUaL771xmxX 38t2Dy0UatF7Nc8LjYxfYjlo331XPLdgmjVll22aPnwzZP8x/oF5PPfvh5pTPxoo557ezl2wNtNa bb2v3vaMmjtkqqxYvZy2ZMWSqqjdu1Zrmjlys8smSap+pU6ZsVHc5YuVr2bdkZcqezw1aOHhc4ZL 3hcvWcMBZMTFis3N2CpgwbtTRVu1WePGDlRixR0tMkpkoq3VHU3U3VVcs2++pWvh8J+zhIxOuvPV 0ovbOFmKjDGtu3Ty8qtGZZk8vKrZ+yMGDJ7MWbNqXNnr12zask3cKPCaKmz2ZMmSzwxWYnhe5UbK OVWpqwZv/dO1mDVkmTFRm0et1VczFgo3cGDJs0MVGjB5ZqvPnNmtblkxYOWzVZmo1ds71Gzpk338 uGCjp03cLm7hwvjgx0J7oy47KbMmzd27asXgs0xXFlVHLlw0YLlnLQyaMmLQwUYGRq0NVmjNg3zU uNVHTRoybsHLJo0LyxivXGZZmYKM2bJc5bs2q9q3NjBVKLiq5wo1XqLmzFg2NJnOkTLsPMJv/5Yd 6Hda3pgRCMA8FXzIQkMqSJI+ScPNDtw9OnwsVYYPZ6enuVZPk+S5m+TdVNnCjZcycG7gwPhoxfX6 9LKL27A9yNcFyjBqbOWDNmoyWUeG5mxXKslWDRgweGLJcuTtKOkubN2T8d2RsxaqMjZe90mjRgmz Q2en/70YNTkzau2a5ewVezzP6H6M/0/GTdcMBjgZqvZ6bPL+IYMOXLIucRJZiwVejQ93hVQ3Pkw9 ymTNy+n0qwegwYtVGZsbMWy9ybqL3T4eGrNcuXOGK5o3XMmrMzXrL2a8yO2r2Tx4wZsHbtcyY48O WZkqZO3blc5bNde1nbBk7XPk2e5/CcF6YvDRwq8rz7D5+5jRofetImysuzrb6LxayrBdb7dYXYJK wvUkwfnZYCykCXqCQpokWQkZUwqQZHEbmgXzif3e9e0U6u8U2i3/rEh7wGepCeAnYLtB3KG1/mTd yyiPeP/P+D8X4PyPTysZzP8T8ihi+77qma95ZrNX7M1Gyr9mpm9l69onCz/NJOSrpLn7/veY+F7I Nna5g6aNnhoqaOWTh94ElWSYvfJm1TNs9N3ly1Xslyh6On9Gv5RKbNWjBu91H2k/JQqyeybO1GTR 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