List:Commits« Previous MessageNext Message »
From:Rafal Somla Date:March 20 2008 10:19am
Subject:Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259
View as plain text  
Hi Ingo,

I have read your patch. In general it looks OK but see my comments and questions 
below.

Rafal

Ingo Struewing wrote:
> Below is the list of changes that have just been committed into a local
> 6.0 repository of istruewing.  When istruewing does a push these changes
> will be propagated to the main repository and, within 24 hours after the
> push, to the public repository.
> For information on how to access the public repository
> see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
> 
> ChangeSet@stripped, 2008-03-11 18:54:28+01:00, istruewing@stripped +32 -0
>   WL#4259 - Debug Sync Facility
>   
>   The Debug Sync Facility allows to place synchronization points
>   in the code:
>   
>   open_tables(...)
>   
>   DEBUG_SYNC(thd, "after_open_tables");
>   
>   lock_tables(...)
>   
>   When activated, a sync point can
>   
>   - Send a signal and/or
>   - Wait for a signal
>   
>   Nomenclature:
>   
>   - signal:            A value of a global variable that persists
>                        until overwritten by a new signal. The global
>                        variable can also be seen as a "signal post"
>                        or "flag mast". Then the signal is what is
>                        attached to the "signal post" or "flag mast".
>   
>   - send a signal:     Assign the value (the signal) to the global
>                        variable ("set a flag") and broadcast a
>                        global condition to wake those waiting for
>                        a signal.
>   
>   - wait for a signal: Loop over waiting for the global condition until
>                        the global value matches the wait-for signal.
>   
>   Please find more information in the top comment in debug_sync.cc
>   or in the worklog entry.
>   
>   Included are modified MERGE table tests. They can be seen as
>   examples for the use of the facility. The merge-big test case is
>   removed. The contained test is moved to the new merge-sync test.
> 
>   BitKeeper/deleted/.del-merge-big.result@stripped, 2008-03-07 19:56:25+01:00,
> istruewing@stripped +0 -0
>     Delete: mysql-test/r/merge-big.result
> 
>   BitKeeper/deleted/.del-merge-big.test@stripped, 2008-03-07 19:56:33+01:00,
> istruewing@stripped +0 -0
>     Delete: mysql-test/t/merge-big.test
> 
>   BitKeeper/etc/ignore@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +1
> -0
>     WL#4259 - Debug Sync Facility
>     Added libmysqld/debug_sync.cc
> 
>   configure.in@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +17 -0
>     WL#4259 - Debug Sync Facility
>     Added configure option --enable-debug-sync.
> 
>   libmysqld/CMakeLists.txt@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped
> +1 -0
>     WL#4259 - Debug Sync Facility
>     Include debug_sync.cc
> 
>   libmysqld/Makefile.am@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +1
> -0
>     WL#4259 - Debug Sync Facility
>     Include debug_sync.cc
> 
>   mysql-test/include/have_debug_sync.inc@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +5 -0
>     WL#4259 - Debug Sync Facility
>     New file. Test for "have_debug_sync".
>     
> 
>   mysql-test/include/have_debug_sync.inc@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +0 -0
> 
>   mysql-test/mysql-test-run.pl@stripped, 2008-03-11 18:54:23+01:00,
> istruewing@stripped +8 -0
>     WL#4259 - Debug Sync Facility
>     Added code for enabling/disabling of the facility.
> 
>   mysql-test/r/debug_sync.result@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +239 -0
>     WL#4259 - Debug Sync Facility
>     New file. The new test result.
>     
> 
>   mysql-test/r/debug_sync.result@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +0 -0
> 
>   mysql-test/r/have_debug_sync.require@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +2 -0
>     WL#4259 - Debug Sync Facility
>     New file. Result for "have_debug_sync".
>     
> 
>   mysql-test/r/have_debug_sync.require@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +0 -0
> 
>   mysql-test/r/merge-sync.result@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +151 -0
>     WL#4259 - Debug Sync Facility
>     New example test result.
> 
>   mysql-test/r/merge-sync.result@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +0 -0
> 
>   mysql-test/r/merge.result@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped
> +4 -111
>     WL#4259 - Debug Sync Facility
>     Fixed the example test result.
> 
>   mysql-test/t/debug_sync.test@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +361 -0
>     WL#4259 - Debug Sync Facility
>     New file. A new test case to test the facility itself.
>     
> 
>   mysql-test/t/debug_sync.test@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +0 -0
> 
>   mysql-test/t/merge-sync.test@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +384 -0
>     WL#4259 - Debug Sync Facility
>     New file. Tests that utilize the new facility.
> 
>   mysql-test/t/merge-sync.test@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +0 -0
> 
>   mysql-test/t/merge.test@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +6
> -156
>     WL#4259 - Debug Sync Facility
>     Removed tests that need the the new facility.
> 
>   mysys/thr_lock.c@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +17 -0
>     WL#4259 - Debug Sync Facility
>     Added a synchronization point hook.
> 
>   sql/CMakeLists.txt@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +1 -0
>     WL#4259 - Debug Sync Facility
>     Include debug_sync.cc
> 
>   sql/Makefile.am@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +1 -0
>     WL#4259 - Debug Sync Facility
>     Include debug_sync.cc
> 
>   sql/debug_sync.cc@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +1527 -0
>     WL#4259 - Debug Sync Facility
>     New file. Implementation of the facility.
>     
> 
>   sql/debug_sync.cc@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +0 -0
> 
>   sql/item_func.cc@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +2 -0
>     WL#4259 - Debug Sync Facility
>     Added a synchronization point.
> 
>   sql/lock.cc@stripped, 2008-03-11 18:54:23+01:00, istruewing@stripped +2 -0
>     WL#4259 - Debug Sync Facility
>     Added synchronization points.
> 
>   sql/mysql_priv.h@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +21 -0
>     WL#4259 - Debug Sync Facility
>     Added declarations for the facility.
> 
>   sql/mysqld.cc@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +44 -1
>     WL#4259 - Debug Sync Facility
>     Added initialization/termination of the facility for the server.
>     Added option "debug-sync".
>     Added system variable "have_debug_sync".
> 
>   sql/set_var.cc@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +6 -0
>     WL#4259 - Debug Sync Facility
>     Added definition of the 'debug_sync' system variable.
>     Added system variable "have_debug_sync".
> 
>   sql/set_var.h@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +15 -0
>     WL#4259 - Debug Sync Facility
>     Added declaration for the 'debug_sync' system variable.
> 
>   sql/share/errmsg.txt@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +8
> -0
>     WL#4259 - Debug Sync Facility
>     Added new error messages.
> 
>   sql/sql_base.cc@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +6 -7
>     WL#4259 - Debug Sync Facility
>     Added synchronization points.
>     Removed old "Debug Sleep" synchronization point, which was used
>     in merge-big.test only.
> 
>   sql/sql_class.cc@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +14 -0
>     WL#4259 - Debug Sync Facility
>     Added initialization/termination of the facility for THD.
> 
>   sql/sql_class.h@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +5 -0
>     WL#4259 - Debug Sync Facility
>     Added the new THD element debug_sync_control.
> 
>   sql/sql_parse.cc@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +1 -0
>     WL#4259 - Debug Sync Facility
>     Added a synchronization point.
> 
>   sql/sql_table.cc@stripped, 2008-03-11 18:54:24+01:00, istruewing@stripped +1 -0
>     WL#4259 - Debug Sync Facility
>     Added a synchronization point.
> 
>   storage/myisammrg/ha_myisammrg.cc@stripped, 2008-03-11 18:54:24+01:00,
> istruewing@stripped +4 -0
>     WL#4259 - Debug Sync Facility
>     Added synchronization points.
> 
> diff -Nrup a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore
> --- a/BitKeeper/etc/ignore	2008-01-25 18:40:41 +01:00
> +++ b/BitKeeper/etc/ignore	2008-03-11 18:54:23 +01:00
> @@ -3027,3 +3027,4 @@ win/vs8cache.txt
>  ylwrap
>  zlib/*.ds?
>  zlib/*.vcproj
> +libmysqld/debug_sync.cc
====================================================================================
> diff -Nrup a/configure.in b/configure.in
> --- a/configure.in	2008-02-15 22:27:06 +01:00
> +++ b/configure.in	2008-03-11 18:54:23 +01:00
> @@ -1701,6 +1701,23 @@ else
>    CXXFLAGS="$OPTIMIZE_CXXFLAGS $CXXFLAGS"
>  fi
>  
> +# Debug Sync Facility. NOTE: depends on 'with_debug'. Must be behind it.
> +AC_MSG_CHECKING(if Debug Sync Facility should be enabled.)
> +AC_ARG_ENABLE(debug_sync,
> +              AS_HELP_STRING([--enable-debug-sync],
> +                             [Build a version with Debug Sync Facility]),
> +              [ enable_debug_sync=$enableval ],
> +              [ enable_debug_sync=$with_debug ])
> +
> +if test "$enable_debug_sync" != "no"
> +then
> +  AC_DEFINE([ENABLED_DEBUG_SYNC], [1],
> +            [If Debug Sync Facility should be enabled])
> +  AC_MSG_RESULT([yes]) 
> +else
> +  AC_MSG_RESULT([no])
> +fi
> +
>  # If we should allow error injection tests
>  AC_ARG_WITH(error-inject,
>      AC_HELP_STRING([--with-error-inject],[Enable error injection in MySQL Server]),
====================================================================================
> diff -Nrup a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
> --- a/libmysqld/CMakeLists.txt	2007-12-13 13:47:11 +01:00
> +++ b/libmysqld/CMakeLists.txt	2008-03-11 18:54:23 +01:00
> @@ -178,6 +178,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libm
>             ../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc 
>             ../sql/sql_binlog.cc ../sql/sql_manager.cc ../sql/sql_map.cc 
>             ../sql/sql_parse.cc ../sql/sql_partition.cc ../sql/sql_plugin.cc 
> +           ../sql/debug_sync.cc
>             ../sql/sql_prepare.cc ../sql/sql_rename.cc ../sql/sql_repl.cc 
>             ../sql/sql_select.cc ../sql/sql_servers.cc
>             ../sql/sql_show.cc ../sql/sql_state.c ../sql/sql_string.cc
====================================================================================
> diff -Nrup a/libmysqld/Makefile.am b/libmysqld/Makefile.am
> --- a/libmysqld/Makefile.am	2007-12-19 14:34:58 +01:00
> +++ b/libmysqld/Makefile.am	2008-03-11 18:54:23 +01:00
> @@ -78,6 +78,7 @@ sqlsources = derror.cc field.cc field_co
>  	event_scheduler.cc events.cc event_data_objects.cc \
>          event_queue.cc event_db_repository.cc \
>  	rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
> +	debug_sync.cc \
>  	sql_tablespace.cc \
>  	rpl_injector.cc my_user.c partition_info.cc \
>  	sql_servers.cc
====================================================================================
> diff -Nrup a/mysql-test/include/have_debug_sync.inc
> b/mysql-test/include/have_debug_sync.inc
> --- /dev/null	Wed Dec 31 16:00:00 196900
> +++ b/mysql-test/include/have_debug_sync.inc	2008-03-11 18:54:24 +01:00
> @@ -0,0 +1,5 @@
> +--require r/have_debug_sync.require
> +disable_query_log;
> +let $value= query_get_value(SHOW VARIABLES LIKE 'debug_sync', Value, 1);
> +eval SELECT ('$value' LIKE 'ON %') AS debug_sync;
> +enable_query_log;
====================================================================================
> diff -Nrup a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
> --- a/mysql-test/mysql-test-run.pl	2008-02-11 18:19:05 +01:00
> +++ b/mysql-test/mysql-test-run.pl	2008-03-11 18:54:23 +01:00
> @@ -268,6 +268,7 @@ my @default_valgrind_args= ("--show-reac
>  my @valgrind_args;
>  my $opt_valgrind_path;
>  my $opt_callgrind;
> +my $opt_debug_sync_timeout= 300; # Default timeout for WAIT_FOR actions.
>  
>  our $opt_stress=               "";
>  our $opt_stress_suite=     "main";
> @@ -617,6 +618,7 @@ sub command_line_setup () {
>               'valgrind-option=s'        => \@valgrind_args,
>               'valgrind-path=s'          => \$opt_valgrind_path,
>  	     'callgrind'                => \$opt_callgrind,
> +	     'debug-sync-timeout=i'     => \$opt_debug_sync_timeout,
>  
>               # Stress testing 
>               'stress'                   => \$opt_stress,
> @@ -3590,6 +3592,10 @@ sub mysqld_arguments ($$$$) {
>    # see BUG#28359
>    mtr_add_arg($args, "%s--connect-timeout=60", $prefix);
>  
> +  # Enable the debug sync facility, set default wait timeout.
> +  # Facility stays disabled if timeout value is zero.
> +  mtr_add_arg($args, "%s--loose-debug-sync-timeout=%s", $prefix,
> +              $opt_debug_sync_timeout);
>  
>    # When mysqld is run by a root user(euid is 0), it will fail
>    # to start unless we specify what user to run as. If not running
> @@ -5024,6 +5030,8 @@ Options for coverage, profiling etc
>                          can be specified more then once
>    valgrind-path=[EXE]   Path to the valgrind executable
>    callgrind             Instruct valgrind to use callgrind
> +  debug-sync-timeout=NUM  Set default timeout for WAIT_FOR debug sync
> +                        actions. Disable facility with NUM=0.
>  
>  Misc options
>  
====================================================================================
> diff -Nrup a/mysql-test/r/debug_sync.result b/mysql-test/r/debug_sync.result
> --- /dev/null	Wed Dec 31 16:00:00 196900
> +++ b/mysql-test/r/debug_sync.result	2008-03-11 18:54:24 +01:00
> @@ -0,0 +1,239 @@
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE IF EXISTS t1;
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: ''
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6           HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2           EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2           EXECUTE 2';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2                     HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2';
> +SET DEBUG_SYNC='p0 SIGNAL s1                       EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1                       EXECUTE 2';
> +SET DEBUG_SYNC='p0 SIGNAL s1                                 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6 EXECUTE 2';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6           HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2           EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2           EXECUTE 2';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2                     HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2';
> +SET DEBUG_SYNC='p0                                           HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 CLEAR';
> +SET DEBUG_SYNC='p0 TEST';
> +SET DEBUG_SYNC='RESET';
> +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2 hit_limit 3';
> +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2';
> +set debug_sync='p0 signal s1 wait_for s2 timeout 6           hit_limit 3';
> +set debug_sync='p0 signal s1 wait_for s2 timeout 6';
> +set debug_sync='p0 signal s1 wait_for s2           execute 2 hit_limit 3';
> +set debug_sync='p0 signal s1 wait_for s2           execute 2';
> +set debug_sync='p0 signal s1 wait_for s2                     hit_limit 3';
> +set debug_sync='p0 signal s1 wait_for s2';
> +set debug_sync='p0 signal s1                       execute 2 hit_limit 3';
> +set debug_sync='p0 signal s1                       execute 2';
> +set debug_sync='p0 signal s1                                 hit_limit 3';
> +set debug_sync='p0 signal s1';
> +set debug_sync='p0           wait_for s2 timeout 6 execute 2 hit_limit 3';
> +set debug_sync='p0           wait_for s2 timeout 6 execute 2';
> +set debug_sync='p0           wait_for s2 timeout 6           hit_limit 3';
> +set debug_sync='p0           wait_for s2 timeout 6';
> +set debug_sync='p0           wait_for s2           execute 2 hit_limit 3';
> +set debug_sync='p0           wait_for s2           execute 2';
> +set debug_sync='p0           wait_for s2                     hit_limit 3';
> +set debug_sync='p0           wait_for s2';
> +set debug_sync='p0                                           hit_limit 3';
> +set debug_sync='p0 clear';
> +set debug_sync='p0 test';
> +set debug_sync='reset';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6
> +                EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0';
> +ERROR 42000: Missing action after synchronization point name 'p0'
> +SET DEBUG_SYNC='p0                                          EXECUTE 2';
> +ERROR 42000: Missing action before EXECUTE
> +SET DEBUG_SYNC='p0                                TIMEOUT 6 EXECUTE 2';
> +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT'
> +SET DEBUG_SYNC='p0                                TIMEOUT 6';
> +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT'
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1';
> +ERROR 42000: Illegal or out of order stuff: 'SIGNAL'
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1           EXECUTE 2';
> +ERROR 42000: Illegal or out of order stuff: 'SIGNAL'
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6 EXECUTE 2';
> +ERROR 42000: Illegal or out of order stuff: 'SIGNAL'
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6';
> +ERROR 42000: Illegal or out of order stuff: 'SIGNAL'
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1 EXECUTE 2';
> +ERROR 42000: Illegal or out of order stuff: 'SIGNAL'
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1';
> +ERROR 42000: Illegal or out of order stuff: 'SIGNAL'
> +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2 EXECUTE 2';
> +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT'
> +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2';
> +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT'
> +SET DEBUG_SYNC='p0                  SIGNAL s1 TIMEOUT 6 EXECUTE 2';
> +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT'
> +SET DEBUG_SYNC='p0                  SIGNAL s1 TIMEOUT 6';
> +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT'
> +SET DEBUG_SYNC='p0 EXECUTE 2 SIGNAL s1 TIMEOUT 6';
> +ERROR 42000: Missing action before EXECUTE
> +SET DEBUG_SYNC='p0 TIMEOUT 6 SIGNAL s1';
> +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT'
> +SET DEBUG_SYNC='p0 EXECUTE 2 TIMEOUT 6 SIGNAL s1';
> +ERROR 42000: Missing action before EXECUTE
> +SET DEBUG_SYNC='p0 CLEAR HIT_LIMIT 3';
> +ERROR 42000: Nothing must follow action CLEAR
> +SET DEBUG_SYNC='CLEAR';
> +ERROR 42000: Missing action after synchronization point name 'CLEAR'
> +SET DEBUG_SYNC='p0 CLEAR p0';
> +ERROR 42000: Nothing must follow action CLEAR
> +SET DEBUG_SYNC='TEST';
> +ERROR 42000: Missing action after synchronization point name 'TEST'
> +SET DEBUG_SYNC='p0 TEST p0';
> +ERROR 42000: Nothing must follow action TEST
> +SET DEBUG_SYNC='p0 RESET';
> +ERROR 42000: Illegal or out of order stuff: 'RESET'
> +SET DEBUG_SYNC='RESET p0';
> +ERROR 42000: Illegal or out of order stuff: 'p0'
> +SET DEBUG_SYNC='p0 RESET p0';
> +ERROR 42000: Illegal or out of order stuff: 'RESET'
> +SET DEBUG_SYNCx='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +ERROR HY000: Unknown system variable 'DEBUG_SYNCx'
> +SET DEBUG_SYNC='p0 SIGNAx s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +ERROR 42000: Illegal or out of order stuff: 'SIGNAx'
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOx s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +ERROR 42000: Illegal or out of order stuff: 'WAIT_FOx'
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUx 0 EXECUTE 2 HIT_LIMIT 3';
> +ERROR 42000: Illegal or out of order stuff: 'TIMEOUx'
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTx 2 HIT_LIMIT 3';
> +ERROR 42000: Illegal or out of order stuff: 'EXECUTx'
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIx 3';
> +ERROR 42000: Illegal or out of order stuff: 'HIT_LIMIx'
> +SET DEBUG_SYNC='p0 CLEARx';
> +ERROR 42000: Illegal or out of order stuff: 'CLEARx'
> +SET DEBUG_SYNC='p0 TESTx';
> +ERROR 42000: Illegal or out of order stuff: 'TESTx'
> +SET DEBUG_SYNC='RESETx';
> +ERROR 42000: Missing action after synchronization point name 'RESETx'
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 0x6 EXECUTE 2 HIT_LIMIT 3';
> +ERROR 42000: Missing valid number after TIMEOUT
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 0x2 HIT_LIMIT 3';
> +ERROR 42000: Missing valid number after EXECUTE
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 7 EXECUTE 2 HIT_LIMIT 0x3';
> +ERROR 42000: Missing valid number after HIT_LIMIT
> +SET DEBUG_SYNC= 7;
> +ERROR 42000: Incorrect argument type to variable 'debug_sync'
> +SET GLOBAL DEBUG_SYNC= 'p0 CLEAR';
> +ERROR HY000: 'SESSION.debug_sync' is not global variable
> +SET DEBUG_SYNC= 'now SIGNAL something';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 'something'
> +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
> +Warnings:
> +Warning	1662	debug sync point wait timed out
> +SET DEBUG_SYNC= 'now SIGNAL nothing';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 'nothing'
> +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
> +SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 'nothing'
> +SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0';
> +SET DEBUG_SYNC= 'now HIT_LIMIT 1';
> +ERROR HY000: debug sync point hit limit reached
> +SET DEBUG_SYNC= 'RESET';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: ''
> +SET DEBUG_SYNC= 'p1abcd   SIGNAL s1 EXECUTE 2';
> +SET DEBUG_SYNC= 'p2abc    SIGNAL s2 EXECUTE 2';
> +SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2';
> +SET DEBUG_SYNC= 'p4a      SIGNAL s4 EXECUTE 2';
> +SET DEBUG_SYNC= 'p5abcde  SIGNAL s5 EXECUTE 2';
> +SET DEBUG_SYNC= 'p6ab     SIGNAL s6 EXECUTE 2';
> +SET DEBUG_SYNC= 'p7       SIGNAL s7 EXECUTE 2';
> +SET DEBUG_SYNC= 'p8abcdef SIGNAL s8 EXECUTE 2';
> +SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2';
> +SET DEBUG_SYNC= 'p4a      TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 's4'
> +SET DEBUG_SYNC= 'p1abcd   TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 's1'
> +SET DEBUG_SYNC= 'p7       TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 's7'
> +SET DEBUG_SYNC= 'p9abcdef TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 's9'
> +SET DEBUG_SYNC= 'p3abcdef TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 's3'
> +SET DEBUG_SYNC= 'p1abcd   CLEAR';
> +SET DEBUG_SYNC= 'p2abc    CLEAR';
> +SET DEBUG_SYNC= 'p5abcde  CLEAR';
> +SET DEBUG_SYNC= 'p6ab     CLEAR';
> +SET DEBUG_SYNC= 'p8abcdef CLEAR';
> +SET DEBUG_SYNC= 'p9abcdef CLEAR';
> +SET DEBUG_SYNC= 'p3abcdef CLEAR';
> +SET DEBUG_SYNC= 'p4a      CLEAR';
> +SET DEBUG_SYNC= 'p7       CLEAR';
> +SET DEBUG_SYNC= 'p1abcd   TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 's3'
> +SET DEBUG_SYNC= 'p7       TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 's3'
> +SET DEBUG_SYNC= 'p9abcdef TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: 's3'
> +SET DEBUG_SYNC= 'RESET';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +Variable_name	Value
> +debug_sync	ON - current signal: ''
> +CREATE USER mysqltest_1@localhost;
> +GRANT SUPER ON *.* TO mysqltest_1@localhost;
> +connection con1, mysqltest_1
> +SET DEBUG_SYNC= 'RESET';
> +connection default
> +DROP USER mysqltest_1@localhost;
> +CREATE USER mysqltest_2@localhost;
> +GRANT ALL ON *.* TO mysqltest_2@localhost;
> +REVOKE SUPER ON *.* FROM mysqltest_2@localhost;
> +connection con1, mysqltest_2
> +SET DEBUG_SYNC= 'RESET';
> +ERROR 42000: Access denied; you need the SUPER privilege for this operation
> +connection default
> +DROP USER mysqltest_2@localhost;
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE IF EXISTS t1;
> +CREATE TABLE t1 (c1 INT);
> +connection con1
> +SET DEBUG_SYNC= 'before_lock_tables_takes_lock
> +      SIGNAL opened WAIT_FOR flushed';
> +INSERT INTO t1 VALUES(1);
> +connection default
> +SET DEBUG_SYNC= 'now WAIT_FOR opened';
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
> +FLUSH TABLE t1;
> +connection con1
> +connection default
> +DROP TABLE t1;
> +SET DEBUG_SYNC= 'RESET';
====================================================================================
> diff -Nrup a/mysql-test/r/have_debug_sync.require
> b/mysql-test/r/have_debug_sync.require
> --- /dev/null	Wed Dec 31 16:00:00 196900
> +++ b/mysql-test/r/have_debug_sync.require	2008-03-11 18:54:24 +01:00
> @@ -0,0 +1,2 @@
> +debug_sync
> +1
====================================================================================
> diff -Nrup a/mysql-test/r/merge-big.result b/mysql-test/r/merge-big.result
> --- a/mysql-test/r/merge-big.result	2008-02-07 12:04:18 +01:00
> +++ /dev/null	Wed Dec 31 16:00:00 196900
> @@ -1,26 +0,0 @@
> -drop table if exists t1,t2,t3,t4,t5,t6;
> -#
> -# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
> -#             corrupts a MERGE table
> -# Problem #3
> -#
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -LOCK TABLE t1 WRITE;
> -# connection con1
> -SET SESSION debug="+d,sleep_open_and_lock_after_open";
> -INSERT INTO t1 VALUES (1);
> -# connection default
> -# Let INSERT go into thr_multi_lock().
> -# Kick INSERT out of thr_multi_lock().
> -FLUSH TABLES;
> -# Let INSERT go through open_tables() where it sleeps.
> -# Unlock and close table and wait for con1 to close too.
> -FLUSH TABLES;
> -# This should give no result.
> -SELECT * FROM t1;
> -c1
> -UNLOCK TABLES;
> -# connection con1
> -SET SESSION debug="-d,sleep_open_and_lock_after_open";
> -# connection default
> -DROP TABLE t1;
====================================================================================
> diff -Nrup a/mysql-test/r/merge-sync.result b/mysql-test/r/merge-sync.result
> --- /dev/null	Wed Dec 31 16:00:00 196900
> +++ b/mysql-test/r/merge-sync.result	2008-03-11 18:54:24 +01:00
> @@ -0,0 +1,151 @@
> +SET DEBUG_SYNC= 'RESET';
> +drop table if exists t1,t2,t3,t4,t5,t6;
> +drop database if exists mysqltest;
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
> +connection con1
> +SET DEBUG_SYNC= 'after_admin_flush
> +                     SIGNAL admin_flush WAIT_FOR end_repair';
> +REPAIR TABLE t1;
> +connection default;
> +SET DEBUG_SYNC= 'now WAIT_FOR admin_flush';
> +SET DEBUG_SYNC= 'mysql_lock_retry HIT_LIMIT 3';
> +SET DEBUG_SYNC= 'before_open_table_wait_refresh SIGNAL end_repair';
> +INSERT INTO t2 VALUES (1);
> +SET DEBUG_SYNC= 'now SIGNAL end_repair';
> +connection con1
> +Table	Op	Msg_type	Msg_text
> +test.t1	repair	status	OK
> +connection default;
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1, t2;
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
> +LOCK TABLE t1 WRITE;
> +REPAIR TABLE t1;
> +Table	Op	Msg_type	Msg_text
> +test.t1	repair	status	OK
> +connection con1
> +SET DEBUG_SYNC= 'mysql_lock_retry HIT_LIMIT 3';
> +SET DEBUG_SYNC= 'after_insert SIGNAL end_repair';
> +SET DEBUG_SYNC= 'before_open_table_wait_refresh SIGNAL end_repair';
> +INSERT INTO t2 VALUES (1);
> +connection default;
> +SET DEBUG_SYNC= 'now WAIT_FOR end_repair';
> +UNLOCK TABLES;
> +connection con1
> +connection default;
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1, t2;
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +LOCK TABLE t1 WRITE;
> +connection con1
> +SET DEBUG_SYNC= 'before_lock_tables_takes_lock
> +                     SIGNAL opened WAIT_FOR flushed';
> +SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2';
> +SET DEBUG_SYNC= 'before_open_table_wait_refresh SIGNAL locked';
> +SET DEBUG_SYNC= 'after_insert SIGNAL locked';
> +INSERT INTO t1 VALUES (1);
> +connection default
> +SET DEBUG_SYNC= 'now WAIT_FOR opened';
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
> +FLUSH TABLES;
> +SET DEBUG_SYNC= 'now WAIT_FOR locked';
> +SELECT * FROM t1;
> +c1
> +UNLOCK TABLES;
> +connection con1
> +connection default
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1;
> +CREATE TABLE t1 (c1 REAL) ENGINE=MyISAM;
> +CREATE TABLE t2 (c1 REAL) ENGINE=MyISAM;
> +INSERT INTO t1 VALUES(0.1);
> +INSERT INTO t2 VALUES(0.2);
> +CREATE TABLE t3 (c1 REAL) ENGINE=MRG_MYISAM UNION=(t1,t2);
> +connection con1
> +SET DEBUG_SYNC= 'before_acos_function
> +                     SIGNAL select WAIT_FOR truncated';
> +SELECT ACOS(c1) FROM t3;
> +connection default
> +SET DEBUG_SYNC= 'now WAIT_FOR select';
> +SET DEBUG_SYNC= 'before_wait_locked_tname SIGNAL truncated';
> +TRUNCATE TABLE t1;
> +SET DEBUG_SYNC= 'now SIGNAL truncated';
> +connection con1
> +connection default
> +SELECT ACOS(c1) FROM t3;
> +ACOS(c1)
> +1.369438406004566
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1, t2, t3;
> +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
> +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST;
> +connection con1
> +SET DEBUG_SYNC= 'before_myisammrg_attach
> +                     SIGNAL attach WAIT_FOR flushed';
> +INSERT INTO m1 VALUES (2);
> +connection default;
> +SET DEBUG_SYNC= 'now WAIT_FOR attach';
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
> +FLUSH TABLE m1;
> +connection con1
> +connection default;
> +SELECT * FROM m1;
> +c1
> +2
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE m1, t1;
> +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
> +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST;
> +connection con1
> +SET DEBUG_SYNC= 'before_myisammrg_attach
> +                     SIGNAL attach WAIT_FOR store_lock1';
> +SET DEBUG_SYNC= 'before_myisammrg_store_lock
> +                     SIGNAL store_lock2 WAIT_FOR flushed';
> +INSERT INTO m1 VALUES (2);
> +connection default;
> +SET DEBUG_SYNC= 'now WAIT_FOR attach';
> +SET DEBUG_SYNC= 'before_myisammrg_store_lock
> +                 SIGNAL store_lock1 WAIT_FOR store_lock2';
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
> +FLUSH TABLE m1;
> +connection con1
> +connection default;
> +SELECT * FROM m1;
> +c1
> +2
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE m1, t1;
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +LOCK TABLE t1 WRITE;
> +connection con1
> +SET DEBUG_SYNC= 'mysql_lock_retry HIT_LIMIT 1';
> +SET DEBUG_SYNC= 'before_lock_tables_takes_lock
> +                     SIGNAL opened WAIT_FOR flushed';
> +SET DEBUG_SYNC= 'after_insert SIGNAL locked';
> +SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2';
> +SET DEBUG_SYNC= 'before_open_table_wait_refresh SIGNAL locked';
> +INSERT INTO t1 VALUES (1);
> +connection default;
> +SET DEBUG_SYNC= 'now WAIT_FOR opened';
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed EXECUTE 2';
> +FLUSH TABLES;
> +SET DEBUG_SYNC= 'now WAIT_FOR locked';
> +UNLOCK TABLES;
> +connection con1
> +connection default;
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1;
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +LOCK TABLE t1 WRITE;
> +connection con1
> +SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked';
> +INSERT INTO t1 VALUES (1);
> +connection default;
> +SET DEBUG_SYNC= 'now WAIT_FOR locked';
> +UNLOCK TABLES;
> +connection con1
> +connection default;
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1;
====================================================================================
> diff -Nrup a/mysql-test/r/merge.result b/mysql-test/r/merge.result
> --- a/mysql-test/r/merge.result	2007-12-13 13:56:17 +01:00
> +++ b/mysql-test/r/merge.result	2008-03-11 18:54:23 +01:00
> @@ -1069,31 +1069,6 @@ c1
>  2
>  UNLOCK TABLES;
>  DROP TABLE t1, t2, t3, t4;
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
> -REPAIR TABLE t1;
> -INSERT INTO t2 VALUES (1);
> -Table	Op	Msg_type	Msg_text
> -test.t1	repair	status	OK
> -DROP TABLE t1, t2;
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
> -LOCK TABLE t1 WRITE;
> -INSERT INTO t2 VALUES (1);
> -REPAIR TABLE t1;
> -Table	Op	Msg_type	Msg_text
> -test.t1	repair	status	OK
> -UNLOCK TABLES;
> -DROP TABLE t1, t2;
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -LOCK TABLE t1 WRITE;
> -INSERT INTO t1 VALUES (1);
> -FLUSH TABLES;
> -FLUSH TABLES;
> -SELECT * FROM t1;
> -c1
> -UNLOCK TABLES;
> -DROP TABLE t1;
>  #
>  # Extra tests for Bug#26379 - Combination of FLUSH TABLE and
>  #                             REPAIR TABLE corrupts a MERGE table
> @@ -1611,6 +1586,7 @@ c1
>  33
>  DELETE FROM t4 WHERE c1 = 33;
>  DROP TRIGGER t3_ai;
> +UNLOCK TABLES;
>  #
>  # Trigger with table use on child
>  DELETE FROM t4 WHERE c1 = 4;
> @@ -1793,9 +1769,9 @@ ALTER TABLE t2 UNION=(t3,t1);
>  SELECT * FROM t2;
>  ERROR HY000: Table 't3' is differently defined or of non-MyISAM type or doesn't
> exist
>  DROP TABLE t1, t2, t3;
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -CREATE TABLE t2 (c1 INT) ENGINE= MyISAM;
> -CREATE TABLE t3 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1, t2);
> +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
> +CREATE TABLE t2 (c1 INT) ENGINE=MyISAM;
> +CREATE TABLE t3 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2);
>  INSERT INTO t1 VALUES (1);
>  INSERT INTO t2 VALUES (2);
>  SELECT * FROM t3;
> @@ -1806,89 +1782,6 @@ TRUNCATE TABLE t1;
>  SELECT * FROM t3;
>  c1
>  2
> -DROP TABLE t1, t2, t3;
> -CREATE TABLE t1 (id INTEGER, grp TINYINT, id_rev INTEGER);
> -SET @rnd_max= 2147483647;
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -SET @rnd= RAND();
> -SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -SET @id_rev= @rnd_max - @id;
> -SET @grp= CAST(127.0 * @rnd AS UNSIGNED);
> -INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev);
> -set @@read_buffer_size=2*1024*1024;
> -CREATE TABLE t2 SELECT * FROM t1;
> -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2;
> -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1;
> -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2;
> -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1;
> -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2;
> -CREATE TABLE t3 (id INTEGER, grp TINYINT, id_rev INTEGER)
> -ENGINE= MRG_MYISAM UNION= (t1, t2);
> -SELECT COUNT(*) FROM t1;
> -COUNT(*)
> -130
> -SELECT COUNT(*) FROM t2;
> -COUNT(*)
> -80
> -SELECT COUNT(*) FROM t3;
> -COUNT(*)
> -210
> -SELECT COUNT(DISTINCT a1.id) FROM t3 AS a1, t3 AS a2
> -WHERE a1.id = a2.id GROUP BY a2.grp;
> -TRUNCATE TABLE t1;
> -SELECT COUNT(*) FROM t1;
> -COUNT(*)
> -0
> -SELECT COUNT(*) FROM t2;
> -COUNT(*)
> -80
> -SELECT COUNT(*) FROM t3;
> -COUNT(*)
> -80
>  DROP TABLE t1, t2, t3;
>  CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
>  CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST;
====================================================================================
> diff -Nrup a/mysql-test/t/debug_sync.test b/mysql-test/t/debug_sync.test
> --- /dev/null	Wed Dec 31 16:00:00 196900
> +++ b/mysql-test/t/debug_sync.test	2008-03-11 18:54:24 +01:00
> @@ -0,0 +1,361 @@
> +###################### t/debug_sync.test ###############################
> +#                                                                      #
> +# Testing of the Debug Sync Facility.                                  #
> +#                                                                      #
> +# There is important documentation within sql/debug_sync.cc            #
> +#                                                                      #
> +# Used objects in this test case:                                      #
> +# p0 - synchronization point 0. Non-existent dummy sync point.         #
> +# s1 - signal 1.                                                       #
> +# s2 - signal 2.                                                       #
> +#                                                                      #
> +# Creation:                                                            #
> +# 2008-02-18 istruewing                                                #
> +#                                                                      #
> +########################################################################
> +
> +#
> +# We need the Debug Sync Facility.
> +#
> +--source include/have_debug_sync.inc
> +
> +#
> +# We are checking privileges, which the embedded server cannot do.
> +#
> +--source include/not_embedded.inc
> +
> +#
> +# Preparative cleanup.
> +#
> +--disable_warnings
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE IF EXISTS t1;
> +--enable_warnings
> +
> +#
> +# Show the special system variable.
> +# It shows ON or OFF depending on the command line option --debug-sync.
> +# The test case assumes it is ON (command line option present).
> +#
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +
> +#
> +# Syntax. Valid forms.
> +#
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6           HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2           EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2           EXECUTE 2';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2                     HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2';
> +SET DEBUG_SYNC='p0 SIGNAL s1                       EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1                       EXECUTE 2';
> +SET DEBUG_SYNC='p0 SIGNAL s1                                 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 SIGNAL s1';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6 EXECUTE 2';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6           HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2           EXECUTE 2 HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2           EXECUTE 2';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2                     HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0           WAIT_FOR s2';
> +SET DEBUG_SYNC='p0                                           HIT_LIMIT 3';
> +SET DEBUG_SYNC='p0 CLEAR';
> +SET DEBUG_SYNC='p0 TEST';
> +SET DEBUG_SYNC='RESET';
> +
> +#
> +# Syntax. Valid forms. Lower case.
> +#
> +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2 hit_limit 3';
> +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2';
> +set debug_sync='p0 signal s1 wait_for s2 timeout 6           hit_limit 3';
> +set debug_sync='p0 signal s1 wait_for s2 timeout 6';
> +set debug_sync='p0 signal s1 wait_for s2           execute 2 hit_limit 3';
> +set debug_sync='p0 signal s1 wait_for s2           execute 2';
> +set debug_sync='p0 signal s1 wait_for s2                     hit_limit 3';
> +set debug_sync='p0 signal s1 wait_for s2';
> +set debug_sync='p0 signal s1                       execute 2 hit_limit 3';
> +set debug_sync='p0 signal s1                       execute 2';
> +set debug_sync='p0 signal s1                                 hit_limit 3';
> +set debug_sync='p0 signal s1';
> +set debug_sync='p0           wait_for s2 timeout 6 execute 2 hit_limit 3';
> +set debug_sync='p0           wait_for s2 timeout 6 execute 2';
> +set debug_sync='p0           wait_for s2 timeout 6           hit_limit 3';
> +set debug_sync='p0           wait_for s2 timeout 6';
> +set debug_sync='p0           wait_for s2           execute 2 hit_limit 3';
> +set debug_sync='p0           wait_for s2           execute 2';
> +set debug_sync='p0           wait_for s2                     hit_limit 3';
> +set debug_sync='p0           wait_for s2';
> +set debug_sync='p0                                           hit_limit 3';
> +set debug_sync='p0 clear';
> +set debug_sync='p0 test';
> +set debug_sync='reset';
> +
> +#
> +# Syntax. Valid forms. Line wrap.
> +#
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6
> +                EXECUTE 2 HIT_LIMIT 3';
> +
> +#
> +# Syntax. Invalid forms.
> +#
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0                                          EXECUTE 2';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0                                TIMEOUT 6 EXECUTE 2';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0                                TIMEOUT 6';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1           EXECUTE 2';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6 EXECUTE 2';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1 EXECUTE 2';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2 EXECUTE 2';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0                  SIGNAL s1 TIMEOUT 6 EXECUTE 2';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0                  SIGNAL s1 TIMEOUT 6';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 EXECUTE 2 SIGNAL s1 TIMEOUT 6';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 TIMEOUT 6 SIGNAL s1';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 EXECUTE 2 TIMEOUT 6 SIGNAL s1';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 CLEAR HIT_LIMIT 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='CLEAR';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 CLEAR p0';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='TEST';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 TEST p0';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 RESET';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='RESET p0';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 RESET p0';
> +
> +#
> +# Syntax. Invalid keywords used.
> +#
> +--error ER_UNKNOWN_SYSTEM_VARIABLE
> +SET DEBUG_SYNCx='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 SIGNAx s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOx s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUx 0 EXECUTE 2 HIT_LIMIT 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTx 2 HIT_LIMIT 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIx 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 CLEARx';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 TESTx';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='RESETx';
> +
> +#
> +# Syntax. Invalid numbers. Decimal only.
> +#
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 0x6 EXECUTE 2 HIT_LIMIT 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 0x2 HIT_LIMIT 3';
> +--error ER_PARSE_ERROR
> +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 7 EXECUTE 2 HIT_LIMIT 0x3';
> +
> +#
> +# Syntax. Invalid value type.
> +#
> +--error ER_WRONG_TYPE_FOR_VAR
> +SET DEBUG_SYNC= 7;
> +
> +#
> +# Syntax. DEBUG_SYNC is a SESSION-only variable.
> +#
> +--error ER_WRONG_OBJECT
> +SET GLOBAL DEBUG_SYNC= 'p0 CLEAR';
> +
> +#
> +# Functional tests.
> +#
> +# NOTE: There is the special synchronization point 'now'. It is placed
> +#       immediately after setting of the DEBUG_SYNC variable.
> +#       So it is executed before the SET statement ends.
> +#
> +# NOTE: There is only on global signal (say "signal post" or "flag mast").
> +#       A SIGNAL action writes its signal into it ("sets a flag").
> +#       The signal persists until explicitly overwritten.
> +#       To avoid confusion for later tests, it is recommended to clear
> +#       the signal by signalling "empty" ("setting the 'empty' flag"):
> +#       SET DEBUG_SYNC= 'now SIGNAL empty';
> +#       Preferably you can reset the whole facility with:
> +#       SET DEBUG_SYNC= 'RESET';
> +#       The signal is then '' (really empty) which connot be done otherwise.
> +#
> +
> +#
> +# Time out immediately. This gives just a warning.
> +#
> +SET DEBUG_SYNC= 'now SIGNAL something';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
> +#
> +# If signal is present already, TIMEOUT 0 does not give a warning.
> +#
> +SET DEBUG_SYNC= 'now SIGNAL nothing';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
> +
> +#
> +# EXECUTE 0 is effectively a no-op.
> +#
> +SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0';
> +
> +#
> +# Run into HIT_LIMIT. This gives an error.
> +#
> +--error ER_DEBUG_SYNC_HIT_LIMIT
> +SET DEBUG_SYNC= 'now HIT_LIMIT 1';
> +
> +#
> +# Many actions. Watch the array growing and shrinking in the debug trace:
> +# egrep 'query:|debug_sync_action:' mysql-test/var/log/master.trace
> +#
> +SET DEBUG_SYNC= 'RESET';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'p1abcd   SIGNAL s1 EXECUTE 2';
> +SET DEBUG_SYNC= 'p2abc    SIGNAL s2 EXECUTE 2';
> +SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2';
> +SET DEBUG_SYNC= 'p4a      SIGNAL s4 EXECUTE 2';
> +SET DEBUG_SYNC= 'p5abcde  SIGNAL s5 EXECUTE 2';
> +SET DEBUG_SYNC= 'p6ab     SIGNAL s6 EXECUTE 2';
> +SET DEBUG_SYNC= 'p7       SIGNAL s7 EXECUTE 2';
> +SET DEBUG_SYNC= 'p8abcdef SIGNAL s8 EXECUTE 2';
> +SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2';
> +#
> +# Execute some actions to show they exist. Each sets a distinct signal.
> +#
> +SET DEBUG_SYNC= 'p4a      TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'p1abcd   TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'p7       TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'p9abcdef TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'p3abcdef TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +#
> +# Clear the actions.
> +#
> +SET DEBUG_SYNC= 'p1abcd   CLEAR';
> +SET DEBUG_SYNC= 'p2abc    CLEAR';
> +SET DEBUG_SYNC= 'p5abcde  CLEAR';
> +SET DEBUG_SYNC= 'p6ab     CLEAR';
> +SET DEBUG_SYNC= 'p8abcdef CLEAR';
> +SET DEBUG_SYNC= 'p9abcdef CLEAR';
> +SET DEBUG_SYNC= 'p3abcdef CLEAR';
> +SET DEBUG_SYNC= 'p4a      CLEAR';
> +SET DEBUG_SYNC= 'p7       CLEAR';
> +#
> +# Execute some actions to show they have gone.
> +#
> +SET DEBUG_SYNC= 'p1abcd   TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'p7       TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +SET DEBUG_SYNC= 'p9abcdef TEST';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +#
> +# Now cleanup. Actions are clear already, but signal needs to be cleared.
> +#
> +SET DEBUG_SYNC= 'RESET';
> +SHOW VARIABLES LIKE 'DEBUG_SYNC';
> +
> +#
> +# Facility requires SUPER privilege.
> +#
> +CREATE USER mysqltest_1@localhost;
> +GRANT SUPER ON *.* TO mysqltest_1@localhost;
> +--echo connection con1, mysqltest_1
> +connect (con1,localhost,mysqltest_1,,);
> +SET DEBUG_SYNC= 'RESET';
> +disconnect con1;
> +--echo connection default
> +connection default;
> +DROP USER mysqltest_1@localhost;
> +#
> +CREATE USER mysqltest_2@localhost;
> +GRANT ALL ON *.* TO mysqltest_2@localhost;
> +REVOKE SUPER ON *.* FROM mysqltest_2@localhost;
> +--echo connection con1, mysqltest_2
> +connect (con1,localhost,mysqltest_2,,);
> +--error ER_SPECIFIC_ACCESS_DENIED_ERROR
> +SET DEBUG_SYNC= 'RESET';
> +disconnect con1;
> +--echo connection default
> +connection default;
> +DROP USER mysqltest_2@localhost;
> +
> +#
> +# Example.
> +#
> +# Preparative cleanup.
> +--disable_warnings
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE IF EXISTS t1;
> +--enable_warnings
> +#
> +# Test.
> +CREATE TABLE t1 (c1 INT);
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    SET DEBUG_SYNC= 'before_lock_tables_takes_lock
> +      SIGNAL opened WAIT_FOR flushed';
> +    send INSERT INTO t1 VALUES(1);
> +--echo connection default
> +connection default;
> +SET DEBUG_SYNC= 'now WAIT_FOR opened';
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
> +FLUSH TABLE t1;
> +    --echo connection con1
> +    connection con1;
> +    reap;
> +    disconnect con1;
> +--echo connection default
> +connection default;
> +DROP TABLE t1;
> +
> +#
> +# Cleanup after test case.
> +# Otherwise signal would contain 'flushed' here,
> +# which could confuse the next test.
> +#
> +SET DEBUG_SYNC= 'RESET';
> +
====================================================================================
> diff -Nrup a/mysql-test/t/merge-big.test b/mysql-test/t/merge-big.test
> --- a/mysql-test/t/merge-big.test	2008-02-07 12:04:18 +01:00
> +++ /dev/null	Wed Dec 31 16:00:00 196900
> @@ -1,82 +0,0 @@
> -#
> -# Test of MERGE tables with multisession and many waits.
> -#
> -# This test takes rather long time so let us run it only in --big-test mode
> ---source include/big_test.inc
> -# We use some debug-only features in this test
> ---source include/have_debug.inc
> -# We use INFORMATION_SCHEMA.PROCESSLIST in this test
> ---source include/not_embedded.inc
> -
> ---disable_warnings
> -drop table if exists t1,t2,t3,t4,t5,t6;
> ---enable_warnings
> -
> ---echo #
> ---echo # Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
> ---echo #             corrupts a MERGE table
> ---echo # Problem #3
> ---echo #
> -# Two FLUSH TABLES within a LOCK TABLES segment could invalidate the lock.
> -# This did *not* require a MERGE table.
> -#
> -# To increase reproducibility it was necessary to enter a sleep of 2
> -# seconds at the end of wait_for_tables() after unlock of LOCK_open. In
> -# 5.0 and 5.1 the sleep must be inserted in open_and_lock_tables() after
> -# open_tables() instead. wait_for_tables() is not used in this case. The
> -# problem was that FLUSH TABLES releases LOCK_open while having unlocked
> -# and closed all tables. When this happened while a thread was in the
> -# loop in mysql_lock_tables() right after wait_for_tables()
> -# (open_tables()) and before retrying to lock, the thread got the lock.
> -# And it did not notice that the table needed a refresh after the
> -# [re-]open. So it executed its statement on the table.
> -#
> -# The first FLUSH TABLES kicked the INSERT out of thr_multi_lock() and
> -# let it wait in wait_for_tables() (open_table()). The second FLUSH
> -# TABLES must happen while the INSERT was on its way from
> -# wait_for_tables() (open_table()) to the next call of thr_multi_lock().
> -# This needed to be supported by a sleep to make it repeatable.
> -#
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -LOCK TABLE t1 WRITE;
> -#SELECT NOW();
> -    --echo # connection con1
> -    connect (con1,localhost,root,,);
> -    let $con1_id= `SELECT CONNECTION_ID()`;
> -    SET SESSION debug="+d,sleep_open_and_lock_after_open";
> -    send INSERT INTO t1 VALUES (1);
> ---echo # connection default
> -connection default;
> ---echo # Let INSERT go into thr_multi_lock().
> -#--sleep 8
> -#SELECT ID,STATE,INFO FROM INFORMATION_SCHEMA.PROCESSLIST;
> -let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST
> -    WHERE ID = $con1_id AND STATE = 'Locked';
> ---source include/wait_condition.inc
> -#SELECT NOW();
> ---echo # Kick INSERT out of thr_multi_lock().
> -FLUSH TABLES;
> -#SELECT NOW();
> ---echo # Let INSERT go through open_tables() where it sleeps.
> -#--sleep 8
> -#SELECT ID,STATE,INFO FROM INFORMATION_SCHEMA.PROCESSLIST;
> -let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST
> -    WHERE ID = $con1_id AND STATE = 'Waiting for table';
> ---source include/wait_condition.inc
> -#SELECT NOW();
> ---echo # Unlock and close table and wait for con1 to close too.
> -FLUSH TABLES;
> -#SELECT NOW();
> ---echo # This should give no result.
> -SELECT * FROM t1;
> -#SELECT NOW();
> -UNLOCK TABLES;
> -    --echo # connection con1
> -    connection con1;
> -    reap;
> -    SET SESSION debug="-d,sleep_open_and_lock_after_open";
> -    disconnect con1;
> ---echo # connection default
> -connection default;
> -DROP TABLE t1;
> -
====================================================================================
> diff -Nrup a/mysql-test/t/merge-sync.test b/mysql-test/t/merge-sync.test
> --- /dev/null	Wed Dec 31 16:00:00 196900
> +++ b/mysql-test/t/merge-sync.test	2008-03-11 18:54:24 +01:00
> @@ -0,0 +1,384 @@
> +#
> +# Test of MERGE TABLES
> +#
> +
> +#
> +# We need the Debug Sync Facility.
> +#
> +--source include/have_debug_sync.inc
> +
> +# Clean up resources used in this test case.
> +--disable_warnings
> +SET DEBUG_SYNC= 'RESET';
> +drop table if exists t1,t2,t3,t4,t5,t6;
> +drop database if exists mysqltest;
> +--enable_warnings
> +
> +#
> +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
> +# Problem #1
> +# A thread trying to lock a MERGE table performed busy waiting while
> +# REPAIR TABLE or a similar table administration task was ongoing on one or
> +# more of its MyISAM tables.
> +# To allow for observability it was necessary to enter a multi-second sleep
> +# in mysql_admin_table() after remove_table_from_cache(), which comes after
> +# mysql_abort_lock(). The sleep faked a long running operation. One could
> +# watch a high CPU load during the sleep time.
> +# The problem was that mysql_abort_lock() upgrades the write lock to
> +# TL_WRITE_ONLY. This lock type persisted until the final unlock at the end
> +# of the administration task. The effect of TL_WRITE_ONLY is to reject any
> +# attempt to lock the table. The trying thread must close the table and wait
> +# until it is no longer used. Unfortunately there is no way to detect that
> +# one of the MyISAM tables of a MERGE table is in use. When trying to lock
> +# the MERGE table, all MyISAM tables are locked. If one fails on
> +# TL_WRITE_ONLY, all locks are aborted and wait_for_tables() is entered.
> +# But this doesn't see the MERGE table as used, so it seems appropriate to
> +# retry a lock...
> +#
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
> +#
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    # When reaching repair code, signal admin_flush and wait for end_repair.
> +    SET DEBUG_SYNC= 'after_admin_flush
> +                     SIGNAL admin_flush WAIT_FOR end_repair';
> +    send REPAIR TABLE t1;
> +#
> +--echo connection default;
> +connection default;
> +# Wait that the other thread reaches repair.
> +SET DEBUG_SYNC= 'now WAIT_FOR admin_flush';
> +#
> +# If the bug exists, INSERT will loop infinitely in getting its lock.
> +# Bail out if lock retry is done 3 times.
> +SET DEBUG_SYNC= 'mysql_lock_retry HIT_LIMIT 3';
> +# When the bug is fixed, we wait for refresh of repaired table.
> +# In this case resume repair thread so that we do not deadlock.
> +SET DEBUG_SYNC= 'before_open_table_wait_refresh SIGNAL end_repair';
> +# Succeeds with bug fixed.
> +INSERT INTO t2 VALUES (1);
> +#
> +# Resume the other thread. (non-bug fixed case)
> +SET DEBUG_SYNC= 'now SIGNAL end_repair';
> +#
> +    --echo connection con1
> +    connection con1;
> +    reap;
> +    disconnect con1;
> +#
> +--echo connection default;
> +connection default;
> +# Clear debug_sync signal.
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1, t2;
> +#
> +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
> +# Problem #2
> +# A thread trying to lock a MERGE table performed busy waiting until all
> +# threads that did REPAIR TABLE or similar table administration tasks on
> +# one or more of its MyISAM tables in LOCK TABLES segments did
> +# UNLOCK TABLES.
> +# The difference against problem #1 is that the busy waiting took place
> +# *after* the administration task. It was terminated by UNLOCK TABLES only.
> +#
> +# This is the same test case as for
> +# Bug#26867 - LOCK TABLES + REPAIR + merge table result in memory/cpu hogging
> +#
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
> +LOCK TABLE t1 WRITE;
> +REPAIR TABLE t1;
> +#
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    # If the bug exists, the insert will loop infinitely in getting its lock.
> +    # Bail out if lock retry is done 3 times.
> +    SET DEBUG_SYNC= 'mysql_lock_retry HIT_LIMIT 3';
> +    # If the bug exists, resume repair thread after reaching the retry limit.
> +    SET DEBUG_SYNC= 'after_insert SIGNAL end_repair';
> +    # If the bug is fixed, we wait for refresh of repaired table.
> +    # In this case resume repair thread so that we do not deadlock.
> +    SET DEBUG_SYNC= 'before_open_table_wait_refresh SIGNAL end_repair';
> +    send INSERT INTO t2 VALUES (1);
> +#
> +--echo connection default;
> +connection default;
> +# Wait for signal from insert. Would be infinite with bug and no retry limit.
> +SET DEBUG_SYNC= 'now WAIT_FOR end_repair';
> +UNLOCK TABLES;
> +#
> +    --echo connection con1
> +    connection con1;
> +    # Succeeds with bug fixed.
> +    reap;
> +    disconnect con1;
> +#
> +--echo connection default;
> +connection default;
> +# Clear debug_sync signal.
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1, t2;
> +#
> +# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
> +# Problem #3
> +# Two FLUSH TABLES within a LOCK TABLES segment could invalidate the lock.
> +# This did *not* require a MERGE table.
> +# To increase reproducibility it was necessary to enter a sleep of 2 seconds
> +# at the end of wait_for_tables() after unlock of LOCK_open. In 5.0 and 5.1
> +# the sleep must be inserted in open_and_lock_tables() after open_tables()
> +# instead. wait_for_tables() is not used in this case.
> +# The problem was that FLUSH TABLES releases LOCK_open while having unlocked
> +# and closed all tables. When this happened while a thread was in the loop in
> +# mysql_lock_tables() right after wait_for_tables() and before retrying to
> +# lock, the thread got the lock.  (Translate to similar code places in 5.0
> +# and 5.1). And it did not notice that the table needed a refresh. So it
> +# executed its statement on the table.
> +# The first FLUSH TABLES kicked the INSERT out of thr_multi_lock() and let
> +# it wait in wait_for_tables(). (open_table() in 5.0 and 5.1). The second
> +# FLUSH TABLES must happen while the INSERT was on its way from
> +# wait_for_tables() to the next call of thr_multi_lock(). This needed to be
> +# supported by a sleep to make it repeatable.
> +# In >= 5.0, when waiting after open_tables() one FLUSH is sufficient
> +# to allow the INSERT to step in.
> +#
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +LOCK TABLE t1 WRITE;
> +#
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    # After open, wait for flush.
> +    SET DEBUG_SYNC= 'before_lock_tables_takes_lock
> +                     SIGNAL opened WAIT_FOR flushed';
> +    # If bug is fixed, INSERT will go into wait_for_lock.
> +    # Retain action after use. First used by general_log.
> +    SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2';
> +    # Alternatively INSERT can wait for refresh in open_table().
> +    SET DEBUG_SYNC= 'before_open_table_wait_refresh SIGNAL locked';
> +    # If bug is not fixed, INSERT will succeed. Pretend locked.
> +    SET DEBUG_SYNC= 'after_insert SIGNAL locked';
> +    send INSERT INTO t1 VALUES (1);
> +#
> +--echo connection default
> +connection default;
> +# Wait until INSERT opened the table.
> +SET DEBUG_SYNC= 'now WAIT_FOR opened';
> +#
> +# Let INSERT exploit the gap when flush waits wthout lock
> +# for other threads to close the tables.
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
> +FLUSH TABLES;
> +#
> +# Wait until INSERT is locked (bug fixed) or finished (bug not fixed).
> +SET DEBUG_SYNC= 'now WAIT_FOR locked';
> +#
> +# This should give no result. But it will if the bug exists.
> +SELECT * FROM t1;
> +UNLOCK TABLES;
> +#
> +    --echo connection con1
> +    connection con1;
> +    reap;
> +    disconnect con1;
> +#
> +--echo connection default
> +connection default;
> +# Clear debug_sync signal.
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1;
> +#
> +# Show that truncate of child table waits while parent table is used.
> +CREATE TABLE t1 (c1 REAL) ENGINE=MyISAM;
> +CREATE TABLE t2 (c1 REAL) ENGINE=MyISAM;
> +INSERT INTO t1 VALUES(0.1);
> +INSERT INTO t2 VALUES(0.2);
> +CREATE TABLE t3 (c1 REAL) ENGINE=MRG_MYISAM UNION=(t1,t2);
> +#
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    # When reaching acos(), send 'select' and wait for truncated.
> +    SET DEBUG_SYNC= 'before_acos_function
> +                     SIGNAL select WAIT_FOR truncated';
> +    send SELECT ACOS(c1) FROM t3;
> +#
> +--echo connection default
> +connection default;
> +# Wait for con1 to reach acos().
> +SET DEBUG_SYNC= 'now WAIT_FOR select';
> +#
> +# With bug fix present, TRUNCATE runs into wait_for_locked_table_names().
> +SET DEBUG_SYNC= 'before_wait_locked_tname SIGNAL truncated';
> +TRUNCATE TABLE t1;
> +#
> +# With bug fix not present, we need to signal after TRUNCATE.
> +SET DEBUG_SYNC= 'now SIGNAL truncated';
> +#
> +    --echo connection con1
> +    connection con1;
> +    # In non-debug server, the order of select and truncate is undetermined.
> +    # So we may have one or two rows here.
> +    --disable_result_log
> +    reap;
> +    --enable_result_log
> +    disconnect con1;
> +#
> +--echo connection default
> +connection default;
> +SELECT ACOS(c1) FROM t3;
> +# Clear debug_sync signal.
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1, t2, t3;
> +
> +#
> +# In-depth test.
> +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
> +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST;
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    # Wait for flush before attaching children.
> +    SET DEBUG_SYNC= 'before_myisammrg_attach
> +                     SIGNAL attach WAIT_FOR flushed';
> +    send INSERT INTO m1 VALUES (2);
> +--echo connection default;
> +connection default;
> +#
> +# Wait for con1 to reach attach_merge_children(), then flush and signal.
> +SET DEBUG_SYNC= 'now WAIT_FOR attach';
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
> +FLUSH TABLE m1;
> +#
> +    --echo connection con1
> +    connection con1;
> +    reap;
> +    disconnect con1;
> +--echo connection default;
> +connection default;
> +SELECT * FROM m1;
> +# Clear debug_sync signal.
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE m1, t1;
> +#
> +# Test derived from test program for
> +# Bug#30273 - merge tables: Can't lock file (errno: 155)
> +# Second test try to step in between lock_count() and store_lock().
> +#
> +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
> +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST;
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    # When reaching attach_merge_children(), signal attach and
> +    # wait for store_lock1 before attaching children.
> +    # Then run through attach of children until store_lock().
> +    # Signal store_lock2 and wait for flushed.
> +    SET DEBUG_SYNC= 'before_myisammrg_attach
> +                     SIGNAL attach WAIT_FOR store_lock1';
> +    SET DEBUG_SYNC= 'before_myisammrg_store_lock
> +                     SIGNAL store_lock2 WAIT_FOR flushed';
> +    send INSERT INTO m1 VALUES (2);
> +--echo connection default;
> +connection default;
> +#
> +# Wait for con1 to reach attach.
> +SET DEBUG_SYNC= 'now WAIT_FOR attach';
> +# Run until myisammrg store_lock(),
> +# then signal store_lock1 and
> +# wait for con1 to go through attach until store_lock() (store_lock2),
> +# then flush and signal flushed.
> +SET DEBUG_SYNC= 'before_myisammrg_store_lock
> +                 SIGNAL store_lock1 WAIT_FOR store_lock2';
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
> +FLUSH TABLE m1;
> +#
> +    --echo connection con1
> +    connection con1;
> +    reap;
> +    disconnect con1;
> +--echo connection default;
> +connection default;
> +SELECT * FROM m1;
> +# Clear debug_sync signal.
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE m1, t1;
> +
> +#
> +# Coverage test for mysql_lock_retry hit limit.
> +# Similar test as for Bug#26379, Problem #3.
> +# But mysql_lock_retry hit limit set.
> +#
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +LOCK TABLE t1 WRITE;
> +#
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    SET DEBUG_SYNC= 'mysql_lock_retry HIT_LIMIT 1';
> +    # After open, wait for flush.
> +    SET DEBUG_SYNC= 'before_lock_tables_takes_lock
> +                     SIGNAL opened WAIT_FOR flushed';
> +    # If bug is not fixed, INSERT will succeed. Pretend locked.
> +    SET DEBUG_SYNC= 'after_insert SIGNAL locked';
> +    # If bug is fixed, INSERT will go into wait_for_lock.
> +    # Retain action after use. First used by general_log.
> +    SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2';
> +    # Alternatively INSERT can wait for refresh in open_table().
> +    SET DEBUG_SYNC= 'before_open_table_wait_refresh SIGNAL locked';
> +    send INSERT INTO t1 VALUES (1);
> +#
> +--echo connection default;
> +connection default;
> +#
> +# Wait until INSERT opened the table.
> +SET DEBUG_SYNC= 'now WAIT_FOR opened';
> +#
> +# Let INSERT exploit the gap when flush waits wthout lock
> +# for other threads to close the tables.
> +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed EXECUTE 2';
> +FLUSH TABLES;
> +#
> +# Wait until INSERT is locked (bug fixed) or finished (bug not fixed).
> +SET DEBUG_SYNC= 'now WAIT_FOR locked';
> +UNLOCK TABLES;
> +#
> +    --echo connection con1
> +    connection con1;
> +    # Succeeds if DEBUG_SYNC is disabled
> +    --error 0, ER_DEBUG_SYNC_HIT_LIMIT
> +    reap;
> +    disconnect con1;
> +#
> +--echo connection default;
> +connection default;
> +#
> +# Clear debug_sync signal.
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1;
> +
> +#
> +# Coverage test for wait_for_lock.
> +#
> +CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> +LOCK TABLE t1 WRITE;
> +#
> +    --echo connection con1
> +    connect (con1,localhost,root,,);
> +    SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked';
> +    send INSERT INTO t1 VALUES (1);
> +#
> +--echo connection default;
> +connection default;
> +#
> +# Wait until INSERT is locked.
> +SET DEBUG_SYNC= 'now WAIT_FOR locked';
> +UNLOCK TABLES;
> +#
> +    --echo connection con1
> +    connection con1;
> +    reap;
> +    disconnect con1;
> +#
> +--echo connection default;
> +connection default;
> +#
> +# Clear debug_sync signal.
> +SET DEBUG_SYNC= 'RESET';
> +DROP TABLE t1;
> +
====================================================================================
> diff -Nrup a/mysql-test/t/merge.test b/mysql-test/t/merge.test
> --- a/mysql-test/t/merge.test	2007-12-13 13:56:18 +01:00
> +++ b/mysql-test/t/merge.test	2008-03-11 18:54:23 +01:00
> @@ -2,6 +2,7 @@
>  # Test of MERGE TABLES
>  #
>  
> +# Clean up resources used in this test case.
>  --disable_warnings
>  drop table if exists t1,t2,t3,t4,t5,t6;
>  drop database if exists mysqltest;
> @@ -691,113 +692,6 @@ SELECT * FROM t3;
>  UNLOCK TABLES;
>  DROP TABLE t1, t2, t3, t4;
>  
> -#
> -# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
> -# Preparation
> -connect (con1,localhost,root,,);
> -connect (con2,localhost,root,,);
> -connection default;
> -#
> -# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
> -# Problem #1
> -# A thread trying to lock a MERGE table performed busy waiting while
> -# REPAIR TABLE or a similar table administration task was ongoing on one or
> -# more of its MyISAM tables.
> -# To allow for observability it was necessary to enter a multi-second sleep
> -# in mysql_admin_table() after remove_table_from_cache(), which comes after
> -# mysql_abort_lock(). The sleep faked a long running operation. One could
> -# watch a high CPU load during the sleep time.
> -# The problem was that mysql_abort_lock() upgrades the write lock to
> -# TL_WRITE_ONLY. This lock type persisted until the final unlock at the end
> -# of the administration task. The effect of TL_WRITE_ONLY is to reject any
> -# attempt to lock the table. The trying thread must close the table and wait
> -# until it is no longer used. Unfortunately there is no way to detect that
> -# one of the MyISAM tables of a MERGE table is in use. When trying to lock
> -# the MERGE table, all MyISAM tables are locked. If one fails on
> -# TL_WRITE_ONLY, all locks are aborted and wait_for_tables() is entered.
> -# But this doesn't see the MERGE table as used, so it seems appropriate to
> -# retry a lock...
> -#
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
> -send REPAIR TABLE t1;
> -    connection con1;
> -    sleep 1; # let repair run into its sleep
> -    INSERT INTO t2 VALUES (1);
> -connection default;
> -reap;
> -DROP TABLE t1, t2;
> -#
> -# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
> -# Problem #2
> -# A thread trying to lock a MERGE table performed busy waiting until all
> -# threads that did REPAIR TABLE or similar table administration tasks on
> -# one or more of its MyISAM tables in LOCK TABLES segments did
> -# UNLOCK TABLES.
> -# The difference against problem #1 is that the busy waiting took place
> -# *after* the administration task. It was terminated by UNLOCK TABLES only.
> -#
> -# This is the same test case as for
> -# Bug#26867 - LOCK TABLES + REPAIR + merge table result in memory/cpu hogging
> -#
> -#
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
> -LOCK TABLE t1 WRITE;
> -    connection con1;
> -    send INSERT INTO t2 VALUES (1);
> -connection default;
> -sleep 1; # Let INSERT go into thr_multi_lock().
> -REPAIR TABLE t1;
> -sleep 2; # con1 performs busy waiting during this sleep.
> -UNLOCK TABLES;
> -    connection con1;
> -    reap;
> -connection default;
> -DROP TABLE t1, t2;
> -#
> -# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
> -# Problem #3
> -# Two FLUSH TABLES within a LOCK TABLES segment could invalidate the lock.
> -# This did *not* require a MERGE table.
> -# To increase reproducibility it was necessary to enter a sleep of 2 seconds
> -# at the end of wait_for_tables() after unlock of LOCK_open. In 5.0 and 5.1
> -# the sleep must be inserted in open_and_lock_tables() after open_tables()
> -# instead. wait_for_tables() is not used in this case.
> -# The problem was that FLUSH TABLES releases LOCK_open while having unlocked
> -# and closed all tables. When this happened while a thread was in the loop in
> -# mysql_lock_tables() right after wait_for_tables() and before retrying to
> -# lock, the thread got the lock.  (Translate to similar code places in 5.0
> -# and 5.1). And it did not notice that the table needed a refresh. So it
> -# executed its statement on the table.
> -# The first FLUSH TABLES kicked the INSERT out of thr_multi_lock() and let
> -# it wait in wait_for_tables(). (open_table() in 5.0 and 5.1). The second
> -# FLUSH TABLES must happen while the INSERT was on its way from
> -# wait_for_tables() to the next call of thr_multi_lock(). This needed to be
> -# supported by a sleep to make it repeatable.
> -#
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
> -LOCK TABLE t1 WRITE;
> -    connection con1;
> -    send INSERT INTO t1 VALUES (1);
> -connection default;
> -sleep 1; # Let INSERT go into thr_multi_lock().
> -FLUSH TABLES;
> -sleep 1; # Let INSERT go through wait_for_tables() where it sleeps.
> -FLUSH TABLES;
> -# This should give no result. But it will with sleep(2) at the right place.
> -SELECT * FROM t1;
> -UNLOCK TABLES;
> -    connection con1;
> -    reap;
> -connection default;
> -DROP TABLE t1;
> -#
> -# Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
> -# Cleanup
> -disconnect con1;
> -disconnect con2;
> -#
>  --echo #
>  --echo # Extra tests for Bug#26379 - Combination of FLUSH TABLE and
>  --echo #                             REPAIR TABLE corrupts a MERGE table
> @@ -1122,6 +1016,7 @@ SELECT @a;
>  SELECT * FROM t4 ORDER BY c1;
>  DELETE FROM t4 WHERE c1 = 33;
>  DROP TRIGGER t3_ai;
> +UNLOCK TABLES;
>  --echo #
>  --echo # Trigger with table use on child
>  DELETE FROM t4 WHERE c1 = 4;
> @@ -1225,62 +1120,17 @@ DROP TABLE t1, t2, t3;
>  
>  #
>  # Bug#25038 - Waiting TRUNCATE
> +# Truncate failed with error message when table was in use by MERGE.
>  #
>  # Show that truncate of child table after use of parent table works.
> -CREATE TABLE t1 (c1 INT) ENGINE= MyISAM; 
> -CREATE TABLE t2 (c1 INT) ENGINE= MyISAM; 
> -CREATE TABLE t3 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1, t2); 
> +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM; 
> +CREATE TABLE t2 (c1 INT) ENGINE=MyISAM; 
> +CREATE TABLE t3 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2); 
>  INSERT INTO t1 VALUES (1);
>  INSERT INTO t2 VALUES (2);
>  SELECT * FROM t3;
>  TRUNCATE TABLE t1;
>  SELECT * FROM t3;
> -DROP TABLE t1, t2, t3;
> -#
> -# Show that truncate of child table waits while parent table is used.
> -# (test partly borrowed from count_distinct3.)
> -CREATE TABLE t1 (id INTEGER, grp TINYINT, id_rev INTEGER);
> -SET @rnd_max= 2147483647;
> -let $1 = 10;
> -while ($1)
> -{
> -  SET @rnd= RAND();
> -  SET @id = CAST(@rnd * @rnd_max AS UNSIGNED);
> -  SET @id_rev= @rnd_max - @id;
> -  SET @grp= CAST(127.0 * @rnd AS UNSIGNED); 
> -  INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); 
> -  dec $1;
> -}
> -set @@read_buffer_size=2*1024*1024;
> -CREATE TABLE t2 SELECT * FROM t1;
> -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2;
> -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1;
> -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2;
> -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1;
> -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2;
> -CREATE TABLE t3 (id INTEGER, grp TINYINT, id_rev INTEGER)
> -  ENGINE= MRG_MYISAM UNION= (t1, t2);
> -SELECT COUNT(*) FROM t1;
> -SELECT COUNT(*) FROM t2;
> -SELECT COUNT(*) FROM t3;
> -connect (con1,localhost,root,,);
> -    # As t3 contains random numbers, results are different from test to test. 
> -    # That's okay, because we test only that select doesn't yield an
> -    # error. Note, that --disable_result_log doesn't suppress error output.
> -    --disable_result_log
> -    send SELECT COUNT(DISTINCT a1.id) FROM t3 AS a1, t3 AS a2
> -      WHERE a1.id = a2.id GROUP BY a2.grp;
> -connection default;
> -sleep 1;
> -TRUNCATE TABLE t1;
> -    connection con1;
> -    reap;
> -    --enable_result_log
> -    disconnect con1;
> -connection default;
> -SELECT COUNT(*) FROM t1;
> -SELECT COUNT(*) FROM t2;
> -SELECT COUNT(*) FROM t3;
>  DROP TABLE t1, t2, t3;
>  
>  #
====================================================================================
> diff -Nrup a/mysys/thr_lock.c b/mysys/thr_lock.c
> --- a/mysys/thr_lock.c	2008-01-28 13:52:34 +01:00
> +++ b/mysys/thr_lock.c	2008-03-11 18:54:23 +01:00
> @@ -386,6 +386,14 @@ static inline my_bool have_specific_lock
>  
>  static void wake_up_waiters(THR_LOCK *lock);
>  
> +#if defined(ENABLED_DEBUG_SYNC)
> +/**
> +  Global pointer to be set if callback function is defined
> +  (e.g. in mysqld). See debug_sync.cc.
> +*/
> +void (*debug_sync_wait_for_lock_callback_ptr)(void);
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
> +
>  
>  static enum enum_thr_lock_result
>  wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
> @@ -397,6 +405,15 @@ wait_for_lock(struct st_lock_list *wait,
>    enum enum_thr_lock_result result= THR_LOCK_ABORTED;
>    my_bool can_deadlock= test(data->owner->info->n_cursors);
>    DBUG_ENTER("wait_for_lock");
> +
> +#if defined(ENABLED_DEBUG_SYNC)
> +  /*
> +    One can use this to signal when a thread is going to wait for a lock.
> +    See debug_sync.cc.
> +  */
> +  if (debug_sync_wait_for_lock_callback_ptr)
> +    (*debug_sync_wait_for_lock_callback_ptr)();
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>  
>    if (!in_wait_list)
>    {
====================================================================================
> diff -Nrup a/sql/CMakeLists.txt b/sql/CMakeLists.txt
> --- a/sql/CMakeLists.txt	2007-12-19 14:34:59 +01:00
> +++ b/sql/CMakeLists.txt	2008-03-11 18:54:23 +01:00
> @@ -65,6 +65,7 @@ ADD_EXECUTABLE(mysqld
>                 sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc sql_lex.cc 
>                 sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc 
>                 sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc 
> +               debug_sync.cc
>                 sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc 
>                 sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
>                 sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc 
====================================================================================
> diff -Nrup a/sql/Makefile.am b/sql/Makefile.am
> --- a/sql/Makefile.am	2007-12-21 20:27:42 +01:00
> +++ b/sql/Makefile.am	2008-03-11 18:54:23 +01:00
> @@ -112,6 +112,7 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
>  			discover.cc time.cc opt_range.cc opt_sum.cc \
>  		   	records.cc filesort.cc handler.cc \
>  		        ha_partition.cc \
> +			debug_sync.cc \
>  			sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
>  			sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
>  			sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
====================================================================================
> diff -Nrup a/sql/debug_sync.cc b/sql/debug_sync.cc
> --- /dev/null	Wed Dec 31 16:00:00 196900
> +++ b/sql/debug_sync.cc	2008-03-11 18:54:24 +01:00
> @@ -0,0 +1,1527 @@
> +/* 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 */
> +
> +/*
> +  Debug Sync Facility.
> +
> +  The Debug Sync Facility allows to place synchronization points in the
> +  code:
> +
> +      open_tables(...)
> +
> +      DEBUG_SYNC(thd, "after_open_tables");
> +
> +      lock_tables(...)
> +
> +  When activated, a sync point can
> +
> +    - Send a signal and/or
> +    - Wait for a signal
> +
> +  Nomenclature:
> +
> +  - signal:             A value of a global variable that persists
> +                        until overwritten by a new signal. The global
> +                        variable can also be seen as a "signal post"
> +                        or "flag mast". Then the signal is what is
> +                        attached to the "signal post" or "flag mast".
> +
> +  - send a signal:      Assign the value (the signal) to the global
> +                        variable ("set a flag") and broadcast a
> +                        global condition to wake those waiting for
> +                        a signal.
> +
> +  - wait for a signal:  Loop over waiting for the global condition until
> +                        the global value matches the wait-for signal.
> +
> +  By default, all sync points are inactive. They do nothing (except of
> +  burning a couple of CPU cycles for checking if they are active).
> +
> +  A sync point becomes active when an action is requested for it:
> +
> +      SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed';
> +
> +  This activates the sync point 'after_open_tables'. It requests it to
> +  send the signal 'opened' and wait for another thread to send the signal
> +  'flushed' when the threads execution runs through the sync point.
> +
> +  For every sync point there can be one action per thread only. Every
> +  thread can request multiple actions, but only one per sync point. In
> +  other words, a thread can activate multiple sync points.
> +
> +  Here is an example how to activate and use the sync points:
> +
> +      --connection conn1
> +      SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed';
> +      send INSERT INTO t1 VALUES(1);
> +          --connection conn2
> +          SET DEBUG_SYNC= 'now WAIT_FOR opened';
> +          SET DEBUG_SYNC= 'after_abort_locks SIGNAL flushed';
> +          FLUSH TABLE t1;
> +
> +  When conn1 runs through the INSERT statement, it hits the sync point
> +  'after_open_tables'. It notices that it is active and executes its
> +  action. It sends the signal 'opened' and waits for another thread to
> +  send the signal 'flushed'.
> +
> +  conn2 waits immediately at the special sync point 'now' for another
> +  thread to send the 'opened' signal.
> +
> +  A signal remains in effect until it is overwritten. If conn1 signals
> +  'opened' before conn2 reaches 'now', it will still find the 'opened'
> +  signal. It does not wait in this case.
> +
> +  When conn2 reaches 'after_abort_locks', it signals 'flushed', which lets
> +  conn1 awake.
> +
> +  Normally the activation of a sync point is cleared when it has been
> +  executed. Sometimes it is necessary to keep the sync point active for
> +  another execution. You can add an execute count to the action:
> +
> +      SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 3';
> +
> +  This will set an activation counter to 3. Each execution decrements the
> +  counter. After the third execution the sync point becomes inactive in
> +  this example.
> +
> +  One of the primary goals of this facility is to eliminate sleeps from
> +  the test suite. In most cases it should be possible to rewrite test
> +  cases so that they do not need to sleep. (But this facility cannot
> +  synchronize multiple processes.) However to support developing of the
> +  tests, and as a last resort, sync point waiting times out. There is a
> +  default timeout, but it can be overridden:
> +
> +      SET DEBUG_SYNC= 'name WAIT_FOR sig TIMEOUT 10 EXECUTE 2';
> +
> +  TIMEOUT 0 is special: If the signal is not present, the wait times out
> +  immediately.
> +
> +  When a wait timed out (even on TIMEOUT 0), a warning is generated so
> +  that it shows up in the test result.
> +
> +  You can throw an error message and kill the query when a synchronization
> +  point is hit a certain number of times:
> +
> +      SET DEBUG_SYNC= 'name HIT_LIMIT 3';
> +
> +  Or combine it with signal and/or wait:
> +
> +      SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 2 HIT_LIMIT 3';
> +
> +  Here the first two hits send the signal, the third hit returns the error
> +  message and kills the query.
> +
> +  For cases where you are not sure that an action is taken and thus
> +  cleared in any case, you can force to clear (deactivate) a sync point:
> +
> +      SET DEBUG_SYNC= 'name CLEAR';
> +
> +  If you want to clear all actions and clear the global signal, use:
> +
> +      SET DEBUG_SYNC= 'RESET';
> +
> +  This is the only way to reset the global signal to an empty string.
> +
> +  For testing of the facility itself you can test a sync point:
> +
> +      SET DEBUG_SYNC= 'name TEST';
> +
> +
> +  ==== Activation/Deactivation ====
> +
> +  The facility is an optional part of the MySQL server.
> +
> +      ./configure --enable-debug-sync
> +
> +  The Debug Sync Facility, when compiled in, is disabled by default. It
> +  can be enabled by a mysqld command line option:
> +
> +      --debug-sync-timeout[=default_wait_timeout_value_in_seconds]
> +
> +  'default_wait_timeout_value_in_seconds' is the default timeout for the
> +  WAIT_FOR action. If set to zero, the facility stays disabled.
> +
> +  The facility is enabled by default in the test suite, but can be
> +  disabled with:
> +
> +      mysql-test-run.pl ... --debug-sync-timeout=0 ...
> +
> +  Likewise the default wait timeout can be set:
> +
> +      mysql-test-run.pl ... --debug-sync-timeout=10 ...
> +
> +
> +  ==== Implementation ====
> +
> +  Pseudo code for a sync point:
> +
> +      #define DEBUG_SYNC(thd, sync_point_name)
> +                if (unlikely(opt_debug_sync_timeout))
> +                  debug_sync(thd, STRING_WITH_LEN(sync_point_name))
> +
> +  The sync point performs a binary search in a sorted array of actions
> +  for this thread.
> +
> +  The SET DEBUG_SYNC statement adds a requested action to the array or
> +  overwrites an existing action for the same sync point. When it adds a
> +  new action, the array is sorted again.
> +*/
> +
> +#include "mysql_priv.h"
> +
> +#if defined(ENABLED_DEBUG_SYNC)
> +
> +/* Action to perform at a synchronization point. */
> +struct st_debug_sync_action
> +{
> +  ulong         activation_count;       /* max(hit_limit, execute) */
> +  ulong         hit_limit;              /* hits before kill query */
> +  ulong         execute;                /* executes before self-clear */
> +  ulong         timeout;                /* wait_for timeout */
> +  String        signal;                 /* signal to send */
> +  String        wait_for;               /* signal to wait for */
> +  String        sync_point;             /* sync point name */
> +  bool          need_sort;              /* if new action, array needs sort */
> +};
> +
> +/* Debug sync control. Referenced by THD. */
> +struct st_debug_sync_control
> +{
> +  st_debug_sync_action  *ds_action;             /* array of actions */

Wouldn't it be nicer to declare it as "st_debug_sync_action ds_action[]"?

Another thing - why not use dynamic array here and reuse the code from mysys 
library?

> +  uint                  ds_active;              /* # active actions */
> +  uint                  ds_allocated;           /* # allocated actions */
> +  ulonglong             dsp_hits;               /* statistics */
> +  ulonglong             dsp_executed;           /* statistics */
> +  ulonglong             dsp_max_active;         /* statistics */
> +};
> +
> +
> +/**
> +  Definitions for the debug sync facility.
> +  1. Global string variable to hold a "signal" ("signal post", "flag mast").
> +  2. Global condition variable for signalling and waiting.
> +  3. Global mutex to synchronize access to the above.
> +*/
> +struct st_debug_sync_globals
> +{
> +  String                ds_signal;              /* signal variable */
> +  pthread_cond_t        ds_cond;                /* condition variable */
> +  pthread_mutex_t       ds_mutex;               /* mutex variable */
> +  ulonglong             dsp_hits;               /* statistics */
> +  ulonglong             dsp_executed;           /* statistics */
> +  ulonglong             dsp_max_active;         /* statistics */
> +};
> +static st_debug_sync_globals debug_sync_global; /* All globals in one object */
> +
> +/**
> +  Callback pointer from thr_lock.cc
> +*/
> +extern void (*debug_sync_wait_for_lock_callback_ptr)(void);
> +
> +
> +/**
> +  Callback from wait_for_lock() for debug sync. See thr_lock.c.
> +
> +  @description
> +    One can use this to signal when a thread is going to wait for a lock.

I was bit confused looking at this callback function. Perhaps in the comment you 
could elaborate more on why you define it here and how it is used.

> +
> +  @note
> +    Beware of waiting for a signal here. The lock has aquired its mutex.
> +    While waiting on a signal here, the locking thread could not aquire
> +    the mutex to release the lock. One could lock up the table
> +    completely.

Hmm, I don't understand this note. But perhaps it's only me...

> +
> +  @note
> +    The callback pointer in thr_lock.c is set only if debug sync is
> +    initialized. And this is done only if opt_debug_sync_timeout is set.
> +*/
> +
> +static void debug_sync_wait_for_lock_callback(void)
> +{
> +  DEBUG_SYNC(current_thd, "wait_for_lock");
> +}
> +
> +
> +/**
> +  Initialize the debug sync facility at server start.
> +
> +  @return status
> +    @retval     0       ok
> +    @retval     != 0    error
> +*/
> +
> +int debug_sync_init(void)
> +{
> +  DBUG_ENTER("debug_sync_init");
> +
> +  if (opt_debug_sync_timeout)
> +  {
> +    /* Initialize the global variables. */
> +    debug_sync_global.ds_signal.length(0);
> +    (void) pthread_cond_init(&debug_sync_global.ds_cond, NULL);
> +    (void) pthread_mutex_init(&debug_sync_global.ds_mutex, MY_MUTEX_INIT_FAST);
> +
> +    /* Set the call back pointer in thr_lock.c. */
> +    debug_sync_wait_for_lock_callback_ptr=
> +      debug_sync_wait_for_lock_callback;
> +  }
> +
> +  DBUG_RETURN(0);
> +}
> +
> +
> +/**
> +  End the debug sync facility.
> +
> +  @description
> +    This is called at server shutdown or after a thread initialization error.
> +*/
> +
> +void debug_sync_end(void)
> +{
> +  DBUG_ENTER("debug_sync_end");
> +
> +  /* End the facility only if it had been initialized. */
> +  if (debug_sync_wait_for_lock_callback_ptr)
> +  {
> +    /* Clear the call back pointer in thr_lock.c. */
> +    debug_sync_wait_for_lock_callback_ptr= NULL;
> +
> +    /* Destroy the global variables. */
> +    debug_sync_global.ds_signal.free();
> +    (void) pthread_cond_destroy(&debug_sync_global.ds_cond);
> +    (void) pthread_mutex_destroy(&debug_sync_global.ds_mutex);
> +
> +    /* Print statistics. */
> +    {
> +      char llbuff[22];
> +      sql_print_information("Debug sync points hit:                   %22s",
> +                            llstr(debug_sync_global.dsp_hits, llbuff));
> +      sql_print_information("Debug sync points executed:              %22s",
> +                            llstr(debug_sync_global.dsp_executed, llbuff));
> +      sql_print_information("Debug sync points max active per thread: %22s",
> +                            llstr(debug_sync_global.dsp_max_active, llbuff));
> +    }
> +  }
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/* purecov: begin tested */
> +
> +/**
> +  Disable the facility after lack of memory if no error can be returned.
> +
> +  @param[in]    thd             thread handle
> +
> +  @note
> +    Do not end the facility here because the global variables can
> +    be in use by other threads.
> +*/
> +
> +static void debug_sync_emergency_disable(THD *thd)
> +{
> +  DBUG_ENTER("debug_sync_emergency_disable");
> +
> +  opt_debug_sync_timeout= 0;
> +
> +  DBUG_PRINT("debug_sync",
> +             ("Debug Sync Facility disabled due to lack of memory."));
> +  sql_print_error("Debug Sync Facility disabled due to lack of memory.");
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +/* purecov: end */
> +
> +
> +/**
> +  Initialize the debug sync facility at thread start.
> +
> +  @param[in]    thd             thread handle
> +*/
> +
> +void debug_sync_init_thread(THD *thd)
> +{
> +  DBUG_ENTER("debug_sync_init_thread");
> +
> +  if (opt_debug_sync_timeout)
> +  {
> +    thd->debug_sync_control= (st_debug_sync_control*)
> +      my_malloc(sizeof(st_debug_sync_control), MYF(MY_WME | MY_ZEROFILL));
> +    if (!thd->debug_sync_control)
> +    {
> +      /*
> +        Error is reported by my_malloc().
> +        We must disable the facility. We have no way to return an error.
> +      */
> +      debug_sync_emergency_disable(thd); /* purecov: tested */
> +    }
> +  }
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/**
> +  Free sync point actions.
> +
> +  @param[in]    action          first action
> +  @param[in]    count           number of actions to free
> +*/
> +
> +static void debug_sync_free_actions(st_debug_sync_action *action, uint count)
> +{
> +  st_debug_sync_action *action_end= action + count;
> +  DBUG_ENTER("debug_sync_free_actions");
> +
> +  for (; action < action_end; action++)
> +  {
> +    action->signal.free();
> +    action->wait_for.free();
> +    action->sync_point.free();
> +  }
> +  DBUG_VOID_RETURN;
> +}
> +

It is just a suggestion, but adding constructor/destructor to 
st_debug_sync_action structure would mke the code look nicer and easier to 
maintain IMO.

> +
> +/**
> +  End the debug sync facility at thread end.
> +
> +  @param[in]    thd             thread handle
> +*/
> +
> +void debug_sync_end_thread(THD *thd)
> +{
> +  DBUG_ENTER("debug_sync_end_thread");
> +
> +  if (thd->debug_sync_control)
> +  {
> +    st_debug_sync_control *ds_control= thd->debug_sync_control;
> +
> +    if (ds_control->ds_action)
> +    {
> +      debug_sync_free_actions(ds_control->ds_action,
> ds_control->ds_allocated);
> +      my_free(ds_control->ds_action, MYF(0));
> +    }
> +
> +    /* Statistics. */
> +    pthread_mutex_lock(&debug_sync_global.ds_mutex);
> +    debug_sync_global.dsp_hits+=           ds_control->dsp_hits;
> +    debug_sync_global.dsp_executed+=       ds_control->dsp_executed;
> +    if (debug_sync_global.dsp_max_active < ds_control->dsp_max_active)
> +      debug_sync_global.dsp_max_active=    ds_control->dsp_max_active;
> +    pthread_mutex_unlock(&debug_sync_global.ds_mutex);
> +
> +    my_free(ds_control, MYF(0));
> +    thd->debug_sync_control= NULL;
> +  }
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/**
> +  Move a string by length.
> +
> +  @param[out]   to              buffer for the resulting string
> +  @param[in]    to_end          end of buffer
> +  @param[in]    from            source string
> +  @param[in]    length          number of bytes to copy
> +
> +  @return       pointer to end of copied string
> +*/
> +
> +static char *debug_sync_bmove_len(char *to, char *to_end,
> +                                  const char *from, size_t length)
> +{
> +  set_if_smaller(length, (size_t) (to_end - to));
> +  memcpy(to, from, length);
> +  return (to + length);
> +}
> +
> +
> +#if !defined(DBUG_OFF)
> +
> +/**
> +  Create a string that describes an action.
> +
> +  @param[out]   result          buffer for the resulting string
> +  @param[in]    size            size of result buffer
> +  @param[in]    action          action to describe
> +*/
> +
> +static void debug_sync_action_string(char *result, uint size,
> +                                     st_debug_sync_action *action)
> +{
> +  char  *wtxt= result;
> +  char  *wend= wtxt + size - 1; /* Allow emergency '\0'. */
> +  DBUG_ENTER("debug_sync_action_string");
> +
> +  /* There must not be inactive actions in the array. */
> +  DBUG_ASSERT(action->activation_count);
> +
> +  /* If an execute count is present, signal or wait_for are needed too. */
> +  DBUG_ASSERT(!action->execute ||
> +              action->signal.length() || action->wait_for.length());
> +
> +  if (action->execute)
> +  {
> +    if (action->signal.length())
> +    {
> +      wtxt= debug_sync_bmove_len(wtxt, wend, STRING_WITH_LEN("SIGNAL "));
> +      wtxt= debug_sync_bmove_len(wtxt, wend, action->signal.ptr(),
> +                                 action->signal.length());
> +    }
> +    if (action->wait_for.length())
> +    {
> +      if ((wtxt == result) && (wtxt < wend))
> +        *(wtxt++)= ' ';
> +      wtxt= debug_sync_bmove_len(wtxt, wend, STRING_WITH_LEN("WAIT_FOR "));
> +      wtxt= debug_sync_bmove_len(wtxt, wend, action->wait_for.ptr(),
> +                                 action->wait_for.length());
> +
> +      if (action->timeout != opt_debug_sync_timeout)
> +      {
> +        wtxt+= my_snprintf(wtxt, wend - wtxt, " TIMEOUT %lu", action->timeout);
> +      }
> +    }
> +    if (action->execute != 1)
> +    {
> +      wtxt+= my_snprintf(wtxt, wend - wtxt, " EXECUTE %lu", action->execute);
> +    }
> +  }
> +  if (action->hit_limit)
> +  {
> +    wtxt+= my_snprintf(wtxt, wend - wtxt, "%sHIT_LIMIT %lu",
> +                       (wtxt == result) ? "" : " ", action->hit_limit);
> +  }
> +
> +  /*
> +    If (wtxt == wend) string may not be terminated.
> +    There is one byte left for an emergency termination.
> +  */
> +  *wtxt= '\0';
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/**
> +  Print actions.
> +
> +  @param[in]    thd             thread handle
> +*/
> +
> +static void debug_sync_print_actions(THD *thd)
> +{
> +  st_debug_sync_control *ds_control= thd->debug_sync_control;
> +  uint                  idx;
> +  DBUG_ENTER("debug_sync_print_actions");
> +
> +  if (!ds_control)
> +    return;
> +
> +  for (idx= 0; idx < ds_control->ds_active; idx++)
> +  {
> +    if (ds_control->ds_action[idx].activation_count)
> +    {
> +      char action_string[256];
> +
> +      debug_sync_action_string(action_string, sizeof(action_string),
> +                               ds_control->ds_action + idx);
> +      DBUG_PRINT("debug_sync_list",
> +                 ("%s %s", ds_control->ds_action[idx].sync_point.c_ptr(),
> +                  action_string));
> +    }
> +  }
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +#endif /* !defined(DBUG_OFF) */
> +
> +
> +/**
> +  Compare two actions by sync point name length, string.
> +
> +  @param[in]    arg1            reference to action1
> +  @param[in]    arg2            reference to action2
> +
> +  @return       difference
> +    @retval     == 0            length1/string1 is same as length2/string2
> +    @retval     < 0             length1/string1 is smaller
> +    @retval     > 0             length1/string1 is bigger
> +*/
> +
> +static int debug_sync_qsort_cmp(const void* arg1, const void* arg2)
> +{
> +  st_debug_sync_action *action1= (st_debug_sync_action*) arg1;
> +  st_debug_sync_action *action2= (st_debug_sync_action*) arg2;
> +  int diff;
> +
> +  if (!(diff= action1->sync_point.length() - action2->sync_point.length()))
> +    diff= memcmp(action1->sync_point.ptr(), action2->sync_point.ptr(),
> +                 action1->sync_point.length());
> +
> +  return diff;
> +}
> +
> +
> +/**
> +  Find a debug sync action.
> +
> +  @param[in]    actionarr       array of debug sync actions
> +  @param[in]    quantity        number of actions in array
> +  @param[in]    dsp_name        name of debug sync point to find
> +  @param[in]    name_len        length of name of debug sync point
> +
> +  @return       action
> +    @retval     != NULL         found sync point in array
> +    @retval     NULL            not found
> +
> +  @description
> +    Binary search. Array needs to be sorted by length, sync point name.
> +*/
> +
> +static st_debug_sync_action *debug_sync_find(st_debug_sync_action *actionarr,
> +                                             int quantity,
> +                                             const char* dsp_name,
> +                                             uint name_len)
> +{
> +  st_debug_sync_action  *action;
> +  int                   low ;
> +  int                   high ;
> +  int                   mid ;
> +  int                   diff ;
> +
> +  low= 0;
> +  high= quantity;
> +
> +  while (low < high)
> +  {
> +    mid= (low + high) / 2;
> +    action= actionarr + mid;

What if actionarr is NULL?

> +    if (!(diff= name_len - action->sync_point.length()) &&
> +        !(diff= memcmp(dsp_name, action->sync_point.ptr(), name_len)))
> +      return action;
> +    if (diff > 0)
> +      low= mid + 1;
> +    else
> +      high= mid - 1;
> +  }
> +
> +  if (low < quantity)
> +  {
> +    action= actionarr + low;
> +    if ((name_len == action->sync_point.length()) &&
> +        !memcmp(dsp_name, action->sync_point.ptr(), name_len))
> +      return action;
> +  }
> +
> +  return NULL;
> +}
> +
> +
> +/**
> +  Reset the debug sync facility.
> +
> +  @param[in]    thd             thread handle
> +
> +  @description
> +    Remove all actions of this thread.
> +    Clear the global signal.
> +*/
> +
> +static void debug_sync_reset(THD *thd)
> +{
> +  st_debug_sync_control *ds_control= thd->debug_sync_control;
> +  DBUG_ENTER("debug_sync_reset");
> +
> +  /* Remove all actions of this thread. */
> +  ds_control->ds_active= 0;

What if ds_control is NULL?

> +
> +  /* Clear the global signal. */
> +  debug_sync_global.ds_signal.length(0);
> +

Don't we need to call String destructors for all stored actions?

> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/**
> +  Remove a debug sync action.
> +
> +  @param[in]    ds_control      control object
> +  @param[in]    action          action to be removed
> +
> +  @description
> +    Removing an action mainly means to decrement the ds_active counter.
> +    But if the action is between other active action in the array, then
> +    the array needs to be shrinked. The active actions above the one to
> +    be removed have to be moved down by one slot.
> +*/
> +
> +static void debug_sync_remove_action(st_debug_sync_control *ds_control,
> +                                     st_debug_sync_action *action)
> +{


DBUG_ASSERT(ds_control) ?
DBUG_ASSERT(action) ?

> +  uint dsp_idx= action - ds_control->ds_action;

This code will break if we store pointer to an action, then add new actions to 
ds_control->ds_action so that it is re-allocated to a new location and then try 
to remove stored action... Should be documented as precondition for this 
function or... a safer implementation used.

> +  DBUG_ENTER("debug_sync_remove_action");
> +  DBUG_ASSERT(dsp_idx < ds_control->ds_active);
> +
> +  /* Decrement the number of currently active actions. */
> +  ds_control->ds_active--;
> +
> +  /*
> +    If this was not the last active action in the array, we need to
> +    shift remaining active actions down to keep the array gap-free.
> +    Otherwise binary search might fail or take longer than necessary at
> +    least. Also new actions are always put to the end of the array.
> +  */
> +  if (ds_control->ds_active > dsp_idx)
> +  {
> +    /* Free strings before copying them over. */
> +    debug_sync_free_actions(action, 1);
> +
> +    /* Move actions down. */
> +    memmove(ds_control->ds_action + dsp_idx,
> +            ds_control->ds_action + dsp_idx + 1,
> +            (ds_control->ds_active - dsp_idx) *
> +            sizeof(st_debug_sync_action));
> +
> +    /* Remove double references of String pointers. */
> +    bzero(ds_control->ds_action +
> +          ds_control->ds_active, sizeof(st_debug_sync_action));

To my taste it is too dangerous to move constructed objects like this. My 
objections are:

- I'm not sure if C++ compilers guarantee (and will guarantee that in the 
future) that if x is an object of type X and you move sizeof(X) bytes from &x to 
a different addres b then you will get a valid instance of X object at b

- In the future one can change either st_debug_sync_action or String class. A 
possible change is to add member with non-trivial copy constructor (e.g. with 
reference couts). Then above code will break things.

Btw. Have you considered using some pointer structure (binary search tree or 
even a simple linked list) for storing actions. Then there will be no need to 
move objects around.

> +  }
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/**
> +  Get a debug sync action.
> +
> +  @param[in]    thd             thread handle
> +  @param[in]    dsp_name        debug sync point name
> +  @param[in]    name_len        length of sync point name
> +
> +  @return       action
> +    @retval     != NULL         ok
> +    @retval     NULL            error
> +
> +  @description
> +    Find the debug sync action for a debug sync point or make a new one.
> +*/
> +
> +static st_debug_sync_action *debug_sync_get_action(THD *thd,
> +                                                   const char *dsp_name,
> +                                                   uint name_len)
> +{
> +  st_debug_sync_control *ds_control= thd->debug_sync_control;
> +  st_debug_sync_action  *action;
> +  DBUG_ENTER("debug_sync_get_action");
> +  DBUG_PRINT("debug_sync", ("sync_point: '%.*s'", (int) name_len, dsp_name));
> +

DBUG_ASSERT(ds_control) ?

> +  /* There cannot be more active actions than allocated. */
> +  DBUG_ASSERT(ds_control->ds_active <= ds_control->ds_allocated);
> +  /* If there are active actions, the action array must be present. */
> +  DBUG_ASSERT(!ds_control->ds_active || ds_control->ds_action);
> +
> +  /* Try to reuse existing action if there is one for this sync point. */
> +  if (ds_control->ds_active &&
> +      (action= debug_sync_find(ds_control->ds_action, ds_control->ds_active,
> +                               dsp_name, name_len)))
> +  {
> +    /* Reuse an already active sync point action. */
> +    DBUG_ASSERT((action - ds_control->ds_action) < ds_control->ds_active);
> +    DBUG_PRINT("debug_sync", ("reuse action idx: %ld",
> +                              action - ds_control->ds_action));
> +  }
> +  else
> +  {
> +    /* Create a new action. */
> +    int dsp_idx= ds_control->ds_active++;
> +    set_if_bigger(ds_control->dsp_max_active, ds_control->ds_active);
> +    if (ds_control->ds_active > ds_control->ds_allocated)
> +    {
> +      uint new_alloc= ds_control->ds_active + 3;
> +      void *new_action= my_realloc(ds_control->ds_action,
> +                                   new_alloc * sizeof(st_debug_sync_action),
> +                                   MYF(MY_WME | MY_ALLOW_ZERO_PTR));

Is it the case that if my_realloc moves the memory to a different location it 
copies all the bytes from the old location?

> +      if (!new_action)
> +      {
> +        /* Error is reported by my_malloc(). */
> +        goto err; /* purecov: tested */
> +      }
> +      ds_control->ds_action= (st_debug_sync_action*) new_action;
> +      ds_control->ds_allocated= new_alloc;
> +      /* Clear memory as we do not run string constructors here. */
> +      bzero((uchar*) (ds_control->ds_action + dsp_idx),
> +            (new_alloc - dsp_idx) * sizeof(st_debug_sync_action));
> +    }
> +    DBUG_PRINT("debug_sync", ("added action idx: %u", dsp_idx));
> +    action= ds_control->ds_action + dsp_idx;
> +    if (action->sync_point.copy(dsp_name, name_len, system_charset_info))
> +    {
> +      /* Error is reported by my_malloc(). */
> +      goto err; /* purecov: tested */
> +    }
> +    action->need_sort= TRUE;
> +  }
> +  DBUG_ASSERT(action >= ds_control->ds_action);
> +  DBUG_ASSERT(action < ds_control->ds_action + ds_control->ds_active);
> +  DBUG_PRINT("debug_sync", ("que action: 0x%lx  beg: 0x%lx  count: %u",
> +                            (long) action, (long) ds_control->ds_action,
> +                            ds_control->ds_active));
> +
> +  DBUG_RETURN(action);
> +
> + err:
> +  DBUG_RETURN(NULL);
> +}
> +
> +
> +/**
> +  Set a debug sync action.
> +
> +  @param[in]    thd             thread handle
> +  @param[in]    action          synchronization action
> +
> +  @return       status
> +    @retval     FALSE           ok
> +    @retval     TRUE            error
> +
> +  @description
> +    This is called from the debug sync parser.

Perhaps elaborate more what does that mean to "set an action".

> +*/
> +
> +static bool debug_sync_set_action(THD *thd, st_debug_sync_action *action)
> +{
> +  st_debug_sync_control *ds_control= thd->debug_sync_control;
> +  bool is_dsp_now= FALSE;
> +  DBUG_ENTER("debug_sync_set_action");
> +  DBUG_ASSERT(ds_control);

You also assume action != NULL.

> +
> +  action->activation_count= max(action->hit_limit, action->execute);
> +  if (!action->activation_count)
> +  {
> +    debug_sync_remove_action(ds_control, action);
> +    DBUG_PRINT("debug_sync", ("action cleared"));
> +  }
> +  else
> +  {
> +    DBUG_PRINT("debug_sync",
> +               ("sync_point: '%s'  activation_count: %lu  hit_limit: %lu  "
> +                "execute: %lu  timeout: %lu  signal: '%s'  wait_for: '%s'",
> +                action->sync_point.c_ptr(), action->activation_count,
> +                action->hit_limit, action->execute, action->timeout,
> +                action->signal.c_ptr(), action->wait_for.c_ptr()));
> +
> +    /* Check this before sorting the array. action may move. */
> +    is_dsp_now= !my_strcasecmp(system_charset_info,
> +                               action->sync_point.c_ptr(), "now");
> +
> +    if (action->need_sort)
> +    {
> +      action->need_sort= FALSE;
> +      /* Sort actions by (name_len, name). */
> +      my_qsort(ds_control->ds_action, ds_control->ds_active,
> +               sizeof(st_debug_sync_action), debug_sync_qsort_cmp);
> +    }
> +  }
> +  DBUG_EXECUTE("debug_sync_list", debug_sync_print_actions(thd););
> +
> +  /* Execute the special sync point 'now' if activated above. */
> +  if (is_dsp_now)
> +  {
> +    DEBUG_SYNC(thd, "now");
> +    /* If HIT_LIMIT is 1, return error to suppress send_ok(). */

I don't understand the above comment...

> +    if (thd->killed)
> +      goto err;
> +  }
> +
> +  DBUG_RETURN(FALSE);
> +
> + err:
> +  DBUG_RETURN(TRUE);
> +}
> +
> +
> +/**
> +  Extract a token from a string.
> +
> +  @param[out]   token_p         returns start of token
> +  @param[out]   token_length_p  returns length of token
> +  @param[in]    ptr             current string pointer
> +
> +  @return       string pointer or NULL
> +    @retval     != NULL         ptr behind token terminator or at string end
> +    @retval     NULL            no token found in remainder of string
> +
> +  @note
> +    This function assumes that the string is in system_charset_info,
> +    that this charset is single byte for ASCII NUL ('\0'), that no
> +    character except of ASCII NUL ('\0') contains a byte with value 0,
> +    and that ASCII NUL ('\0') is used as the string terminator.
> +
> +    This function needs to return tokens that are terminated with ASCII
> +    NUL ('\0'). The tokens are used in my_strcasecmp(). Unfortunately
> +    there is no my_strncasecmp().
> +
> +    To return the last token without copying it, we require the input
> +    string to be nul terminated.
> +
> +  @description
> +    This function skips space characters at string begin.
> +
> +    It returns a pointer to the first non-space character in *token_p.
> +
> +    If no non-space character is found before the string terminator
> +    ASCII NUL ('\0'), the function returns NULL. *token_p and
> +    *token_length_p remain unchanged in this case (they are not set).
> +
> +    The function takes a space character or an ASCII NUL ('\0') as a
> +    terminator of the token. The space character could be multi-byte.
> +
> +    It returns the length of the token in bytes, excluding the
> +    terminator, in *token_length_p.
> +
> +    If the terminator of the token is ASCII NUL ('\0'), it returns a
> +    pointer to the terminator (string end).
> +
> +    If the terminator is a space character, it replaces the the first
> +    byte of the terminator character by ASCII NUL ('\0'), skips the (now
> +    corrupted) terminator character, and skips all following space
> +    characters. It returns a pointer to the next non-space character or
> +    to the string terminator ASCII NUL ('\0').
> +*/
> +
> +static char *debug_sync_token(char **token_p, uint *token_length_p, char *ptr)
> +{

How about asserting here that token_p, token_length_p and ptr are not NULL? The 
code below uses that assumption.

> +  /* Skip leading space */
> +  while (my_isspace(system_charset_info, *ptr))
> +    ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr);
> +
> +  if (!*ptr)
> +  {
> +    ptr= NULL;
> +    goto end;
> +  }
> +
> +  /* Get token start. */
> +  *token_p= ptr;
> +
> +  /* Find token end. */
> +  while (*ptr && !my_isspace(system_charset_info, *ptr))
> +    ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr);
> +
> +  /* Get token length. */
> +  *token_length_p= ptr - *token_p;
> +
> +  /* If necessary, terminate token. */
> +  if (*ptr)
> +  {
> +    /* Get terminator character length. */
> +    uint mbspacelen= my_mbcharlen(system_charset_info, (uchar) *ptr);
> +
> +    /* Terminate token. */
> +    *ptr= '\0';
> +
> +    /* Skip the terminator. */
> +    ptr+= mbspacelen;
> +
> +    /* Skip trailing space */
> +    while (my_isspace(system_charset_info, *ptr))
> +      ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr);
> +  }
> +
> + end:
> +  return ptr;
> +}
> +
> +
> +/**
> +  Extract a number from a string.
> +
> +  @param[out]   number_p        returns number
> +  @param[in]    ptr             current string pointer
> +
> +  @return       string pointer or NULL
> +    @retval     != NULL         ptr behind token terminator or at string end
> +    @retval     NULL            no token found or token is not valid number
> +
> +  @note
> +    The same assumptions about charset apply as for debug_sync_token().
> +
> +  @description
> +    This function fetches a token from the string and converts it
> +    into a number.
> +
> +    If there is no token left in the string, or the token is not a valid
> +    decimal number, NULL is returned. The result in *number_p is
> +    undefined in this case.
> +*/
> +
> +static char *debug_sync_number(ulong *number_p, char *ptr)
> +{
> +  char                  *ept;
> +  char                  *token;
> +  uint                  token_length;
> +
> +  /* Get token from string. */
> +  if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +    goto end;
> +
> +  *number_p= strtoul(token, &ept, 10);
> +  if (*ept)
> +    ptr= NULL;
> +
> + end:
> +  return ptr;
> +}
> +
> +
> +/**
> +  Evaluate a debug sync action string.
> +
> +  @param[in]        thd             thread handle
> +  @param[in,out]    action_str      action string to receive '\0' terminators
> +
> +  @return           status
> +    @retval         FALSE           ok
> +    @retval         TRUE            error
> +
> +  @description
> +    This is called when the DEBUG_SYNC system variable is set.
> +    Parse action string, build a debug sync action, activate it.

Mention that the result of parsing is stored inside thd's action table.

> +
> +  @note
> +    The input string needs to be ASCII NUL ('\0') terminated. We split
> +    nul-terminated tokens in it without copy.

Perhaps add here all the other assumptions about action_str. For example, that 
it must be in system character set.

> +*/
> +

This is the grammar for command strings which I deduced from 
reverse-engenieering the code (there are additional constraints, for example 
EXECUTE must be preceeded by SIGNAL or WAIT_FOR:

RESET
<point name> TEST
<point name> CLEAR
<point name> [SIGNAL <signal name>] [WAIT_FOR <signal name> [TIMEOUT
<seconds>]]
              [EXECUTE <count>] [HIT_LIMIT <count>]

Would be good if this grammar is documented somewhere. In particular, the order 
of actions is fixed which is not clearly documented in the existing documentation.

> +static bool debug_sync_eval_action(THD *thd, char *action_str)

How about calling it debug_sync_parse_action instead?

> +{
> +  st_debug_sync_action  *action= NULL;
> +  const char            *errmsg;
> +  char                  *ptr;
> +  char                  *token;
> +  uint                  token_length;
> +  DBUG_ENTER("debug_sync_eval_action");
> +
> +  /*
> +    Get debug sync point name. Or a special command.
> +  */
> +  if (!(ptr= debug_sync_token(&token, &token_length, action_str)))
> +  {
> +    errmsg= "Missing synchronization point name";

Why error messages are not internationalized?

> +    goto err;
> +  }
> +
> +  /*
> +    If there is a second token, the first one is the sync point name.
> +  */
> +  if (*ptr)
> +  {
> +    /* Get an action object to collect the requested action parameters. */
> +    action= debug_sync_get_action(thd, token, token_length);
> +    if (!action)
> +    {
> +      /* Error message is sent. */
> +      DBUG_RETURN(TRUE);
> +    }
> +  }
> +
> +  /*
> +    Get kind of action to be taken at sync point.
> +  */
> +  if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +  {
> +    /* No action present. Try special commands. Token unchanged. */
> +
> +    /*
> +      Try RESET.
> +    */
> +    if (!my_strcasecmp(system_charset_info, token, "RESET"))
> +    {
> +      /* It is RESET. Reset all actions and global signal. */
> +      debug_sync_reset(thd);
> +      goto end;
> +    }
> +
> +    /* Token unchanged. It still contains sync point name. */
> +    errmsg= "Missing action after synchronization point name '%.*s'";
> +    goto err;
> +  }
> +
> +  /*
> +    Check for pseudo actions first. Start with actions that work on
> +    an existing action.
> +  */
> +  DBUG_ASSERT(action);
> +
> +  /*
> +    Try TEST.
> +  */
> +  if (!my_strcasecmp(system_charset_info, token, "TEST"))
> +  {
> +    /* It is TEST. Nothing must follow it. */
> +    if (*ptr)
> +    {
> +      errmsg= "Nothing must follow action TEST";
> +      goto err;
> +    }
> +
> +    /* Execute sync point. */
> +    debug_sync(thd, action->sync_point.ptr(), action->sync_point.length());
> +    /* Fix statistics. This was not a real hit of the sync point. */
> +    thd->debug_sync_control->dsp_hits--;
> +    goto end;
> +  }
> +
> +  /*
> +    Now check for actions that define a new action.
> +    Initialize action. Do not use bzero(). Strings may have malloced.
> +  */
> +  action->activation_count= 0;
> +  action->hit_limit= 0;
> +  action->execute= 0;
> +  action->timeout= 0;
> +  action->signal.length(0);
> +  action->wait_for.length(0);
> +

Use of constructor would be nice...

> +  /*
> +    Try CLEAR.
> +  */
> +  if (!my_strcasecmp(system_charset_info, token, "CLEAR"))
> +  {
> +    /* It is CLEAR. Nothing must follow it. */
> +    if (*ptr)
> +    {
> +      errmsg= "Nothing must follow action CLEAR";
> +      goto err;
> +    }
> +
> +    /* Set (clear/remove) action. */
> +    goto set_action;
> +  }
> +
> +  /*
> +    Now check for real sync point actions.
> +  */
> +
> +  /*
> +    Try SIGNAL.
> +  */
> +  if (!my_strcasecmp(system_charset_info, token, "SIGNAL"))
> +  {
> +    /* It is SIGNAL. Signal name must follow. */
> +    if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +    {
> +      errmsg= "Missing signal name after action SIGNAL";
> +      goto err;
> +    }
> +    if (action->signal.copy(token, token_length, system_charset_info))
> +    {
> +      /* Error is reported by my_malloc(). */
> +      errmsg= NULL;
> +      goto err; /* purecov: tested */
> +    }
> +
> +    /* Set default for EXECUTE option. */
> +    action->execute= 1;
> +
> +    /* Get next token. If none follows, set action. */
> +    if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +      goto set_action;
> +  }
> +
> +  /*
> +    Try WAIT_FOR.
> +  */
> +  if (!my_strcasecmp(system_charset_info, token, "WAIT_FOR"))
> +  {
> +    /* It is WAIT_FOR. Wait_for signal name must follow. */
> +    if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +    {
> +      errmsg= "Missing signal name after action WAIT_FOR";
> +      goto err;
> +    }
> +    if (action->wait_for.copy(token, token_length, system_charset_info))
> +    {
> +      /* Error is reported by my_malloc(). */
> +      errmsg= NULL;
> +      goto err; /* purecov: tested */
> +    }
> +
> +    /* Set default for EXECUTE and TIMEOUT options. */
> +    action->execute= 1;
> +    action->timeout= opt_debug_sync_timeout;
> +
> +    /* Get next token. If none follows, set action. */
> +    if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +      goto set_action;
> +
> +    /*
> +      Try TIMEOUT.
> +    */
> +    if (!my_strcasecmp(system_charset_info, token, "TIMEOUT"))
> +    {
> +      /* It is TIMEOUT. Number must follow. */
> +      if (!(ptr= debug_sync_number(&action->timeout, ptr)))
> +      {
> +        errmsg= "Missing valid number after TIMEOUT";
> +        goto err;
> +      }
> +
> +      /* Get next token. If none follows, set action. */
> +      if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +        goto set_action;
> +    }
> +  }
> +
> +  /*
> +    Try EXECUTE.
> +  */
> +  if (!my_strcasecmp(system_charset_info, token, "EXECUTE"))
> +  {
> +    /*
> +      EXECUTE requires either SIGNAL and/or WAIT_FOR to be present.
> +      In this case action->execute has been preset to 1.
> +    */
> +    if (!action->execute)
> +    {
> +      errmsg= "Missing action before EXECUTE";
> +      goto err;
> +    }
> +
> +    /* Number must follow. */
> +    if (!(ptr= debug_sync_number(&action->execute, ptr)))
> +    {
> +      errmsg= "Missing valid number after EXECUTE";
> +      goto err;
> +    }
> +
> +    /* Get next token. If none follows, set action. */
> +    if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +      goto set_action;
> +  }
> +
> +  /*
> +    Try HIT_LIMIT.
> +  */
> +  if (!my_strcasecmp(system_charset_info, token, "HIT_LIMIT"))
> +  {
> +    /* Number must follow. */
> +    if (!(ptr= debug_sync_number(&action->hit_limit, ptr)))
> +    {
> +      errmsg= "Missing valid number after HIT_LIMIT";
> +      goto err;
> +    }
> +
> +    /* Get next token. If none follows, set action. */
> +    if (!(ptr= debug_sync_token(&token, &token_length, ptr)))
> +      goto set_action;
> +  }
> +
> +  errmsg= "Illegal or out of order stuff: '%.*s'";
> +
> + err:
> +  if (errmsg)
> +  {
> +    /*
> +      NOTE: errmsg must either have %.*s or none % at all.
> +      It can be NULL if an error message is already reported
> +      (e.g. by my_malloc()).
> +    */
> +    set_if_smaller(token_length, 64); /* Limit error message length. */
> +    my_printf_error(ER_PARSE_ERROR, errmsg, MYF(0), token_length, token);
> +  }
> +  DBUG_RETURN(TRUE);
> +
> + set_action:
> +  DBUG_RETURN(debug_sync_set_action(thd, action));
> +
> + end:
> +  DBUG_RETURN(FALSE);
> +}
> +
> +
> +/**
> +  Check if the system variable 'debug_sync' can be set.
> +
> +  @param[in]    thd             thread handle
> +  @param[in]    var             set variable request
> +
> +  @return       status
> +    @retval     FALSE           ok, variable can be set
> +    @retval     TRUE            error, variable cannot be set
> +*/
> +
> +bool sys_var_debug_sync::check(THD *thd, set_var *var)
> +{
> +  DBUG_ENTER("sys_var_debug_sync::check");
> +
> +  /* Variable can be set for the session only. */
> +  if (var->type == OPT_GLOBAL)
> +  {
> +    my_error(ER_WRONG_OBJECT, MYF(0), "SESSION", name, "global variable");
> +    DBUG_RETURN(TRUE);
> +  }
> +
> +  /*
> +    Do not check for disabled facility. Test result should not
> +    unnecessarily differ from enabled facility.
> +  */
> +
> +  /*
> +    Facility requires SUPER privilege. Sync points could be inside
> +    global mutexes (e.g. LOCK_open). Waiting there forever would
> +    stall the whole server.
> +  */
> +  DBUG_RETURN(check_global_access(thd, SUPER_ACL));
> +}
> +
> +
> +/**
> +  Set the system variable 'debug_sync'.
> +
> +  @param[in]    thd             thread handle
> +  @param[in]    var             set variable request
> +
> +  @return       status
> +    @retval     FALSE           ok, variable is set
> +    @retval     TRUE            error, variable could not be set
> +
> +  @note
> +    "Setting" of the system variable 'debug_sync' does not mean to
> +    assign a value to it as usual. Instead a debug sync action is parsed
> +    from the input string and stored apart from the variable value.
> +*/
> +
> +bool sys_var_debug_sync::update(THD *thd, set_var *var)
> +{
> +  char empty= '\0';
> +  char *val_str= var ? var->value->str_value.c_ptr() : &empty;
> +  DBUG_ENTER("sys_var_debug_sync::update");
> +
> +  DBUG_PRINT("debug_sync", ("set action: '%s'", val_str));
> +
> +  DBUG_RETURN(opt_debug_sync_timeout ?
> +              debug_sync_eval_action(thd, val_str) :
> +              FALSE);
> +}
> +
> +
> +/**
> +  Retrieve the value of the system variable 'debug_sync'.
> +
> +  @param[in]    thd             thread handle
> +  @param[in]    type            variable type, unused
> +  @param[in]    base            variable base, unused
> +
> +  @return       string
> +    @retval     != NULL         ok, string pointer
> +    @retval     NULL            memory allocation error
> +
> +  @note
> +    The value of the system variable 'debug_sync' reflects if
> +    the facility is enabled ("ON") or disabled (default, "OFF").
> +
> +    When "ON", the current signal is added.
> +*/
> +
> +uchar *sys_var_debug_sync::value_ptr(THD *thd,
> +                                     enum_var_type type __attribute__((unused)),
> +                                     LEX_STRING *base __attribute__((unused)))
> +{
> +  char *value;
> +  DBUG_ENTER("sys_var_debug_sync::value_ptr");
> +
> +  if (opt_debug_sync_timeout)
> +  {
> +    static char on[]= "ON - current signal: '";
> +    size_t lgt= (sizeof(on) /* includes '\0' */ +
> +                 debug_sync_global.ds_signal.length() + 1 /* for '\'' */);
> +    char *vend;
> +    char *vptr;
> +
> +    if ((value= (char*) alloc_root(thd->mem_root, lgt)))
> +    {
> +      vend= value + lgt - 1; /* reserve space for '\0'. */
> +      vptr= debug_sync_bmove_len(value, vend, STRING_WITH_LEN(on));
> +      vptr= debug_sync_bmove_len(vptr, vend, debug_sync_global.ds_signal.ptr(),
> +                                 debug_sync_global.ds_signal.length());
> +      if (vptr < vend)
> +        *(vptr++)= '\'';
> +      *vptr= '\0'; /* We have one byte reserved for the worst case. */
> +    }
> +  }
> +  else
> +    value= strmake_root(thd->mem_root, STRING_WITH_LEN("OFF"));
> +
> +  DBUG_RETURN((uchar*) value);
> +}
> +
> +
> +/**
> +  Execute requested action at a synchronization point.
> +
> +  @param[in]    thd                 thread handle
> +  @param[in]    action              action to be executed
> +
> +  @note
> +    This is to be called only if activation count > 0.
> +*/
> +
> +static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
> +{
> +  DBUG_ENTER("debug_sync_execute");
> +  DBUG_PRINT("debug_sync", ("sync_point: '%s'  activation_count: %lu  "
> +                            "hit_limit: %lu  execute: %lu  timeout: %lu  "
> +                            "signal: '%s'  wait_for: '%s'",
> +                            action->sync_point.c_ptr(),
> +                            action->activation_count,
> +                            action->hit_limit, action->execute,
> action->timeout,
> +                            action->signal.c_ptr(),
> action->wait_for.c_ptr()));
> +  DBUG_ASSERT(action->activation_count);
> +
> +  if (action->execute)
> +  {
> +    if (action->signal.length())
> +    {
> +      /*
> +        Protect copying of the signal string to the global string
> +        to avoid race conditions during test case development.
> +        After approaching a clean test case it should not happen
> +        that two threads try to signal at the same time.
> +      */
> +      pthread_mutex_lock(&debug_sync_global.ds_mutex);
> +      /* Copy the signal to the global variable. */
> +      if (debug_sync_global.ds_signal.copy(action->signal))
> +      {
> +        /*
> +          Error is reported by my_malloc().
> +          We must disable the facility. We have no way to return an error.
> +        */
> +        debug_sync_emergency_disable(thd); /* purecov: tested */
> +      }
> +      /* Wake threads waiting in a sync point. */
> +      pthread_cond_broadcast(&debug_sync_global.ds_cond);
> +      DBUG_PRINT("debug_sync_exec", ("signal '%s'  at: '%s'",
> +                                     action->signal.c_ptr(),
> +                                     action->sync_point.c_ptr()));
> +      pthread_mutex_unlock(&debug_sync_global.ds_mutex);
> +    }
> +
> +    if (action->wait_for.length())
> +    {
> +      const char      *old_proc_info;
> +      int             error= 0;
> +      struct timespec abstime;
> +
> +      pthread_mutex_lock(&debug_sync_global.ds_mutex);
> +      old_proc_info= thd->enter_cond(&debug_sync_global.ds_cond,
> +                                     &debug_sync_global.ds_mutex,
> +                                     action->sync_point.c_ptr());
> +
> +      set_timespec(abstime, action->timeout);
> +      DBUG_PRINT("debug_sync_exec", ("wait for '%s'  at: '%s'  curr: '%s'",
> +                                     action->wait_for.c_ptr(),
> +                                     action->sync_point.c_ptr(),
> +                                     debug_sync_global.ds_signal.c_ptr()));
> +
> +      /*
> +        Wait until global signal string matches the wait_for string.
> +        Interrupt when thread or query is killed or facility disabled.
> +        The facility can become disabled when some thread cannot get
> +        the required dynamic memory allocated.
> +      */
> +      while (stringcmp(&debug_sync_global.ds_signal, &action->wait_for)
> &&
> +             !thd->killed && opt_debug_sync_timeout)
> +      {
> +        error= pthread_cond_timedwait(&debug_sync_global.ds_cond,
> +                                      &debug_sync_global.ds_mutex,
> +                                      &abstime);
> +        if (error == ETIMEDOUT || error == ETIME)
> +        {
> +          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                       ER_DEBUG_SYNC_TIMEOUT, ER(ER_DEBUG_SYNC_TIMEOUT));
> +          break;
> +        }
> +        error= 0;
> +      }
> +      DBUG_PRINT("debug_sync_exec", ("%s from '%s'  at: '%s'",
> +                                     error ? "timeout" : "resume",
> +                                     action->wait_for.c_ptr(),
> +                                     action->sync_point.c_ptr()));
> +
> +      thd->exit_cond(old_proc_info);
> +    }
> +
> +    action->execute--;

Wouldn't it be better to decrease the counter at the very beginning? This way we 
don't have to worry about early returns and such...

> +  }
> +
> +  /* hit_limit is zero for infinite. Don't decrement unconditionally. */
> +  if (action->hit_limit)
> +  {
> +    if (!--action->hit_limit)
> +    {
> +      thd->killed= THD::KILL_QUERY;
> +      my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0));
> +    }
> +    DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu  at: '%s'",
> +                                   action->hit_limit,
> +                                   action->sync_point.c_ptr()));
> +  }
> +
> +  action->activation_count--;
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/**
> +  Execute requested action at a synchronization point.
> +
> +  @param[in]     thd                thread handle
> +  @param[in]     sync_point_name    name of synchronization point
> +  @param[in]     name_len           length of sync point name
> +*/
> +
> +void debug_sync(THD *thd, const char *sync_point_name, size_t name_len)
> +{
> +  st_debug_sync_control *ds_control= thd->debug_sync_control;
> +  st_debug_sync_action  *action;
> +  DBUG_ENTER("debug_sync");
> +  DBUG_PRINT("debug_sync_point", ("hit: '%s'", sync_point_name));
> +
> +  /* Statistics. */
> +  ds_control->dsp_hits++;
> +
> +  if (ds_control->ds_active &&
> +      (action= debug_sync_find(ds_control->ds_action, ds_control->ds_active,
> +                               sync_point_name, name_len)) &&
> +      action->activation_count)
> +  {
> +    debug_sync_execute(thd, action);
> +
> +    /* Statistics. */
> +    ds_control->dsp_executed++;
> +  }
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
====================================================================================
> diff -Nrup a/sql/item_func.cc b/sql/item_func.cc
> --- a/sql/item_func.cc	2008-01-25 21:27:10 +01:00
> +++ b/sql/item_func.cc	2008-03-11 18:54:23 +01:00
> @@ -1689,6 +1689,8 @@ double Item_func_pow::val_real()
>  double Item_func_acos::val_real()
>  {
>    DBUG_ASSERT(fixed == 1);
> +  /* One can use this to defer SELECT processing. */
> +  DEBUG_SYNC(current_thd, "before_acos_function");
>    // the volatile's for BUG #2338 to calm optimizer down (because of gcc's bug)
>    volatile double value= args[0]->val_real();
>    if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
====================================================================================
> diff -Nrup a/sql/lock.cc b/sql/lock.cc
> --- a/sql/lock.cc	2007-12-21 20:27:43 +01:00
> +++ b/sql/lock.cc	2008-03-11 18:54:23 +01:00
> @@ -351,6 +351,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
>      */
>      reset_lock_data_and_free(&sql_lock);
>  retry:
> +    DEBUG_SYNC(thd, "mysql_lock_retry");
>      if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
>      {
>        *need_reopen= TRUE;
> @@ -1112,6 +1113,7 @@ bool wait_for_locked_table_names(THD *th
>        result=1;
>        break;
>      }
> +    DEBUG_SYNC(thd, "before_wait_locked_tname");
>      wait_for_condition(thd, &LOCK_open, &COND_refresh);
>      pthread_mutex_lock(&LOCK_open);
>    }
====================================================================================
> diff -Nrup a/sql/mysql_priv.h b/sql/mysql_priv.h
> --- a/sql/mysql_priv.h	2008-02-14 18:35:22 +01:00
> +++ b/sql/mysql_priv.h	2008-03-11 18:54:24 +01:00
> @@ -589,6 +589,27 @@ void debug_sync_point(const char* lock_n
>  #define DBUG_SYNC_POINT(lock_name,lock_timeout)
>  #endif /* EXTRA_DEBUG */
>  
> +/* Debug Sync Facility. */
> +#if defined(ENABLED_DEBUG_SYNC)
> +/* Macro to be put in the code at synchronization points. */
> +#define DEBUG_SYNC(_thd_, _sync_point_name_)                            \
> +          do { if (unlikely(opt_debug_sync_timeout))                    \
> +               debug_sync(_thd_, STRING_WITH_LEN(_sync_point_name_));   \
> +             } while (0)
> +/* Command line option --debug-sync. See mysqld.cc. */
> +extern uint opt_debug_sync_timeout;

Comment should say "--debug-sync-timeout".

> +/* Default WAIT_FOR timeout if command line option is given without argument. */
> +#define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300
> +/* Debug Sync prototypes. See debug_sync.cc. */
> +extern int  debug_sync_init(void);
> +extern void debug_sync_end(void);
> +extern void debug_sync_init_thread(THD *thd);
> +extern void debug_sync_end_thread(THD *thd);
> +extern void debug_sync(THD *thd, const char *sync_point_name, size_t name_len);
> +#else /* defined(ENABLED_DEBUG_SYNC) */
> +#define DEBUG_SYNC(_thd_, _sync_point_name_)    /* disabled DEBUG_SYNC */
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
> +
>  /* BINLOG_DUMP options */
>  
>  #define BINLOG_DUMP_NON_BLOCK   1
====================================================================================
> diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
> --- a/sql/mysqld.cc	2008-02-14 10:00:48 +01:00
> +++ b/sql/mysqld.cc	2008-03-11 18:54:24 +01:00
> @@ -468,6 +468,9 @@ my_bool lower_case_file_system= 0;
>  my_bool opt_large_pages= 0;
>  my_bool opt_myisam_use_mmap= 0;
>  uint    opt_large_page_size= 0;
> +#if defined(ENABLED_DEBUG_SYNC)
> +uint    opt_debug_sync_timeout= 0;
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>  my_bool opt_old_style_user_limits= 0, trust_function_creators= 0;
>  /*
>    True if there is at least one per-hour limit for some user, so we should
> @@ -1332,6 +1335,10 @@ void clean_up(bool print_message)
>  #ifdef USE_REGEX
>    my_regex_end();
>  #endif
> +#if defined(ENABLED_DEBUG_SYNC)
> +  /* End the debug sync facility. See debug_sync.cc. */
> +  debug_sync_end();
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>  
>  #if !defined(EMBEDDED_LIBRARY)
>    if (!opt_bootstrap)
> @@ -3298,6 +3305,12 @@ static int init_common_variables(const c
>    sys_var_slow_log_path.value= my_strdup(s, MYF(0));
>    sys_var_slow_log_path.value_length= strlen(s);
>  
> +#if defined(ENABLED_DEBUG_SYNC)
> +  /* Initialize the debug sync facility. See debug_sync.cc. */
> +  if (debug_sync_init())
> +    return 1; /* purecov: tested */
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
> +
>    if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
>      return 1;
>    if (my_database_names_init())
> @@ -4617,7 +4630,7 @@ void create_thread_to_handle_connection(
>                                handle_one_connection,
>                                (void*) thd)))
>      {
> -      /* purify: begin inspected */
> +      /* purecov: begin inspected */
>        DBUG_PRINT("error",
>                   ("Can't create thread to handle request (error %d)",
>                    error));
> @@ -5404,6 +5417,9 @@ enum options_mysqld
>    OPT_SECURE_FILE_PRIV,
>    OPT_MIN_EXAMINED_ROW_LIMIT,
>    OPT_LOG_SLOW_SLAVE_STATEMENTS,
> +#if defined(ENABLED_DEBUG_SYNC)
> +  OPT_DEBUG_SYNC_TIMEOUT,
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>    OPT_OLD_MODE,
>  #if HAVE_POOL_OF_THREADS == 1
>    OPT_POOL_OF_THREADS,
> @@ -6151,6 +6167,14 @@ log and this option does nothing anymore
>     "Decision to use in heuristic recover process. Possible values are COMMIT or
> ROLLBACK.",
>     (uchar**) &opt_tc_heuristic_recover, (uchar**)
> &opt_tc_heuristic_recover,
>     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
> +#if defined(ENABLED_DEBUG_SYNC)
> +  {"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT,
> +   "Enable the debug sync facility "
> +   "and optionally specify a default wait timeout in seconds. "
> +   "A zero value keeps the facility disabled.",
> +   (uchar**) &opt_debug_sync_timeout, 0,
> +   0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0},
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>    {"temp-pool", OPT_TEMP_POOL,
>     "Using this option will cause most temporary files created to use a small set of
> names, rather than a unique name for each new file.",
>     (uchar**) &use_temp_pool, (uchar**) &use_temp_pool, 0, GET_BOOL, NO_ARG,
> 1,
> @@ -7343,6 +7367,9 @@ static void mysql_init_variables(void)
>    bzero((uchar*) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
>    bzero((char *) &global_status_var, sizeof(global_status_var));
>    opt_large_pages= 0;
> +#if defined(ENABLED_DEBUG_SYNC)
> +  opt_debug_sync_timeout= 0;
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>    key_map_full.set_all();
>  
>    /* Character sets */
> @@ -8001,6 +8028,22 @@ mysqld_get_one_option(int optid,
>      lower_case_table_names= argument ? atoi(argument) : 1;
>      lower_case_table_names_used= 1;
>      break;
> +#if defined(ENABLED_DEBUG_SYNC)
> +  case OPT_DEBUG_SYNC_TIMEOUT:
> +    /*
> +      Debug Sync Facility. See debug_sync.cc.
> +      Default timeout for WAIT_FOR action.
> +      Default value is zero (facility disabled).
> +      If option is given without an argument, supply a non-zero value.
> +    */
> +    if (!argument)
> +    {
> +      /* purecov: begin tested */
> +      opt_debug_sync_timeout= DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT;
> +      /* purecov: end */
> +    }
> +    break;
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>    }
>    return 0;
>  }
====================================================================================
> diff -Nrup a/sql/set_var.cc b/sql/set_var.cc
> --- a/sql/set_var.cc	2008-02-08 17:54:40 +01:00
> +++ b/sql/set_var.cc	2008-03-11 18:54:24 +01:00
> @@ -481,6 +481,12 @@ static sys_var_long_ptr	sys_table_cache_
>  					     &table_cache_size);
>  static sys_var_long_ptr	sys_table_lock_wait_timeout(&vars,
> "table_lock_wait_timeout",
>                                                      &table_lock_wait_timeout);
> +
> +#if defined(ENABLED_DEBUG_SYNC)
> +/* Debug Sync Facility. Implemented in debug_sync.cc. */
> +static sys_var_debug_sync sys_debug_sync(&vars, "debug_sync");
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
> +
>  static sys_var_long_ptr	sys_thread_cache_size(&vars, "thread_cache_size",
>  					      &thread_cache_size);
>  #if HAVE_POOL_OF_THREADS == 1
====================================================================================
> diff -Nrup a/sql/set_var.h b/sql/set_var.h
> --- a/sql/set_var.h	2008-02-08 17:02:58 +01:00
> +++ b/sql/set_var.h	2008-03-11 18:54:24 +01:00
> @@ -567,6 +567,21 @@ public:
>    uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *b);
>  };
>  
> +#if defined(ENABLED_DEBUG_SYNC)
> +/* Debug Sync Facility. Implemented in debug_sync.cc. */
> +class sys_var_debug_sync :public sys_var_thd
> +{
> +public:
> +  sys_var_debug_sync(sys_var_chain *chain, const char *name_arg)
> +    :sys_var_thd(name_arg)
> +  { chain_sys_var(chain); }
> +  bool check(THD *thd, set_var *var);
> +  bool update(THD *thd, set_var *var);
> +  SHOW_TYPE show_type() { return SHOW_CHAR; }
> +  bool check_update_type(Item_result type) { return type != STRING_RESULT; }
> +  uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
> +};
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>  
>  
>  /* some variables that require special handling */
====================================================================================
> diff -Nrup a/sql/share/errmsg.txt b/sql/share/errmsg.txt
> --- a/sql/share/errmsg.txt	2008-02-05 15:30:25 +01:00
> +++ b/sql/share/errmsg.txt	2008-03-11 18:54:24 +01:00
> @@ -6234,3 +6234,11 @@ ER_SLAVE_HEARTBEAT_FAILURE
>    eng "Unexpected master's heartbeat data: %s"
>  ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
>    eng "The requested value for the heartbeat period %s %s"
> +
> +ER_DEBUG_SYNC_TIMEOUT
> +  eng "debug sync point wait timed out"
> +  ger "Debug Sync Point Wartezeit �berschritten"
> +ER_DEBUG_SYNC_HIT_LIMIT
> +  eng "debug sync point hit limit reached"
> +  ger "Debug Sync Point Hit Limit erreicht"
> +
> diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
> --- a/sql/sql_base.cc	2008-02-02 13:19:47 +01:00
> +++ b/sql/sql_base.cc	2008-03-11 18:54:24 +01:00
> @@ -1021,6 +1021,8 @@ bool close_cached_tables(THD *thd, TABLE
>      close_old_data_files(thd,thd->open_tables,1,1);
>      mysql_ha_flush(thd);
>  
> +    DEBUG_SYNC(thd, "after_flush_unlock");
> +
>      bool found=1;
>      /* Wait until all threads has closed all the tables we had locked */
>      DBUG_PRINT("info",
> @@ -2898,6 +2900,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *
>        */
>        if (table->in_use != thd)
>        {
> +        DEBUG_SYNC(thd, "before_open_table_wait_refresh");
> +
>          /* wait_for_conditionwill unlock LOCK_open for us */
>          wait_for_condition(thd, &LOCK_open, &COND_refresh);
>        }
> @@ -4870,13 +4874,6 @@ bool open_and_lock_tables_derived(THD *t
>    {
>      if (open_tables(thd, &tables, &counter, 0))
>        DBUG_RETURN(-1);
> -
> -    DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
> -      const char *old_proc_info= thd->proc_info;
> -      thd->proc_info= "DBUG sleep";
> -      my_sleep(6000000);
> -      thd->proc_info= old_proc_info;});
> -
>      if (!lock_tables(thd, tables, counter, &need_reopen))
>        break;
>      if (!need_reopen)
> @@ -5170,6 +5167,8 @@ int lock_tables(THD *thd, TABLE_LIST *ta
>          thd->set_current_stmt_binlog_row_based_if_mixed();
>        }
>      }
> +
> +    DEBUG_SYNC(thd, "before_lock_tables_takes_lock");
>  
>      if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
>                                          lock_flag, need_reopen)))
====================================================================================
> diff -Nrup a/sql/sql_class.cc b/sql/sql_class.cc
> --- a/sql/sql_class.cc	2008-02-12 18:29:06 +01:00
> +++ b/sql/sql_class.cc	2008-03-11 18:54:24 +01:00
> @@ -501,6 +501,9 @@ THD::THD()
>     derived_tables_processing(FALSE),
>     spcont(NULL),
>     m_lip(NULL)
> +#if defined(ENABLED_DEBUG_SYNC)
> +   ,debug_sync_control(0)
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>  {
>    ulong tmp;
>  
> @@ -727,6 +730,11 @@ void THD::init(void)
>    update_charset();
>    reset_current_stmt_binlog_row_based();
>    bzero((char *) &status_var, sizeof(status_var));
> +
> +#if defined(ENABLED_DEBUG_SYNC)
> +  /* Initialize the Debug Sync Facility. See debug_sync.cc. */
> +  debug_sync_init_thread(this);
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
>  }
>  
>  
> @@ -802,6 +810,12 @@ void THD::cleanup(void)
>      lock=locked_tables; locked_tables=0;
>      close_thread_tables(this);
>    }
> +
> +#if defined(ENABLED_DEBUG_SYNC)
> +  /* End the Debug Sync Facility. See debug_sync.cc. */
> +  debug_sync_end_thread(this);
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
> +
>    mysql_ha_cleanup(this);
>    delete_dynamic(&user_var_events);
>    hash_free(&user_vars);
====================================================================================
> diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
> --- a/sql/sql_class.h	2008-02-01 15:08:44 +01:00
> +++ b/sql/sql_class.h	2008-03-11 18:54:24 +01:00
> @@ -1740,6 +1740,11 @@ public:
>    partition_info *work_part_info;
>  #endif
>  
> +#if defined(ENABLED_DEBUG_SYNC)
> +  /* Debug Sync facility. See debug_sync.cc. */
> +  struct st_debug_sync_control *debug_sync_control;
> +#endif /* defined(ENABLED_DEBUG_SYNC) */
> +
>    THD();
>    ~THD();
>  
====================================================================================
> diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
> --- a/sql/sql_parse.cc	2008-02-15 22:25:57 +01:00
> +++ b/sql/sql_parse.cc	2008-03-11 18:54:24 +01:00
> @@ -2789,6 +2789,7 @@ end_with_restore_list:
>        thd->first_successful_insert_id_in_cur_stmt=
>          thd->first_successful_insert_id_in_prev_stmt;
>  
> +    DEBUG_SYNC(thd, "after_insert");
>      break;
>    }
>    case SQLCOM_REPLACE_SELECT:
====================================================================================
> diff -Nrup a/sql/sql_table.cc b/sql/sql_table.cc
> --- a/sql/sql_table.cc	2008-02-14 18:35:22 +01:00
> +++ b/sql/sql_table.cc	2008-03-11 18:54:24 +01:00
> @@ -4184,6 +4184,7 @@ static bool mysql_admin_table(THD* thd, 
>                                RTFC_WAIT_OTHER_THREAD_FLAG |
>                                RTFC_CHECK_KILLED_FLAG);
>        thd->exit_cond(old_message);
> +      DEBUG_SYNC(thd, "after_admin_flush");
>        DBUG_EXECUTE_IF("wait_in_mysql_admin_table", wait_for_kill_signal(thd););
>        if (thd->killed)
>  	goto err;
====================================================================================
> diff -Nrup a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
> --- a/storage/myisammrg/ha_myisammrg.cc	2007-12-21 20:27:49 +01:00
> +++ b/storage/myisammrg/ha_myisammrg.cc	2008-03-11 18:54:24 +01:00
> @@ -456,6 +456,8 @@ int ha_myisammrg::attach_children(void)
>    DBUG_PRINT("myrg", ("test_if_locked: %u", this->test_if_locked));
>    DBUG_ASSERT(!this->file->children_attached);
>  
> +  DEBUG_SYNC(current_thd, "before_myisammrg_attach");
> +
>    /*
>      Initialize variables that are used, modified, and/or set by
>      myisammrg_attach_children_callback().
> @@ -925,6 +927,8 @@ THR_LOCK_DATA **ha_myisammrg::store_lock
>  					 enum thr_lock_type lock_type)
>  {
>    MYRG_TABLE *open_table;
> +
> +  DEBUG_SYNC(thd, "before_myisammrg_store_lock");
>  
>    /*
>      This method can be called while another thread is attaching the
> 
Thread
bk commit into 6.0 tree (istruewing:1.2569) WL#4259Ingo Struewing12 Mar
  • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Ingo Strüwing12 Mar
  • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Sergei Golubchik12 Mar
    • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Ingo Strüwing12 Mar
      • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Sergei Golubchik17 Mar
        • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Ingo Strüwing17 Mar
          • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Sergei Golubchik17 Mar
            • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Ingo Strüwing18 Mar
  • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Rafal Somla20 Mar
    • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Ingo Strüwing10 Apr
      • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Rafal Somla14 Apr
        • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Ingo Strüwing16 Apr
          • Re: bk commit into 6.0 tree (istruewing:1.2569) WL#4259Rafal Somla16 Apr