Commit 81a5b6cc authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-17433 Allow InnoDB start up with empty ib_logfile0 from mariabackup --prepare

A prepared backup from Mariabackup does not really need to contain any
redo log file, because all log will have been applied to the data files.

When the user copies a prepared backup to a data directory (overwriting
existing files), it could happen that the data directory already contained
redo log files from the past. mariabackup --copy-back) would delete the
old redo log files, but a user’s own copying script might not do that.
To prevent corruption caused by mixing an old redo log file with data
files from a backup, starting with MDEV-13311, Mariabackup would create
a zero-length ib_logfile0 that would prevent startup.

Actually, there is no need to prevent InnoDB from starting up when a
single zero-length file ib_logfile0 is present. Only if there exist
multiple data files of different lengths, then we should refuse to
start up due to inconsistency. A single zero-length ib_logfile0 should
be treated as if the log files were missing: create new log files
according to the configuration.

open_log_file(): Remove. There is no need to open the log files
at this point, because os_file_get_status() already determined
the size of the file.

innobase_start_or_create_for_mysql(): Move the creation of new
log files a little later, not when finding out that the first log
file does not exist, but after finding out that it does not exist
or it exists as a zero-length file.
parent b8944e89
...@@ -3,7 +3,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES ...@@ -3,7 +3,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb' WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED'); AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /InnoDB: Log file .*ib_logfile0 size 0 is too small/ in mysqld.1.err FOUND 1 /InnoDB: Log file .*ib_logfile1 is of different size .* bytes than other log files 0 bytes!/ in mysqld.1.err
CHECK TABLE t1; CHECK TABLE t1;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 check status OK test.t1 check status OK
......
...@@ -43,7 +43,7 @@ eval $check_no_innodb; ...@@ -43,7 +43,7 @@ eval $check_no_innodb;
--move_file $MYSQLD_DATADIR/ib_logfile.old $MYSQLD_DATADIR/ib_logfile.0 --move_file $MYSQLD_DATADIR/ib_logfile.old $MYSQLD_DATADIR/ib_logfile.0
--source include/shutdown_mysqld.inc --source include/shutdown_mysqld.inc
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err; let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
let SEARCH_PATTERN= InnoDB: Log file .*ib_logfile0 size 0 is too small; let SEARCH_PATTERN= InnoDB: Log file .*ib_logfile1 is of different size .* bytes than other log files 0 bytes!;
--source include/search_pattern_in_file.inc --source include/search_pattern_in_file.inc
--source include/start_mysqld.inc --source include/start_mysqld.inc
CHECK TABLE t1; CHECK TABLE t1;
......
...@@ -570,34 +570,6 @@ create_log_files_rename( ...@@ -570,34 +570,6 @@ create_log_files_rename(
return(err); return(err);
} }
/*********************************************************************//**
Opens a log file.
@return DB_SUCCESS or error code */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
open_log_file(
/*==========*/
pfs_os_file_t* file, /*!< out: file handle */
const char* name, /*!< in: log file name */
os_offset_t* size) /*!< out: file size */
{
bool ret;
*file = os_file_create(innodb_log_file_key, name,
OS_FILE_OPEN, OS_FILE_AIO,
OS_LOG_FILE, srv_read_only_mode, &ret);
if (!ret) {
ib::error() << "Unable to open '" << name << "'";
return(DB_ERROR);
}
*size = os_file_get_size(*file);
ret = os_file_close(*file);
ut_a(ret);
return(DB_SUCCESS);
}
/*********************************************************************//** /*********************************************************************//**
Create undo tablespace. Create undo tablespace.
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
...@@ -1975,8 +1947,9 @@ innobase_start_or_create_for_mysql() ...@@ -1975,8 +1947,9 @@ innobase_start_or_create_for_mysql()
return(srv_init_abort(err)); return(srv_init_abort(err));
} }
} else { } else {
srv_log_file_size = 0;
for (i = 0; i < SRV_N_LOG_FILES_MAX; i++) { for (i = 0; i < SRV_N_LOG_FILES_MAX; i++) {
os_offset_t size;
os_file_stat_t stat_info; os_file_stat_t stat_info;
sprintf(logfilename + dirnamelen, sprintf(logfilename + dirnamelen,
...@@ -1994,40 +1967,6 @@ innobase_start_or_create_for_mysql() ...@@ -1994,40 +1967,6 @@ innobase_start_or_create_for_mysql()
== SRV_OPERATION_RESTORE_EXPORT) { == SRV_OPERATION_RESTORE_EXPORT) {
return(DB_SUCCESS); return(DB_SUCCESS);
} }
if (flushed_lsn
< static_cast<lsn_t>(1000)) {
ib::error()
<< "Cannot create"
" log files because"
" data files are"
" corrupt or the"
" database was not"
" shut down cleanly"
" after creating"
" the data files.";
return(srv_init_abort(
DB_ERROR));
}
err = create_log_files(
logfilename, dirnamelen,
flushed_lsn, logfile0);
if (err == DB_SUCCESS) {
err = create_log_files_rename(
logfilename,
dirnamelen,
flushed_lsn, logfile0);
}
if (err != DB_SUCCESS) {
return(srv_init_abort(err));
}
/* Suppress the message about
crash recovery. */
flushed_lsn = log_get_lsn();
goto files_checked;
} }
/* opened all files */ /* opened all files */
...@@ -2038,12 +1977,7 @@ innobase_start_or_create_for_mysql() ...@@ -2038,12 +1977,7 @@ innobase_start_or_create_for_mysql()
return(srv_init_abort(DB_ERROR)); return(srv_init_abort(DB_ERROR));
} }
err = open_log_file(&files[i], logfilename, &size); const os_offset_t size = stat_info.size;
if (err != DB_SUCCESS) {
return(srv_init_abort(err));
}
ut_a(size != (os_offset_t) -1); ut_a(size != (os_offset_t) -1);
if (size & (OS_FILE_LOG_BLOCK_SIZE - 1)) { if (size & (OS_FILE_LOG_BLOCK_SIZE - 1)) {
...@@ -2068,8 +2002,13 @@ innobase_start_or_create_for_mysql() ...@@ -2068,8 +2002,13 @@ innobase_start_or_create_for_mysql()
/* The first log file must consist of /* The first log file must consist of
at least the following 512-byte pages: at least the following 512-byte pages:
header, checkpoint page 1, empty, header, checkpoint page 1, empty,
checkpoint page 2, redo log page(s) */ checkpoint page 2, redo log page(s).
if (size <= OS_FILE_LOG_BLOCK_SIZE * 4) {
Mariabackup --prepare would create an
empty ib_logfile0. Tolerate it if there
are no other ib_logfile* files. */
if ((size != 0 || i != 0)
&& size <= OS_FILE_LOG_BLOCK_SIZE * 4) {
ib::error() << "Log file " ib::error() << "Log file "
<< logfilename << " size " << logfilename << " size "
<< size << " is too small"; << size << " is too small";
...@@ -2086,6 +2025,39 @@ innobase_start_or_create_for_mysql() ...@@ -2086,6 +2025,39 @@ innobase_start_or_create_for_mysql()
} }
} }
if (srv_log_file_size == 0) {
if (flushed_lsn < lsn_t(1000)) {
ib::error()
<< "Cannot create log files because"
" data files are corrupt or the"
" database was not shut down cleanly"
" after creating the data files.";
return srv_init_abort(DB_ERROR);
}
strcpy(logfilename + dirnamelen, "ib_logfile0");
srv_log_file_size = srv_log_file_size_requested;
err = create_log_files(
logfilename, dirnamelen,
flushed_lsn, logfile0);
if (err == DB_SUCCESS) {
err = create_log_files_rename(
logfilename, dirnamelen,
flushed_lsn, logfile0);
}
if (err != DB_SUCCESS) {
return(srv_init_abort(err));
}
/* Suppress the message about
crash recovery. */
flushed_lsn = log_get_lsn();
goto files_checked;
}
srv_n_log_files_found = i; srv_n_log_files_found = i;
/* Create the in-memory file space objects. */ /* Create the in-memory file space objects. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment