List:Commits« Previous MessageNext Message »
From:Ingo Struewing Date:December 28 2007 2:46pm
Subject:bk commit into 5.1 tree (istruewing:1.2638)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 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, 2007-12-28 15:46:42+01:00, istruewing@stripped +25 -0
  Test Synchronization Facility #2
  
  This is a proposal for a facility to synchronize threads in the
  test suite to make race conditions repeatable and get rid of sleeps.
  
  It is based os a proposal from Monty. The facility is contolled
  by a new SQL statement.
  
  The patch does also include a changed merge.test and its result.
  It is an example how to use the facility.
  
  The synchronization points required in the example tests are also
  included.

  libmysqld/CMakeLists.txt@stripped, 2007-12-28 15:46:39+01:00, istruewing@stripped +1 -1
    Test Synchronization Facility #2
    Include mysql_test_sync.cc

  libmysqld/Makefile.am@stripped, 2007-12-28 15:46:39+01:00, istruewing@stripped +1 -1
    Test Synchronization Facility #2
    Include mysql_test_sync.cc

  mysql-test/mysql-test-run.pl@stripped, 2007-12-28 15:46:39+01:00, istruewing@stripped +7 -0
    Test Synchronization Facility #2
    Added code for enabling/disabling of the facility.

  mysql-test/r/grant.result@stripped, 2007-12-28 15:46:39+01:00, istruewing@stripped +4 -4
    Test Synchronization Facility #2
    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, 2007-12-28 15:46:39+01:00, istruewing@stripped +112 -86
    Test Synchronization Facility #2
    Fixed the example test result.

  mysql-test/r/test_synchronize.result@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +159 -0
    Test Synchronization Facility #2
    Added test result.

  mysql-test/r/test_synchronize.result@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +0 -0

  mysql-test/t/merge.test@stripped, 2007-12-28 15:46:39+01:00, istruewing@stripped +282 -63
    Test Synchronization Facility #2
    Example tests.
    Reworked tests to utilize the new facility.
    Added more tests.

  mysql-test/t/test_synchronize.test@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +201 -0
    Test Synchronization Facility #2
    Added a new test case to test the facility itself.

  mysql-test/t/test_synchronize.test@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +0 -0

  mysys/thr_lock.c@stripped, 2007-12-28 15:46:39+01:00, istruewing@stripped +13 -0
    Test Synchronization Facility #2
    Added a synchronization point hook.

  sql/CMakeLists.txt@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +1 -0
    Test Synchronization Facility #2
    Include mysql_test_sync.cc and mysql_test_sync.h

  sql/Makefile.am@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +2 -2
    Test Synchronization Facility #2
    Include mysql_test_sync.cc and mysql_test_sync.h

  sql/item_func.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +2 -0
    Test Synchronization Facility #2
    Added a synchronization point.

  sql/lex.h@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +7 -0
    Test Synchronization Facility #2
    Added keywords.

  sql/lock.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +2 -0
    Test Synchronization Facility #2
    Added synchronization points.

  sql/mysql_test_sync.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +432 -0
    Test Synchronization Facility #2
    Added variables and functions for the facility.

  sql/mysql_test_sync.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +0 -0

  sql/mysql_test_sync.h@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +83 -0
    Test Synchronization Facility #2
    Added declarations for the facility.

  sql/mysql_test_sync.h@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +0 -0

  sql/mysqld.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +15 -1
    Test Synchronization Facility #2
    Added initialization/deletion of the facility for the server.
    Added option "test-synchronize".

  sql/sql_base.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +6 -0
    Test Synchronization Facility #2
    Added synchronization points.

  sql/sql_class.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +8 -1
    Test Synchronization Facility #2
    Added initialization/deletion of the facility for THD.

  sql/sql_class.h@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +7 -0
    Test Synchronization Facility #2
    Added a THD element.

  sql/sql_lex.h@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +3 -1
    Test Synchronization Facility #2
    Added statement symbol.
    Added a lex element.

  sql/sql_parse.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +17 -0
    Test Synchronization Facility #2
    Added a synchronization point.
    Added TEST SYNCHRONIZE statement execution.

  sql/sql_table.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +1 -0
    Test Synchronization Facility #2
    Added a synchronization point.

  sql/sql_yacc.yy@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +83 -0
    Test Synchronization Facility #2
    Added syntax extension.

  storage/myisammrg/ha_myisammrg.cc@stripped, 2007-12-28 15:46:40+01:00, istruewing@stripped +4 -0
    Test Synchronization Facility #2
    Added synchronization points.

