Skip to content

Commit 3ee1991

Browse files
committed
MDEV-36159 mariabackup failed after upgrade
Ever since commit 685d958 (MDEV-14425) mariadb-backup --backup had some trouble to keep up with write workloads of the mariadbd server. Debarun Banerjee found out that mariadb-backup --backup was copying the log in the wrong way and not pausing when it made sense to do so. This change includes his fix as well as some dead code removal from xtrabackup_copy_mmap_logfile(). Some earlier changes to the default behaviour of mariadb-backup --backup will be reverted, by making the configuration parameters OFF by default. These parameters were basically working around this bug: * commit 652f33e (MDEV-30000) introduced --innodb-log-checkpoint-now and made it ON by default. Making the server execute a log checkpoint can be really I/O intensive. * commit 6acada7 (MDEV-34062) introduced --innodb-log-file-mmap and made it ON by default on Linux and FreeBSD. There are no documented semantics what should happen to a memory mapping when there are concurrent pwrite(2) operations by other processes. While it appears to work, it is safer to default to clearly documented semantics. xtrabackup_copy_logfile(): Add a parameter early_exit. Always read a log snippet to the start of recv_sys.buf and assign recv_sys.len to the read length. We used to shift recv_sys.buf with memmove(). However, on recv_sys_t::PREMATURE_EOF we cannot know which part of the mini-transaction was correctly read, because that part of the ib_logfile0 may be concurrently modified by the server. So, we will reread everything from the start of the mini-transaction. xtrabackup_backup_func(): Invoke xtrabackup_copy_logfile(true), allowing it to stop on every recv_sys_t::PREMATURE_EOF. This will also avoid repeated "Retry" messages when there is no more redo log to copy. get_current_lsn(): Execute FLUSH ENGINE LOGS to ensure that InnoDB will complete any buffered writes to the ib_logfile0 and ensure that everything up to the current LSN has been written. backup_wait_for_commit_lsn(): Wait for as much as is really needed. This avoids an extra 5-second wait at the end of the backup. xtrabackup_copy_mmap_logfile(): Remove some dead code, and add debug assertions to demonstrate that the parser can only return recv_sys_t::OK or recv_sys_t::GOT_EOF.
1 parent e8026a5 commit 3ee1991

File tree

6 files changed

+60
-92
lines changed

6 files changed

+60
-92
lines changed

extra/mariabackup/backup_mysql.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,7 @@ ulonglong get_current_lsn(MYSQL *connection)
20682068
{
20692069
static const char lsn_prefix[] = "\nLog sequence number ";
20702070
ulonglong lsn = 0;
2071+
msg("Getting InnoDB LSN");
20712072
if (MYSQL_RES *res = xb_mysql_query(connection,
20722073
"SHOW ENGINE INNODB STATUS",
20732074
true, false)) {
@@ -2081,5 +2082,10 @@ ulonglong get_current_lsn(MYSQL *connection)
20812082
}
20822083
mysql_free_result(res);
20832084
}
2085+
msg("InnoDB LSN: %llu, Flushing Logs", lsn);
2086+
/* Make sure that current LSN is written and flushed to disk. */
2087+
xb_mysql_query(connection, "FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS",
2088+
false, false);
2089+
msg("Flushed Logs");
20842090
return lsn;
20852091
}

extra/mariabackup/xtrabackup.cc

