Commit 86dc7b4d authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-24626 Remove synchronous write of page0 file during file creation

During data file creation, InnoDB holds dict_sys mutex, tries to
write page 0 of the file and flushes the file. This not only causing
unnecessary contention but also a deviation from the write-ahead
logging protocol.

The clean sequence of operations is that we first start a dictionary
transaction and write SYS_TABLES and SYS_INDEXES records that identify
the tablespace. Then, we durably write a FILE_CREATE record to the
write-ahead log and create the file.

Recovery should not unnecessarily insist that the first page of each
data file that is referred to by the redo log is valid. It must be
enough that page 0 of the tablespace can be initialized based on the
redo log contents.

We introduce a new data structure deferred_spaces that keeps track
of corrupted-looking files during recovery. The data structure holds
the last LSN of a FILE_ record referring to the data file, the
tablespace identifier, and the last known file name.

There are two scenarios can happen during recovery:
i) Sufficient memory: InnoDB can reconstruct the
tablespace after parsing all redo log records.

ii) Insufficient memory(multiple apply phase): InnoDB should
store the deferred tablespace redo logs even though
tablespace is not present. InnoDB should start constructing
the tablespace when it first encounters deferred tablespace
id.

Mariabackup copies the zero filled ibd file in backup_fix_ddl() as
the extension of .new file. Mariabackup test case does page flushing
when it deals with DDL operation during backup operation.

fil_ibd_create(): Remove the write of page0 and flushing of file

fil_ibd_load(): Return FIL_LOAD_DEFER if the tablespace has
zero filled page0

Datafile: Clean up the error handling, and do not report errors
if we are in the middle of recovery. The caller will check
Datafile::m_defer.

fil_node_t::deferred: Indicates whether the tablespace loading was
deferred during recovery

FIL_LOAD_DEFER: Returned by fil_ibd_load() to indicate that tablespace
file was cannot be loaded.

recv_sys_t::recover_deferred(): Invoke deferred_spaces.create() to
initialize fil_space_t based on buffered metadata and records to
initialize page 0. Ignore the flags in fil_name_t, because they are
intentionally invalid.

fil_name_process(): Update deferred_spaces.

recv_sys_t::parse(): Store the redo log if the tablespace id
is present in deferred spaces

recv_sys_t::recover_low(): Should recover the first page of
the tablespace even though the tablespace instance is not
present

recv_sys_t::apply(): Initialize the deferred tablespace
before applying the deferred tablespace records

recv_validate_tablespace(): Skip the validation for deferred_spaces.

recv_rename_files(): Moved and revised from recv_sys_t::apply().
For deferred-recovery tablespaces, do not attempt to rename the
file if a deferred-recovery tablespace is associated with the name.

recv_recovery_from_checkpoint_start(): Invoke recv_rename_files()
and initialize all deferred tablespaces before applying redo log.

fil_node_t::read_page0(): Skip page0 validation if the tablespace
is deferred

buf_page_create_deferred(): A variant of buf_page_create() when
the fil_space_t is not available yet

This is joint work with Thirunarayanan Balathandayuthapani,
who implemented an initial prototype.
parent c290c0d7
...@@ -364,6 +364,7 @@ xb_fil_cur_result_t xb_fil_cur_read(xb_fil_cur_t* cursor, ...@@ -364,6 +364,7 @@ xb_fil_cur_result_t xb_fil_cur_read(xb_fil_cur_t* cursor,
ib_int64_t offset; ib_int64_t offset;
ib_int64_t to_read; ib_int64_t to_read;
const ulint page_size = cursor->page_size; const ulint page_size = cursor->page_size;
bool defer = false;
xb_ad(!cursor->is_system() || page_size == srv_page_size); xb_ad(!cursor->is_system() || page_size == srv_page_size);
cursor->read_filter->get_next_batch(&cursor->read_filter_ctxt, cursor->read_filter->get_next_batch(&cursor->read_filter_ctxt,
...@@ -418,13 +419,15 @@ xb_fil_cur_result_t xb_fil_cur_read(xb_fil_cur_t* cursor, ...@@ -418,13 +419,15 @@ xb_fil_cur_result_t xb_fil_cur_read(xb_fil_cur_t* cursor,
ret = XB_FIL_CUR_ERROR; ret = XB_FIL_CUR_ERROR;
goto func_exit; goto func_exit;
} }
defer = space->is_deferred();
/* check pages for corruption and re-read if necessary. i.e. in case of /* check pages for corruption and re-read if necessary. i.e. in case of
partially written pages */ partially written pages */
for (page = cursor->buf, i = 0; i < npages; for (page = cursor->buf, i = 0; i < npages;
page += page_size, i++) { page += page_size, i++) {
unsigned page_no = cursor->buf_page_no + i; unsigned page_no = cursor->buf_page_no + i;
if (page_is_corrupted(page, page_no, cursor, space)){ if (!defer && page_is_corrupted(page, page_no, cursor, space)) {
retry_count--; retry_count--;
if (retry_count == 0) { if (retry_count == 0) {
......
...@@ -510,7 +510,8 @@ bool CorruptedPages::empty() const ...@@ -510,7 +510,8 @@ bool CorruptedPages::empty() const
} }
static void xb_load_single_table_tablespace(const std::string &space_name, static void xb_load_single_table_tablespace(const std::string &space_name,
bool set_size); bool set_size,
ulint defer_space_id=0);
static void xb_data_files_close(); static void xb_data_files_close();
static fil_space_t* fil_space_get_by_name(const char* name); static fil_space_t* fil_space_get_by_name(const char* name);
...@@ -587,7 +588,8 @@ xtrabackup_add_datasink(ds_ctxt_t *ds) ...@@ -587,7 +588,8 @@ xtrabackup_add_datasink(ds_ctxt_t *ds)
typedef void (*process_single_tablespace_func_t)(const char *dirname, typedef void (*process_single_tablespace_func_t)(const char *dirname,
const char *filname, const char *filname,
bool is_remote, bool is_remote,
bool skip_node_page0); bool skip_node_page0,
ulint defer_space_id);
static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback); static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback);
/* ======== Datafiles iterator ======== */ /* ======== Datafiles iterator ======== */
...@@ -1680,7 +1682,8 @@ debug_sync_point(const char *name) ...@@ -1680,7 +1682,8 @@ debug_sync_point(const char *name)
static std::set<std::string> tables_for_export; static std::set<std::string> tables_for_export;
static void append_export_table(const char *dbname, const char *tablename, static void append_export_table(const char *dbname, const char *tablename,
bool is_remote, bool skip_node_page0) bool is_remote, bool skip_node_page0,
ulint defer_space_id)
{ {
if(dbname && tablename && !is_remote) if(dbname && tablename && !is_remote)
{ {
...@@ -3271,11 +3274,14 @@ xb_fil_io_init() ...@@ -3271,11 +3274,14 @@ xb_fil_io_init()
node page0 will be read, and it's size and free pages limit node page0 will be read, and it's size and free pages limit
will be set from page 0, what is neccessary for checking and fixing corrupted will be set from page 0, what is neccessary for checking and fixing corrupted
pages. pages.
@param[in] defer_space_id use the space id to create space object
when there is deferred tablespace
*/ */
static void xb_load_single_table_tablespace(const char *dirname, static void xb_load_single_table_tablespace(const char *dirname,
const char *filname, const char *filname,
bool is_remote, bool is_remote,
bool skip_node_page0) bool skip_node_page0,
ulint defer_space_id)
{ {
ut_ad(srv_operation == SRV_OPERATION_BACKUP ut_ad(srv_operation == SRV_OPERATION_BACKUP
|| srv_operation == SRV_OPERATION_RESTORE_DELTA || srv_operation == SRV_OPERATION_RESTORE_DELTA
...@@ -3298,6 +3304,7 @@ static void xb_load_single_table_tablespace(const char *dirname, ...@@ -3298,6 +3304,7 @@ static void xb_load_single_table_tablespace(const char *dirname,
lsn_t flush_lsn; lsn_t flush_lsn;
dberr_t err; dberr_t err;
fil_space_t *space; fil_space_t *space;
bool defer = false;
name = static_cast<char*>(ut_malloc_nokey(pathlen)); name = static_cast<char*>(ut_malloc_nokey(pathlen));
...@@ -3329,14 +3336,30 @@ static void xb_load_single_table_tablespace(const char *dirname, ...@@ -3329,14 +3336,30 @@ static void xb_load_single_table_tablespace(const char *dirname,
} }
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
file->m_defer = false;
err = file->validate_first_page(&flush_lsn); err = file->validate_first_page(&flush_lsn);
if (err != DB_CORRUPTION) {
if (file->m_defer) {
if (defer_space_id) {
defer = true;
file->set_space_id(defer_space_id);
file->set_flags(FSP_FLAGS_PAGE_SSIZE());
err = DB_SUCCESS;
break;
}
} else if (err != DB_CORRUPTION) {
break; break;
} }
my_sleep(1000); my_sleep(1000);
} }
if (!defer && file->m_defer) {
delete file;
ut_free(name);
return;
}
bool is_empty_file = file->exists() && file->is_empty_file(); bool is_empty_file = file->exists() && file->is_empty_file();
if (err == DB_SUCCESS && file->space_id() != SRV_TMP_SPACE_ID) { if (err == DB_SUCCESS && file->space_id() != SRV_TMP_SPACE_ID) {
...@@ -3345,9 +3368,11 @@ static void xb_load_single_table_tablespace(const char *dirname, ...@@ -3345,9 +3368,11 @@ static void xb_load_single_table_tablespace(const char *dirname,
FIL_TYPE_TABLESPACE, NULL/* TODO: crypt_data */); FIL_TYPE_TABLESPACE, NULL/* TODO: crypt_data */);
ut_a(space != NULL); ut_a(space != NULL);
space->add(file->filepath(), fil_node_t* node= space->add(
file->filepath(),
skip_node_page0 ? file->detach() : pfs_os_file_t(), skip_node_page0 ? file->detach() : pfs_os_file_t(),
0, false, false); 0, false, false);
node->deferred= defer;
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
space->read_page0(); space->read_page0();
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
...@@ -3368,7 +3393,8 @@ static void xb_load_single_table_tablespace(const char *dirname, ...@@ -3368,7 +3393,8 @@ static void xb_load_single_table_tablespace(const char *dirname,
} }
static void xb_load_single_table_tablespace(const std::string &space_name, static void xb_load_single_table_tablespace(const std::string &space_name,
bool skip_node_page0) bool skip_node_page0,
ulint defer_space_id)
{ {
std::string name(space_name); std::string name(space_name);
bool is_remote= access((name + ".ibd").c_str(), R_OK) != 0; bool is_remote= access((name + ".ibd").c_str(), R_OK) != 0;
...@@ -3379,14 +3405,13 @@ static void xb_load_single_table_tablespace(const std::string &space_name, ...@@ -3379,14 +3405,13 @@ static void xb_load_single_table_tablespace(const std::string &space_name,
buf[sizeof buf - 1]= '\0'; buf[sizeof buf - 1]= '\0';
const char *dbname= buf; const char *dbname= buf;
char *p= strchr(buf, '/'); char *p= strchr(buf, '/');
if (p == 0) if (!p)
die("Unexpected tablespace %s filename %s", space_name.c_str(), die("Unexpected tablespace %s filename %s", space_name.c_str(),
name.c_str()); name.c_str());
ut_a(p);
*p= 0; *p= 0;
const char *tablename= p + 1; const char *tablename= p + 1;
xb_load_single_table_tablespace(dbname, tablename, is_remote, xb_load_single_table_tablespace(dbname, tablename, is_remote,
skip_node_page0); skip_node_page0, defer_space_id);
} }
/** Scan the database directories under the MySQL datadir, looking for /** Scan the database directories under the MySQL datadir, looking for
...@@ -3425,12 +3450,11 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback) ...@@ -3425,12 +3450,11 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
/* General tablespaces are always at the first level of the /* General tablespaces are always at the first level of the
data home dir */ data home dir */
if (dbinfo.type == OS_FILE_TYPE_FILE) { if (dbinfo.type != OS_FILE_TYPE_FILE) {
bool is_isl = ends_with(dbinfo.name, ".isl"); const bool is_isl = ends_with(dbinfo.name, ".isl");
bool is_ibd = !is_isl && ends_with(dbinfo.name,".ibd"); if (is_isl || ends_with(dbinfo.name,".ibd")) {
(*callback)(nullptr, dbinfo.name, is_isl,
if (is_isl || is_ibd) { false, 0);
(*callback)(NULL, dbinfo.name, is_isl, false);
} }
} }
...@@ -3486,7 +3510,7 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback) ...@@ -3486,7 +3510,7 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
if (strlen(fileinfo.name) > 4) { if (strlen(fileinfo.name) > 4) {
bool is_isl= false; bool is_isl= false;
if (ends_with(fileinfo.name, ".ibd") || ((is_isl = ends_with(fileinfo.name, ".isl")))) if (ends_with(fileinfo.name, ".ibd") || ((is_isl = ends_with(fileinfo.name, ".isl"))))
(*callback)(dbinfo.name, fileinfo.name, is_isl, false); (*callback)(dbinfo.name, fileinfo.name, is_isl, false, 0);
} }
} }
...@@ -4567,9 +4591,9 @@ FTWRL. This ensures consistent backup in presence of DDL. ...@@ -4567,9 +4591,9 @@ FTWRL. This ensures consistent backup in presence of DDL.
*/ */
void backup_fix_ddl(CorruptedPages &corrupted_pages) void backup_fix_ddl(CorruptedPages &corrupted_pages)
{ {
std::set<std::string> new_tables;
std::set<std::string> dropped_tables; std::set<std::string> dropped_tables;
std::map<std::string, std::string> renamed_tables; std::map<std::string, std::string> renamed_tables;
space_id_to_name_t new_tables;
/* Disable further DDL on backed up tables (only needed for --no-lock).*/ /* Disable further DDL on backed up tables (only needed for --no-lock).*/
pthread_mutex_lock(&backup_mutex); pthread_mutex_lock(&backup_mutex);
...@@ -4619,7 +4643,7 @@ void backup_fix_ddl(CorruptedPages &corrupted_pages) ...@@ -4619,7 +4643,7 @@ void backup_fix_ddl(CorruptedPages &corrupted_pages)
if (ddl_tracker.drops.find(id) == ddl_tracker.drops.end()) { if (ddl_tracker.drops.find(id) == ddl_tracker.drops.end()) {
dropped_tables.erase(name); dropped_tables.erase(name);
new_tables.insert(name); new_tables[id] = name;
if (opt_log_innodb_page_corruption) if (opt_log_innodb_page_corruption)
corrupted_pages.drop_space(id); corrupted_pages.drop_space(id);
} }
...@@ -4661,12 +4685,12 @@ void backup_fix_ddl(CorruptedPages &corrupted_pages) ...@@ -4661,12 +4685,12 @@ void backup_fix_ddl(CorruptedPages &corrupted_pages)
} }
DBUG_EXECUTE_IF("check_mdl_lock_works", DBUG_ASSERT(new_tables.size() == 0);); DBUG_EXECUTE_IF("check_mdl_lock_works", DBUG_ASSERT(new_tables.size() == 0););
for (std::set<std::string>::iterator iter = new_tables.begin();
iter != new_tables.end(); iter++) { for (const auto &t : new_tables) {
const char *space_name = iter->c_str(); if (!check_if_skip_table(t.second.c_str())) {
if (check_if_skip_table(space_name)) xb_load_single_table_tablespace(t.second, false,
continue; t.first);
xb_load_single_table_tablespace(*iter, false); }
} }
datafiles_iter_t it2; datafiles_iter_t it2;
...@@ -4677,6 +4701,7 @@ void backup_fix_ddl(CorruptedPages &corrupted_pages) ...@@ -4677,6 +4701,7 @@ void backup_fix_ddl(CorruptedPages &corrupted_pages)
std::string dest_name= filename_to_spacename( std::string dest_name= filename_to_spacename(
node->name, strlen(node->name)); node->name, strlen(node->name));
dest_name.append(".new"); dest_name.append(".new");
xtrabackup_copy_datafile(node, 0, dest_name.c_str(), wf_write_through, xtrabackup_copy_datafile(node, 0, dest_name.c_str(), wf_write_through,
corrupted_pages); corrupted_pages);
} }
......
SET GLOBAL innodb_file_per_table=ON; SET GLOBAL innodb_file_per_table=ON;
FLUSH TABLES; FLUSH TABLES;
CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB;
# restart
CREATE TABLE t3(a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t3(a INT PRIMARY KEY) ENGINE=InnoDB;
BEGIN; BEGIN;
INSERT INTO t3 VALUES (33101),(347); INSERT INTO t3 VALUES (33101),(347);
...@@ -31,7 +32,7 @@ WHERE engine = 'innodb' ...@@ -31,7 +32,7 @@ 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: Ignoring data file '.*t[23].ibd' with space ID/ in mysqld.1.err FOUND 1 /InnoDB: Ignoring data file '.*t[23].ibd' with space ID/ in mysqld.1.err
FOUND 1 /InnoDB: Tablespace \d+ was not found at .*t1.ibd/ in mysqld.1.err NOT FOUND /InnoDB: Tablespace \d+ was not found at .*t1.ibd/ in mysqld.1.err
FOUND 1 /InnoDB: Tablespace \d+ was not found at .*t3.ibd/ in mysqld.1.err FOUND 1 /InnoDB: Tablespace \d+ was not found at .*t3.ibd/ in mysqld.1.err
FOUND 2 /InnoDB: Set innodb_force_recovery=1 to ignore this and to permanently lose all changes to the tablespace/ in mysqld.1.err FOUND 2 /InnoDB: Set innodb_force_recovery=1 to ignore this and to permanently lose all changes to the tablespace/ in mysqld.1.err
# Fault 4: Missing data file # Fault 4: Missing data file
...@@ -54,7 +55,7 @@ WHERE engine = 'innodb' ...@@ -54,7 +55,7 @@ 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
NOT FOUND /\[Note\] InnoDB: Cannot read first page of .*t2.ibd/ in mysqld.1.err NOT FOUND /\[Note\] InnoDB: Cannot read first page of .*t2.ibd/ in mysqld.1.err
FOUND 1 /\[ERROR\] InnoDB: Datafile .*t2.*\. Cannot determine the space ID from the first 64 pages/ in mysqld.1.err FOUND 1 /.*\[ERROR\] InnoDB: Cannot apply log to \[page id: space=[1-9][0-9]*, page number=3\] of corrupted file './test/t2\.ibd'/ in mysqld.1.err
# restart # restart
SELECT * FROM t2; SELECT * FROM t2;
a a
...@@ -85,27 +86,6 @@ INSERT INTO u6 VALUES(2); ...@@ -85,27 +86,6 @@ INSERT INTO u6 VALUES(2);
# Kill the server # Kill the server
# Fault 6: All-zero data file and innodb_force_recovery # Fault 6: All-zero data file and innodb_force_recovery
# restart: --innodb-force-recovery=1 # restart: --innodb-force-recovery=1
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /\[Note\] InnoDB: Header page consists of zero bytes in datafile: .*u1.ibd/ in mysqld.1.err
FOUND 1 /\[ERROR\] InnoDB: Datafile .*u1.*\. Cannot determine the space ID from the first 64 pages/ in mysqld.1.err
NOT FOUND /\[Note\] InnoDB: Cannot read first page of .*u2.ibd/ in mysqld.1.err
# Fault 7: Missing or wrong data file and innodb_force_recovery
# restart: --innodb-force-recovery=1
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /\[Note\] InnoDB: Header page consists of zero bytes in datafile: .*u1.ibd/ in mysqld.1.err
FOUND 1 /InnoDB: At LSN: \d+: unable to open file .*u[1-5].ibd for tablespace/ in mysqld.1.err
FOUND 1 /\[ERROR\] InnoDB: Cannot replay rename of tablespace \d+ from '.*u4.ibd' to '.*u6.ibd' because the target file exists/ in mysqld.1.err
# restart: --innodb-force-recovery=1
FOUND 1 /\[Note\] InnoDB: Header page consists of zero bytes in datafile: .*u1.ibd/ in mysqld.1.err
FOUND 1 /InnoDB: At LSN: \d+: unable to open file .*u[1-5].ibd for tablespace/ in mysqld.1.err
FOUND 1 /\[Warning\] InnoDB: Tablespace \d+ was not found at .*u[1-5].ibd, and innodb_force_recovery was set. All redo log for this tablespace will be ignored!/ in mysqld.1.err
# restart
DROP TABLE u1,u2,u3,u6; DROP TABLE u1,u2,u3,u6;
# List of files: # List of files:
db.opt db.opt
......
...@@ -12,6 +12,7 @@ FLUSH TABLES; ...@@ -12,6 +12,7 @@ FLUSH TABLES;
CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB;
--source include/restart_mysqld.inc
--source include/no_checkpoint_start.inc --source include/no_checkpoint_start.inc
CREATE TABLE t3(a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t3(a INT PRIMARY KEY) ENGINE=InnoDB;
...@@ -120,7 +121,7 @@ eval $check_no_innodb; ...@@ -120,7 +121,7 @@ eval $check_no_innodb;
let SEARCH_PATTERN= \[Note\] InnoDB: Cannot read first page of .*t2.ibd; let SEARCH_PATTERN= \[Note\] InnoDB: Cannot read first page of .*t2.ibd;
--source include/search_pattern_in_file.inc --source include/search_pattern_in_file.inc
let SEARCH_PATTERN= \[ERROR\] InnoDB: Datafile .*t2.*\. Cannot determine the space ID from the first 64 pages; let SEARCH_PATTERN= .*\[ERROR\] InnoDB: Cannot apply log to \\[page id: space=[1-9][0-9]*, page number=3\\] of corrupted file './test/t2\\.ibd';
--source include/search_pattern_in_file.inc --source include/search_pattern_in_file.inc
# Restore t2.ibd # Restore t2.ibd
...@@ -150,13 +151,15 @@ call mtr.add_suppression("InnoDB: Cannot open datafile for read-write: '.*t2\.ib ...@@ -150,13 +151,15 @@ call mtr.add_suppression("InnoDB: Cannot open datafile for read-write: '.*t2\.ib
# The following are for aborted startup without --innodb-force-recovery: # The following are for aborted startup without --innodb-force-recovery:
call mtr.add_suppression("InnoDB: Tablespace .* was not found at .*test"); call mtr.add_suppression("InnoDB: Tablespace .* was not found at .*test");
call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1 to ignore this and to permanently lose all changes to the tablespace"); call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1 to ignore this and to permanently lose all changes to the tablespace");
call mtr.add_suppression("InnoDB: Cannot read first page of '.*test.[tu]2.ibd' I/O error"); call mtr.add_suppression("InnoDB: Cannot read first page of '.*test.[tu]2.ibd': I/O error");
call mtr.add_suppression("InnoDB: Cannot apply log to \\[page id: space=[1-9][0-9]*, page number=3\\] of corrupted file './test/t2\\.ibd'");
call mtr.add_suppression("InnoDB: Datafile '.*test.*ibd' is corrupted"); call mtr.add_suppression("InnoDB: Datafile '.*test.*ibd' is corrupted");
call mtr.add_suppression("InnoDB: Cannot replay file rename. Remove either file and try again"); call mtr.add_suppression("InnoDB: Cannot replay file rename. Remove either file and try again");
call mtr.add_suppression("InnoDB: Cannot rename.*because the target file exists"); call mtr.add_suppression("InnoDB: Cannot rename.*because the target file exists");
call mtr.add_suppression("InnoDB: Log scan aborted at LSN"); call mtr.add_suppression("InnoDB: Log scan aborted at LSN");
# The following are for the --innodb-force-recovery=1 with broken u* tables: # The following are for the --innodb-force-recovery=1 with broken u* tables:
call mtr.add_suppression("InnoDB: The size of the file .*u1\\.ibd is only 16384 bytes, should be at least 65536"); call mtr.add_suppression("InnoDB: The size of the file .*u[12]\\.ibd is only [1-9][0-9]* bytes, should be at least 65536");
call mtr.add_suppression("InnoDB: The size of tablespace file '.*test/u[12].ibd' is only");
call mtr.add_suppression("InnoDB: The error means the system cannot find the path specified"); call mtr.add_suppression("InnoDB: The error means the system cannot find the path specified");
call mtr.add_suppression("InnoDB: .*you must create directories"); call mtr.add_suppression("InnoDB: .*you must create directories");
call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: '.*u[1-5]\.ibd'"); call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: '.*u[1-5]\.ibd'");
...@@ -199,69 +202,14 @@ EOF ...@@ -199,69 +202,14 @@ EOF
--exec echo "" > $MYSQLD_DATADIR/test/u2.ibd --exec echo "" > $MYSQLD_DATADIR/test/u2.ibd
# TODO: Test with this, once
# Bug#18131883 IMPROVE INNODB ERROR MESSAGES REGARDING FILES
# has been fixed:
#--mkdir $MYSQLD_DATADIR/test/u3.ibd
--copy_file $MYSQLD_DATADIR/test/u6.ibd $MYSQLD_DATADIR/test/u4.ibd --copy_file $MYSQLD_DATADIR/test/u6.ibd $MYSQLD_DATADIR/test/u4.ibd
--let $restart_parameters= --innodb-force-recovery=1 --let $restart_parameters= --innodb-force-recovery=1
--source include/start_mysqld.inc --source include/start_mysqld.inc
eval $check_no_innodb;
let SEARCH_PATTERN= \[Note\] InnoDB: Header page consists of zero bytes in datafile: .*u1.ibd;
--source include/search_pattern_in_file.inc
let SEARCH_PATTERN= \[ERROR\] InnoDB: Datafile .*u1.*\. Cannot determine the space ID from the first 64 pages;
--source include/search_pattern_in_file.inc
# TODO: These errors should state the file name (u2.ibd) and be ignored
# in innodb-force-recovery mode once
# Bug#18131883 IMPROVE INNODB ERROR MESSAGES REGARDING FILES
# has been fixed:
let SEARCH_PATTERN= \[Note\] InnoDB: Cannot read first page of .*u2.ibd;
--source include/search_pattern_in_file.inc
--source include/shutdown_mysqld.inc
# Allow --innodb-force-recovery to start despite the broken file.
# TODO: Remove this workaround, and make --innodb-force-recovery=1
# ignore the broken file.
--remove_file $MYSQLD_DATADIR/test/u2.ibd
--echo # Fault 7: Missing or wrong data file and innodb_force_recovery
--source include/start_mysqld.inc
eval $check_no_innodb;
let SEARCH_PATTERN= \[Note\] InnoDB: Header page consists of zero bytes in datafile: .*u1.ibd;
--source include/search_pattern_in_file.inc
let SEARCH_PATTERN= InnoDB: At LSN: \d+: unable to open file .*u[1-5].ibd for tablespace;
--source include/search_pattern_in_file.inc
let SEARCH_PATTERN= \[ERROR\] InnoDB: Cannot replay rename of tablespace \d+ from '.*u4.ibd' to '.*u6.ibd' because the target file exists;
--source include/search_pattern_in_file.inc
--remove_file $MYSQLD_DATADIR/test/u6.ibd
--source include/restart_mysqld.inc
let SEARCH_PATTERN= \[Note\] InnoDB: Header page consists of zero bytes in datafile: .*u1.ibd;
--source include/search_pattern_in_file.inc
let SEARCH_PATTERN= InnoDB: At LSN: \d+: unable to open file .*u[1-5].ibd for tablespace;
--source include/search_pattern_in_file.inc
let SEARCH_PATTERN= \[Warning\] InnoDB: Tablespace \d+ was not found at .*u[1-5].ibd, and innodb_force_recovery was set. All redo log for this tablespace will be ignored!;
--source include/search_pattern_in_file.inc
--let $restart_parameters=
--source include/restart_mysqld.inc
DROP TABLE u1,u2,u3,u6; DROP TABLE u1,u2,u3,u6;
--remove_file $MYSQLD_DATADIR/test/u4.ibd
--echo # List of files: --echo # List of files:
--list_files $MYSQLD_DATADIR/test --list_files $MYSQLD_DATADIR/test
......
...@@ -29,7 +29,7 @@ connect ddl3, localhost, root,,; ...@@ -29,7 +29,7 @@ connect ddl3, localhost, root,,;
CREATE TABLE t3(a TEXT,b TEXT,FULLTEXT INDEX(a)) ENGINE=InnoDB; CREATE TABLE t3(a TEXT,b TEXT,FULLTEXT INDEX(a)) ENGINE=InnoDB;
ALTER TABLE t3 DROP INDEX a, ADD FULLTEXT INDEX(b), ALGORITHM=COPY; ALTER TABLE t3 DROP INDEX a, ADD FULLTEXT INDEX(b), ALGORITHM=COPY;
connection default; connection default;
# restart: with restart_parameters # restart
disconnect ddl1; disconnect ddl1;
disconnect ddl2; disconnect ddl2;
disconnect ddl3; disconnect ddl3;
...@@ -69,7 +69,7 @@ DELETE FROM articles LIMIT 1; ...@@ -69,7 +69,7 @@ DELETE FROM articles LIMIT 1;
ROLLBACK; ROLLBACK;
disconnect flush_redo_log; disconnect flush_redo_log;
connection default; connection default;
# restart: with restart_parameters # restart
disconnect dml; disconnect dml;
INSERT INTO articles (title,body) VALUES INSERT INTO articles (title,body) VALUES
('MySQL Tutorial','DBMS stands for DataBase ...'); ('MySQL Tutorial','DBMS stands for DataBase ...');
...@@ -129,7 +129,7 @@ id title body ...@@ -129,7 +129,7 @@ id title body
1 MySQL Tutorial DBMS stands for Database... 1 MySQL Tutorial DBMS stands for Database...
2 MariaDB Tutorial DB means Database ... 2 MariaDB Tutorial DB means Database ...
connection default; connection default;
# restart: with restart_parameters # restart
disconnect dml; disconnect dml;
disconnect dml2; disconnect dml2;
INSERT INTO articles VALUES (8, 12, 'MySQL Tutorial','DBMS stands for DataBase ...'); INSERT INTO articles VALUES (8, 12, 'MySQL Tutorial','DBMS stands for DataBase ...');
......
...@@ -93,16 +93,6 @@ SET DEBUG_SYNC='now WAIT_FOR 3'; ...@@ -93,16 +93,6 @@ SET DEBUG_SYNC='now WAIT_FOR 3';
--enable_query_log --enable_query_log
} }
if (!$have_debug)
{
# Work around the lack of MDEV-24626
let $restart_parameters=--innodb-force-recovery=1;
}
if ($have_debug)
{
let $restart_parameters=--innodb-force-recovery=0;
}
let $restart_noprint=1;
let $shutdown_timeout=0; let $shutdown_timeout=0;
--source include/restart_mysqld.inc --source include/restart_mysqld.inc
...@@ -301,16 +291,15 @@ call mtr.add_suppression("InnoDB indexes are inconsistent with what defined in \ ...@@ -301,16 +291,15 @@ call mtr.add_suppression("InnoDB indexes are inconsistent with what defined in \
call mtr.add_suppression("InnoDB could not find key no [01] with name [ab] from dict cache for table test/t[123]"); call mtr.add_suppression("InnoDB could not find key no [01] with name [ab] from dict cache for table test/t[123]");
call mtr.add_suppression("InnoDB: Table test/t[123] contains .* indexes inside InnoDB"); call mtr.add_suppression("InnoDB: Table test/t[123] contains .* indexes inside InnoDB");
call mtr.add_suppression("InnoDB: Table `test`\\.`t3` does not exist"); call mtr.add_suppression("InnoDB: Table `test`\\.`t3` does not exist");
# MDEV-24626 FIXME: a 0-sized file will not be deleted!
--list_files $datadir/test #sql-alter-*.ibd
# Work around the lack of MDEV-24626 as well. # Some errors are reported despite the MDEV-24626 fix.
--remove_files_wildcard $datadir/test #sql-alter-*.ibd
--remove_files_wildcard $datadir/test #sql-backup-*.ibd
call mtr.add_suppression("InnoDB: Cannot (read first page of|open datafile for read-only:) '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd'"); call mtr.add_suppression("InnoDB: Cannot (read first page of|open datafile for read-only:) '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd'");
call mtr.add_suppression("InnoDB: Datafile '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd' is corrupted"); call mtr.add_suppression("InnoDB: Datafile '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd' is corrupted");
call mtr.add_suppression("InnoDB: (The error means|Operating system error)"); call mtr.add_suppression("InnoDB: (The error means|Operating system error)");
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`(FTS_|#sql-(backup|alter)-).*` because it could not be opened\\."); call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`(FTS_|#sql-(backup|alter)-).*` because it could not be opened\\.");
call mtr.add_suppression("InnoDB: Tablespace [1-9][0-9]* was not found at ./test/(FTS_|#sql-(alter|backup)-).*\\.ibd, and innodb_force_recovery was set"); call mtr.add_suppression("InnoDB: Expected tablespace id [1-9][0-9]* but found 0 in the file .*/test/(FTS_|#sql-(alter|backup)-).*\\.ibd");
call mtr.add_suppression("InnoDB: Corrupted page \\[page id: space=[1-9][0-9]*, page number=0\\] of datafile './test/(FTS_|#sql-(alter|backup)-).*\\.ibd' could not be found in the doublewrite buffer\\.");
--enable_query_log --enable_query_log
} }
--remove_files_wildcard $datadir/test #sql-*.frm --remove_files_wildcard $datadir/test #sql-*.frm
......
...@@ -12,6 +12,7 @@ INSERT INTO t VALUES ...@@ -12,6 +12,7 @@ INSERT INTO t VALUES
(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9),
(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9),
(0), (1), (2), (3), (4), (5), (6), (7), (8), (9); (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);
set global innodb_log_checkpoint_now = 1;
# xtrabackup backup, execute the following query after test.t is copied: # xtrabackup backup, execute the following query after test.t is copied:
# BEGIN NOT ATOMIC INSERT INTO test.t SELECT * FROM test.t; UPDATE test.t SET i = 10 WHERE i = 0; DELETE FROM test.t WHERE i = 1; END # BEGIN NOT ATOMIC INSERT INTO test.t SELECT * FROM test.t; UPDATE test.t SET i = 10 WHERE i = 0; DELETE FROM test.t WHERE i = 1; END
SELECT count(*) FROM t WHERE i = 0; SELECT count(*) FROM t WHERE i = 0;
......
...@@ -32,6 +32,7 @@ INSERT INTO t VALUES ...@@ -32,6 +32,7 @@ INSERT INTO t VALUES
(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9),
(0), (1), (2), (3), (4), (5), (6), (7), (8), (9); (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);
set global innodb_log_checkpoint_now = 1;
--let after_copy_test_t=BEGIN NOT ATOMIC INSERT INTO test.t SELECT * FROM test.t; UPDATE test.t SET i = 10 WHERE i = 0; DELETE FROM test.t WHERE i = 1; END --let after_copy_test_t=BEGIN NOT ATOMIC INSERT INTO test.t SELECT * FROM test.t; UPDATE test.t SET i = 10 WHERE i = 0; DELETE FROM test.t WHERE i = 1; END
--echo # xtrabackup backup, execute the following query after test.t is copied: --echo # xtrabackup backup, execute the following query after test.t is copied:
......
...@@ -3,6 +3,7 @@ CREATE TABLE t2 (i int) ENGINE=INNODB; ...@@ -3,6 +3,7 @@ CREATE TABLE t2 (i int) ENGINE=INNODB;
CREATE TABLE t3 (i int) ENGINE=INNODB; CREATE TABLE t3 (i int) ENGINE=INNODB;
CREATE TABLE t4 (i int) ENGINE=INNODB; CREATE TABLE t4 (i int) ENGINE=INNODB;
CREATE TABLE t5 (i int) ENGINE=INNODB; CREATE TABLE t5 (i int) ENGINE=INNODB;
set global innodb_log_checkpoint_now=1;
# xtrabackup prepare # xtrabackup prepare
# shutdown server # shutdown server
# remove datadir # remove datadir
......
...@@ -6,6 +6,8 @@ CREATE TABLE t3 (i int) ENGINE=INNODB; ...@@ -6,6 +6,8 @@ CREATE TABLE t3 (i int) ENGINE=INNODB;
CREATE TABLE t4 (i int) ENGINE=INNODB; CREATE TABLE t4 (i int) ENGINE=INNODB;
CREATE TABLE t5 (i int) ENGINE=INNODB; CREATE TABLE t5 (i int) ENGINE=INNODB;
set global innodb_log_checkpoint_now=1;
--let before_copy_test_t1=DROP TABLE test.t1 --let before_copy_test_t1=DROP TABLE test.t1
--let after_copy_test_t2=DROP TABLE test.t2; --let after_copy_test_t2=DROP TABLE test.t2;
# MDEV-18185, drop + rename combination # MDEV-18185, drop + rename combination
......
...@@ -3,6 +3,7 @@ CREATE TABLE t1(i INT PRIMARY KEY) ENGINE INNODB; ...@@ -3,6 +3,7 @@ CREATE TABLE t1(i INT PRIMARY KEY) ENGINE INNODB;
CREATE TABLE t2(i INT PRIMARY KEY) ENGINE INNODB; CREATE TABLE t2(i INT PRIMARY KEY) ENGINE INNODB;
CREATE TABLE t3(i INT) ENGINE INNODB; CREATE TABLE t3(i INT) ENGINE INNODB;
CREATE TABLE t10(i INT PRIMARY KEY) ENGINE INNODB; CREATE TABLE t10(i INT PRIMARY KEY) ENGINE INNODB;
set global innodb_log_checkpoint_now = 1;
# Create full backup , modify table, then create incremental/differential backup # Create full backup , modify table, then create incremental/differential backup
INSERT into t1 values(1); INSERT into t1 values(1);
# Prepare full backup, apply incremental one # Prepare full backup, apply incremental one
......
...@@ -10,6 +10,8 @@ CREATE TABLE t2(i INT PRIMARY KEY) ENGINE INNODB; ...@@ -10,6 +10,8 @@ CREATE TABLE t2(i INT PRIMARY KEY) ENGINE INNODB;
CREATE TABLE t3(i INT) ENGINE INNODB; CREATE TABLE t3(i INT) ENGINE INNODB;
CREATE TABLE t10(i INT PRIMARY KEY) ENGINE INNODB; CREATE TABLE t10(i INT PRIMARY KEY) ENGINE INNODB;
set global innodb_log_checkpoint_now = 1;
echo # Create full backup , modify table, then create incremental/differential backup; echo # Create full backup , modify table, then create incremental/differential backup;
--disable_result_log --disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir;
......
...@@ -7,5 +7,6 @@ PARTITION p1 VALUES LESS THAN (1995), ...@@ -7,5 +7,6 @@ PARTITION p1 VALUES LESS THAN (1995),
PARTITION p2 VALUES LESS THAN (2000), PARTITION p2 VALUES LESS THAN (2000),
PARTITION p3 VALUES LESS THAN (2005) PARTITION p3 VALUES LESS THAN (2005)
) ; ) ;
set global innodb_log_checkpoint_now = 1;
DROP TABLE t; DROP TABLE t;
DROP TABLE `bobby``tables`; DROP TABLE `bobby``tables`;
...@@ -13,6 +13,8 @@ CREATE TABLE `bobby``tables` (id INT, name VARCHAR(50), purchased DATE) ENGINE I ...@@ -13,6 +13,8 @@ CREATE TABLE `bobby``tables` (id INT, name VARCHAR(50), purchased DATE) ENGINE I
PARTITION p3 VALUES LESS THAN (2005) PARTITION p3 VALUES LESS THAN (2005)
) ; ) ;
set global innodb_log_checkpoint_now = 1;
--disable_result_log --disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --lock-ddl-per-table=1 --dbug=+d,check_mdl_lock_works; exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --lock-ddl-per-table=1 --dbug=+d,check_mdl_lock_works;
--enable_result_log --enable_result_log
......
...@@ -7,7 +7,6 @@ COMMIT; ...@@ -7,7 +7,6 @@ COMMIT;
SELECT count(*) FROM t; SELECT count(*) FROM t;
count(*) count(*)
100000 100000
FOUND 1 /Checksum mismatch in datafile/ in backup.log
# Prepare full backup, apply incremental one # Prepare full backup, apply incremental one
# Restore and check results # Restore and check results
# shutdown server # shutdown server
......
...@@ -18,15 +18,7 @@ INSERT INTO t select uuid(), uuid(), uuid(), uuid() from seq_1_to_100000; ...@@ -18,15 +18,7 @@ INSERT INTO t select uuid(), uuid(), uuid(), uuid() from seq_1_to_100000;
COMMIT; COMMIT;
SELECT count(*) FROM t; SELECT count(*) FROM t;
let $backuplog=$MYSQLTEST_VARDIR/tmp/backup.log; exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir --dbug=+d,page_intermittent_checksum_mismatch;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir --dbug=+d,page_intermittent_checksum_mismatch 2> $backuplog;
--let SEARCH_RANGE = 10000000
--let SEARCH_PATTERN=Checksum mismatch in datafile
--let SEARCH_FILE=$backuplog
--source include/search_pattern_in_file.inc
remove_file $backuplog;
--disable_result_log --disable_result_log
echo # Prepare full backup, apply incremental one; echo # Prepare full backup, apply incremental one;
......
...@@ -4,8 +4,8 @@ CREATE TABLE t21(i INT) ENGINE INNODB; ...@@ -4,8 +4,8 @@ CREATE TABLE t21(i INT) ENGINE INNODB;
INSERT INTO t21 VALUES(1); INSERT INTO t21 VALUES(1);
CREATE TABLE t2(i int) ENGINE INNODB; CREATE TABLE t2(i int) ENGINE INNODB;
# xtrabackup backup # xtrabackup backup
t1.ibd t1.new
t21.ibd t21.new
# xtrabackup prepare # xtrabackup prepare
t1.cfg t1.cfg
t21.cfg t21.cfg
......
...@@ -17,6 +17,7 @@ let targetdir=$MYSQLTEST_VARDIR/tmp/backup; ...@@ -17,6 +17,7 @@ let targetdir=$MYSQLTEST_VARDIR/tmp/backup;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup "--tables=test.*1" --target-dir=$targetdir; exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup "--tables=test.*1" --target-dir=$targetdir;
--enable_result_log --enable_result_log
list_files $targetdir/test *.ibd; list_files $targetdir/test *.ibd;
list_files $targetdir/test *.new;
# Inject a junk .ibd file into backup dir to # Inject a junk .ibd file into backup dir to
# see if prepare does not choke on it. # see if prepare does not choke on it.
......
...@@ -9,7 +9,7 @@ USE db2; ...@@ -9,7 +9,7 @@ USE db2;
CREATE TABLE t1(i INT) ENGINE INNODB; CREATE TABLE t1(i INT) ENGINE INNODB;
USE test; USE test;
# xtrabackup backup # xtrabackup backup
t1.ibd t1.new
DROP TABLE t1; DROP TABLE t1;
DROP TABLE t2; DROP TABLE t2;
DROP DATABASE db2; DROP DATABASE db2;
...@@ -27,6 +27,7 @@ exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup "--tables-ex ...@@ -27,6 +27,7 @@ exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup "--tables-ex
--enable_result_log --enable_result_log
# check that only t1 table is in backup (t2 is excluded) # check that only t1 table is in backup (t2 is excluded)
list_files $targetdir/test *.new;
list_files $targetdir/test *.ibd; list_files $targetdir/test *.ibd;
# check that db2 database is not in the backup (excluded) # check that db2 database is not in the backup (excluded)
--error 1 --error 1
......
...@@ -2,6 +2,7 @@ CREATE TABLE t1(i int) ENGINE=INNODB; ...@@ -2,6 +2,7 @@ CREATE TABLE t1(i int) ENGINE=INNODB;
CREATE TABLE t2(i int) ENGINE=INNODB; CREATE TABLE t2(i int) ENGINE=INNODB;
CREATE TABLE t3(a CHAR(36)) ENGINE INNODB; CREATE TABLE t3(a CHAR(36)) ENGINE INNODB;
INSERT INTO t3 SELECT UUID() FROM seq_1_to_1000; INSERT INTO t3 SELECT UUID() FROM seq_1_to_1000;
set global innodb_log_checkpoint_now=1;
# xtrabackup backup # xtrabackup backup
# xtrabackup prepare # xtrabackup prepare
# shutdown server # shutdown server
......
...@@ -7,6 +7,7 @@ CREATE TABLE t2(i int) ENGINE=INNODB; ...@@ -7,6 +7,7 @@ CREATE TABLE t2(i int) ENGINE=INNODB;
CREATE TABLE t3(a CHAR(36)) ENGINE INNODB; CREATE TABLE t3(a CHAR(36)) ENGINE INNODB;
INSERT INTO t3 SELECT UUID() FROM seq_1_to_1000; INSERT INTO t3 SELECT UUID() FROM seq_1_to_1000;
set global innodb_log_checkpoint_now=1;
# this will table and populate it, after backup has list of tables to be copied # this will table and populate it, after backup has list of tables to be copied
--let before_copy_test_t1=BEGIN NOT ATOMIC DROP TABLE test.t1;CREATE TABLE test.t1 ENGINE=INNODB SELECT UUID() from test.seq_1_to_100; END --let before_copy_test_t1=BEGIN NOT ATOMIC DROP TABLE test.t1;CREATE TABLE test.t1 ENGINE=INNODB SELECT UUID() from test.seq_1_to_100; END
--let after_copy_test_t2=BEGIN NOT ATOMIC DROP TABLE test.t2;CREATE TABLE test.t2 ENGINE=INNODB SELECT UUID() from test.seq_1_to_1000; END --let after_copy_test_t2=BEGIN NOT ATOMIC DROP TABLE test.t2;CREATE TABLE test.t2 ENGINE=INNODB SELECT UUID() from test.seq_1_to_1000; END
......
...@@ -14,6 +14,7 @@ CREATE TABLE a1(a1 int) ENGINE INNODB; ...@@ -14,6 +14,7 @@ CREATE TABLE a1(a1 int) ENGINE INNODB;
INSERT INTO a1 VALUES(1); INSERT INTO a1 VALUES(1);
CREATE TABLE b1(b1 CHAR(2)) ENGINE INNODB; CREATE TABLE b1(b1 CHAR(2)) ENGINE INNODB;
INSERT INTO b1 VALUES('b1'); INSERT INTO b1 VALUES('b1');
set global innodb_log_checkpoint_now = 1;
# xtrabackup prepare # xtrabackup prepare
# shutdown server # shutdown server
# remove datadir # remove datadir
......
...@@ -24,6 +24,8 @@ INSERT INTO a1 VALUES(1); ...@@ -24,6 +24,8 @@ INSERT INTO a1 VALUES(1);
CREATE TABLE b1(b1 CHAR(2)) ENGINE INNODB; CREATE TABLE b1(b1 CHAR(2)) ENGINE INNODB;
INSERT INTO b1 VALUES('b1'); INSERT INTO b1 VALUES('b1');
set global innodb_log_checkpoint_now = 1;
# Test renames before of after copying tablespaces # Test renames before of after copying tablespaces
--let before_copy_test_t1=RENAME TABLE test.t1 TO test.t1_renamed --let before_copy_test_t1=RENAME TABLE test.t1 TO test.t1_renamed
--let after_copy_test_t2=RENAME TABLE test.t2 TO test.t2_renamed --let after_copy_test_t2=RENAME TABLE test.t2 TO test.t2_renamed
......
CREATE TABLE t1(i int) ENGINE INNODB; CREATE TABLE t1(i int) ENGINE INNODB;
set global innodb_log_checkpoint_now = 1;
# xtrabackup prepare # xtrabackup prepare
# shutdown server # shutdown server
# remove datadir # remove datadir
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
mkdir $targetdir; mkdir $targetdir;
CREATE TABLE t1(i int) ENGINE INNODB; CREATE TABLE t1(i int) ENGINE INNODB;
set global innodb_log_checkpoint_now = 1;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --lock-ddl-per-table --dbug=+d,rename_during_mdl_lock_table; exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --lock-ddl-per-table --dbug=+d,rename_during_mdl_lock_table;
echo # xtrabackup prepare; echo # xtrabackup prepare;
......
...@@ -22,8 +22,8 @@ CREATE TABLE t2(i int) ENGINE INNODB; ...@@ -22,8 +22,8 @@ CREATE TABLE t2(i int) ENGINE INNODB;
ALTER TABLE t21 FORCE, ALGORITHM=INPLACE; ALTER TABLE t21 FORCE, ALGORITHM=INPLACE;
# Create partial backup (excluding table t21), Ignore the # Create partial backup (excluding table t21), Ignore the
# unsupported redo log for the table t21. # unsupported redo log for the table t21.
t1.ibd t1.new
t2.ibd t2.new
# Prepare the full backup # Prepare the full backup
t1.ibd t1.ibd
t2.ibd t2.ibd
......
...@@ -60,6 +60,7 @@ ALTER TABLE t21 FORCE, ALGORITHM=INPLACE; ...@@ -60,6 +60,7 @@ ALTER TABLE t21 FORCE, ALGORITHM=INPLACE;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup "--tables-exclude=test.t21" --target-dir=$targetdir; exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup "--tables-exclude=test.t21" --target-dir=$targetdir;
--enable_result_log --enable_result_log
--list_files $targetdir/test *.ibd --list_files $targetdir/test *.ibd
--list_files $targetdir/test *.new
--echo # Prepare the full backup --echo # Prepare the full backup
--disable_result_log --disable_result_log
......
...@@ -3258,25 +3258,12 @@ void buf_block_t::initialise(const page_id_t page_id, ulint zip_size, ...@@ -3258,25 +3258,12 @@ void buf_block_t::initialise(const page_id_t page_id, ulint zip_size,
page_zip_set_size(&page.zip, zip_size); page_zip_set_size(&page.zip, zip_size);
} }
/** Initialize a page in the buffer pool. The page is usually not read static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size,
from a file even if it cannot be found in the buffer buf_pool. This is one mtr_t *mtr, buf_block_t *free_block)
of the functions which perform to a block a state transition NOT_USED =>
FILE_PAGE (the other is buf_page_get_gen).
@param[in,out] space space object
@param[in] offset offset of the tablespace
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
@param[in,out] mtr mini-transaction
@param[in,out] free_block pre-allocated buffer block
@return pointer to the block, page bufferfixed */
buf_block_t*
buf_page_create(fil_space_t *space, uint32_t offset,
ulint zip_size, mtr_t *mtr, buf_block_t *free_block)
{ {
page_id_t page_id(space->id, offset);
ut_ad(mtr->is_active()); ut_ad(mtr->is_active());
ut_ad(page_id.space() != 0 || !zip_size); ut_ad(page_id.space() != 0 || !zip_size);
space->free_page(offset, false);
free_block->initialise(page_id, zip_size, 1); free_block->initialise(page_id, zip_size, 1);
const ulint fold= page_id.fold(); const ulint fold= page_id.fold();
...@@ -3440,6 +3427,39 @@ buf_page_create(fil_space_t *space, uint32_t offset, ...@@ -3440,6 +3427,39 @@ buf_page_create(fil_space_t *space, uint32_t offset,
return block; return block;
} }
/** Initialize a page in the buffer pool. The page is usually not read
from a file even if it cannot be found in the buffer buf_pool. This is one
of the functions which perform to a block a state transition NOT_USED =>
FILE_PAGE (the other is buf_page_get_gen).
@param[in,out] space space object
@param[in] offset offset of the tablespace
or deferred space id if space
object is null
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
@param[in,out] mtr mini-transaction
@param[in,out] free_block pre-allocated buffer block
@return pointer to the block, page bufferfixed */
buf_block_t*
buf_page_create(fil_space_t *space, uint32_t offset,
ulint zip_size, mtr_t *mtr, buf_block_t *free_block)
{
space->free_page(offset, false);
return buf_page_create_low({space->id, offset}, zip_size, mtr, free_block);
}
/** Initialize a page in buffer pool while initializing the
deferred tablespace
@param space_id space identfier
@param zip_size ROW_FORMAT=COMPRESSED page size or 0
@param mtr mini-transaction
@param free_block pre-allocated buffer block
@return pointer to the block, page bufferfixed */
buf_block_t* buf_page_create_deferred(uint32_t space_id, ulint zip_size,
mtr_t *mtr, buf_block_t *free_block)
{
return buf_page_create_low({space_id, 0}, zip_size, mtr, free_block);
}
/** Monitor the buffer page read/write activity, and increment corresponding /** Monitor the buffer page read/write activity, and increment corresponding
counter value in MONITOR_MODULE_BUF_PAGE. counter value in MONITOR_MODULE_BUF_PAGE.
@param bpage buffer page whose read or write was completed @param bpage buffer page whose read or write was completed
......
...@@ -2134,46 +2134,9 @@ fil_ibd_create( ...@@ -2134,46 +2134,9 @@ fil_ibd_create(
crypt_data->fill_page0(flags, page); crypt_data->fill_page0(flags, page);
} }
if (ulint zip_size = fil_space_t::zip_size(flags)) {
page_zip_des_t page_zip;
page_zip_set_size(&page_zip, zip_size);
page_zip.data = page + srv_page_size;
#ifdef UNIV_DEBUG
page_zip.m_start = 0;
#endif /* UNIV_DEBUG */
page_zip.m_end = 0;
page_zip.m_nonempty = 0;
page_zip.n_blobs = 0;
buf_flush_init_for_writing(NULL, page, &page_zip, false);
*err = os_file_write(IORequestWrite, path, file,
page_zip.data, 0, zip_size);
} else {
buf_flush_init_for_writing(NULL, page, NULL,
fil_space_t::full_crc32(flags));
*err = os_file_write(IORequestWrite, path, file,
page, 0, srv_page_size);
}
aligned_free(page); aligned_free(page);
fil_space_t::name_type space_name; fil_space_t::name_type space_name;
if (*err != DB_SUCCESS) {
ib::error()
<< "Could not write the first page to"
<< " tablespace '" << path << "'";
goto err_exit;
}
if (!os_file_flush(file)) {
ib::error() << "File flush of tablespace '"
<< path << "' failed";
*err = DB_ERROR;
goto err_exit;
}
if (has_data_dir) { if (has_data_dir) {
/* Make the ISL file if the IBD file is not /* Make the ISL file if the IBD file is not
in the default location. */ in the default location. */
...@@ -2657,15 +2620,23 @@ fil_ibd_load( ...@@ -2657,15 +2620,23 @@ fil_ibd_load(
} }
os_offset_t size; os_offset_t size;
bool deferred_space = false;
/* Read and validate the first page of the tablespace. /* Read and validate the first page of the tablespace.
Assign a tablespace name based on the tablespace type. */ Assign a tablespace name based on the tablespace type. */
switch (file.validate_for_recovery()) { switch (file.validate_for_recovery()) {
os_offset_t minimum_size; os_offset_t minimum_size;
case DB_SUCCESS: case DB_SUCCESS:
deferred_space = file.m_defer;
if (deferred_space) {
goto tablespace_check;
}
if (file.space_id() != space_id) { if (file.space_id() != space_id) {
return(FIL_LOAD_ID_CHANGED); return(FIL_LOAD_ID_CHANGED);
} }
tablespace_check:
/* Get and test the file size. */ /* Get and test the file size. */
size = os_file_get_size(file.handle()); size = os_file_get_size(file.handle());
...@@ -2681,6 +2652,8 @@ fil_ibd_load( ...@@ -2681,6 +2652,8 @@ fil_ibd_load(
ib::error() << "Could not measure the size of" ib::error() << "Could not measure the size of"
" single-table tablespace file '" " single-table tablespace file '"
<< file.filepath() << "'"; << file.filepath() << "'";
} else if (deferred_space) {
return FIL_LOAD_DEFER;
} else if (size < minimum_size) { } else if (size < minimum_size) {
ib::error() << "The size of tablespace file '" ib::error() << "The size of tablespace file '"
<< file.filepath() << "' is only " << size << file.filepath() << "' is only " << size
......
...@@ -280,11 +280,8 @@ Datafile::read_first_page(bool read_only_mode) ...@@ -280,11 +280,8 @@ Datafile::read_first_page(bool read_only_mode)
} else if (srv_operation == SRV_OPERATION_BACKUP) { } else if (srv_operation == SRV_OPERATION_BACKUP) {
break; break;
} else { } else {
ib::error() << "Cannot read first page of '"
ib::error() << m_filepath << "': " << err;
<< "Cannot read first page of '"
<< m_filepath << "' "
<< err;
break; break;
} }
} }
...@@ -424,6 +421,9 @@ Datafile::validate_for_recovery() ...@@ -424,6 +421,9 @@ Datafile::validate_for_recovery()
" the first 64 pages."; " the first 64 pages.";
return(err); return(err);
} }
if (m_space_id == ULINT_UNDEFINED) {
return DB_SUCCESS; /* empty file */
}
if (restore_from_doublewrite()) { if (restore_from_doublewrite()) {
return(DB_CORRUPTION); return(DB_CORRUPTION);
...@@ -467,11 +467,18 @@ dberr_t Datafile::validate_first_page(lsn_t *flush_lsn) ...@@ -467,11 +467,18 @@ dberr_t Datafile::validate_first_page(lsn_t *flush_lsn)
if (error_txt != NULL) { if (error_txt != NULL) {
err_exit: err_exit:
free_first_page();
if (recv_recovery_is_on()
|| srv_operation == SRV_OPERATION_BACKUP) {
m_defer= true;
return DB_SUCCESS;
}
ib::info() << error_txt << " in datafile: " << m_filepath ib::info() << error_txt << " in datafile: " << m_filepath
<< ", Space ID:" << m_space_id << ", Flags: " << ", Space ID:" << m_space_id << ", Flags: "
<< m_flags; << m_flags;
m_is_valid = false; m_is_valid = false;
free_first_page();
return(DB_CORRUPTION); return(DB_CORRUPTION);
} }
...@@ -500,13 +507,18 @@ dberr_t Datafile::validate_first_page(lsn_t *flush_lsn) ...@@ -500,13 +507,18 @@ dberr_t Datafile::validate_first_page(lsn_t *flush_lsn)
ulint logical_size = fil_space_t::logical_size(m_flags); ulint logical_size = fil_space_t::logical_size(m_flags);
if (srv_page_size != logical_size) { if (srv_page_size != logical_size) {
free_first_page();
if (recv_recovery_is_on()
|| srv_operation == SRV_OPERATION_BACKUP) {
m_defer= true;
return DB_SUCCESS;
}
/* Logical size must be innodb_page_size. */ /* Logical size must be innodb_page_size. */
ib::error() ib::error()
<< "Data file '" << m_filepath << "' uses page size " << "Data file '" << m_filepath << "' uses page size "
<< logical_size << ", but the innodb_page_size" << logical_size << ", but the innodb_page_size"
" start-up parameter is " " start-up parameter is "
<< srv_page_size; << srv_page_size;
free_first_page();
return(DB_ERROR); return(DB_ERROR);
} }
...@@ -535,10 +547,18 @@ dberr_t Datafile::validate_first_page(lsn_t *flush_lsn) ...@@ -535,10 +547,18 @@ dberr_t Datafile::validate_first_page(lsn_t *flush_lsn)
fil_node_t* node = UT_LIST_GET_FIRST(space->chain); fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
if (node && !strcmp(m_filepath, node->name)) { if (node && !strcmp(m_filepath, node->name)) {
ok_exit:
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
return DB_SUCCESS; return DB_SUCCESS;
} }
if (!m_space_id
&& (recv_recovery_is_on()
|| srv_operation == SRV_OPERATION_BACKUP)) {
m_defer= true;
goto ok_exit;
}
/* Make sure the space_id has not already been opened. */ /* Make sure the space_id has not already been opened. */
ib::error() << "Attempted to open a previously opened" ib::error() << "Attempted to open a previously opened"
" tablespace. Previous tablespace: " " tablespace. Previous tablespace: "
...@@ -575,6 +595,10 @@ Datafile::find_space_id() ...@@ -575,6 +595,10 @@ Datafile::find_space_id()
file_size = os_file_get_size(m_handle); file_size = os_file_get_size(m_handle);
if (!file_size) {
return DB_SUCCESS;
}
if (file_size == (os_offset_t) -1) { if (file_size == (os_offset_t) -1) {
ib::error() << "Could not get file size of datafile '" ib::error() << "Could not get file size of datafile '"
<< m_filepath << "'"; << m_filepath << "'";
......
...@@ -314,6 +314,17 @@ buf_block_t* ...@@ -314,6 +314,17 @@ buf_block_t*
buf_page_create(fil_space_t *space, uint32_t offset, buf_page_create(fil_space_t *space, uint32_t offset,
ulint zip_size, mtr_t *mtr, buf_block_t *free_block); ulint zip_size, mtr_t *mtr, buf_block_t *free_block);
/** Initialize a page in buffer pool while initializing the
deferred tablespace
@param space_id space identfier
@param zip_size ROW_FORMAT=COMPRESSED page size or 0
@param mtr mini-transaction
@param free_block pre-allocated buffer block
@return pointer to the block, page bufferfixed */
buf_block_t*
buf_page_create_deferred(uint32_t space_id, ulint zip_size, mtr_t *mtr,
buf_block_t *free_block);
/********************************************************************//** /********************************************************************//**
Releases a compressed-only page acquired with buf_page_get_zip(). */ Releases a compressed-only page acquired with buf_page_get_zip(). */
UNIV_INLINE UNIV_INLINE
......
...@@ -99,6 +99,7 @@ this must be equal to srv_page_size */ ...@@ -99,6 +99,7 @@ this must be equal to srv_page_size */
class page_id_t class page_id_t
{ {
public: public:
/** Constructor from (space, page_no). /** Constructor from (space, page_no).
@param[in] space tablespace id @param[in] space tablespace id
@param[in] page_no page number */ @param[in] page_no page number */
...@@ -152,6 +153,7 @@ class page_id_t ...@@ -152,6 +153,7 @@ class page_id_t
} }
ulonglong raw() { return m_id; } ulonglong raw() { return m_id; }
private: private:
/** The page identifier */ /** The page identifier */
uint64_t m_id; uint64_t m_id;
......
...@@ -507,6 +507,8 @@ struct fil_space_t final ...@@ -507,6 +507,8 @@ struct fil_space_t final
/** @return whether the storage device is rotational (HDD, not SSD) */ /** @return whether the storage device is rotational (HDD, not SSD) */
inline bool is_rotational() const; inline bool is_rotational() const;
inline bool is_deferred() const;
/** Open each file. Never invoked on .ibd files. /** Open each file. Never invoked on .ibd files.
@param create_new_db whether to skip the call to fil_node_t::read_page0() @param create_new_db whether to skip the call to fil_node_t::read_page0()
@return whether all files were opened */ @return whether all files were opened */
...@@ -1088,6 +1090,10 @@ struct fil_node_t final ...@@ -1088,6 +1090,10 @@ struct fil_node_t final
/** Filesystem block size */ /** Filesystem block size */
ulint block_size; ulint block_size;
/** Deferring the tablespace during recovery and it
can be used to skip the validation of page0 */
bool deferred=false;
/** FIL_NODE_MAGIC_N */ /** FIL_NODE_MAGIC_N */
ulint magic_n; ulint magic_n;
...@@ -1145,6 +1151,11 @@ inline bool fil_space_t::is_rotational() const ...@@ -1145,6 +1151,11 @@ inline bool fil_space_t::is_rotational() const
return false; return false;
} }
inline bool fil_space_t::is_deferred() const
{
return UT_LIST_GET_FIRST(chain)->deferred;
}
/** Common InnoDB file extensions */ /** Common InnoDB file extensions */
enum ib_extention { enum ib_extention {
NO_EXT = 0, NO_EXT = 0,
...@@ -1475,6 +1486,11 @@ struct fil_system_t { ...@@ -1475,6 +1486,11 @@ struct fil_system_t {
/** Extend all open data files to the recovered size */ /** Extend all open data files to the recovered size */
ATTRIBUTE_COLD void extend_to_recv_size(); ATTRIBUTE_COLD void extend_to_recv_size();
/** Determine if a tablespace associated with a file name exists.
@param path tablespace file name to look for
@return a matching tablespace */
inline fil_space_t *find(const char *path) const;
}; };
/** The tablespace memory cache. */ /** The tablespace memory cache. */
...@@ -1684,7 +1700,9 @@ enum fil_load_status { ...@@ -1684,7 +1700,9 @@ enum fil_load_status {
/** The file(s) were not found */ /** The file(s) were not found */
FIL_LOAD_NOT_FOUND, FIL_LOAD_NOT_FOUND,
/** The file(s) were not valid */ /** The file(s) were not valid */
FIL_LOAD_INVALID FIL_LOAD_INVALID,
/** The tablespace file was deferred to open */
FIL_LOAD_DEFER
}; };
/** Open a single-file tablespace and add it to the InnoDB data structures. /** Open a single-file tablespace and add it to the InnoDB data structures.
......
...@@ -324,6 +324,9 @@ class Datafile { ...@@ -324,6 +324,9 @@ class Datafile {
@return the first data page */ @return the first data page */
const byte* get_first_page() const { return(m_first_page); } const byte* get_first_page() const { return(m_first_page); }
void set_space_id(ulint space_id) { m_space_id= space_id; }
void set_flags(ulint flags) { m_flags = flags; }
private: private:
/** Free the filepath buffer. */ /** Free the filepath buffer. */
void free_filepath(); void free_filepath();
...@@ -443,6 +446,8 @@ class Datafile { ...@@ -443,6 +446,8 @@ class Datafile {
ulint m_last_os_error; ulint m_last_os_error;
public: public:
/** true if table is deferred during recovery */
bool m_defer=false;
/** Use the following to determine the uniqueness of this datafile. */ /** Use the following to determine the uniqueness of this datafile. */
#ifdef _WIN32 #ifdef _WIN32
/* Use fields dwVolumeSerialNumber, nFileIndexLow, nFileIndexHigh. */ /* Use fields dwVolumeSerialNumber, nFileIndexLow, nFileIndexHigh. */
......
...@@ -405,6 +405,15 @@ struct recv_sys_t ...@@ -405,6 +405,15 @@ struct recv_sys_t
{ {
return UNIV_UNLIKELY(recovery_on) ? recover_low(page_id) : nullptr; return UNIV_UNLIKELY(recovery_on) ? recover_low(page_id) : nullptr;
} }
/** Try to recover a tablespace that was not readable earlier
@param p iterator, initially pointing to page_id_t{space_id,0};
the records will be freed and the iterator advanced
@param name tablespace file name
@param free_block spare buffer block
@return whether recovery failed */
bool recover_deferred(map::iterator &p, const std::string &name,
buf_block_t *&free_block);
}; };
/** The recovery system */ /** The recovery system */
......
This diff is collapsed.
...@@ -4463,109 +4463,110 @@ void fil_node_t::find_metadata(os_file_t file ...@@ -4463,109 +4463,110 @@ void fil_node_t::find_metadata(os_file_t file
bool fil_node_t::read_page0() bool fil_node_t::read_page0()
{ {
mysql_mutex_assert_owner(&fil_system.mutex); mysql_mutex_assert_owner(&fil_system.mutex);
const unsigned psize = space->physical_size(); const unsigned psize= space->physical_size();
#ifndef _WIN32 #ifndef _WIN32
struct stat statbuf; struct stat statbuf;
if (fstat(handle, &statbuf)) { if (fstat(handle, &statbuf))
return false; return false;
} os_offset_t size_bytes= statbuf.st_size;
os_offset_t size_bytes = statbuf.st_size;
#else #else
os_offset_t size_bytes = os_file_get_size(handle); os_offset_t size_bytes= os_file_get_size(handle);
ut_a(size_bytes != (os_offset_t) -1); ut_a(size_bytes != (os_offset_t) -1);
#endif #endif
const uint32_t min_size = FIL_IBD_FILE_INITIAL_SIZE * psize; const uint32_t min_size= FIL_IBD_FILE_INITIAL_SIZE * psize;
if (size_bytes < min_size) { if (size_bytes < min_size)
{
ib::error() << "The size of the file " << name ib::error() << "The size of the file " << name
<< " is only " << size_bytes << " is only " << size_bytes
<< " bytes, should be at least " << min_size; << " bytes, should be at least " << min_size;
return false; return false;
} }
if (!deferred)
{
page_t *page= static_cast<byte*>(aligned_malloc(psize, psize)); page_t *page= static_cast<byte*>(aligned_malloc(psize, psize));
if (os_file_read(IORequestRead, handle, page, 0, psize) if (os_file_read(IORequestRead, handle, page, 0, psize)
!= DB_SUCCESS) { != DB_SUCCESS)
{
ib::error() << "Unable to read first page of file " << name; ib::error() << "Unable to read first page of file " << name;
corrupted: corrupted:
aligned_free(page); aligned_free(page);
return false; return false;
} }
const ulint space_id = memcmp_aligned<2>( const ulint space_id= memcmp_aligned<2>
FIL_PAGE_SPACE_ID + page, (FIL_PAGE_SPACE_ID + page,
FSP_HEADER_OFFSET + FSP_SPACE_ID + page, 4) FSP_HEADER_OFFSET + FSP_SPACE_ID + page, 4)
? ULINT_UNDEFINED ? ULINT_UNDEFINED
: mach_read_from_4(FIL_PAGE_SPACE_ID + page); : mach_read_from_4(FIL_PAGE_SPACE_ID + page);
ulint flags = fsp_header_get_flags(page); ulint flags= fsp_header_get_flags(page);
const uint32_t size = fsp_header_get_field(page, FSP_SIZE); const uint32_t size= fsp_header_get_field(page, FSP_SIZE);
const uint32_t free_limit = fsp_header_get_field(page, FSP_FREE_LIMIT); const uint32_t free_limit= fsp_header_get_field(page, FSP_FREE_LIMIT);
const uint32_t free_len = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE const uint32_t free_len= flst_get_len(FSP_HEADER_OFFSET + FSP_FREE + page);
+ page); if (!fil_space_t::is_valid_flags(flags, space->id))
if (!fil_space_t::is_valid_flags(flags, space->id)) { {
ulint cflags = fsp_flags_convert_from_101(flags); ulint cflags= fsp_flags_convert_from_101(flags);
if (cflags == ULINT_UNDEFINED) { if (cflags == ULINT_UNDEFINED)
{
invalid: invalid:
ib::error() ib::error() << "Expected tablespace flags "
<< "Expected tablespace flags "
<< ib::hex(space->flags) << ib::hex(space->flags)
<< " but found " << ib::hex(flags) << " but found " << ib::hex(flags)
<< " in the file " << name; << " in the file " << name;
goto corrupted; goto corrupted;
} }
ulint cf = cflags & ~FSP_FLAGS_MEM_MASK; ulint cf= cflags & ~FSP_FLAGS_MEM_MASK;
ulint sf = space->flags & ~FSP_FLAGS_MEM_MASK; ulint sf= space->flags & ~FSP_FLAGS_MEM_MASK;
if (!fil_space_t::is_flags_equal(cf, sf) if (!fil_space_t::is_flags_equal(cf, sf) &&
&& !fil_space_t::is_flags_equal(sf, cf)) { !fil_space_t::is_flags_equal(sf, cf))
goto invalid; goto invalid;
} flags= cflags;
flags = cflags;
} }
ut_ad(!(flags & FSP_FLAGS_MEM_MASK)); ut_ad(!(flags & FSP_FLAGS_MEM_MASK));
/* Try to read crypt_data from page 0 if it is not yet read. */ /* Try to read crypt_data from page 0 if it is not yet read. */
if (!space->crypt_data) { if (!space->crypt_data)
space->crypt_data = fil_space_read_crypt_data( space->crypt_data= fil_space_read_crypt_data(
fil_space_t::zip_size(flags), page); fil_space_t::zip_size(flags), page);
}
aligned_free(page); aligned_free(page);
if (UNIV_UNLIKELY(space_id != space->id)) { if (UNIV_UNLIKELY(space_id != space->id))
{
ib::error() << "Expected tablespace id " << space->id ib::error() << "Expected tablespace id " << space->id
<< " but found " << space_id << " but found " << space_id
<< " in the file " << name; << " in the file " << name;
return false; return false;
} }
space->flags= (space->flags & FSP_FLAGS_MEM_MASK) | flags;
ut_ad(space->free_limit == 0 || space->free_limit == free_limit);
ut_ad(space->free_len == 0 || space->free_len == free_len);
space->size_in_header= size;
space->free_limit= free_limit;
space->free_len= free_len;
}
#ifdef UNIV_LINUX #ifdef UNIV_LINUX
find_metadata(handle, &statbuf); find_metadata(handle, &statbuf);
#else #else
find_metadata(); find_metadata();
#endif #endif
/* Truncate the size to a multiple of extent size. */ /* Truncate the size to a multiple of extent size. */
ulint mask = psize * FSP_EXTENT_SIZE - 1; ulint mask= psize * FSP_EXTENT_SIZE - 1;
if (size_bytes <= mask) { if (size_bytes <= mask);
/* .ibd files start smaller than an /* .ibd files start smaller than an
extent size. Do not truncate valid data. */ extent size. Do not truncate valid data. */
} else { else size_bytes &= ~os_offset_t(mask);
size_bytes &= ~os_offset_t(mask);
}
space->flags = (space->flags & FSP_FLAGS_MEM_MASK) | flags;
space->punch_hole = space->is_compressed(); space->punch_hole= space->is_compressed();
this->size = uint32_t(size_bytes / psize); this->size= uint32_t(size_bytes / psize);
space->set_sizes(this->size); space->set_sizes(this->size);
ut_ad(space->free_limit == 0 || space->free_limit == free_limit);
ut_ad(space->free_len == 0 || space->free_len == free_len);
space->size_in_header = size;
space->free_limit = free_limit;
space->free_len = free_len;
return true; return true;
} }
#endif /* !UNIV_INNOCHECKSUM */ #endif /* !UNIV_INNOCHECKSUM */
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