Skip to content

Commit

Permalink
MDEV-14909 MariaDB 10.2 refuses to start up after clean shutdown of M…
Browse files Browse the repository at this point in the history
…ariaDB 10.3

recv_log_recover_10_3(): Determine if a log from MariaDB 10.3 is clean.

recv_find_max_checkpoint(): Allow startup with a clean 10.3 redo log.

srv_prepare_to_delete_redo_log_files(): When starting up with a 10.3 log,
display a "Downgrading redo log" message instead of "Upgrading".
  • Loading branch information
dr-m committed Jan 10, 2018
1 parent b132d4d commit d1cf9b1
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 17 deletions.
27 changes: 24 additions & 3 deletions mysql-test/suite/encryption/r/innodb_encrypt_log_corruption.result
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: Upgrade after a crash is not supported. This redo log was created before MariaDB 10\.2\.2, and it appears corrupted/ in mysqld.1.err
# empty redo log from before MariaDB 10.2.2
SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
COUNT(*)
1
FOUND 1 /InnoDB: Upgrading redo log:/ in mysqld.1.err
# redo log from "after" MariaDB 10.2.2, but with invalid header checksum
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
Expand All @@ -28,7 +35,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: Unsupported redo log format. The redo log was created with malicious intentions, or perhaps\. Please follow the instructions at http://dev.mysql.com/doc/refman/5.7/en/upgrading-downgrading.html/ in mysqld.1.err
FOUND 1 /InnoDB: Unsupported redo log format. The redo log was created with malicious intentions, or perhaps\./ in mysqld.1.err
# valid header, but old-format checkpoint blocks
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
Expand Down Expand Up @@ -86,12 +93,26 @@ AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: MLOG_FILE_NAME incorrect:bigot/ in mysqld.1.err
FOUND 1 /len 22; hex 38000000000012860cb7809781e800066269676f7400; asc 8 bigot ;/ in mysqld.1.err
# missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
# 10.2 missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42/ in mysqld.1.err
# 10.3 missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
NOT FOUND /InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42$/ in mysqld.1.err
FOUND 1 /InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42/ in mysqld.1.err
FOUND 1 /Downgrade after a crash is not supported\. The redo log was created with MariaDB 10\.3\.1/ in mysqld.1.err
# Empty 10.3 redo log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
COUNT(*)
1
FOUND 1 /InnoDB: Downgrading redo log:/ in mysqld.1.err
# Minimal MariaDB 10.1.21 encrypted redo log
SELECT COUNT(*) `1` FROM INFORMATION_SCHEMA.ENGINES WHERE engine='innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
Expand Down
27 changes: 24 additions & 3 deletions mysql-test/suite/innodb/r/log_corruption.result
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: Upgrade after a crash is not supported. This redo log was created before MariaDB 10\.2\.2, and it appears corrupted/ in mysqld.1.err
# empty redo log from before MariaDB 10.2.2
SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
COUNT(*)
1
FOUND 1 /InnoDB: Upgrading redo log:/ in mysqld.1.err
# redo log from "after" MariaDB 10.2.2, but with invalid header checksum
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
Expand All @@ -28,7 +35,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: Unsupported redo log format. The redo log was created with malicious intentions, or perhaps\. Please follow the instructions at http://dev.mysql.com/doc/refman/5.7/en/upgrading-downgrading.html/ in mysqld.1.err
FOUND 1 /InnoDB: Unsupported redo log format. The redo log was created with malicious intentions, or perhaps\./ in mysqld.1.err
# valid header, but old-format checkpoint blocks
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
Expand Down Expand Up @@ -86,12 +93,26 @@ AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: MLOG_FILE_NAME incorrect:bigot/ in mysqld.1.err
FOUND 1 /len 22; hex 38000000000012860cb7809781e800066269676f7400; asc 8 bigot ;/ in mysqld.1.err
# missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
# 10.2 missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42/ in mysqld.1.err
# 10.3 missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
NOT FOUND /InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42$/ in mysqld.1.err
FOUND 1 /InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42/ in mysqld.1.err
FOUND 1 /Downgrade after a crash is not supported\. The redo log was created with MariaDB 10\.3\.1/ in mysqld.1.err
# Empty 10.3 redo log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
COUNT(*)
1
FOUND 1 /InnoDB: Downgrading redo log:/ in mysqld.1.err
# Minimal MariaDB 10.1.21 encrypted redo log
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
Expand Down
62 changes: 58 additions & 4 deletions mysql-test/suite/innodb/t/log_corruption.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
--source include/have_innodb_16k.inc