diff -Nrup a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
--- a/libmysqld/CMakeLists.txt	2007-08-06 23:14:47 +02:00
+++ b/libmysqld/CMakeLists.txt	2007-12-28 15:46:39 +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-08-31 01:23:07 +02:00
+++ b/libmysqld/Makefile.am	2007-12-28 15:46:39 +01:00
@@ -76,7 +76,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	2007-12-07 23:04:44 +01:00
+++ b/mysql-test/mysql-test-run.pl	2007-12-28 15:46:39 +01:00
@@ -264,6 +264,7 @@ my @default_valgrind_args= ("--show-reac
 my @valgrind_args;
 my $opt_valgrind_path;
 my $opt_callgrind;
+my $opt_skip_test_synchronize;
 
 our $opt_stress=               "";
 our $opt_stress_suite=     "main";
@@ -613,6 +614,7 @@ sub command_line_setup () {
              'valgrind-option=s'        => \@valgrind_args,
              'valgrind-path=s'          => \$opt_valgrind_path,
 	     'callgrind'                => \$opt_callgrind,
+	     'skip-test-synchronize'    => \$opt_skip_test_synchronize,
 
              # Stress testing 
              'stress'                   => \$opt_stress,
@@ -3807,6 +3809,11 @@ sub mysqld_arguments ($$$$) {
   # see BUG#28359
   mtr_add_arg($args, "%s--connect-timeout=60", $prefix);
 
+  if ( ! $opt_skip_test_synchronize )
+  {
+    # Enable the TEST SYNCHRONIZE facility
+    mtr_add_arg($args, "%s--test-synchronize", $prefix);
+  }
 
   # 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
diff -Nrup a/mysql-test/r/grant.result b/mysql-test/r/grant.result
--- a/mysql-test/r/grant.result	2007-12-07 11:56:02 +01:00
+++ b/mysql-test/r/grant.result	2007-12-28 15:46:39 +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-11-18 20:28:35 +01:00
+++ b/mysql-test/r/merge.result	2007-12-28 15:46:39 +01:00
@@ -1,3 +1,4 @@
+TEST SYNCHRONIZE NOW SIGNAL empty;
 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));
@@ -1034,28 +1035,58 @@ 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 NOW SIGNAL empty;
 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 NOW SIGNAL empty;
 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 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 NOW SIGNAL empty;
 DROP TABLE t1;
 #
 # Extra tests for Bug#26379 - Combination of FLUSH TABLE and
@@ -1574,6 +1605,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;
@@ -1756,9 +1788,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;
@@ -1770,88 +1802,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.3694384060046
+TEST SYNCHRONIZE NOW SIGNAL empty;
 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;
@@ -1947,3 +1916,60 @@ 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 NOW SIGNAL empty;
+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 NOW SIGNAL empty;
+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 after_insert SIGNAL locked EXECUTE 2;
+TEST SYNCHRONIZE wait_for_lock SIGNAL locked EXECUTE 4;
+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 opened;
+FLUSH TABLES;
+TEST SYNCHRONIZE NOW WAIT_FOR locked;
+UNLOCK TABLES;
+connection con1
+connection default;
+TEST SYNCHRONIZE NOW SIGNAL empty;
+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	2007-12-28 15:46:40 +01:00
@@ -0,0 +1,159 @@
+TEST SYNCHRONIZE NOW SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT 3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0           HIT_LIMIT 3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW SIGNAL sig1 WAIT_FOR sig2 TIMEOUT 0;
+Warnings:
+Error	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:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW             WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW             WAIT_FOR sig2 TIMEOUT 0           HIT_LIMIT 3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW             WAIT_FOR sig2 TIMEOUT 0;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW                                               HIT_LIMIT 3;
+TEST SYNCHRONIZE NOW CLEAR;
+TEST SYNCHRONIZE 'NOW' SIGNAL sig1   WAIT_FOR sig2   TIMEOUT 0;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW   SIGNAL 'sig1' WAIT_FOR sig2   TIMEOUT 0;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW   SIGNAL sig1   WAIT_FOR 'sig2' TIMEOUT 0;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW WAIT_FOR sig2 TIMEOUT 0 EXECUTE 2 HIT_LIMIT=3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW WAIT_FOR sig2 TIMEOUT 0 EXECUTE=2 HIT_LIMIT 3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW WAIT_FOR sig2 TIMEOUT 0 EXECUTE=2 HIT_LIMIT=3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW WAIT_FOR sig2 TIMEOUT=0 EXECUTE 2 HIT_LIMIT 3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW WAIT_FOR sig2 TIMEOUT=0 EXECUTE 2 HIT_LIMIT=3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW WAIT_FOR sig2 TIMEOUT=0 EXECUTE=2 HIT_LIMIT 3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW WAIT_FOR sig2 TIMEOUT=0 EXECUTE=2 HIT_LIMIT=3;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE FLUSH SIGNAL sig1  WAIT_FOR sig2  TIMEOUT 0;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW   SIGNAL FLUSH WAIT_FOR sig2  TIMEOUT 0;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+TEST SYNCHRONIZE NOW   SIGNAL sig1  WAIT_FOR FLUSH TIMEOUT 0;
+Warnings:
+Error	1105	TEST SYNCHRONIZE sync point timed out
+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
+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
+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 NOW SIGNAL empty;
+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 NOW SIGNAL empty;
diff -Nrup a/mysql-test/t/merge.test b/mysql-test/t/merge.test
--- a/mysql-test/t/merge.test	2007-11-18 20:28:35 +01:00
+++ b/mysql-test/t/merge.test	2007-12-28 15:46:39 +01:00
@@ -2,7 +2,9 @@
 # test of MERGE TABLES
 #
 
+# Clean up resources used in this test case.
 --disable_warnings
+TEST SYNCHRONIZE NOW SIGNAL empty;
 drop table if exists t1,t2,t3,t4,t5,t6;
 drop database if exists mysqltest;
 --enable_warnings
@@ -671,12 +673,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
@@ -698,12 +694,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 NOW SIGNAL empty;
 DROP TABLE t1, t2;
 #
 # Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
@@ -718,20 +741,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 NOW SIGNAL empty;
 DROP TABLE t1, t2;
 #
 # Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table
@@ -753,28 +795,52 @@ 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;
+    # 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 NOW SIGNAL empty;
 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
@@ -1100,6 +1166,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;
@@ -1203,11 +1270,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;
@@ -1216,49 +1284,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 NOW SIGNAL empty;
 DROP TABLE t1, t2, t3;
 
 #
@@ -1358,4 +1421,160 @@ 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 NOW SIGNAL empty;
+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 NOW SIGNAL empty;
+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 NOW SIGNAL empty;
+#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 not fixed, INSERT will succeed. Pretend locked.
+    TEST SYNCHRONIZE after_insert SIGNAL locked 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;
+    send INSERT INTO t1 VALUES (1);
+#
+--echo connection default;
+connection default;
+#
+# 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 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 NOW SIGNAL empty;
+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	2007-12-28 15:46:40 +01:00
@@ -0,0 +1,201 @@
+###################### 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
+
+#
+# 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;
+
+#
+# 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 FLUSH SIGNAL sig1  WAIT_FOR sig2  TIMEOUT 0;
+TEST SYNCHRONIZE NOW   SIGNAL FLUSH WAIT_FOR sig2  TIMEOUT 0;
+TEST SYNCHRONIZE NOW   SIGNAL sig1  WAIT_FOR FLUSH 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;
+
+#
+# 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;
+
+#
+# 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.
+#
+# Preparative cleanup.
+--disable_warnings
+TEST SYNCHRONIZE NOW SIGNAL empty;
+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;
+
+#
+# Cleanup after test case.
+# Otherwise signal would contain 'flushed' here,
+# which could confuse the next test.
+#
+TEST SYNCHRONIZE NOW SIGNAL empty;
+
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	2007-12-28 15:46:39 +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-11-14 16:11:41 +01:00
+++ b/sql/CMakeLists.txt	2007-12-28 15:46:40 +01:00
@@ -75,6 +75,7 @@ ADD_EXECUTABLE(mysqld
                partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
                rpl_rli.cc rpl_mi.cc sql_servers.cc
                sql_connect.cc scheduler.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-10-08 20:55:16 +02:00
+++ b/sql/Makefile.am	2007-12-28 15:46:40 +01:00
@@ -74,7 +74,7 @@ noinst_HEADERS =	item.h item_func.h item
 			sql_plugin.h authors.h \
 			event_data_objects.h event_scheduler.h \
 			sql_partition.h partition_info.h partition_element.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 \
@@ -117,7 +117,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
+			sql_servers.cc mysql_test_sync.cc
 
 nodist_mysqld_SOURCES =	mini_client_errors.c pack.c client.c my_time.c my_user.c 
 
diff -Nrup a/sql/item_func.cc b/sql/item_func.cc
--- a/sql/item_func.cc	2007-11-28 17:08:25 +01:00
+++ b/sql/item_func.cc	2007-12-28 15:46:40 +01:00
@@ -1682,6 +1682,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-04-02 10:54:27 +02:00
+++ b/sql/lex.h	2007-12-28 15:46:40 +01:00
@@ -104,6 +104,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)},
@@ -228,6 +229,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)},
@@ -465,6 +467,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)},
@@ -510,16 +513,19 @@ static SYMBOL symbols[] = {
   { "SUBPARTITIONS",    SYM(SUBPARTITIONS_SYM)},
   { "SUPER",		SYM(SUPER_SYM)},
   { "SUSPEND",          SYM(SUSPEND_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)},
@@ -566,6 +572,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-11 21:38:05 +01:00
+++ b/sql/lock.cc	2007-12-28 15:46:40 +01:00
@@ -318,6 +318,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
     thd->locked=0;
 retry:
     sql_lock=0;
+    TEST_SYNCHRONIZE(thd, MYSQL_LOCK_RETRY);
     if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
     {
       *need_reopen= TRUE;
@@ -1109,6 +1110,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	2007-12-28 15:46:40 +01:00
@@ -0,0 +1,432 @@
+/* Copyright (C) 2007 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include "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
+};
+
+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 signalling 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_enabled is set.
+*/
+
+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_enabled is set.
+*/
+
+int test_sync_init(void)
+{
+  DBUG_ENTER("test_sync_init");
+  DBUG_ASSERT(opt_test_synchronize_enabled);
+
+  /*
+    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 without --test-synchronize",
+                    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 at server shutdown.
+
+  @note
+    This is called only if opt_test_synchronize_enabled is set.
+*/
+
+void test_sync_end(void)
+{
+  DBUG_ENTER("test_sync_end");
+  DBUG_ASSERT(opt_test_synchronize_enabled);
+
+  /* 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_enabled)
+  {
+    thd->test_sync_action= (struct st_test_sync_action*)
+      my_malloc(NUMBER_OF_SYNC_POINTS * sizeof(struct st_test_sync_action),
+                MYF(MY_WME | MY_ZEROFILL));
+    if (!thd->test_sync_action)
+    {
+      /* We must disable the facility. We have no way to return error. */
+      test_sync_end();
+      opt_test_synchronize_enabled= FALSE;
+    }
+  }
+
+  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)
+  {
+    struct st_test_sync_action *action= thd->test_sync_action;
+    struct 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;
+}
+
+
+/**
+  Set a test synchronization action.
+
+  @param[in]    thd             thread handle
+  @param[in]    test_sync_req   synchronization request
+*/
+
+int test_sync_set_action(THD *thd, struct st_test_sync_request *test_sync_req)
+{
+  struct st_test_sync_action *test_sync_action;
+  int sync_point_index;
+  DBUG_ENTER("test_sync_set_action");
+
+  if (!opt_test_synchronize_enabled)
+  {
+    /*
+      Do not raise error or warning. Test result should not
+      unnecessarily differ from enabled facility.
+    */
+    DBUG_RETURN(0);
+  }
+
+  /* Find synchronisation point array index by its name. */
+  if ((sync_point_index= find_type(test_sync_req->sync_point.str,
+                                   &test_sync_point_typelib, 1+2)) > 0)
+  {
+    sync_point_index--; /* find_type() returns offset + 1. */
+    DBUG_ASSERT(sync_point_index < NUMBER_OF_SYNC_POINTS);
+    test_sync_action= &thd->test_sync_action[sync_point_index];
+  }
+  else
+  {
+#ifdef ERROR_ON_UNKNOWN_SYNC_POINT
+    my_printf_error(ER_UNKNOWN_ERROR, "No such synchronization point: '%.64s'",
+                    MYF(0), test_sync_req->sync_point.str);
+    DBUG_RETURN(1);
+#else
+    /* TODO: enter action in a list. Maintain a sorted array. */
+    DBUG_RETURN(0);
+#endif
+  }
+
+  /* Create the action struct from the request. */
+  test_sync_action->activation_count=
+    max(test_sync_req->hit_limit, test_sync_req->exec_count);
+  if (test_sync_action->activation_count)
+  {
+    test_sync_action->hit_limit= test_sync_req->hit_limit;
+    test_sync_action->exec_count= test_sync_req->exec_count;
+    test_sync_action->timeout= test_sync_req->timeout;
+    test_sync_action->signal.copy(test_sync_req->signal.str,
+                                  test_sync_req->signal.length,
+                                  system_charset_info);
+    test_sync_action->wait_for.copy(test_sync_req->wait_for.str,
+                                    test_sync_req->wait_for.length,
+                                    system_charset_info);
+    DBUG_PRINT("test_sync", ("sync_point: '%s'  activation_count: %lu  "
+                             "hit_limit: %lu  exec_count: %lu  timeout: %lu  "
+                             "signal: '%s'  wait_for: '%s'",
+                             test_sync_req->sync_point.str,
+                             test_sync_action->activation_count,
+                             test_sync_action->hit_limit,
+                             test_sync_action->exec_count,
+                             test_sync_action->timeout,
+                             test_sync_action->signal.c_ptr(),
+                             test_sync_action->wait_for.c_ptr()));
+  }
+  DBUG_RETURN(0);
+}
+
+
+/**
+  Execute requested actions at an synchronization point.
+
+  @param[in]    thd                 thread handle
+  @param[in]    test_sync_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,
+                              struct st_test_sync_action *test_sync_action,
+                              const char *sync_point_name)
+{
+  DBUG_ENTER("test_sync_execute");
+  DBUG_PRINT("test_sync", ("sync_point: '%s'  activation_count: %lu  "
+                           "hit_limit: %lu  exec_count: %lu  timeout: %lu  "
+                           "signal: '%s'  wait_for: '%s'",
+                           sync_point_name,
+                           test_sync_action->activation_count,
+                             test_sync_action->hit_limit,
+                           test_sync_action->exec_count,
+                           test_sync_action->timeout,
+                           test_sync_action->signal.c_ptr(),
+                           test_sync_action->wait_for.c_ptr()));
+  DBUG_ASSERT(test_sync_action->activation_count);
+
+  if (test_sync_action->exec_count)
+  {
+    if (test_sync_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(test_sync_action->signal);
+      /* Wake threads waiting in a sync point. */
+      pthread_cond_broadcast(&COND_test_sync);
+      DBUG_PRINT("test_sync_exec", ("signal '%s'  at: '%s'",
+                                    test_sync_action->signal.c_ptr(),
+                                    sync_point_name));
+      pthread_mutex_unlock(&LOCK_test_sync);
+    }
+
+    if (test_sync_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, test_sync_action->timeout);
+      DBUG_PRINT("test_sync_exec", ("wait for '%s'  at: '%s'  curr: '%s'",
+                                    test_sync_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, &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_ERROR, 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",
+                                    test_sync_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);
+    }
+
+    test_sync_action->exec_count--;
+  }
+
+  /* hit_limit is zero for infinite. Don't decrement unconditionally. */
+  if (test_sync_action->hit_limit)
+  {
+    if (!--test_sync_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'",
+                                  test_sync_action->hit_limit,
+                                  sync_point_name));
+  }
+
+  test_sync_action->activation_count--;
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Execute requested actions at an synchronization point.
+
+  @param[in]    thd                 thread handle
+  @param[in]    test_sync_point     synchronization point identifier
+*/
+
+void test_synchronize(THD *thd, enum enum_test_sync_point test_sync_point)
+{
+  DBUG_ASSERT(test_sync_point < NUMBER_OF_SYNC_POINTS);
+
+  /* During bootstrap or in non-THD threads, thd can be NULL. */
+  if (thd && thd->test_sync_action[test_sync_point].activation_count)
+    test_sync_execute(thd, &thd->test_sync_action[test_sync_point],
+                      get_type(&test_sync_point_typelib, test_sync_point));
+}
+
+
+#ifdef NOT_YET_IMPLEMENTED
+/**
+  Execute requested actions at an synchronization point.
+
+  @param[in]    thd                 thread handle
+  @param[in]    user_var_name       name of user variable
+  @param[in]    name_len            length of name of user variable
+*/
+
+void test_synchronize(THD *thd, const char *sync_point_name, size_t name_len)
+{
+  /* Find sync point action by string. */
+  /* To be implemented. */
+  /* Remove dynamic action when activation_count became zero. */
+}
+#endif /*NOT_YET_IMPLEMENTED*/
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	2007-12-28 15:46:40 +01:00
@@ -0,0 +1,83 @@
+/* Copyright (C) 2007 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 */
+
+#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
+};
+
+#define TEST_SYNC_DEFAULT_WAIT_TIMEOUT 300
+
+struct st_test_sync_request
+{
+  ulong         hit_limit;
+  ulong         exec_count;
+  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         exec_count;
+  ulong         timeout;
+  String        signal;
+  String        wait_for;
+};
+
+/* Command line option --test-synchronize. See mysqld.cc. */
+extern my_bool opt_test_synchronize_enabled;
+
+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,
+                                 struct st_test_sync_request *test_sync_req);
+extern void test_synchronize(THD *thd,
+                             enum enum_test_sync_point test_sync_point);
+
+#define TEST_SYNCHRONIZE(_thd_, _sync_point_id_)                        \
+          do { if (unlikely(opt_test_synchronize_enabled))              \
+                 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	2007-11-28 17:08:25 +01:00
+++ b/sql/mysqld.cc	2007-12-28 15:46:40 +01:00
@@ -421,6 +421,7 @@ my_bool opt_old_style_user_limits= 0, tr
 volatile bool mqh_used = 0;
 my_bool opt_noacl;
 my_bool sp_automatic_privileges= 1;
+my_bool opt_test_synchronize_enabled= 0;
 
 ulong opt_binlog_rows_event_max_size;
 const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
@@ -1244,6 +1245,9 @@ void clean_up(bool print_message)
 #ifdef USE_REGEX
   my_regex_end();
 #endif
+  /* End the test synchronization facility. See mysql_test_sync.cc */
+  if (opt_test_synchronize_enabled)
+    test_sync_end();
 
 #if !defined(EMBEDDED_LIBRARY)
   if (!opt_bootstrap)
@@ -2989,6 +2993,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_enabled && 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())
@@ -5115,7 +5123,8 @@ enum options_mysqld
   OPT_SECURE_FILE_PRIV,
   OPT_MIN_EXAMINED_ROW_LIMIT,
   OPT_LOG_SLOW_SLAVE_STATEMENTS,
-  OPT_OLD_MODE
+  OPT_OLD_MODE,
+  OPT_TEST_SYNCHRONIZE
 };
 
 
@@ -5861,6 +5870,10 @@ 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.",
+   (uchar**) &opt_test_synchronize_enabled, 0,
+   0, GET_BOOL, NO_ARG, 0, 0, 0, 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,
@@ -7110,6 +7123,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_enabled= 0;
   key_map_full.set_all();
 
   /* Character sets */
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc	2007-12-11 21:38:05 +01:00
+++ b/sql/sql_base.cc	2007-12-28 15:46:40 +01:00
@@ -994,6 +994,8 @@ bool close_cached_tables(THD *thd, bool 
     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",
@@ -2855,6 +2857,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);
       }
@@ -5123,6 +5127,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	2007-11-27 17:02:59 +01:00
+++ b/sql/sql_class.cc	2007-12-28 15:46:40 +01:00
@@ -375,7 +375,7 @@ THD::THD()
    bootstrap(0),
    derived_tables_processing(FALSE),
    spcont(NULL),
-   m_lip(NULL)
+   m_lip(NULL), test_sync_action(0)
 {
   ulong tmp;
 
@@ -603,6 +603,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);
 }
 
 
@@ -678,6 +681,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	2007-11-28 19:49:23 +01:00
+++ b/sql/sql_class.h	2007-12-28 15:46:40 +01:00
@@ -217,6 +217,7 @@ public:
   LEX_COLUMN (const String& x,const  uint& y ): column (x),rights (y) {}
 };
 
+#include "mysql_test_sync.h"
 #include "sql_lex.h"				/* Must be here */
 
 class Delayed_insert;
@@ -1561,6 +1562,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-11-28 15:34:10 +01:00
+++ b/sql/sql_lex.h	2007-12-28 15:46:40 +01:00
@@ -116,7 +116,7 @@ enum enum_sql_command {
   SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT,
   SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
   SQLCOM_SHOW_CREATE_TRIGGER,
-  SQLCOM_ALTER_DB_UPGRADE,
+  SQLCOM_ALTER_DB_UPGRADE, SQLCOM_TEST_SYNC,
 
   /* This should be the last !!! */
 
@@ -1713,6 +1713,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	2007-12-10 10:45:52 +01:00
+++ b/sql/sql_parse.cc	2007-12-28 15:46:40 +01:00
@@ -2827,6 +2827,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:
@@ -4535,6 +4536,22 @@ 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 (test_sync_set_action(thd, &lex->test_sync_req))
+      break; /* purecov: tested */
+
+    TEST_SYNCHRONIZE(thd, NOW);
+
     send_ok(thd, 1);
     break;
   }
diff -Nrup a/sql/sql_table.cc b/sql/sql_table.cc
--- a/sql/sql_table.cc	2007-12-11 23:57:54 +01:00
+++ b/sql/sql_table.cc	2007-12-28 15:46:40 +01:00
@@ -4171,6 +4171,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	2007-11-30 12:34:23 +01:00
+++ b/sql/sql_yacc.yy	2007-12-28 15:46:40 +01:00
@@ -588,6 +588,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 */
@@ -718,6 +719,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
@@ -965,6 +967,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
@@ -1005,6 +1008,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  SUM_SYM                       /* SQL-2003-N */
 %token  SUPER_SYM
 %token  SUSPEND_SYM
+%token  SYNCHRONIZE_SYM
 %token  SYSDATE
 %token  TABLES
 %token  TABLESPACE
@@ -1013,10 +1017,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
@@ -1070,6 +1076,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
@@ -1279,6 +1286,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
@@ -1394,6 +1402,7 @@ statement:
         | show
         | slave
         | start
+        | test_stmt
         | truncate
         | uninstall
         | unlock
@@ -10251,6 +10260,7 @@ keyword:
         | SONAME_SYM            {}
         | START_SYM             {}
         | STOP_SYM              {}
+        | TEST_SYM              {}
         | TRUNCATE_SYM          {}
         | UNICODE_SYM           {}
         | UNINSTALL_SYM         {}
@@ -10288,6 +10298,7 @@ keyword_sp:
         | CHAIN_SYM                {}
         | CHANGED                  {}
         | CIPHER_SYM               {}
+        | CLEAR_SYM                {}
         | CLIENT_SYM               {}
         | COALESCE                 {}
         | CODE_SYM                 {}
@@ -10343,6 +10354,7 @@ keyword_sp:
         | GRANTS                   {}
         | GLOBAL_SYM               {}
         | HASH_SYM                 {}
+        | HIT_LIMIT_SYM            {}
         | HOSTS_SYM                {}
         | HOUR_SYM                 {}
         | IDENTIFIED_SYM           {}
