List:Commits« Previous MessageNext Message »
From:Ingo Struewing Date:February 11 2008 1:05pm
Subject:bk commit into 6.0 tree (istruewing:1.2526) WL#4259
View as plain text  
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-02-11 13:05:21+01:00, istruewing@stripped +25 -0
  WL#4259 - Test Synchronization Facility
  
  The Test Synchronization Facility allows to place synchronization points
  in the code like Dbug Sleep, Debug Sync Point, and Backup Breakpoint:
  
      open_tables(...)
  
      TEST_SYNCHRONIZE(thd, after_open_tables);
  
      lock_tables(...)
  
  When activated, a sync point can
  
    - Send a signal and/or
    - Wait for a signal
  
  Nomenclature:
  
    - signal:             A global value that keeps its value until
                          overwritten by a new signal. One may also say
                          "signal post" or "flag mast".
  
    - send a signal:      Set the global value ("set a flag") and
                          broadcast a global condition.
  
    - 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 mysql_test_sync.cc
  or in the worklog entry.

  libmysqld/CMakeLists.txt@stripped, 2008-02-11 13:05:17+01:00, istruewing@stripped +1 -1
    WL#4259 - Test Synchronization Facility
    Include mysql_test_sync.cc

  libmysqld/Makefile.am@stripped, 2008-02-11 13:05:17+01:00, istruewing@stripped +1 -1
    WL#4259 - Test Synchronization Facility
    Include mysql_test_sync.cc

  mysql-test/mysql-test-run.pl@stripped, 2008-02-11 13:05:17+01:00, istruewing@stripped +8 -0
    WL#4259 - Test Synchronization Facility
    Added code for enabling/disabling of the facility.

  mysql-test/r/grant.result@stripped, 2008-02-11 13:05:17+01:00, istruewing@stripped +4 -4
    WL#4259 - Test Synchronization Facility
    Fixed test result. 'test' is now a keyword.
    It is always quoted. Even when "set sql_quote_show_create= 0"
    is in effect.

  mysql-test/r/merge.result@stripped, 2008-02-11 13:05:17+01:00, istruewing@stripped +117 -86
    WL#4259 - Test Synchronization Facility
    Fixed the example test result.

  mysql-test/r/test_synchronize.result@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +284 -0
    WL#4259 - Test Synchronization Facility
    Added test result.
    

  mysql-test/r/test_synchronize.result@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +0 -0

  mysql-test/t/merge.test@stripped, 2008-02-11 13:05:17+01:00, istruewing@stripped +294 -63
    WL#4259 - Test Synchronization Facility
    Example tests.
    Reworked tests to utilize the new facility.
    Added more tests.

  mysql-test/t/test_synchronize.test@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +346 -0
    WL#4259 - Test Synchronization Facility
    Added a new test case to test the facility itself.
    

  mysql-test/t/test_synchronize.test@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +0 -0

  mysys/thr_lock.c@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +13 -0
    WL#4259 - Test Synchronization Facility
    Added a synchronization point hook.

  sql/CMakeLists.txt@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +1 -0
    WL#4259 - Test Synchronization Facility
    Include mysql_test_sync.cc and mysql_test_sync.h

  sql/Makefile.am@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +2 -2
    WL#4259 - Test Synchronization Facility
    Include mysql_test_sync.cc and mysql_test_sync.h

  sql/item_func.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +2 -0
    WL#4259 - Test Synchronization Facility
    Added a synchronization point.

  sql/lex.h@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +7 -0
    WL#4259 - Test Synchronization Facility
    Added keywords.

  sql/lock.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +2 -0
    WL#4259 - Test Synchronization Facility
    Added synchronization points.

  sql/mysql_test_sync.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +819 -0
    WL#4259 - Test Synchronization Facility
    Added variables and functions for the facility.
    

  sql/mysql_test_sync.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +0 -0

  sql/mysql_test_sync.h@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +93 -0
    WL#4259 - Test Synchronization Facility
    Added declarations for the facility.
    

  sql/mysql_test_sync.h@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +0 -0

  sql/mysqld.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +27 -1
    WL#4259 - Test Synchronization Facility
    Added initialization/deletion of the facility for the server.
    Added option "test-synchronize".

  sql/sql_base.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +6 -0
    WL#4259 - Test Synchronization Facility
    Added synchronization points.

  sql/sql_class.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +8 -1
    WL#4259 - Test Synchronization Facility
    Added initialization/deletion of the facility for THD.

  sql/sql_class.h@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +7 -0
    WL#4259 - Test Synchronization Facility
    Added a THD element.

  sql/sql_lex.h@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +4 -1
    WL#4259 - Test Synchronization Facility
    Added statement symbol.
    Added a lex element.

  sql/sql_parse.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +15 -0
    WL#4259 - Test Synchronization Facility
    Added a synchronization point.
    Added TEST SYNCHRONIZE statement execution.

  sql/sql_table.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +1 -0
    WL#4259 - Test Synchronization Facility
    Added a synchronization point.

  sql/sql_yacc.yy@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +107 -0
    WL#4259 - Test Synchronization Facility
    Added syntax extension.

  storage/myisammrg/ha_myisammrg.cc@stripped, 2008-02-11 13:05:18+01:00, istruewing@stripped +4 -0
    WL#4259 - Test Synchronization Facility
    Added synchronization points.

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-02-11 13:05:17 +01:00
@@ -187,7 +187,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libm
            ../sql/strfunc.cc ../sql/table.cc ../sql/thr_malloc.cc
            ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc
            ../sql/partition_info.cc ../sql/sql_connect.cc 
-           ../sql/scheduler.cc
+           ../sql/scheduler.cc ../sql/mysql_test_sync.cc
            ${GEN_SOURCES}
            ${LIB_SOURCES})
 
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-02-11 13:05:17 +01:00
@@ -80,7 +80,7 @@ sqlsources = derror.cc field.cc field_co
 	rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
 	sql_tablespace.cc \
 	rpl_injector.cc my_user.c partition_info.cc \
-	sql_servers.cc
+	sql_servers.cc mysql_test_sync.cc
 
 libmysqld_int_a_SOURCES= $(libmysqld_sources)
 nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)