--disable_query_log
call mtr.add_suppression("InnoDB: Upgrade after a crash is not supported");
call mtr.add_suppression("InnoDB: (Up|Down)grade after a crash is not supported");
call mtr.add_suppression("InnoDB: Plugin initialization aborted");
call mtr.add_suppression("Plugin 'InnoDB' init function returned error");
call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed");
Expand All @@ -16,6 +16,7 @@ call mtr.add_suppression("InnoDB: Log scan aborted at LSN");
call mtr.add_suppression("InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42\\r?$");
call mtr.add_suppression("InnoDB: Obtaining redo log encryption key version 1 failed");
call mtr.add_suppression("InnoDB: Decrypting checkpoint failed");
call mtr.add_suppression("InnoDB: Are you sure you are using the right ib_logfiles to start up the database\\? Log sequence number in the ib_logfiles is 1213964,");
--enable_query_log

let bugdir= $MYSQLTEST_VARDIR/tmp/log_corruption;
Expand Down Expand Up @@ -140,6 +141,24 @@ eval $check_no_innodb;
let SEARCH_PATTERN=InnoDB: Upgrade after a crash is not supported. This redo log was created before MariaDB 10\\.2\\.2, and it appears corrupted;
--source include/search_pattern_in_file.inc

--echo # empty redo log from before MariaDB 10.2.2
perl;
die unless open OUT, "+<", "$ENV{bugdir}/ib_logfile0";
binmode OUT;
die unless seek(OUT, 0x800, 0);
print OUT pack("NnnNx[496]N", 0x80000944, 12, 12, 0, 0xb2a);
close OUT or die;
EOF
--let $restart_parameters= $dirs --innodb-force-recovery=5 --innodb-log-file-size=1m
--source include/start_mysqld.inc
SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
--source include/shutdown_mysqld.inc
--let SEARCH_PATTERN= InnoDB: Upgrading redo log:
--source include/search_pattern_in_file.inc
--let $restart_parameters= $dirs

--echo # redo log from "after" MariaDB 10.2.2, but with invalid header checksum
perl;
die unless open OUT, "+<", "$ENV{bugdir}/ib_logfile0";
Expand All @@ -165,7 +184,7 @@ EOF
--source include/start_mysqld.inc
eval $check_no_innodb;
--source include/shutdown_mysqld.inc
let SEARCH_PATTERN=InnoDB: Unsupported redo log format. The redo log was created with malicious intentions, or perhaps\. Please follow the instructions at http://dev.mysql.com/doc/refman/5.7/en/upgrading-downgrading.html;
let SEARCH_PATTERN=InnoDB: Unsupported redo log format. The redo log was created with malicious intentions, or perhaps\.;
--source include/search_pattern_in_file.inc

--echo # valid header, but old-format checkpoint blocks
Expand Down Expand Up @@ -321,7 +340,7 @@ let SEARCH_PATTERN=InnoDB: MLOG_FILE_NAME incorrect:bigot;
--let SEARCH_PATTERN= len 22; hex 38000000000012860cb7809781e800066269676f7400; asc 8 bigot ;
--source include/search_pattern_in_file.inc

--echo # missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
--echo # 10.2 missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
perl;
die unless open OUT, "+<", "$ENV{bugdir}/ib_logfile0";
binmode OUT;
Expand Down Expand Up @@ -349,7 +368,42 @@ EOF
--source include/start_mysqld.inc
eval $check_no_innodb;
--source include/shutdown_mysqld.inc
--let SEARCH_PATTERN= InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42\$
--let SEARCH_PATTERN= InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42
--source include/search_pattern_in_file.inc

--echo # 10.3 missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT
perl;
die unless open OUT, "+<", "$ENV{bugdir}/ib_logfile0";
binmode OUT;
print OUT pack("Nx[5]nx[5]", 103, 0x1286), "MariaDB 10.3.1";
print OUT pack("x[478]N", 0x85021a0f);
close OUT or die;
EOF

--source include/start_mysqld.inc
eval $check_no_innodb;
--source include/shutdown_mysqld.inc
--let SEARCH_PATTERN= InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= Downgrade after a crash is not supported\. The redo log was created with MariaDB 10\.3\.1
--source include/search_pattern_in_file.inc

--echo # Empty 10.3 redo log
perl;
die unless open OUT, "+<", "$ENV{bugdir}/ib_logfile0";
binmode OUT;
die unless seek(OUT, 0x800, 0);
print OUT pack("NnnNx[496]N", 0x80000944, 12, 12, 1, 0x46c8a2a2);
close OUT or die;
EOF

--let $restart_parameters= $dirs --innodb-force-recovery=5 --innodb-log-file-size=1m
--source include/start_mysqld.inc
SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
--source include/shutdown_mysqld.inc
--let SEARCH_PATTERN= InnoDB: Downgrading redo log:
--source include/search_pattern_in_file.inc

--echo # Minimal MariaDB 10.1.21 encrypted redo log
Expand Down
4 changes: 3 additions & 1 deletion storage/innobase/include/log0log.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2009, Google Inc.
Copyright (c) 2017, MariaDB Corporation.
Copyright (c) 2017, 2018, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
Expand Down Expand Up @@ -513,6 +513,8 @@ or the MySQL version that created the redo log file. */
/** The redo log format identifier corresponding to the current format version.
Stored in LOG_HEADER_FORMAT. */
#define LOG_HEADER_FORMAT_CURRENT 1
/** The MariaDB 10.3.2 log format */
#define LOG_HEADER_FORMAT_10_3 103
/** Encrypted MariaDB redo log */
#define LOG_HEADER_FORMAT_ENCRYPTED (1U<<31)

Expand Down
80 changes: 76 additions & 4 deletions storage/innobase/log/log0recv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2017, MariaDB Corporation.
Copyright (c) 2013, 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Expand Down Expand Up @@ -907,6 +907,58 @@ recv_log_format_0_recover(lsn_t lsn)
return(DB_SUCCESS);
}

/** Determine if a redo log from MariaDB 10.3 is clean.
@return error code
@retval DB_SUCCESS if the redo log is clean
@retval DB_CORRUPTION if the redo log is corrupted
@retval DB_ERROR if the redo log is not empty */
static
dberr_t
recv_log_recover_10_3()
{
log_group_t* group = &log_sys->log;
const lsn_t lsn = group->lsn;
const lsn_t source_offset = log_group_calc_lsn_offset(lsn, group);
const ulint page_no
= (ulint) (source_offset / univ_page_size.physical());
byte* buf = log_sys->buf;

fil_io(IORequestLogRead, true,
page_id_t(SRV_LOG_SPACE_FIRST_ID, page_no),
univ_page_size,
(ulint) ((source_offset & ~(OS_FILE_LOG_BLOCK_SIZE - 1))
% univ_page_size.physical()),
OS_FILE_LOG_BLOCK_SIZE, buf, NULL);

if (log_block_calc_checksum(buf) != log_block_get_checksum(buf)) {
return(DB_CORRUPTION);
}

if (group->is_encrypted()) {
log_crypt(buf, lsn, OS_FILE_LOG_BLOCK_SIZE, true);
}

/* On a clean shutdown, the redo log will be logically empty
after the checkpoint lsn. */

if (log_block_get_data_len(buf)
!= (source_offset & (OS_FILE_LOG_BLOCK_SIZE - 1))) {
return(DB_ERROR);
}

/* Mark the redo log for downgrading. */
srv_log_file_size = 0;
recv_sys->parse_start_lsn = recv_sys->recovered_lsn
= recv_sys->scanned_lsn
= recv_sys->mlog_checkpoint_lsn = lsn;
log_sys->last_checkpoint_lsn = log_sys->next_checkpoint_lsn
= log_sys->lsn = log_sys->write_lsn
= log_sys->current_flush_lsn = log_sys->flushed_to_disk_lsn
= lsn;
log_sys->next_checkpoint_no = 0;
return(DB_SUCCESS);
}

