List:Commits« Previous MessageNext Message »
From:cbell Date:November 1 2007 8:12pm
Subject:bk commit into 5.2 tree (cbell:1.2610)
View as plain text  
Below is the list of changes that have just been committed into a local
5.2 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-11-01 15:11:55-04:00, cbell@mysql_cab_desk. +5 -0
  WL#4062 : Online Backup: Metadata freeze
  
  This patch implements the first iteration of the metadata freeze (hence
  DDL blocker) for the online backup project. It uses a normal pthread
  condition variable loop to block all DDL operations while a backup is
  running and another to block a backup if any DDL operations are running.
  
  Note: This patch requires the patch for WL#3324 from 1 November.

  mysql-test/r/backup_ddl_blocker.result@stripped, 2007-11-01 15:11:45-04:00,
cbell@mysql_cab_desk. +227 -0
    WL#4062 : Online Backup: Metadata freeze
    
    New result file.

  mysql-test/r/backup_ddl_blocker.result@stripped, 2007-11-01 15:11:45-04:00,
cbell@mysql_cab_desk. +0 -0

  mysql-test/t/backup_ddl_blocker.test@stripped, 2007-11-01 15:11:46-04:00,
cbell@mysql_cab_desk. +432 -0
    WL#4062 : Online Backup: Metadata freeze
    
    This adds a test for the DDL blocker.

  mysql-test/t/backup_ddl_blocker.test@stripped, 2007-11-01 15:11:46-04:00,
cbell@mysql_cab_desk. +0 -0

  sql/backup/sql_backup.cc@stripped, 2007-11-01 15:11:44-04:00, cbell@mysql_cab_desk. +86 -5
    WL#4062 : Online Backup: Metadata freeze
    
    This patch adds the methods for checking if DDL operations are running. If there are, 
    the backup process is blocked until the DDL operations are complete.

  sql/mysqld.cc@stripped, 2007-11-01 15:11:43-04:00, cbell@mysql_cab_desk. +15 -0
    WL#4062 : Online Backup: Metadata freeze
    
    This patch adds the mutex and condition variables for the DDL blocker.

  sql/sql_parse.cc@stripped, 2007-11-01 15:11:44-04:00, cbell@mysql_cab_desk. +83 -1
    WL#4062 : Online Backup: Metadata freeze
    
    This patch adds the methods for checking the DDL blocker and blocking DDL operations
    while the backup process is running.

diff -Nrup a/mysql-test/r/backup_ddl_blocker.result
b/mysql-test/r/backup_ddl_blocker.result
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/r/backup_ddl_blocker.result	2007-11-01 15:11:45 -04:00
@@ -0,0 +1,227 @@
+DROP DATABASE IF EXISTS bup_ddl_blocker;
+CREATE DATABASE bup_ddl_blocker;
+
+Starting Test 1
+
+DROP TABLE IF EXISTS test.t1, test.t3, test.t4;
+con1: Creating tables
+CREATE TABLE bup_ddl_blocker.t2 (col_a CHAR(40)) ENGINE=MYISAM;
+CREATE TABLE test.t3 (col_a CHAR(40)) ENGINE=CSV;
+CREATE TABLE test.t4 (col_a CHAR(40)) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker.t5 (col_a CHAR(40)) ENGINE=MYISAM;
+con1: Loading data
+INSERT INTO bup_ddl_blocker.t2 VALUES ("01 Some data to test");
+INSERT INTO bup_ddl_blocker.t2 VALUES ("02 Some data to test");
+INSERT INTO bup_ddl_blocker.t2 VALUES ("03 Some data to test");
+INSERT INTO test.t3 VALUES ("01 Some data to test");
+INSERT INTO test.t3 VALUES ("02 Some data to test");
+INSERT INTO test.t3 VALUES ("03 Some data to test");
+INSERT INTO test.t4 VALUES ("01 Some data to test");
+INSERT INTO test.t4 VALUES ("02 Some data to test");
+INSERT INTO test.t4 VALUES ("03 Some data to test");
+INSERT INTO bup_ddl_blocker.t5 VALUES ("01 Some data to test");
+INSERT INTO bup_ddl_blocker.t5 VALUES ("02 Some data to test");
+INSERT INTO bup_ddl_blocker.t5 VALUES ("03 Some data to test");
+con1: Show that the new data doesn't exist before backup.
+SELECT * FROM bup_ddl_blocker.t2;
+col_a
+01 Some data to test
+02 Some data to test
+03 Some data to test
+SELECT * FROM test.t3;
+col_a
+01 Some data to test
+02 Some data to test
+03 Some data to test
+SELECT * FROM test.t4;
+col_a
+01 Some data to test
+02 Some data to test
+03 Some data to test
+SELECT * FROM bup_ddl_blocker.t5;
+col_a
+01 Some data to test
+02 Some data to test
+03 Some data to test
+con7: 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 TABLE test.t1 (col_a CHAR(40)) ENGINE=INNODB;
+con3: Get a DDL going and stop in the middle
+ALTER TABLE bup_ddl_blocker.t2 ADD COLUMN col_b int;
+con4: Get a DDL going and stop in the middle
+DROP TABLE test.t3;
+con5: Get a DDL going and stop in the middle
+RENAME TABLE test.t4 TO test.t41;
+con1: Backing up database -- will block with lock
+BACKUP DATABASE bup_ddl_blocker TO "bup_ddl_blocker.bak";
+con7: Checking locks
+con7: Getting lock on DDL blocker.
+SELECT get_lock("DDL_blocked", 0);
+get_lock("DDL_blocked", 0)
+1
+con6: Try a DDL but it is blocked by backup -- will not be in backup
+ALTER TABLE bup_ddl_blocker.t5 ADD COLUMN col_b int;
+con7: Checking locks
+con7: Releasing lock
+SELECT release_lock("DDL_blocked");
+release_lock("DDL_blocked")
+1
+con2: Completing DDL
+con3: Completing DDL
+con4: Completing DDL
+con5: Completing DDL
+con6: Completing DDL
+Backup Summary
+ header     =       29 bytes
+ meta-data  =      222 bytes
+ data       =      288 bytes
+              --------------
+ total             539 bytes
+con1: Showing columns after updates and backup
+DESCRIBE test.t1;
+Field	Type	Null	Key	Default	Extra
+col_a	char(40)	YES		NULL	
+DESCRIBE bup_ddl_blocker.t2;
+Field	Type	Null	Key	Default	Extra
+col_a	char(40)	YES		NULL	
+col_b	int(11)	YES		NULL	
+DESCRIBE test.t3;
+ERROR 42S02: Table 'test.t3' doesn't exist
+DESCRIBE test.t41;
+Field	Type	Null	Key	Default	Extra
+col_a	char(40)	YES		NULL	
+DESCRIBE bup_ddl_blocker.t5;
+Field	Type	Null	Key	Default	Extra
+col_a	char(40)	YES		NULL	
+col_b	int(11)	YES		NULL	
+con1: Dropping the database tables
+DROP TABLE bup_ddl_blocker.t2, bup_ddl_blocker.t5;
+con1: Restoring the database
+RESTORE FROM "bup_ddl_blocker.bak";
+Restore Summary
+ header     =       29 bytes
+ meta-data  =      222 bytes
+ data       =      288 bytes
+              --------------
+ total             539 bytes
+
+Verifying test 1 results:
+
+T1 should have the changes after backup - count(*) = 1
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test';
+count(*)
+1
+T2 should the changes after backup - count(*) = 2
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't2' AND TABLE_SCHEMA = 'bup_ddl_blocker';
+count(*)
+2
+T3 should have the changes after backup - count(*) = 0
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't3' AND TABLE_SCHEMA = 'test';
+count(*)
+0
+T4 should have the changes after backup - count(*) = 1
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't41' AND TABLE_SCHEMA = 'test';
+count(*)
+1
+T5 should have the changes after backup - count(*) = 1
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't5' AND TABLE_SCHEMA = 'bup_ddl_blocker';
+count(*)
+1
+con1: Cleanup
+DROP TABLE test.t1, bup_ddl_blocker.t2,
+test.t41, bup_ddl_blocker.t5;
+
+Starting Test 2
+
+DROP TABLE IF EXISTS test.t2;
+DROP TABLE IF EXISTS bup_ddl_blocker.t1, bup_ddl_blocker.t3;
+con1: Creating tables
+CREATE TABLE bup_ddl_blocker.t1 (col_a CHAR(40)) ENGINE=INNODB;
+CREATE TABLE test.t2 (col_a CHAR(40)) ENGINE=MYISAM;
+CREATE TABLE bup_ddl_blocker.t3 (col_a CHAR(40)) ENGINE=CSV;
+con1: Loading data
+INSERT INTO bup_ddl_blocker.t1 VALUES ("01 Some data to test");
+INSERT INTO bup_ddl_blocker.t1 VALUES ("02 Some data to test");
+INSERT INTO bup_ddl_blocker.t1 VALUES ("03 Some data to test");
+INSERT INTO test.t2 VALUES ("01 Some data to test");
+INSERT INTO test.t2 VALUES ("02 Some data to test");
+INSERT INTO test.t2 VALUES ("03 Some data to test");
+INSERT INTO bup_ddl_blocker.t3 VALUES ("01 Some data to test");
+INSERT INTO bup_ddl_blocker.t3 VALUES ("02 Some data to test");
+INSERT INTO bup_ddl_blocker.t3 VALUES ("03 Some data to test");
+con1: Show that the new data doesn't exist before backup.
+SELECT * FROM bup_ddl_blocker.t1;
+col_a
+01 Some data to test
+02 Some data to test
+03 Some data to test
+SELECT * FROM test.t2;
+col_a
+01 Some data to test
+02 Some data to test
+03 Some data to test
+SELECT * FROM bup_ddl_blocker.t3;
+col_a
+01 Some data to test
+02 Some data to test
+03 Some data to test
+con7: Getting lock on DDL in progress.
+SELECT get_lock("DDL_blocked", 0);
+get_lock("DDL_blocked", 0)
+1
+con2: Get a DDL going and stop in the middle
+ALTER TABLE bup_ddl_blocker.t1 ADD COLUMN col_b int;
+con3: Get a DDL going and stop in the middle
+ALTER TABLE test.t2 ADD COLUMN col_b int;
+con4: Get a DDL going and stop in the middle
+ALTER TABLE bup_ddl_blocker.t3 ADD COLUMN col_b int;
+con7: Checking locks
+con7: Releasing lock
+SELECT release_lock("DDL_blocked");
+release_lock("DDL_blocked")
+1
+con2: Completing DDL
+con3: Completing DDL
+con4: Completing DDL
+con1: Showing columns after updates and backup
+DESCRIBE bup_ddl_blocker.t1;
+Field	Type	Null	Key	Default	Extra
+col_a	char(40)	YES		NULL	
+col_b	int(11)	YES		NULL	
+DESCRIBE test.t2;
+Field	Type	Null	Key	Default	Extra
+col_a	char(40)	YES		NULL	
+col_b	int(11)	YES		NULL	
+DESCRIBE bup_ddl_blocker.t3;
+Field	Type	Null	Key	Default	Extra
+col_a	char(40)	YES		NULL	
+col_b	int(11)	YES		NULL	
+
+Verifying test 2 results:
+
+T1 should have the changes after backup - count(*) = 2
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'bup_ddl_blocker';
+count(*)
+2
+T2 should the changes after backup - count(*) = 2
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't2' AND TABLE_SCHEMA = 'test';
+count(*)
+2
+T3 should not have the changes after backup - count(*) = 2
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't3' AND TABLE_SCHEMA = 'bup_ddl_blocker';
+count(*)
+2
+con1: Cleanup
+DROP DATABASE bup_ddl_blocker;
+DROP TABLE test.t2;
diff -Nrup a/mysql-test/t/backup_ddl_blocker.test b/mysql-test/t/backup_ddl_blocker.test
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/backup_ddl_blocker.test	2007-11-01 15:11:46 -04:00
@@ -0,0 +1,432 @@
+#
+# This test is for the DDL blocker
+# The goals of the test should be to ensure the following assumptions for
+# the behaviour of the DDL blocker hold true.
+#
+# a) DDL in progress are not blocked 
+# b) DDL that are running are allowed to complete and backup blocks
+# c) backup blocks all DDL even if not part of backup
+# d) DDL operations do not block each other
+#
+# The results of the backup should show (based on statements above):
+#
+# a) Test result for this assumption: Included in backup
+# b) Test result for this assumption: Included in backup
+# c) Test result for this assumption: Not included in backup
+#
+# The test shall run two sets of data definition statements. 
+#
+# 1) test DDL in progress that block backup and while the backup in progress
+#    check that DDLs that start after the backup are blocked
+# 2) DDL do not block each other
+#
+# TODO : Add a native driver to the test when one becomes available
+#
+
+--source include/have_innodb.inc
+--source include/have_debug.inc
+
+--disable_warnings
+DROP DATABASE IF EXISTS bup_ddl_blocker;
+--enable_warnings
+
+CREATE DATABASE bup_ddl_blocker;
+
+#
+# Connections used in this test
+#
+# con1 - used to create data, load data, and run the backup 
+# con2 - used for CREATE TABLE statements
+# con3 - used for ALTER TABLE statements
+# con4 - used for DROP TABLE statements
+# con5 - used for RENAME TABLE statements
+# con6 - used for ALTER TABLE statements after backup starts in test #1 
+#        and before backup starts in test #2
+# con7 - used for setting and releasing breakpoints
+#
+
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+connect (con3,localhost,root,,);
+connect (con4,localhost,root,,);
+connect (con5,localhost,root,,);
+connect (con6,localhost,root,,);
+connect (con7,localhost,root,,);
+
+connection con1;
+
+#
+# Test 1 - Test DDL in progress that block backup and while the backup in progress
+#          check that DDLs that start after the backup are blocked
+#
+
+--echo 
+--echo Starting Test 1
+--echo 
+
+#
+# Test 1 sequence diagram (not UML)
+#
+#   con1     con2     con3     con4     con5     con6       con7
+#  (setup)    |        |        |        |        |          |
+#     |       |        |        |        |        |          |
+#     |       |        |        |        |        | lock("DDL_in_progress");
+#     |       |        |        |        |        |   <wait for locks>
+#     |   CREATE a.t1  |        |        |        |          |
+#     |       |   ALTER b.t2    |        |        |          |
+#     |       |        |    DROP a.t3    |        |          |
+#     |       |        |        |   RENAME a.t4   |          |
+# BACKUP b    |        |        |        |        |          |
+#     |       |        |        |        |        | lock("DDL_blocked");
+#     |     <...>    <...>    <...>    <...>      |          |
+#     |       |        |        |        |    ALTER b.t5     |
+#     |       |        |        |        |        |   <wait for locks>
+#     |       |        |        |        |        |    <release locks>
+#   <...>     |        |        |        |      <...>        |
+# (results)   |        |        |        |        |          |
+#
+# Note: The resume of the commands is indicated with <...> and
+#       may occur in any order.
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS test.t1, test.t3, test.t4;
+--enable_warnings
+
+# Create transaction tables and load them with data.
+--echo con1: Creating tables
+CREATE TABLE bup_ddl_blocker.t2 (col_a CHAR(40)) ENGINE=MYISAM;
+CREATE TABLE test.t3 (col_a CHAR(40)) ENGINE=CSV;
+CREATE TABLE test.t4 (col_a CHAR(40)) ENGINE=INNODB;
+CREATE TABLE bup_ddl_blocker.t5 (col_a CHAR(40)) ENGINE=MYISAM;
+
+--echo con1: Loading data
+INSERT INTO bup_ddl_blocker.t2 VALUES ("01 Some data to test");
+INSERT INTO bup_ddl_blocker.t2 VALUES ("02 Some data to test");
+INSERT INTO bup_ddl_blocker.t2 VALUES ("03 Some data to test");
+
+INSERT INTO test.t3 VALUES ("01 Some data to test");
+INSERT INTO test.t3 VALUES ("02 Some data to test");
+INSERT INTO test.t3 VALUES ("03 Some data to test");
+
+INSERT INTO test.t4 VALUES ("01 Some data to test");
+INSERT INTO test.t4 VALUES ("02 Some data to test");
+INSERT INTO test.t4 VALUES ("03 Some data to test");
+
+INSERT INTO bup_ddl_blocker.t5 VALUES ("01 Some data to test");
+INSERT INTO bup_ddl_blocker.t5 VALUES ("02 Some data to test");
+INSERT INTO bup_ddl_blocker.t5 VALUES ("03 Some data to test");
+
+--echo con1: Show that the new data doesn't exist before backup.
+SELECT * FROM bup_ddl_blocker.t2;
+SELECT * FROM test.t3;
+SELECT * FROM test.t4;
+SELECT * FROM bup_ddl_blocker.t5;
+
+connection con7;
+
+# Set the breakpoint for DDL in progress.
+--echo con7: 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 TABLE test.t1 (col_a CHAR(40)) ENGINE=INNODB;
+
+connection con3;
+
+--echo con3: Get a DDL going and stop in the middle
+send ALTER TABLE bup_ddl_blocker.t2 ADD COLUMN col_b int;
+
+connection con4;
+
+--echo con4: Get a DDL going and stop in the middle
+send DROP TABLE test.t3;
+
+connection con5;
+
+--echo con5: Get a DDL going and stop in the middle
+send RENAME TABLE test.t4 TO test.t41;
+
+# 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 TO "bup_ddl_blocker.bak";
+
+connection con7;
+
+# Wait for lock to be acquired and execution to reach breakpoint
+--echo con7: 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
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+                      FROM INFORMATION_SCHEMA.PROCESSLIST
+                      WHERE info LIKE "CREATE TABLE test.t1%";
+--source include/wait_condition.inc
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+                      FROM INFORMATION_SCHEMA.PROCESSLIST
+                      WHERE info LIKE "ALTER TABLE bup_ddl_blocker.t2%";
+--source include/wait_condition.inc
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+                      FROM INFORMATION_SCHEMA.PROCESSLIST
+                      WHERE info LIKE "DROP TABLE test.t3%";
+--source include/wait_condition.inc
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_in_progress"
+                      FROM INFORMATION_SCHEMA.PROCESSLIST
+                      WHERE info LIKE "RENAME TABLE test.t4%";
+--source include/wait_condition.inc
+
+# Now set the breakpoint for DDL blocker.
+# This releases lock on DDL_in_progress stopping all DDLs.
+--echo con7: Getting lock on DDL blocker.
+SELECT get_lock("DDL_blocked", 0);
+
+connection con6;
+
+--echo con6: Try a DDL but it is blocked by backup -- will not be in backup
+send ALTER TABLE bup_ddl_blocker.t5 ADD COLUMN col_b int;
+
+connection con7;
+
+--echo con7: 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
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_blocked"
+                      FROM INFORMATION_SCHEMA.PROCESSLIST
+                      WHERE info LIKE "ALTER TABLE bup_ddl_blocker.t5%";
+--source include/wait_condition.inc
+
+--echo con7: 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;
+
+connection con6;
+--echo con6: Completing DDL
+reap;
+
+# Reconnect to con1 and let backup finish.
+
+connection con1;
+reap;
+
+# Now restore the database and then check to make sure the new column
+# were included in the backup.
+
+# Show that all changes got applied.
+# t3 should not exist (dropped)
+--echo con1: Showing columns after updates and backup
+DESCRIBE test.t1;
+DESCRIBE bup_ddl_blocker.t2;
+--error 1146 
+DESCRIBE test.t3;
+DESCRIBE test.t41;
+DESCRIBE bup_ddl_blocker.t5;
+
+--echo con1: Dropping the database tables
+DROP TABLE bup_ddl_blocker.t2, bup_ddl_blocker.t5;
+
+--echo con1: Restoring the database
+RESTORE FROM "bup_ddl_blocker.bak";
+
+--echo
+--echo Verifying test 1 results:
+--echo
+
+--echo T1 should have the changes after backup - count(*) = 1
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test';
+
+--echo T2 should the changes after backup - count(*) = 2
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't2' AND TABLE_SCHEMA = 'bup_ddl_blocker';
+
+--echo T3 should have the changes after backup - count(*) = 0
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't3' AND TABLE_SCHEMA = 'test';
+
+--echo T4 should have the changes after backup - count(*) = 1
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't41' AND TABLE_SCHEMA = 'test';
+
+--echo T5 should have the changes after backup - count(*) = 1
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't5' AND TABLE_SCHEMA = 'bup_ddl_blocker';
+
+--echo con1: Cleanup
+DROP TABLE test.t1, bup_ddl_blocker.t2,
+           test.t41, bup_ddl_blocker.t5;
+
+remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker.bak;
+
+#
+# Test 2 - Test DDL do not block each other
+#
+
+--echo 
+--echo Starting Test 2
+--echo 
+
+#
+# Test 2 sequence diagram (not UML)
+#
+#   con1     con2     con3     con4       con7
+#  (setup)    |        |        |          |
+#     |       |        |        |          |
+#     |   ALTER a.t1   |        |          |
+#     |       |   ALTER b.t2    |          |
+#     |       |        |    ALTER a.t3     |
+#     |       |        |        | lock("DDL_in_progress");
+#     |       |        |        |    <wait for locks>
+#     |       |        |        |    <release locks>
+#     |     <...>    <...>    <...>        |
+# (results)   |        |        |          | 
+#
+# Note: The resume of the commands is indicated with <...> and
+#       may occur in any order.
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS test.t2;
+DROP TABLE IF EXISTS bup_ddl_blocker.t1, bup_ddl_blocker.t3;
+--enable_warnings
+
+# Create transaction tables and load them with data.
+--echo con1: Creating tables
+CREATE TABLE bup_ddl_blocker.t1 (col_a CHAR(40)) ENGINE=INNODB;
+CREATE TABLE test.t2 (col_a CHAR(40)) ENGINE=MYISAM;
+CREATE TABLE bup_ddl_blocker.t3 (col_a CHAR(40)) ENGINE=CSV;
+
+--echo con1: Loading data
+INSERT INTO bup_ddl_blocker.t1 VALUES ("01 Some data to test");
+INSERT INTO bup_ddl_blocker.t1 VALUES ("02 Some data to test");
+INSERT INTO bup_ddl_blocker.t1 VALUES ("03 Some data to test");
+
+INSERT INTO test.t2 VALUES ("01 Some data to test");
+INSERT INTO test.t2 VALUES ("02 Some data to test");
+INSERT INTO test.t2 VALUES ("03 Some data to test");
+
+INSERT INTO bup_ddl_blocker.t3 VALUES ("01 Some data to test");
+INSERT INTO bup_ddl_blocker.t3 VALUES ("02 Some data to test");
+INSERT INTO bup_ddl_blocker.t3 VALUES ("03 Some data to test");
+
+--echo con1: Show that the new data doesn't exist before backup.
+SELECT * FROM bup_ddl_blocker.t1;
+SELECT * FROM test.t2;
+SELECT * FROM bup_ddl_blocker.t3;
+
+connection con7;
+
+# Set the breakpoint for DDL in progress.
+--echo con7: Getting lock on DDL in progress.
+SELECT get_lock("DDL_blocked", 0);
+
+connection con2;
+
+--echo con2: Get a DDL going and stop in the middle
+send ALTER TABLE bup_ddl_blocker.t1 ADD COLUMN col_b int;
+
+connection con3;
+
+--echo con3: Get a DDL going and stop in the middle
+send ALTER TABLE test.t2 ADD COLUMN col_b int;
+
+connection con4;
+
+--echo con4: Get a DDL going and stop in the middle
+send ALTER TABLE bup_ddl_blocker.t3 ADD COLUMN col_b int;
+
+connection con7;
+
+# Wait for lock to be acquired and execution to reach breakpoint
+--echo con7: Checking locks
+let $wait_condition = SELECT state = "debug_sync_point: DDL_blocked"
+                      FROM INFORMATION_SCHEMA.PROCESSLIST
+                      WHERE info LIKE "ALTER TABLE bup_ddl_blocker.t1%";
+--source include/wait_condition.inc
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_blocked"
+                      FROM INFORMATION_SCHEMA.PROCESSLIST
+                      WHERE info LIKE "ALTER TABLE test.t2%";
+--source include/wait_condition.inc
+
+let $wait_condition = SELECT state = "debug_sync_point: DDL_blocked"
+                      FROM INFORMATION_SCHEMA.PROCESSLIST
+                      WHERE info LIKE "ALTER TABLE bup_ddl_blocker.t3%";
+--source include/wait_condition.inc
+
+--echo con7: Releasing lock
+SELECT release_lock("DDL_blocked");
+
+# Reconnect to con2, con3, and con4 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;
+
+# Reconnect to con1 and show results
+
+connection con1;
+
+# Do selects to show that all changes got applied.
+--echo con1: Showing columns after updates and backup
+DESCRIBE bup_ddl_blocker.t1;
+DESCRIBE test.t2;
+DESCRIBE bup_ddl_blocker.t3;
+
+--echo
+--echo Verifying test 2 results:
+--echo
+
+--echo T1 should have the changes after backup - count(*) = 2
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'bup_ddl_blocker';
+
+--echo T2 should the changes after backup - count(*) = 2
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't2' AND TABLE_SCHEMA = 'test';
+
+--echo T3 should not have the changes after backup - count(*) = 2
+SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME = 't3' AND TABLE_SCHEMA = 'bup_ddl_blocker';
+
+--echo con1: Cleanup
+DROP DATABASE bup_ddl_blocker;
+DROP TABLE test.t2;
+
diff -Nrup a/sql/backup/sql_backup.cc b/sql/backup/sql_backup.cc
--- a/sql/backup/sql_backup.cc	2007-10-17 16:20:36 -04:00
+++ b/sql/backup/sql_backup.cc	2007-11-01 15:11:44 -04:00
@@ -31,6 +31,10 @@
 #include "be_default.h"
 #include "be_snapshot.h"
 
+extern void block_DDL(my_bool block);
+extern pthread_mutex_t THR_LOCK_DDL_blocker;
+extern pthread_cond_t COND_backup_blocked;
+
 namespace backup {
 
 // Helper functions
@@ -59,6 +63,51 @@ bool test_error_flag= FALSE;
 #endif
 }
 
+extern pthread_cond_t COND_backup_blocked;
+extern pthread_cond_t COND_DDL_blocker;
+extern my_bool backup_blocked_for_DDL;
+extern my_bool DDL_blocked;
+
+/*
+  @returns TRUE if ok to do backup (no DDL in progress) or FALSE if error.
+*/
+my_bool check_DDL_blocked(THD *thd)
+{
+  DBUG_ENTER("check_DDL_blocked()");
+  /*
+    Check the ddl blocker condition. Rest until ddl blocker is released.
+  */
+  pthread_mutex_lock(&THR_LOCK_DDL_blocker);
+  thd->enter_cond(&COND_backup_blocked, &THR_LOCK_DDL_blocker,
+                  "Online backup: Checking block on DDL changes");
+  while (backup_blocked_for_DDL)
+    pthread_cond_wait(&COND_backup_blocked, &THR_LOCK_DDL_blocker);
+  thd->exit_cond("Online backup: Ok to run operation - no DDL in progress");
+  DBUG_RETURN(!backup_blocked_for_DDL);
+}
+
+/**
+   block_DDL
+
+   This method blocks (freezes) or unblocks (unfreezes) all DDL operations by
+   turning on (block == TRUE) or off (block == FALSE) the DDL blocker condition
+   for the check_DDL_blocker() method.
+
+   If 
+*/
+void block_DDL(my_bool block)
+{
+  pthread_mutex_lock(&THR_LOCK_DDL_blocker);
+  /*
+    Tell the waiting DDL process that the backup is done and it can
+    proceed.
+  */
+  if (!block && DDL_blocked)
+    pthread_cond_broadcast(&COND_DDL_blocker);
+  DDL_blocked= block;
+  pthread_mutex_unlock(&THR_LOCK_DDL_blocker);
+}
+
 /**
   Call backup kernel API to execute backup related SQL statement.
 
@@ -118,7 +167,6 @@ execute_backup_command(THD *thd, LEX *le
       {
         info.report_error(backup::log_level::INFO,ER_BACKUP_RESTORE_START);
 
-        // TODO: freeze all DDL operations here
 
         info.save_errors();
         info.restore_all_dbs();
@@ -140,7 +188,6 @@ execute_backup_command(THD *thd, LEX *le
           send_summary(thd,info);
         }
 
-        // TODO: unfreeze DDL here
       }
     } // if (!stream)
 
@@ -176,8 +223,6 @@ execute_backup_command(THD *thd, LEX *le
 
       info.report_error(backup::log_level::INFO,ER_BACKUP_BACKUP_START);
 
-      // TODO: freeze all DDL operations here
-
       info.save_errors();
 
       if (lex->db_list.is_empty())
@@ -212,7 +257,6 @@ execute_backup_command(THD *thd, LEX *le
         send_summary(thd,info);
       }
 
-      // TODO: unfreeze DDL here
     } // if (!stream)
 
     goto finish_backup;
@@ -280,6 +324,18 @@ int mysql_backup(THD *thd,
 {
   DBUG_ENTER("mysql_backup");
 
+  BACKUP_SYNC("DDL_in_progress");
+  if (!check_DDL_blocked(thd))
+  {
+    //This is an error, abort.
+  }
+
+  /*
+    Freeze all DDL operations by turning on DDL blocker.
+  */
+  block_DDL(TRUE);
+  BACKUP_SYNC("DDL_blocked");
+
   // This function should not be called with invalid backup info.
   DBUG_ASSERT(info.is_valid());
 
@@ -309,10 +365,16 @@ int mysql_backup(THD *thd,
 
   info.total_size= s.bytes - start_bytes;
 
+  /*
+    Unfreeze all DDL operations by turning off DDL blocker.
+  */
+  block_DDL(FALSE);
+  BACKUP_SYNC("DDL_unblocked");
   DBUG_RETURN(0);
 
  error:
 
+  block_DDL(FALSE);
   DBUG_RETURN(backup::ERROR);
 }
 
@@ -1060,8 +1122,27 @@ int mysql_restore(THD *thd, backup::Rest
 
   DBUG_PRINT("restore",("Restoring table data"));
 
+  BACKUP_SYNC("DDL_in_progress");
+  if (!check_DDL_blocked(thd))
+  {
+    //This is an error, abort.
+  }
+
+  /*
+    Freeze all DDL operations by turning on DDL blocker.
+  */
+  block_DDL(TRUE);
+
   if (backup::restore_table_data(thd,info,s))
+  {
+    block_DDL(FALSE);
     DBUG_RETURN(backup::ERROR);
+  }
+
+  /*
+    Unfreeze all DDL operations by turning off DDL blocker.
+  */
+  block_DDL(FALSE);
 
   DBUG_PRINT("restore",("Done."));
 
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc	2007-10-17 09:57:33 -04:00
+++ b/sql/mysqld.cc	2007-11-01 15:11:43 -04:00
@@ -577,6 +577,15 @@ 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_cond_t COND_DDL_blocker;
+pthread_cond_t COND_backup_blocked;
+
 /*
   The below lock protects access to two global server variables:
   max_prepared_stmt_count and prepared_stmt_count. These variables
@@ -1335,6 +1344,9 @@ 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_cond_destroy(&COND_DDL_blocker);
+  (void) pthread_cond_destroy(&COND_backup_blocked);
   Events::destroy_mutexes();
 #ifdef HAVE_OPENSSL
   (void) pthread_mutex_destroy(&LOCK_des_key_file);
@@ -3074,6 +3086,9 @@ 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_cond_init(&COND_DDL_blocker, NULL);
+  (void) pthread_cond_init(&COND_backup_blocked, NULL);
 #ifdef HAVE_OPENSSL
   (void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
 #ifndef HAVE_YASSL
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc	2007-09-14 05:20:44 -04:00
+++ b/sql/sql_parse.cc	2007-11-01 15:11:44 -04:00
@@ -27,6 +27,7 @@
 #include "sp_cache.h"
 #include "events.h"
 #include "sql_trigger.h"
+#include "debug.h"
 
 /**
   @defgroup Runtime_Environment Runtime Environment
@@ -87,6 +88,52 @@ const char *xa_state_names[]={
   "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
 };
 
+extern pthread_mutex_t THR_LOCK_DDL_blocker; 
+extern pthread_cond_t COND_DDL_blocker;
+extern pthread_cond_t COND_backup_blocked;
+my_bool DDL_blocked= FALSE;
+my_bool backup_blocked_for_DDL= FALSE;
+
+/*
+  @returns TRUE if ok to do DDL or FALSE if error.
+*/
+my_bool check_DDL_blocker(THD *thd)
+{
+  DBUG_ENTER("check_DDL_blocker()");
+  /*
+    Check the ddl blocker condition. Rest until ddl blocker is released.
+  */
+  pthread_mutex_lock(&THR_LOCK_DDL_blocker);
+  backup_blocked_for_DDL= TRUE;
+  thd->enter_cond(&COND_DDL_blocker, &THR_LOCK_DDL_blocker,
+                  "DDL blocker: Checking block on DDL changes");
+  while (DDL_blocked)
+    pthread_cond_wait(&COND_DDL_blocker, &THR_LOCK_DDL_blocker);
+  backup_blocked_for_DDL= FALSE;
+  thd->exit_cond("DDL blocker: Ok to run DDL");
+  DBUG_RETURN(!DDL_blocked);
+}
+
+/**
+   block_backup_for_DDL
+
+   This method is used to indicate that a DDL operation is in progress. DDL
+   operations call this method once at the beginning setting the block to
+   TRUE and once after the DDL operation setting the block to FALSE.
+*/
+void block_backup_for_DDL(my_bool block)
+{
+  pthread_mutex_lock(&THR_LOCK_DDL_blocker);
+  /*
+    Tell the waiting backup process that the DDL is done and it can
+    proceed.
+  */
+  if (!block && backup_blocked_for_DDL)
+    pthread_cond_broadcast(&COND_backup_blocked);
+  backup_blocked_for_DDL= block;
+  pthread_mutex_unlock(&THR_LOCK_DDL_blocker);
+}
+
 
 static void unlock_locked_tables(THD *thd)
 {
@@ -2164,6 +2211,13 @@ mysql_execute_command(THD *thd)
     }
     else
     {
+      BACKUP_SYNC("DDL_blocked");
+      if (!check_DDL_blocker(thd))
+      {
+         // This is an error. The ddl blocker should return TRUE.
+      }
+      block_backup_for_DDL(TRUE);
+      BACKUP_SYNC("DDL_in_progress");
       /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
       if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
         thd->options|= OPTION_KEEP_LOG;
@@ -2177,6 +2231,7 @@ mysql_execute_command(THD *thd)
                                 create_table->table_name, &create_info,
                                 &alter_info, 0, 0);
       }
+      block_backup_for_DDL(FALSE);
       if (!res)
 	send_ok(thd);
     }
@@ -2331,6 +2386,13 @@ end_with_restore_list:
       }
 
       thd->enable_slow_log= opt_log_slow_admin_statements;
+      BACKUP_SYNC("DDL_blocked");
+      if (!check_DDL_blocker(thd))
+      {
+         // This is an error. The ddl blocker should return TRUE.
+      }
+      block_backup_for_DDL(TRUE);
+      BACKUP_SYNC("DDL_in_progress");
       res= mysql_alter_table(thd, select_lex->db, lex->name.str,
                              &create_info,
                              first_table,
@@ -2338,6 +2400,7 @@ end_with_restore_list:
                              select_lex->order_list.elements,
                              (ORDER *) select_lex->order_list.first,
                              lex->ignore);
+      block_backup_for_DDL(FALSE);
       break;
     }
   case SQLCOM_RENAME_TABLE:
@@ -2366,8 +2429,19 @@ end_with_restore_list:
         goto error;
     }
 
+      BACKUP_SYNC("DDL_blocked");
+      if (!check_DDL_blocker(thd))
+      {
+         // This is an error. The ddl blocker should return TRUE.
+      }
+      block_backup_for_DDL(TRUE);
+      BACKUP_SYNC("DDL_in_progress");
     if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
-      goto error;
+      {
+        block_backup_for_DDL(FALSE);
+        goto error;
+      }
+      block_backup_for_DDL(FALSE);
     break;
   }
 #ifndef EMBEDDED_LIBRARY
@@ -2811,9 +2885,17 @@ end_with_restore_list:
       /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
       thd->options|= OPTION_KEEP_LOG;
     }
+      BACKUP_SYNC("DDL_blocked");
+      if (!check_DDL_blocker(thd))
+      {
+         // This is an error. The ddl blocker should return TRUE.
+      }
+      block_backup_for_DDL(TRUE);
+      BACKUP_SYNC("DDL_in_progress");
     /* DDL and binlog write order protected by LOCK_open */
     res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
 			lex->drop_temporary);
+      block_backup_for_DDL(FALSE);
   }
   break;
   case SQLCOM_SHOW_PROCESSLIST:

Thread
bk commit into 5.2 tree (cbell:1.2610)cbell1 Nov