Fix mariabackup InnoDB recovered binlog position on server upgrade
Before MariaDB 10.3.5, the binlog position was stored in the TRX_SYS page, while after it is stored in rollback segments. There is code to read the legacy position from TRX_SYS to handle upgrades. The problem was if the legacy position happens to compare larger than the position found in rollback segments; in this case, the old TRX_SYS position would incorrectly be preferred over the newer position from rollback segments. Fixed by always preferring a position from rollback segments over a legacy position. Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
parent
f8f5ed2280
commit
9fa718b1a1
@ -31,3 +31,26 @@ sub mycrc32 {
|
||||
|
||||
return $crc;
|
||||
}
|
||||
|
||||
|
||||
# Fix the checksum of an InnoDB tablespace page.
|
||||
# Inputs:
|
||||
# $page A bytestring with the page data.
|
||||
# $full_crc32 Checksum type, see get_full_crc32() in innodb-util.pl
|
||||
# Returns: the modified page as a bytestring.
|
||||
sub fix_page_crc {
|
||||
my ($page, $full_crc32)= @_;
|
||||
my $ps= length($page);
|
||||
my $polynomial = 0x82f63b78; # CRC-32C
|
||||
if ($full_crc32) {
|
||||
my $ck = mycrc32(substr($page, 0, $ps - 4), 0, $polynomial);
|
||||
substr($page, $ps - 4, 4) = pack("N", $ck);
|
||||
} else {
|
||||
my $ck= pack("N",
|
||||
mycrc32(substr($page, 4, 22), 0, $polynomial) ^
|
||||
mycrc32(substr($page, 38, $ps - 38 - 8), 0, $polynomial));
|
||||
substr($page, 0, 4)= $ck;
|
||||
substr($page, $ps-8, 4)= $ck;
|
||||
}
|
||||
return $page;
|
||||
}
|
||||
|
@ -124,3 +124,22 @@ sub ib_restore_ibd_files {
|
||||
ib_restore_ibd_file($tmpd, $datadir, $db, $table);
|
||||
}
|
||||
}
|
||||
|
||||
# Read the flag whether a tablespace is using full_crc32.
|
||||
# Input: filehandle opened on the tablespace.
|
||||
sub get_full_crc32 {
|
||||
my ($TBLSPC)= @_;
|
||||
my $old_pos= sysseek($TBLSPC, 0, 1);
|
||||
die "tell() failed on tablespace filehandle: $!\n"
|
||||
unless defined($old_pos);
|
||||
sysseek($TBLSPC, 0, 0)
|
||||
or die "sysseek() failed on tablespace filehandle: $!\n";
|
||||
my $tblspc_hdr;
|
||||
sysread($TBLSPC, $tblspc_hdr, 58)
|
||||
or die "Cannot read tablespace header: $!\n";
|
||||
sysseek($TBLSPC, $old_pos, 0)
|
||||
or die "sysseek() failed on tablespace filehandle: $!\n";
|
||||
my $full_crc32=
|
||||
unpack("N", substr($tblspc_hdr, 54, 4)) & 0x10; # FIL_SPACE_FLAGS
|
||||
return $full_crc32;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
# restart
|
||||
RESET MASTER;
|
||||
CREATE TABLE t1(a varchar(60) PRIMARY KEY, b VARCHAR(60)) ENGINE INNODB;
|
||||
INSERT INTO t1 VALUES(1, NULL);
|
||||
|
@ -3,6 +3,58 @@
|
||||
|
||||
# Test provisioning a slave from an existing server, using mariabackup --no-lock
|
||||
# and the binlog position recovered from InnoDB redo log.
|
||||
|
||||
# Update the InnoDB system tablespace to simulate a pre-10.3.5
|
||||
# position in TRX_SYS. There was a bug that the wrong position could
|
||||
# be recovered if the old filename in TRX_SYS compares newer than the
|
||||
# newer filenames stored in rseg headers.
|
||||
let MYSQLD_DATADIR=`select @@datadir`;
|
||||
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
|
||||
|
||||
--source include/shutdown_mysqld.inc
|
||||
|
||||
--perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use Fcntl qw(:DEFAULT :seek);
|
||||
do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl";
|
||||
do "$ENV{MTR_SUITE_DIR}/../innodb/include/innodb-util.pl";
|
||||
|
||||
my $ps = $ENV{INNODB_PAGE_SIZE};
|
||||
|
||||
sysopen IBD_FILE, "$ENV{MYSQLD_DATADIR}/ibdata1", O_RDWR
|
||||
or die "Cannot open ibdata1: $!\n";
|
||||
|
||||
# Read the TRX_SYS page.
|
||||
my $page;
|
||||
sysseek(IBD_FILE, $ps * 5, SEEK_SET)
|
||||
or die "Cannot seek ibdata1: $!\n";
|
||||
sysread(IBD_FILE, $page, $ps)
|
||||
or die "Cannot read ibdata1: $!\n";
|
||||
|
||||
# Put in an old binlog position that will compare larger than master-bin.000001
|
||||
my $old_name= '~~~-bin.999999' . chr(0);
|
||||
my $old_off= 0xffff0000;
|
||||
my $old_magic= 873422344;
|
||||
my $binlog_offset= $ps - 1000 + 38;
|
||||
substr($page, $binlog_offset, 4)= pack('N', $old_magic);
|
||||
substr($page, $binlog_offset + 4, 4)= pack('N', ($old_off >> 32));
|
||||
substr($page, $binlog_offset + 8, 4)= pack('N', ($old_off & 0xffffffff));
|
||||
substr($page, $binlog_offset + 12, length($old_name))= $old_name;
|
||||
|
||||
# Write back the modified page.
|
||||
my $full_crc32= get_full_crc32(\*IBD_FILE);
|
||||
my $page= fix_page_crc($page, $full_crc32);
|
||||
sysseek(IBD_FILE, $ps * 5, SEEK_SET)
|
||||
or die "Cannot seek ibdata1: $!\n";
|
||||
syswrite(IBD_FILE, $page, $ps) == $ps
|
||||
or die "Cannot write ibdata1: $!\n";
|
||||
close IBD_FILE;
|
||||
EOF
|
||||
|
||||
--source include/start_mysqld.inc
|
||||
|
||||
|
||||
let $basedir=$MYSQLTEST_VARDIR/tmp/backup;
|
||||
|
||||
RESET MASTER;
|
||||
|
@ -867,6 +867,8 @@ public:
|
||||
uint64_t recovered_binlog_offset;
|
||||
/** Latest recovered binlog file name */
|
||||
char recovered_binlog_filename[TRX_SYS_MYSQL_LOG_NAME_LEN];
|
||||
/** Set when latest position is from pre-version 10.3.5 TRX_SYS. */
|
||||
bool recovered_binlog_is_legacy_pos;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -468,7 +468,10 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
||||
compile_time_assert(TRX_RSEG_BINLOG_NAME_LEN == sizeof
|
||||
trx_sys.recovered_binlog_filename);
|
||||
|
||||
int cmp = *trx_sys.recovered_binlog_filename
|
||||
/* Always prefer a position from rollback segment over
|
||||
a legacy position from before version 10.3.5. */
|
||||
int cmp = *trx_sys.recovered_binlog_filename &&
|
||||
!trx_sys.recovered_binlog_is_legacy_pos
|
||||
? strncmp(binlog_name,
|
||||
trx_sys.recovered_binlog_filename,
|
||||
TRX_RSEG_BINLOG_NAME_LEN)
|
||||
@ -489,6 +492,7 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
||||
trx_sys.recovered_binlog_offset
|
||||
= binlog_offset;
|
||||
}
|
||||
trx_sys.recovered_binlog_is_legacy_pos= false;
|
||||
}
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
@ -564,6 +568,7 @@ static void trx_rseg_init_binlog_info(const page_t* page)
|
||||
trx_sys.recovered_binlog_offset = mach_read_from_8(
|
||||
TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET
|
||||
+ TRX_SYS + page);
|
||||
trx_sys.recovered_binlog_is_legacy_pos= true;
|
||||
}
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
@ -578,6 +583,7 @@ dberr_t trx_rseg_array_init()
|
||||
|
||||
*trx_sys.recovered_binlog_filename = '\0';
|
||||
trx_sys.recovered_binlog_offset = 0;
|
||||
trx_sys.recovered_binlog_is_legacy_pos= false;
|
||||
#ifdef WITH_WSREP
|
||||
trx_sys.recovered_wsrep_xid.null();
|
||||
XID wsrep_sys_xid;
|
||||
|
Loading…
x
Reference in New Issue
Block a user