/** Find the latest checkpoint in the log header.
@param[out] max_field LOG_CHECKPOINT_1 or LOG_CHECKPOINT_2
@return error code or DB_SUCCESS */
Expand Down Expand Up @@ -938,18 +990,24 @@ recv_find_max_checkpoint(ulint* max_field)
return(DB_CORRUPTION);
}

char creator[LOG_HEADER_CREATOR_END - LOG_HEADER_CREATOR + 1];

memcpy(creator, buf + LOG_HEADER_CREATOR, sizeof creator);
/* Ensure that the string is NUL-terminated. */
creator[LOG_HEADER_CREATOR_END - LOG_HEADER_CREATOR] = 0;

switch (group->format) {
case 0:
return(recv_find_max_checkpoint_0(&group, max_field));
case LOG_HEADER_FORMAT_CURRENT:
case LOG_HEADER_FORMAT_CURRENT | LOG_HEADER_FORMAT_ENCRYPTED:
case LOG_HEADER_FORMAT_10_3:
case LOG_HEADER_FORMAT_10_3 | LOG_HEADER_FORMAT_ENCRYPTED:
break;
default:
/* Ensure that the string is NUL-terminated. */
buf[LOG_HEADER_CREATOR_END] = 0;
ib::error() << "Unsupported redo log format."
" The redo log was created"
" with " << buf + LOG_HEADER_CREATOR <<
" with " << creator <<
". Please follow the instructions at "
REFMAN "upgrading-downgrading.html";
/* Do not issue a message about a possibility
Expand Down Expand Up @@ -1018,6 +1076,20 @@ recv_find_max_checkpoint(ulint* max_field)
return(DB_ERROR);
}

switch (group->format) {
case LOG_HEADER_FORMAT_10_3:
case LOG_HEADER_FORMAT_10_3 | LOG_HEADER_FORMAT_ENCRYPTED:
dberr_t err = recv_log_recover_10_3();
if (err != DB_SUCCESS) {
ib::error()
<< "Downgrade after a crash is not supported."
" The redo log was created with " << creator
<< (err == DB_ERROR
? "." : ", and it appears corrupted.");
}
return(err);
}

return(DB_SUCCESS);
}

Expand Down
8 changes: 6 additions & 2 deletions storage/innobase/srv/srv0start.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2017, MariaDB Corporation.
Copyright (c) 2013, 2018, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
Expand Down Expand Up @@ -1413,7 +1413,11 @@ srv_prepare_to_delete_redo_log_files(
{
ib::info info;
if (srv_log_file_size == 0) {
info << "Upgrading redo log: ";
info << ((log_sys->log.format
& ~LOG_HEADER_FORMAT_ENCRYPTED)
!= LOG_HEADER_FORMAT_10_3
? "Upgrading redo log: "
: "Downgrading redo log: ");
} else if (n_files != srv_n_log_files
|| srv_log_file_size
!= srv_log_file_size_requested) {
Expand Down

0 comments on commit d1cf9b1

Please sign in to comment.