summaryrefslogtreecommitdiff
path: root/storage/innobase/trx/trx0undo.cc
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-06-21 12:34:07 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-06-21 12:34:07 +0300
commite46f76c9749d7758765ba274a212cfc2dcf3eeb8 (patch)
tree6a64682c1f19f98fef1358fbc1f48a4457117f2e /storage/innobase/trx/trx0undo.cc
parent241d30d3faac0fbbcb7bcfad3dcc118bb03eceb0 (diff)
downloadmariadb-git-e46f76c9749d7758765ba274a212cfc2dcf3eeb8.tar.gz
MDEV-15912: Remove traces of insert_undo
Let us simply refuse an upgrade from earlier versions if the upgrade procedure was not followed. This simplifies the purge, commit, and rollback of transactions. Before upgrading to MariaDB 10.3 or later, a clean shutdown of the server (with innodb_fast_shutdown=1 or 0) is necessary, to ensure that any incomplete transactions are rolled back. The undo log format was changed in MDEV-12288. There is only one persistent undo log for each transaction.
Diffstat (limited to 'storage/innobase/trx/trx0undo.cc')
-rw-r--r--storage/innobase/trx/trx0undo.cc193
1 files changed, 90 insertions, 103 deletions
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index 7254c830cde..dea85c40473 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2020, MariaDB Corporation.
+Copyright (c) 2014, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -34,6 +34,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0purge.h"
#include "trx0rec.h"
#include "trx0rseg.h"
+#include "log.h"
/* How should the old versions in the history list be managed?
----------------------------------------------------------
@@ -1011,13 +1012,8 @@ loop:
}
/** Frees an undo log segment which is not in the history list.
-@param[in] undo undo log
-@param[in] noredo whether the undo tablespace is redo logged */
-static
-void
-trx_undo_seg_free(
- const trx_undo_t* undo,
- bool noredo)
+@param undo temporary undo log */
+static void trx_undo_seg_free(const trx_undo_t *undo)
{
trx_rseg_t* rseg;
fseg_header_t* file_seg;
@@ -1029,16 +1025,12 @@ trx_undo_seg_free(
rseg = undo->rseg;
do {
-
- mtr_start(&mtr);
-
- if (noredo) {
- mtr.set_log_mode(MTR_LOG_NO_REDO);
- }
+ mtr.start();
+ mtr.set_log_mode(MTR_LOG_NO_REDO);
mutex_enter(&(rseg->mutex));
- seg_header = trx_undo_page_get(page_id_t(undo->rseg->space->id,
+ seg_header = trx_undo_page_get(page_id_t(SRV_TMP_SPACE_ID,
undo->hdr_page_no),
&mtr)
+ TRX_UNDO_SEG_HDR;
@@ -1069,10 +1061,11 @@ trx_undo_seg_free(
@param[in] id rollback segment slot
@param[in] page_no undo log segment page number
@param[in,out] max_trx_id the largest observed transaction ID
-@return size of the undo log in pages */
-ulint
-trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
- trx_id_t& max_trx_id)
+@return the undo log
+@retval nullptr on error */
+trx_undo_t *
+trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no,
+ trx_id_t &max_trx_id)
{
mtr_t mtr;
XID xid;
@@ -1082,16 +1075,56 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
mtr.start();
const page_t* undo_page = trx_undo_page_get(
page_id_t(rseg->space->id, page_no), &mtr);
- const ulint type = mach_read_from_2(
- TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + undo_page);
- ut_ad(type == 0 || type == TRX_UNDO_INSERT || type == TRX_UNDO_UPDATE);
+ const uint16_t type = mach_read_from_2(TRX_UNDO_PAGE_HDR
+ + TRX_UNDO_PAGE_TYPE
+ + undo_page);
+ switch (type) {
+ case 0:
+ case 2: /* TRX_UNDO_UPDATE */
+ break;
+ case 1: /* TRX_UNDO_INSERT */
+ sql_print_error("InnoDB: upgrade from older version than"
+ " MariaDB 10.3 requires clean shutdown");
+ goto corrupted;
+ default:
+ sql_print_error("InnoDB: unsupported undo header type %u",
+ type);
+ corrupted:
+ mtr.commit();
+ return NULL;
+ }
- uint state = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
- + undo_page);
- uint offset = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG
- + undo_page);
+ uint16_t offset = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG
+ + undo_page);
+ if (offset < TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE ||
+ offset >= srv_page_size - TRX_UNDO_LOG_OLD_HDR_SIZE) {
+ sql_print_error("InnoDB: invalid undo header offset %u",
+ offset);
+ goto corrupted;
+ }
- const trx_ulogf_t* undo_header = undo_page + offset;
+ const trx_ulogf_t* const undo_header = undo_page + offset;
+ uint16_t state = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
+ + undo_page);
+ switch (state) {
+ case TRX_UNDO_ACTIVE:
+ case TRX_UNDO_PREPARED:
+ break;
+ default:
+ sql_print_error("InnoDB: unsupported undo header state %u",
+ state);
+ goto corrupted;
+ case TRX_UNDO_TO_PURGE:
+ case TRX_UNDO_CACHED:
+ trx_id_t id = mach_read_from_8(TRX_UNDO_TRX_NO + undo_header);
+ if (id >> 48) {
+ sql_print_error("InnoDB: corrupted TRX_NO %llx", id);
+ goto corrupted;
+ }
+ if (id > max_trx_id) {
+ max_trx_id = id;
+ }
+ }
/* Read X/Open XA transaction identification if it exists, or
set it to NULL. */
@@ -1103,6 +1136,10 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
}
trx_id_t trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
+ if (trx_id >> 48) {
+ sql_print_error("InnoDB: corrupted TRX_ID %llx", trx_id);
+ goto corrupted;
+ }
if (trx_id > max_trx_id) {
max_trx_id = trx_id;
}
@@ -1111,61 +1148,45 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
trx_undo_t* undo = trx_undo_mem_create(
rseg, id, trx_id, &xid, page_no, offset);
mutex_exit(&rseg->mutex);
+ if (!undo) {
+ return undo;
+ }
undo->dict_operation = undo_header[TRX_UNDO_DICT_TRANS];
undo->table_id = mach_read_from_8(undo_header + TRX_UNDO_TABLE_ID);
undo->size = flst_get_len(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST
+ undo_page);
- if (UNIV_UNLIKELY(state == TRX_UNDO_TO_FREE)) {
- /* This is an old-format insert_undo log segment that
- is being freed. The page list is inconsistent. */
- ut_ad(type == TRX_UNDO_INSERT);
- state = TRX_UNDO_TO_PURGE;
- } else {
- if (state == TRX_UNDO_TO_PURGE
- || state == TRX_UNDO_CACHED) {
- trx_id_t id = mach_read_from_8(TRX_UNDO_TRX_NO
- + undo_header);
- if (id > max_trx_id) {
- max_trx_id = id;
- }
- }
+ fil_addr_t last_addr = flst_get_last(
+ TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + undo_page, &mtr);
- fil_addr_t last_addr = flst_get_last(
- TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + undo_page,
- &mtr);
-
- undo->last_page_no = last_addr.page;
- undo->top_page_no = last_addr.page;
+ undo->last_page_no = last_addr.page;
+ undo->top_page_no = last_addr.page;
- page_t* last_page = trx_undo_page_get(
- page_id_t(rseg->space->id, undo->last_page_no), &mtr);
+ page_t* last_page = trx_undo_page_get(
+ page_id_t(rseg->space->id, undo->last_page_no), &mtr);
- if (const trx_undo_rec_t* rec = trx_undo_page_get_last_rec(
- last_page, page_no, offset)) {
- undo->top_offset = ulint(rec - last_page);
- undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
- ut_ad(!undo->empty());
- } else {
- undo->top_undo_no = IB_ID_MAX;
- ut_ad(undo->empty());
- }
+ if (const trx_undo_rec_t* rec = trx_undo_page_get_last_rec(
+ last_page, page_no, offset)) {
+ undo->top_offset = ulint(rec - last_page);
+ undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
+ ut_ad(!undo->empty());
+ } else {
+ undo->top_undo_no = IB_ID_MAX;
+ ut_ad(undo->empty());
}
undo->state = state;
if (state != TRX_UNDO_CACHED) {
- UT_LIST_ADD_LAST(type == TRX_UNDO_INSERT
- ? rseg->old_insert_list
- : rseg->undo_list, undo);
+ UT_LIST_ADD_LAST(rseg->undo_list, undo);
} else {
UT_LIST_ADD_LAST(rseg->undo_cached, undo);
MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED);
}
mtr.commit();
- return undo->size;
+ return undo;
}
/********************************************************************//**
@@ -1577,22 +1598,18 @@ trx_undo_set_state_at_prepare(
return(undo_page);
}
-/** Free an old insert or temporary undo log after commit or rollback.
+/** Free temporary undo log after commit or rollback.
The information is not needed after a commit or rollback, therefore
the data can be discarded.
-@param[in,out] undo undo log
-@param[in] is_temp whether this is temporary undo log */
-void
-trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
+@param undo temporary undo log */
+void trx_undo_commit_cleanup(trx_undo_t *undo)
{
trx_rseg_t* rseg = undo->rseg;
- ut_ad(is_temp == !rseg->is_persistent());
- ut_ad(!is_temp || 0 == UT_LIST_GET_LEN(rseg->old_insert_list));
+ ut_ad(rseg->space == fil_system.temp_space);
mutex_enter(&rseg->mutex);
- UT_LIST_REMOVE(is_temp ? rseg->undo_list : rseg->old_insert_list,
- undo);
+ UT_LIST_REMOVE(rseg->undo_list, undo);
if (undo->state == TRX_UNDO_CACHED) {
UT_LIST_ADD_FIRST(rseg->undo_cached, undo);
@@ -1602,7 +1619,7 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
/* Delete first the undo log segment in the file */
mutex_exit(&rseg->mutex);
- trx_undo_seg_free(undo, is_temp);
+ trx_undo_seg_free(undo);
mutex_enter(&rseg->mutex);
ut_ad(rseg->curr_size > undo->size);
@@ -1615,15 +1632,13 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
}
/** At shutdown, frees the undo logs of a transaction. */
-void
-trx_undo_free_at_shutdown(trx_t *trx)
+void trx_undo_free_at_shutdown(trx_t *trx)
{
if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) {
switch (undo->state) {
case TRX_UNDO_PREPARED:
break;
case TRX_UNDO_CACHED:
- case TRX_UNDO_TO_FREE:
case TRX_UNDO_TO_PURGE:
ut_ad(trx_state_eq(trx,
TRX_STATE_COMMITTED_IN_MEMORY));
@@ -1644,34 +1659,6 @@ trx_undo_free_at_shutdown(trx_t *trx)
ut_free(undo);
undo = NULL;
}
-
- if (trx_undo_t*& undo = trx->rsegs.m_redo.old_insert) {
- switch (undo->state) {
- case TRX_UNDO_PREPARED:
- break;
- case TRX_UNDO_CACHED:
- case TRX_UNDO_TO_FREE:
- case TRX_UNDO_TO_PURGE:
- ut_ad(trx_state_eq(trx,
- TRX_STATE_COMMITTED_IN_MEMORY));
- /* fall through */
- case TRX_UNDO_ACTIVE:
- /* trx_t::commit_state() assigns
- trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
- ut_a(!srv_was_started
- || srv_read_only_mode
- || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
- || srv_fast_shutdown);
- break;
- default:
- ut_error;
- }
-
- UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->old_insert_list, undo);
- ut_free(undo);
- undo = NULL;
- }
-
if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) {
ut_a(undo->state == TRX_UNDO_PREPARED);