row0purge.c, row0mysql.c, os0file.c, os0file.h, fil0fil.h, fil0fil.c:
IMPORT TABLESPACE must reset lsns if they are too high ha_innodb.cc: DISCARD/IMPORT TABLESPACE must have a TL_WRITE lock on the table sql/ha_innodb.cc: DISCARD/IMPORT TABLESPACE must have a TL_WRITE lock on the table innobase/fil/fil0fil.c: IMPORT TABLESPACE must reset lsns if they are too high innobase/include/fil0fil.h: IMPORT TABLESPACE must reset lsns if they are too high innobase/include/os0file.h: IMPORT TABLESPACE must reset lsns if they are too high innobase/os/os0file.c: IMPORT TABLESPACE must reset lsns if they are too high innobase/row/row0mysql.c: IMPORT TABLESPACE must reset lsns if they are too high innobase/row/row0purge.c: IMPORT TABLESPACE must reset lsns if they are too high
This commit is contained in:
parent
cec45b6acf
commit
d9709ffeb0
@ -1302,11 +1302,13 @@ fil_write_flushed_lsn_to_data_files(
|
||||
space = UT_LIST_GET_FIRST(fil_system->space_list);
|
||||
|
||||
while (space) {
|
||||
/* We only write the lsn to the system tablespace
|
||||
(space id == 0) files */
|
||||
/* We only write the lsn to all existing data files which have
|
||||
been open during the lifetime of the mysqld process; they are
|
||||
represented by the space objects in the tablespace memory
|
||||
cache. Note that all data files in the system tablespace 0 are
|
||||
always open. */
|
||||
|
||||
if (space->id == 0) {
|
||||
ut_a(space->purpose == FIL_TABLESPACE);
|
||||
if (space->purpose == FIL_TABLESPACE) {
|
||||
sum_of_sizes = 0;
|
||||
|
||||
node = UT_LIST_GET_FIRST(space->chain);
|
||||
@ -1326,8 +1328,6 @@ fil_write_flushed_lsn_to_data_files(
|
||||
sum_of_sizes += node->size;
|
||||
node = UT_LIST_GET_NEXT(chain, node);
|
||||
}
|
||||
|
||||
break; /* there is only one space with id == 0 */
|
||||
}
|
||||
space = UT_LIST_GET_NEXT(space_list, space);
|
||||
}
|
||||
@ -1937,6 +1937,147 @@ fil_create_new_single_table_tablespace(
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
It is possible, though very improbable, that the lsn's in the tablespace to be
|
||||
imported have risen above the current system lsn, if a lengthy purge, ibuf
|
||||
merge, or rollback was performed on a backup taken with ibbackup. If that is
|
||||
the case, reset page lsn's in the file. We assume that mysqld was shut down
|
||||
after it performed these cleanup operations on the .ibd file, so that it at
|
||||
the shutdown stamped the latest lsn to the FIL_PAGE_FILE_FLUSH_LSN in the
|
||||
first page of the .ibd file, and we can determine whether we need to reset the
|
||||
lsn's just by looking at that flush lsn. */
|
||||
|
||||
ibool
|
||||
fil_reset_too_high_lsns(
|
||||
/*====================*/
|
||||
/* out: TRUE if success */
|
||||
char* name, /* in: table name in the databasename/tablename
|
||||
format */
|
||||
dulint current_lsn) /* in: reset lsn's if the lsn stamped to
|
||||
FIL_PAGE_FILE_FLUSH_LSN in the first page is
|
||||
too high */
|
||||
{
|
||||
os_file_t file;
|
||||
char* filepath;
|
||||
byte* page;
|
||||
dulint flush_lsn;
|
||||
ulint space_id;
|
||||
ib_longlong file_size;
|
||||
ib_longlong offset;
|
||||
ulint page_no;
|
||||
ibool success;
|
||||
|
||||
filepath = ut_malloc(OS_FILE_MAX_PATH);
|
||||
|
||||
ut_a(strlen(name) < OS_FILE_MAX_PATH - 10);
|
||||
|
||||
sprintf(filepath, "./%s.ibd", name);
|
||||
|
||||
srv_normalize_path_for_win(filepath);
|
||||
|
||||
file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN,
|
||||
OS_FILE_READ_WRITE, &success);
|
||||
if (!success) {
|
||||
ut_free(filepath);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/* Read the first page of the tablespace */
|
||||
|
||||
page = ut_malloc(UNIV_PAGE_SIZE);
|
||||
|
||||
success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE);
|
||||
if (!success) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
/* We have to read the file flush lsn from the header of the file */
|
||||
|
||||
flush_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN);
|
||||
|
||||
if (ut_dulint_cmp(current_lsn, flush_lsn) >= 0) {
|
||||
/* Ok */
|
||||
success = TRUE;
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
space_id = fsp_header_get_space_id(page);
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Flush lsn in the tablespace file %lu to be imported\n"
|
||||
"InnoDB: is %lu %lu, which exceeds current system lsn %lu %lu.\n"
|
||||
"InnoDB: We reset the lsn's in the file %s.\n",
|
||||
space_id,
|
||||
ut_dulint_get_high(flush_lsn),
|
||||
ut_dulint_get_low(flush_lsn),
|
||||
ut_dulint_get_high(current_lsn),
|
||||
ut_dulint_get_low(current_lsn), filepath);
|
||||
|
||||
/* Loop through all the pages in the tablespace and reset the lsn and
|
||||
the page checksum if necessary */
|
||||
|
||||
file_size = os_file_get_size_as_iblonglong(file);
|
||||
|
||||
for (offset = 0; offset < file_size; offset += UNIV_PAGE_SIZE) {
|
||||
success = os_file_read(file, page,
|
||||
(ulint)(offset & 0xFFFFFFFFUL),
|
||||
(ulint)(offset >> 32), UNIV_PAGE_SIZE);
|
||||
if (!success) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
if (ut_dulint_cmp(mach_read_from_8(page + FIL_PAGE_LSN),
|
||||
current_lsn) > 0) {
|
||||
/* We have to reset the lsn */
|
||||
space_id = mach_read_from_4(page
|
||||
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
|
||||
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
|
||||
|
||||
buf_flush_init_for_writing(page, current_lsn, space_id,
|
||||
page_no);
|
||||
success = os_file_write(filepath, file, page,
|
||||
(ulint)(offset & 0xFFFFFFFFUL),
|
||||
(ulint)(offset >> 32), UNIV_PAGE_SIZE);
|
||||
if (!success) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
success = os_file_flush(file);
|
||||
if (!success) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
/* We now update the flush_lsn stamp at the start of the file */
|
||||
success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE);
|
||||
if (!success) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
mach_write_to_8(page + FIL_PAGE_FILE_FLUSH_LSN, current_lsn);
|
||||
|
||||
success = os_file_write(filepath, file, page, 0, 0, UNIV_PAGE_SIZE);
|
||||
if (!success) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
success = os_file_flush(file);
|
||||
func_exit:
|
||||
os_file_close(file);
|
||||
ut_free(page);
|
||||
ut_free(filepath);
|
||||
|
||||
return(success);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Tries to open a single-table tablespace and checks the space id is right in
|
||||
it. If does not succeed, prints an error message to the .err log. This
|
||||
@ -1982,7 +2123,9 @@ fil_open_single_table_tablespace(
|
||||
"InnoDB: open the tablespace file %s!\n", filepath);
|
||||
fprintf(stderr,
|
||||
"InnoDB: have you moved InnoDB .ibd files around without using the\n"
|
||||
"InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n");
|
||||
"InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n"
|
||||
"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
|
||||
"InnoDB: how to resolve the issue.\n");
|
||||
|
||||
ut_free(filepath);
|
||||
|
||||
@ -2007,7 +2150,9 @@ fil_open_single_table_tablespace(
|
||||
"InnoDB: data dictionary it is %lu.\n", filepath, space_id, id);
|
||||
fprintf(stderr,
|
||||
"InnoDB: Have you moved InnoDB .ibd files around without using the\n"
|
||||
"InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n");
|
||||
"InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n"
|
||||
"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
|
||||
"InnoDB: how to resolve the issue.\n");
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
|
@ -326,6 +326,25 @@ fil_open_single_table_tablespace(
|
||||
char* name); /* in: table name in the databasename/tablename
|
||||
format */
|
||||
/************************************************************************
|
||||
It is possible, though very improbable, that the lsn's in the tablespace to be
|
||||
imported have risen above the current system lsn, if a lengthy purge, ibuf
|
||||
merge, or rollback was performed on a backup taken with ibbackup. If that is
|
||||
the case, reset page lsn's in the file. We assume that mysqld was shut down
|
||||
after it performed these cleanup operations on the .ibd file, so that it at
|
||||
the shutdown stamped the latest lsn to the FIL_PAGE_FILE_FLUSH_LSN in the
|
||||
first page of the .ibd file, and we can determine whether we need to reset the
|
||||
lsn's just by looking at that flush lsn. */
|
||||
|
||||
ibool
|
||||
fil_reset_too_high_lsns(
|
||||
/*====================*/
|
||||
/* out: TRUE if success */
|
||||
char* name, /* in: table name in the databasename/tablename
|
||||
format */
|
||||
dulint current_lsn); /* in: reset lsn's if the lsn stamped to
|
||||
FIL_PAGE_FILE_FLUSH_LSN in the first page is
|
||||
too high */
|
||||
/************************************************************************
|
||||
At the server startup, if we need crash recovery, scans the database
|
||||
directories under the MySQL datadir, looking for .ibd files. Those files are
|
||||
single-table tablespaces. We need to know the space id in each of them so that
|
||||
|
@ -301,6 +301,14 @@ os_file_get_size(
|
||||
size */
|
||||
ulint* size_high);/* out: most significant 32 bits of size */
|
||||
/***************************************************************************
|
||||
Gets file size as a 64-bit integer ib_longlong. */
|
||||
|
||||
ib_longlong
|
||||
os_file_get_size_as_iblonglong(
|
||||
/*===========================*/
|
||||
/* out: size in bytes, -1 if error */
|
||||
os_file_t file); /* in: handle to a file */
|
||||
/***************************************************************************
|
||||
Sets a file size. This function can be used to extend or truncate a file. */
|
||||
|
||||
ibool
|
||||
|
@ -1204,6 +1204,29 @@ os_file_get_size(
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Gets file size as a 64-bit integer ib_longlong. */
|
||||
|
||||
ib_longlong
|
||||
os_file_get_size_as_iblonglong(
|
||||
/*===========================*/
|
||||
/* out: size in bytes, -1 if error */
|
||||
os_file_t file) /* in: handle to a file */
|
||||
{
|
||||
ulint size;
|
||||
ulint size_high;
|
||||
ibool success;
|
||||
|
||||
success = os_file_get_size(file, &size, &size_high);
|
||||
|
||||
if (!success) {
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return((((ib_longlong)size_high) << 32) + (ib_longlong)size);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Sets a file size. This function can be used to extend or truncate a file. */
|
||||
|
||||
|
@ -1871,6 +1871,16 @@ row_discard_tablespace_for_mysql(
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
if (table->space == 0) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Error: table %s\n"
|
||||
"InnoDB: is in the system tablespace 0 which cannot be discarded\n", name);
|
||||
err = DB_ERROR;
|
||||
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
|
||||
|
||||
sprintf(buf,
|
||||
@ -1967,6 +1977,7 @@ row_import_tablespace_for_mysql(
|
||||
{
|
||||
dict_table_t* table;
|
||||
ibool success;
|
||||
dulint current_lsn;
|
||||
ulint err = DB_SUCCESS;
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
@ -1975,6 +1986,30 @@ row_import_tablespace_for_mysql(
|
||||
|
||||
trx->op_info = (char*) "importing tablespace";
|
||||
|
||||
current_lsn = log_get_lsn();
|
||||
|
||||
/* It is possible, though very improbable, that the lsn's in the
|
||||
tablespace to be imported have risen above the current system lsn, if
|
||||
a lengthy purge, ibuf merge, or rollback was performed on a backup
|
||||
taken with ibbackup. If that is the case, reset page lsn's in the
|
||||
file. We assume that mysqld was shut down after it performed these
|
||||
cleanup operations on the .ibd file, so that it stamped the latest lsn
|
||||
to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
|
||||
|
||||
TODO: reset also the trx id's in clustered index records and write
|
||||
a new space id to each data page. That would allow us to import clean
|
||||
.ibd files from another MySQL installation. */
|
||||
|
||||
success = fil_reset_too_high_lsns(name, current_lsn);
|
||||
|
||||
if (!success) {
|
||||
err = DB_ERROR;
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
@ -1988,6 +2023,16 @@ row_import_tablespace_for_mysql(
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
if (table->space == 0) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Error: table %s\n"
|
||||
"InnoDB: is in the system tablespace 0 which cannot be imported\n", name);
|
||||
err = DB_ERROR;
|
||||
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
if (!table->tablespace_discarded) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
|
@ -534,7 +534,7 @@ row_purge_parse_undo_rec(
|
||||
|
||||
node->table = NULL;
|
||||
|
||||
return;
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
clust_index = dict_table_get_first_index(node->table);
|
||||
|
@ -4572,8 +4572,7 @@ ha_innobase::external_lock(
|
||||
|
||||
update_thd(thd);
|
||||
|
||||
if (lock_type != F_UNLCK && prebuilt->table->ibd_file_missing
|
||||
&& !current_thd->tablespace_op) {
|
||||
if (prebuilt->table->ibd_file_missing && !current_thd->tablespace_op) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr, " InnoDB error:\n"
|
||||
"MySQL is trying to use a table handle but the .ibd file for\n"
|
||||
|
Loading…
x
Reference in New Issue
Block a user