Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 81 additions & 4 deletions extra/mariabackup/xtrabackup.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
#include <row0quiesce.h>
#include <srv0start.h>
#include "trx0sys.h"
#include "trx0trx.h"
#include "trx0roll.h"
#include <buf0flu.h>
#include <buf0dblwr.h>
#include <buf0flu.h>
#include "ha_innodb.h"
Expand Down Expand Up @@ -151,6 +154,8 @@ my_bool xtrabackup_help;
my_bool xtrabackup_export;
my_bool ignored_option;

my_bool xtrabackup_rollback_xa;

longlong xtrabackup_use_memory;

uint opt_protocol;
Expand Down Expand Up @@ -1354,6 +1359,7 @@ enum options_xtrabackup
OPT_XTRA_BACKUP,
OPT_XTRA_PREPARE,
OPT_XTRA_EXPORT,
OPT_XTRA_ROLLBACK_XA,
OPT_XTRA_PRINT_PARAM,
OPT_XTRA_USE_MEMORY,
OPT_XTRA_THROTTLE,
Expand Down Expand Up @@ -1477,6 +1483,13 @@ struct my_option xb_client_options[]= {
"create files to import to another database when prepare.",
(G_PTR *) &xtrabackup_export, (G_PTR *) &xtrabackup_export, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"rollback-xa", OPT_XTRA_ROLLBACK_XA,
"Rollback prepared XA transactions on --prepare. Enabled by default; "
"use --skip-rollback-xa to disable. "
"After preparing target directory with this option "
"it can no longer be a base for incremental backup.",
(G_PTR *) &xtrabackup_rollback_xa, (G_PTR *) &xtrabackup_rollback_xa, 0,
GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
Comment on lines +1486 to +1492
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think it is acceptable to change the default behaviour in stable release series. The need to change a large number of existing tests in a stable release series should be a warning sign to any reviewer.

Furthermore, I don’t think it is acceptable to break incremental backup by default, in any release.

{"print-param", OPT_XTRA_PRINT_PARAM,
"print parameter of mysqld needed for copyback.",
(G_PTR *) &xtrabackup_print_param, (G_PTR *) &xtrabackup_print_param, 0,
Expand Down Expand Up @@ -6900,8 +6913,26 @@ static bool xtrabackup_prepare_func(char** argv)
if (!ok) goto cleanup;
}

/* Prevent incompatible combination of --rollback_xa and --export
options. These options cannot be used together because:
- --export sets SRV_OPERATION_RESTORE_EXPORT which makes the redo
log mapping read-only for consistency during table export
- --rollback_xa requires write access to the log system to modify
transaction state during XA rollback
The combination creates mmap state inconsistency in InnoDB's MTR
system, leading to crash.
*/
if (xtrabackup_rollback_xa && xtrabackup_export) {
msg("mariabackup: ERROR: --rollback_xa and --export options cannot "
"be used together. This combination causes internal mmap state "
"inconsistency leading to crashes.");
goto error;
}

srv_operation = xtrabackup_export
? SRV_OPERATION_RESTORE_EXPORT : SRV_OPERATION_RESTORE;
? SRV_OPERATION_RESTORE_EXPORT
: (xtrabackup_rollback_xa ? SRV_OPERATION_RESTORE_ROLLBACK_XA
: SRV_OPERATION_RESTORE);

if (innodb_init_param()) {
goto error;
Expand All @@ -6920,12 +6951,46 @@ static bool xtrabackup_prepare_func(char** argv)
srv_max_dirty_pages_pct_lwm = srv_max_buf_pool_modified_pct;
}

if (xtrabackup_rollback_xa)
srv_fast_shutdown = 0;

recv_sys.recovery_on = false;
if (innodb_init()) {
goto error;
}

ut_ad(!fil_system.freeze_space_list);
if (xtrabackup_rollback_xa) {
/* Roll back recovered prepared XA transactions.
The backup does not contain the binary log needed
to resolve them. (MDEV-36025) */
XID *xid_list =
(XID *) my_malloc(PSI_NOT_INSTRUMENTED,
MAX_XID_LIST_SIZE * sizeof(XID),
MYF(0));
if (!xid_list) {
msg("Can't allocate memory for XID list");
ok = false;
goto cleanup;
}
ut_ad(recv_no_log_write);
ut_d(recv_no_log_write = false);
int got;
while ((got = trx_recover_for_mysql(xid_list,
MAX_XID_LIST_SIZE)) > 0) {
for (int i = 0; i < got; i++) {
trx_t *trx = trx_get_trx_by_xid(&xid_list[i]);
if (trx) {
trx_rollback_for_mysql(trx);
trx->free();
msg("Rolled back prepared XA transaction");
}
}
}
my_free(xid_list);
ut_d(recv_no_log_write = true);
}

ut_ad(!fil_system.freeze_space_list);

corrupted_pages.read_from_file(MB_CORRUPTED_PAGES_FILE);
if (xtrabackup_incremental)
Expand Down Expand Up @@ -6982,9 +7047,21 @@ static bool xtrabackup_prepare_func(char** argv)
else if (ok) xb_write_galera_info(xtrabackup_incremental);
#endif

innodb_shutdown();
/* Without buf_flush_sync(), the rolled-back changes would exist only
in the buffer pool and be lost on shutdown, leaving the data files in
an inconsistent state.
In the innodb_preshutdown(), the condition was updated to include
SRV_OPERATION_RESTORE_ROLLBACK_XA so it waits for transactions when
srv_fast_shutdown == 0. The innodb_preshutdown() is called by
innodb_shutdown(), which will wait for any active transactions to
finish and shut down purge and undo background sources for
SRV_OPERATION_RESTORE_ROLLBACK_XA. */
if (xtrabackup_rollback_xa)
buf_flush_sync_batch(0, false);

innodb_shutdown();

innodb_free_param();
innodb_free_param();
Comment on lines -6985 to +7064
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is rather confusing. Why can’t we invoke the higher-level function log_make_checkpoint() here? Can we issue a some messages that would indicate that the backup has now diverged from the server it was copied from? And mention the new checkpoint LSN?


/* output to metadata file */
if (ok) {
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/suite/mariabackup/encrypted_export.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10

echo # xtrabackup prepare export;
--disable_result_log
exec $XTRABACKUP --prepare --export --target-dir=$targetdir;
exec $XTRABACKUP --prepare --export --target-dir=$targetdir --skip-rollback-xa;
--enable_result_log

--source include/start_mysqld.inc
Expand Down
6 changes: 3 additions & 3 deletions mysql-test/suite/mariabackup/innodb_force_recovery.test
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ close $fd;
EOF
--echo # "innodb_force_recovery" should be read from "backup-my.cnf" (mariabackup)
--disable_result_log
exec $XTRABACKUP --defaults-file=$targetdir/backup-my.cnf --prepare --export --target-dir=$targetdir >$backuplog;
exec $XTRABACKUP --defaults-file=$targetdir/backup-my.cnf --prepare --export --target-dir=$targetdir --skip-rollback-xa >$backuplog;
--enable_result_log
--let SEARCH_PATTERN=innodb_force_recovery = 1
--let SEARCH_FILE=$backuplog
Expand All @@ -84,7 +84,7 @@ close $fd;
EOF
--echo # "innodb_force_recovery=1" should be read from "backup-my.cnf" (innobackupex)
--disable_result_log
exec $XTRABACKUP --innobackupex --defaults-file=$targetdir/backup-my.cnf --apply-log --export $targetdir >$backuplog;
exec $XTRABACKUP --innobackupex --defaults-file=$targetdir/backup-my.cnf --apply-log --export --skip-rollback-xa $targetdir >$backuplog;
--enable_result_log
--let SEARCH_PATTERN=innodb_force_recovery = 1
--let SEARCH_FILE=$backuplog
Expand Down Expand Up @@ -121,7 +121,7 @@ close $fd;
EOF
--echo # "innodb_force_recovery" from the command line should override "backup-my.cnf" (innobackupex)
--disable_result_log
exec $XTRABACKUP --innobackupex --defaults-file=$targetdir/backup-my.cnf --apply-log --innodb-force-recovery=0 --export $targetdir >$backuplog;
exec $XTRABACKUP --innobackupex --defaults-file=$targetdir/backup-my.cnf --apply-log --innodb-force-recovery=0 --export --skip-rollback-xa $targetdir >$backuplog;
--enable_result_log
--let SEARCH_PATTERN=innodb_force_recovery = 1
--let SEARCH_FILE=$backuplog
Expand Down
41 changes: 41 additions & 0 deletions mysql-test/suite/mariabackup/innodb_xa_rollback.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
CALL mtr.add_suppression("Found 1 prepared XA transactions");
RESET MASTER;
CREATE TABLE t1 (a INT) ENGINE=INNODB;
XA START 'test1';
INSERT t1 VALUES (10);
XA END 'test1';
XA PREPARE 'test1';
XA RECOVER;
formatID gtrid_length bqual_length data
1 5 0 test1
# xtrabackup backup
XA ROLLBACK 'test1';
# xtrabackup prepare and rollback prepared XA
# shutdown server
# remove datadir
# xtrabackup move back
# restart
XA RECOVER;
formatID gtrid_length bqual_length data
1 5 0 test1
# xtrabackup prepare and DO NOT rollback prepared XA
# shutdown server
# remove datadir
# xtrabackup move back
# restart
XA RECOVER;
formatID gtrid_length bqual_length data
1 5 0 test1
XA ROLLBACK 'test1';
# xtrabackup prepare for export and rollback prepared XA (should fail)
# The above command should fail with error about incompatible options
# xtrabackup prepare for export and DO NOT rollback prepared XA
# shutdown server
# remove datadir
# xtrabackup move back
# restart
XA RECOVER;
formatID gtrid_length bqual_length data
1 5 0 test1
XA ROLLBACK 'test1';
DROP TABLE t1;
75 changes: 75 additions & 0 deletions mysql-test/suite/mariabackup/innodb_xa_rollback.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#
# Optionally rollback prepared XA when backup is prepared
#
--source include/have_innodb.inc
--source include/have_binlog_format_mixed.inc

CALL mtr.add_suppression("Found 1 prepared XA transactions");

RESET MASTER;

let targetdir1=$MYSQLTEST_VARDIR/tmp/backup1;
let targetdir2=$MYSQLTEST_VARDIR/tmp/backup2;
let targetdir3=$MYSQLTEST_VARDIR/tmp/backup3;
let targetdir4=$MYSQLTEST_VARDIR/tmp/backup4;

CREATE TABLE t1 (a INT) ENGINE=INNODB;
XA START 'test1';
INSERT t1 VALUES (10);
XA END 'test1';
XA PREPARE 'test1';
XA RECOVER;

--echo # xtrabackup backup
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir1;
--enable_result_log

perl;
use lib "lib";
use My::Handles { suppress_init_messages => 1 };
use My::File::Path;
copytree($ENV{'targetdir1'}, $ENV{'targetdir2'});
copytree($ENV{'targetdir1'}, $ENV{'targetdir3'});
copytree($ENV{'targetdir1'}, $ENV{'targetdir4'});
EOF

XA ROLLBACK 'test1';

--echo # xtrabackup prepare and rollback prepared XA
--disable_result_log
exec $XTRABACKUP --prepare --rollback_xa --target-dir=$targetdir1;
--let $targetdir = $targetdir1
--source include/restart_and_restore.inc
--enable_result_log
XA RECOVER;

--echo # xtrabackup prepare and DO NOT rollback prepared XA
--disable_result_log
exec $XTRABACKUP --prepare --target-dir=$targetdir2;
--let $targetdir = $targetdir2
--source include/restart_and_restore.inc
--enable_result_log
XA RECOVER;
XA ROLLBACK 'test1';

--echo # xtrabackup prepare for export and rollback prepared XA (should fail)
--disable_result_log
--error 1
exec $XTRABACKUP --prepare --rollback_xa --export --target-dir=$targetdir3;
--echo # The above command should fail with error about incompatible options

--echo # xtrabackup prepare for export and DO NOT rollback prepared XA
--disable_result_log
exec $XTRABACKUP --prepare --export --target-dir=$targetdir4 --skip-rollback-xa;
--let $targetdir = $targetdir4
--source include/restart_and_restore.inc
--enable_result_log
XA RECOVER;
XA ROLLBACK 'test1';

DROP TABLE t1;
rmdir $targetdir1;
rmdir $targetdir2;
rmdir $targetdir3;
rmdir $targetdir4;
2 changes: 1 addition & 1 deletion mysql-test/suite/mariabackup/page_compression_level.test
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir;
echo # xtrabackup prepare;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir --skip-rollback-xa;
--enable_result_log

--let SEARCH_PATTERN=innodb_compression_level=3
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/suite/mariabackup/partial.test
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ EOF

echo # xtrabackup prepare;
--disable_result_log
exec $XTRABACKUP --defaults-file=$server_cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir;
exec $XTRABACKUP --defaults-file=$server_cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir --skip-rollback-xa;
--enable_result_log

list_files $targetdir/test *.cfg;
Expand All @@ -59,7 +59,7 @@ SELECT * FROM t1;
--echo # MDEV-33023 Crash in mariadb-backup --prepare --export after --prepare
--disable_result_log
exec $XTRABACKUP --defaults-file=$server_cnf --defaults-group-suffix=.1 --prepare --target-dir=$targetdir;
exec $XTRABACKUP --defaults-file=$server_cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir;
exec $XTRABACKUP --defaults-file=$server_cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir --skip-rollback-xa;
--enable_result_log

list_files $targetdir/test *.cfg;
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/suite/mariabackup/partial_exclude.test
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ rmdir $MYSQLD_DATADIR/db5;

--let $backup_log=$MYSQLTEST_VARDIR/tmp/backup.log
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --export --prepare --target-dir="$targetdir" > $backup_log;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --export --prepare --target-dir="$targetdir" --skip-rollback-xa > $backup_log;
--enable_result_log

--let SEARCH_FILE=$backup_log
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/suite/mariabackup/partition_partial.test
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ INSERT INTO t1 VALUES (1), (101), (201), (301);

echo # xtrabackup prepare;
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group-suffix=.1 --prepare --export --target-dir=$targetdir --skip-rollback-xa;
--enable_result_log


Expand Down
30 changes: 30 additions & 0 deletions mysql-test/suite/mariabackup/xa_prepared_on_restore.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
call mtr.add_suppression("Can't init tc log");
call mtr.add_suppression("Found .* prepared transactions!");
call mtr.add_suppression("Aborting");
CREATE TABLE t1 (a INT) ENGINE=INNODB;
SET GLOBAL innodb_flush_log_at_trx_commit=1;
INSERT INTO t1 VALUES (0);
FLUSH TABLES;
connect con1,localhost,root,,;
SET debug_sync='ha_commit_trans_after_prepare WAIT_FOR go';
INSERT INTO t1 VALUES (1);
connect con2,localhost,root,,;
SET debug_sync='ha_commit_trans_after_prepare WAIT_FOR go';
INSERT INTO t1 VALUES (2);
connect con3,localhost,root,,;
SET debug_sync='ha_commit_trans_after_prepare WAIT_FOR go';
INSERT INTO t1 VALUES (3);
connect con4,localhost,root,,;
SET debug_sync='ha_commit_trans_after_prepare WAIT_FOR go';
INSERT INTO t1 VALUES (4);
connect con5,localhost,root,,;
SET debug_sync='ha_commit_trans_after_prepare WAIT_FOR go';
INSERT INTO t1 VALUES (5);
connection default;
# Kill the server
FOUND 1 /Found .* prepared transactions!/ in mysqld.1.err
# restart
SELECT * FROM t1;
a
0
DROP TABLE t1;
Loading