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#36795 | Oystein Grovlen | 8 Aug |