diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2023-02-15 18:16:41 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2023-02-15 18:16:41 +0200 |
commit | 5300c0fb7632e7e49a22997297bf731e691d3c24 (patch) | |
tree | e5a9ceaadac8fd11aaeadc12f0bceee114a687e4 | |
parent | 192427e37d2b066f9f681cc1b998b2efdc407c55 (diff) | |
download | mariadb-git-5300c0fb7632e7e49a22997297bf731e691d3c24.tar.gz |
MDEV-30657 InnoDB: Not applying UNDO_APPEND due to corruption
This almost completely reverts
commit acd23da4c2363511aae7d984c24cc6847aa3f19c and
retains a safe optimization:
recv_sys_t::parse(): Remove any old redo log records for the
truncated tablespace, to free up memory earlier.
If recovery consists of multiple batches, then recv_sys_t::apply()
will must invoke recv_sys_t::trim() again to avoid wrongly
applying old log records to an already truncated undo tablespace.
-rw-r--r-- | storage/innobase/include/log0recv.h | 12 | ||||
-rw-r--r-- | storage/innobase/log/log0recv.cc | 16 |
2 files changed, 21 insertions, 7 deletions
diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index 73d5724f612..e4a8f0d25a2 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -266,9 +266,15 @@ private: @param lsn log sequence number of the shrink operation */ inline void trim(const page_id_t page_id, lsn_t lsn); - /** Truncated undo tablespace size for which truncate has been logged - (indexed by page_id_t::space() - srv_undo_space_id_start), or 0 */ - unsigned truncated_undo_spaces[127]; + /** Undo tablespaces for which truncate has been logged + (indexed by page_id_t::space() - srv_undo_space_id_start) */ + struct trunc + { + /** log sequence number of FILE_CREATE, or 0 if none */ + lsn_t lsn; + /** truncated size of the tablespace, or 0 if not truncated */ + unsigned pages; + } truncated_undo_spaces[127]; public: /** The contents of the doublewrite buffer */ diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 9b4ceb4f03e..c4217d7a1cb 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1952,7 +1952,8 @@ same_page: /* The entire undo tablespace will be reinitialized by innodb_undo_log_truncate=ON. Discard old log for all pages. */ trim({space_id, 0}, recovered_lsn); - truncated_undo_spaces[space_id - srv_undo_space_id_start]= page_no; + truncated_undo_spaces[space_id - srv_undo_space_id_start]= + { recovered_lsn, page_no }; if (undo_space_trunc) undo_space_trunc(space_id); #endif @@ -2677,15 +2678,22 @@ void recv_sys_t::apply(bool last_batch) for (auto id= srv_undo_tablespaces_open; id--;) { - if (unsigned pages= truncated_undo_spaces[id]) + const trunc& t= truncated_undo_spaces[id]; + if (t.lsn) { - if (fil_space_t *space= fil_space_get(id + srv_undo_space_id_start)) + /* The entire undo tablespace will be reinitialized by + innodb_undo_log_truncate=ON. Discard old log for all pages. + Even though we recv_sys_t::parse() already invoked trim(), + this will be needed in case recovery consists of multiple batches + (there was an invocation with !last_batch). */ + trim({id + srv_undo_space_id_start, 0}, t.lsn); + if (fil_space_t *space = fil_space_get(id + srv_undo_space_id_start)) { ut_ad(UT_LIST_GET_LEN(space->chain) == 1); fil_node_t *file= UT_LIST_GET_FIRST(space->chain); ut_ad(file->is_open()); os_file_truncate(file->name, file->handle, - os_offset_t{pages} << srv_page_size_shift, true); + os_offset_t{t.pages} << srv_page_size_shift, true); } } } |