summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2023-02-15 18:16:41 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2023-02-15 18:16:41 +0200
commit5300c0fb7632e7e49a22997297bf731e691d3c24 (patch)
treee5a9ceaadac8fd11aaeadc12f0bceee114a687e4
parent192427e37d2b066f9f681cc1b998b2efdc407c55 (diff)
downloadmariadb-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.h12
-rw-r--r--storage/innobase/log/log0recv.cc16
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);
}
}
}