Below is the list of changes that have just been committed into a local
6.0 repository of cbell. When cbell 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-12 15:13:31-05:00, cbell@mysql_cab_desk. +7 -0
BUG#33024 : DDL Blocker uses exposed variables
This patch includes a refactored DDL blocker that hides the
condition booleans and implements the methods as a singleton class.
Patch also adds CREATE INDEX and DROP INDEX to list of DDLs blocker
(per Guilhem).
mysql-test/r/backup_ddl_blocker.result@stripped, 2007-12-12 15:13:22-05:00, cbell@mysql_cab_desk. +309 -3
BUG#33024 : DDL Blocker uses exposed variables
New result file.
mysql-test/t/backup_ddl_blocker.test@stripped, 2007-12-12 15:13:23-05:00, cbell@mysql_cab_desk. +415 -7
BUG#33024 : DDL Blocker uses exposed variables
Added test for testing multiple blockers.
sql/backup/kernel.cc@stripped, 2007-12-12 15:13:25-05:00, cbell@mysql_cab_desk. +7 -9
BUG#33024 : DDL Blocker uses exposed variables
Changes made to call singleton.
sql/ddl_blocker.cc@stripped, 2007-12-12 15:13:23-05:00, cbell@mysql_cab_desk. +60 -13
BUG#33024 : DDL Blocker uses exposed variables
Refactored DDL blocker using a singleton class.
sql/ddl_blocker.h@stripped, 2007-12-12 15:13:24-05:00, cbell@mysql_cab_desk. +115 -41
BUG#33024 : DDL Blocker uses exposed variables
This patch changes the DDL blocker from APIs to a singleton class.
sql/mysqld.cc@stripped, 2007-12-12 15:13:24-05:00, cbell@mysql_cab_desk. +9 -17
BUG#33024 : DDL Blocker uses exposed variables
Instantiate the singleton class.
sql/sql_parse.cc@stripped, 2007-12-12 15:13:25-05:00, cbell@mysql_cab_desk. +32 -28
BUG#33024 : DDL Blocker uses exposed variables
Changes made to call singleton.
diff -Nrup a/mysql-test/r/backup_ddl_blocker.result b/mysql-test/r/backup_ddl_blocker.result
--- a/mysql-test/r/backup_ddl_blocker.result 2007-12-04 12:38:01 -05:00
+++ b/mysql-test/r/backup_ddl_blocker.result 2007-12-12 15:13:22 -05:00
@@ -1056,7 +1056,314 @@ con1: Cleanup
DROP DATABASE bup_ddl_blocker_2;
DROP DATABASE bup_ddl_blocker_4;
-Starting Test 6
+Starting Test 6 - Backup
+
+DROP DATABASE IF EXISTS bup_ddl_blocker_1;
+DROP DATABASE IF EXISTS bup_ddl_blocker_2;
+DROP DATABASE IF EXISTS bup_ddl_blocker_3;
+DROP DATABASE IF EXISTS bup_ddl_blocker_4;
+con1: Creating databases
+CREATE DATABASE bup_ddl_blocker_1;
+CREATE DATABASE bup_ddl_blocker_2;
+CREATE DATABASE bup_ddl_blocker_3;
+CREATE DATABASE bup_ddl_blocker_4;
+con1: Creating tables
+CREATE TABLE bup_ddl_blocker_1.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_2.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_3.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_4.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+con1: Loading data
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("01 Some data to test", 10);
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("02 Some data to test", 09);
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("03 Some data to test", 12);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("01 Some data to test", 3);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("02 Some data to test", 8);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("03 Some data to test", 11);
+CREATE INDEX 2t1col_b ON bup_ddl_blocker_2.t1 (col_b);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("01 Some data to test", 2);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("02 Some data to test", 4);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("03 Some data to test", 5);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("01 Some data to test", 1);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("02 Some data to test", 12);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("03 Some data to test", 3);
+CREATE INDEX 4t1col_b ON bup_ddl_blocker_4.t1 (col_b);
+con6: Getting lock on DDL in progress.
+SELECT get_lock("DDL_in_progress", 0);
+get_lock("DDL_in_progress", 0)
+1
+con2: Get a DDL going and stop in the middle
+CREATE INDEX 1t1col_b ON bup_ddl_blocker_1.t1 (col_b);
+con3: Get a DDL going and stop in the middle
+DROP INDEX 2t1col_b ON bup_ddl_blocker_2.t1;
+con1: Backing up database -- will block with lock
+BACKUP DATABASE bup_ddl_blocker_1, bup_ddl_blocker_2,
+bup_ddl_blocker_3, bup_ddl_blocker_4
+TO "bup_ddl_blocker.bak";
+con6: Checking locks
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "BACKUP DATABASE%";
+state info
+debug_sync_point: DDL_in_progress BACKUP DATABASE bup_ddl_blocker_1, bup_ddl_blocker_2,
+bup_ddl_blocker_3, bup_ddl_blocker_4
+TO "bup_ddl_blocker.bak"
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "CREATE INDEX 1t1col_b%";
+state info
+debug_sync_point: DDL_in_progress CREATE INDEX 1t1col_b ON bup_ddl_blocker_1.t1 (col_b)
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DROP INDEX 2t1col_b%";
+state info
+debug_sync_point: DDL_in_progress DROP INDEX 2t1col_b ON bup_ddl_blocker_2.t1
+con6: Getting lock on DDL blocker.
+SELECT get_lock("DDL_blocked", 0);
+get_lock("DDL_blocked", 0)
+1
+con6: Checking locks
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "BACKUP DATABASE%";
+state info
+debug_sync_point: DDL_blocked BACKUP DATABASE bup_ddl_blocker_1, bup_ddl_blocker_2,
+bup_ddl_blocker_3, bup_ddl_blocker_4
+TO "bup_ddl_blocker.bak"
+con4: Try a DDL but it is blocked by backup -- will not be in backup
+CREATE INDEX 3t1col_b ON bup_ddl_blocker_3.t1 (col_b);
+con5: Try a DDL but it is blocked by backup -- will not be in backup
+DROP INDEX 4t1col_b ON bup_ddl_blocker_4.t1;
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "CREATE INDEX 3t1col_b%";
+state info
+DDL blocker: DDL is blocked CREATE INDEX 3t1col_b ON bup_ddl_blocker_3.t1 (col_b)
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DROP INDEX 4t1col_b%";
+state info
+DDL blocker: DDL is blocked DROP INDEX 4t1col_b ON bup_ddl_blocker_4.t1
+con6: Releasing lock
+SELECT release_lock("DDL_blocked");
+release_lock("DDL_blocked")
+1
+con2: Completing DDL
+con3: Completing DDL
+con4: Completing DDL
+con5: Completing DDL
+backup_id
+#
+
+Verifying Test 6 results for backup.
+
+con1: Showing database tables after updates and backup
+con1: bup_ddl_blocker_2 and bup_ddl_blocker_4 indexes are not present
+SHOW INDEX FROM bup_ddl_blocker_1.t1;
+Table t1
+Non_unique 1
+Key_name 1t1col_b
+Seq_in_index 1
+Column_name col_b
+Collation A
+Cardinality 3
+Sub_part NULL
+Packed NULL
+Null YES
+Index_type BTREE
+Comment
+Index_Comment
+SHOW INDEX FROM bup_ddl_blocker_2.t1;
+SHOW INDEX FROM bup_ddl_blocker_3.t1;
+Table t1
+Non_unique 1
+Key_name 3t1col_b
+Seq_in_index 1
+Column_name col_b
+Collation A
+Cardinality 3
+Sub_part NULL
+Packed NULL
+Null YES
+Index_type BTREE
+Comment
+Index_Comment
+SHOW INDEX FROM bup_ddl_blocker_4.t1;
+con1: Dropping the database tables
+DROP DATABASE bup_ddl_blocker_1;
+DROP DATABASE bup_ddl_blocker_2;
+DROP DATABASE bup_ddl_blocker_3;
+DROP DATABASE bup_ddl_blocker_4;
+con1: Restoring the database
+RESTORE FROM "bup_ddl_blocker.bak";
+backup_id
+#
+con1: Showing databases that were backed up
+con1: bup_ddl_blocker_2 and bup_ddl_blocker_3 indexes are not present
+SHOW INDEX FROM bup_ddl_blocker_1.t1;
+Table t1
+Non_unique 1
+Key_name 1t1col_b
+Seq_in_index 1
+Column_name col_b
+Collation A
+Cardinality 3
+Sub_part NULL
+Packed NULL
+Null YES
+Index_type BTREE
+Comment
+Index_Comment
+SHOW INDEX FROM bup_ddl_blocker_2.t1;
+SHOW INDEX FROM bup_ddl_blocker_3.t1;
+SHOW INDEX FROM bup_ddl_blocker_4.t1;
+Table t1
+Non_unique 1
+Key_name 4t1col_b
+Seq_in_index 1
+Column_name col_b
+Collation A
+Cardinality 3
+Sub_part NULL
+Packed NULL
+Null YES
+Index_type BTREE
+Comment
+Index_Comment
+con1: Cleanup
+DROP DATABASE bup_ddl_blocker_1;
+DROP DATABASE bup_ddl_blocker_2;
+DROP DATABASE bup_ddl_blocker_3;
+DROP DATABASE bup_ddl_blocker_4;
+
+Starting Test 6 - Restore
+
+DROP DATABASE IF EXISTS bup_ddl_blocker_1;
+DROP DATABASE IF EXISTS bup_ddl_blocker_2;
+DROP DATABASE IF EXISTS bup_ddl_blocker_3;
+DROP DATABASE IF EXISTS bup_ddl_blocker_4;
+con1: Creating databases
+CREATE DATABASE bup_ddl_blocker_1;
+CREATE DATABASE bup_ddl_blocker_2;
+CREATE DATABASE bup_ddl_blocker_3;
+CREATE DATABASE bup_ddl_blocker_4;
+con1: Creating tables
+CREATE TABLE bup_ddl_blocker_1.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_2.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_3.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_4.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+con1: Loading data
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("01 Some data to test", 10);
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("02 Some data to test", 09);
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("03 Some data to test", 12);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("01 Some data to test", 3);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("02 Some data to test", 8);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("03 Some data to test", 11);
+CREATE INDEX 2t1col_b ON bup_ddl_blocker_2.t1 (col_b);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("01 Some data to test", 2);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("02 Some data to test", 4);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("03 Some data to test", 5);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("01 Some data to test", 1);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("02 Some data to test", 12);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("03 Some data to test", 3);
+CREATE INDEX 4t1col_b ON bup_ddl_blocker_4.t1 (col_b);
+BACKUP DATABASE bup_ddl_blocker_1, bup_ddl_blocker_2,
+bup_ddl_blocker_3, bup_ddl_blocker_4
+TO "bup_ddl_blocker_orig.bak";
+backup_id
+#
+con6: Getting lock on DDL in progress.
+SELECT get_lock("DDL_in_progress", 0);
+get_lock("DDL_in_progress", 0)
+1
+con2: Get a DDL going and stop in the middle
+CREATE INDEX 1t1col_b ON bup_ddl_blocker_1.t1 (col_b);
+con3: Get a DDL going and stop in the middle
+DROP INDEX 2t1col_b ON bup_ddl_blocker_2.t1;
+con1: Restoring database -- will block with lock
+RESTORE FROM "bup_ddl_blocker_orig.bak";
+con6: Checking locks
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "RESTORE FROM%";
+state info
+debug_sync_point: DDL_in_progress RESTORE FROM "bup_ddl_blocker_orig.bak"
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "CREATE INDEX 1t1col_b%";
+state info
+debug_sync_point: DDL_in_progress CREATE INDEX 1t1col_b ON bup_ddl_blocker_1.t1 (col_b)
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DROP INDEX 2t1col_b%";
+state info
+debug_sync_point: DDL_in_progress DROP INDEX 2t1col_b ON bup_ddl_blocker_2.t1
+con6: Getting lock on DDL blocker.
+SELECT get_lock("DDL_blocked", 0);
+get_lock("DDL_blocked", 0)
+1
+con6: Checking locks
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "RESTORE FROM%";
+state info
+debug_sync_point: DDL_blocked RESTORE FROM "bup_ddl_blocker_orig.bak"
+con4: Try a DDL but it is blocked by backup -- will not be in backup
+CREATE INDEX 3t1col_b ON bup_ddl_blocker_3.t1 (col_b);
+con5: Try a DDL but it is blocked by backup -- will not be in backup
+DROP INDEX 4t1col_b ON bup_ddl_blocker_4.t1;
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "CREATE INDEX 3t1col_b%";
+state info
+DDL blocker: DDL is blocked CREATE INDEX 3t1col_b ON bup_ddl_blocker_3.t1 (col_b)
+Timeout in wait_condition.inc for SELECT state = "DDL blocker: DDL is blocked"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DDROP INDEX 4t1col_b%"
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DROP INDEX 4t1col_b%";
+state info
+DDL blocker: DDL is blocked DROP INDEX 4t1col_b ON bup_ddl_blocker_4.t1
+con6: Releasing lock
+SELECT release_lock("DDL_blocked");
+release_lock("DDL_blocked")
+1
+con2: Completing DDL
+con3: Completing DDL
+con4: Completing DDL
+con5: Completing DDL
+backup_id
+#
+
+Verifying Test 6 results for restore.
+
+con1: Showing databases that were backed up
+con1: bup_ddl_blocker_1 and bup_ddl_blocker_4 indexes are not present
+SHOW INDEX FROM bup_ddl_blocker_1.t1;
+SHOW INDEX FROM bup_ddl_blocker_2.t1;
+Table t1
+Non_unique 1
+Key_name 2t1col_b
+Seq_in_index 1
+Column_name col_b
+Collation A
+Cardinality 3
+Sub_part NULL
+Packed NULL
+Null YES
+Index_type BTREE
+Comment
+Index_Comment
+SHOW INDEX FROM bup_ddl_blocker_3.t1;
+Table t1
+Non_unique 1
+Key_name 3t1col_b
+Seq_in_index 1
+Column_name col_b
+Collation A
+Cardinality 3
+Sub_part NULL
+Packed NULL
+Null YES
+Index_type BTREE
+Comment
+Index_Comment
+SHOW INDEX FROM bup_ddl_blocker_4.t1;
+con1: Cleanup
+DROP DATABASE bup_ddl_blocker_1;
+DROP DATABASE bup_ddl_blocker_2;
+DROP DATABASE bup_ddl_blocker_3;
+DROP DATABASE bup_ddl_blocker_4;
+
+Starting Test 7
DROP TABLE IF EXISTS test.t2;
DROP TABLE IF EXISTS bup_ddl_blocker.t1, bup_ddl_blocker.t3;
@@ -1134,7 +1441,7 @@ Field Type Null Key Default Extra
col_a char(40) YES NULL
col_b int(11) YES NULL
-Verifying Test 6 results:
+Verifying Test 7 results:
T1 should have the changes after backup - count(*) = 2
SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
@@ -1152,5 +1459,4 @@ WHERE TABLE_NAME = 't3' AND TABLE_SCHEMA
count(*)
2
DROP TABLE test.t2;
-con1: Cleanup
DROP DATABASE bup_ddl_blocker;
diff -Nrup a/mysql-test/t/backup_ddl_blocker.test b/mysql-test/t/backup_ddl_blocker.test
--- a/mysql-test/t/backup_ddl_blocker.test 2007-12-06 13:05:56 -05:00
+++ b/mysql-test/t/backup_ddl_blocker.test 2007-12-12 15:13:23 -05:00
@@ -34,7 +34,9 @@
# 4 DROP DATABASE
# 5 ALTER DATABASE
# 5 TRUNCATE TABLE
-# 6 DDL statements do not block each other
+# 6 CREATE INDEX
+# 6 DROP INDEX
+# 7 DDL statements do not block each other
#
# The tests shall be run once for backup and again for restore.
#
@@ -1799,12 +1801,421 @@ DROP DATABASE bup_ddl_blocker_4;
##############################################################
--echo
---echo Starting Test 6
+--echo Starting Test 6 - Backup
+--echo
+##############################################################
+
+--disable_warnings
+DROP DATABASE IF EXISTS bup_ddl_blocker_1;
+DROP DATABASE IF EXISTS bup_ddl_blocker_2;
+DROP DATABASE IF EXISTS bup_ddl_blocker_3;
+DROP DATABASE IF EXISTS bup_ddl_blocker_4;
+--enable_warnings
+
+# Create databases.
+--echo con1: Creating databases
+CREATE DATABASE bup_ddl_blocker_1;
+CREATE DATABASE bup_ddl_blocker_2;
+CREATE DATABASE bup_ddl_blocker_3;
+CREATE DATABASE bup_ddl_blocker_4;
+
+# Create transaction tables and load them with data.
+--echo con1: Creating tables
+CREATE TABLE bup_ddl_blocker_1.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_2.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_3.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_4.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+
+--echo con1: Loading data
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("01 Some data to test", 10);
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("02 Some data to test", 09);
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("03 Some data to test", 12);
+
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("01 Some data to test", 3);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("02 Some data to test", 8);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("03 Some data to test", 11);
+
+CREATE INDEX 2t1col_b ON bup_ddl_blocker_2.t1 (col_b);
+
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("01 Some data to test", 2);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("02 Some data to test", 4);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("03 Some data to test", 5);
+
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("01 Some data to test", 1);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("02 Some data to test", 12);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("03 Some data to test", 3);
+
+CREATE INDEX 4t1col_b ON bup_ddl_blocker_4.t1 (col_b);
+
+connection con6;
+
+# Set the breakpoint for DDL in progress.
+--echo con6: Getting lock on DDL in progress.
+SELECT get_lock("DDL_in_progress", 0);
+
+connection con2;
+
+--echo con2: Get a DDL going and stop in the middle
+send CREATE INDEX 1t1col_b ON bup_ddl_blocker_1.t1 (col_b);
+
+connection con3;
+
+--echo con3: Get a DDL going and stop in the middle
+send DROP INDEX 2t1col_b ON bup_ddl_blocker_2.t1;
+
+# Start the backup and allow it to break on lock.
+
+connection con1;
+
+--echo con1: Backing up database -- will block with lock
+send BACKUP DATABASE bup_ddl_blocker_1, bup_ddl_blocker_2,
+ bup_ddl_blocker_3, bup_ddl_blocker_4
+ TO "bup_ddl_blocker.bak";
+
+connection con6;
+
+# Wait for lock to be acquired and execution to reach breakpoint
+--echo con6: Checking locks
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "BACKUP DATABASE%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "BACKUP DATABASE%";
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "CREATE INDEX 1t1col_b%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "CREATE INDEX 1t1col_b%";
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "DROP INDEX 2t1col_b%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DROP INDEX 2t1col_b%";
+
+# Now set the breakpoint for DDL blocker.
+# This releases lock on DDL_in_progress stopping all DDLs.
+--echo con6: Getting lock on DDL blocker.
+SELECT get_lock("DDL_blocked", 0);
+
+connection con6;
+
+--echo con6: Checking locks
+let $wait_condition = SELECT state = "debug_sync_point: DDL_blocked"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "BACKUP DATABASE%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "BACKUP DATABASE%";
+
+connection con4;
+
+--echo con4: Try a DDL but it is blocked by backup -- will not be in backup
+send CREATE INDEX 3t1col_b ON bup_ddl_blocker_3.t1 (col_b);
+
+connection con5;
+
+--echo con5: Try a DDL but it is blocked by backup -- will not be in backup
+send DROP INDEX 4t1col_b ON bup_ddl_blocker_4.t1;
+
+connection con6;
+
+let $wait_condition = SELECT state = "DDL blocker: DDL is blocked"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "CREATE INDEX 3t1col_b%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "CREATE INDEX 3t1col_b%";
+
+let $wait_condition = SELECT state = "DDL blocker: DDL is blocked"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "DROP INDEX 4t1col_b%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DROP INDEX 4t1col_b%";
+
+--echo con6: Releasing lock
+SELECT release_lock("DDL_blocked");
+
+# Reconnect to connections and allow them to finish.
+
+connection con2;
+--echo con2: Completing DDL
+reap;
+
+connection con3;
+--echo con3: Completing DDL
+reap;
+
+connection con4;
+--echo con4: Completing DDL
+reap;
+
+connection con5;
+--echo con5: Completing DDL
+reap;
+
+# Reconnect to con1 and let backup finish.
+
+connection con1;
+--replace_column 1 #
+reap;
+
+##############################################################
+--echo
+--echo Verifying Test 6 results for backup.
+--echo
+##############################################################
+
+# Show that all changes got applied.
+--echo con1: Showing database tables after updates and backup
+--echo con1: bup_ddl_blocker_2 and bup_ddl_blocker_4 indexes are not present
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_1.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_2.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_3.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_4.t1
+
+--echo con1: Dropping the database tables
+DROP DATABASE bup_ddl_blocker_1;
+DROP DATABASE bup_ddl_blocker_2;
+DROP DATABASE bup_ddl_blocker_3;
+DROP DATABASE bup_ddl_blocker_4;
+
+--echo con1: Restoring the database
+--replace_column 1 #
+--disable_warnings
+RESTORE FROM "bup_ddl_blocker.bak";
+--enable_warnings
+
+--echo con1: Showing databases that were backed up
+--echo con1: bup_ddl_blocker_2 and bup_ddl_blocker_3 indexes are not present
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_1.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_2.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_3.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_4.t1
+
+--echo con1: Cleanup
+DROP DATABASE bup_ddl_blocker_1;
+DROP DATABASE bup_ddl_blocker_2;
+DROP DATABASE bup_ddl_blocker_3;
+DROP DATABASE bup_ddl_blocker_4;
+
+##############################################################
+--echo
+--echo Starting Test 6 - Restore
+--echo
+##############################################################
+--disable_warnings
+DROP DATABASE IF EXISTS bup_ddl_blocker_1;
+DROP DATABASE IF EXISTS bup_ddl_blocker_2;
+DROP DATABASE IF EXISTS bup_ddl_blocker_3;
+DROP DATABASE IF EXISTS bup_ddl_blocker_4;
+--enable_warnings
+
+# Create databases.
+--echo con1: Creating databases
+CREATE DATABASE bup_ddl_blocker_1;
+CREATE DATABASE bup_ddl_blocker_2;
+CREATE DATABASE bup_ddl_blocker_3;
+CREATE DATABASE bup_ddl_blocker_4;
+
+# Create transaction tables and load them with data.
+--echo con1: Creating tables
+CREATE TABLE bup_ddl_blocker_1.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_2.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_3.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker_4.t1 (col_a CHAR(40), col_b int) ENGINE=INNODB;
+
+--echo con1: Loading data
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("01 Some data to test", 10);
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("02 Some data to test", 09);
+INSERT INTO bup_ddl_blocker_1.t1 VALUES ("03 Some data to test", 12);
+
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("01 Some data to test", 3);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("02 Some data to test", 8);
+INSERT INTO bup_ddl_blocker_2.t1 VALUES ("03 Some data to test", 11);
+
+CREATE INDEX 2t1col_b ON bup_ddl_blocker_2.t1 (col_b);
+
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("01 Some data to test", 2);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("02 Some data to test", 4);
+INSERT INTO bup_ddl_blocker_3.t1 VALUES ("03 Some data to test", 5);
+
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("01 Some data to test", 1);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("02 Some data to test", 12);
+INSERT INTO bup_ddl_blocker_4.t1 VALUES ("03 Some data to test", 3);
+
+CREATE INDEX 4t1col_b ON bup_ddl_blocker_4.t1 (col_b);
+
+# Get a backup to work with.
+--replace_column 1 #
+BACKUP DATABASE bup_ddl_blocker_1, bup_ddl_blocker_2,
+ bup_ddl_blocker_3, bup_ddl_blocker_4
+ TO "bup_ddl_blocker_orig.bak";
+
+connection con6;
+
+# Set the breakpoint for DDL in progress.
+--echo con6: Getting lock on DDL in progress.
+SELECT get_lock("DDL_in_progress", 0);
+
+connection con2;
+
+--echo con2: Get a DDL going and stop in the middle
+send CREATE INDEX 1t1col_b ON bup_ddl_blocker_1.t1 (col_b);
+
+connection con3;
+
+--echo con3: Get a DDL going and stop in the middle
+send DROP INDEX 2t1col_b ON bup_ddl_blocker_2.t1;
+
+# Start the backup and allow it to break on lock.
+
+connection con1;
+
+--echo con1: Restoring database -- will block with lock
+send RESTORE FROM "bup_ddl_blocker_orig.bak";
+
+connection con6;
+
+# Wait for lock to be acquired and execution to reach breakpoint
+--echo con6: Checking locks
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "RESTORE FROM%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "RESTORE FROM%";
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "CREATE INDEX 1t1col_b%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "CREATE INDEX 1t1col_b%";
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "DROP INDEX 2t1col_b%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DROP INDEX 2t1col_b%";
+
+# Now set the breakpoint for DDL blocker.
+# This releases lock on DDL_in_progress stopping all DDLs.
+--echo con6: Getting lock on DDL blocker.
+SELECT get_lock("DDL_blocked", 0);
+
+connection con6;
+
+--echo con6: Checking locks
+let $wait_condition = SELECT state = "debug_sync_point: DDL_blocked"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "RESTORE FROM%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "RESTORE FROM%";
+
+connection con4;
+
+--echo con4: Try a DDL but it is blocked by backup -- will not be in backup
+send CREATE INDEX 3t1col_b ON bup_ddl_blocker_3.t1 (col_b);
+
+connection con5;
+
+--echo con5: Try a DDL but it is blocked by backup -- will not be in backup
+send DROP INDEX 4t1col_b ON bup_ddl_blocker_4.t1;
+
+connection con6;
+
+let $wait_condition = SELECT state = "DDL blocker: DDL is blocked"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "CREATE INDEX 3t1col_b%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "CREATE INDEX 3t1col_b%";
+
+let $wait_condition = SELECT state = "DDL blocker: DDL is blocked"
+ FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE info LIKE "DDROP INDEX 4t1col_b%";
+--source include/wait_condition.inc
+
+SELECT state, info FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE info LIKE "DROP INDEX 4t1col_b%";
+
+--echo con6: Releasing lock
+SELECT release_lock("DDL_blocked");
+
+# Reconnect to connections and allow them to finish.
+
+connection con2;
+--echo con2: Completing DDL
+reap;
+
+connection con3;
+--echo con3: Completing DDL
+reap;
+
+connection con4;
+--echo con4: Completing DDL
+reap;
+
+connection con5;
+--echo con5: Completing DDL
+reap;
+
+# Reconnect to con1 and let backup finish.
+
+connection con1;
+--replace_column 1 #
+reap;
+
+##############################################################
+--echo
+--echo Verifying Test 6 results for restore.
+--echo
+##############################################################
+
+--echo con1: Showing databases that were backed up
+--echo con1: bup_ddl_blocker_1 and bup_ddl_blocker_4 indexes are not present
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_1.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_2.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_3.t1
+--query_vertical SHOW INDEX FROM bup_ddl_blocker_4.t1
+
+--echo con1: Cleanup
+DROP DATABASE bup_ddl_blocker_1;
+DROP DATABASE bup_ddl_blocker_2;
+DROP DATABASE bup_ddl_blocker_3;
+DROP DATABASE bup_ddl_blocker_4;
+
+
+
+
+
+##############################################################
+--echo
+--echo Starting Test 7
--echo
##############################################################
#
-# Test 6 sequence diagram (not UML)
+# Test 7 sequence diagram (not UML)
#
# con1 con2 con3 con4 con5
# (setup) | | | |
@@ -1929,7 +2340,7 @@ DESCRIBE bup_ddl_blocker.t3;
##############################################################
--echo
---echo Verifying Test 6 results:
+--echo Verifying Test 7 results:
--echo
##############################################################
@@ -1946,9 +2357,6 @@ SELECT count(*) FROM INFORMATION_SCHEMA.
WHERE TABLE_NAME = 't3' AND TABLE_SCHEMA = 'bup_ddl_blocker';
DROP TABLE test.t2;
-
-
---echo con1: Cleanup
DROP DATABASE bup_ddl_blocker;
remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker_orig.bak;
diff -Nrup a/sql/backup/kernel.cc b/sql/backup/kernel.cc
--- a/sql/backup/kernel.cc 2007-12-03 15:28:16 -05:00
+++ b/sql/backup/kernel.cc 2007-12-12 15:13:25 -05:00
@@ -29,6 +29,8 @@
#include "ddl_blocker.h"
#include "backup_progress.h"
+extern DDL_blocker_class *DDL_blocker;
+
namespace backup {
// Helper functions
@@ -67,10 +69,6 @@ void free_stream_memory();
}
-extern pthread_mutex_t THR_LOCK_DDL_blocker;
-extern pthread_cond_t COND_backup_blocked;
-extern pthread_cond_t COND_DDL_blocker;
-
/**
Call backup kernel API to execute backup related SQL statement.
@@ -177,7 +175,7 @@ execute_backup_command(THD *thd, LEX *le
/*
Freeze all DDL operations by turning on DDL blocker.
*/
- if (!block_DDL(thd))
+ if (!DDL_blocker->block_DDL(thd))
{
stop= my_time(0);
info.save_end_time(stop);
@@ -235,7 +233,7 @@ execute_backup_command(THD *thd, LEX *le
/*
Unfreeze all DDL operations by turning off DDL blocker.
*/
- unblock_DDL();
+ DDL_blocker->unblock_DDL();
BACKUP_BREAKPOINT("DDL_unblocked");
if (stream)
@@ -267,7 +265,7 @@ execute_backup_command(THD *thd, LEX *le
be counted. Waiting until after this step caused backup to
skip new or dropped tables.
*/
- if (!block_DDL(thd))
+ if (!DDL_blocker->block_DDL(thd))
goto backup_error;
Backup_info info(thd);
@@ -359,7 +357,7 @@ execute_backup_command(THD *thd, LEX *le
/*
Unfreeze all DDL operations by turning off DDL blocker.
*/
- unblock_DDL();
+ DDL_blocker->unblock_DDL();
BACKUP_BREAKPOINT("DDL_unblocked");
if (stream)
@@ -442,7 +440,7 @@ int mysql_backup(THD *thd,
error:
- unblock_DDL();
+ DDL_blocker->unblock_DDL();
DBUG_RETURN(ERROR);
}
diff -Nrup a/sql/ddl_blocker.cc b/sql/ddl_blocker.cc
--- a/sql/ddl_blocker.cc 2007-11-23 08:27:41 -05:00
+++ b/sql/ddl_blocker.cc 2007-12-12 15:13:23 -05:00
@@ -29,15 +29,49 @@
#include "ddl_blocker.h"
-my_bool DDL_blocked= FALSE; ///< Assume DDL is not blocked.
-int DDL_blocks= 0; ///< Number of DDL operations in progress.
+DDL_blocker_class *DDL_blocker_class::m_instance= NULL;
+
+DDL_blocker_class *DDL_blocker_class::get_DDL_blocker_class_instance()
+{
+ if (m_instance == NULL)
+ m_instance = new DDL_blocker_class();
+ return m_instance;
+}
+
+void DDL_blocker_class::destroy_DDL_blocker_class_instance()
+{
+ delete m_instance;
+ m_instance= NULL;
+}
+
+DDL_blocker_class::DDL_blocker_class()
+{
+ pthread_mutex_init(&THR_LOCK_DDL_blocker, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&THR_LOCK_DDL_is_blocked, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&THR_LOCK_DDL_blocker_blocked, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&COND_DDL_blocker, NULL);
+ pthread_cond_init(&COND_process_blocked, NULL);
+ pthread_cond_init(&COND_DDL_blocker_blocked, NULL);
+ DDL_blocked= FALSE;
+ DDL_blocks= 0;
+}
+
+DDL_blocker_class::~DDL_blocker_class()
+{
+ pthread_mutex_destroy(&THR_LOCK_DDL_blocker);
+ pthread_mutex_destroy(&THR_LOCK_DDL_is_blocked);
+ pthread_mutex_destroy(&THR_LOCK_DDL_blocker_blocked);
+ pthread_cond_destroy(&COND_DDL_blocker);
+ pthread_cond_destroy(&COND_process_blocked);
+ pthread_cond_destroy(&COND_DDL_blocker_blocked);
+}
/**
start_DDL()
Increments the DDL_blocks counter to indicate a DDL is in progress.
*/
-void start_DDL()
+void DDL_blocker_class::start_DDL()
{
DBUG_ENTER("start_DDL()");
pthread_mutex_lock(&THR_LOCK_DDL_blocker);
@@ -52,7 +86,7 @@ void start_DDL()
Decrements the DDL_blocks counter to indicate a DDL is done.
Signals blocked process if counter == 0.
*/
-void end_DDL()
+void DDL_blocker_class::end_DDL()
{
DBUG_ENTER("end_DDL()");
pthread_mutex_lock(&THR_LOCK_DDL_blocker);
@@ -65,7 +99,7 @@ void end_DDL()
}
/**
- check_ddl_blocker
+ check_DDL_blocker
Check to see if we are blocked from continuing. If so,
wait until the blocked process signals the condition.
@@ -73,7 +107,7 @@ void end_DDL()
@param thd The THD object from the caller.
@returns TRUE
*/
-my_bool check_DDL_blocker(THD *thd)
+my_bool DDL_blocker_class::check_DDL_blocker(THD *thd)
{
DBUG_ENTER("check_DDL_blocker()");
BACKUP_BREAKPOINT("DDL_not_blocked");
@@ -105,26 +139,38 @@ my_bool check_DDL_blocker(THD *thd)
@params thd THD object.
@returns TRUE
*/
-my_bool block_DDL(THD *thd)
+my_bool DDL_blocker_class::block_DDL(THD *thd)
{
DBUG_ENTER("block_DDL()");
BACKUP_BREAKPOINT("DDL_in_progress");
+
/*
Only 1 DDL blocking operation can run at a time.
+ Check the blocker blocked condition.
+ Rest until another blocker is done.
*/
- if (DDL_blocked)
- DBUG_RETURN(FALSE);
+ pthread_mutex_lock(&THR_LOCK_DDL_blocker_blocked);
+ thd->enter_cond(&COND_DDL_blocker_blocked, &THR_LOCK_DDL_blocker_blocked,
+ "DDL blocker: Checking block on blocker");
+ while (DDL_blocked)
+ pthread_cond_wait(&COND_DDL_blocker_blocked,
+ &THR_LOCK_DDL_blocker_blocked);
+ DDL_blocked= TRUE;
+ thd->exit_cond("DDL blocker: Ok to block DDL");
+
+ BACKUP_BREAKPOINT("DDL_blocker_blocked");
+
/*
Check the ddl blocker condition. Rest until ddl blocker is released.
*/
pthread_mutex_lock(&THR_LOCK_DDL_blocker);
thd->enter_cond(&COND_process_blocked, &THR_LOCK_DDL_blocker,
- "DDL blocker: Checking block on DDL changes");
+ "DDL blocker: Checking block on DDL");
while (DDL_blocks != 0)
pthread_cond_wait(&COND_process_blocked, &THR_LOCK_DDL_blocker);
- DDL_blocked= TRUE;
- thd->exit_cond("DDL blocker: Ok to run operation - no DDL in progress");
+ thd->exit_cond("DDL blocker: DDL is now blocked");
+
BACKUP_BREAKPOINT("DDL_blocked");
DBUG_RETURN(TRUE);
}
@@ -135,11 +181,12 @@ my_bool block_DDL(THD *thd)
This method is used to unblock all DDL commands. It sets the boolean
DDL_blocked to FALSE to tell the DDL operations that they can proceed.
*/
-void unblock_DDL()
+void DDL_blocker_class::unblock_DDL()
{
pthread_mutex_lock(&THR_LOCK_DDL_blocker);
DDL_blocked= FALSE;
pthread_cond_broadcast(&COND_DDL_blocker);
+ pthread_cond_signal(&COND_DDL_blocker_blocked);
pthread_mutex_unlock(&THR_LOCK_DDL_blocker);
}
diff -Nrup a/sql/ddl_blocker.h b/sql/ddl_blocker.h
--- a/sql/ddl_blocker.h 2007-11-24 16:45:07 -05:00
+++ b/sql/ddl_blocker.h 2007-12-12 15:13:24 -05:00
@@ -6,44 +6,118 @@
#include "mysql_priv.h"
#include "backup/debug.h"
-/*
- Mutexes and condition variables -- see mysqld.cc.
-*/
-extern pthread_mutex_t THR_LOCK_DDL_blocker;
-extern pthread_mutex_t THR_LOCK_DDL_is_blocked;
-extern pthread_cond_t COND_DDL_blocker;
-extern pthread_cond_t COND_process_blocked;
-
-/*
- Increments the backup's counter to indicate a DDL is in progress.
-*/
-void start_DDL();
-
-/*
- Decrements the backup's counter to indicate a DDL is done.
- Signals backup process if counter == 0.
-*/
-void end_DDL();
-
-/*
- Check to see if we are blocked from continuing. If so,
- wait until the backup process signals the condition.
-*/
-my_bool check_DDL_blocker(THD *thd);
-
-/*
- This method is used to block all DDL commands. It checks the counter
- DDL_blocks and if > 0 it blocks the backup until all DDL operations are
- complete and the condition variable has been signaled.
-
- The method also sets the boolean DDL_blocked to TRUE to tell the DDL
- operations that they must block until the backup operation is complete.
-*/
-my_bool block_DDL(THD *thd);
-
-/*
- This method is used to unblock all DDL commands. It sets the boolean
- DDL_blocked to FALSE to tell the DDL operations that they can proceed.
-*/
-void unblock_DDL();
-
+/**
+ @class DDL_blocker_class
+
+ @brief Implements a simple DDL blocker mechanism.
+
+ The DDL_blocker_class is a singleton class designed to allow DDL
+ operations to be blocked while an operation that uses this class
+ executes. The class is designed to allow any number of DDL operations
+ to execute but only one blocking operation can block DDL operations
+ at a time.
+
+ If an operation has blocked DDL operations and another operation attempts
+ to block DDL operations, the second blocking operation will wait
+ until the first blocking operation is complete.
+
+ Checking for Block
+ For any DDL operation that needs to be blocked while another
+ operation is executing, you can check the status of the DDL blocker
+ by calling @c check_DDL_blocker(). This method will return when there
+ is no block or wait while the blocking operation is running. Once the
+ method returns, the DDL operation that called the method is registered
+ so that any other blocking operation will wait while the DDL operation
+ is running. When the DDL operation is complete, you must unregister the
+ DDL operation by calling end_DDL().
+
+ Blocking DDL Operations
+ To block a DDL operation, call block_DDL(). This registers the blocking
+ operation and prevents any DDL operations that use check_DDL_blocker()
+ to block while the blocking operation is running. When the blocking
+ operation is complete, you must call unblock_DDL() to unregister
+ the blocking operation.
+
+ Singleton Methods
+ The creation of the singleton is accomplished using
+ get_DDL_blocker_class_instance(). This method is called from mysqld.cc
+ and creates and initializes all of the private mutex, condition, and
+ controlling variables. The method destroy_DDL_blocker_class_instance()
+ destroys the mutex and condition variables.
+
+ Calling the Singleton
+ To call the singleton class, you must declare an external variable
+ to the global variable DDL_blocker as shown below.
+
+ @c extern DDL_blocker_class *DDL_blocker;
+
+ Calling methods on the singleton is accomplished using the DDL_blocker
+ variable such as: @c DDL_blocker->block_DDL().
+
+ @note: This class is currently only used in online backup. If you would
+ like to use it elsewhere and have questions, please contact
+ Chuck Bell (cbell@stripped) for more details and how to setup
+ a test case to test the DDL blocking mechanism for your use.
+ */
+class DDL_blocker_class
+{
+ public:
+
+ /*
+ Singleton class
+ */
+ static DDL_blocker_class *get_DDL_blocker_class_instance();
+ static void destroy_DDL_blocker_class_instance();
+
+ /*
+ Check to see if we are blocked from continuing. If so,
+ wait until the backup process signals the condition.
+ */
+ my_bool check_DDL_blocker(THD *thd);
+
+ /*
+ Decrements the backup's counter to indicate a DDL is done.
+ Signals backup process if counter == 0.
+ */
+ void end_DDL();
+
+ /*
+ This method is used to block all DDL commands. It checks the counter
+ DDL_blocks and if > 0 it blocks the backup until all DDL operations are
+ complete and the condition variable has been signaled.
+
+ The method also sets the boolean DDL_blocked to TRUE to tell the DDL
+ operations that they must block until the backup operation is complete.
+ */
+ my_bool block_DDL(THD *thd);
+
+ /*
+ This method is used to unblock all DDL commands. It sets the boolean
+ DDL_blocked to FALSE to tell the DDL operations that they can proceed.
+ */
+ void unblock_DDL();
+
+ private:
+
+ DDL_blocker_class();
+ ~DDL_blocker_class();
+
+ /*
+ Increments the backup's counter to indicate a DDL is in progress.
+ */
+ void start_DDL();
+
+ /*
+ These variables are used to implement the metadata freeze "DDL blocker"
+ for online backup.
+ */
+ pthread_mutex_t THR_LOCK_DDL_blocker; ///< Mutex for blocking DDL
+ pthread_mutex_t THR_LOCK_DDL_is_blocked; ///< Mutex for checking block DDL
+ pthread_mutex_t THR_LOCK_DDL_blocker_blocked; ///< One blocker at a time
+ pthread_cond_t COND_DDL_blocker; ///< cond for blocking DDL
+ pthread_cond_t COND_process_blocked; ///< cond for checking block DDL
+ pthread_cond_t COND_DDL_blocker_blocked; ///< cond for blocker blocked
+ my_bool DDL_blocked; ///< Is blocking operation running
+ int DDL_blocks; ///< Number of DDL operations in progress.
+ static DDL_blocker_class *m_instance; ///< instance var for singleton
+};
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc 2007-12-06 12:31:04 -05:00
+++ b/sql/mysqld.cc 2007-12-12 15:13:24 -05:00
@@ -26,6 +26,7 @@
#include "mysqld_suffix.h"
#include "mysys_err.h"
#include "events.h"
+#include "ddl_blocker.h"
#include "../storage/myisam/ha_myisam.h"
@@ -364,6 +365,7 @@ static pthread_cond_t COND_thread_cache,
/* Global variables */
+DDL_blocker_class *DDL_blocker= NULL;
bool opt_update_log, opt_bin_log;
my_bool opt_log, opt_slow_log;
ulong log_output_options;
@@ -579,15 +581,6 @@ pthread_mutex_t LOCK_mysql_create_db, LO
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
LOCK_global_system_variables,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
-
-/*
- These variables are used to implement the metadata freeze "DDL blocker"
- for online backup.
-*/
-pthread_mutex_t THR_LOCK_DDL_blocker;
-pthread_mutex_t THR_LOCK_DDL_is_blocked;
-pthread_cond_t COND_DDL_blocker;
-pthread_cond_t COND_process_blocked;
pthread_mutex_t LOCK_backup;
/*
@@ -1348,11 +1341,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_user_conn);
- (void) pthread_mutex_destroy(&THR_LOCK_DDL_blocker);
- (void) pthread_mutex_destroy(&THR_LOCK_DDL_is_blocked);
(void) pthread_mutex_destroy(&LOCK_backup);
- (void) pthread_cond_destroy(&COND_DDL_blocker);
- (void) pthread_cond_destroy(&COND_process_blocked);
Events::destroy_mutexes();
#ifdef HAVE_OPENSSL
(void) pthread_mutex_destroy(&LOCK_des_key_file);
@@ -1380,6 +1369,7 @@ static void clean_up_mutexes()
(void) pthread_cond_destroy(&COND_thread_cache);
(void) pthread_cond_destroy(&COND_flush_thread_cache);
(void) pthread_cond_destroy(&COND_manager);
+ DDL_blocker_class::destroy_DDL_blocker_class_instance();
}
#endif /*EMBEDDED_LIBRARY*/
@@ -3109,11 +3099,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_prepared_stmt_count, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&THR_LOCK_DDL_blocker, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&THR_LOCK_DDL_is_blocked, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_backup, MY_MUTEX_INIT_FAST);
- (void) pthread_cond_init(&COND_DDL_blocker, NULL);
- (void) pthread_cond_init(&COND_process_blocked, NULL);
#ifdef HAVE_OPENSSL
(void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
#ifndef HAVE_YASSL
@@ -3143,6 +3129,12 @@ static int init_thread_environment()
#endif
(void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_server_started,NULL);
+
+ /*
+ Initialize the DDL blocker
+ */
+ DDL_blocker= DDL_blocker_class::get_DDL_blocker_class_instance();
+
sp_cache_init();
Events::init_mutexes();
/* Parameter for threads created for connections */
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc 2007-12-06 12:31:04 -05:00
+++ b/sql/sql_parse.cc 2007-12-12 15:13:25 -05:00
@@ -89,6 +89,8 @@ const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};
+extern DDL_blocker_class *DDL_blocker;
+
static void unlock_locked_tables(THD *thd)
{
if (thd->locked_tables)
@@ -2142,7 +2144,7 @@ mysql_execute_command(THD *thd)
TABLE in the same way. That way we avoid that a new table is
created during a gobal read lock.
*/
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
if (!thd->locked_tables &&
!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
{
@@ -2240,7 +2242,7 @@ mysql_execute_command(THD *thd)
res= handle_select(thd, lex, result, 0);
delete result;
}
- end_DDL();
+ DDL_blocker->end_DDL();
}
else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
create_table= lex->unlink_first_table(&link_to_local);
@@ -2267,7 +2269,7 @@ mysql_execute_command(THD *thd)
/* put tables back for PS rexecuting */
end_with_restore_list:
- end_DDL();
+ DDL_blocker->end_DDL();
lex->link_first_table_back(create_table, link_to_local);
break;
}
@@ -2283,6 +2285,7 @@ end_with_restore_list:
table without having to do a full rebuild.
*/
{
+ DDL_blocker->check_DDL_blocker(thd);
/* Prepare stack copies to be re-execution safe */
HA_CREATE_INFO create_info;
Alter_info alter_info(lex->alter_info, thd->mem_root);
@@ -2310,6 +2313,7 @@ end_with_restore_list:
res= mysql_alter_table(thd, first_table->db, first_table->table_name,
&create_info, first_table, &alter_info,
0, (ORDER*) 0, 0);
+ DDL_blocker->end_DDL();
break;
}
#ifdef HAVE_REPLICATION
@@ -2351,7 +2355,7 @@ end_with_restore_list:
case SQLCOM_ALTER_TABLE:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
{
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
ulong priv=0;
ulong priv_needed= ALTER_ACL;
/*
@@ -2365,7 +2369,7 @@ end_with_restore_list:
if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
{
- end_DDL();
+ DDL_blocker->end_DDL();
goto error;
}
/*
@@ -2386,7 +2390,7 @@ end_with_restore_list:
(TABLE_LIST *)
create_info.merge_list.first))
{
- end_DDL();
+ DDL_blocker->end_DDL();
goto error; /* purecov: inspected */
}
if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
@@ -2401,7 +2405,7 @@ end_with_restore_list:
if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
UINT_MAX, 0))
{
- end_DDL();
+ DDL_blocker->end_DDL();
goto error;
}
}
@@ -2422,7 +2426,7 @@ end_with_restore_list:
!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
{
res= 1;
- end_DDL();
+ DDL_blocker->end_DDL();
break;
}
@@ -2434,7 +2438,7 @@ end_with_restore_list:
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
lex->ignore);
- end_DDL();
+ DDL_blocker->end_DDL();
break;
}
case SQLCOM_RENAME_TABLE:
@@ -2463,13 +2467,13 @@ end_with_restore_list:
goto error;
}
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
{
- end_DDL();
+ DDL_blocker->end_DDL();
goto error;
}
- end_DDL();
+ DDL_blocker->end_DDL();
break;
}
#ifndef EMBEDDED_LIBRARY
@@ -2519,9 +2523,9 @@ end_with_restore_list:
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
res= mysql_repair_table(thd, first_table, &lex->check_opt);
- end_DDL();
+ DDL_blocker->end_DDL();
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
@@ -2571,11 +2575,11 @@ end_with_restore_list:
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
mysql_recreate_table(thd, first_table) :
mysql_optimize_table(thd, first_table, &lex->check_opt);
- end_DDL();
+ DDL_blocker->end_DDL();
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
@@ -2818,9 +2822,9 @@ end_with_restore_list:
goto error;
}
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
res= mysql_truncate(thd, first_table, 0);
- end_DDL();
+ DDL_blocker->end_DDL();
break;
case SQLCOM_DELETE:
@@ -2927,11 +2931,11 @@ end_with_restore_list:
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
thd->options|= OPTION_KEEP_LOG;
}
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
/* DDL and binlog write order protected by LOCK_open */
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
lex->drop_temporary);
- end_DDL();
+ DDL_blocker->end_DDL();
}
break;
case SQLCOM_SHOW_PROCESSLIST:
@@ -3162,10 +3166,10 @@ end_with_restore_list:
if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
is_schema_db(lex->name.str)))
break;
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
lex->name.str), &create_info, 0);
- end_DDL();
+ DDL_blocker->end_DDL();
break;
}
case SQLCOM_DROP_DB:
@@ -3205,9 +3209,9 @@ end_with_restore_list:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
- end_DDL();
+ DDL_blocker->end_DDL();
break;
}
case SQLCOM_ALTER_DB_UPGRADE:
@@ -3248,9 +3252,9 @@ end_with_restore_list:
goto error;
}
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
res= mysql_upgrade_db(thd, db);
- end_DDL();
+ DDL_blocker->end_DDL();
if (!res)
send_ok(thd);
break;
@@ -3288,9 +3292,9 @@ end_with_restore_list:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- check_DDL_blocker(thd);
+ DDL_blocker->check_DDL_blocker(thd);
res= mysql_alter_db(thd, db->str, &create_info);
- end_DDL();
+ DDL_blocker->end_DDL();
break;
}
case SQLCOM_SHOW_CREATE_DB: