List:Commits« Previous MessageNext Message »
From:Oystein Grovlen Date:August 8 2008 11:18am
Subject:bzr push into mysql-6.0-backup branch (oystein.grovlen:2678) Bug#36795
View as plain text  
 2678 Oystein Grovlen	2008-08-08
      Bug#36795 Concurrency issues when starting backups in parallel.
      
      Raise condition on Backup_restore_ctx::mem_alloc since it is static.
      The failing backup will set mem_alloc to null when terminating.  The
      next time the running backup wants to allocate memory, an assert will
      fail.
      
      Makes mem_alloc non-static.  That way, concurrent backups will not
      interfere.  This requires that it is possible to bstream_alloc to find
      the right Backup_restore_ctx to use.  Fixes that by changing the
      static is_running flag to a static pointer, current_op, to the Backup_restore_ctx
      of the currently running backup.  If the pointer is null, it means
      that no backup is currently running.
added:
  mysql-test/r/backup_concurrent.result
  mysql-test/t/backup_concurrent.test
modified:
  mysql-test/lib/mtr_report.pl
  sql/backup/backup_kernel.h
  sql/backup/kernel.cc

=== modified file 'mysql-test/lib/mtr_report.pl'

=== modified file 'mysql-test/lib/mtr_report.pl'
--- a/mysql-test/lib/mtr_report.pl	2008-08-05 08:04:30 +0000
+++ b/mysql-test/lib/mtr_report.pl	2008-08-08 11:17:37 +0000
@@ -334,6 +334,12 @@
 		  /Backup:/ or /Restore:/ or /Can't open the online backup progress tables/
 		) or
                 