Lines changed: 49 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,7 +1957,7 @@ struct my_option xb_server_options[] =
19571957
"Whether ib_logfile0 should be memory-mapped",
19581958
(G_PTR*) &log_sys.log_mmap,
19591959
(G_PTR*) &log_sys.log_mmap, 0, GET_BOOL, NO_ARG,
1960-
log_sys.log_mmap_default, 0, 0, 0, 0, 0},
1960+
FALSE, 0, 0, 0, 0, 0},
19611961
#if defined __linux__ || defined _WIN32
19621962
{"innodb_log_file_buffering", OPT_INNODB_LOG_FILE_BUFFERING,
19631963
"Whether the file system cache for ib_logfile0 is enabled during --backup",
@@ -2086,7 +2086,7 @@ struct my_option xb_server_options[] =
20862086
"(for --backup): Force an InnoDB checkpoint",
20872087
(G_PTR*)&innodb_log_checkpoint_now,
20882088
(G_PTR*)&innodb_log_checkpoint_now,
2089-
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
2089+
0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
20902090

20912091
{"mysqld-args", OPT_XTRA_MYSQLD_ARGS,
20922092
"All arguments that follow this argument are considered as server "
@@ -3438,87 +3438,53 @@ static bool xtrabackup_copy_mmap_logfile()
34383438
recv_sys.len= size_t(log_sys.file_size);
34393439
const size_t seq_offset{log_sys.is_encrypted() ? 8U + 5U : 5U};
34403440
const char one{'\1'};
3441+
const byte *start= &log_sys.buf[recv_sys.offset];
3442+
ut_d(recv_sys_t::parse_mtr_result r);
34413443

3442-
for (unsigned retry_count{0};;)
3444+
if ((ut_d(r=) recv_sys.parse_mmap<recv_sys_t::store::BACKUP>(false)) ==
3445+
recv_sys_t::OK)
34433446
{
3444-
recv_sys_t::parse_mtr_result r;
3445-
const byte *start= &log_sys.buf[recv_sys.offset];
3446-
3447-
if (recv_sys.parse_mmap<recv_sys_t::store::BACKUP>(false) ==
3448-
recv_sys_t::OK)
3447+
do
34493448
{
3450-
const byte *end;
3451-
3452-
do
3449+
/* Set the sequence bit (the backed-up log will not wrap around) */
3450+
size_t seqo= recv_sys.offset - seq_offset;
3451+
if (seqo < log_sys.START_OFFSET)
3452+
seqo+= static_cast<size_t>(log_sys.file_size - log_sys.START_OFFSET);
3453+
const byte *seq= &log_sys.buf[seqo];
3454+
ut_ad(*seq == log_sys.get_sequence_bit(recv_sys.lsn - seq_offset));
3455+
if (!*seq)
34533456
{
3454-
/* Set the sequence bit (the backed-up log will not wrap around) */
3455-
size_t seqo= recv_sys.offset - seq_offset;
3456-
if (seqo < log_sys.START_OFFSET)
3457-
seqo+= static_cast<size_t>(log_sys.file_size - log_sys.START_OFFSET);
3458-
const byte *seq= &log_sys.buf[seqo];
3459-
ut_ad(*seq == log_sys.get_sequence_bit(recv_sys.lsn - seq_offset));
3460-
if (!*seq)
3461-
{
3462-
if (xtrabackup_copy_mmap_snippet(dst_log_file, start, seq) ||
3463-
ds_write(dst_log_file, &one, 1))
3464-
goto write_error;
3465-
start = seq + 1;
3466-
}
3457+
if (xtrabackup_copy_mmap_snippet(dst_log_file, start, seq) ||
3458+
ds_write(dst_log_file, &one, 1))
3459+
goto write_error;
3460+
start = seq + 1;
34673461
}
3468-
while ((r= recv_sys.parse_mmap<recv_sys_t::store::BACKUP>(false)) ==
3469-
recv_sys_t::OK);
3470-
3471-
end= &log_sys.buf[recv_sys.offset];
3472-
3473-
if (xtrabackup_copy_mmap_snippet(dst_log_file, start, end))
3474-
{
3475-
write_error:
3476-
msg("Error: write to ib_logfile0 failed");
3477-
return true;
3478-
}
3479-
3480-
start= end;
3481-
3482-
pthread_cond_broadcast(&scanned_lsn_cond);
3483-
3484-
if (r == recv_sys_t::GOT_EOF)
3485-
break;
3486-
3487-
retry_count= 0;
34883462
}
3489-
else
3490-
{
3491-
if (metadata_to_lsn)
3492-
{
3493-
if (metadata_to_lsn <= recv_sys.lsn)
3494-
return false;
3495-
}
3496-
else if (xtrabackup_throttle && io_ticket-- < 0)
3497-
mysql_cond_wait(&wait_throttle, &recv_sys.mutex);
3463+
while ((ut_d(r=) recv_sys.parse_mmap<recv_sys_t::store::BACKUP>(false)) ==
3464+
recv_sys_t::OK);
34983465

3499-
if (!retry_count++)
3500-
msg("Retrying read of log at LSN=" LSN_PF, recv_sys.lsn);
3501-
else if (retry_count == 100)
3502-
break;
3503-
else
3504-
{
3505-
timespec abstime;
3506-
set_timespec_nsec(abstime, 1000000ULL /* 1 ms */);
3507-
if (!mysql_cond_timedwait(&log_copying_stop, &recv_sys.mutex,
3508-
&abstime))
3509-
return true;
3510-
}
3466+
if (xtrabackup_copy_mmap_snippet(dst_log_file, start,
3467+
&log_sys.buf[recv_sys.offset]))
3468+
{
3469+
write_error:
3470+
msg("Error: write to ib_logfile0 failed");
3471+
return true;
35113472
}
3473+
3474+
pthread_cond_broadcast(&scanned_lsn_cond);
35123475
}
35133476

3477+
ut_ad(r == recv_sys_t::GOT_EOF);
3478+
35143479
if (verbose)
35153480
msg(">> log scanned up to (" LSN_PF ")", recv_sys.lsn);
35163481
return false;
35173482
}
35183483

35193484
/** Copy redo log until the current end of the log is reached
3485+
@param early_exit parse and copy only logs from first read and return
35203486
@return whether the operation failed */
3521-
static bool xtrabackup_copy_logfile()
3487+
static bool xtrabackup_copy_logfile(bool early_exit)
35223488
{
35233489
mysql_mutex_assert_owner(&recv_sys.mutex);
35243490
DBUG_EXECUTE_IF("log_checksum_mismatch", return false;);
@@ -3534,20 +3500,19 @@ static bool xtrabackup_copy_logfile()
35343500

35353501
recv_sys.offset= size_t(recv_sys.lsn - log_sys.get_first_lsn()) &
35363502
block_size_1;
3537-
recv_sys.len= 0;
35383503

35393504
for (unsigned retry_count{0};;)
35403505
{
35413506
recv_sys_t::parse_mtr_result r;
35423507
size_t start_offset{recv_sys.offset};
35433508

35443509
{
3510+
recv_sys.len= 0;
35453511
{
35463512
auto source_offset=
3547-
log_sys.calc_lsn_offset(recv_sys.lsn + recv_sys.len -
3548-
recv_sys.offset);
3513+
log_sys.calc_lsn_offset(recv_sys.lsn - recv_sys.offset);
35493514
source_offset&= ~block_size_1;
3550-
size_t size{log_sys.buf_size - recv_sys.len};
3515+
size_t size{log_sys.buf_size};
35513516
if (UNIV_UNLIKELY(source_offset + size > log_sys.file_size))
35523517
{
35533518
const size_t first{size_t(log_sys.file_size - source_offset)};
@@ -3589,32 +3554,25 @@ static bool xtrabackup_copy_logfile()
35893554
msg("Error: write to ib_logfile0 failed");
35903555
return true;
35913556
}
3592-
else
3593-
{
3594-
const auto ofs= recv_sys.offset & ~block_size_1;
3595-
memmove_aligned<64>(log_sys.buf, log_sys.buf + ofs,
3596-
recv_sys.len - ofs);
3597-
recv_sys.len-= ofs;
3598-
recv_sys.offset&= block_size_1;
3599-
}
3600-
36013557
pthread_cond_broadcast(&scanned_lsn_cond);
36023558

3603-
if (r == recv_sys_t::GOT_EOF)
3559+
if (r == recv_sys_t::GOT_EOF || early_exit)
36043560
break;
36053561

3562+
ut_ad(r == recv_sys_t::PREMATURE_EOF);
3563+
36063564
if (recv_sys.offset < log_sys.write_size)
36073565
break;
36083566

36093567
if (xtrabackup_throttle && io_ticket-- < 0)
36103568
mysql_cond_wait(&wait_throttle, &recv_sys.mutex);
36113569

3570+
recv_sys.offset&= block_size_1;
36123571
retry_count= 0;
36133572
continue;
36143573
}
36153574
else
36163575
{
3617-
recv_sys.len= recv_sys.offset & ~block_size_1;
36183576
if (retry_count == 100)
36193577
break;
36203578

@@ -3694,7 +3652,7 @@ static void log_copying_thread()
36943652
{
36953653
my_thread_init();
36963654
mysql_mutex_lock(&recv_sys.mutex);
3697-
while (!xtrabackup_copy_logfile() &&
3655+
while (!xtrabackup_copy_logfile(false) &&
36983656
(!metadata_last_lsn || metadata_last_lsn > recv_sys.lsn))
36993657
{
37003658
timespec abstime;
@@ -4912,7 +4870,7 @@ static bool backup_wait_for_commit_lsn()
49124870
ut_ad(metadata_to_lsn);
49134871
metadata_last_lsn= lsn;
49144872

4915-
last_lsn= backup_wait_for_lsn_low(LSN_MAX);
4873+
last_lsn= backup_wait_for_lsn_low(lsn);
49164874

49174875
metadata_last_lsn= last_lsn;
49184876
stop_backup_threads();
@@ -5468,12 +5426,14 @@ static bool xtrabackup_backup_func()
54685426
}
54695427
msg("cd to %s", mysql_real_data_home);
54705428
encryption_plugin_backup_init(mysql_connection);
5471-
if (innodb_log_checkpoint_now != false && mysql_send_query(
5472-
mysql_connection,
5429+
if (innodb_log_checkpoint_now) {
5430+
msg("Initiating checkpoint");
5431+
if (mysql_send_query(mysql_connection,
54735432
C_STRING_WITH_LEN("SET GLOBAL "
54745433
"innodb_log_checkpoint_now=ON;"))) {
5475-
msg("initiating checkpoint failed");
5476-
return(false);
5434+
msg("initiating checkpoint failed");
5435+
return(false);
5436+
}
54775437
}
54785438

54795439
msg("open files limit requested %lu, set to %lu",
@@ -5587,6 +5547,7 @@ static bool xtrabackup_backup_func()
55875547
server does not support this */
55885548
if (innodb_log_checkpoint_now != false) {
55895549
mysql_read_query_result(mysql_connection);
5550+
msg("Finished waiting for checkpoint");
55905551
}
55915552

55925553
if (!select_history()) {
@@ -5626,7 +5587,7 @@ static bool xtrabackup_backup_func()
56265587
mysql_mutex_lock(&recv_sys.mutex);
56275588
recv_sys.lsn = log_sys.next_checkpoint_lsn;
56285589

5629-
const bool log_copy_failed = xtrabackup_copy_logfile();
5590+
const bool log_copy_failed = xtrabackup_copy_logfile(true);
56305591

56315592
mysql_mutex_unlock(&recv_sys.mutex);
56325593

mysql-test/suite/mariabackup/full_backup.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
1010
--disable_result_log
1111
--error 1
1212
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --parallel=10 --innodb-log-write-ahead-size=4095 > $backup_log 2>&1;
13-
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --parallel=10 --innodb-log-write-ahead-size=10000 > $backup_log 2>&1;
13+
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --parallel=10 --innodb-log-write-ahead-size=10000 --innodb_log_checkpoint_now=1 > $backup_log 2>&1;
1414
--enable_result_log
1515

1616
# The following warning must not appear after MDEV-27343 fix

mysql-test/suite/mariabackup/partial.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ echo # xtrabackup backup;
1414

1515
let targetdir=$MYSQLTEST_VARDIR/tmp/backup;
1616
--disable_result_log
17-
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 "--tables=test.*1" --target-dir=$targetdir;
17+
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 "--tables=test.*1" --target-dir=$targetdir --innodb_log_checkpoint_now=1;
1818
--enable_result_log
1919
list_files $targetdir/test *.ibd;
2020
list_files $targetdir/test *.new;
@@ -96,6 +96,7 @@ exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --tables-file
9696
--enable_result_log
9797

9898
--echo # table t2 is skipped. Shows only t1
99+
--replace_result .new .ibd
99100
list_files $targetdir/test;
100101
DROP TABLE t2, t1;
101102
rmdir $targetdir;

mysql-test/suite/mariabackup/partial_exclude.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ echo # xtrabackup backup;
2828

2929
let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
3030
--disable_result_log
31-
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 "--tables-exclude=test.*2" "--databases-exclude=db2" --target-dir=$targetdir;
31+
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 "--tables-exclude=test.*2" "--databases-exclude=db2" --target-dir=$targetdir --innodb_log_checkpoint_now=1;
3232
--enable_result_log
3333

3434
COMMIT;

mysql-test/suite/mariabackup/unsupported_redo.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ ALTER TABLE t21 FORCE, ALGORITHM=INPLACE;
5858
--echo # unsupported redo log for the table t21.
5959

6060
--disable_result_log
61-
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 "--tables-exclude=test.t21" --target-dir=$targetdir;
61+
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 "--tables-exclude=test.t21" --target-dir=$targetdir --innodb_log_checkpoint_now=1;
6262
--enable_result_log
6363
--list_files $targetdir/test *.ibd
6464
--list_files $targetdir/test *.new

0 commit comments

Comments
 (0)