diff -Nrup a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
--- a/mysql-test/mysql-test-run.pl	2008-01-25 18:40:44 +01:00
+++ b/mysql-test/mysql-test-run.pl	2008-02-11 13:05:17 +01:00
@@ -264,6 +264,7 @@ my @default_valgrind_args= ("--show-reac
 my @valgrind_args;
 my $opt_valgrind_path;
 my $opt_callgrind;
+my $opt_test_synchronize= 300; # Default timeout for WAIT_FOR actions.
 
 our $opt_stress=               "";
 our $opt_stress_suite=     "main";
@@ -612,6 +613,7 @@ sub command_line_setup () {
              'valgrind-option=s'        => \@valgrind_args,
              'valgrind-path=s'          => \$opt_valgrind_path,
 	     'callgrind'                => \$opt_callgrind,
+	     'test-synchronize=i'       => \$opt_test_synchronize,
 
              # Stress testing 
              'stress'                   => \$opt_stress,
@@ -3555,6 +3557,10 @@ sub mysqld_arguments ($$$$) {
   # see BUG#28359
   mtr_add_arg($args, "%s--connect-timeout=60", $prefix);
 
+  # Enable the TEST SYNCHRONIZE facility, set default wait timeout.
+  # Facility stays disabled if timeout value is zero.
+  mtr_add_arg($args, "%s--test-synchronize=%s", $prefix,
+              $opt_test_synchronize);
 
   # 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
@@ -4979,6 +4985,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
+  test-synchronize=NUM  Set default timeout for WAIT_FOR test synchronize
+                        actions. Disable facility with NUM=0.
 
 Misc options
 
diff -Nrup a/mysql-test/r/grant.result b/mysql-test/r/grant.result
--- a/mysql-test/r/grant.result	2007-12-12 16:40:30 +01:00
+++ b/mysql-test/r/grant.result	2008-02-11 13:05:17 +01:00
@@ -213,14 +213,14 @@ set sql_quote_show_create=0;
 show grants for drop_user@localhost;
 Grants for drop_user@localhost
 GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION
-GRANT ALL PRIVILEGES ON test.* TO 'drop_user'@'localhost' WITH GRANT OPTION
-GRANT SELECT (a) ON test.t1 TO 'drop_user'@'localhost'
+GRANT ALL PRIVILEGES ON `test`.* TO 'drop_user'@'localhost' WITH GRANT OPTION
+GRANT SELECT (a) ON `test`.t1 TO 'drop_user'@'localhost'
 set sql_mode="ansi_quotes";
 show grants for drop_user@localhost;
 Grants for drop_user@localhost
 GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION
-GRANT ALL PRIVILEGES ON test.* TO 'drop_user'@'localhost' WITH GRANT OPTION
-GRANT SELECT (a) ON test.t1 TO 'drop_user'@'localhost'
+GRANT ALL PRIVILEGES ON "test".* TO 'drop_user'@'localhost' WITH GRANT OPTION
+GRANT SELECT (a) ON "test".t1 TO 'drop_user'@'localhost'
 set sql_quote_show_create=1;
 show grants for drop_user@localhost;
 Grants for drop_user@localhost
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-02-11 13:05:17 +01:00
@@ -1,3 +1,4 @@
+TEST SYNCHRONIZE RESET;
 drop table if exists t1,t2,t3,t4,t5,t6;
 drop database if exists mysqltest;
 create table t1 (a int not null primary key auto_increment, message char(20));
@@ -1071,28 +1072,59 @@ 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;
+connection con1
+TEST SYNCHRONIZE after_admin_flush SIGNAL admin_flush WAIT_FOR end_repair;
 REPAIR TABLE t1;
+connection default;
+TEST SYNCHRONIZE NOW WAIT_FOR admin_flush;
+TEST SYNCHRONIZE mysql_lock_retry HIT_LIMIT 3;
+TEST SYNCHRONIZE before_open_table_wait_refresh SIGNAL end_repair;
 INSERT INTO t2 VALUES (1);
+TEST SYNCHRONIZE NOW SIGNAL end_repair;
+connection con1
 Table	Op	Msg_type	Msg_text
 test.t1	repair	status	OK
+connection default;
+TEST SYNCHRONIZE 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;
-INSERT INTO t2 VALUES (1);
 REPAIR TABLE t1;
 Table	Op	Msg_type	Msg_text
 test.t1	repair	status	OK
+connection con1
+TEST SYNCHRONIZE mysql_lock_retry HIT_LIMIT 3;
+TEST SYNCHRONIZE after_insert SIGNAL end_repair;
+TEST SYNCHRONIZE before_open_table_wait_refresh SIGNAL end_repair;
+INSERT INTO t2 VALUES (1);
+connection default;
+TEST SYNCHRONIZE NOW WAIT_FOR end_repair;
 UNLOCK TABLES;
+connection con1
+connection default;
+TEST SYNCHRONIZE RESET;
 DROP TABLE t1, t2;
 CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
 LOCK TABLE t1 WRITE;
+connection con1
+TEST SYNCHRONIZE before_lock_tables_takes_lock
+SIGNAL opened WAIT_FOR flushed;
+TEST SYNCHRONIZE wait_for_lock SIGNAL locked EXECUTE 2;
+TEST SYNCHRONIZE before_open_table_wait_refresh SIGNAL locked;
+TEST SYNCHRONIZE after_insert SIGNAL locked;
 INSERT INTO t1 VALUES (1);
+connection default
+TEST SYNCHRONIZE NOW WAIT_FOR opened;
+TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed;
 FLUSH TABLES;
-FLUSH TABLES;
+TEST SYNCHRONIZE NOW WAIT_FOR locked;
 SELECT * FROM t1;
 c1
 UNLOCK TABLES;
+connection con1
+connection default
+TEST SYNCHRONIZE RESET;
 DROP TABLE t1;
 #
 # Extra tests for Bug#26379 - Combination of FLUSH TABLE and
@@ -1611,6 +1643,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 +1826,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;
@@ -1807,88 +1840,25 @@ 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;
+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
+TEST SYNCHRONIZE before_acos_function SIGNAL 'select' WAIT_FOR truncated;
+SELECT ACOS(c1) FROM t3;
+connection default
+TEST SYNCHRONIZE NOW WAIT_FOR 'select';
+TEST SYNCHRONIZE before_wait_locked_tname SIGNAL truncated;
 TRUNCATE TABLE t1;
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-0
-SELECT COUNT(*) FROM t2;
-COUNT(*)
-80
-SELECT COUNT(*) FROM t3;
-COUNT(*)
-80
+TEST SYNCHRONIZE NOW SIGNAL truncated;
+connection con1
+connection default
+SELECT ACOS(c1) FROM t3;
+ACOS(c1)
+1.369438406004566
+TEST SYNCHRONIZE RESET;
 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;
@@ -1984,3 +1954,64 @@ test.t1	optimize	status	OK
 FLUSH TABLES m1, t1;
 UNLOCK TABLES;
 DROP TABLE t1, m1;
+CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
+CREATE TABLE m1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1) INSERT_METHOD=LAST;
+connection con1
+TEST SYNCHRONIZE before_myisammrg_attach SIGNAL attach WAIT_FOR flushed;
+INSERT INTO m1 VALUES (2);
+connection default;
+TEST SYNCHRONIZE NOW WAIT_FOR attach;
+TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed;
+FLUSH TABLE m1;
+connection con1
+connection default;
+SELECT * FROM m1;
+c1
+2
+TEST SYNCHRONIZE 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
+TEST SYNCHRONIZE before_myisammrg_attach SIGNAL attach WAIT_FOR store_lock1;
+TEST SYNCHRONIZE before_myisammrg_store_lock
+SIGNAL store_lock2 WAIT_FOR flushed;
+INSERT INTO m1 VALUES (2);
+connection default;
+TEST SYNCHRONIZE NOW WAIT_FOR attach;
+TEST SYNCHRONIZE before_myisammrg_store_lock
+SIGNAL store_lock1 WAIT_FOR store_lock2;
+TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed;
+FLUSH TABLE m1;
+connection con1
+connection default;
+SELECT * FROM m1;
+c1
+2
+TEST SYNCHRONIZE RESET;
+DROP TABLE m1, t1;
+CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
+LOCK TABLE t1 WRITE;
+connection con1
+TEST SYNCHRONIZE mysql_lock_retry HIT_LIMIT 2;
+TEST SYNCHRONIZE before_lock_tables_takes_lock
+SIGNAL opened WAIT_FOR flushed EXECUTE 2;
+TEST SYNCHRONIZE wait_for_lock SIGNAL locked EXECUTE 4;
+TEST SYNCHRONIZE before_open_table_wait_refresh SIGNAL refresh EXECUTE 2;
+TEST SYNCHRONIZE after_insert SIGNAL locked EXECUTE 2;
+INSERT INTO t1 VALUES (1);
+connection default;
+TEST SYNCHRONIZE NOW WAIT_FOR opened;
+TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed EXECUTE 2;
+FLUSH TABLES;
+TEST SYNCHRONIZE NOW WAIT_FOR refresh;
+UNLOCK TABLES;
+LOCK TABLE t1 WRITE;
+TEST SYNCHRONIZE NOW WAIT_FOR opened;
+FLUSH TABLES;
+TEST SYNCHRONIZE NOW WAIT_FOR locked;
+UNLOCK TABLES;
+connection con1
+connection default;
+TEST SYNCHRONIZE RESET;
+DROP TABLE t1;
diff -Nrup a/mysql-test/r/test_synchronize.result b/mysql-test/r/test_synchronize.result
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/r/test_synchronize.result	2008-02-11 13:05:18 +01:00
@@ -0,0 +1,284 @@
+TEST SYNCHRONIZE RESET;
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0           HIT_LIMIT 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now SIGNAL sig1                         EXECUTE 2 HIT_LIMIT 3;
+TEST SYNCHRONIZE now SIGNAL sig1                         EXECUTE 2;
+TEST SYNCHRONIZE now SIGNAL sig1                                   HIT_LIMIT 3;
+TEST SYNCHRONIZE now SIGNAL sig1;
+TEST SYNCHRONIZE now             WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now             WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now             WAIT_FOR sig2 TIMEOUT 0           HIT_LIMIT 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now             WAIT_FOR sig2 TIMEOUT 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now                                               HIT_LIMIT 3;
+TEST SYNCHRONIZE now CLEAR;
+TEST SYNCHRONIZE RESET;
+TEST SYNCHRONIZE SHOW STATUS;
+Status	Current_Signal
+ON	
+TEST SYNCHRONIZE SHOW ACTION;
+Sync_Point	Action
+TEST SYNCHRONIZE now TEST;
+test synchronize now signal sig1 wait_for sig2 timeout 0 execute 2 hit_limit 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+test synchronize now signal sig1 wait_for sig2 timeout 0 execute 2;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+test synchronize now signal sig1 wait_for sig2 timeout 0           hit_limit 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+test synchronize now signal sig1 wait_for sig2 timeout 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+test synchronize now signal sig1                         execute 2 hit_limit 3;
+test synchronize now signal sig1                         execute 2;
+test synchronize now signal sig1                                   hit_limit 3;
+test synchronize now signal sig1;
+test synchronize now             wait_for sig2 timeout 0 execute 2 hit_limit 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+test synchronize now             wait_for sig2 timeout 0 execute 2;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+test synchronize now             wait_for sig2 timeout 0           hit_limit 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+test synchronize now             wait_for sig2 timeout 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+test synchronize now                                               hit_limit 3;
+test synchronize now clear;
+test synchronize reset;
+test synchronize show status;
+Status	Current_Signal
+ON	
+test synchronize show action;
+Sync_Point	Action
+test synchronize now test;
+TEST SYNCHRONIZE 'now' SIGNAL sig1   WAIT_FOR sig2   TIMEOUT 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now   SIGNAL 'sig1' WAIT_FOR sig2   TIMEOUT 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now   SIGNAL sig1   WAIT_FOR 'sig2' TIMEOUT 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT=3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 EXECUTE=2 HIT_LIMIT 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 EXECUTE=2 HIT_LIMIT=3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT=0 EXECUTE 2 HIT_LIMIT 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT=0 EXECUTE 2 HIT_LIMIT=3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT=0 EXECUTE=2 HIT_LIMIT 3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT=0 EXECUTE=2 HIT_LIMIT=3;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now   SIGNAL sig1  WAIT_FOR FLUSH TIMEOUT 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now   SIGNAL FLUSH WAIT_FOR sig2  TIMEOUT 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE FLUSH SIGNAL sig1  WAIT_FOR sig2  TIMEOUT 0;
+ERROR HY000: No such synchronization point: 'FLUSH'
+TEST SYNCHRONIZE WHERE SIGNAL sig1  WAIT_FOR sig2  TIMEOUT 0;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE SIGNAL sig1  WAIT_FOR sig2  TIMEOUT 0' at line 1
+TEST SYNCHRONIZE now   SIGNAL WHERE WAIT_FOR sig2  TIMEOUT 0;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE WAIT_FOR sig2  TIMEOUT 0' at line 1
+TEST SYNCHRONIZE now   SIGNAL sig1  WAIT_FOR WHERE TIMEOUT 0;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE TIMEOUT 0' at line 1
+TEST SYNCHRONIZE now;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
+TEST SYNCHRONIZE now                                          EXECUTE 2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'EXECUTE 2' at line 1
+TEST SYNCHRONIZE now                                TIMEOUT 0 EXECUTE 2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TIMEOUT 0 EXECUTE 2' at line 1
+TEST SYNCHRONIZE now                                TIMEOUT 0;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TIMEOUT 0' at line 1
+TEST SYNCHRONIZE now WAIT_FOR sig2 SIGNAL sig1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SIGNAL sig1' at line 1
+TEST SYNCHRONIZE now WAIT_FOR sig2 SIGNAL sig1           EXECUTE 2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SIGNAL sig1           EXECUTE 2' at line 1
+TEST SYNCHRONIZE now WAIT_FOR sig2 SIGNAL sig1 TIMEOUT 0 EXECUTE 2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SIGNAL sig1 TIMEOUT 0 EXECUTE 2' at line 1
+TEST SYNCHRONIZE now WAIT_FOR sig2 SIGNAL sig1 TIMEOUT 0;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SIGNAL sig1 TIMEOUT 0' at line 1
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 SIGNAL sig1 EXECUTE 2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SIGNAL sig1 EXECUTE 2' at line 1
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 SIGNAL sig1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SIGNAL sig1' at line 1
+TEST SYNCHRONIZE now TIMEOUT 0 WAIT_FOR sig2 EXECUTE 2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TIMEOUT 0 WAIT_FOR sig2 EXECUTE 2' at line 1
+TEST SYNCHRONIZE now TIMEOUT 0 WAIT_FOR sig2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TIMEOUT 0 WAIT_FOR sig2' at line 1
+TEST SYNCHRONIZE now                  SIGNAL sig1 TIMEOUT 0 EXECUTE 2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TIMEOUT 0 EXECUTE 2' at line 1
+TEST SYNCHRONIZE now                  SIGNAL sig1 TIMEOUT 0;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TIMEOUT 0' at line 1
+TEST SYNCHRONIZE now EXECUTE 2 SIGNAL sig1 TIMEOUT 0;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'EXECUTE 2 SIGNAL sig1 TIMEOUT 0' at line 1
+TEST SYNCHRONIZE now TIMEOUT 0 SIGNAL sig1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TIMEOUT 0 SIGNAL sig1' at line 1
+TEST SYNCHRONIZE now EXECUTE 2 TIMEOUT 0 SIGNAL sig1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'EXECUTE 2 TIMEOUT 0 SIGNAL sig1' at line 1
+TEST SYNCHRONIZE now CLEAR HIT_LIMIT 3;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'HIT_LIMIT 3' at line 1
+TEST SYNCHRONIZE CLEAR;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
+TEST SYNCHRONIZE now RESET;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RESET' at line 1
+TEST SYNCHRONIZE now SHOW;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW' at line 1
+TEST SYNCHRONIZE now SHOW STATUS;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW STATUS' at line 1
+TEST SYNCHRONIZE now SHOW ACTION;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW ACTION' at line 1
+TEST SYNCHRONIZE now SHOW test;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW test' at line 1
+TEST SYNCHRONIZE TEST;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
+TESTx SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TESTx SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3' at line 1
+TEST SYNCHRONIZEx now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SYNCHRONIZEx now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3' at line 1
+TEST SYNCHRONIZE now SIGNALx sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SIGNALx sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3' at line 1
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FORx sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WAIT_FORx sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3' at line 1
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUTx 0 EXECUTE 2 HIT_LIMIT 3;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TIMEOUTx 0 EXECUTE 2 HIT_LIMIT 3' at line 1
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTEx 2 HIT_LIMIx 3;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'EXECUTEx 2 HIT_LIMIx 3' at line 1
+TEST SYNCHRONIZE now CLEARx;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CLEARx' at line 1
+TEST SYNCHRONIZE RESETx;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
+TEST SYNCHRONIZE SHOWx STATUS;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'STATUS' at line 1
+TEST SYNCHRONIZE SHOW STATUSx;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'STATUSx' at line 1
+TEST SYNCHRONIZE SHOW ACTIONx;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ACTIONx' at line 1
+TEST SYNCHRONIZE now TESTx;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TESTx' at line 1
+TEST SYNCHRONIZE now SIGNAL something;
+TEST SYNCHRONIZE SHOW STATUS;
+Status	Current_Signal
+ON	something
+TEST SYNCHRONIZE now WAIT_FOR nothing TIMEOUT 0;
+Warnings:
+Warning	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE now SIGNAL nothing;
+TEST SYNCHRONIZE SHOW STATUS;
+Status	Current_Signal
+ON	nothing
+TEST SYNCHRONIZE now WAIT_FOR nothing TIMEOUT 0;
+TEST SYNCHRONIZE now SIGNAL something EXECUTE 0;
+TEST SYNCHRONIZE SHOW STATUS;
+Status	Current_Signal
+ON	nothing
+TEST SYNCHRONIZE now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0;
+TEST SYNCHRONIZE now HIT_LIMIT 1;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+TEST SYNCHRONIZE SHOW ACTION;
+Sync_Point	Action
+TEST SYNCHRONIZE wait_for_lock SIGNAL s1 WAIT_FOR s2 TIMEOUT 0 EXECUTE 2;
+TEST SYNCHRONIZE now SIGNAL s3 EXECUTE 2;
+TEST SYNCHRONIZE SHOW ACTION;
+Sync_Point	Action
+now	SIGNAL s3
+wait_for_lock	SIGNAL s1 WAIT_FOR s2 TIMEOUT 0 EXECUTE 2
+TEST SYNCHRONIZE now  CLEAR;
+TEST SYNCHRONIZE SHOW ACTION;
+Sync_Point	Action
+wait_for_lock	SIGNAL s1 WAIT_FOR s2 TIMEOUT 0 EXECUTE 2
+TEST SYNCHRONIZE SHOW STATUS;
+Status	Current_Signal
+ON	s3
+TEST SYNCHRONIZE RESET;
+TEST SYNCHRONIZE SHOW STATUS;
+Status	Current_Signal
+ON	
+TEST SYNCHRONIZE SHOW ACTION;
+Sync_Point	Action
+CREATE USER mysqltest_1@localhost;
+GRANT SUPER ON *.* TO mysqltest_1@localhost;
+TEST SYNCHRONIZE now SIGNAL empty;
+DROP USER mysqltest_1@localhost;
+CREATE USER mysqltest_2@localhost;
+GRANT ALL ON *.* TO mysqltest_2@localhost;
+REVOKE SUPER ON *.* FROM mysqltest_2@localhost;
+TEST SYNCHRONIZE now SIGNAL empty;
+ERROR 42000: Access denied; you need the SUPER privilege for this operation
+DROP USER mysqltest_2@localhost;
+TEST SYNCHRONIZE now SIGNAL TEST;
+TEST SYNCHRONIZE now SIGNAL CLEAR;
+TEST SYNCHRONIZE now SIGNAL HIT_LIMIT;
+TEST SYNCHRONIZE now SIGNAL SIGNAL;
+TEST SYNCHRONIZE now SIGNAL SYNCHRONIZE;
+TEST SYNCHRONIZE now SIGNAL TIMEOUT;
+TEST SYNCHRONIZE now SIGNAL WAIT_FOR;
+TEST SYNCHRONIZE RESET;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (c1 INT);
+connection con1
+TEST SYNCHRONIZE before_lock_tables_takes_lock
+SIGNAL opened WAIT_FOR flushed;
+INSERT INTO t1 VALUES(1);
+connection default
+TEST SYNCHRONIZE now WAIT_FOR opened;
+TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed;
+FLUSH TABLE t1;
+connection con1
+connection default
+DROP TABLE t1;
+TEST SYNCHRONIZE RESET;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, c2 INT);
+LOCK TABLE t1 WRITE;
+connection con1
+TEST SYNCHRONIZE wait_for_lock SIGNAL locked WAIT_FOR inserted;
+INSERT INTO t1 SET c2=1;
+connection default
+TEST SYNCHRONIZE now WAIT_FOR locked;
+TEST SYNCHRONIZE after_insert SIGNAL inserted;
+INSERT INTO t1 SET c2=2;
+UNLOCK TABLES;
+connection con1
+connection default
+SELECT * FROM t1;
+c1	c2
+1	2
+2	1
+DROP TABLE t1;
+TEST SYNCHRONIZE RESET;
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-02-11 13:05:17 +01:00
@@ -2,7 +2,9 @@
 # Test of MERGE TABLES
 #
 
+# Clean up resources used in this test case.
 --disable_warnings
+TEST SYNCHRONIZE RESET;
 drop table if exists t1,t2,t3,t4,t5,t6;
 drop database if exists mysqltest;
 --enable_warnings
@@ -693,12 +695,6 @@ 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
@@ -720,12 +716,39 @@ connection default;
 #
 CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
 CREATE TABLE t2 (c1 INT) ENGINE= MRG_MYISAM UNION= (t1) INSERT_METHOD= LAST;
-send REPAIR TABLE t1;
+#
+    --echo connection con1
+    connect (con1,localhost,root,,);
+    # When reaching repair code, signal admin_flush and wait for end_repair.
+    TEST SYNCHRONIZE 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.
+TEST SYNCHRONIZE 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.
+TEST SYNCHRONIZE 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.
+TEST SYNCHRONIZE 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)
+TEST SYNCHRONIZE NOW SIGNAL end_repair;
+#
+    --echo connection con1
     connection con1;