+		# backup_concurrent performs a backup that should fail
+		($testname eq 'main.backup_concurrent') and
+		(
+		  /Can't execute this command because another BACKUP\/RESTORE operation is in progress/
+		) or
+                
 		# The tablespace test triggers error below on purpose
 		($testname eq 'main.backup_tablespace') and
 		(

=== added file 'mysql-test/r/backup_concurrent.result'
--- a/mysql-test/r/backup_concurrent.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/backup_concurrent.result	2008-08-08 11:17:37 +0000
@@ -0,0 +1,75 @@
+SET DEBUG_SYNC= 'reset';
+DROP DATABASE IF EXISTS backup_concurrent;
+CREATE DATABASE backup_concurrent;
+USE backup_concurrent;
+Creating Table
+CREATE TABLE t (
+t1 INTEGER NOT NULL,
+t2 CHAR(36),
+PRIMARY KEY (t1)
+);
+---------------------------------------------------
+Testing starting new backup while backup is ongoing
+---------------------------------------------------
+Starting first backup
+SET DEBUG_SYNC= 'after_backup_start_backup SIGNAL running WAIT_FOR backup';
+BACKUP DATABASE backup_concurrent TO 'backup1';
+Waiting for first backup to get going
+SET DEBUG_SYNC= 'now WAIT_FOR running';
+Starting second backup in another connection.  
+(Should fail because another backup is running.)
+BACKUP DATABASE backup_concurrent TO 'backup2';
+ERROR HY000: Can't execute this command because another BACKUP/RESTORE operation is in progress
+Insert Data
+INSERT INTO t VALUES (1, 'test');
+Wait for first backup to complete
+SET DEBUG_SYNC= 'now SIGNAL backup';
+backup_id
+#
+---------------------------------------------------
+Testing starting restore while backup is ongoing
+---------------------------------------------------
+Starting backup
+SET DEBUG_SYNC= 'after_backup_start_backup SIGNAL running WAIT_FOR backup';
+BACKUP DATABASE backup_concurrent TO 'backup3';
+Waiting for backup to get going
+SET DEBUG_SYNC= 'now WAIT_FOR running';
+Starting restore in another connection.  
+(Should fail because another backup is running.)
+RESTORE FROM 'backup1';
+ERROR HY000: Can't execute this command because another BACKUP/RESTORE operation is in progress
+Insert Data
+INSERT INTO t VALUES (2, 'test');
+Wait for backup to complete
+SET DEBUG_SYNC= 'now SIGNAL backup';
+backup_id
+#
+---------------------------------------------------
+Testing starting backup/restore restore is ongoing
+---------------------------------------------------
+Starting restore
+SET DEBUG_SYNC= 'after_backup_start_restore SIGNAL running WAIT_FOR restore';
+RESTORE FROM 'backup1';
+Waiting for restore to get going
+SET DEBUG_SYNC= 'now WAIT_FOR running';
+Starting backup in another connection.  
+(Should fail because restore is running.)
+BACKUP DATABASE backup_concurrent TO 'backup4';
+ERROR HY000: Can't execute this command because another BACKUP/RESTORE operation is in progress
+Insert Data
+INSERT INTO t VALUES (3, 'test');
+Starting a new restore in another connection.  
+(Should fail because another restore is running.)
+RESTORE FROM 'backup3';
+ERROR HY000: Can't execute this command because another BACKUP/RESTORE operation is in progress
+Insert Data
+INSERT INTO t VALUES (4, 'test');
+Wait for backup to complete
+SET DEBUG_SYNC= 'now SIGNAL restore';
+backup_id
+#
+
+Test completed. Cleaning up.
+
+DROP DATABASE backup_concurrent;
+SET DEBUG_SYNC= 'reset';

=== added file 'mysql-test/t/backup_concurrent.test'
--- a/mysql-test/t/backup_concurrent.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/backup_concurrent.test	2008-08-08 11:17:37 +0000
@@ -0,0 +1,121 @@
+###########################################################################
+# Author: Oystein Grovlen
+# Date: 2008-07-31
+# Purpose: To test starting backups/retore in parallel
+###############################################################################
+--source include/not_embedded.inc
+--source include/have_debug_sync.inc
+
+#Create Database and object view for this test.
+
+--disable_warnings
+SET DEBUG_SYNC= 'reset';
+DROP DATABASE IF EXISTS backup_concurrent;
+--enable_warnings
+
+CREATE DATABASE backup_concurrent;
+USE backup_concurrent;
+
+#Create table
+
+--echo Creating Table
+CREATE TABLE t (
+t1 INTEGER NOT NULL,
+t2 CHAR(36),
+PRIMARY KEY (t1)
+);
+
+--echo ---------------------------------------------------
+--echo Testing starting new backup while backup is ongoing
+--echo ---------------------------------------------------
+--echo Starting first backup
+connect (backup,localhost,root,,);
+SET DEBUG_SYNC= 'after_backup_start_backup SIGNAL running WAIT_FOR backup';
+send BACKUP DATABASE backup_concurrent TO 'backup1';
+
+connection default;
+--echo Waiting for first backup to get going
+SET DEBUG_SYNC= 'now WAIT_FOR running';
+--echo Starting second backup in another connection.  
+--echo (Should fail because another backup is running.)
+--error ER_BACKUP_RUNNING
+BACKUP DATABASE backup_concurrent TO 'backup2';
+
+--echo Insert Data
+INSERT INTO t VALUES (1, 'test');
+
+--echo Wait for first backup to complete
+SET DEBUG_SYNC= 'now SIGNAL backup';
+connection backup;
+replace_column 1 #;
+reap;
+
+--echo ---------------------------------------------------
+--echo Testing starting restore while backup is ongoing
+--echo ---------------------------------------------------
+--echo Starting backup
+SET DEBUG_SYNC= 'after_backup_start_backup SIGNAL running WAIT_FOR backup';
+send BACKUP DATABASE backup_concurrent TO 'backup3';
+
+connection default;
+--echo Waiting for backup to get going
+SET DEBUG_SYNC= 'now WAIT_FOR running';
+--echo Starting restore in another connection.  
+--echo (Should fail because another backup is running.)
+--error ER_BACKUP_RUNNING
+RESTORE FROM 'backup1';
+
+--echo Insert Data
+INSERT INTO t VALUES (2, 'test');
+
+--echo Wait for backup to complete
+SET DEBUG_SYNC= 'now SIGNAL backup';
+connection backup;
+replace_column 1 #;
+reap;
+
+--echo ---------------------------------------------------
+--echo Testing starting backup/restore restore is ongoing
+--echo ---------------------------------------------------
+--echo Starting restore
+SET DEBUG_SYNC= 'after_backup_start_restore SIGNAL running WAIT_FOR restore';
+send RESTORE FROM 'backup1';
+
+connection default;
+--echo Waiting for restore to get going
+SET DEBUG_SYNC= 'now WAIT_FOR running';
+
+--echo Starting backup in another connection.  
+--echo (Should fail because restore is running.)
+--error ER_BACKUP_RUNNING
+BACKUP DATABASE backup_concurrent TO 'backup4';
+
+--echo Insert Data
+INSERT INTO t VALUES (3, 'test');
+
+--echo Starting a new restore in another connection.  
+--echo (Should fail because another restore is running.)
+--error ER_BACKUP_RUNNING
+RESTORE FROM 'backup3';
+
+--echo Insert Data
+INSERT INTO t VALUES (4, 'test');
+
+--echo Wait for backup to complete
+SET DEBUG_SYNC= 'now SIGNAL restore';
+connection backup;
+replace_column 1 #;
+reap;
+
+
+# Test cleanup section
+
+--echo
+--echo Test completed. Cleaning up.
+--echo
+
+DROP DATABASE backup_concurrent;
+SET DEBUG_SYNC= 'reset';
+--remove_file $MYSQLTEST_VARDIR/master-data/backup1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup3
+

=== modified file 'sql/backup/backup_kernel.h'
--- a/sql/backup/backup_kernel.h	2008-07-07 12:51:56 +0000
+++ b/sql/backup/backup_kernel.h	2008-08-08 11:17:37 +0000
@@ -79,9 +79,11 @@
 
  private:
 
-  /** Indicates if a backup/restore operation is in progress. */
-  static bool is_running;
-  static pthread_mutex_t  run_lock; ///< To guard @c is_running flag.
+  /** @c current_op points to the @c Backup_restore_ctx for the
+      ongoing backup/restore operation.  If pointer is null, no
+      operation is currently running. */
+  static Backup_restore_ctx *current_op;
+  static pthread_mutex_t  run_lock; ///< To guard @c current_op.
 
   /** 
     @brief State of a context object. 
@@ -109,7 +111,7 @@
   backup::Image_info *m_catalog;  ///< Pointer to the image catalogue object.
 
   /** Memory allocator for backup stream library. */
-  static backup::Mem_allocator *mem_alloc;
+  backup::Mem_allocator *mem_alloc;
 
   int prepare(LEX_STRING location);
   void disable_fkey_constraints();

=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc	2008-07-31 10:45:02 +0000
+++ b/sql/backup/kernel.cc	2008-08-08 11:17:37 +0000
@@ -344,15 +344,14 @@
 
 // static members
 
-bool Backup_restore_ctx::is_running= FALSE;
+Backup_restore_ctx *Backup_restore_ctx::current_op= NULL;
 pthread_mutex_t Backup_restore_ctx::run_lock;
-backup::Mem_allocator *Backup_restore_ctx::mem_alloc= NULL;
 
 
 Backup_restore_ctx::Backup_restore_ctx(THD *thd)
  :Logger(thd), m_state(CREATED), m_thd_options(thd->options),
   m_error(0), m_path(NULL), m_remove_loc(FALSE), m_stream(NULL),
-  m_catalog(NULL), m_tables_locked(FALSE)
+  m_catalog(NULL), mem_alloc(NULL), m_tables_locked(FALSE)
 {
   /*
     Check for progress tables.
@@ -365,6 +364,7 @@
 {
   close();
   
+  delete mem_alloc;
   delete m_catalog;  
   delete m_stream;
 }
@@ -412,8 +412,8 @@
 
   pthread_mutex_lock(&run_lock);
 
-  if (!is_running)
-    is_running= TRUE;
+  if (!current_op)
+    current_op= this;
   else
     fatal_error(ER_BACKUP_RUNNING);
 
@@ -802,10 +802,11 @@
   delete mem_alloc;
   mem_alloc= NULL;
   
-  // deregister this operation
-
+  // deregister this operation if it was running
   pthread_mutex_lock(&run_lock);
-  is_running= FALSE;
+  if (current_op == this) {
+    current_op= NULL;
+  }
   pthread_mutex_unlock(&run_lock);
 
   /* 
@@ -1194,9 +1195,10 @@
 {
   using namespace backup;
 
-  DBUG_ASSERT(Backup_restore_ctx::mem_alloc);
+  DBUG_ASSERT(Backup_restore_ctx::current_op 
+              && Backup_restore_ctx::current_op->mem_alloc);
 
-  return (bstream_byte*)Backup_restore_ctx::mem_alloc->alloc(size);
+  return (bstream_byte*)Backup_restore_ctx::current_op->mem_alloc->alloc(size);
 }
 
 /**
@@ -1206,8 +1208,9 @@
 void bstream_free(bstream_byte *ptr)
 {
   using namespace backup;
-  if (Backup_restore_ctx::mem_alloc)
-    Backup_restore_ctx::mem_alloc->free(ptr);
+  if (Backup_restore_ctx::current_op 
+      && Backup_restore_ctx::current_op->mem_alloc)
+    Backup_restore_ctx::current_op->mem_alloc->free(ptr);
 }
 
 /**

Thread
bzr push into mysql-6.0-backup branch (oystein.grovlen:2678) Bug#36795Oystein Grovlen8 Aug