Skip to content

Commit 3f13631

Browse files
kdjakevinbjornmu
authored andcommitted
Bug #20534616 - FAILURES IN INNODB.INNODB_WL6501_CRASH_* TESTS
The UNDO log is getting corrupted because tablespace and file path data are being updated to the system tables during startup before calling truncate::fixup_tables() which does not expect any changed pages. This patch prevents that from happening in two ways. First, it prevents all updates to SYS_TABLESPACES and SYS_DATAFILES during startup until these two system tables can be properly opened and/or created. Some of these preventions had already been made in wl6205, but a few more are added here. Secondly, it breaks up truncate::fixup_tables() into two halves. The first half works only on tables in the system tablespace and it does that before these two system tables are opened and tablespace discovery is done. In this way, it can be assured that UNDO pages are not changed. Then after tablespace discovery, the rest of the tables are fixed-up. This patch also contains an extra limitation on the frequency of calling dict_replace_tablespace_and_filepath() in fil_ibd_open(). These tablespaces are all initially opened during tablespace discovery. Since the filepath of file-per-table tablespaces are not looked up in SYS_DATAFILES during tablespace discovery (the filepath is still generated from the table name) there is no need to update the dictionary with the filepath generated. It is most likely already there. (cherry picked from commit 7c9b696b6733beff9ca7858b5dfb3f8c75cdb7d6)
1 parent 47f66a3 commit 3f13631

File tree

6 files changed

+144
-33
lines changed

6 files changed

+144
-33
lines changed

storage/innobase/dict/dict0crea.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Created 1/8/1996 Heikki Tuuri
4848
#include "fts0priv.h"
4949
#include "fsp0space.h"
5050
#include "fsp0sysspace.h"
51+
#include "srv0start.h"
5152

5253
/*****************************************************************//**
5354
Based on a table object, this function builds the entry to be inserted
@@ -2060,6 +2061,11 @@ dict_replace_tablespace_in_dictionary(
20602061
trx_t* trx,
20612062
bool commit)
20622063
{
2064+
if (!srv_sys_tablespaces_open) {
2065+
/* Startup procedure is not yet ready for updates. */
2066+
return(DB_SUCCESS);
2067+
}
2068+
20632069
dberr_t error;
20642070

20652071
pars_info_t* info = pars_info_create();
@@ -2111,6 +2117,8 @@ dict_add_datafile_to_dictionary(
21112117
const char* path,
21122118
trx_t* trx)
21132119
{
2120+
ut_ad(srv_sys_tablespaces_open);
2121+
21142122
dberr_t error;
21152123

21162124
pars_info_t* info = pars_info_create();
@@ -2156,6 +2164,7 @@ dict_delete_tablespace_and_datafiles(
21562164
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_X));
21572165
#endif /* UNIV_SYNC_DEBUG */
21582166
ut_ad(mutex_own(&dict_sys->mutex));
2167+
ut_ad(srv_sys_tablespaces_open);
21592168

21602169
trx->op_info = "delete tablespace and datafiles from dictionary";
21612170