-    sleep 1; # let repair run into its sleep
-    INSERT INTO t2 VALUES (1);
+    reap;
+    disconnect con1;
+#
+--echo connection default;
 connection default;
-reap;
+# Clear test_sync signal.
+TEST SYNCHRONIZE RESET;
 DROP TABLE t1, t2;
 #
 # Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
@@ -740,20 +763,39 @@ DROP TABLE t1, t2;
 # 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;
+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.
+    TEST SYNCHRONIZE mysql_lock_retry HIT_LIMIT 3;
+    # If the bug exists, resume repair thread after reaching the retry limit.
+    TEST SYNCHRONIZE 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.
+    TEST SYNCHRONIZE before_open_table_wait_refresh SIGNAL end_repair;
     send INSERT INTO t2 VALUES (1);
+#
+--echo connection default;
 connection default;
-sleep 1; # Let INSERT go into thr_multi_lock().
-REPAIR TABLE t1;
-sleep 2; # con1 performs busy waiting during this sleep.
+# Wait for signal from insert. Would be infinite with bug and no retry limit.
+TEST SYNCHRONIZE 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 test_sync signal.
+TEST SYNCHRONIZE RESET;
 DROP TABLE t1, t2;
 #
 # Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
@@ -775,28 +817,54 @@ DROP TABLE t1, t2;
 # 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;
-    connection con1;
+#
+    --echo connection con1
+    connect (con1,localhost,root,,);
+    # After open, wait for flush.
+    TEST SYNCHRONIZE 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.
+    TEST SYNCHRONIZE wait_for_lock SIGNAL locked EXECUTE 2;
+    # Alternatively INSERT can wait for refresh in open_table().
+    TEST SYNCHRONIZE before_open_table_wait_refresh SIGNAL locked;
+    # If bug is not fixed, INSERT will succeed. Pretend locked.
+    TEST SYNCHRONIZE after_insert SIGNAL locked;
     send INSERT INTO t1 VALUES (1);
+#
+--echo connection default
 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.
+# Wait until INSERT opened the table.
+TEST SYNCHRONIZE NOW WAIT_FOR opened;
+#
+# Let INSERT exploit the gap when flush waits wthout lock
+# for other threads to close the tables.
+TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed;
 FLUSH TABLES;
-# This should give no result. But it will with sleep(2) at the right place.
+#
+# Wait until INSERT is locked (bug fixed) or finished (bug not fixed).
+TEST SYNCHRONIZE 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 test_sync signal.
+TEST SYNCHRONIZE RESET;
 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
@@ -1122,6 +1190,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,11 +1294,12 @@ 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;
@@ -1238,49 +1308,44 @@ 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;
+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.
+    TEST SYNCHRONIZE before_acos_function SIGNAL 'select' WAIT_FOR truncated;
+    send SELECT ACOS(c1) FROM t3;
+#
+--echo connection default
 connection default;
-sleep 1;
+# Wait for con1 to reach acos().
+TEST SYNCHRONIZE NOW WAIT_FOR 'select';
+#
+# With bug fix present, TRUNCATE runs into wait_for_locked_table_names().
+TEST SYNCHRONIZE before_wait_locked_tname SIGNAL truncated;
 TRUNCATE TABLE t1;
+#
+# With bug fix not present, we need to signal after TRUNCATE.
+TEST SYNCHRONIZE 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 COUNT(*) FROM t1;
-SELECT COUNT(*) FROM t2;
-SELECT COUNT(*) FROM t3;
+SELECT ACOS(c1) FROM t3;
+# Clear test_sync signal.
+TEST SYNCHRONIZE RESET;
 DROP TABLE t1, t2, t3;
 
 #
@@ -1380,4 +1445,170 @@ OPTIMIZE TABLE t1;
 FLUSH TABLES m1, t1;
 UNLOCK TABLES;
 DROP TABLE t1, m1;
+#
+# 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.
+    TEST SYNCHRONIZE 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.
+TEST SYNCHRONIZE NOW WAIT_FOR attach;
+TEST SYNCHRONIZE 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 test_sync signal.
+TEST SYNCHRONIZE 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.
+    TEST SYNCHRONIZE before_myisammrg_attach SIGNAL attach WAIT_FOR store_lock1;
+    TEST SYNCHRONIZE 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.
+TEST SYNCHRONIZE 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.
+TEST SYNCHRONIZE before_myisammrg_store_lock
+  SIGNAL store_lock1 WAIT_FOR store_lock2;
+TEST SYNCHRONIZE 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 test_sync signal.
+TEST SYNCHRONIZE RESET;
+DROP TABLE m1, t1;
+
+#
+# Coverage test for get_user_var().
+# Same test as for Bug#26379, Problem #3.
+# But mysql_test_sync_lock_retry_limit set to null.
+#
+#CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
+#LOCK TABLE t1 WRITE;
+#    --echo connection con1
+#    connect (con1,localhost,root,,);
+#    # Set a null integer value.
+#    SET @mysql_test_sync_lock_retry_limit= NULL;
+#    TEST SYNCHRONIZE before_lock_tables_takes_lock
+#      SIGNAL opened WAIT_FOR flushed;
+#    TEST SYNCHRONIZE wait_for_lock SIGNAL locked EXECUTE 2;
+#    TEST SYNCHRONIZE after_insert SIGNAL locked;
+#    send INSERT INTO t1 VALUES (1);
+#--echo connection default;
+#connection default;
+#TEST SYNCHRONIZE NOW WAIT_FOR opened;
+#TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed;
+#FLUSH TABLES;
+#TEST SYNCHRONIZE NOW WAIT_FOR locked;
+#UNLOCK TABLES;
+#    --echo connection con1
+#    connection con1;
+#    reap;
+#    disconnect con1;
+#--echo connection default;
+#connection default;
+# Clear test_sync signal.
+#TEST SYNCHRONIZE RESET;
+#DROP TABLE t1;
+#
+# Coverage test for mysql_lock_retry_limit().
+# Similar test as for Bug#26379, Problem #3.
+# But mysql_lock_retry limit set to 2 and FLUSH repeated
+# so that the INSERT results in ER_LOCK_WAIT_TIMEOUT.
+#
+CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
+LOCK TABLE t1 WRITE;
+#
+    --echo connection con1
+    connect (con1,localhost,root,,);
+    TEST SYNCHRONIZE mysql_lock_retry HIT_LIMIT 2;
+    # After open, wait for flush.
+    TEST SYNCHRONIZE before_lock_tables_takes_lock
+      SIGNAL opened WAIT_FOR flushed EXECUTE 2;
+    # If bug is fixed, INSERT will go into wait_for_lock.
+    # Retain action after use. First used by general_log.
+    TEST SYNCHRONIZE wait_for_lock SIGNAL locked EXECUTE 4;
+    # Alternatively INSERT can wait for refresh in open_table().
+    TEST SYNCHRONIZE before_open_table_wait_refresh SIGNAL refresh EXECUTE 2;
+    # If bug is not fixed, INSERT will succeed. Pretend locked.
+    TEST SYNCHRONIZE after_insert SIGNAL locked EXECUTE 2;
+    #SET debug='+d,test_sync_point,test_sync_exec:+i';
+    send INSERT INTO t1 VALUES (1);
+#
+--echo connection default;
+connection default;
+#SET debug='+d,test_sync_point,test_sync_exec:+i';
+#
+# Wait until INSERT opened the table.
+TEST SYNCHRONIZE NOW WAIT_FOR opened;
+#
+# Let INSERT exploit the gap when flush waits wthout lock
+# for other threads to close the tables.
+TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed EXECUTE 2;
+FLUSH TABLES;
+#
+# Wait until INSERT waits for refresh.
+# Then we need to close and reopen the table to let it succed another open.
+TEST SYNCHRONIZE NOW WAIT_FOR refresh;
+UNLOCK TABLES;
+LOCK TABLE t1 WRITE;
+#
+# Wait until INSERT opened the table the second time.
+# Then flush the second time.
+TEST SYNCHRONIZE NOW WAIT_FOR opened;
+FLUSH TABLES;
+#
+# Wait until INSERT is locked (bug fixed) or finished (bug not fixed).
+TEST SYNCHRONIZE NOW WAIT_FOR locked;
+UNLOCK TABLES;
+#
+    --echo connection con1
+    connection con1;
+    # Succeeds if TEST SYNCHRONIZE is disabled
+    --error 0, ER_LOCK_WAIT_TIMEOUT
+    reap;
+    disconnect con1;
+#
+--echo connection default;
+connection default;
+#
+# Clear test_sync signal.
+TEST SYNCHRONIZE RESET;
+DROP TABLE t1;
 
diff -Nrup a/mysql-test/t/test_synchronize.test b/mysql-test/t/test_synchronize.test
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/test_synchronize.test	2008-02-11 13:05:18 +01:00
@@ -0,0 +1,346 @@
+###################### t/test_synchronize.test #########################
+#                                                                      #
+# Testing of the TEST SYNCHRONIZE facility.                            #
+#                                                                      #
+# There is important documentation within                              #
+#       sql/mysql_test_sync.cc                                         #
+#                                                                      #
+# Creation:                                                            #
+# 2007-12-14 ingo                                                      #
+#                                                                      #
+########################################################################
+
+#
+# We are checking privileges, which the embedded server cannot do.
+#
+--source include/not_embedded.inc
+
+#
+# Preparative cleanup.
+# Otherwise SHOW ACTION below might show old actions.
+#
+TEST SYNCHRONIZE RESET;
+
+#
+# Syntax. Valid forms.
+# Using the special synchronization point "now" here.
+# Using timeout=0 to avoid blocking as there is noone to wake us.
+# Consequently we cannot show omission of timeout.
+#
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2;
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0           HIT_LIMIT 3;
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0;
+TEST SYNCHRONIZE now SIGNAL sig1                         EXECUTE 2 HIT_LIMIT 3;
+TEST SYNCHRONIZE now SIGNAL sig1                         EXECUTE 2;
+TEST SYNCHRONIZE now SIGNAL sig1                                   HIT_LIMIT 3;
+TEST SYNCHRONIZE now SIGNAL sig1;
+TEST SYNCHRONIZE now             WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+TEST SYNCHRONIZE now             WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2;
+TEST SYNCHRONIZE now             WAIT_FOR sig2 TIMEOUT 0           HIT_LIMIT 3;
+TEST SYNCHRONIZE now             WAIT_FOR sig2 TIMEOUT 0;
+TEST SYNCHRONIZE now                                               HIT_LIMIT 3;
+TEST SYNCHRONIZE now CLEAR;
+TEST SYNCHRONIZE RESET;
+TEST SYNCHRONIZE SHOW STATUS;
+TEST SYNCHRONIZE SHOW ACTION;
+TEST SYNCHRONIZE now TEST;
+
+#
+# Syntax. Valid forms. Lower case.
+#
+test synchronize now signal sig1 wait_for sig2 timeout 0 execute 2 hit_limit 3;
+test synchronize now signal sig1 wait_for sig2 timeout 0 execute 2;
+test synchronize now signal sig1 wait_for sig2 timeout 0           hit_limit 3;
+test synchronize now signal sig1 wait_for sig2 timeout 0;
+test synchronize now signal sig1                         execute 2 hit_limit 3;
+test synchronize now signal sig1                         execute 2;
+test synchronize now signal sig1                                   hit_limit 3;
+test synchronize now signal sig1;
+test synchronize now             wait_for sig2 timeout 0 execute 2 hit_limit 3;
+test synchronize now             wait_for sig2 timeout 0 execute 2;
+test synchronize now             wait_for sig2 timeout 0           hit_limit 3;
+test synchronize now             wait_for sig2 timeout 0;
+test synchronize now                                               hit_limit 3;
+test synchronize now clear;
+test synchronize reset;
+test synchronize show status;
+test synchronize show action;
+test synchronize now test;
+
+#
+# Syntax. Valid forms. Strings are allowed.
+#
+TEST SYNCHRONIZE 'now' SIGNAL sig1   WAIT_FOR sig2   TIMEOUT 0;
+TEST SYNCHRONIZE now   SIGNAL 'sig1' WAIT_FOR sig2   TIMEOUT 0;
+TEST SYNCHRONIZE now   SIGNAL sig1   WAIT_FOR 'sig2' TIMEOUT 0;
+
+#
+# Syntax. Valid forms. Numbers can be preceded by '='.
+#
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT=3;
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 EXECUTE=2 HIT_LIMIT 3;
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 EXECUTE=2 HIT_LIMIT=3;
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT=0 EXECUTE 2 HIT_LIMIT 3;
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT=0 EXECUTE 2 HIT_LIMIT=3;
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT=0 EXECUTE=2 HIT_LIMIT 3;
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT=0 EXECUTE=2 HIT_LIMIT=3;
+
+#
+# Syntax. Valid forms. Non-reserved keywords are allowed. (e.g. FLUSH)
+#
+TEST SYNCHRONIZE now   SIGNAL sig1  WAIT_FOR FLUSH TIMEOUT 0;
+TEST SYNCHRONIZE now   SIGNAL FLUSH WAIT_FOR sig2  TIMEOUT 0;
+# Syntax allowed, but sync point is unknown.
+--error ER_UNKNOWN_ERROR
+TEST SYNCHRONIZE FLUSH SIGNAL sig1  WAIT_FOR sig2  TIMEOUT 0;
+
+#
+# Syntax. Invalid forms. Reserved keywords are not allowed. (e.g. WHERE)
+#
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE WHERE SIGNAL sig1  WAIT_FOR sig2  TIMEOUT 0;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now   SIGNAL WHERE WAIT_FOR sig2  TIMEOUT 0;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now   SIGNAL sig1  WAIT_FOR WHERE TIMEOUT 0;
+
+#
+# Syntax. Invalid forms.
+#
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now                                          EXECUTE 2;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now                                TIMEOUT 0 EXECUTE 2;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now                                TIMEOUT 0;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now WAIT_FOR sig2 SIGNAL sig1;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now WAIT_FOR sig2 SIGNAL sig1           EXECUTE 2;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now WAIT_FOR sig2 SIGNAL sig1 TIMEOUT 0 EXECUTE 2;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now WAIT_FOR sig2 SIGNAL sig1 TIMEOUT 0;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 SIGNAL sig1 EXECUTE 2;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now WAIT_FOR sig2 TIMEOUT 0 SIGNAL sig1;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now TIMEOUT 0 WAIT_FOR sig2 EXECUTE 2;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now TIMEOUT 0 WAIT_FOR sig2;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now                  SIGNAL sig1 TIMEOUT 0 EXECUTE 2;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now                  SIGNAL sig1 TIMEOUT 0;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now EXECUTE 2 SIGNAL sig1 TIMEOUT 0;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now TIMEOUT 0 SIGNAL sig1;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now EXECUTE 2 TIMEOUT 0 SIGNAL sig1;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now CLEAR HIT_LIMIT 3;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE CLEAR;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now RESET;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now SHOW;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now SHOW STATUS;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now SHOW ACTION;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now SHOW test;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE TEST;
+
+#
+# Syntax. Invalid keywords used.
+#
+--error ER_PARSE_ERROR
+TESTx SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZEx now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now SIGNALx sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FORx sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUTx 0 EXECUTE 2 HIT_LIMIT 3;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTEx 2 HIT_LIMIx 3;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now CLEARx;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE RESETx;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE SHOWx STATUS;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE SHOW STATUSx;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE SHOW ACTIONx;
+--error ER_PARSE_ERROR
+TEST SYNCHRONIZE now TESTx;
+
+#
+# Functional tests.
+#
+# NOTE: There is the special synchronization point 'now'. It is placed
+#       immediately after setting of an action.
+#       So it is executed before the TEST SYNCHRONIZE statement ends.
+#
+# NOTE: There is only on global signal (say "signal post" or "flag mast").
+#       A SIGNAL activity 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"):
+#       TEST SYNCHRONIZE now SIGNAL empty;
+#       Alternatively you can reset the whole facility with:
+#       TEST SYNCHRONIZE RESET;
+#       The signal is then '' (really empty) which connot be done otherwise.
+#
+
+#
+# Time out immediately. This gives just a warning.
+#
+TEST SYNCHRONIZE now SIGNAL something;
+TEST SYNCHRONIZE SHOW STATUS;
+TEST SYNCHRONIZE now WAIT_FOR nothing TIMEOUT 0;
+#
+# If signal is present already, TIMEOUT 0 does not give a warning.
+#
+TEST SYNCHRONIZE now SIGNAL nothing;
+TEST SYNCHRONIZE SHOW STATUS;
+TEST SYNCHRONIZE now WAIT_FOR nothing TIMEOUT 0;
+
+#
+# EXECUTE 0 is effectively a no-op.
+#
+TEST SYNCHRONIZE now SIGNAL something EXECUTE 0;
+TEST SYNCHRONIZE SHOW STATUS;
+TEST SYNCHRONIZE now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0;
+
+#
+# Run into HIT_LIMIT. This gives an error.
+#
+--error ER_LOCK_WAIT_TIMEOUT
+TEST SYNCHRONIZE now HIT_LIMIT 1;
+
+#
+# List active actions.
+#
+TEST SYNCHRONIZE SHOW ACTION;
+TEST SYNCHRONIZE wait_for_lock SIGNAL s1 WAIT_FOR s2 TIMEOUT 0 EXECUTE 2;
+TEST SYNCHRONIZE now SIGNAL s3 EXECUTE 2;
+TEST SYNCHRONIZE SHOW ACTION;
+TEST SYNCHRONIZE now  CLEAR;
+TEST SYNCHRONIZE SHOW ACTION;
+TEST SYNCHRONIZE SHOW STATUS;
+TEST SYNCHRONIZE RESET;
+TEST SYNCHRONIZE SHOW STATUS;
+TEST SYNCHRONIZE SHOW ACTION;
+
+#
+# Facility requires SUPER privilege.
+#
+CREATE USER mysqltest_1@localhost;
+GRANT SUPER ON *.* TO mysqltest_1@localhost;
+connect (con1,localhost,mysqltest_1,,);
+TEST SYNCHRONIZE now SIGNAL empty;
+disconnect con1;
+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;
+connect (con1,localhost,mysqltest_2,,);
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+TEST SYNCHRONIZE now SIGNAL empty;
+disconnect con1;
+connection default;
+DROP USER mysqltest_2@localhost;
+
+#
+# Coverage test of parser. Use keywords defined by this facility.
+#
+TEST SYNCHRONIZE now SIGNAL TEST;
+TEST SYNCHRONIZE now SIGNAL CLEAR;
+TEST SYNCHRONIZE now SIGNAL HIT_LIMIT;
+TEST SYNCHRONIZE now SIGNAL SIGNAL;
+TEST SYNCHRONIZE now SIGNAL SYNCHRONIZE;
+TEST SYNCHRONIZE now SIGNAL TIMEOUT;
+TEST SYNCHRONIZE now SIGNAL WAIT_FOR;
+
+#
+# Example 1.
+#
+# Preparative cleanup.
+--disable_warnings
+TEST SYNCHRONIZE RESET;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+#
+# Test.
+CREATE TABLE t1 (c1 INT);
+    --echo connection con1
+    connect (con1,localhost,root,,);
+    TEST SYNCHRONIZE before_lock_tables_takes_lock
+      SIGNAL opened WAIT_FOR flushed;
+    send INSERT INTO t1 VALUES(1);
+--echo connection default
+connection default;
+TEST SYNCHRONIZE now WAIT_FOR opened;
+TEST SYNCHRONIZE after_flush_unlock SIGNAL flushed;
+FLUSH TABLE t1;
+    --echo connection con1
+    connection con1;
+    reap;
+    disconnect con1;
+--echo connection default
+connection default;
+DROP TABLE t1;
+
+#
+# Example 2.
+#
+# Preparative cleanup.
+--disable_warnings
+TEST SYNCHRONIZE RESET;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+#
+# Test.
+CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, c2 INT);
+LOCK TABLE t1 WRITE;
+    --echo connection con1
+    connect (con1,localhost,root,,);
+    TEST SYNCHRONIZE wait_for_lock SIGNAL locked WAIT_FOR inserted;
+    send INSERT INTO t1 SET c2=1;
+--echo connection default
+connection default;
+TEST SYNCHRONIZE now WAIT_FOR locked;
+TEST SYNCHRONIZE after_insert SIGNAL inserted;
+INSERT INTO t1 SET c2=2;
+UNLOCK TABLES;
+    --echo connection con1
+    connection con1;
+    reap;
+    disconnect con1;
+--echo connection default
+connection default;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Cleanup after test case.
+# Otherwise signal would contain 'flushed' here,
+# which could confuse the next test.
+#
+TEST SYNCHRONIZE RESET;
+
diff -Nrup a/mysys/thr_lock.c b/mysys/thr_lock.c
--- a/mysys/thr_lock.c	2007-11-15 20:25:40 +01:00
+++ b/mysys/thr_lock.c	2008-02-11 13:05:18 +01:00
@@ -386,6 +386,12 @@ static inline my_bool have_specific_lock
 
 static void wake_up_waiters(THR_LOCK *lock);
 
