diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2022-11-28 11:34:22 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2022-11-28 11:34:22 +0200 |
commit | db14eb16f9977453467ec4765f481bb2f71814ba (patch) | |
tree | b8702f3ac2be4dc68f1b9101dbc53350983c0a06 | |
parent | e0d672f30b8a7d5486c367b5ed8ec58e41c1b6b1 (diff) | |
download | mariadb-git-db14eb16f9977453467ec4765f481bb2f71814ba.tar.gz |
MDEV-30106 InnoDB fails to validate the change buffer on startup
ibuf_init_at_db_start(): Validate the change buffer root page.
A later version may stop creating a change buffer, and this
validation check will prevent a downgrade from such later versions.
ibuf_max_size_update(): If the change buffer was not loaded, do nothing.
dict_boot(): Merge the local variable "error" to "err". Ignore
failures of ibuf_init_at_db_start() if innodb_force_recovery>=4.
-rw-r--r-- | mysql-test/suite/innodb/t/log_corruption.test | 1 | ||||
-rw-r--r-- | storage/innobase/dict/dict0boot.cc | 26 | ||||
-rw-r--r-- | storage/innobase/ibuf/ibuf0ibuf.cc | 55 | ||||
-rw-r--r-- | storage/innobase/srv/srv0start.cc | 3 |
4 files changed, 52 insertions, 33 deletions
diff --git a/mysql-test/suite/innodb/t/log_corruption.test b/mysql-test/suite/innodb/t/log_corruption.test index 7c7f32b8d85..a3ab4510743 100644 --- a/mysql-test/suite/innodb/t/log_corruption.test +++ b/mysql-test/suite/innodb/t/log_corruption.test @@ -19,6 +19,7 @@ call mtr.add_suppression("InnoDB: Obtaining redo log encryption key version 1 fa call mtr.add_suppression("InnoDB: Decrypting checkpoint failed"); call mtr.add_suppression("InnoDB: Are you sure you are using the right ib_logfile0 to start up the database\\? Log sequence number in the ib_logfile0 is 1213964,"); call mtr.add_suppression("InnoDB: Log file .*ib_logfile1 is of different size 1048576 bytes than other log files 2097152 bytes!"); +call mtr.add_suppression("InnoDB: The change buffer is corrupted"); --enable_query_log let bugdir= $MYSQLTEST_VARDIR/tmp/log_corruption; diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc index bd2cf4ffdd8..1414f21221f 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -313,9 +313,9 @@ dict_boot(void) dict_mem_index_add_field(index, "NAME", 0); index->id = DICT_TABLES_ID; - dberr_t error = dict_index_add_to_cache( + dberr_t err = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_TABLES)); - ut_a(error == DB_SUCCESS); + ut_a(err == DB_SUCCESS); ut_ad(!table->is_instant()); table->indexes.start->n_core_null_bytes = static_cast<uint8_t>( UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable))); @@ -325,9 +325,9 @@ dict_boot(void) dict_mem_index_add_field(index, "ID", 0); index->id = DICT_TABLE_IDS_ID; - error = dict_index_add_to_cache( + err = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_TABLE_IDS)); - ut_a(error == DB_SUCCESS); + ut_a(err == DB_SUCCESS); /*-------------------------*/ table = dict_mem_table_create("SYS_COLUMNS", fil_system.sys_space, @@ -355,9 +355,9 @@ dict_boot(void) dict_mem_index_add_field(index, "POS", 0); index->id = DICT_COLUMNS_ID; - error = dict_index_add_to_cache( + err = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_COLUMNS)); - ut_a(error == DB_SUCCESS); + ut_a(err == DB_SUCCESS); ut_ad(!table->is_instant()); table->indexes.start->n_core_null_bytes = static_cast<uint8_t>( UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable))); @@ -398,9 +398,9 @@ dict_boot(void) dict_mem_index_add_field(index, "ID", 0); index->id = DICT_INDEXES_ID; - error = dict_index_add_to_cache( + err = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_INDEXES)); - ut_a(error == DB_SUCCESS); + ut_a(err == DB_SUCCESS); ut_ad(!table->is_instant()); table->indexes.start->n_core_null_bytes = static_cast<uint8_t>( UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable))); @@ -427,9 +427,9 @@ dict_boot(void) dict_mem_index_add_field(index, "POS", 0); index->id = DICT_FIELDS_ID; - error = dict_index_add_to_cache( + err = dict_index_add_to_cache( index, mach_read_from_4(dict_hdr + DICT_HDR_FIELDS)); - ut_a(error == DB_SUCCESS); + ut_a(err == DB_SUCCESS); ut_ad(!table->is_instant()); table->indexes.start->n_core_null_bytes = static_cast<uint8_t>( UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable))); @@ -440,9 +440,11 @@ dict_boot(void) /* Initialize the insert buffer table and index for each tablespace */ - dberr_t err = ibuf_init_at_db_start(); + err = ibuf_init_at_db_start(); - if (err == DB_SUCCESS) { + if (err == DB_SUCCESS + || srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { + err = DB_SUCCESS; /* Load definitions of other indexes on system tables */ dict_load_sys_table(dict_sys.sys_tables); diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index ee462bc68c2..d88c2b0027e 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -50,6 +50,7 @@ Created 7/19/1997 Heikki Tuuri #include "que0que.h" #include "srv0start.h" /* srv_shutdown_state */ #include "rem0cmp.h" +#include "log.h" /* STRUCTURE OF AN INSERT BUFFER RECORD @@ -408,35 +409,24 @@ ibuf_init_at_db_start(void) ulint n_used; ut_ad(!ibuf.index); + dberr_t err; mtr_t mtr; mtr.start(); compile_time_assert(IBUF_SPACE_ID == TRX_SYS_SPACE); compile_time_assert(IBUF_SPACE_ID == 0); mtr_x_lock_space(fil_system.sys_space, &mtr); - buf_block_t* header_page = buf_page_get( + buf_block_t* header_page = buf_page_get_gen( page_id_t(IBUF_SPACE_ID, FSP_IBUF_HEADER_PAGE_NO), - 0, RW_X_LATCH, &mtr); + 0, RW_X_LATCH, nullptr, BUF_GET, + __FILE__, __LINE__, &mtr, &err); if (!header_page) { +err_exit: + sql_print_error("InnoDB: The change buffer is corrupted"); mtr.commit(); - return DB_DECRYPTION_FAILED; + return err; } - /* At startup we intialize ibuf to have a maximum of - CHANGE_BUFFER_DEFAULT_SIZE in terms of percentage of the - buffer pool size. Once ibuf struct is initialized this - value is updated with the user supplied size by calling - ibuf_max_size_update(). */ - ibuf.max_size = ((buf_pool_get_curr_size() >> srv_page_size_shift) - * CHANGE_BUFFER_DEFAULT_SIZE) / 100; - - mutex_create(LATCH_ID_IBUF, &ibuf_mutex); - - mutex_create(LATCH_ID_IBUF_PESSIMISTIC_INSERT, - &ibuf_pessimistic_insert_mutex); - - mutex_enter(&ibuf_mutex); - fseg_n_reserved_pages(*header_page, IBUF_HEADER + IBUF_TREE_SEG_HEADER + header_page->frame, &n_used, &mtr); @@ -448,15 +438,39 @@ ibuf_init_at_db_start(void) { buf_block_t* block; - block = buf_page_get( + block = buf_page_get_gen( page_id_t(IBUF_SPACE_ID, FSP_IBUF_TREE_ROOT_PAGE_NO), - 0, RW_X_LATCH, &mtr); + 0, RW_X_LATCH, nullptr, BUF_GET, + __FILE__, __LINE__, &mtr, &err); + + if (!block) goto err_exit; buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); root = buf_block_get_frame(block); } + if (page_is_comp(root) || fil_page_get_type(root) != FIL_PAGE_INDEX + || btr_page_get_index_id(root) != DICT_IBUF_ID_MIN) { + err = DB_CORRUPTION; + goto err_exit; + } + + /* At startup we initialize ibuf to have a maximum of + CHANGE_BUFFER_DEFAULT_SIZE in terms of percentage of the + buffer pool size. Once ibuf struct is initialized this + value is updated with the user supplied size by calling + ibuf_max_size_update(). */ + ibuf.max_size = ((buf_pool_get_curr_size() >> srv_page_size_shift) + * CHANGE_BUFFER_DEFAULT_SIZE) / 100; + + mutex_create(LATCH_ID_IBUF, &ibuf_mutex); + + mutex_create(LATCH_ID_IBUF_PESSIMISTIC_INSERT, + &ibuf_pessimistic_insert_mutex); + + mutex_enter(&ibuf_mutex); + ibuf_size_update(root); mutex_exit(&ibuf_mutex); @@ -507,6 +521,7 @@ ibuf_max_size_update( ulint new_val) /*!< in: new value in terms of percentage of the buffer pool size */ { + if (UNIV_UNLIKELY(!ibuf.index)) return; ulint new_size = ((buf_pool_get_curr_size() >> srv_page_size_shift) * new_val) / 100; mutex_enter(&ibuf_mutex); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index c0b2f5e02f0..ae4f831bf2d 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -2056,7 +2056,8 @@ void innodb_shutdown() || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO); ut_ad(lock_sys.is_initialised() || !srv_was_started); ut_ad(log_sys.is_initialised() || !srv_was_started); - ut_ad(ibuf.index || !srv_was_started); + ut_ad(ibuf.index || !srv_was_started + || srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE); dict_stats_deinit(); |