#At file:///ext/mysql/bzr/backup/bug40305/
2748 Rafal Somla 2009-01-08
Bug #40305 - Backup: Bad feedback when BACKUP/RESTORE operation aborted.
This patch refactors the code reporting termination of BACKUP/RESTORE statement.
After the changes "Backup/Restore completed" is shown only if operation has been
completed. In case of abnormal termination (error, interruption) a warning
"Operation aborted" or "Operation aborted - data might be corrupted" is logged.
The latter is in the case of RESTORE operation which has modified some data in
the server.
The main changes are:
- Function backup::Logger::report_stop() is replaced by 2 new functions:
report_completed() and report_aborted() to differentiate the feedback given in
the two situations.
- Make sure that a call to report_completed() or report_aborted() always matches
a previous call to report_start(). This is done in Backup_restore_ctx::close()
which is called from the destructor.
- Change the logic for removing backup file (in case BACKUP operation is not
completed). Before this was guarded by explicit m_remove_loc flag. Now we can
directly check if BACKUP operation has been completed successfully (i.e.
report_completed() was called) or not.
Note: the new functionality is covered by existing test cases.
modified:
mysql-test/lib/mtr_report.pl
mysql-test/suite/backup/r/backup_errors.result
mysql-test/suite/backup/r/backup_logs_purge.result
mysql-test/suite/backup/t/backup_errors.test
mysql-test/suite/backup/t/backup_logs_purge.test
sql/backup/backup_kernel.h
sql/backup/image_info.h
sql/backup/kernel.cc
sql/backup/logger.h
sql/backup/restore_info.h
sql/share/errmsg.txt
per-file messages:
mysql-test/lib/mtr_report.pl
Filter out the abort warnings.
mysql-test/suite/backup/r/backup_errors.result
Result change - now additional warning about statement interruption is pushed on
the error stack.
mysql-test/suite/backup/t/backup_errors.test
- Echo what is tested to improve readability of result file.
- Move repeated database test after the results of previous
test are examined.
mysql-test/suite/backup/t/backup_logs_purge.test
Update debug synchronization points - BACKUP/RESTORE must be stopped before
state change to "Completed" is reported in backup progress log. This state
change is reported by report_completed().
sql/backup/backup_kernel.h
- Document the states of Backup_restore_ctx class.
- Remove m_remove_loc member which is no longer used.
- Report the state change when moving to error state.
sql/backup/image_info.h
Make is_valid() method visible from base class Image_info.
sql/backup/kernel.cc
- Update Backup_restore_ctx::close() (which is called from Backup_restore_ctx
destructor) so that it calls either report_completed() or report_aborted() to
match the report_start() call made in Backuo_restor_ctx::prepare_for...()
method.
- Also, Backup_restore_ctx::close() moves the context to error state in case the
catalogue got corrupted. This writes an entry into backup logs.
- Change the logic for removing backup file: instead of using explicit
m_remove_loc flag, decide based on whether BACKUP operation has completed
successfully or not (as now this information is available).
- Call Backup_restore_ctx::close() in do_backup() and do_restore(), when
operation is completed - no need to wait any longer.
- Report data changes when objects are created in bcat_create_item() and
restore_triggers_and_events().
sql/backup/logger.h
Replace backup::Logger::report_stop() with two new methods: report_completed()
and report_aborted().
sql/backup/restore_info.h
Add flag for recording the fact that data has been modified during
restore operation.
sql/share/errmsg.txt
Add messages for reporting early termination of a statement.
=== modified file 'mysql-test/lib/mtr_report.pl'
--- a/mysql-test/lib/mtr_report.pl 2008-12-16 20:54:07 +0000
+++ b/mysql-test/lib/mtr_report.pl 2009-01-08 14:57:41 +0000
@@ -328,6 +328,9 @@ sub mtr_report_stats ($) {
/Slave: Can't drop database.* database doesn't exist/ or
/Slave SQL:.*(?:Error_code: \d+|Query:.*)/ or
+ # Ignore warnings issued when backup/restore operation is aborted.
+ /\[Warning\] (Backup|Restore): Operation aborted/ or
+
# backup_errors test is supposed to trigger lots of backup related errors
($testname eq 'backup.backup_errors') and
(
=== modified file 'mysql-test/suite/backup/r/backup_errors.result'
--- a/mysql-test/suite/backup/r/backup_errors.result 2009-01-06 09:53:50 +0000
+++ b/mysql-test/suite/backup/r/backup_errors.result 2009-01-08 14:57:41 +0000
@@ -1,5 +1,6 @@
DROP DATABASE IF EXISTS adb;
DROP DATABASE IF EXISTS bdb;
+# non-existent backup archive
RESTORE FROM 'test.bak';
ERROR HY000: File 'MYSQLTEST_VARDIR/master-data/test.bak' not found (Errcode: #)
Get last backup_id
@@ -20,11 +21,13 @@ error
CREATE DATABASE adb;
CREATE DATABASE bdb;
CREATE TABLE bdb.t1(a int) ENGINE=MEMORY;
+# invalid location
BACKUP DATABASE adb TO '';
ERROR HY000: Malformed file path ''
SHOW WARNINGS;
Level Code Message
Error # Malformed file path ''
+Warning # Operation aborted
Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE adb TO%";
@@ -40,23 +43,27 @@ starting
running
Malformed file path ''
error
+# don't overwrite existing files
BACKUP DATABASE adb TO "bdb/t1.frm";
ERROR HY000: Can't create/write to file 'MYSQLTEST_VARDIR/master-data/bdb/t1.frm' (Errcode: #)
SHOW WARNINGS;
Level Code Message
Error # Can't create/write to file 'MYSQLTEST_VARDIR/master-data/bdb/t1.frm' (Errcode: #)
Error # Can't write to backup location 'bdb/t1.frm'
+Warning # Operation aborted
BACKUP DATABASE adb TO "test.bak";
backup_id
#
SHOW WARNINGS;
Level Code Message
+# don't overwrite existing backup image
BACKUP DATABASE adb TO "test.bak";
ERROR HY000: Can't create/write to file 'MYSQLTEST_VARDIR/master-data/test.bak' (Errcode: #)
SHOW WARNINGS;
Level Code Message
Error # Can't create/write to file 'MYSQLTEST_VARDIR/master-data/test.bak' (Errcode: #)
Error # Can't write to backup location 'test.bak'
+Warning # Operation aborted
Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE adb TO%";
@@ -72,6 +79,7 @@ starting
running
Can't write to backup location 'test.bak'
error
+# non-existent database
DROP DATABASE IF EXISTS foo;
DROP DATABASE IF EXISTS bar;
BACKUP DATABASE foo TO 'test.bak';
@@ -79,13 +87,13 @@ ERROR 42000: Unknown database 'foo'
SHOW WARNINGS;
Level Code Message
Error # Unknown database 'foo'
+Warning # Operation aborted
BACKUP DATABASE test,foo,bdb,bar TO 'test.bak';
ERROR 42000: Unknown database 'foo,bar'
SHOW WARNINGS;
Level Code Message
Error # Unknown database 'foo,bar'
-BACKUP DATABASE foo,test,bar,foo TO 'test.bak';
-ERROR 42000: Not unique database: 'foo'
+Warning # Operation aborted
Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE test,foo,bdb,bar TO%";
@@ -101,6 +109,12 @@ starting
running
Unknown database 'foo,bar'
error
+# repeated database
+BACKUP DATABASE foo,test,bar,foo TO 'test.bak';
+ERROR 42000: Not unique database: 'foo'
+SHOW WARNINGS;
+Level Code Message
+Error # Not unique database: 'foo'
use adb;
create table t1 (a int);
create procedure p1() backup database test to 'test.bak';
@@ -131,6 +145,7 @@ ERROR HY000: Database 'mysql' cannot be
SHOW WARNINGS;
Level Code Message
Error # Database 'mysql' cannot be included in a backup
+Warning # Operation aborted
Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE mysql TO%";
@@ -152,6 +167,7 @@ ERROR HY000: Database 'information_schem
SHOW WARNINGS;
Level Code Message
Error # Database 'information_schema' cannot be included in a backup
+Warning # Operation aborted
Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE information_schema TO%";
@@ -173,6 +189,7 @@ ERROR HY000: Database 'mysql' cannot be
SHOW WARNINGS;
Level Code Message
Error # Database 'mysql' cannot be included in a backup
+Warning # Operation aborted
Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE mysql, information_schema TO%";
@@ -194,6 +211,7 @@ ERROR HY000: Database 'mysql' cannot be
SHOW WARNINGS;
Level Code Message
Error # Database 'mysql' cannot be included in a backup
+Warning # Operation aborted
Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE mysql, test TO%";
@@ -215,12 +233,14 @@ ERROR HY000: Database 'information_schem
SHOW WARNINGS;
Level Code Message
Error # Database 'information_schema' cannot be included in a backup
+Warning # Operation aborted
Backup of mysql, information_schema scenario 6
BACKUP DATABASE mysql, information_schema, test TO 't.bak';
ERROR HY000: Database 'mysql' cannot be included in a backup
SHOW WARNINGS;
Level Code Message
Error # Database 'mysql' cannot be included in a backup
+Warning # Operation aborted
Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE mysql, information_schema, test TO%";
@@ -393,6 +413,7 @@ SHOW WARNINGS;
Level Code Message
Error # Can't create/write to file 'MYSQLTEST_VARDIR/master-data/test.bak' (Errcode: #)
Error # Can't write to backup location 'test.bak'
+Warning # Operation aborted
# Test that there are no warnings after successful BACKUP
BACKUP DATABASE db1 TO 'newtest.bak';
@@ -408,6 +429,7 @@ SHOW WARNINGS;
Level Code Message
Error # Can't create/write to file 'MYSQLTEST_VARDIR/master-data/test.bak' (Errcode: #)
Error # Can't write to backup location 'test.bak'
+Warning # Operation aborted
# Test that there are no warnings after successful RESTORE
RESTORE FROM 'newtest.bak' OVERWRITE;
=== modified file 'mysql-test/suite/backup/r/backup_logs_purge.result'
--- a/mysql-test/suite/backup/r/backup_logs_purge.result 2008-11-17 09:57:51 +0000
+++ b/mysql-test/suite/backup/r/backup_logs_purge.result 2009-01-08 14:57:41 +0000
@@ -252,7 +252,7 @@ count(*)
24
SET SESSION debug="+d,set_backup_id";
con2: Activate sync points for the backup statement.
-SET DEBUG_SYNC= 'before_backup_done SIGNAL ready WAIT_FOR proceed';
+SET DEBUG_SYNC= 'before_backup_completed SIGNAL ready WAIT_FOR proceed';
BACKUP DATABASE backup_logs to 'backup5.bak';
con1: Wait for the backup to be ready.
SET DEBUG_SYNC= 'now WAIT_FOR ready';
@@ -305,7 +305,7 @@ SELECT count(*) FROM mysql.backup_progre
count(*)
13
con2: Activate sync points for the backup statement.
-SET DEBUG_SYNC= 'before_restore_done SIGNAL ready WAIT_FOR proceed';
+SET DEBUG_SYNC= 'before_restore_completed SIGNAL ready WAIT_FOR proceed';
RESTORE FROM 'backup5.bak' OVERWRITE;
con1: Wait for the backup to be ready.
SET DEBUG_SYNC= 'now WAIT_FOR ready';
=== modified file 'mysql-test/suite/backup/t/backup_errors.test'
--- a/mysql-test/suite/backup/t/backup_errors.test 2009-01-06 09:53:50 +0000
+++ b/mysql-test/suite/backup/t/backup_errors.test 2009-01-08 14:57:41 +0000
@@ -12,7 +12,7 @@ DROP DATABASE IF EXISTS bdb;
--remove_file $MYSQLTEST_VARDIR/master-data/test.bak
--enable_warnings
-# non-existent backup archive
+--echo # non-existent backup archive
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 29
@@ -32,7 +32,7 @@ CREATE DATABASE adb;
CREATE DATABASE bdb;
CREATE TABLE bdb.t1(a int) ENGINE=MEMORY;
-# invalid location
+--echo # invalid location
--error ER_BAD_PATH
BACKUP DATABASE adb TO '';
--replace_column 2 #
@@ -48,7 +48,7 @@ SELECT backup_state,operation, backup_fi
SELECT notes FROM mysql.backup_progress
WHERE backup_id=@bup_id;
-# don't overwrite existing files
+--echo # don't overwrite existing files
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 1
@@ -63,7 +63,7 @@ BACKUP DATABASE adb TO "test.bak";
# There should be no warnings after a successful backup
SHOW WARNINGS;
-# don't overwrite existing backup image
+--echo # don't overwrite existing backup image
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /Errcode: [0-9]+/Errcode: #/
--error 1
@@ -85,7 +85,7 @@ SELECT notes FROM mysql.backup_progress
--remove_file $MYSQLTEST_VARDIR/master-data/test.bak
-# non-existent database
+--echo # non-existent database
--disable_warnings
DROP DATABASE IF EXISTS foo;
DROP DATABASE IF EXISTS bar;
@@ -101,10 +101,6 @@ BACKUP DATABASE test,foo,bdb,bar TO 'tes
--replace_column 2 #
SHOW WARNINGS;
-# repeated database
--- error ER_NONUNIQ_DB
-BACKUP DATABASE foo,test,bar,foo TO 'test.bak';
-
--echo Get last backup_id
SELECT MAX(backup_id) INTO @bup_id FROM mysql.backup_history
WHERE command LIKE "BACKUP DATABASE test,foo,bdb,bar TO%";
@@ -115,6 +111,16 @@ SELECT backup_state,operation,backup_fil
SELECT notes FROM mysql.backup_progress
WHERE backup_id=@bup_id;
+#
+# Note: the following error is detected on parser level. Thus no
+# backup_id is assigned and nothing is written to backup logs.
+#
+--echo # repeated database
+-- error ER_NONUNIQ_DB
+BACKUP DATABASE foo,test,bar,foo TO 'test.bak';
+--replace_column 2 #
+SHOW WARNINGS;
+
# Test that BACKUP/RESTORE statements are disable inside stored routines,
# triggers and events.
=== modified file 'mysql-test/suite/backup/t/backup_logs_purge.test'
--- a/mysql-test/suite/backup/t/backup_logs_purge.test 2008-11-17 09:57:51 +0000
+++ b/mysql-test/suite/backup/t/backup_logs_purge.test 2009-01-08 14:57:41 +0000
@@ -274,7 +274,7 @@ SET SESSION debug="+d,set_backup_id";
# it writes the history log and last complete log entry.
#
--echo con2: Activate sync points for the backup statement.
-SET DEBUG_SYNC= 'before_backup_done SIGNAL ready WAIT_FOR proceed';
+SET DEBUG_SYNC= 'before_backup_completed SIGNAL ready WAIT_FOR proceed';
SEND BACKUP DATABASE backup_logs to 'backup5.bak';
connection con1;
@@ -328,7 +328,7 @@ connection con2;
# it writes the history log and last complete log entry.
#
--echo con2: Activate sync points for the backup statement.
-SET DEBUG_SYNC= 'before_restore_done SIGNAL ready WAIT_FOR proceed';
+SET DEBUG_SYNC= 'before_restore_completed SIGNAL ready WAIT_FOR proceed';
SEND RESTORE FROM 'backup5.bak' OVERWRITE;
connection con1;
=== modified file 'sql/backup/backup_kernel.h'
--- a/sql/backup/backup_kernel.h 2008-12-18 21:46:36 +0000
+++ b/sql/backup/backup_kernel.h 2009-01-08 14:57:41 +0000
@@ -102,9 +102,31 @@ private:
/**
@brief State of a context object.
-
- Backup/restore can be performed only if object is prepared for that
- operation.
+
+ The following diagram illustrates the states in which a context object
+ can be and how the state changes as a result of calling public methods.
+ Methods which are not listed are forbidden in a given state.
+ @verbatim
+ CREATED
+ prepare_for_backup() -> PREPARED_FOR_BACKUP
+ prepare_for_restore() -> PREPARED_FOR_RESTORE
+ close() -> CLOSED
+
+ PREPARED_FOR_BACKUP
+ do_backup() -> CLOSED
+ close() -> CLOSED
+
+ PREPARED_FOR_RESTORE
+ do_restore() -> CLOSED
+ close() -> CLOSED
+
+ CLOSED
+ close() -> CLOSED
+ @endverbatim
+
+ @note An instance of the context class can be used only once -- when it
+ moves to CLOSED state no methods can be called except for close() which does
+ nothing in that case.
*/
enum { CREATED,
PREPARED_FOR_BACKUP,
@@ -132,9 +154,6 @@ private:
::String m_path; ///< Path to where the backup image file is located.
- /** If true, the backup image file is deleted at clean-up time. */
- bool m_remove_loc;
-
backup::Stream *m_stream; ///< Pointer to the backup stream object, if opened.
backup::Image_info *m_catalog; ///< Pointer to the image catalogue object.
@@ -163,6 +182,9 @@ private:
int report_stream_open_failure(int open_error, const LEX_STRING *location);
+ /// Indicates if the operation has been successfully completed.
+ bool m_completed;
+
friend int backup_init();
friend void backup_shutdown();
friend bstream_byte* bstream_alloc(unsigned long int);
@@ -210,12 +232,11 @@ void Backup_restore_ctx::disable_fkey_co
inline
int Backup_restore_ctx::fatal_error(int error_code)
{
- m_remove_loc= TRUE;
-
if (m_error)
return m_error;
m_error= error_code;
+ report_state(BUP_ERRORS);
return error_code;
}
=== modified file 'sql/backup/image_info.h'
--- a/sql/backup/image_info.h 2008-12-18 21:46:36 +0000
+++ b/sql/backup/image_info.h 2009-01-08 14:57:41 +0000
@@ -85,6 +85,8 @@ public: // public interface
// info about image (most of it is in the st_bstream_image_header base
+ virtual bool is_valid() =0; ///< Is the structure valid?
+
size_t data_size; ///< How much of table data is saved in the image.
st_bstream_binlog_pos master_pos; ///< To store master position info.
=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc 2008-12-18 21:46:36 +0000
+++ b/sql/backup/kernel.cc 2009-01-08 14:57:41 +0000
@@ -270,8 +270,6 @@ int send_error(Backup_restore_ctx &conte
va_end(args);
}
- if (context.backup::Logger::m_state == backup::Logger::RUNNING)
- context.report_stop(my_time(0), FALSE); // FASLE = no success
return error_code;
}
@@ -376,9 +374,9 @@ pthread_mutex_t Backup_restore_ctx::run_
Backup_restore_ctx::Backup_restore_ctx(THD *thd)
:Logger(thd), m_state(CREATED), m_thd_options(thd->options),
- m_error(0), m_remove_loc(FALSE), m_stream(NULL),
+ m_error(0), m_stream(NULL),
m_catalog(NULL), mem_alloc(NULL), m_tables_locked(FALSE),
- m_engage_binlog(FALSE)
+ m_engage_binlog(FALSE), m_completed(FALSE)
{
/*
Check for progress tables.
@@ -625,9 +623,6 @@ Backup_restore_ctx::prepare_for_backup(S
return NULL;
}
- // Mark that the file should be removed unless operation completes successfuly
- m_remove_loc= TRUE;
-
int my_open_status= s->open();
if (my_open_status != 0)
{
@@ -936,6 +931,35 @@ int Backup_restore_ctx::close()
using namespace backup;
+ // Move context to error state if the catalog became corrupted.
+ if (m_catalog && !m_catalog->is_valid())
+ fatal_error(m_type == BACKUP ? ER_BACKUP_BACKUP : ER_BACKUP_RESTORE);
+
+ /*
+ Report end of the operation which has started if it has not been done
+ before (Logger is in RUNNING state).
+ */
+ if (Logger::m_state == RUNNING)
+ {
+ time_t now= my_time(0);
+ if (m_catalog)
+ m_catalog->save_end_time(now);
+
+ // Report either completion or interruption depending on m_completed flag.
+ if (m_completed)
+ report_completed(now);
+ else
+ {
+ /*
+ If this is restore operation then m_data_changed flag in the
+ Restore_info object tells if data has been modified or not.
+ */
+ const bool data_changed= m_type==RESTORE && m_catalog &&
+ static_cast<Restore_info*>(m_catalog)->m_data_changed;
+ report_aborted(now, data_changed);
+ }
+ }
+
/*
Allow slaves connect after restore is complete.
*/
@@ -952,8 +976,6 @@ int Backup_restore_ctx::close()
if (m_engage_binlog)
obs::engage_binlog(TRUE);
- time_t when= my_time(0);
-
// unlock tables if they are still locked
unlock_tables(); // Never errors
@@ -964,7 +986,7 @@ int Backup_restore_ctx::close()
m_thd->options= m_thd_options;
- // close stream
+ // close stream if not closed already (in which case m_steam is NULL)
if (m_stream && !m_stream->close())
{
@@ -972,16 +994,13 @@ int Backup_restore_ctx::close()
fatal_error(report_error(ER_BACKUP_CLOSE));
}
- if (m_catalog)
- m_catalog->save_end_time(when); // Note: no errors.
-
/*
- Remove the location, if asked for.
+ Remove the location if it is BACKUP operation and it has not completed
+ successfully.
- Important: This is done only for backup operation - RESTORE should never
- remove the specified backup image!
+ Important: RESTORE should never remove the specified backup image!
*/
- if (m_remove_loc && m_state == PREPARED_FOR_BACKUP)
+ if (m_state == PREPARED_FOR_BACKUP && !m_completed)
{
int ret= my_delete(m_path.c_ptr(), MYF(0));
@@ -989,17 +1008,8 @@ int Backup_restore_ctx::close()
Ignore ENOENT error since it is ok if the file doesn't exist.
*/
if (ret && my_errno != ENOENT)
- fatal_error(report_error(ER_CANT_DELETE_FILE, m_path.c_ptr(), my_errno));
- }
-
- /* We report completion of the operation only if no errors were detected,
- and logger has been initialized.
- */
- if (!m_error)
- {
- if (backup::Logger::m_state == backup::Logger::RUNNING)
{
- report_stop(when, TRUE);
+ fatal_error(report_error(ER_CANT_DELETE_FILE, m_path.c_ptr(), my_errno));
}
}
@@ -1078,17 +1088,14 @@ int Backup_restore_ctx::do_backup()
if (ret)
DBUG_RETURN(fatal_error(report_error(ER_BACKUP_WRITE_SUMMARY)));
- /*
- Now backup image has been written. Set m_remove_loc to FALSE, so that the
- backup file is not removed in Backup_restore_ctx::close().
- */
- m_remove_loc= FALSE;
+ DEBUG_SYNC(m_thd, "before_backup_completed");
+ m_completed= TRUE;
report_stats_post(info); // Never errors
DBUG_PRINT("backup",("Backup done."));
DEBUG_SYNC(m_thd, "before_backup_done");
- DBUG_RETURN(0);
+ DBUG_RETURN(close());
}
/**
@@ -1113,11 +1120,13 @@ int Backup_restore_ctx::restore_triggers
DBUG_ENTER("restore_triggers_and_events");
+ DBUG_ASSERT(m_type == RESTORE);
+ Restore_info *info= static_cast<Restore_info*>(m_catalog);
Image_info::Obj *obj;
List<Image_info::Obj> events;
Image_info::Obj::describe_buf buf;
- Image_info::Iterator *dbit= m_catalog->get_dbs();
+ Image_info::Iterator *dbit= info->get_dbs();
if (!dbit)
DBUG_RETURN(fatal_error(report_error(ER_OUT_OF_RESOURCES)));
@@ -1126,7 +1135,7 @@ int Backup_restore_ctx::restore_triggers
while ((obj= (*dbit)++))
{
Image_info::Iterator *it=
- m_catalog->get_db_objects(*static_cast<Image_info::Db*>(obj));
+ info->get_db_objects(*static_cast<Image_info::Db*>(obj));
if (!it)
DBUG_RETURN(fatal_error(report_error(ER_OUT_OF_RESOURCES)));
@@ -1144,6 +1153,8 @@ int Backup_restore_ctx::restore_triggers
case BSTREAM_IT_TRIGGER:
DBUG_ASSERT(obj->m_obj_ptr);
+ // Mark that data is being changed.
+ info->m_data_changed= TRUE;
if (obj->m_obj_ptr->create(m_thd))
{
delete it;
@@ -1168,11 +1179,15 @@ int Backup_restore_ctx::restore_triggers
Image_info::Obj *ev;
while ((ev= it++))
+ {
+ // Mark that data is being changed.
+ info->m_data_changed= TRUE;
if (ev->m_obj_ptr->create(m_thd))
{
int ret= report_error(ER_BACKUP_CANT_RESTORE_EVENT,ev->describe(buf));
DBUG_RETURN(fatal_error(ret));
};
+ }
DBUG_RETURN(0);
}
@@ -1260,7 +1275,11 @@ int Backup_restore_ctx::do_restore(bool
if (err)
DBUG_RETURN(fatal_error(err));
- // Here restore drivers are created to restore table data
+ /*
+ Here restore drivers are created to restore table data. Data is being
+ (potentially) changed so we set m_data_changed flag.
+ */
+ info.m_data_changed= TRUE;
err= restore_table_data(m_thd, info, s); // logs errors
unlock_tables(); // Never errors
@@ -1290,6 +1309,9 @@ int Backup_restore_ctx::do_restore(bool
DBUG_PRINT("restore",("Done."));
+ DEBUG_SYNC(m_thd, "before_restore_completed");
+ m_completed= TRUE;
+
err= read_summary(info, s);
if (err)
DBUG_RETURN(fatal_error(report_error(ER_BACKUP_READ_SUMMARY)));
@@ -1307,7 +1329,7 @@ int Backup_restore_ctx::do_restore(bool
DEBUG_SYNC(m_thd, "before_restore_done");
- DBUG_RETURN(0);
+ DBUG_RETURN(close());
}
/**
@@ -2040,6 +2062,9 @@ int bcat_create_item(st_bstream_image_he
}
}
+ // Mark that data is being changed.
+ info->m_data_changed= TRUE;
+
if (sobj->create(thd))
{
log.report_error(create_err, desc);
=== modified file 'sql/backup/logger.h'
--- a/sql/backup/logger.h 2008-12-18 21:46:36 +0000
+++ b/sql/backup/logger.h 2009-01-08 14:57:41 +0000
@@ -58,7 +58,8 @@ public:
int log_error(int error_code, ...);
void report_start(time_t);
- void report_stop(time_t, bool);
+ void report_completed(time_t);
+ void report_aborted(time_t, bool data_changed);
void report_state(enum_backup_state);
void report_vp_time(time_t, bool);
void report_binlog_pos(const st_bstream_binlog_pos&);
@@ -67,6 +68,7 @@ public:
void report_backup_file(char * path);
void report_stats_pre(const Image_info&);
void report_stats_post(const Image_info&);
+
/// Return the Backup_id of the current operation
ulonglong get_op_id() const
{
@@ -192,27 +194,73 @@ void Logger::report_start(time_t when)
backup_log->state(BUP_RUNNING);
}
+/**
+ Report that the operation has completed successfully.
+
+ @param[in] when the time when operation has completed.
+
+ @note This method can be called only after @c report_start(). It can not be
+ called after end of operation has been logged with either this method or
+ @c report_aborted().
+*/
+inline
+void Logger::report_completed(time_t when)
+{
+ DBUG_ASSERT(m_state == RUNNING);
+ DBUG_ASSERT(backup_log);
+
+ report_error(log_level::INFO, m_type == BACKUP ? ER_BACKUP_BACKUP_DONE
+ : ER_BACKUP_RESTORE_DONE);
+ report_state(BUP_COMPLETE);
+
+ // Report stop time to backup logs.
+ backup_log->stop(when);
+ /*
+ Since the operation has completed, we can now write the backup history log
+ entry describing it.
+ */
+ backup_log->write_history();
+}
+
/**
- Report end of the operation.
+ Report that backup/restore operation has been aborted.
+
+ @param[in] when time when the operation has ended.
+ @param[in] data_changed tells if data has been already modified in case
+ this is restore operation.
+
+ This method should be called when backup/restore operation has been aborted
+ before its completion, e.g., because of an error or user interruption.
- @param[in] when time when report stopped
- @param[in] success indicates if the operation ended successfully
+ The method will log the stop time and ER_OPERATION_ABORTED warning.
+ However, if a restore operation has been interrupted and @c data_changed flag
+ is true, ER_OPERATION_ABORTED_CORRUPTED warning will be logged, to warn the
+ user about the possibility of data corruption.
+
+ @note This method must be called after @c report_start(). It can not be
+ called after end of operation has been logged with either this method or
+ @c report_completed().
*/
inline
-void Logger::report_stop(time_t when, bool success)
+void Logger::report_aborted(time_t when, bool data_changed)
{
- if (m_state == DONE)
- return;
-
DBUG_ASSERT(m_state == RUNNING);
DBUG_ASSERT(backup_log);
- report_error(log_level::INFO, m_type == BACKUP ? ER_BACKUP_BACKUP_DONE
- : ER_BACKUP_RESTORE_DONE);
+ if (m_type == RESTORE && data_changed)
+ report_error(log_level::WARNING, ER_OPERATION_ABORTED_CORRUPTED);
+ else
+ report_error(log_level::WARNING, ER_OPERATION_ABORTED);
+
+ // Report stop time to backup logs.
backup_log->stop(when);
- backup_log->state(success ? BUP_COMPLETE : BUP_ERRORS);
+ /*
+ Since the operation has ended, we can now write the backup history log
+ entry describing it.
+ */
backup_log->write_history();
+
m_state= DONE;
}
=== modified file 'sql/backup/restore_info.h'
--- a/sql/backup/restore_info.h 2008-12-18 21:46:36 +0000
+++ b/sql/backup/restore_info.h 2009-01-08 14:57:41 +0000
@@ -38,7 +38,7 @@ public:
~Restore_info();
/// Determine of information class is valid.
- bool is_valid() const;
+ bool is_valid();
Image_info::Ts* add_ts(const ::String&, uint);
Image_info::Db* add_db(const ::String&, uint);
@@ -59,6 +59,9 @@ private:
THD *m_thd;
+ /// A flag to indicate that data has been modified during restore operation.
+ bool m_data_changed;
+
friend int backup::restore_table_data(THD*, Restore_info&,
backup::Input_stream&);
friend int ::bcat_add_item(st_bstream_image_header*,
@@ -72,7 +75,7 @@ private:
inline
Restore_info::Restore_info(backup::Logger &log, THD *thd)
- :m_log(log), m_thd(thd)
+ :m_log(log), m_thd(thd), m_data_changed(FALSE)
{}
inline
@@ -86,7 +89,7 @@ Restore_info::~Restore_info()
}
inline
-bool Restore_info::is_valid() const
+bool Restore_info::is_valid()
{
return TRUE;
}
=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt 2008-12-16 20:54:07 +0000
+++ b/sql/share/errmsg.txt 2009-01-08 14:57:41 +0000
@@ -6449,3 +6449,7 @@ ER_BACKUP_SYNCHRONIZE
eng "Backup failed to synchronize table images."
ER_RESTORE_CANNOT_START_SLAVE
eng "Cannot start slave. SLAVE START is blocked by %-.64s."
+ER_OPERATION_ABORTED
+ eng "Operation aborted"
+ER_OPERATION_ABORTED_CORRUPTED
+ eng "Operation aborted - data might be corrupted"
| Thread |
|---|
| • bzr commit into mysql-6.0-backup branch (Rafal.Somla:2748) Bug#40305 | Rafal Somla | 8 Jan |