From: Ingo Struewing Date: December 28 2007 2:46pm Subject: bk commit into 5.1 tree (istruewing:1.2638) List-Archive: http://lists.mysql.com/commits/40450 Message-Id: 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 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