MDEV-13564: Refuse MLOG_TRUNCATE in mariabackup

The MySQL 5.7 TRUNCATE TABLE is inherently incompatible
with hot backup, because it is creating and deleting a separate
log file, and it is not writing redo log for all changes of the
InnoDB data dictionary tables. Refuse to create a corrupted backup
if the unsafe form of TRUNCATE was executed.

Note: Undo log tablespace truncation cannot be detected easily.
Also it is incompatible with backup, for similar reasons.

xtrabackup_backup_func(): "Subscribe to" the log events before
the first invocation of xtrabackup_copy_logfile().

recv_parse_or_apply_log_rec_body(): If the function pointer
log_truncate is set, invoke it to report MLOG_TRUNCATE.
This commit is contained in:
Marko Mäkelä 2018-08-16 16:10:18 +03:00
parent 1b49c89429
commit d6f7fd6016
5 changed files with 56 additions and 9 deletions

View File

@ -358,9 +358,8 @@ struct ddl_tracker_t {
/* For DDL operation found in redo log, */
space_id_to_name_t id_to_name;
};
const space_id_t REMOVED_SPACE_ID = ULINT_MAX;
static ddl_tracker_t ddl_tracker;
static ddl_tracker_t ddl_tracker;
/* Whether xtrabackup_binlog_info should be created on recovery */
static bool recover_binlog_info;
@ -618,9 +617,8 @@ void backup_file_op(ulint space_id, const byte* flags,
/** Callback whenever MLOG_INDEX_LOAD happens.
@param[in] space_id space id to check
@return false */
void backup_optimized_ddl_op(ulint space_id)
@param[in] space_id space id to check */
static void backup_optimized_ddl_op(ulint space_id)
{
// TODO : handle incremental
if (xtrabackup_incremental)
@ -631,6 +629,15 @@ void backup_optimized_ddl_op(ulint space_id)
pthread_mutex_unlock(&backup_mutex);
}
/** Callback whenever MLOG_TRUNCATE happens. */
static void backup_truncate_fail()
{
msg("mariabackup: Incompatible TRUNCATE operation detected.%s\n",
opt_lock_ddl_per_table
? ""
: " Use --lock-ddl-per-table to lock all tables before backup.");
}
/* ======== Date copying thread context ======== */
typedef struct {
@ -4240,12 +4247,13 @@ fail_before_log_copying_thread_start:
/* copy log file by current position */
log_copy_scanned_lsn = checkpoint_lsn_start;
recv_sys->recovered_lsn = log_copy_scanned_lsn;
log_optimized_ddl_op = backup_optimized_ddl_op;
log_truncate = backup_truncate_fail;
if (xtrabackup_copy_logfile())
goto fail_before_log_copying_thread_start;
log_copying_stop = os_event_create(0);
log_optimized_ddl_op = backup_optimized_ddl_op;
os_thread_create(log_copying_thread, NULL, &log_copying_thread_id);
/* FLUSH CHANGED_PAGE_BITMAPS call */

View File

@ -0,0 +1,4 @@
CREATE TABLE t1 ENGINE=InnoDB SELECT 1;
DROP TABLE t1;
SET GLOBAL innodb_log_checkpoint_now=1;
SET GLOBAL innodb_log_checkpoint_now=DEFAULT;

View File

@ -0,0 +1,19 @@
--source include/have_debug.inc
let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
mkdir $targetdir;
CREATE TABLE t1 ENGINE=InnoDB SELECT 1;
--let after_load_tablespaces=TRUNCATE test.t1
--disable_result_log
--error 1
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --dbug=+d,mariabackup_events;
--enable_result_log
--let after_load_tablespaces=
DROP TABLE t1;
SET GLOBAL innodb_log_checkpoint_now=1;
SET GLOBAL innodb_log_checkpoint_now=DEFAULT;
rmdir $targetdir;

View File

@ -153,10 +153,15 @@ bool recv_parse_log_recs(lsn_t checkpoint_lsn, store_t store, bool apply);
/** Moves the parsing buffer data left to the buffer start. */
void recv_sys_justify_left_parsing_buf();
/** Report optimized DDL operation (without redo log), corresponding to MLOG_INDEX_LOAD.
/** Report optimized DDL operation (without redo log),
corresponding to MLOG_INDEX_LOAD.
@param[in] space_id tablespace identifier
*/
extern void(*log_optimized_ddl_op)(ulint space_id);
extern void (*log_optimized_ddl_op)(ulint space_id);
/** Report backup-unfriendly TRUNCATE operation (with separate log file),
corresponding to MLOG_TRUNCATE. */
extern void (*log_truncate)();
/** Report an operation to create, delete, or rename a file during backup.
@param[in] space_id tablespace identifier

View File

@ -169,11 +169,16 @@ typedef std::map<
static recv_spaces_t recv_spaces;
/** Report optimized DDL operation (without redo log), corresponding to MLOG_INDEX_LOAD.
/** Report optimized DDL operation (without redo log),
corresponding to MLOG_INDEX_LOAD.
@param[in] space_id tablespace identifier
*/
void (*log_optimized_ddl_op)(ulint space_id);
/** Report backup-unfriendly TRUNCATE operation (with separate log file),
corresponding to MLOG_TRUNCATE. */
void (*log_truncate)();
/** Report an operation to create, delete, or rename a file during backup.
@param[in] space_id tablespace identifier
@param[in] flags tablespace flags (NULL if not create)
@ -1196,6 +1201,12 @@ recv_parse_or_apply_log_rec_body(
}
return(ptr + 8);
case MLOG_TRUNCATE:
if (log_truncate) {
ut_ad(srv_operation != SRV_OPERATION_NORMAL);
log_truncate();
recv_sys->found_corrupt_fs = true;
return NULL;
}
return(truncate_t::parse_redo_entry(ptr, end_ptr, space_id));
default: