From d92be859d61c8b9d295c06ed84c65159be5675dc Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Thu, 10 Dec 2020 21:11:26 +0300 Subject: MDEV-18976: Implement a CHECKSUM redo log record for improved validation This is draft implementation without test. --- .../suite/innodb/t/MDEV-18976-redolog-crc.test | 21 +++++++++ storage/innobase/buf/buf0buf.cc | 4 -- storage/innobase/fsp/fsp0fsp.cc | 6 +-- storage/innobase/handler/ha_innodb.cc | 6 +++ storage/innobase/include/buf0types.h | 2 +- storage/innobase/include/mtr0log.h | 26 +++++++++-- storage/innobase/include/mtr0mtr.h | 43 +++++++++++++++++- storage/innobase/include/mtr0types.h | 3 ++ storage/innobase/include/srv0srv.h | 1 + storage/innobase/log/log0recv.cc | 33 ++++++++++++-- storage/innobase/mtr/mtr0mtr.cc | 53 +++++++++++++++++++++- storage/innobase/srv/srv0srv.cc | 2 + 12 files changed, 183 insertions(+), 17 deletions(-) create mode 100644 mysql-test/suite/innodb/t/MDEV-18976-redolog-crc.test diff --git a/mysql-test/suite/innodb/t/MDEV-18976-redolog-crc.test b/mysql-test/suite/innodb/t/MDEV-18976-redolog-crc.test new file mode 100644 index 00000000000..76503ef56a7 --- /dev/null +++ b/mysql-test/suite/innodb/t/MDEV-18976-redolog-crc.test @@ -0,0 +1,21 @@ +--source include/have_innodb.inc +--source include/have_debug.inc + +# Disable pages flushing to allow redo log records to be executed on --prepare. +#SET @old_debug_dbug=@@global.debug_dbug; +SET GLOBAL debug_dbug="+d,ib_log_checkpoint_avoid"; +#SET @old_innodb_page_cleaner_disabled_debug=@@global.innodb_page_cleaner_disabled_debug; +SET GLOBAL innodb_page_cleaner_disabled_debug=ON; +SET GLOBAL innodb_redo_log_checksum=ON; + +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES (1), (2), (3), (4), (5); + +--source include/kill_mysqld.inc + + +--source include/start_mysqld.inc + +DROP TABLE t; +#SET GLOBAL innodb_page_cleaner_disabled_debug=@old_innodb_page_cleaner_disabled_debug; +#SET GLOBAL debug_dbug=@old_debug_dbug; diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 2ddd9f278b1..05dbe068bbf 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2504,10 +2504,6 @@ void buf_page_free(const page_id_t page_id, buf_block_t *block= reinterpret_cast (buf_pool.page_hash_get_low(page_id, fold)); - /* TODO: try to all this part of mtr_t::free() */ - if (srv_immediate_scrub_data_uncompressed || mtr->is_page_compressed()) - mtr->add_freed_offset(page_id); - if (!block || block->page.state() != BUF_BLOCK_FILE_PAGE) { /* FIXME: if block!=NULL, convert to BUF_BLOCK_FILE_PAGE, diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index ae8c557b24c..167a87077a0 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -2637,9 +2637,9 @@ fseg_free_extent( for (ulint i = 0; i < FSP_EXTENT_SIZE; i++) { if (!xdes_is_free(descr, i)) { - buf_page_free( - page_id_t(space->id, first_page_in_extent + 1), - mtr, __FILE__, __LINE__); + page_id_t freed_page_id(space->id, first_page_in_extent + 1); + buf_page_free(freed_page_id, mtr, __FILE__, __LINE__); + mtr->add_freed_offset(freed_page_id); } } } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 9a47fb6b30f..9cad32e1917 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19914,6 +19914,11 @@ static MYSQL_SYSVAR_BOOL(immediate_scrub_data_uncompressed, "Enable scrubbing of data", NULL, NULL, FALSE); +static MYSQL_SYSVAR_BOOL( + redo_log_checksum, srv_redo_log_checksum, 0, + "Write redo log record with page crc for each modified page on mtr commit", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_BOOL(background_scrub_data_uncompressed, deprecated::innodb_background_scrub_data_uncompressed, PLUGIN_VAR_OPCMDARG, innodb_deprecated_ignored, NULL, @@ -20140,6 +20145,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(background_thread), MYSQL_SYSVAR(encrypt_temporary_tables), + MYSQL_SYSVAR(redo_log_checksum), NULL }; diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index ba1e2e5eaa6..e2026052122 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/include/buf0types.h @@ -171,7 +171,7 @@ public: m_id= (m_id & ~uint64_t{0} << 32) | page_no; } - ulonglong raw() { return m_id; } + ulonglong raw() const { return m_id; } private: /** The page identifier */ uint64_t m_id; diff --git a/storage/innobase/include/mtr0log.h b/storage/innobase/include/mtr0log.h index 2bcd69d8899..8d7ff84b1aa 100644 --- a/storage/innobase/include/mtr0log.h +++ b/storage/innobase/include/mtr0log.h @@ -384,8 +384,8 @@ template inline byte *mtr_t::log_write(const page_id_t id, const buf_page_t *bpage, size_t len, bool alloc, size_t offset) { - static_assert(!(type & 15) && type != RESERVED && type != OPTION && - type <= FILE_CHECKPOINT, "invalid type"); + static_assert(!(type & 15) && type != RESERVED && type <= FILE_CHECKPOINT, + "invalid type"); ut_ad(type >= FILE_CREATE || is_named_space(id.space())); ut_ad(!bpage || bpage->id() == id); constexpr bool have_len= type != INIT_PAGE && type != FREE_PAGE; @@ -541,9 +541,13 @@ inline void mtr_t::init(buf_block_t *b) inline void mtr_t::free(fil_space_t &space, uint32_t offset) { page_id_t freed_page_id(space.id, offset); + + if (srv_redo_log_checksum || srv_immediate_scrub_data_uncompressed + || is_page_compressed()) + add_freed_offset(freed_page_id); + if (m_log_mode == MTR_LOG_ALL) m_log.close(log_write(freed_page_id, nullptr)); - ut_ad(!m_user_space || m_user_space == &space); if (&space == fil_system.sys_space) freed_system_tablespace_page(); @@ -673,3 +677,19 @@ inline void mtr_t::trim_pages(const page_id_t id) m_log.close(l); set_trim_pages(); } + +inline void mtr_t::page_checksum(const page_id_t id, uint32_t crc, + lsn_t flushed_lsn) +{ + if (m_log_mode != MTR_LOG_ALL) + return; + static_assert(sizeof(crc) == 4, "compatibility"); + static_assert(sizeof(flushed_lsn) == 8, "compatibility"); + byte* l = log_write