MDEV-9566 Prepare xtradb for xtrabackup

These changes are comparable to Percona's modifications in innodb in the
Percona Xtrabackup repository.

- If functions are used in backup as well as in innodb, make them non-static.

- Define IS_XTRABACKUP() macro for special handling of innodb running
  inside backup.

- Extend some functions for backup.
  fil_space_for_table_exists_in_mem() gets additional parameter
  'remove_from_data_dict_if_does_not_exist', for partial backups

  fil_load_single_table_tablespaces() gets an optional parameter predicate
  which tells whether to load tablespace based on database or table name,
  also for partial backups.

  srv_undo_tablespaces_init() gets an optional parameter 'backup_mode'

- Allow single redo log file (for backup "prepare")

- Do not read doublewrite buffer pages in backup, they are outdated

- Add function fil_remove_invalid_table_from_data_dict(), to remove non-existing
   tables from data dictionary in case of partial backups.

- On Windows, fix file share modes when opening tablespaces,
to allow mariabackup to read tablespaces while server is online.

- Avoid access to THDVARs in backup, because innodb plugin is not loaded,
and THDVAR would crash in this case.
This commit is contained in:
Vladislav Vaintroub 2017-04-18 17:57:07 +00:00 committed by Sergei Golubchik
parent f06ab0fc99
commit 9c4b7cad27
18 changed files with 556 additions and 109 deletions

View File