@@ -10464,6 +10476,7 @@ keyword_sp:
         | SIMPLE_SYM               {}
         | SHARE_SYM                {}
         | SHUTDOWN                 {}
+        | SIGNAL_SYM               {}
         | SNAPSHOT_SYM             {}
         | SOUNDS_SYM               {}
         | SQL_CACHE_SYM            {}
@@ -10480,6 +10493,7 @@ keyword_sp:
         | SUBPARTITIONS_SYM        {}
         | SUPER_SYM                {}
         | SUSPEND_SYM              {}
+        | SYNCHRONIZE_SYM          {}
         | TABLES                   {}
         | TABLESPACE               {}
         | TEMPORARY                {}
@@ -10489,6 +10503,7 @@ keyword_sp:
         | TRANSACTION_SYM          {}
         | TRANSACTIONAL_SYM        {}
         | TRIGGERS_SYM             {}
+        | TIMEOUT_SYM              {}
         | TIMESTAMP                {}
         | TIMESTAMP_ADD            {}
         | TIMESTAMP_DIFF           {}
@@ -10509,6 +10524,7 @@ keyword_sp:
         | VIEW_SYM                 {}
         | VALUE_SYM                {}
         | WARNINGS                 {}
+        | WAIT_FOR_SYM             {}
         | WAIT_SYM                 {}
         | WEEK_SYM                 {}
         | WORK_SYM                 {}
@@ -12373,6 +12389,73 @@ uninstall:
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
             lex->comment= $3;
+          }
+        ;
+
+test_stmt:
+          TEST_SYM test_statement
+        ;
+
+test_statement:
+          SYNCHRONIZE_SYM ident_or_text
+          {
+            Lex->sql_command= SQLCOM_TEST_SYNC;
+            Lex->test_sync_req.hit_limit= 0;
+            Lex->test_sync_req.exec_count= 0;
+            Lex->test_sync_req.timeout= TEST_SYNC_DEFAULT_WAIT_TIMEOUT;
+            Lex->test_sync_req.signal.length= 0;
+            Lex->test_sync_req.wait_for.length= 0;
+            Lex->test_sync_req.sync_point= $2;
+          }
+          test_sync_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 exec_count= 0 */
+        ;
+
+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.exec_count= 1;
+          }
+        | EXECUTE_SYM opt_equal real_ulong_num
+          {
+            Lex->test_sync_req.exec_count= $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-11 15:32:09 +01:00
+++ b/storage/myisammrg/ha_myisammrg.cc	2007-12-28 15:46:40 +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().
@@ -918,6 +920,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 5.1 tree (istruewing:1.2638)Ingo Struewing28 Dec