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;
|
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);
|
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;
|
RESET MASTER;
|
||||||
CREATE TABLE t1(a varchar(60) PRIMARY KEY, b VARCHAR(60)) ENGINE INNODB;
|
CREATE TABLE t1(a varchar(60) PRIMARY KEY, b VARCHAR(60)) ENGINE INNODB;
|
||||||
INSERT INTO t1 VALUES(1, NULL);
|
INSERT INTO t1 VALUES(1, NULL);
|
||||||
|
@ -3,6 +3,58 @@
|
|||||||
|
|
||||||
# Test provisioning a slave from an existing server, using mariabackup --no-lock
|
# Test provisioning a slave from an existing server, using mariabackup --no-lock
|
||||||
# and the binlog position recovered from InnoDB redo log.
|
# 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;
|
let $basedir=$MYSQLTEST_VARDIR/tmp/backup;
|
||||||
|
|
||||||
RESET MASTER;
|
RESET MASTER;
|
||||||
|
@ -867,6 +867,8 @@ public:
|
|||||||
uint64_t recovered_binlog_offset;
|
uint64_t recovered_binlog_offset;
|
||||||
/** Latest recovered binlog file name */
|
/** Latest recovered binlog file name */
|
||||||
char recovered_binlog_filename[TRX_SYS_MYSQL_LOG_NAME_LEN];
|
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
|
compile_time_assert(TRX_RSEG_BINLOG_NAME_LEN == sizeof
|
||||||
trx_sys.recovered_binlog_filename);
|
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,
|
? strncmp(binlog_name,
|
||||||
trx_sys.recovered_binlog_filename,
|
trx_sys.recovered_binlog_filename,
|
||||||
TRX_RSEG_BINLOG_NAME_LEN)
|
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
|
trx_sys.recovered_binlog_offset
|
||||||
= binlog_offset;
|
= binlog_offset;
|
||||||
}
|
}
|
||||||
|
trx_sys.recovered_binlog_is_legacy_pos= false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_WSREP
|
#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.recovered_binlog_offset = mach_read_from_8(
|
||||||
TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET
|
TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET
|
||||||
+ TRX_SYS + page);
|
+ TRX_SYS + page);
|
||||||
|
trx_sys.recovered_binlog_is_legacy_pos= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
@ -578,6 +583,7 @@ dberr_t trx_rseg_array_init()
|
|||||||
|
|
||||||
*trx_sys.recovered_binlog_filename = '\0';
|
*trx_sys.recovered_binlog_filename = '\0';
|
||||||
trx_sys.recovered_binlog_offset = 0;
|
trx_sys.recovered_binlog_offset = 0;
|
||||||
|
trx_sys.recovered_binlog_is_legacy_pos= false;
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
trx_sys.recovered_wsrep_xid.null();
|
trx_sys.recovered_wsrep_xid.null();
|
||||||
XID wsrep_sys_xid;
|
XID wsrep_sys_xid;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user