@ -722,7 +722,6 @@ btr_root_fseg_validate(
/**************************************************************//**
Gets the root node of a tree and x- or s-latches it.
@return root page, x- or s-latched */
static
buf_block_t*
btr_root_block_get(
/*===============*/
@ -1531,7 +1530,6 @@ btr_node_ptr_set_child_page_no(
/************************************************************//**
Returns the child page of a node pointer and x-latches it.
@return child page, x-latched */
static
buf_block_t*
btr_node_ptr_get_child(
/*===================*/

View File

@ -2864,7 +2864,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
success = buf_flush_list(PCT_IO(100), LSN_MAX, &n_flushed);
buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
} while (!success || n_flushed > 0);
} while (!success || n_flushed > 0 || (IS_XTRABACKUP() && buf_get_n_pending_read_ios() > 0));
/* Some sanity checks */
ut_a(srv_get_active_thread_type() == SRV_NONE);

View File

@ -955,11 +955,8 @@ buf_read_ibuf_merge_pages(
tablespace_deleted:
/* We have deleted or are deleting the single-table
tablespace: remove the entries for that page */
ibuf_merge_or_delete_for_page(NULL, space_ids[i],
page_nos[i],
zip_size, FALSE);
tablespace: remove the entries for tablespace. */
ibuf_delete_for_discarded_space(space_ids[i]);
break;
case DB_DECRYPTION_FAILED:
ib_logf(IB_LOG_LEVEL_ERROR,

View File

@ -945,6 +945,10 @@ dict_insert_tablespace_and_filepath(
return(err);
}
/* Set by Xtrabackup */
my_bool (*dict_check_if_skip_table)(const char* name) = 0;
/********************************************************************//**
This function looks at each table defined in SYS_TABLES. It checks the
tablespace for any table with a space_id > 0. It looks up the tablespace
@ -1064,6 +1068,9 @@ loop:
bool is_temp = false;
bool discarded = false;
bool print_error_if_does_not_exist;
bool remove_from_data_dict_if_does_not_exist;
ib_uint32_t flags2 = static_cast<ib_uint32_t>(
mach_read_from_4(field));
@ -1089,6 +1096,19 @@ loop:
goto loop;
}
ut_a(!IS_XTRABACKUP() || dict_check_if_skip_table);
if (is_temp || discarded ||
(IS_XTRABACKUP() && dict_check_if_skip_table(name))) {
print_error_if_does_not_exist = false;
}
else {
print_error_if_does_not_exist = true;
}
remove_from_data_dict_if_does_not_exist = IS_XTRABACKUP() && !(is_temp || discarded);
mtr_commit(&mtr);
switch (dict_check) {
@ -1096,8 +1116,8 @@ loop:
/* All tablespaces should have been found in
fil_load_single_table_tablespaces(). */
if (fil_space_for_table_exists_in_mem(
space_id, name, !(is_temp || discarded),
false, NULL, 0, flags)
space_id, name, print_error_if_does_not_exist,
remove_from_data_dict_if_does_not_exist , false, NULL, 0, flags)
&& !(is_temp || discarded)) {
/* If user changes the path of .ibd files in
*.isl files before doing crash recovery ,
@ -1130,7 +1150,7 @@ loop:
trx_resurrect_table_locks(). */
if (fil_space_for_table_exists_in_mem(
space_id, name, false,
false, NULL, 0, flags)) {
false, false, NULL, 0, flags)) {
break;
}
/* fall through */
@ -2383,7 +2403,7 @@ err_exit:
table->file_unreadable = true;
} else if (!fil_space_for_table_exists_in_mem(
table->space, name, false, true, heap,
table->space, name, false, IS_XTRABACKUP(), true, heap,
table->id, table->flags)) {
if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)) {

View File

@ -67,6 +67,7 @@ static ulint srv_data_read, srv_data_written;
#include <fcntl.h>
#endif
#include "row0mysql.h"
#include "trx0purge.h"
MYSQL_PLUGIN_IMPORT extern my_bool lower_case_file_system;
@ -369,7 +370,6 @@ fil_node_get_space_id(
/*******************************************************************//**
Returns the table space by a given name, NULL if not found. */
UNIV_INLINE
fil_space_t*
fil_space_get_by_name(
/*==================*/
@ -1574,12 +1574,13 @@ fil_space_create(
if (!fil_system->space_id_reuse_warned) {
fil_system->space_id_reuse_warned = TRUE;
ib_logf(IB_LOG_LEVEL_WARN,
"Allocated tablespace %lu, old maximum "
"was %lu",
(ulong) id,
(ulong) fil_system->max_assigned_id);
if (!IS_XTRABACKUP()) {
ib_logf(IB_LOG_LEVEL_WARN,
"Allocated tablespace %lu, old maximum "
"was %lu",
(ulong)id,
(ulong)fil_system->max_assigned_id);
}
}
fil_system->max_assigned_id = id;
@ -2413,6 +2414,19 @@ fil_read_first_page(
const char* check_msg = NULL;
fil_space_crypt_t* cdata;
if (IS_XTRABACKUP() && srv_backup_mode) {
/* Files smaller than page size may occur
in xtrabackup, when server creates new file
but has not yet written into it, or wrote only
partially. Checks size here, to avoid exit in os_file_read.
This file will be skipped by xtrabackup if it is too small.
*/
os_offset_t file_size;
file_size = os_file_get_size(data_file);
if (file_size < FIL_IBD_FILE_INITIAL_SIZE*UNIV_PAGE_SIZE) {
return "File size is less than minimum";
}
}
buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
/* Align the memory for a possible read from a raw device */
@ -2443,7 +2457,9 @@ fil_read_first_page(
}
}
check_msg = fil_check_first_page(page, *space_id, *flags);
if (!(IS_XTRABACKUP() && srv_backup_mode)) {
check_msg = fil_check_first_page(page, *space_id, *flags);
}
}
flushed_lsn = mach_read_from_8(page +
@ -3137,7 +3153,7 @@ fil_delete_tablespace(
err = DB_IO_ERROR;
}
if (err == DB_SUCCESS) {
if (err == DB_SUCCESS && !IS_XTRABACKUP()) {
#ifndef UNIV_HOTBACKUP
/* Write a log record about the deletion of the .ibd
file, so that mysqlbackup can replay it in the
@ -3536,7 +3552,7 @@ skip_second_rename:
mutex_exit(&fil_system->mutex);
#ifndef UNIV_HOTBACKUP
if (success && !recv_recovery_on) {
if (success && !recv_recovery_on && !IS_XTRABACKUP()) {
mtr_t mtr;
mtr_start(&mtr);
@ -3782,7 +3798,18 @@ fil_create_new_single_table_tablespace(
ibool success;
/* TRUE if a table is created with CREATE TEMPORARY TABLE */
bool is_temp = !!(flags2 & DICT_TF2_TEMPORARY);
bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags) != 0;
/* For XtraBackup recovery we force remote tablespaces to be local,
i.e. never execute the code path corresponding to has_data_dir == true.
We don't create .isl files either, because we rely on innobackupex to
copy them under a global lock, and use them to copy remote tablespaces
to their proper locations on --copy-back.
See also MySQL bug #72022: dir_path is always NULL for remote
tablespaces when a MLOG_FILE_CREATE* log record is replayed (the remote
directory is not available from MLOG_FILE_CREATE*). */
bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags) != 0 && !IS_XTRABACKUP();
ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags);
fil_space_crypt_t *crypt_data = NULL;
@ -3964,6 +3991,7 @@ fil_create_new_single_table_tablespace(
}
#ifndef UNIV_HOTBACKUP
if (!IS_XTRABACKUP())
{
mtr_t mtr;
ulint mlog_file_flag = 0;
@ -4004,6 +4032,138 @@ error_exit_3:
return(err);
}
#include "pars0pars.h"
#include "que0que.h"
#include "dict0priv.h"
static
void
fil_remove_invalid_table_from_data_dict(const char *name)
{
trx_t* trx;
pars_info_t* info = NULL;
trx = trx_allocate_for_mysql();
trx_start_for_ddl(trx, TRX_DICT_OP_TABLE);
ut_ad(mutex_own(&dict_sys->mutex));
trx->op_info = "removing invalid table from data dictionary";
info = pars_info_create();
pars_info_add_str_literal(info, "table_name", name);
que_eval_sql(info,
"PROCEDURE DROP_TABLE_PROC () IS\n"
"sys_foreign_id CHAR;\n"
"table_id CHAR;\n"
"index_id CHAR;\n"
"foreign_id CHAR;\n"
"found INT;\n"
"DECLARE CURSOR cur_fk IS\n"
"SELECT ID FROM SYS_FOREIGN\n"
"WHERE FOR_NAME = :table_name\n"
"AND TO_BINARY(FOR_NAME)\n"
" = TO_BINARY(:table_name)\n"
"LOCK IN SHARE MODE;\n"
"DECLARE CURSOR cur_idx IS\n"
"SELECT ID FROM SYS_INDEXES\n"
"WHERE TABLE_ID = table_id\n"
"LOCK IN SHARE MODE;\n"
"BEGIN\n"
"SELECT ID INTO table_id\n"
"FROM SYS_TABLES\n"
"WHERE NAME = :table_name\n"
"LOCK IN SHARE MODE;\n"
"IF (SQL % NOTFOUND) THEN\n"
" RETURN;\n"
"END IF;\n"
"found := 1;\n"
"SELECT ID INTO sys_foreign_id\n"
"FROM SYS_TABLES\n"
"WHERE NAME = 'SYS_FOREIGN'\n"
"LOCK IN SHARE MODE;\n"
"IF (SQL % NOTFOUND) THEN\n"
" found := 0;\n"
"END IF;\n"
"IF (:table_name = 'SYS_FOREIGN') THEN\n"
" found := 0;\n"
"END IF;\n"
"IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
" found := 0;\n"
"END IF;\n"
"OPEN cur_fk;\n"
"WHILE found = 1 LOOP\n"
" FETCH cur_fk INTO foreign_id;\n"
" IF (SQL % NOTFOUND) THEN\n"
" found := 0;\n"
" ELSE\n"
" DELETE FROM SYS_FOREIGN_COLS\n"
" WHERE ID = foreign_id;\n"
" DELETE FROM SYS_FOREIGN\n"
" WHERE ID = foreign_id;\n"
" END IF;\n"
"END LOOP;\n"
"CLOSE cur_fk;\n"
"found := 1;\n"
"OPEN cur_idx;\n"
"WHILE found = 1 LOOP\n"
" FETCH cur_idx INTO index_id;\n"
" IF (SQL % NOTFOUND) THEN\n"
" found := 0;\n"
" ELSE\n"
" DELETE FROM SYS_FIELDS\n"
" WHERE INDEX_ID = index_id;\n"
" DELETE FROM SYS_INDEXES\n"
" WHERE ID = index_id\n"
" AND TABLE_ID = table_id;\n"
" END IF;\n"
"END LOOP;\n"
"CLOSE cur_idx;\n"
"DELETE FROM SYS_COLUMNS\n"
"WHERE TABLE_ID = table_id;\n"
"DELETE FROM SYS_TABLES\n"
"WHERE NAME = :table_name;\n"
"END;\n"
, FALSE, trx);
/* SYS_DATAFILES and SYS_TABLESPACES do not necessarily exist
on XtraBackup recovery. See comments around
dict_create_or_check_foreign_constraint_tables() in
innobase_start_or_create_for_mysql(). */
if (dict_table_get_low("SYS_DATAFILES") != NULL) {
info = pars_info_create();
pars_info_add_str_literal(info, "table_name", name);
que_eval_sql(info,
"PROCEDURE DROP_TABLE_PROC () IS\n"
"space_id INT;\n"
"BEGIN\n"
"SELECT SPACE INTO space_id\n"
"FROM SYS_TABLES\n"
"WHERE NAME = :table_name;\n"
"IF (SQL % NOTFOUND) THEN\n"
" RETURN;\n"
"END IF;\n"
"DELETE FROM SYS_TABLESPACES\n"
"WHERE SPACE = space_id;\n"
"DELETE FROM SYS_DATAFILES\n"
"WHERE SPACE = space_id;\n"
"END;\n"
, FALSE, trx);
}
trx_commit_for_mysql(trx);
trx_free_for_mysql(trx);
}
#ifndef UNIV_HOTBACKUP
/********************************************************************//**
Report information about a bad tablespace. */
@ -4144,8 +4304,10 @@ fil_open_single_table_tablespace(
in the default location. If it is remote, it should not be here. */
def.filepath = fil_make_ibd_name(tablename, false);
/* The path_in was read from SYS_DATAFILES. */
if (path_in) {
/* The path_in was read from SYS_DATAFILES.
We skip SYS_DATAFILES validation and remote tablespaces discovery for
XtraBackup, as all tablespaces are local for XtraBackup recovery. */
if (path_in && !IS_XTRABACKUP()) {
if (strcmp(def.filepath, path_in)) {
dict.filepath = mem_strdup(path_in);
/* possibility of multiple files. */
@ -4287,12 +4449,19 @@ fil_open_single_table_tablespace(
/* The following call prints an error message */
os_file_get_last_error(true);
ib_logf(IB_LOG_LEVEL_ERROR,
ib_logf(IS_XTRABACKUP() ? IB_LOG_LEVEL_WARN : IB_LOG_LEVEL_ERROR,
"Could not find a valid tablespace file for '%s'. "
"See " REFMAN "innodb-troubleshooting-datadict.html "
"for how to resolve the issue.",
tablename);
if (IS_XTRABACKUP() && fix_dict) {
ib_logf(IB_LOG_LEVEL_WARN,
"It will be removed from the data dictionary.");
if (purge_sys) {
fil_remove_invalid_table_from_data_dict(tablename);
}
}
err = DB_CORRUPTION;
goto cleanup_and_exit;
@ -4717,6 +4886,11 @@ check_first_page:
}
if (!fsp->success) {
if (IS_XTRABACKUP()) {
/* Do not attempt restore from doublewrite buffer
in Xtrabackup, this does not work.*/
return;
}
if (!restore_attempted) {
if (!fil_user_tablespace_find_space_id(fsp)) {
return;
@ -4784,6 +4958,10 @@ fil_load_single_table_tablespace(
os_offset_t size;
fil_space_t* space;
fsp_open_info* fsp;
ulong minimum_size;
ibool file_space_create_success;
memset(&def, 0, sizeof(def));
memset(&remote, 0, sizeof(remote));
@ -4839,6 +5017,7 @@ fil_load_single_table_tablespace(
# endif /* !UNIV_HOTBACKUP */
#endif
/* Check for a link file which locates a remote tablespace. */
remote.success = fil_open_linked_file(
tablename, &remote.filepath, &remote.file, FALSE);
@ -4849,6 +5028,17 @@ fil_load_single_table_tablespace(
if (!remote.success) {
os_file_close(remote.file);
mem_free(remote.filepath);
if (srv_backup_mode && (remote.id == ULINT_UNDEFINED
|| remote.id == 0)) {
/* Ignore files that have uninitialized space
IDs on the backup stage. This means that a
tablespace has just been created and we will
replay the corresponding log records on
prepare. */
goto func_exit_after_close;
}
}
}
@ -4863,6 +5053,18 @@ fil_load_single_table_tablespace(
fil_validate_single_table_tablespace(tablename, &def);
if (!def.success) {
os_file_close(def.file);
if (IS_XTRABACKUP() && srv_backup_mode && (def.id == ULINT_UNDEFINED
|| def.id == 0)) {
/* Ignore files that have uninitialized space
IDs on the backup stage. This means that a
tablespace has just been created and we will
replay the corresponding log records on
prepare. */
goto func_exit_after_close;
}
}
}
@ -4948,7 +5150,7 @@ will_not_choose:
/* At this point, only one tablespace is open */
ut_a(def.success == !remote.success);
fsp_open_info* fsp = def.success ? &def : &remote;
fsp = def.success ? &def : &remote;
/* Get and test the file size. */
size = os_file_get_size(fsp->file);
@ -4967,19 +5169,14 @@ will_not_choose:
/* Every .ibd file is created >= 4 pages in size. Smaller files
cannot be ok. */
ulong minimum_size = FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE;
minimum_size = FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE;
if (size < minimum_size) {
#ifndef UNIV_HOTBACKUP
ib_logf(IB_LOG_LEVEL_ERROR,
"The size of single-table tablespace file %s "
"is only " UINT64PF ", should be at least %lu!",
fsp->filepath, size, minimum_size);
os_file_close(fsp->file);
goto no_good_file;
#else
fsp->id = ULINT_UNDEFINED;
fsp->flags = 0;
#endif /* !UNIV_HOTBACKUP */
}
#ifdef UNIV_HOTBACKUP
@ -5050,6 +5247,7 @@ will_not_choose:
}
mutex_exit(&fil_system->mutex);
#endif /* UNIV_HOTBACKUP */
/* Adjust the memory-based flags that would normally be set by
dict_tf_to_fsp_flags(). In recovery, we have no data dictionary. */
if (FSP_FLAGS_HAS_PAGE_COMPRESSION(fsp->flags)) {
@ -5060,7 +5258,7 @@ will_not_choose:
/* We will leave atomic_writes at ATOMIC_WRITES_DEFAULT.
That will be adjusted in fil_space_for_table_exists_in_mem(). */
ibool file_space_create_success = fil_space_create(
file_space_create_success = fil_space_create(
tablename, fsp->id, fsp->flags, FIL_TABLESPACE,
fsp->crypt_data, false);
@ -5088,13 +5286,56 @@ will_not_choose:
}
func_exit:
os_file_close(fsp->file);
/* We reuse file handles on the backup stage in XtraBackup to avoid
inconsistencies between the file name and the actual tablespace contents
if a DDL occurs between a fil_load_single_table_tablespaces() call and
the actual copy operation. */
if (IS_XTRABACKUP() && srv_backup_mode && !srv_close_files) {
fil_node_t* node;
fil_space_t* space;
mutex_enter(&fil_system->mutex);
space = fil_space_get_by_id(fsp->id);
if (space) {
node = UT_LIST_GET_LAST(space->chain);
/* The handle will be closed by xtrabackup in
xtrabackup_copy_datafile(). We set node->open to TRUE to
make sure no one calls fil_node_open_file()
(i.e. attempts to reopen the tablespace by name) during
the backup stage. */
node->open = TRUE;
node->handle = fsp->file;
/* The following is copied from fil_node_open_file() to
pass fil_system validaty checks. We cannot use
fil_node_open_file() directly, as that would re-open the
file by name and create another file handle. */
fil_system->n_open++;
fil_n_file_opened++;
if (fil_space_belongs_in_lru(space)) {
/* Put the node to the LRU list */
UT_LIST_ADD_FIRST(LRU, fil_system->LRU, node);
}
}
mutex_exit(&fil_system->mutex);
}
else {
os_file_close(fsp->file);
}
#ifdef UNIV_HOTBACKUP
func_exit_after_close:
#else
ut_ad(!mutex_own(&fil_system->mutex));
#endif
mem_free(tablename);
if (remote.success) {
mem_free(remote.filepath);
@ -5108,7 +5349,7 @@ directory. We retry 100 times if os_file_readdir_next_file() returns -1. The
idea is to read as much good data as we can and jump over bad data.
@return 0 if ok, -1 if error even after the retries, 1 if at the end
of the directory */
static
UNIV_INTERN
int
fil_file_readdir_next_file(
/*=======================*/
@ -5149,7 +5390,7 @@ space id is != 0.
@return DB_SUCCESS or error number */
UNIV_INTERN
dberr_t
fil_load_single_table_tablespaces(void)
fil_load_single_table_tablespaces(ibool (*pred)(const char*, const char*))
/*===================================*/
{
int ret;
@ -5224,14 +5465,20 @@ fil_load_single_table_tablespaces(void)
goto next_file_item;
}
/* We found a symlink or a file */
/* We found a symlink or a file
Ignore .isl files on XtraBackup
recovery, all tablespaces must be local. */
if (strlen(fileinfo.name) > 4
&& (0 == strcmp(fileinfo.name
+ strlen(fileinfo.name) - 4,
".ibd")
|| 0 == strcmp(fileinfo.name
+ strlen(fileinfo.name) - 4,
".isl"))) {
|| ((!IS_XTRABACKUP() || srv_backup_mode)
&& 0 == strcmp(fileinfo.name
+ strlen(fileinfo.name) - 4,
".isl")))
&& (!pred ||
pred(dbinfo.name, fileinfo.name))) {
/* The name ends in .ibd or .isl;
try opening the file */
fil_load_single_table_tablespace(
@ -5387,6 +5634,9 @@ fil_space_for_table_exists_in_mem(
information to the .err log if a
matching tablespace is not found from
memory */
bool remove_from_data_dict_if_does_not_exist,
/*!< in: remove from the data dictionary
if tablespace does not exist */
bool adjust_space, /*!< in: whether to adjust space id
when find table space mismatch */
mem_heap_t* heap, /*!< in: heap memory */
@ -5457,6 +5707,11 @@ fil_space_for_table_exists_in_mem(
if (fnamespace == NULL) {
if (print_error_if_does_not_exist) {
fil_report_missing_tablespace(name, id);
if (IS_XTRABACKUP() && remove_from_data_dict_if_does_not_exist) {
ib_logf(IB_LOG_LEVEL_WARN,
"It will be removed from "
"the data dictionary.");
}
}
} else {
ut_print_timestamp(stderr);
@ -6119,7 +6374,7 @@ _fil_io(
/* Check that at least the start offset is within the bounds of a
single-table tablespace, including rollback tablespaces. */
if (UNIV_UNLIKELY(node->size <= block_offset)
&& space->id != 0 && space->purpose == FIL_TABLESPACE) {
&& space->id != 0 && space->purpose == FIL_TABLESPACE) {
fil_report_invalid_page_access(
block_offset, space_id, space->name, byte_offset,

View File

@ -284,7 +284,8 @@ static TYPELIB innodb_stats_method_typelib = {
/** Possible values for system variables "innodb_checksum_algorithm" and
"innodb_log_checksum_algorithm". */
static const char* innodb_checksum_algorithm_names[] = {
UNIV_INTERN
const char* innodb_checksum_algorithm_names[] = {
"CRC32",
"STRICT_CRC32",
"INNODB",
@ -296,7 +297,8 @@ static const char* innodb_checksum_algorithm_names[] = {
/** Used to define an enumerate type of the system variables
innodb_checksum_algorithm and innodb_log_checksum_algorithm. */
static TYPELIB innodb_checksum_algorithm_typelib = {
UNIV_INTERN
TYPELIB innodb_checksum_algorithm_typelib = {
array_elements(innodb_checksum_algorithm_names) - 1,
"innodb_checksum_algorithm_typelib",
innodb_checksum_algorithm_names,
@ -2013,7 +2015,9 @@ thd_supports_xa(
THD* thd) /*!< in: thread handle, or NULL to query
the global innodb_supports_xa */
{
return(THDVAR(thd, support_xa));
/* THDVAR cannot be used in xtrabackup,
plugin variables for innodb are not loaded. */
return (thd || !IS_XTRABACKUP())? THDVAR(thd, support_xa): FALSE;
}
/** Get the value of innodb_tmpdir.
@ -2046,7 +2050,9 @@ thd_fake_changes(
THD* thd) /*!< in: thread handle, or NULL to query
the global innodb_supports_xa */
{
return(THDVAR((THD*) thd, fake_changes));
/* THDVAR cannot be used in xtrabackup,
plugin variables for innodb are not loaded */
return (thd || !IS_XTRABACKUP())? THDVAR((THD*) thd, fake_changes) : FALSE ;
}
/******************************************************************//**
@ -2086,7 +2092,10 @@ thd_flush_log_at_trx_commit(
/*================================*/
void* thd)
{
return(THDVAR((THD*) thd, flush_log_at_trx_commit));
/* THDVAR cannot be used in xtrabackup,
plugin variables for innodb are not loaded,
this makes xtrabackup crash when trying to use them. */
return (thd || !IS_XTRABACKUP())? THDVAR((THD*)thd, flush_log_at_trx_commit) : FALSE;
}
/********************************************************************//**
@ -3053,7 +3062,7 @@ trx_is_started(
/****************************************************************//**
Update log_checksum_algorithm_ptr with a pointer to the function corresponding
to a given checksum algorithm. */
static
void
innodb_log_checksum_func_update(
/*============================*/
@ -21951,22 +21960,27 @@ ib_logf(
str = static_cast<char*>(malloc(BUFSIZ));
my_vsnprintf(str, BUFSIZ, format, args);
#endif /* __WIN__ */
switch(level) {
case IB_LOG_LEVEL_INFO:
sql_print_information("InnoDB: %s", str);
break;
case IB_LOG_LEVEL_WARN:
sql_print_warning("InnoDB: %s", str);
break;
case IB_LOG_LEVEL_ERROR:
sql_print_error("InnoDB: %s", str);
sd_notifyf(0, "STATUS=InnoDB: Error: %s", str);
break;
case IB_LOG_LEVEL_FATAL:
sql_print_error("InnoDB: %s", str);
sd_notifyf(0, "STATUS=InnoDB: Fatal: %s", str);
break;
if (!IS_XTRABACKUP()) {
switch (level) {
case IB_LOG_LEVEL_INFO:
sql_print_information("InnoDB: %s", str);
break;
case IB_LOG_LEVEL_WARN:
sql_print_warning("InnoDB: %s", str);
break;
case IB_LOG_LEVEL_ERROR:
sql_print_error("InnoDB: %s", str);
sd_notifyf(0, "STATUS=InnoDB: Error: %s", str);
break;
case IB_LOG_LEVEL_FATAL:
sql_print_error("InnoDB: %s", str);
sd_notifyf(0, "STATUS=InnoDB: Fatal: %s", str);
break;
}
}
else {
/* Don't use server logger for XtraBackup, just print to stderr. */
fprintf(stderr, "InnoDB: %s\n", str);
}
va_end(args);

View File

@ -136,6 +136,7 @@ extern fil_addr_t fil_addr_null;
#define FIL_PAGE_DATA 38 /*!< start of the data on the page */
/* Following are used when page compression is used */
#define FIL_PAGE_COMPRESSED_SIZE 2 /*!< Number of bytes used to store
actual payload data size on
compressed pages. */
@ -1042,7 +1043,7 @@ space id is != 0.
@return DB_SUCCESS or error number */
UNIV_INTERN
dberr_t
fil_load_single_table_tablespaces(void);
fil_load_single_table_tablespaces(ibool (*pred)(const char*, const char*)=0);
/*===================================*/
/*******************************************************************//**
Returns TRUE if a single-table tablespace does not exist in the memory cache,
@ -1081,6 +1082,9 @@ fil_space_for_table_exists_in_mem(
information to the .err log if a
matching tablespace is not found from
memory */
bool remove_from_data_dict_if_does_not_exist,
/*!< in: remove from the data dictionary
if tablespace does not exist */
bool adjust_space, /*!< in: whether to adjust space id
when find table space mismatch */
mem_heap_t* heap, /*!< in: heap memory */

View File

@ -499,7 +499,9 @@ as enum type because the configure option takes unsigned integer type. */
extern ulong srv_innodb_stats_method;
#ifdef UNIV_LOG_ARCHIVE
extern ibool srv_log_archive_on;
extern bool srv_log_archive_on;
extern bool srv_archive_recovery;
extern ib_uint64_t srv_archive_recovery_limit_lsn;
#endif /* UNIV_LOG_ARCHIVE */
extern char* srv_file_flush_method_str;
@ -550,6 +552,14 @@ extern ulong srv_pass_corrupt_table;
extern ulong srv_log_checksum_algorithm;
extern bool srv_apply_log_only;
extern bool srv_backup_mode;
extern bool srv_close_files;
extern bool srv_xtrabackup;
#define IS_XTRABACKUP() (srv_xtrabackup)
extern my_bool srv_force_primary_key;
/* Helper macro to support srv_pass_corrupt_table checks. If 'cond' is FALSE,

View File

@ -336,8 +336,9 @@ trx_sys_update_wsrep_checkpoint(
trx_sysf_t* sys_header, /*!< in: sys_header */
mtr_t* mtr); /*!< in: mtr */
void
/** Read WSREP checkpoint XID from sys header. */
/** Read WSREP checkpoint XID from sys header.
@return true on success, false on error. */
bool
trx_sys_read_wsrep_checkpoint(
XID* xid); /*!< out: WSREP XID */
#endif /* WITH_WSREP */

View File

@ -635,7 +635,7 @@ functions. */
#ifdef __WIN__
#define usleep(a) Sleep((a)/1000)
typedef ulint os_thread_ret_t;
typedef DWORD os_thread_ret_t;
#define OS_THREAD_DUMMY_RETURN return(0)
#else
typedef void* os_thread_ret_t;

View File

@ -2629,7 +2629,7 @@ loop:
start_lsn += len;
buf += len;
if (recv_sys->report(ut_time())) {
if (recv_sys && recv_sys->report(ut_time())) {
ib_logf(IB_LOG_LEVEL_INFO, "Read redo log up to LSN=" LSN_PF,
start_lsn);
sd_notifyf(0, "STATUS=Read redo log up to LSN=" LSN_PF,

View File

@ -692,7 +692,6 @@ recv_synchronize_groups(
/***********************************************************************//**
Checks the consistency of the checkpoint info
@return TRUE if ok */
static
ibool
recv_check_cp_is_consistent(
/*========================*/
@ -722,7 +721,7 @@ recv_check_cp_is_consistent(
/********************************************************//**
Looks for the maximum consistent checkpoint from the log groups.
@return error code or DB_SUCCESS */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
recv_find_max_checkpoint(
/*=====================*/
@ -3474,6 +3473,7 @@ recv_recovery_from_checkpoint_finish(void)
#ifdef __WIN__
if (recv_writer_thread_handle) {
CloseHandle(recv_writer_thread_handle);
recv_writer_thread_handle = 0;
}
#endif /* __WIN__ */
@ -3700,6 +3700,102 @@ recv_reset_log_files_for_backup(
}
#endif /* UNIV_HOTBACKUP */
/******************************************************//**
Checks the 4-byte checksum to the trailer checksum field of a log
block. We also accept a log block in the old format before
InnoDB-3.23.52 where the checksum field contains the log block number.
@return TRUE if ok, or if the log block may be in the format of InnoDB
version predating 3.23.52 */
UNIV_INTERN
ibool
log_block_checksum_is_ok_or_old_format(
/*===================================*/
const byte* block) /*!< in: pointer to a log block */
{
#ifdef UNIV_LOG_DEBUG
return(TRUE);
#endif /* UNIV_LOG_DEBUG */
ulint block_checksum = log_block_get_checksum(block);
if (UNIV_LIKELY(srv_log_checksum_algorithm ==
SRV_CHECKSUM_ALGORITHM_NONE ||
log_block_calc_checksum(block) == block_checksum)) {
return(TRUE);
}
if (srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32 ||
srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB ||
srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_NONE) {
const char* algo = NULL;
ib_logf(IB_LOG_LEVEL_ERROR,
"log block checksum mismatch: expected " ULINTPF ", "
"calculated checksum " ULINTPF,
block_checksum,
log_block_calc_checksum(block));
if (block_checksum == LOG_NO_CHECKSUM_MAGIC) {
algo = "none";
} else if (block_checksum ==
log_block_calc_checksum_crc32(block)) {
algo = "crc32";
} else if (block_checksum ==
log_block_calc_checksum_innodb(block)) {
algo = "innodb";
}
if (algo) {
const char* current_algo;
current_algo = buf_checksum_algorithm_name(
(srv_checksum_algorithm_t)
srv_log_checksum_algorithm);
ib_logf(IB_LOG_LEVEL_ERROR,
"current InnoDB log checksum type: %s, "
"detected log checksum type: %s",
current_algo,
algo);
}
ib_logf(IB_LOG_LEVEL_FATAL,
"STRICT method was specified for innodb_log_checksum, "
"so we intentionally assert here.");
}
ut_ad(srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_CRC32 ||
srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_INNODB);
if (block_checksum == LOG_NO_CHECKSUM_MAGIC ||
block_checksum == log_block_calc_checksum_crc32(block) ||
block_checksum == log_block_calc_checksum_innodb(block)) {
return(TRUE);
}
if (log_block_get_hdr_no(block) == block_checksum) {
/* We assume the log block is in the format of
InnoDB version < 3.23.52 and the block is ok */
#if 0
fprintf(stderr,
"InnoDB: Scanned old format < InnoDB-3.23.52"
" log block number %lu\n",
log_block_get_hdr_no(block));
#endif
return(TRUE);
}
return(FALSE);
}
void recv_dblwr_t::add(byte* page)
{
pages.push_back(page);

View File

@ -130,7 +130,7 @@ UNIV_INTERN os_ib_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES];
#define OS_AIO_MERGE_N_CONSECUTIVE 64
#ifdef WITH_INNODB_DISALLOW_WRITES
#define WAIT_ALLOW_WRITES() os_event_wait(srv_allow_writes_event)
#define WAIT_ALLOW_WRITES() if (!IS_XTRABACKUP()) os_event_wait(srv_allow_writes_event)
#else
#define WAIT_ALLOW_WRITES() do { } while (0)
#endif /* WITH_INNODB_DISALLOW_WRITES */
@ -1001,7 +1001,6 @@ os_file_lock(
#ifndef UNIV_HOTBACKUP
/****************************************************************//**
Creates the seek mutexes used in positioned reads and writes. */
static
void
os_io_init_simple(void)
/*===================*/
@ -1640,6 +1639,10 @@ os_file_create_simple_no_error_handling_func(
return((os_file_t) -1);
}
if (IS_XTRABACKUP()) {
share_mode |= FILE_SHARE_DELETE | FILE_SHARE_WRITE;
}
file = CreateFile((LPCTSTR) name,
access,
share_mode,
@ -1921,7 +1924,10 @@ os_file_create_func(
create_mode &= ~OS_FILE_ON_ERROR_NO_EXIT;
create_mode &= ~OS_FILE_ON_ERROR_SILENT;
if (srv_backup_mode){
/* Permit others to write, while I'm reading. */
share_mode |= FILE_SHARE_WRITE;
}
if (create_mode == OS_FILE_OPEN_RAW) {
ut_a(!srv_read_only_mode);
@ -3525,7 +3531,7 @@ os_file_get_status(
fh = CreateFile(
(LPCTSTR) path, // File to open
access,
0, // No sharing
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, // Default security
OPEN_EXISTING, // Existing file only
FILE_ATTRIBUTE_NORMAL, // Normal file

View File

@ -4483,8 +4483,9 @@ row_drop_table_for_mysql(
if (!is_temp
&& !fil_space_for_table_exists_in_mem(
space_id, tablename,
print_msg, false, NULL, 0,
print_msg, IS_XTRABACKUP() && print_msg, false, NULL, 0,
table_flags)) {
/* This might happen if we are dropping a
discarded tablespace */
err = DB_SUCCESS;

View File

@ -203,7 +203,7 @@ performance killer causing calling thread to context switch. Besides, Innodb
is preallocating large number (often millions) of os_events. With kernel event
objects it takes a big chunk out of non-paged pool, which is better suited
for tasks like IO than for storing idle event objects. */
UNIV_INTERN ibool srv_use_native_conditions = FALSE;
UNIV_INTERN ibool srv_use_native_conditions = TRUE;
#endif /* __WIN__ */
UNIV_INTERN ulint srv_n_data_files = 0;
@ -366,7 +366,9 @@ readahead request. */
UNIV_INTERN ulong srv_read_ahead_threshold = 56;
#ifdef UNIV_LOG_ARCHIVE
UNIV_INTERN ibool srv_log_archive_on = FALSE;
UNIV_INTERN bool srv_log_archive_on;
UNIV_INTERN bool srv_archive_recovery;
UNIV_INTERN ib_uint64_t srv_archive_recovery_limit_lsn;
#endif /* UNIV_LOG_ARCHIVE */
/* This parameter is used to throttle the number of insert buffers that are
@ -522,6 +524,12 @@ UNIV_INTERN ulong srv_doublewrite_batch_size = 120;
UNIV_INTERN ulong srv_replication_delay = 0;
UNIV_INTERN bool srv_apply_log_only;
UNIV_INTERN bool srv_backup_mode;
UNIV_INTERN bool srv_close_files;
UNIV_INTERN bool srv_xtrabackup;
UNIV_INTERN ulong srv_pass_corrupt_table = 0; /* 0:disable 1:enable */
UNIV_INTERN ulong srv_log_checksum_algorithm =

View File

@ -140,7 +140,7 @@ SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
UNIV_INTERN enum srv_shutdown_state srv_shutdown_state = SRV_SHUTDOWN_NONE;
/** Files comprising the system tablespace */
static os_file_t files[1000];
os_file_t files[1000];
/** io_handler_thread parameters for thread identification */
static ulint n[SRV_MAX_N_IO_THREADS];
@ -826,7 +826,7 @@ open_log_file(
/*********************************************************************//**
Creates or opens database data files and closes them.
@return DB_SUCCESS or error code */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
open_or_create_data_files(
/*======================*/
@ -1080,8 +1080,10 @@ skip_size_check:
/* This is the earliest location where we can load
the double write buffer. */
if (i == 0) {
/* XtraBackup never loads corrupted pages from
the doublewrite buffer */
buf_dblwr_init_or_load_pages(
files[i], srv_data_file_names[i], true);
files[i], srv_data_file_names[i], !IS_XTRABACKUP());
}
bool retry = true;
@ -1365,12 +1367,15 @@ srv_undo_tablespace_open(
/********************************************************************
Opens the configured number of undo tablespaces.
@return DB_SUCCESS or error code */
static
dberr_t
srv_undo_tablespaces_init(
/*======================*/
ibool create_new_db, /*!< in: TRUE if new db being
created */
ibool backup_mode, /*!< in: TRUE disables reading
the system tablespace (used in
XtraBackup), FALSE is passed on
recovery. */
const ulint n_conf_tablespaces, /*!< in: configured undo
tablespaces */
ulint* n_opened) /*!< out: number of UNDO
@ -1424,7 +1429,7 @@ srv_undo_tablespaces_init(
we build the undo_tablespace_ids ourselves since they don't
already exist. */
if (!create_new_db) {
if (!create_new_db && !backup_mode) {
n_undo_tablespaces = trx_rseg_get_n_undo_tablespaces(
undo_tablespace_ids);
} else {
@ -2318,11 +2323,11 @@ innobase_start_or_create_for_mysql(void)
max_flushed_lsn = min_flushed_lsn
= log_get_lsn();
goto files_checked;
} else if (i < 2) {
/* must have at least 2 log files */
ib_logf(IB_LOG_LEVEL_ERROR,
"Only one log file found.");
return(err);
} else if (i < 2 && !IS_XTRABACKUP()) {
/* must have at least 2 log files */
ib_logf(IB_LOG_LEVEL_ERROR,
"Only one log file found.");
return(err);
}
/* opened all files */
@ -2416,6 +2421,7 @@ files_checked:
err = srv_undo_tablespaces_init(
create_new_db,
FALSE,
srv_undo_tablespaces,
&srv_undo_tablespaces_open);
@ -2689,6 +2695,17 @@ files_checked:
dict_check_tablespaces_and_store_max_id(dict_check);
}
if (IS_XTRABACKUP()
&& !srv_backup_mode
&& srv_read_only_mode
&& srv_log_file_size_requested != srv_log_file_size) {
ib_logf(IB_LOG_LEVEL_WARN,
"Log files size mismatch, ignored in readonly mode");
srv_log_file_size_requested = srv_log_file_size;
}
if (!srv_force_recovery
&& !recv_sys->found_corrupt_log
&& (srv_log_file_size_requested != srv_log_file_size
@ -3323,7 +3340,8 @@ innobase_shutdown_for_mysql(void)
srv_was_started = FALSE;
srv_start_has_been_called = FALSE;
/* reset io_tid_i, in case current process does second innodb start (xtrabackup might do that).*/
io_tid_i = 0;
return(DB_SUCCESS);
}
#endif /* !UNIV_HOTBACKUP */

View File

@ -397,7 +397,7 @@ trx_sys_update_wsrep_checkpoint(
}
void
bool
trx_sys_read_wsrep_checkpoint(XID* xid)
/*===================================*/
{
@ -418,7 +418,7 @@ trx_sys_read_wsrep_checkpoint(XID* xid)
xid->formatID = -1;
trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
mtr_commit(&mtr);
return;
return false;
}
xid->formatID = (int)mach_read_from_4(
@ -435,6 +435,7 @@ trx_sys_read_wsrep_checkpoint(XID* xid)
XIDDATASIZE);
mtr_commit(&mtr);
return true;
}
#endif /* WITH_WSREP */
@ -1330,14 +1331,17 @@ trx_sys_close(void)
trx_purge_sys_close();
/* Free the double write data structures. */
buf_dblwr_free();
if (buf_dblwr) {
buf_dblwr_free();
}
ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
/* Only prepared transactions may be left in the system. Free them. */
ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == trx_sys->n_prepared_trx
|| srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
|| (IS_XTRABACKUP() && srv_apply_log_only));
while ((trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list)) != NULL) {
trx_free_prepared(trx);
@ -1368,10 +1372,12 @@ trx_sys_close(void)
UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view);
}
ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
if (!IS_XTRABACKUP() || !srv_apply_log_only) {
ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
}
mutex_free(&trx_sys->mutex);
@ -1418,6 +1424,9 @@ ulint
trx_sys_any_active_transactions(void)
/*=================================*/
{
if (IS_XTRABACKUP() && srv_apply_log_only) {
return(0);
}
mutex_enter(&trx_sys->mutex);
ulint total_trx = UT_LIST_GET_LEN(trx_sys->mysql_trx_list);

View File

@ -721,9 +721,16 @@ trx_resurrect_insert(
if (srv_force_recovery == 0) {
trx->state = TRX_STATE_PREPARED;
trx_sys->n_prepared_trx++;
trx_sys->n_prepared_recovered_trx++;
/* XtraBackup should rollback prepared XA
transactions */
if (IS_XTRABACKUP()) {
trx->state = TRX_STATE_ACTIVE;
}
else {
trx->state = TRX_STATE_PREPARED;
trx_sys->n_prepared_trx++;
trx_sys->n_prepared_recovered_trx++;
}
} else {
fprintf(stderr,
"InnoDB: Since innodb_force_recovery"
@ -790,13 +797,16 @@ trx_resurrect_update_in_prepared_state(
if (srv_force_recovery == 0) {
if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) {
trx_sys->n_prepared_trx++;
trx_sys->n_prepared_recovered_trx++;
if (!IS_XTRABACKUP()) {
trx_sys->n_prepared_trx++;
trx_sys->n_prepared_recovered_trx++;
}
} else {
ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED));
}
trx->state = TRX_STATE_PREPARED;
/* XtraBackup should rollback prepared XA
transactions */
trx->state = IS_XTRABACKUP()?TRX_STATE_ACTIVE: TRX_STATE_PREPARED;
} else {
fprintf(stderr,
"InnoDB: Since innodb_force_recovery"