Skip to content

Commit ab8199f

Browse files
committed
MDEV-12103 Reduce the time of looking for MLOG_CHECKPOINT during crash recovery
This fixes MySQL Bug#80788 in MariaDB 10.2.5. When I made the InnoDB crash recovery more robust by implementing WL#7142, I also introduced an extra redo log scan pass that can be shortened. This fix will slightly extend the InnoDB redo log format that I introduced in MySQL 5.7.9 by writing the start LSN of the MLOG_CHECKPOINT mini-transaction to the end of the log checkpoint page, so that recovery can jump straight to it without scanning all the preceding redo log. LOG_CHECKPOINT_END_LSN: At the end of the checkpoint page, the start LSN of the MLOG_CHECKPOINT mini-transaction. Previously, these bytes were written as 0. log_write_checkpoint_info(), log_group_checkpoint(): Add the parameter end_lsn for writing LOG_CHECKPOINT_END_LSN. log_checkpoint(): Remember the LSN at which the MLOG_CHECKPOINT mini-transaction is starting (or at which the redo log ends on shutdown). recv_init_crash_recovery(): Remove. recv_group_scan_log_recs(): Add the parameter checkpoint_lsn. recv_recovery_from_checkpoint_start(): Read LOG_CHECKPOINT_END_LSN and if it is set, start the first scan from it instead of the checkpoint LSN. Improve some messages and remove bogus assertions. recv_parse_log_recs(): Do not skip DBUG_PRINT("ib_log") for some file-level redo log records. recv_parse_or_apply_log_rec_body(): If we have not parsed all redo log between the checkpoint and the corresponding MLOG_CHECKPOINT record, defer the check for MLOG_FILE_DELETE or MLOG_FILE_NAME records to recv_init_crash_recovery_spaces(). recv_init_crash_recovery_spaces(): Refuse recovery if MLOG_FILE_NAME or MLOG_FILE_DELETE records are missing.
1 parent e4a2e80 commit ab8199f

File tree

6 files changed

+148
-83
lines changed

6 files changed

+148
-83
lines changed

mysql-test/suite/encryption/r/innodb_encrypt_log_corruption.result

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ WHERE engine = 'innodb'
8484
AND support IN ('YES', 'DEFAULT', 'ENABLED');
8585
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
8686
FOUND /len 22; hex 38000000000012860cb7809781e800066269676f7400; asc 8 bigot ;/ in mysqld.1.err
87+
# missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
88+
SELECT * FROM INFORMATION_SCHEMA.ENGINES
89+
WHERE engine = 'innodb'
90+
AND support IN ('YES', 'DEFAULT', 'ENABLED');
91+
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
92+
NOT FOUND /InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42$/ in mysqld.1.err
8793
# Minimal MariaDB 10.1.21 encrypted redo log
8894
SELECT COUNT(*) `1` FROM INFORMATION_SCHEMA.ENGINES WHERE engine='innodb'
8995
AND support IN ('YES', 'DEFAULT', 'ENABLED');

mysql-test/suite/innodb/r/log_corruption.result

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ WHERE engine = 'innodb'
8484
AND support IN ('YES', 'DEFAULT', 'ENABLED');
8585
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
8686
FOUND /len 22; hex 38000000000012860cb7809781e800066269676f7400; asc 8 bigot ;/ in mysqld.1.err
87+
# missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
88+
SELECT * FROM INFORMATION_SCHEMA.ENGINES
89+
WHERE engine = 'innodb'
90+
AND support IN ('YES', 'DEFAULT', 'ENABLED');
91+
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
92+
NOT FOUND /InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42$/ in mysqld.1.err
8793
# Minimal MariaDB 10.1.21 encrypted redo log
8894
SELECT * FROM INFORMATION_SCHEMA.ENGINES
8995
WHERE engine = 'innodb'

mysql-test/suite/innodb/t/log_corruption.test

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ call mtr.add_suppression("InnoDB: Missing MLOG_CHECKPOINT");
1313
call mtr.add_suppression("InnoDB: MLOG_FILE_NAME incorrect");
1414
call mtr.add_suppression("InnoDB: ############### CORRUPT LOG RECORD FOUND");
1515
call mtr.add_suppression("InnoDB: Log scan aborted at LSN");
16+
call mtr.add_suppression("InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42\\r?$");
1617
call mtr.add_suppression("InnoDB: Obtaining redo log encryption key version 1 failed");
1718
call mtr.add_suppression("InnoDB: Decrypting checkpoint failed");
1819
--enable_query_log
@@ -316,6 +317,37 @@ eval $check_no_innodb;
316317
--let SEARCH_PATTERN= len 22; hex 38000000000012860cb7809781e800066269676f7400; asc 8 bigot ;
317318
--source include/search_pattern_in_file.inc
318319

320+
--echo # missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
321+
perl;
322+
die unless open OUT, "+<", "$ENV{bugdir}/ib_logfile0";
323+
binmode OUT;
324+
# header block
325+
print OUT pack("Nx[5]nx[5]", 1, 0x1286);
326+
print OUT "ibbackup was here!!!1!";
327+
print OUT pack("x[470]N", 0x52b54540);
328+
# invalid (all-zero) checkpoint page 1 and an empty log page
329+
print OUT chr(0) x 1024;
330+
# valid checkpoint block 2
331+
print OUT pack("x[12]NNNx[264]", 0x12860c, 0, 0x80c);
332+
# pointer to the MLOG_CHECKPOINT record, and checkpoint page checksum
333+
print OUT pack("H*x[204]NNN", "590DBAACFE922582", 0x128612, 0, 0x101741b);
334+
# log page
335+
print OUT pack("H*", "800009440022000c00000001");
336+
# MLOG_1BYTE record for missing tablespace 42 page 123
337+
print OUT pack("CCCnC", 128 | 1, 42, 123, 4567, 89);
338+
# MLOG_CHECKPOINT record
339+
print OUT pack("CNN", 56, 0, 0x12860c);
340+
# padding (MLOG_DUMMY_RECORD) and block checksum
341+
print OUT " " x 481, pack("N", 0x644e6db8);
342+
close OUT or die;
343+
EOF
344+
345+
--source include/start_mysqld.inc
346+
eval $check_no_innodb;
347+
--source include/shutdown_mysqld.inc
348+
--let SEARCH_PATTERN= InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42\$
349+
--source include/search_pattern_in_file.inc
350+
319351
--echo # Minimal MariaDB 10.1.21 encrypted redo log
320352
perl;
321353
die unless open OUT, "+<", "$ENV{bugdir}/ib_logfile0";

storage/innobase/include/log0log.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,10 @@ log_group_header_read(
252252
const log_group_t* group,
253253
ulint header);
254254
/** Write checkpoint info to the log header and invoke log_mutex_exit().
255-
@param[in] sync whether to wait for the write to complete */
255+
@param[in] sync whether to wait for the write to complete
256+
@param[in] end_lsn start LSN of the MLOG_CHECKPOINT mini-transaction */
256257
void
257-
log_write_checkpoint_info(
258-
bool sync);
258+
log_write_checkpoint_info(bool sync, lsn_t end_lsn);
259259

260260
/** Set extra data to be written to the redo log during checkpoint.
261261
@param[in] buf data to be appended on checkpoint, or NULL
@@ -487,17 +487,26 @@ extern my_bool innodb_log_checksums;
487487
.._HDR_NO */
488488
#define LOG_BLOCK_TRL_SIZE 4 /* trailer size in bytes */
489489

490-
/* Offsets inside the checkpoint pages (redo log format version 1) */
490+
/** Offsets inside the checkpoint pages (redo log format version 1) @{ */
491+
/** Checkpoint number */
491492
#define LOG_CHECKPOINT_NO 0
493+
/** Log sequence number up to which all changes have been flushed */
492494
#define LOG_CHECKPOINT_LSN 8
495+
/** Byte offset of the log record corresponding to LOG_CHECKPOINT_LSN */
493496
#define LOG_CHECKPOINT_OFFSET 16
497+
/** log_sys_t::buf_size at the time of the checkpoint (not used) */
494498
#define LOG_CHECKPOINT_LOG_BUF_SIZE 24
495499
/** MariaDB 10.2.5 encrypted redo log encryption key version (32 bits)*/
496500
#define LOG_CHECKPOINT_CRYPT_KEY 32
497501
/** MariaDB 10.2.5 encrypted redo log random nonce (32 bits) */
498502
#define LOG_CHECKPOINT_CRYPT_NONCE 36
499503
/** MariaDB 10.2.5 encrypted redo log random message (MY_AES_BLOCK_SIZE) */
500504
#define LOG_CHECKPOINT_CRYPT_MESSAGE 40
505+
/** start LSN of the MLOG_CHECKPOINT mini-transaction corresponding
506+
to this checkpoint, or 0 if the information has not been written */
507+
#define LOG_CHECKPOINT_END_LSN OS_FILE_LOG_BLOCK_SIZE - 16
508+
509+
/* @} */
501510

502511
/** Offsets of a log file header */
503512
/* @{ */

storage/innobase/log/log0log.cc

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,19 +1612,22 @@ log_io_complete_checkpoint(void)
16121612
log_mutex_exit();
16131613
}
16141614

1615-
/******************************************************//**
1616-
Writes the checkpoint info to a log group header. */
1615+
/** Write checkpoint info to the log header.
1616+
@param[in,out] group redo log
1617+
@param[in] end_lsn start LSN of the MLOG_CHECKPOINT mini-transaction */
16171618
static
16181619
void
1619-
log_group_checkpoint(
1620-
/*=================*/
1621-
log_group_t* group) /*!< in: log group */
1620+
log_group_checkpoint(log_group_t* group, lsn_t end_lsn)
16221621
{
16231622
lsn_t lsn_offset;
16241623
byte* buf;
16251624

16261625
ut_ad(!srv_read_only_mode);
16271626
ut_ad(log_mutex_own());
1627+
ut_ad(end_lsn == 0 || end_lsn >= log_sys->next_checkpoint_lsn);
1628+
ut_ad(end_lsn <= log_sys->lsn);
1629+
ut_ad(end_lsn + SIZE_OF_MLOG_CHECKPOINT <= log_sys->lsn
1630+
|| srv_shutdown_state != SRV_SHUTDOWN_NONE);
16281631

16291632
DBUG_PRINT("ib_log", ("checkpoint " UINT64PF " at " LSN_PF
16301633
" written to group " ULINTPF,
@@ -1646,6 +1649,7 @@ log_group_checkpoint(
16461649
group);
16471650
mach_write_to_8(buf + LOG_CHECKPOINT_OFFSET, lsn_offset);
16481651
mach_write_to_8(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, log_sys->buf_size);
1652+
mach_write_to_8(buf + LOG_CHECKPOINT_END_LSN, end_lsn);
16491653

16501654
log_block_set_checksum(buf, log_block_calc_checksum_crc32(buf));
16511655

@@ -1702,9 +1706,10 @@ log_group_header_read(
17021706
}
17031707

17041708
/** Write checkpoint info to the log header and invoke log_mutex_exit().
1705-
@param[in] sync whether to wait for the write to complete */
1709+
@param[in] sync whether to wait for the write to complete
1710+
@param[in] end_lsn start LSN of the MLOG_CHECKPOINT mini-transaction */
17061711
void
1707-
log_write_checkpoint_info(bool sync)
1712+
log_write_checkpoint_info(bool sync, lsn_t end_lsn)
17081713
{
17091714
ut_ad(log_mutex_own());
17101715
ut_ad(!srv_read_only_mode);
@@ -1713,7 +1718,7 @@ log_write_checkpoint_info(bool sync)
17131718
group;
17141719
group = UT_LIST_GET_NEXT(log_groups, group)) {
17151720

1716-
log_group_checkpoint(group);
1721+
log_group_checkpoint(group, end_lsn);
17171722
}
17181723

17191724
log_mutex_exit();
@@ -1827,12 +1832,13 @@ log_checkpoint(
18271832
threads will be blocked, and no pages can be added to the
18281833
flush lists. */
18291834
lsn_t flush_lsn = oldest_lsn;
1835+
const lsn_t end_lsn = log_sys->lsn;
18301836
const bool do_write
18311837
= srv_shutdown_state == SRV_SHUTDOWN_NONE
1832-
|| flush_lsn != log_sys->lsn;
1838+
|| flush_lsn != end_lsn;
18331839

18341840
if (fil_names_clear(flush_lsn, do_write)) {
1835-
ut_ad(log_sys->lsn >= flush_lsn + SIZE_OF_MLOG_CHECKPOINT);
1841+
ut_ad(log_sys->lsn >= end_lsn + SIZE_OF_MLOG_CHECKPOINT);
18361842
flush_lsn = log_sys->lsn;
18371843
}
18381844

@@ -1878,7 +1884,7 @@ log_checkpoint(
18781884
}
18791885

18801886
log_sys->next_checkpoint_lsn = oldest_lsn;
1881-
log_write_checkpoint_info(sync);
1887+
log_write_checkpoint_info(sync, end_lsn);
18821888
ut_ad(!log_mutex_own());
18831889

18841890
return(true);

0 commit comments

Comments
 (0)