+/**
+  Global pointer to be set if callback function is defined
+  (e.g. in mysqld). See mysql_test_sync.cc.
+*/
+void (*test_sync_wait_for_lock_callback_ptr)(void);
+
 
 static enum enum_thr_lock_result
 wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
@@ -397,6 +403,13 @@ 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");
+
+  /*
+    One can use this to signal when a thread is going to wait for a lock.
+    See mysql_test_sync.cc.
+  */
+  if (test_sync_wait_for_lock_callback_ptr)
+    (*test_sync_wait_for_lock_callback_ptr)();
 
   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-02-11 13:05:18 +01:00
@@ -76,6 +76,7 @@ ADD_EXECUTABLE(mysqld
                rpl_rli.cc rpl_mi.cc sql_servers.cc
                sql_connect.cc scheduler.cc 
                sql_profile.cc
+               mysql_test_sync.cc mysql_test_sync.h
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
                ${PROJECT_SOURCE_DIR}/include/mysqld_error.h
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-02-11 13:05:18 +01:00
@@ -86,7 +86,7 @@ noinst_HEADERS =	item.h item_func.h item
 			event_data_objects.h event_scheduler.h \
 			sql_partition.h partition_info.h partition_element.h \
 			probes.h \
-			contributors.h sql_servers.h
+			contributors.h sql_servers.h mysql_test_sync.h
 
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc sql_partition.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -130,7 +130,7 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
                         event_queue.cc event_db_repository.cc events.cc \
 			sql_plugin.cc sql_binlog.cc \
 			sql_builtin.cc sql_tablespace.cc partition_info.cc \
-			sql_servers.cc sha2.cc
+			sql_servers.cc sha2.cc mysql_test_sync.cc
 
 if HAVE_DTRACE
   mysqld_SOURCES += probes.d
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-02-11 13:05:18 +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. */
+  TEST_SYNCHRONIZE(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/lex.h b/sql/lex.h
--- a/sql/lex.h	2007-12-18 15:36:15 +01:00
+++ b/sql/lex.h	2008-02-11 13:05:18 +01:00
@@ -105,6 +105,7 @@ static SYMBOL symbols[] = {
   { "CHECK",		SYM(CHECK_SYM)},
   { "CHECKSUM",		SYM(CHECKSUM_SYM)},
   { "CIPHER",		SYM(CIPHER_SYM)},
+  { "CLEAR",            SYM(CLEAR_SYM)},
   { "CLIENT",		SYM(CLIENT_SYM)},
   { "CLOSE",		SYM(CLOSE_SYM)},
   { "COALESCE",		SYM(COALESCE)},
@@ -234,6 +235,7 @@ static SYMBOL symbols[] = {
   { "HAVING",		SYM(HAVING)},
   { "HELP",		SYM(HELP_SYM)},
   { "HIGH_PRIORITY",	SYM(HIGH_PRIORITY)},
+  { "HIT_LIMIT",        SYM(HIT_LIMIT_SYM)},
   { "HOST",		SYM(HOST_SYM)},
   { "HOSTS",		SYM(HOSTS_SYM)},
   { "HOUR",		SYM(HOUR_SYM)},
@@ -478,6 +480,7 @@ static SYMBOL symbols[] = {
   { "SHARE",		SYM(SHARE_SYM)},
   { "SHOW",		SYM(SHOW)},
   { "SHUTDOWN",		SYM(SHUTDOWN)},
+  { "SIGNAL",           SYM(SIGNAL_SYM)},
   { "SIGNED",		SYM(SIGNED_SYM)},
   { "SIMPLE",		SYM(SIMPLE_SYM)},
   { "SLAVE",            SYM(SLAVE)},
@@ -526,16 +529,19 @@ static SYMBOL symbols[] = {
   { "SUSPEND",          SYM(SUSPEND_SYM)},
   { "SWAPS",      SYM(SWAPS_SYM)},
   { "SWITCHES",   SYM(SWITCHES_SYM)},
+  { "SYNCHRONIZE",      SYM(SYNCHRONIZE_SYM)},
   { "TABLE",		SYM(TABLE_SYM)},
   { "TABLES",		SYM(TABLES)},
   { "TABLESPACE",	SYM(TABLESPACE)},
   { "TEMPORARY",	SYM(TEMPORARY)},
   { "TEMPTABLE",	SYM(TEMPTABLE_SYM)},
   { "TERMINATED",	SYM(TERMINATED)},
+  { "TEST",             SYM(TEST_SYM)},
   { "TEXT",		SYM(TEXT_SYM)},
   { "THAN",             SYM(THAN_SYM)},
   { "THEN",		SYM(THEN_SYM)},
   { "TIME",		SYM(TIME_SYM)},
+  { "TIMEOUT",          SYM(TIMEOUT_SYM)},
   { "TIMESTAMP",	SYM(TIMESTAMP)},
   { "TIMESTAMPADD",     SYM(TIMESTAMP_ADD)},
   { "TIMESTAMPDIFF",    SYM(TIMESTAMP_DIFF)},
@@ -582,6 +588,7 @@ static SYMBOL symbols[] = {
   { "VARCHARACTER",	SYM(VARCHAR)},
   { "VARIABLES",	SYM(VARIABLES)},
   { "VARYING",		SYM(VARYING)},
+  { "WAIT_FOR",         SYM(WAIT_FOR_SYM)},
   { "WAIT",		SYM(WAIT_SYM)},
   { "WARNINGS",		SYM(WARNINGS)},
   { "WEEK",		SYM(WEEK_SYM)},
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-02-11 13:05:18 +01:00
@@ -351,6 +351,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
     */
     reset_lock_data_and_free(&sql_lock);
 retry:
+    TEST_SYNCHRONIZE(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;
     }
+    TEST_SYNCHRONIZE(thd, before_wait_locked_tname);
     wait_for_condition(thd, &LOCK_open, &COND_refresh);
     pthread_mutex_lock(&LOCK_open);
   }
diff -Nrup a/sql/mysql_test_sync.cc b/sql/mysql_test_sync.cc
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/mysql_test_sync.cc	2008-02-11 13:05:18 +01:00
@@ -0,0 +1,819 @@
+/* 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 */
+
+/*
+  Test Synchronization Facility.
+
+  The Test Synchronization Facility allows to place synchronization points
+  in the code:
+
+      open_tables(...)
+
+      TEST_SYNCHRONIZE(thd, after_open_tables);
+
+      lock_tables(...)
+
+  When activated, a sync point can
+
+    - Send a signal and/or
+    - Wait for a signal
+
+  Nomenclature:
+
+    - signal:             A global value that keeps its value until
+                          overwritten by a new signal. One may also say
+                          "signal post" or "flag mast".
+
+    - send a signal:      Set the global value ("set a flag") and
+                          broadcast a global condition.
+
+    - 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:
+
+      TEST SYNCHRONIZE sync_point_name SIGNAL signal_1 WAIT_FOR signal_2;
+
+  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
+      TEST SYNCHRONIZE after_open_tables SIGNAL opened WAIT_FOR flushed;
+      send INSERT INTO t1 VALUES(1);
+          --connection conn2
+          TEST SYNCHRONIZE now WAIT_FOR opened;
+          TEST SYNCHRONIZE 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:
+
+      TEST SYNCHRONIZE 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:
+
+      TEST SYNCHRONIZE 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:
+
+      TEST SYNCHRONIZE name HIT_LIMIT 3;
+
+  Or combine it with signal and/or wait:
+
+      TEST SYNCHRONIZE 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:
+
+      TEST SYNCHRONIZE name CLEAR;
+
+  If you want to clear all actions and clear the global signal, use:
+
+      TEST SYNCHRONIZE RESET;
+
+  This is the only way to reset the global signal to an empty string.
+
+  For testing the facility itself there are the following pseudo actions:
+
+      TEST SYNCHRONIZE SHOW STATUS;
+      Status   Current_Signal
+      ON       s1
+
+      TEST SYNCHRONIZE SHOW ACTION;
+      Sync_Point   Action
+      p2abc        SIGNAL s2 EXECUTE 2
+      p1abcd       SIGNAL s1
+
+      TEST SYNCHRONIZE sync_point_to_test TEST;
+
+  The latter executes the action for 'sync_point_to_test' (if any) just as
+  if the sync point had been hit during the TEST SYNCHRONIZE statement.
+
+  The Test Synchronization Facility is disabled by default. It can be
+  enabled by a mysqld command line option:
+
+      --test-synchronize[=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 ... --test-synchronize=0 ...
+
+  Likewise the default wait timeout can be set:
+
+      mysql-test-run.pl ... --test-synchronize=10 ...
+
+
+  ==== Implementation ====
+
+  Pseudo code for a sync point:
+
+      #define TEST_SYNCHRONIZE(thd, sync_point_identifier)
+                if (unlikely(opt_test_synchronize))
+                  test_synchronize(thd, sync_point_identifier)
+
+  There is an enum with synchronization point identifiers, a typelib that
+  maps sync point names to their identifiers, and an array of actions per
+  sync point referenced from THD.
+
+      void test_synchronize(thd, sync_point_identifier)
+      {
+        if (!thd->test_sync_action[sync_point_identifier].activation_count)
+          return;
+        execute test sync point action
+      }
+
+  The TEST SYNCHRONIZE statement searches for the array slot of the
+  sync point by using the typelib. It does then modify the array slot.
+
+  To add a new sync point one must:
+
+      1. Edit the enum in mysql_test_sync.h
+      2. Edit the string array in mysql_test_sync.cc
+      3. Edit the file where the sync point is to be put.
+*/
+
+#include "mysql_priv.h"
+
+/*
+  Test synchronization point names must match enum_test_sync_point in
+  mysql_test_sync.h.
+*/
+static const char *test_sync_point_names[] =
+{
+  /* Special sync point: TEST SYNCHRONIZE now [SEND sig] [WAIT_FOR sig] */
+  "now",
+
+  /* Normal sync points. */
+  "before_open_table_wait_refresh",
+  "before_lock_tables_takes_lock",
+  "wait_for_lock",
+  "mysql_lock_retry",
+  "after_insert",
+  "after_flush_unlock",
+  "after_admin_flush",
+  "before_acos_function",
+  "before_wait_locked_tname",
+  "before_myisammrg_attach",
+  "before_myisammrg_store_lock",
+
+  /* Do not add sync points below this line. */
+  NullS
+};
+
+/*
+  Typelib made from the synchronization point names array.
+*/
+static TYPELIB test_sync_point_typelib=
+{
+  array_elements(test_sync_point_names) - 1,
+  "test_sync_point_typelib",
+  test_sync_point_names,
+  NULL
+};
+
+/**
+  Definitions for the test synchronization facility.
+  1. Global string variable to hold a "signal".
+  2. Global condition variable for signaling and waiting.
+  3. Global mutex to synchronize access to the above.
+*/
+
+static String SIGNAL_test_sync;
+static pthread_cond_t COND_test_sync;
+static pthread_mutex_t LOCK_test_sync;
+
+/**
+  Callback pointer from thr_lock.cc
+*/
+extern void (*test_sync_wait_for_lock_callback_ptr)(void);
+
+
+/**
+  Callback from wait_for_lock() for test synchronization. See thr_lock.c.
+
+  @description
+    One can use this to signal when a thread is going to wait for a lock.
+
+  @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.
+
+  @note
+    The callback pointer in thr_lock.c is set only if test
+    synchronization is initialized. And this is done only if
+    opt_test_synchronize is non-zero.
+*/
+
+static void test_sync_wait_for_lock_callback(void)
+{
+  test_synchronize(current_thd, wait_for_lock);
+}
+
+
+/**
+  Initialize the test synchronization facility at server start.
+
+  @return status
+    @retval     0       ok
+    @retval     != 0    error
+
+  @note
+    This is called only if opt_test_synchronize is non-zero.
+*/
+
+int test_sync_init(void)
+{
+  DBUG_ENTER("test_sync_init");
+  DBUG_ASSERT(opt_test_synchronize);
+
+  /*
+    Initialize the global variables before the consistency check
+    so that they can be destroyed by server clean up.
+  */
+  SIGNAL_test_sync.length(0);
+  (void) pthread_cond_init(&COND_test_sync, NULL);
+  (void) pthread_mutex_init(&LOCK_test_sync, MY_MUTEX_INIT_FAST);
+
+  /* Consistency check. */
+  if (array_elements(test_sync_point_names) - 1 != NUMBER_OF_SYNC_POINTS)
+  {
+    my_printf_error(ER_UNKNOWN_ERROR,
+                    "Internal error:  "
+                    "number of synchronization point names: %d  "
+                    "does not match number of enums: %d  "
+                    "run with --test-synchronize=0",
+                    MYF(0), array_elements(test_sync_point_names),
+                    NUMBER_OF_SYNC_POINTS);
+    DBUG_RETURN(1);
+  }
+
+  /* Set the call back pointer in thr_lock.c. */
+  test_sync_wait_for_lock_callback_ptr=
+    test_sync_wait_for_lock_callback;
+
+  DBUG_RETURN(0);
+}
+
+
+/**
+  End the test synchronization facility.
+
+  @description
+    This is called at server shutdown or after an thread initialization error.
+*/
+
+void test_sync_end(void)
+{
+  DBUG_ENTER("test_sync_end");
+
+  /* End the facility only if it had been initialized. */
+  if (test_sync_wait_for_lock_callback_ptr)
+  {
+    /* Clear the call back pointer in thr_lock.c. */
+    test_sync_wait_for_lock_callback_ptr= NULL;
+
+    /* Destroy the global variables. */
+    SIGNAL_test_sync.free();
+    (void) pthread_cond_destroy(&COND_test_sync);
+    (void) pthread_mutex_destroy(&LOCK_test_sync);
+  }
+
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Initialize the test synchronization facility at thread start.
+
+  @param[in]    thd             thread handle
+*/
+
+void test_sync_init_thread(THD *thd)
+{
+  DBUG_ENTER("test_sync_init_thread");
+
+  if (opt_test_synchronize)
+  {
+    thd->test_sync_action= (st_test_sync_action*)
+      my_malloc(NUMBER_OF_SYNC_POINTS * sizeof(st_test_sync_action),
+                MYF(MY_WME | MY_ZEROFILL));
+    if (!thd->test_sync_action)
+    {
+      /* purecov: tested */
+      /*
+        We must disable the facility. We have no way to return an error.
+        We do not end the facility here because the global variables can
+        be in use by other threads.
+      */
+      pthread_mutex_lock(&LOCK_test_sync);
+      opt_test_synchronize= 0;
+      pthread_mutex_unlock(&LOCK_test_sync);
+      DBUG_PRINT("test_sync", ("Test Synchronization Facility disabled "
+                               "due to lack of memory."));
+      sql_print_error("Test Synchronization Facility disabled "
+                      "due to lack of memory.");
+      /* purecov: end */
+    }
+  }
+
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  End the test synchronization facility at thread end.
+
+  @param[in]    thd             thread handle
+*/
+
+void test_sync_end_thread(THD *thd)
+{
+  DBUG_ENTER("test_sync_end_thread");
+
+  if (thd->test_sync_action)
+  {
+    st_test_sync_action *action= thd->test_sync_action;
+    st_test_sync_action *action_end= action + NUMBER_OF_SYNC_POINTS;
+
+    for (; action < action_end; action++)
+    {
+      action->signal.free();
+      action->wait_for.free();
+    }
+    my_free(thd->test_sync_action, MYF(0));
+  }
+
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  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 test_sync_action_string(char *result, uint size,
+                                    st_test_sync_action *action)
+{
+  char  *wtxt= result;
+  char  *wend= wtxt + size - 1; /* Allow emergency '\0'. */
+  DBUG_ENTER("test_sync_action_string");
+
+  if (action->signal.length())
+  {
+    wtxt= strxnmov(wtxt, wend - wtxt, "SIGNAL ", action->signal.c_ptr(), NullS);
+  }
+  if (action->wait_for.length())
+  {
+    wtxt= strxnmov(wtxt, wend - wtxt, (wtxt == result) ? "" : " ",
+                   "WAIT_FOR ", action->wait_for.c_ptr(), NullS);
+    if (action->timeout != opt_test_synchronize)
+    {
+      wtxt+= my_snprintf(wtxt, wend - wtxt, " TIMEOUT %lu", action->timeout);
+    }
+  }
+  if (!action->signal.length() && !action->wait_for.length())
+  {
+    wtxt= strnmov(wtxt, "CLEAR", wend - wtxt);
+  }
+  else
+  {
+    if (action->execute != 1)
+    {
+      wtxt+= my_snprintf(wtxt, wend - wtxt, " EXECUTE %lu", action->execute);
+    }
+    if (action->hit_limit != 0)
+    {
+      wtxt+= my_snprintf(wtxt, wend - wtxt, " HIT_LIMIT %lu",
+                         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;
+}
+
+
+/**
+  Set a test synchronization action.
+
+  @param[in]    thd             thread handle
+  @param[in]    request         synchronization request
+*/
+
+int test_sync_set_action(THD *thd, st_test_sync_request *request)
+{
+  st_test_sync_action *action;
+  int sync_point_id;
+  DBUG_ENTER("test_sync_set_action");
+
+  if (!opt_test_synchronize)
+  {
+    /*
+      Do not raise error or warning. Test result should not
+      unnecessarily differ from enabled facility.
+    */
+    DBUG_PRINT("test_sync", ("facility disabled"));
+    goto end;
+  }
+
+  /* Find synchronisation point array index by its name. */
+  if ((sync_point_id= find_type(request->sync_point.str,
+                                &test_sync_point_typelib, 1+2)) > 0)
+  {
+    sync_point_id--; /* find_type() returns offset + 1. */
+    DBUG_ASSERT(sync_point_id < NUMBER_OF_SYNC_POINTS);
+    action= &thd->test_sync_action[sync_point_id];
+  }
+  else
+  {
+    my_printf_error(ER_UNKNOWN_ERROR, "No such synchronization point: '%.64s'",
+                    MYF(0), request->sync_point.str);
+    goto err;
+  }
+
+  /* Create the action struct from the request. */
+  action->activation_count= max(request->hit_limit, request->execute);
+  if (action->activation_count)
+  {
+    action->hit_limit=  request->hit_limit;
+    action->execute=    request->execute;
+    action->timeout=    request->timeout;
+    action->signal.copy(request->signal.str,
+                        request->signal.length, system_charset_info);
+    action->wait_for.copy(request->wait_for.str,
+                          request->wait_for.length, system_charset_info);
+
+    DBUG_PRINT("test_sync", ("sync_point: '%s'  activation_count: %lu  "
+                             "hit_limit: %lu  execute: %lu  timeout: %lu  "
+                             "signal: '%s'  wait_for: '%s'",
+                             request->sync_point.str,
+                             action->activation_count, action->hit_limit,
+                             action->execute, action->timeout,
+                             action->signal.c_ptr(), action->wait_for.c_ptr()));
+
+    TEST_SYNCHRONIZE(thd, now);
+    /* Hit_limit can produce an error message. */
+    if (thd->main_da.is_error())
+      goto err;
+  }
+  else
+    DBUG_PRINT("test_sync", ("sync_point: '%s'  cleared",
+                             request->sync_point.str));
+
+ end:
+  send_ok(thd);
+  DBUG_RETURN(0);
+
+ err:
+  DBUG_RETURN(1);
+}
+
+
+/**
+  Execute a test synchronization command.
+
+  @param[in]    thd             thread handle
+  @param[in]    request         synchronization request
+*/
+
+int test_sync_do_command(THD *thd, st_test_sync_request *request)
+{
+  int sync_point_id;
+  DBUG_ENTER("test_sync_do_command");
+
+  /* The SHOW STATUS command works even with disabled facility. */
+  if (!opt_test_synchronize && (request->command != show_status))
+  {
+    /*
+      Do not raise error or warning. Test result should not
+      unnecessarily differ from enabled facility.
+    */
+    DBUG_PRINT("test_sync", ("facility disabled"));
+    goto end;
+  }
+
+  switch (request->command) {
+  case reset:
+    {
+      st_test_sync_action *action= thd->test_sync_action;
+      st_test_sync_action *action_end= action + NUMBER_OF_SYNC_POINTS;
+
+      /* Clear all actions. */
+      for (; action < action_end; action++)
+        action->activation_count= 0;
+
+      /* Reset the global signal. */
+      SIGNAL_test_sync.length(0);
+
+      goto end;
+    }
+  case show_status:
+    {
+      List<Item>    fields;
+      Item          *item;
+      CHARSET_INFO  *cs= system_charset_info;
+      Protocol      *protocol= thd->protocol;
+
+      /* Send field list. */
+      fields.push_back(item= new Item_empty_string("Status", 7, cs));
+      fields.push_back(item= new Item_empty_string("Current_Signal", 32, cs));
+      item->maybe_null = 1;
+      if (protocol->send_fields(&fields,
+                                Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+        goto err;
+
+      /* Send info. */
+      protocol->prepare_for_resend();
+      if (opt_test_synchronize)
+      {
+        protocol->store(STRING_WITH_LEN("ON"), cs);
+        protocol->store(SIGNAL_test_sync.ptr(), SIGNAL_test_sync.length(), cs);
+        if (protocol->write())
+          goto err;
+      }
+      else
+      {
+        protocol->store(STRING_WITH_LEN("OFF"), cs);
+        protocol->store_null();
+        if (protocol->write())
+          goto err;
+      }
+      goto eof;
+    }
+  case show_action:
+    {
+      List<Item>    fields;
+      Item          *item;
+      CHARSET_INFO  *cs= system_charset_info;
+      Protocol      *protocol= thd->protocol;
+      st_test_sync_action *action= thd->test_sync_action;
+      st_test_sync_action *action_end= action + NUMBER_OF_SYNC_POINTS;
+
+      /* Send field list. */
+      fields.push_back(item= new Item_empty_string("Sync_Point", 32, cs));
+      fields.push_back(item= new Item_empty_string("Action", 256, cs));
+      if (protocol->send_fields(&fields,
+                                Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+        goto err;
+
+      /* Send actions. */
+      for (; action < action_end; action++)
+      {
+        const char *sync_point_name;
+        char       action_string[256];
+
+        if (!action->activation_count)
+          continue;
+
+        /* Collect info. */
+        sync_point_name= get_type(&test_sync_point_typelib,
+                                  action - thd->test_sync_action);
+        test_sync_action_string(action_string, sizeof(action_string), action);
+
+        /* Send info. */
+        protocol->prepare_for_resend();
+        protocol->store(sync_point_name, strlen(sync_point_name), cs);
+        protocol->store(action_string, strlen(action_string), cs);
+        if (protocol->write())
+          goto err;
+      }
+      goto eof;
+    }
+  case test:
+    {
+      /* This requires the sync point index. */
+      break;
+    }
+  default:
+    {
+      /* This should not happen. */
+      DBUG_ASSERT(request->command - request->command);
+      my_printf_error(ER_UNKNOWN_ERROR, "Illegal synchronization command: %u",
+                      MYF(0), request->command);
+      goto err;
+    }
+  }
+
+  /* Find synchronisation point array index by its name. */
+  if ((sync_point_id= find_type(request->sync_point.str,
+                                &test_sync_point_typelib, 1+2)) > 0)
+  {
+    sync_point_id--; /* find_type() returns offset + 1. */
+    DBUG_ASSERT(sync_point_id < NUMBER_OF_SYNC_POINTS);
+  }
+  else
+  {
+    my_printf_error(ER_UNKNOWN_ERROR, "No such synchronization point: '%.64s'",
+                    MYF(0), request->sync_point.str);
+    goto err;
+  }
+
+  /* Currently we come here only for "TEST SYNCHRONIZE ... TEST". */
+  DBUG_ASSERT(request->command == test);
+  test_synchronize(thd, (enum enum_test_sync_point) sync_point_id);
+
+ end:
+  send_ok(thd);
+  DBUG_RETURN(0);
+
+ eof:
+  send_eof(thd);
+  DBUG_RETURN(0);
+
+ err:
+  DBUG_RETURN(1);
+}
+
+
+/**
+  Execute requested actions at an synchronization point.
+
+  @param[in]    thd                 thread handle
+  @param[in]    action              action to be executed
+  @param[in]    sync_point_name     name of synchronization point
+
+  @note
+    This is to be called only if activation count > 0.
+*/
+
+static void test_sync_execute(THD *thd, st_test_sync_action *action,
+                              const char *sync_point_name)
+{
+  DBUG_ENTER("test_sync_execute");
+  DBUG_PRINT("test_sync", ("sync_point: '%s'  activation_count: %lu  "
+                           "hit_limit: %lu  execute: %lu  timeout: %lu  "
+                           "signal: '%s'  wait_for: '%s'",
+                           sync_point_name,
+                           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(&LOCK_test_sync);
+      /* Copy the signal to the global variable. */
+      SIGNAL_test_sync.copy(action->signal);
+      /* Wake threads waiting in a sync point. */
+      pthread_cond_broadcast(&COND_test_sync);
+      DBUG_PRINT("test_sync_exec", ("signal '%s'  at: '%s'",
+                                    action->signal.c_ptr(), sync_point_name));
+      pthread_mutex_unlock(&LOCK_test_sync);
+    }
+
+    if (action->wait_for.length())
+    {
+      const char      *old_proc_info;
+      int             error= 0;
+      struct timespec abstime;
+
+      pthread_mutex_lock(&LOCK_test_sync);
+      old_proc_info= thd->enter_cond(&COND_test_sync, &LOCK_test_sync,
+                                     sync_point_name);
+
+      set_timespec(abstime, action->timeout);
+      DBUG_PRINT("test_sync_exec", ("wait for '%s'  at: '%s'  curr: '%s'",
+                                    action->wait_for.c_ptr(),
+                                    sync_point_name,
+                                    SIGNAL_test_sync.c_ptr()));
+
+      /* Wait until global signal string matches the wait_for string. */
+      while (stringcmp(&SIGNAL_test_sync, &action->wait_for) &&
+             !thd->killed)
+      {
+        error= pthread_cond_timedwait(&COND_test_sync, &LOCK_test_sync,
+                                      &abstime);
+        if (error == ETIMEDOUT || error == ETIME)
+        {
+          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
+                       "TEST SYNCHRONIZE sync point timed out");
+          break;
+        }
+        error= 0;
+      }
+      DBUG_PRINT("test_sync_exec", ("%s from '%s'  at: '%s'",
+                                    error ? "timeout" : "resume",
+                                    action->wait_for.c_ptr(), sync_point_name));
+
+      /* @todo Maybe we could do here: SIGNAL_test_sync.length(0); */
+      thd->exit_cond(old_proc_info);
+    }
+
+    action->execute--;
+  }
+
+  /* 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_LOCK_WAIT_TIMEOUT, MYF(0));
+      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_UNKNOWN_ERROR,
+                   "TEST SYNCHRONIZE sync point reached hit limit");
+    }
+    DBUG_PRINT("test_sync_exec", ("hit_limit: %lu  at: '%s'",
+                                  action->hit_limit, sync_point_name));
+  }
+
+  action->activation_count--;
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Execute requested actions at an synchronization point.
+
+  @param[in]    thd                 thread handle
+  @param[in]    sync_point_id       synchronization point identifier
+*/
+
+void test_synchronize(THD *thd, enum enum_test_sync_point sync_point_id)
+{
+  st_test_sync_action *action;
+  DBUG_ENTER("test_synchronize");
+  DBUG_ASSERT(sync_point_id < NUMBER_OF_SYNC_POINTS);
+  DBUG_PRINT("test_sync_point",
+             ("hit: '%s'", get_type(&test_sync_point_typelib, sync_point_id)));
+
+  action= &thd->test_sync_action[sync_point_id];
+  if (action->activation_count)
+    test_sync_execute(thd, action,
+                      get_type(&test_sync_point_typelib, sync_point_id));
+  DBUG_VOID_RETURN;
+}
+
diff -Nrup a/sql/mysql_test_sync.h b/sql/mysql_test_sync.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/mysql_test_sync.h	2008-02-11 13:05:18 +01:00
@@ -0,0 +1,93 @@
+/* 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 */
+
+/*
+  Test Synchronization Facility.
+  See description in mysql_test_sync.cc
+*/
+
+#ifndef _mysql_test_sync_h_
+#define _mysql_test_sync_h_
+
+/*
+  Test synchronization enums must match test_sync_point_names in
+  mysql_test_sync.cc.
+*/
+enum enum_test_sync_point
+{
+  /* Special sync point: TEST SYNCHRONIZE 'now' [SEND sig] [WAIT_FOR sig] */
+  now,
+
+  /* Normal sync points. */
+  before_open_table_wait_refresh,
+  before_lock_tables_takes_lock,
+  wait_for_lock,
+  mysql_lock_retry,
+  after_insert,
+  after_flush_unlock,
+  after_admin_flush,
+  before_acos_function,
+  before_wait_locked_tname,
+  before_myisammrg_attach,
+  before_myisammrg_store_lock,
+
+  /* Do not add sync points below this line. */
+  NUMBER_OF_SYNC_POINTS
+};
+
+/* Test sync request commands. */
+enum enum_test_sync_cmd
+{
+  action, test, reset, show_status, show_action
+};
+
+struct st_test_sync_request
+{
+  enum enum_test_sync_cmd       command;
+  ulong                         hit_limit;
+  ulong                         execute;
+  ulong                         timeout;
+  LEX_STRING                    signal;
+  LEX_STRING                    wait_for;
+  LEX_STRING                    sync_point;
+};
+
+struct st_test_sync_action
+{
+  ulong                         activation_count;
+  ulong                         hit_limit;
+  ulong                         execute;
+  ulong                         timeout;
+  String                        signal;
+  String                        wait_for;
+};
+
+/* Command line option --test-synchronize. See mysqld.cc. */
+extern uint opt_test_synchronize;
+
+extern int  test_sync_init(void);
+extern void test_sync_end(void);
+extern void test_sync_init_thread(THD *thd);
+extern void test_sync_end_thread(THD *thd);
+extern int  test_sync_set_action(THD *thd, st_test_sync_request *request);
+extern int  test_sync_do_command(THD *thd, st_test_sync_request *request);
+extern void test_synchronize(THD *thd,
+                             enum enum_test_sync_point sync_point_id);
+
+#define TEST_SYNCHRONIZE(_thd_, _sync_point_id_)                        \
+          do { if (unlikely(opt_test_synchronize))                      \
+                 test_synchronize(_thd_, _sync_point_id_); } while (0)
+
+#endif /* _mysql_test_sync_h_ */
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc	2008-01-29 08:50:45 +01:00
+++ b/sql/mysqld.cc	2008-02-11 13:05:18 +01:00
@@ -488,6 +488,7 @@ uint mysqld_port_timeout;
 uint delay_key_write_options, protocol_version;
 uint lower_case_table_names;
 uint tc_heuristic_recover= 0;
+uint opt_test_synchronize= 0;
 uint volatile thread_count, thread_running;
 ulonglong thd_startup_options;
 ulong back_log, connect_timeout, concurrency, server_id;
@@ -1325,6 +1326,8 @@ void clean_up(bool print_message)
 #ifdef USE_REGEX
   my_regex_end();
 #endif
+  /* End the test synchronization facility. See mysql_test_sync.cc */
+  test_sync_end();
 
 #if !defined(EMBEDDED_LIBRARY)
   if (!opt_bootstrap)
@@ -2967,6 +2970,7 @@ SHOW_VAR com_status_vars[]= {
   {"stmt_prepare",         (char*) offsetof(STATUS_VAR, com_stmt_prepare), SHOW_LONG_STATUS},
   {"stmt_reset",           (char*) offsetof(STATUS_VAR, com_stmt_reset), SHOW_LONG_STATUS},
   {"stmt_send_long_data",  (char*) offsetof(STATUS_VAR, com_stmt_send_long_data), SHOW_LONG_STATUS},
+  {"test_synchronize",     (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TEST_SYNC]), SHOW_LONG_STATUS},
   {"truncate",             (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS},
   {"uninstall_plugin",     (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UNINSTALL_PLUGIN]), SHOW_LONG_STATUS},
   {"unlock_tables",        (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UNLOCK_TABLES]), SHOW_LONG_STATUS},
@@ -3262,6 +3266,10 @@ 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);
 
+  /* Initialize the test synchronization facility. See mysql_test_sync.cc */
+  if (opt_test_synchronize && test_sync_init())
+    return 1; /* purecov: tested */
+
   if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
     return 1;
   if (my_database_names_init())
@@ -5371,7 +5379,8 @@ enum options_mysqld
 #if HAVE_POOL_OF_THREADS == 1
   OPT_POOL_OF_THREADS,
 #endif
-  OPT_OLD_MODE
+  OPT_OLD_MODE,
+  OPT_TEST_SYNCHRONIZE
 };
 
 
@@ -6111,6 +6120,12 @@ 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},
+  {"test-synchronize", OPT_TEST_SYNCHRONIZE,
+   "Enable the TEST SYNCHRONIZE facility "
+   "and optionally specify a default wait timeout in seconds. "
+   "A zero value keeps the facility disabled.",
+   (uchar**) &opt_test_synchronize, 0,
+   0, GET_INT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0},
   {"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,
@@ -7267,6 +7282,7 @@ 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;
+  opt_test_synchronize= 0;
   key_map_full.set_all();
 
   /* Character sets */
@@ -7917,6 +7933,16 @@ mysqld_get_one_option(int optid,
   case OPT_LOWER_CASE_TABLE_NAMES:
     lower_case_table_names= argument ? atoi(argument) : 1;
     lower_case_table_names_used= 1;
+    break;
+  case OPT_TEST_SYNCHRONIZE:
+    /*
+      Test Synchronization Facility. See mysql_test_sync.cc.
+      Default value is zero (facility disabled).
+      If option is given without an argument, supply a non-zero value.
+      Default timeout for WAIT_FOR action.
+    */
+    if (!argument)
+      opt_test_synchronize= 300; /* purecov: tested */
     break;
   }
   return 0;
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc	2008-01-25 21:27:10 +01:00
+++ b/sql/sql_base.cc	2008-02-11 13:05:18 +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);
 
+    TEST_SYNCHRONIZE(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)
       {
+        TEST_SYNCHRONIZE(thd, before_open_table_wait_refresh);
+
         /* wait_for_conditionwill unlock LOCK_open for us */
         wait_for_condition(thd, &LOCK_open, &COND_refresh);
       }
@@ -5170,6 +5174,8 @@ int lock_tables(THD *thd, TABLE_LIST *ta
         thd->set_current_stmt_binlog_row_based_if_mixed();
       }
     }
+
+    TEST_SYNCHRONIZE(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-01-25 18:40:46 +01:00
+++ b/sql/sql_class.cc	2008-02-11 13:05:18 +01:00
@@ -500,7 +500,7 @@ THD::THD()
    bootstrap(0),
    derived_tables_processing(FALSE),
    spcont(NULL),
-   m_lip(NULL)
+   m_lip(NULL), test_sync_action(0)
 {
   ulong tmp;
 
@@ -727,6 +727,9 @@ void THD::init(void)
   update_charset();
   reset_current_stmt_binlog_row_based();
   bzero((char *) &status_var, sizeof(status_var));
+
+  /* Initialize the test synchronization facility. See mysql_test_sync.cc */
+  test_sync_init_thread(this);
 }
 
 
@@ -802,6 +805,10 @@ void THD::cleanup(void)
     lock=locked_tables; locked_tables=0;
     close_thread_tables(this);
   }
+
+  /* End the test synchronization facility. See mysql_test_sync.cc */
+  test_sync_end_thread(this);
+
   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-01-28 18:51:20 +01:00
+++ b/sql/sql_class.h	2008-02-11 13:05:18 +01:00
@@ -239,6 +239,7 @@ struct Query_cache_tls
   Query_cache_tls() :first_query_block(NULL) {}
 };
 
+#include "mysql_test_sync.h"
 #include "sql_lex.h"				/* Must be here */
 
 class Delayed_insert;
@@ -1736,6 +1737,12 @@ public:
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   partition_info *work_part_info;
 #endif
+
+  /*
+    Pointer to array of TEST SYNCHRONIZE actions.
+    There is one array slot per synchronization point.
+  */
+  struct st_test_sync_action *test_sync_action;
 
   THD();
   ~THD();
diff -Nrup a/sql/sql_lex.h b/sql/sql_lex.h
--- a/sql/sql_lex.h	2007-12-19 14:35:03 +01:00
+++ b/sql/sql_lex.h	2008-02-11 13:05:18 +01:00
@@ -118,10 +118,11 @@ enum enum_sql_command {
   SQLCOM_SHOW_CREATE_TRIGGER,
   SQLCOM_ALTER_DB_UPGRADE,
   SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES,
+  SQLCOM_TEST_SYNC,
 
   /*
     When a command is added here, be sure it's also added in mysqld.cc
-    in "struct show_var_st status_vars[]= {" ...
+    in "struct show_var_st com_status_vars[]= {" ...
   */
   /* This should be the last !!! */
   SQLCOM_END
@@ -1728,6 +1729,8 @@ typedef struct st_lex : public Query_tab
   
   bool escape_used;
   bool is_lex_started; /* If lex_start() did run. For debugging. */
+
+  struct st_test_sync_request test_sync_req;
 
   st_lex();
 
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc	2008-01-29 12:52:37 +01:00
+++ b/sql/sql_parse.cc	2008-02-11 13:05:18 +01:00
@@ -2785,6 +2785,7 @@ end_with_restore_list:
       thd->first_successful_insert_id_in_cur_stmt=
         thd->first_successful_insert_id_in_prev_stmt;
 
+    TEST_SYNCHRONIZE(thd, after_insert);
     break;
   }
   case SQLCOM_REPLACE_SELECT:
@@ -4525,6 +4526,20 @@ create_sp_error:
       break;
     }
     send_ok(thd, 1);
+    break;
+  }
+  case SQLCOM_TEST_SYNC:
+  {
+    LEX *lex= thd->lex;
+    DBUG_PRINT("info", ("case SQLCOM_TEST_SYNC"));
+
+    if (check_global_access(thd, SUPER_ACL))
+      break;
+
+    if (lex->test_sync_req.command == action )
+      VOID(test_sync_set_action(thd, &lex->test_sync_req));
+    else
+      VOID(test_sync_do_command(thd, &lex->test_sync_req));
     break;
   }
   default:
diff -Nrup a/sql/sql_table.cc b/sql/sql_table.cc
--- a/sql/sql_table.cc	2008-01-29 12:52:37 +01:00
+++ b/sql/sql_table.cc	2008-02-11 13:05:18 +01:00
@@ -4180,6 +4180,7 @@ static bool mysql_admin_table(THD* thd, 
                               RTFC_WAIT_OTHER_THREAD_FLAG |
                               RTFC_CHECK_KILLED_FLAG);
       thd->exit_cond(old_message);
+      TEST_SYNCHRONIZE(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/sql/sql_yacc.yy b/sql/sql_yacc.yy
--- a/sql/sql_yacc.yy	2008-01-25 21:27:12 +01:00
+++ b/sql/sql_yacc.yy	2008-02-11 13:05:18 +01:00
@@ -593,6 +593,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  CHECKSUM_SYM
 %token  CHECK_SYM                     /* SQL-2003-R */
 %token  CIPHER_SYM
+%token  CLEAR_SYM
 %token  CLIENT_SYM
 %token  CLOSE_SYM                     /* SQL-2003-R */
 %token  COALESCE                      /* SQL-2003-N */
@@ -728,6 +729,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  HELP_SYM
 %token  HEX_NUM
 %token  HIGH_PRIORITY
+%token  HIT_LIMIT_SYM
 %token  HOST_SYM
 %token  HOSTS_SYM
 %token  HOUR_MICROSECOND_SYM
@@ -982,6 +984,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  SHIFT_RIGHT                   /* OPERATOR */
 %token  SHOW
 %token  SHUTDOWN
+%token  SIGNAL_SYM
 %token  SIGNED_SYM
 %token  SIMPLE_SYM                    /* SQL-2003-N */
 %token  SLAVE
@@ -1025,6 +1028,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  SUSPEND_SYM
 %token  SWAPS_SYM
 %token  SWITCHES_SYM
+%token  SYNCHRONIZE_SYM
 %token  SYSDATE
 %token  TABLES
 %token  TABLESPACE
@@ -1033,10 +1037,12 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  TEMPORARY                     /* SQL-2003-N */
 %token  TEMPTABLE_SYM
 %token  TERMINATED
+%token  TEST_SYM
 %token  TEXT_STRING
 %token  TEXT_SYM
 %token  THAN_SYM
 %token  THEN_SYM                      /* SQL-2003-R */
+%token  TIMEOUT_SYM
 %token  TIMESTAMP                     /* SQL-2003-R */
 %token  TIMESTAMP_ADD
 %token  TIMESTAMP_DIFF
@@ -1090,6 +1096,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  VARYING                       /* SQL-2003-R */
 %token  VAR_SAMP_SYM
 %token  VIEW_SYM                      /* SQL-2003-N */
+%token  WAIT_FOR_SYM
 %token  WAIT_SYM
 %token  WARNINGS
 %token  WEEK_SYM
@@ -1315,6 +1322,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
         init_key_options key_options key_opts key_opt key_using_alg
         server_def server_options_list server_option
         definer_opt no_definer definer
+        test_stmt TEST_SYM test_statement SYNCHRONIZE_SYM
 END_OF_INPUT
 
 %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@@ -1431,6 +1439,7 @@ statement:
         | show
         | slave
         | start
+        | test_stmt
         | truncate
         | uninstall
         | unlock
@@ -10516,6 +10525,7 @@ keyword:
         | SONAME_SYM            {}
         | START_SYM             {}
         | STOP_SYM              {}
+        | TEST_SYM              {}
         | TRUNCATE_SYM          {}
         | UNICODE_SYM           {}
         | UNINSTALL_SYM         {}
@@ -10554,6 +10564,7 @@ keyword_sp:
         | CHAIN_SYM                {}
         | CHANGED                  {}
         | CIPHER_SYM               {}
+        | CLEAR_SYM                {}
         | CLIENT_SYM               {}
         | COALESCE                 {}
         | CODE_SYM                 {}
@@ -10614,6 +10625,7 @@ keyword_sp:
         | GRANTS                   {}
         | GLOBAL_SYM               {}
         | HASH_SYM                 {}
+        | HIT_LIMIT_SYM            {}
         | HOSTS_SYM                {}
         | HOUR_SYM                 {}
         | IDENTIFIED_SYM           {}
@@ -10742,6 +10754,7 @@ keyword_sp:
         | SIMPLE_SYM               {}
         | SHARE_SYM                {}
         | SHUTDOWN                 {}
+        | SIGNAL_SYM               {}
         | SNAPSHOT_SYM             {}
         | SOUNDS_SYM               {}
         | SOURCE_SYM               {}
@@ -10761,6 +10774,7 @@ keyword_sp:
         | SUSPEND_SYM              {}
         | SWAPS_SYM                {}
         | SWITCHES_SYM             {}
+        | SYNCHRONIZE_SYM          {}
         | TABLES                   {}
         | TABLESPACE               {}
         | TEMPORARY                {}
@@ -10770,6 +10784,7 @@ keyword_sp:
         | TRANSACTION_SYM          {}
         | TRANSACTIONAL_SYM        {}
         | TRIGGERS_SYM             {}
+        | TIMEOUT_SYM              {}
         | TIMESTAMP                {}
         | TIMESTAMP_ADD            {}
         | TIMESTAMP_DIFF           {}
@@ -10790,6 +10805,7 @@ keyword_sp:
         | VIEW_SYM                 {}
         | VALUE_SYM                {}
         | WARNINGS                 {}
+        | WAIT_FOR_SYM             {}
         | WAIT_SYM                 {}
         | WEEK_SYM                 {}
         | WEIGHT_STRING_SYM        {}
@@ -12707,6 +12723,97 @@ uninstall:
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
             lex->comment= $3;
+          }
+        ;
+
+test_stmt:
+          TEST_SYM test_statement
+        ;
+
+test_statement:
+          SYNCHRONIZE_SYM
+          {
+            Lex->sql_command= SQLCOM_TEST_SYNC;
+            Lex->test_sync_req.command= action;
+            Lex->test_sync_req.hit_limit= 0;
+            Lex->test_sync_req.execute= 0;
+            Lex->test_sync_req.timeout= opt_test_synchronize;
+            Lex->test_sync_req.signal.length= 0;
+            Lex->test_sync_req.wait_for.length= 0;
+            Lex->test_sync_req.sync_point.length= 0;
+          }
+          test_sync_stmt
+        ;
+
+test_sync_stmt:
+          ident_or_text test_sync_action
+          {
+            Lex->test_sync_req.sync_point= $1;
+          }
+        | RESET_SYM
+          {
+            Lex->test_sync_req.command= reset;
+          }
+        | SHOW STATUS_SYM
+          {
+            Lex->test_sync_req.command= show_status;
+          }
+        | SHOW ACTION
+          {
+            Lex->test_sync_req.command= show_action;
+          }
+        ;
+
+test_sync_action:
+          test_sync_signal_wait test_sync_execute
+        | test_sync_signal_wait test_sync_execute test_sync_limit
+        | test_sync_limit
+        | CLEAR_SYM /* hit_limit= 0 and execute= 0 */
+        | TEST_SYM
+          {
+            Lex->test_sync_req.command= test;
+          }
+        ;
+
+test_sync_signal_wait:
+          SIGNAL_SYM ident_or_text
+          {
+            Lex->test_sync_req.signal= $2;
+          }
+        | SIGNAL_SYM ident_or_text WAIT_FOR_SYM ident_or_text test_sync_timeout
+          {
+            Lex->test_sync_req.signal= $2;
+            Lex->test_sync_req.wait_for= $4;
+          }
+        | WAIT_FOR_SYM ident_or_text test_sync_timeout
+          {
+            Lex->test_sync_req.wait_for= $2;
+          }
+        ;        
+
+test_sync_timeout:
+          /* empty */
+        | TIMEOUT_SYM opt_equal real_ulong_num
+          {
+            Lex->test_sync_req.timeout= $3;
+          }
+        ;        
+
+test_sync_execute:
+          /* empty */
+          {
+            Lex->test_sync_req.execute= 1;
+          }
+        | EXECUTE_SYM opt_equal real_ulong_num
+          {
+            Lex->test_sync_req.execute= $3;
+          }
+        ;        
+
+test_sync_limit:
+          HIT_LIMIT_SYM opt_equal real_ulong_num
+          {
+            Lex->test_sync_req.hit_limit= $3;
           }
         ;
 
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-02-11 13:05:18 +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);
 
+  TEST_SYNCHRONIZE(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;
+
+  TEST_SYNCHRONIZE(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.2526) WL#4259Ingo Struewing11 Feb