storage/innobase/dict/dict0load.cc

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -791,10 +791,6 @@ dict_get_space_name(
791791
ulint space_id,
792792
mem_heap_t* callers_heap)
793793
{
794-
if (!srv_sys_tablespaces_open) {
795-
return(NULL);
796-
}
797-
798794
mtr_t mtr;
799795
dict_table_t* sys_tablespaces;
800796
dict_index_t* sys_index;
@@ -810,9 +806,12 @@ dict_get_space_name(
810806

811807
ut_ad(mutex_own(&dict_sys->mutex));
812808

813-
mtr_start(&mtr);
814-
815809
sys_tablespaces = dict_table_get_low("SYS_TABLESPACES");
810+
if (sys_tablespaces == NULL) {
811+
ut_a(!srv_sys_tablespaces_open);
812+
return(NULL);
813+
}
814+
816815
sys_index = UT_LIST_GET_FIRST(sys_tablespaces->indexes);
817816

818817
ut_ad(!dict_table_is_comp(sys_tablespaces));
@@ -830,6 +829,8 @@ dict_get_space_name(
830829
dfield_set_data(dfield, buf, 4);
831830
dict_index_copy_types(tuple, sys_index, 1);
832831

832+
mtr_start(&mtr);
833+
833834
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
834835
BTR_SEARCH_LEAF, &pcur, &mtr);
835836

@@ -884,6 +885,11 @@ dict_update_filepath(
884885
ulint space_id,
885886
const char* filepath)
886887
{
888+
if (!srv_sys_tablespaces_open) {
889+
/* Startup procedure is not yet ready for updates. */
890+
return(DB_SUCCESS);
891+
}
892+
887893
dberr_t err = DB_SUCCESS;
888894
trx_t* trx;
889895

@@ -944,6 +950,13 @@ dict_replace_tablespace_and_filepath(
944950
const char* filepath,
945951
ulint fsp_flags)
946952
{
953+
if (!srv_sys_tablespaces_open) {
954+
/* Startup procedure is not yet ready for updates.
955+
Return success since this will likely get updated
956+
later. */
957+
return(DB_SUCCESS);
958+
}
959+
947960
dberr_t err = DB_SUCCESS;
948961
trx_t* trx;
949962

@@ -984,6 +997,13 @@ dict_add_filepath(
984997
ulint space_id,
985998
const char* filepath)
986999
{
1000+
if (!srv_sys_tablespaces_open) {
1001+
/* Startup procedure is not yet ready for updates.
1002+
Return success since this will likely get updated
1003+
later. */
1004+
return(DB_SUCCESS);
1005+
}
1006+
9871007
dberr_t err = DB_SUCCESS;
9881008
trx_t* trx;
9891009

@@ -2572,15 +2592,17 @@ dict_get_and_save_space_name(
25722592
}
25732593

25742594
/* Read it from the dictionary. */
2575-
if (!dict_mutex_own) {
2576-
dict_mutex_enter_for_mysql();
2577-
}
2595+
if (srv_sys_tablespaces_open) {
2596+
if (!dict_mutex_own) {
2597+
dict_mutex_enter_for_mysql();
2598+
}
25782599

2579-
table->tablespace = dict_get_space_name(
2580-
table->space, table->heap);
2600+
table->tablespace = dict_get_space_name(
2601+
table->space, table->heap);
25812602

2582-
if (!dict_mutex_own) {
2583-
dict_mutex_exit_for_mysql();
2603+
if (!dict_mutex_own) {
2604+
dict_mutex_exit_for_mysql();
2605+
}
25842606
}
25852607
}
25862608

storage/innobase/fil/fil0fil.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3809,10 +3809,14 @@ fil_ibd_open(
38093809
id, space_name, df_remote.filepath(), flags);
38103810
}
38113811

3812-
} else if (df_default.is_open() && path_in == NULL) {
3812+
} else if (df_default.is_open()
3813+
&& path_in == NULL
3814+
&& (DICT_TF_HAS_DATA_DIR(flags)
3815+
|| DICT_TF_HAS_SHARED_SPACE(flags))) {
38133816
/* SYS_DATAFILES record for this tablespace ID
3814-
was not supplied. Replace whatever was there with
3815-
this filepath, name and flags. */
3817+
was not supplied and it should have been.
3818+
Replace whatever was there with this filepath,
3819+
name and flags. */
38163820
dict_replace_tablespace_and_filepath(
38173821
id, space_name, df_default.filepath(), flags);
38183822
}

storage/innobase/include/row0trunc.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 2013, 2014, Oracle and/or its affiliates. All Rights Reserved.
3+
Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
44
55
This program is free software; you can redistribute it and/or modify it under
66
the terms of the GNU General Public License as published by the Free Software
@@ -286,10 +286,15 @@ class truncate_t {
286286

287287
/**
288288
Fix the table truncate by applying information parsed from TRUNCATE log.
289-
Fix-up includes re-creating table (drop and re-create
290-
indexes) and for single-tablespace re-creating tablespace.
289+
Fix-up includes re-creating table (drop and re-create indexes)
291290
@return error code or DB_SUCCESS */
292-
static dberr_t fixup_tables();
291+
static dberr_t fixup_tables_in_system_tablespace();
292+
293+
/**
294+
Fix the table truncate by applying information parsed from TRUNCATE log.
295+
Fix-up includes re-creating tablespace.
296+
@return error code or DB_SUCCESS */
297+
static dberr_t fixup_tables_in_non_system_tablespace();
293298

294299
/**
295300
Check whether a tablespace was truncated during recovery

storage/innobase/row/row0trunc.cc

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,12 +2018,64 @@ row_truncate_table_for_mysql(
20182018

20192019
/**
20202020
Fix the table truncate by applying information parsed from TRUNCATE log.
2021-
Fix-up includes re-creating table (drop and re-create indexes) and for
2022-
single-tablespace re-creating tablespace.
2023-
@return error code or DB_SUCCESS */
2021+
Fix-up includes re-creating table (drop and re-create indexes)
2022+
@return error code or DB_SUCCESS */
2023+
dberr_t
2024+
truncate_t::fixup_tables_in_system_tablespace()
2025+
{
2026+
dberr_t err = DB_SUCCESS;
2027+
2028+
/* Using the info cached during REDO log scan phase fix the
2029+
table truncate. */
2030+
2031+
for (tables_t::iterator it = s_tables.begin();
2032+
it != s_tables.end();) {
2033+
2034+
if ((*it)->m_space_id == TRX_SYS_SPACE) {
2035+
/* Step-1: Drop and re-create indexes. */
2036+
ib::info() << "Completing truncate for table with "
2037+
"id (" << (*it)->m_old_table_id << ") "
2038+
"residing in the system tablespace.";
2039+
2040+
err = fil_recreate_table(
2041+
(*it)->m_space_id,
2042+
(*it)->m_format_flags,
2043+
(*it)->m_tablespace_flags,
2044+
(*it)->m_tablename,
2045+
**it);
2046+
2047+
/* Step-2: Update the SYS_XXXX tables to reflect
2048+
this new table_id and root_page_no. */
2049+
table_id_t new_id;
2050+
2051+
dict_hdr_get_new_id(&new_id, NULL, NULL, NULL, true);
2052+
2053+
err = row_truncate_update_sys_tables_during_fix_up(
2054+
**it, new_id, TRUE,
2055+
(err == DB_SUCCESS) ? false : true);
20242056

2057+
if (err != DB_SUCCESS) {
2058+
break;
2059+
}
2060+
2061+
os_file_delete(
2062+
innodb_log_file_key, (*it)->m_log_file_name);
2063+
UT_DELETE(*it);
2064+
it = s_tables.erase(it);
2065+
} else {
2066+
++it;
2067+
}
2068+
}
2069+
2070+
return(err);
2071+
}
2072+
2073+
/**
2074+
Fix the table truncate by applying information parsed from TRUNCATE log.
2075+
Fix-up includes re-creating tablespace.
2076+
@return error code or DB_SUCCESS */
20252077
dberr_t
2026-
truncate_t::fixup_tables()
2078+
truncate_t::fixup_tables_in_non_system_tablespace()
20272079
{
20282080
dberr_t err = DB_SUCCESS;
20292081

@@ -2033,17 +2085,22 @@ truncate_t::fixup_tables()
20332085

20342086
for (tables_t::iterator it = s_tables.begin(); it != end; ++it) {
20352087

2088+
/* All tables in the system tablesapce have already been
2089+
done and erased from this list. */
2090+
ut_a((*it)->m_space_id != TRX_SYS_SPACE);
2091+
20362092
/* Step-1: Drop tablespace (only for single-tablespace),
20372093
drop indexes and re-create indexes. */
20382094

2039-
ib::info() << "Completing truncate for table with id ("
2040-
<< (*it)->m_old_table_id << ") residing in space with"
2041-
" id (" << (*it)->m_space_id << ")";
2042-
20432095
if (fsp_is_file_per_table((*it)->m_space_id,
20442096
(*it)->m_tablespace_flags)) {
20452097
/* The table is file_per_table */
20462098

2099+
ib::info() << "Completing truncate for table with "
2100+
"id (" << (*it)->m_old_table_id << ") "
2101+
"residing in file-per-table tablespace with "
2102+
"id (" << (*it)->m_space_id << ")";
2103+
20472104
if (!fil_space_get((*it)->m_space_id)) {
20482105

20492106
/* Create the database directory for name,
@@ -2080,7 +2137,13 @@ truncate_t::fixup_tables()
20802137
(*it)->m_tablename,
20812138
**it, log_get_lsn());
20822139

2083-
} else { /* not file_per_table */
2140+
} else {
2141+
/* Table is in a shared tablespace */
2142+
2143+
ib::info() << "Completing truncate for table with "
2144+
"id (" << (*it)->m_old_table_id << ") "
2145+
"residing in shared tablespace with "
2146+
"id (" << (*it)->m_space_id << ")";
20842147

20852148
/* Temp-tables in temp-tablespace are never restored.*/
20862149
ut_ad((*it)->m_space_id != srv_tmp_space.space_id());
@@ -2093,8 +2156,8 @@ truncate_t::fixup_tables()
20932156
**it);
20942157
}
20952158

2096-
/* Step-2: Update the SYS_XXXX tables to reflect new table-id
2097-
and root_page_no. */
2159+
/* Step-2: Update the SYS_XXXX tables to reflect new
2160+
table-id and root_page_no. */
20982161
table_id_t new_id;
20992162

21002163
dict_hdr_get_new_id(&new_id, NULL, NULL, NULL, true);

storage/innobase/srv/srv0start.cc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,15 +2113,23 @@ innobase_start_or_create_for_mysql(void)
21132113

21142114
recv_recovery_from_checkpoint_finish();
21152115

2116+
/* Fix-up truncate of tables in the system tablespace
2117+
if server crashed while truncate was active. The non-
2118+
system tables are done after tablespace discovery. Do
2119+
this now because this procedure assumes that no pages
2120+
have changed since redo recovery. Tablespace discovery
2121+
can do updates to pages in the system tablespace.*/
2122+
err = truncate_t::fixup_tables_in_system_tablespace();
2123+
21162124
if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
21172125
/* Open or Create SYS_TABLESPACES and SYS_DATAFILES
21182126
so that tablespace names and other metadata can be
21192127
found. */
2128+
srv_sys_tablespaces_open = true;
21202129
err = dict_create_or_check_sys_tablespace();
21212130
if (err != DB_SUCCESS) {
21222131
return(srv_init_abort(err));
21232132
}
2124-
srv_sys_tablespaces_open = true;
21252133

21262134
/* The following call is necessary for the insert
21272135
buffer to work with multiple tablespaces. We must
@@ -2153,7 +2161,7 @@ innobase_start_or_create_for_mysql(void)
21532161

21542162
/* Fix-up truncate of table if server crashed while truncate
21552163
was active. */
2156-
err = truncate_t::fixup_tables();
2164+
err = truncate_t::fixup_tables_in_non_system_tablespace();
21572165

21582166
if (err != DB_SUCCESS) {
21592167
return(srv_init_abort(err));

0 commit comments

Comments
 (0)