Commit e46f76c9 authored by Marko Mäkelä's avatar Marko Mäkelä

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.
parent 241d30d3
/* /*
Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2014, 2019, MariaDB Corporation. Copyright (c) 2014, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -138,13 +138,10 @@ static ulong write_check; ...@@ -138,13 +138,10 @@ static ulong write_check;
struct innodb_page_type { struct innodb_page_type {
int n_undo_state_active; int n_undo_state_active;
int n_undo_state_cached; int n_undo_state_cached;
int n_undo_state_to_free;
int n_undo_state_to_purge; int n_undo_state_to_purge;
int n_undo_state_prepared; int n_undo_state_prepared;
int n_undo_state_other; int n_undo_state_other;
int n_undo_insert; int n_undo;
int n_undo_update;
int n_undo_other;
int n_fil_page_index; int n_fil_page_index;
int n_fil_page_undo_log; int n_fil_page_undo_log;
int n_fil_page_inode; int n_fil_page_inode;
...@@ -955,21 +952,7 @@ parse_page( ...@@ -955,21 +952,7 @@ parse_page(
fprintf(file, "#::%llu\t\t|\t\tUndo log page\t\t\t|", fprintf(file, "#::%llu\t\t|\t\tUndo log page\t\t\t|",
cur_page_num); cur_page_num);
} }
if (undo_page_type == TRX_UNDO_INSERT) { page_type.n_undo++;
page_type.n_undo_insert++;
if (page_type_dump) {
fprintf(file, "\t%s",
"Insert Undo log page");
}
} else if (undo_page_type == TRX_UNDO_UPDATE) {
page_type.n_undo_update++;
if (page_type_dump) {
fprintf(file, "\t%s",
"Update undo log page");
}
}
undo_page_type = mach_read_from_2(page + TRX_UNDO_SEG_HDR + undo_page_type = mach_read_from_2(page + TRX_UNDO_SEG_HDR +
TRX_UNDO_STATE); TRX_UNDO_STATE);
switch (undo_page_type) { switch (undo_page_type) {
...@@ -989,14 +972,6 @@ parse_page( ...@@ -989,14 +972,6 @@ parse_page(
} }
break; break;
case TRX_UNDO_TO_FREE:
page_type.n_undo_state_to_free++;
if (page_type_dump) {
fprintf(file, ", %s", "Insert undo "
"segment that can be freed");
}
break;
case TRX_UNDO_TO_PURGE: case TRX_UNDO_TO_PURGE:
page_type.n_undo_state_to_purge++; page_type.n_undo_state_to_purge++;
if (page_type_dump) { if (page_type_dump) {
...@@ -1220,15 +1195,11 @@ print_summary( ...@@ -1220,15 +1195,11 @@ print_summary(
fprintf(fil_out, "\n===============================================\n"); fprintf(fil_out, "\n===============================================\n");
fprintf(fil_out, "Additional information:\n"); fprintf(fil_out, "Additional information:\n");
fprintf(fil_out, "Undo page type: %d insert, %d update, %d other\n", fprintf(fil_out, "Undo page type: %d\n", page_type.n_undo);
page_type.n_undo_insert, fprintf(fil_out, "Undo page state: %d active, %d cached, %d"
page_type.n_undo_update,
page_type.n_undo_other);
fprintf(fil_out, "Undo page state: %d active, %d cached, %d to_free, %d"
" to_purge, %d prepared, %d other\n", " to_purge, %d prepared, %d other\n",
page_type.n_undo_state_active, page_type.n_undo_state_active,
page_type.n_undo_state_cached, page_type.n_undo_state_cached,
page_type.n_undo_state_to_free,
page_type.n_undo_state_to_purge, page_type.n_undo_state_to_purge,
page_type.n_undo_state_prepared, page_type.n_undo_state_prepared,
page_type.n_undo_state_other); page_type.n_undo_state_other);
......
...@@ -109,8 +109,8 @@ File::tab#.ibd ...@@ -109,8 +109,8 @@ File::tab#.ibd
=============================================== ===============================================
Additional information: Additional information:
Undo page type: # insert, # update, # other Undo page type: #
Undo page state: # active, # cached, # to_free, # to_purge, # prepared, # other Undo page state: # active, # cached, # to_purge, # prepared, # other
index_id #pages #leaf_pages #recs_per_page #bytes_per_page index_id #pages #leaf_pages #recs_per_page #bytes_per_page
# # # # # # # # # #
# # # # # # # # # #
...@@ -144,8 +144,8 @@ File::tab#.ibd ...@@ -144,8 +144,8 @@ File::tab#.ibd
=============================================== ===============================================
Additional information: Additional information:
Undo page type: # insert, # update, # other Undo page type: #
Undo page state: # active, # cached, # to_free, # to_purge, # prepared, # other Undo page state: # active, # cached, # to_purge, # prepared, # other
index_id #pages #leaf_pages #recs_per_page #bytes_per_page index_id #pages #leaf_pages #recs_per_page #bytes_per_page
# # # # # # # # # #
# # # # # # # # # #
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2018, MariaDB Corporation. Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -78,20 +78,16 @@ class TrxUndoRsegs { ...@@ -78,20 +78,16 @@ class TrxUndoRsegs {
typedef trx_rsegs_t::iterator iterator; typedef trx_rsegs_t::iterator iterator;
typedef trx_rsegs_t::const_iterator const_iterator; typedef trx_rsegs_t::const_iterator const_iterator;
/** Default constructor */ TrxUndoRsegs() : trx_no(0), m_rsegs() {}
TrxUndoRsegs() {}
/** Constructor */ /** Constructor */
TrxUndoRsegs(trx_rseg_t& rseg) TrxUndoRsegs(trx_rseg_t& rseg)
: m_commit(rseg.last_commit), m_rsegs(1, &rseg) {} : trx_no(rseg.last_trx_no()), m_rsegs(1, &rseg) {}
/** Constructor */ /** Constructor */
TrxUndoRsegs(trx_id_t trx_no, trx_rseg_t& rseg) TrxUndoRsegs(trx_id_t trx_no, trx_rseg_t& rseg)
: m_commit(trx_no << 1), m_rsegs(1, &rseg) {} : trx_no(trx_no), m_rsegs(1, &rseg) {}
/** @return the transaction commit identifier */
trx_id_t trx_no() const { return m_commit >> 1; }
bool operator!=(const TrxUndoRsegs& other) const bool operator!=(const TrxUndoRsegs& other) const
{ return m_commit != other.m_commit; } { return trx_no != other.trx_no; }
bool empty() const { return m_rsegs.empty(); } bool empty() const { return m_rsegs.empty(); }
void erase(iterator& it) { m_rsegs.erase(it); } void erase(iterator& it) { m_rsegs.erase(it); }
iterator begin() { return(m_rsegs.begin()); } iterator begin() { return(m_rsegs.begin()); }
...@@ -105,14 +101,14 @@ class TrxUndoRsegs { ...@@ -105,14 +101,14 @@ class TrxUndoRsegs {
@return true if elem1 > elem2 else false.*/ @return true if elem1 > elem2 else false.*/
bool operator()(const TrxUndoRsegs& lhs, const TrxUndoRsegs& rhs) bool operator()(const TrxUndoRsegs& lhs, const TrxUndoRsegs& rhs)
{ {
return(lhs.m_commit > rhs.m_commit); return(lhs.trx_no > rhs.trx_no);
} }
/** Copy of trx_rseg_t::last_trx_no() */
trx_id_t trx_no;
private: private:
/** Copy trx_rseg_t::last_commit */
trx_id_t m_commit;
/** Rollback segments of a transaction, scheduled for purge. */ /** Rollback segments of a transaction, scheduled for purge. */
trx_rsegs_t m_rsegs; trx_rsegs_t m_rsegs;
}; };
typedef std::priority_queue< typedef std::priority_queue<
...@@ -370,17 +366,13 @@ class purge_sys_t ...@@ -370,17 +366,13 @@ class purge_sys_t
{ {
bool operator<=(const iterator& other) const bool operator<=(const iterator& other) const
{ {
if (commit < other.commit) return true; if (trx_no < other.trx_no) return true;
if (commit > other.commit) return false; if (trx_no > other.trx_no) return false;
return undo_no <= other.undo_no; return undo_no <= other.undo_no;
} }
/** @return the commit number of the transaction */ /** trx_t::no of the committed transaction */
trx_id_t trx_no() const { return commit >> 1; } trx_id_t trx_no;
void reset_trx_no(trx_id_t trx_no) { commit = trx_no << 1; }
/** 2 * trx_t::no + old_insert of the committed transaction */
trx_id_t commit;
/** The record number within the committed transaction's undo /** The record number within the committed transaction's undo
log, increasing, purged from from 0 onwards */ log, increasing, purged from from 0 onwards */
undo_no_t undo_no; undo_no_t undo_no;
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2019, MariaDB Corporation. Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -82,9 +82,8 @@ trx_rseg_header_create( ...@@ -82,9 +82,8 @@ trx_rseg_header_create(
buf_block_t* sys_header, buf_block_t* sys_header,
mtr_t* mtr); mtr_t* mtr);
/** Initialize the rollback segments in memory at database startup. */ /** Initialize or recover the rollback segments at startup. */
void dberr_t trx_rseg_array_init();
trx_rseg_array_init();
/** Free a rollback segment in memory. */ /** Free a rollback segment in memory. */
void void
...@@ -147,21 +146,13 @@ struct trx_rseg_t { ...@@ -147,21 +146,13 @@ struct trx_rseg_t {
/** List of undo log segments cached for fast reuse */ /** List of undo log segments cached for fast reuse */
UT_LIST_BASE_NODE_T(trx_undo_t) undo_cached; UT_LIST_BASE_NODE_T(trx_undo_t) undo_cached;
/** List of recovered old insert_undo logs of incomplete
transactions (to roll back or XA COMMIT & purge) */
UT_LIST_BASE_NODE_T(trx_undo_t) old_insert_list;
/*--------------------------------------------------------*/ /*--------------------------------------------------------*/
/** Page number of the last not yet purged log header in the history /** Last not yet purged undo log header; FIL_NULL if all purged */
list; FIL_NULL if all list purged */ uint32_t last_page_no;
ulint last_page_no;
/** Byte offset of the last not yet purged log header */
ulint last_offset;
/** trx_t::no * 2 + old_insert of the last not yet purged log */ /** trx_t::no | last_offset << 48 */
trx_id_t last_commit; uint64_t last_commit_and_offset;
/** Whether the log segment needs purge */ /** Whether the log segment needs purge */
bool needs_purge; bool needs_purge;
...@@ -173,13 +164,17 @@ struct trx_rseg_t { ...@@ -173,13 +164,17 @@ struct trx_rseg_t {
UNDO-tablespace marked for truncate. */ UNDO-tablespace marked for truncate. */
bool skip_allocation; bool skip_allocation;
/** @return the commit ID of the last committed transaction */ /** @return the commit ID of the last committed transaction */
trx_id_t last_trx_no() const { return last_commit >> 1; } trx_id_t last_trx_no() const
{ return last_commit_and_offset & ((1ULL << 48) - 1); }
void set_last_trx_no(trx_id_t trx_no, bool is_update) /** @return header offset of the last committed transaction */
{ uint16_t last_offset() const
last_commit = trx_no << 1 | trx_id_t(is_update); { return static_cast<uint16_t>(last_commit_and_offset >> 48); }
}
void set_last_commit(ulint last_offset, trx_id_t trx_no)
{
last_commit_and_offset= static_cast<uint64_t>(last_offset) << 48 | trx_no;
}
/** @return whether the rollback segment is persistent */ /** @return whether the rollback segment is persistent */
bool is_persistent() const bool is_persistent() const
......
...@@ -79,7 +79,7 @@ void trx_free_at_shutdown(trx_t *trx); ...@@ -79,7 +79,7 @@ void trx_free_at_shutdown(trx_t *trx);
void trx_disconnect_prepared(trx_t *trx); void trx_disconnect_prepared(trx_t *trx);
/** Initialize (resurrect) transactions at startup. */ /** Initialize (resurrect) transactions at startup. */
void trx_lists_init_at_db_start(); dberr_t trx_lists_init_at_db_start();
/*************************************************************//** /*************************************************************//**
Starts the transaction if it is not yet started. */ Starts the transaction if it is not yet started. */
...@@ -698,10 +698,6 @@ struct trx_undo_ptr_t { ...@@ -698,10 +698,6 @@ struct trx_undo_ptr_t {
yet */ yet */
trx_undo_t* undo; /*!< pointer to the undo log, or trx_undo_t* undo; /*!< pointer to the undo log, or
NULL if nothing logged yet */ NULL if nothing logged yet */
trx_undo_t* old_insert; /*!< pointer to recovered
insert undo log, or NULL if no
INSERT transactions were
recovered from old-format undo logs */
}; };
/** An instance of temporary rollback segment. */ /** An instance of temporary rollback segment. */
...@@ -1055,13 +1051,6 @@ struct trx_t { ...@@ -1055,13 +1051,6 @@ struct trx_t {
return(has_logged_persistent() || rsegs.m_noredo.undo); return(has_logged_persistent() || rsegs.m_noredo.undo);
} }
/** @return whether any undo log has been generated or
recovered */
bool has_logged_or_recovered() const
{
return(has_logged() || rsegs.m_redo.old_insert);
}
/** @return rollback segment for modifying temporary tables */ /** @return rollback segment for modifying temporary tables */
trx_rseg_t* get_temp_rseg() trx_rseg_t* get_temp_rseg()
{ {
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -253,13 +253,11 @@ trx_undo_set_state_at_prepare( ...@@ -253,13 +253,11 @@ trx_undo_set_state_at_prepare(
bool rollback, bool rollback,
mtr_t* mtr); mtr_t* mtr);
/** 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 information is not needed after a commit or rollback, therefore
the data can be discarded. the data can be discarded.
@param[in,out] undo undo log @param undo temporary undo log */
@param[in] is_temp whether this is temporary undo log */ void trx_undo_commit_cleanup(trx_undo_t *undo);
void
trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp);
/** At shutdown, frees the undo logs of a transaction. */ /** At shutdown, frees the undo logs of a transaction. */
void void
...@@ -302,10 +300,11 @@ trx_undo_parse_page_header( ...@@ -302,10 +300,11 @@ trx_undo_parse_page_header(
@param[in] id rollback segment slot @param[in] id rollback segment slot
@param[in] page_no undo log segment page number @param[in] page_no undo log segment page number
@param[in,out] max_trx_id the largest observed transaction ID @param[in,out] max_trx_id the largest observed transaction ID
@return size of the undo log in pages */ @return the undo log
ulint @retval nullptr on error */
trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no, trx_undo_t *
trx_id_t& max_trx_id); trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no,
trx_id_t &max_trx_id);
#endif /* !UNIV_INNOCHECKSUM */ #endif /* !UNIV_INNOCHECKSUM */
...@@ -319,7 +318,6 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no, ...@@ -319,7 +318,6 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
#define TRX_UNDO_ACTIVE 1 /* contains an undo log of an active #define TRX_UNDO_ACTIVE 1 /* contains an undo log of an active
transaction */ transaction */
#define TRX_UNDO_CACHED 2 /* cached for quick reuse */ #define TRX_UNDO_CACHED 2 /* cached for quick reuse */
#define TRX_UNDO_TO_FREE 3 /* insert undo segment can be freed */
#define TRX_UNDO_TO_PURGE 4 /* update undo segment will not be #define TRX_UNDO_TO_PURGE 4 /* update undo segment will not be
reused: it can be freed in purge when reused: it can be freed in purge when
all undo data in it is removed */ all undo data in it is removed */
...@@ -383,7 +381,8 @@ struct trx_undo_t { ...@@ -383,7 +381,8 @@ struct trx_undo_t {
/** Transaction undo log page header offsets */ /** Transaction undo log page header offsets */
/* @{ */ /* @{ */
#define TRX_UNDO_PAGE_TYPE 0 /*!< unused; 0 (before MariaDB 10.3.1: #define TRX_UNDO_PAGE_TYPE 0 /*!< unused; 0 (before MariaDB 10.3.1:
TRX_UNDO_INSERT or TRX_UNDO_UPDATE) */ 1=TRX_UNDO_INSERT or
2=TRX_UNDO_UPDATE) */
#define TRX_UNDO_PAGE_START 2 /*!< Byte offset where the undo log #define TRX_UNDO_PAGE_START 2 /*!< Byte offset where the undo log
records for the LATEST transaction records for the LATEST transaction
start on this page (remember that start on this page (remember that
......
...@@ -4584,7 +4584,7 @@ lock_print_info_summary( ...@@ -4584,7 +4584,7 @@ lock_print_info_summary(
"Purge done for trx's n:o < " TRX_ID_FMT "Purge done for trx's n:o < " TRX_ID_FMT
" undo n:o < " TRX_ID_FMT " state: %s\n" " undo n:o < " TRX_ID_FMT " state: %s\n"
"History list length %u\n", "History list length %u\n",
purge_sys.tail.trx_no(), purge_sys.tail.trx_no,
purge_sys.tail.undo_no, purge_sys.tail.undo_no,
purge_sys.enabled() purge_sys.enabled()
? (purge_sys.running() ? "running" ? (purge_sys.running() ? "running"
......
...@@ -1404,6 +1404,11 @@ dberr_t srv_start(bool create_new_db) ...@@ -1404,6 +1404,11 @@ dberr_t srv_start(bool create_new_db)
|| is_mariabackup_restore_or_export()); || is_mariabackup_restore_or_export());
if (srv_force_recovery) {
ib::info() << "!!! innodb_force_recovery is set to "
<< srv_force_recovery << " !!!";
}
if (srv_force_recovery == SRV_FORCE_NO_LOG_REDO) { if (srv_force_recovery == SRV_FORCE_NO_LOG_REDO) {
srv_read_only_mode = true; srv_read_only_mode = true;
} }
...@@ -1922,7 +1927,11 @@ dberr_t srv_start(bool create_new_db) ...@@ -1922,7 +1927,11 @@ dberr_t srv_start(bool create_new_db)
All the remaining rollback segments will be created later, All the remaining rollback segments will be created later,
after the double write buffer has been created. */ after the double write buffer has been created. */
trx_sys_create_sys_pages(); trx_sys_create_sys_pages();
trx_lists_init_at_db_start(); err = trx_lists_init_at_db_start();
if (err != DB_SUCCESS) {
return(srv_init_abort(err));
}
err = dict_create(); err = dict_create();
...@@ -1986,7 +1995,10 @@ dberr_t srv_start(bool create_new_db) ...@@ -1986,7 +1995,10 @@ dberr_t srv_start(bool create_new_db)
case SRV_OPERATION_RESTORE: case SRV_OPERATION_RESTORE:
/* This must precede /* This must precede
recv_apply_hashed_log_recs(true). */ recv_apply_hashed_log_recs(true). */
trx_lists_init_at_db_start(); err = trx_lists_init_at_db_start();
if (err != DB_SUCCESS) {
return srv_init_abort(err);
}
break; break;
case SRV_OPERATION_RESTORE_DELTA: case SRV_OPERATION_RESTORE_DELTA:
case SRV_OPERATION_BACKUP: case SRV_OPERATION_BACKUP:
...@@ -2453,11 +2465,6 @@ dberr_t srv_start(bool create_new_db) ...@@ -2453,11 +2465,6 @@ dberr_t srv_start(bool create_new_db)
<< "; transaction id " << trx_sys.get_max_trx_id(); << "; transaction id " << trx_sys.get_max_trx_id();
} }
if (srv_force_recovery > 0) {
ib::info() << "!!! innodb_force_recovery is set to "
<< srv_force_recovery << " !!!";
}
if (srv_force_recovery == 0) { if (srv_force_recovery == 0) {
/* In the insert buffer we may have even bigger tablespace /* In the insert buffer we may have even bigger tablespace
id's, because we may have dropped those tablespaces, but id's, because we may have dropped those tablespaces, but
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -87,7 +87,7 @@ inline bool TrxUndoRsegsIterator::set_next() ...@@ -87,7 +87,7 @@ inline bool TrxUndoRsegsIterator::set_next()
number shouldn't increase. Undo the increment of number shouldn't increase. Undo the increment of
expected commit done by caller assuming rollback expected commit done by caller assuming rollback
segments from given transaction are done. */ segments from given transaction are done. */
purge_sys.tail.commit = (*m_iter)->last_commit; purge_sys.tail.trx_no = (*m_iter)->last_trx_no();
} else if (!purge_sys.purge_queue.empty()) { } else if (!purge_sys.purge_queue.empty()) {
m_rsegs = purge_sys.purge_queue.top(); m_rsegs = purge_sys.purge_queue.top();
purge_sys.purge_queue.pop(); purge_sys.purge_queue.pop();
...@@ -108,17 +108,17 @@ inline bool TrxUndoRsegsIterator::set_next() ...@@ -108,17 +108,17 @@ inline bool TrxUndoRsegsIterator::set_next()
mutex_enter(&purge_sys.rseg->mutex); mutex_enter(&purge_sys.rseg->mutex);
ut_a(purge_sys.rseg->last_page_no != FIL_NULL); ut_a(purge_sys.rseg->last_page_no != FIL_NULL);
ut_ad(purge_sys.rseg->last_trx_no() == m_rsegs.trx_no()); ut_ad(purge_sys.rseg->last_trx_no() == m_rsegs.trx_no);
/* We assume in purge of externally stored fields that space id is /* We assume in purge of externally stored fields that space id is
in the range of UNDO tablespace space ids */ in the range of UNDO tablespace space ids */
ut_ad(purge_sys.rseg->space->id == TRX_SYS_SPACE ut_ad(purge_sys.rseg->space->id == TRX_SYS_SPACE
|| srv_is_undo_tablespace(purge_sys.rseg->space->id)); || srv_is_undo_tablespace(purge_sys.rseg->space->id));
ut_a(purge_sys.tail.commit <= purge_sys.rseg->last_commit); ut_a(purge_sys.tail.trx_no <= purge_sys.rseg->last_trx_no());
purge_sys.tail.commit = purge_sys.rseg->last_commit; purge_sys.tail.trx_no = purge_sys.rseg->last_trx_no();
purge_sys.hdr_offset = purge_sys.rseg->last_offset; purge_sys.hdr_offset = purge_sys.rseg->last_offset();
purge_sys.hdr_page_no = purge_sys.rseg->last_page_no; purge_sys.hdr_page_no = purge_sys.rseg->last_page_no;
mutex_exit(&purge_sys.rseg->mutex); mutex_exit(&purge_sys.rseg->mutex);
...@@ -209,8 +209,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) ...@@ -209,8 +209,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr)
{ {
DBUG_PRINT("trx", ("commit(" TRX_ID_FMT "," TRX_ID_FMT ")", DBUG_PRINT("trx", ("commit(" TRX_ID_FMT "," TRX_ID_FMT ")",
trx->id, trx->no)); trx->id, trx->no));
ut_ad(undo == trx->rsegs.m_redo.undo ut_ad(undo == trx->rsegs.m_redo.undo);
|| undo == trx->rsegs.m_redo.old_insert);
trx_rseg_t* rseg = trx->rsegs.m_redo.rseg; trx_rseg_t* rseg = trx->rsegs.m_redo.rseg;
ut_ad(undo->rseg == rseg); ut_ad(undo->rseg == rseg);
trx_rsegf_t* rseg_header = trx_rsegf_get( trx_rsegf_t* rseg_header = trx_rsegf_get(
...@@ -302,9 +301,8 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) ...@@ -302,9 +301,8 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr)
} }
if (rseg->last_page_no == FIL_NULL) { if (rseg->last_page_no == FIL_NULL) {
rseg->last_page_no = undo->hdr_page_no; rseg->last_page_no = static_cast<uint32_t>(undo->hdr_page_no);
rseg->last_offset = undo->hdr_offset; rseg->set_last_commit(undo->hdr_offset, trx->no);
rseg->set_last_trx_no(trx->no, undo == trx->rsegs.m_redo.undo);
rseg->needs_purge = true; rseg->needs_purge = true;
} }
...@@ -460,8 +458,8 @@ trx_purge_truncate_rseg_history( ...@@ -460,8 +458,8 @@ trx_purge_truncate_rseg_history(
undo_trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO); undo_trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
if (undo_trx_no >= limit.trx_no()) { if (undo_trx_no >= limit.trx_no) {
if (undo_trx_no == limit.trx_no()) { if (undo_trx_no == limit.trx_no) {
trx_undo_truncate_start( trx_undo_truncate_start(
&rseg, hdr_addr.page, &rseg, hdr_addr.page,
hdr_addr.boffset, limit.undo_no); hdr_addr.boffset, limit.undo_no);
...@@ -884,7 +882,7 @@ trx_purge_initiate_truncate( ...@@ -884,7 +882,7 @@ trx_purge_initiate_truncate(
undo != NULL && all_free; undo != NULL && all_free;
undo = UT_LIST_GET_NEXT(undo_list, undo)) { undo = UT_LIST_GET_NEXT(undo_list, undo)) {
if (limit.trx_no() < undo->trx_id) { if (limit.trx_no < undo->trx_id) {
all_free = false; all_free = false;
} else { } else {
cached_undo_size += undo->size; cached_undo_size += undo->size;
...@@ -986,7 +984,6 @@ trx_purge_initiate_truncate( ...@@ -986,7 +984,6 @@ trx_purge_initiate_truncate(
/* Before re-initialization ensure that we free the existing /* Before re-initialization ensure that we free the existing
structure. There can't be any active transactions. */ structure. There can't be any active transactions. */
ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0); ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0);
ut_a(UT_LIST_GET_LEN(rseg->old_insert_list) == 0);
trx_undo_t* next_undo; trx_undo_t* next_undo;
...@@ -1002,7 +999,6 @@ trx_purge_initiate_truncate( ...@@ -1002,7 +999,6 @@ trx_purge_initiate_truncate(
UT_LIST_INIT(rseg->undo_list, &trx_undo_t::undo_list); UT_LIST_INIT(rseg->undo_list, &trx_undo_t::undo_list);
UT_LIST_INIT(rseg->undo_cached, &trx_undo_t::undo_list); UT_LIST_INIT(rseg->undo_cached, &trx_undo_t::undo_list);
UT_LIST_INIT(rseg->old_insert_list, &trx_undo_t::undo_list);
/* These were written by trx_rseg_header_create(). */ /* These were written by trx_rseg_header_create(). */
ut_ad(!mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT ut_ad(!mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT
...@@ -1014,8 +1010,7 @@ trx_purge_initiate_truncate( ...@@ -1014,8 +1010,7 @@ trx_purge_initiate_truncate(
rseg->curr_size = 1; rseg->curr_size = 1;
rseg->trx_ref_count = 0; rseg->trx_ref_count = 0;
rseg->last_page_no = FIL_NULL; rseg->last_page_no = FIL_NULL;
rseg->last_offset = 0; rseg->last_commit_and_offset = 0;
rseg->last_commit = 0;
rseg->needs_purge = false; rseg->needs_purge = false;
} }
...@@ -1076,12 +1071,12 @@ function is called, the caller must not have any latches on undo log pages! ...@@ -1076,12 +1071,12 @@ function is called, the caller must not have any latches on undo log pages!
static void trx_purge_truncate_history() static void trx_purge_truncate_history()
{ {
ut_ad(purge_sys.head <= purge_sys.tail); ut_ad(purge_sys.head <= purge_sys.tail);
purge_sys_t::iterator& head = purge_sys.head.commit purge_sys_t::iterator& head = purge_sys.head.trx_no
? purge_sys.head : purge_sys.tail; ? purge_sys.head : purge_sys.tail;
if (head.trx_no() >= purge_sys.view.low_limit_no()) { if (head.trx_no >= purge_sys.view.low_limit_no()) {
/* This is sometimes necessary. TODO: find out why. */ /* This is sometimes necessary. TODO: find out why. */
head.reset_trx_no(purge_sys.view.low_limit_no()); head.trx_no = purge_sys.view.low_limit_no();
head.undo_no = 0; head.undo_no = 0;
} }
...@@ -1109,7 +1104,6 @@ static void trx_purge_rseg_get_next_history_log( ...@@ -1109,7 +1104,6 @@ static void trx_purge_rseg_get_next_history_log(
handled */ handled */
{ {
page_t* undo_page; page_t* undo_page;
trx_ulogf_t* log_hdr;
fil_addr_t prev_log_addr; fil_addr_t prev_log_addr;
trx_id_t trx_no; trx_id_t trx_no;
mtr_t mtr; mtr_t mtr;
...@@ -1118,7 +1112,7 @@ static void trx_purge_rseg_get_next_history_log( ...@@ -1118,7 +1112,7 @@ static void trx_purge_rseg_get_next_history_log(
ut_a(purge_sys.rseg->last_page_no != FIL_NULL); ut_a(purge_sys.rseg->last_page_no != FIL_NULL);
purge_sys.tail.commit = purge_sys.rseg->last_commit + 1; purge_sys.tail.trx_no = purge_sys.rseg->last_trx_no() + 1;
purge_sys.tail.undo_no = 0; purge_sys.tail.undo_no = 0;
purge_sys.next_stored = false; purge_sys.next_stored = false;
...@@ -1128,7 +1122,7 @@ static void trx_purge_rseg_get_next_history_log( ...@@ -1128,7 +1122,7 @@ static void trx_purge_rseg_get_next_history_log(
page_id_t(purge_sys.rseg->space->id, page_id_t(purge_sys.rseg->space->id,
purge_sys.rseg->last_page_no), &mtr); purge_sys.rseg->last_page_no), &mtr);
log_hdr = undo_page + purge_sys.rseg->last_offset; const trx_ulogf_t* log_hdr = undo_page + purge_sys.rseg->last_offset();
/* Increase the purge page count by one for every handled log */ /* Increase the purge page count by one for every handled log */
...@@ -1160,17 +1154,16 @@ static void trx_purge_rseg_get_next_history_log( ...@@ -1160,17 +1154,16 @@ static void trx_purge_rseg_get_next_history_log(
+ prev_log_addr.boffset; + prev_log_addr.boffset;
trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO); trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
unsigned purge = mach_read_from_2(log_hdr + TRX_UNDO_NEEDS_PURGE); ut_ad(mach_read_from_2(log_hdr + TRX_UNDO_NEEDS_PURGE) <= 1);
ut_ad(purge <= 1);
mtr_commit(&mtr); mtr_commit(&mtr);
mutex_enter(&purge_sys.rseg->mutex); mutex_enter(&purge_sys.rseg->mutex);
purge_sys.rseg->last_page_no = prev_log_addr.page; purge_sys.rseg->last_page_no = static_cast<uint32_t>(
purge_sys.rseg->last_offset = prev_log_addr.boffset; prev_log_addr.page);
purge_sys.rseg->set_last_trx_no(trx_no, purge != 0); purge_sys.rseg->set_last_commit(prev_log_addr.boffset, trx_no);
purge_sys.rseg->needs_purge = purge != 0; purge_sys.rseg->needs_purge = log_hdr[TRX_UNDO_NEEDS_PURGE + 1] != 0;
/* Purge can also produce events, however these are already ordered /* Purge can also produce events, however these are already ordered
in the rollback segment and any user generated event will be greater in the rollback segment and any user generated event will be greater
...@@ -1187,15 +1180,13 @@ static void trx_purge_rseg_get_next_history_log( ...@@ -1187,15 +1180,13 @@ static void trx_purge_rseg_get_next_history_log(
} }
/** Position the purge sys "iterator" on the undo record to use for purging. */ /** Position the purge sys "iterator" on the undo record to use for purging. */
static static void trx_purge_read_undo_rec()
void
trx_purge_read_undo_rec()
{ {
ulint offset; ulint offset;
ulint page_no; ulint page_no;
ib_uint64_t undo_no; ib_uint64_t undo_no;
purge_sys.hdr_offset = purge_sys.rseg->last_offset; purge_sys.hdr_offset = purge_sys.rseg->last_offset();
page_no = purge_sys.hdr_page_no = purge_sys.rseg->last_page_no; page_no = purge_sys.hdr_page_no = purge_sys.rseg->last_page_no;
if (purge_sys.rseg->needs_purge) { if (purge_sys.rseg->needs_purge) {
...@@ -1268,7 +1259,7 @@ trx_purge_get_next_rec( ...@@ -1268,7 +1259,7 @@ trx_purge_get_next_rec(
mtr_t mtr; mtr_t mtr;
ut_ad(purge_sys.next_stored); ut_ad(purge_sys.next_stored);
ut_ad(purge_sys.tail.trx_no() < purge_sys.view.low_limit_no()); ut_ad(purge_sys.tail.trx_no < purge_sys.view.low_limit_no());
space = purge_sys.rseg->space->id; space = purge_sys.rseg->space->id;
page_no = purge_sys.page_no; page_no = purge_sys.page_no;
...@@ -1361,7 +1352,7 @@ trx_purge_fetch_next_rec( ...@@ -1361,7 +1352,7 @@ trx_purge_fetch_next_rec(
} }
} }
if (purge_sys.tail.trx_no() >= purge_sys.view.low_limit_no()) { if (purge_sys.tail.trx_no >= purge_sys.view.low_limit_no()) {
return(NULL); return(NULL);
} }
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2020, MariaDB Corporation. Copyright (c) 2016, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -70,12 +70,6 @@ static bool trx_rollback_finish(trx_t* trx) ...@@ -70,12 +70,6 @@ static bool trx_rollback_finish(trx_t* trx)
ut_a(!srv_undo_sources); ut_a(!srv_undo_sources);
ut_ad(srv_fast_shutdown); ut_ad(srv_fast_shutdown);
ut_d(trx->in_rollback = false); ut_d(trx->in_rollback = false);
if (trx_undo_t*& undo = trx->rsegs.m_redo.old_insert) {
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_redo.undo) { if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) {
UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->undo_list, UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->undo_list,
undo); undo);
...@@ -124,7 +118,7 @@ trx_rollback_to_savepoint_low( ...@@ -124,7 +118,7 @@ trx_rollback_to_savepoint_low(
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
if (trx->has_logged_or_recovered()) { if (trx->has_logged()) {
ut_ad(trx->rsegs.m_redo.rseg != 0 ut_ad(trx->rsegs.m_redo.rseg != 0
|| trx->rsegs.m_noredo.rseg != 0); || trx->rsegs.m_noredo.rseg != 0);
...@@ -240,7 +234,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -240,7 +234,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
case TRX_STATE_PREPARED: case TRX_STATE_PREPARED:
case TRX_STATE_PREPARED_RECOVERED: case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx_is_autocommit_non_locking(trx));
if (trx->rsegs.m_redo.undo || trx->rsegs.m_redo.old_insert) { if (trx->rsegs.m_redo.undo) {
/* The XA ROLLBACK of a XA PREPARE transaction /* The XA ROLLBACK of a XA PREPARE transaction
will consist of multiple mini-transactions. will consist of multiple mini-transactions.
...@@ -256,11 +250,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -256,11 +250,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
killed, and finally, the transaction would be killed, and finally, the transaction would be
recovered in XA PREPARE state, with some of recovered in XA PREPARE state, with some of
the actions already having been rolled back. */ the actions already having been rolled back. */
ut_ad(!trx->rsegs.m_redo.undo ut_ad(trx->rsegs.m_redo.undo->rseg
|| trx->rsegs.m_redo.undo->rseg
== trx->rsegs.m_redo.rseg);
ut_ad(!trx->rsegs.m_redo.old_insert
|| trx->rsegs.m_redo.old_insert->rseg
== trx->rsegs.m_redo.rseg); == trx->rsegs.m_redo.rseg);
mtr_t mtr; mtr_t mtr;
mtr.start(); mtr.start();
...@@ -269,10 +259,6 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -269,10 +259,6 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
trx_undo_set_state_at_prepare(trx, undo, true, trx_undo_set_state_at_prepare(trx, undo, true,
&mtr); &mtr);
} }
if (trx_undo_t* undo = trx->rsegs.m_redo.old_insert) {
trx_undo_set_state_at_prepare(trx, undo, true,
&mtr);
}
mutex_exit(&trx->rsegs.m_redo.rseg->mutex); mutex_exit(&trx->rsegs.m_redo.rseg->mutex);
/* Write the redo log for the XA ROLLBACK /* Write the redo log for the XA ROLLBACK
state change to the global buffer. It is state change to the global buffer. It is
...@@ -959,23 +945,13 @@ trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap) ...@@ -959,23 +945,13 @@ trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap)
} }
trx_undo_t* undo = NULL; trx_undo_t* undo = NULL;
trx_undo_t* insert = trx->rsegs.m_redo.old_insert;
trx_undo_t* update = trx->rsegs.m_redo.undo; trx_undo_t* update = trx->rsegs.m_redo.undo;
trx_undo_t* temp = trx->rsegs.m_noredo.undo; trx_undo_t* temp = trx->rsegs.m_noredo.undo;
const undo_no_t limit = trx->roll_limit; const undo_no_t limit = trx->roll_limit;
ut_ad(!insert || !update || insert->empty() || update->empty()
|| insert->top_undo_no != update->top_undo_no);
ut_ad(!insert || !temp || insert->empty() || temp->empty()
|| insert->top_undo_no != temp->top_undo_no);
ut_ad(!update || !temp || update->empty() || temp->empty() ut_ad(!update || !temp || update->empty() || temp->empty()
|| update->top_undo_no != temp->top_undo_no); || update->top_undo_no != temp->top_undo_no);
if (UNIV_LIKELY_NULL(insert)
&& !insert->empty() && limit <= insert->top_undo_no) {
undo = insert;
}
if (update && !update->empty() && update->top_undo_no >= limit) { if (update && !update->empty() && update->top_undo_no >= limit) {
if (!undo) { if (!undo) {
undo = update; undo = update;
...@@ -1020,18 +996,12 @@ trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap) ...@@ -1020,18 +996,12 @@ trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap)
MDEV-12288 removed the insert_undo log. There is no MDEV-12288 removed the insert_undo log. There is no
instant ADD COLUMN for temporary tables. Therefore, instant ADD COLUMN for temporary tables. Therefore,
this record can only be present in the main undo log. */ this record can only be present in the main undo log. */
ut_ad(undo == update);
/* fall through */ /* fall through */
case TRX_UNDO_RENAME_TABLE: case TRX_UNDO_RENAME_TABLE:
ut_ad(undo == insert || undo == update); ut_ad(undo == update);
/* fall through */ /* fall through */
case TRX_UNDO_INSERT_REC: case TRX_UNDO_INSERT_REC:
ut_ad(undo == insert || undo == update || undo == temp);
*roll_ptr |= 1ULL << ROLL_PTR_INSERT_FLAG_POS; *roll_ptr |= 1ULL << ROLL_PTR_INSERT_FLAG_POS;
break;
default:
ut_ad(undo == update || undo == temp);
break;
} }
trx->undo_no = undo_no; trx->undo_no = undo_no;
......
...@@ -359,7 +359,6 @@ trx_rseg_mem_free(trx_rseg_t* rseg) ...@@ -359,7 +359,6 @@ trx_rseg_mem_free(trx_rseg_t* rseg)
/* There can't be any active transactions. */ /* There can't be any active transactions. */
ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0); ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0);
ut_a(UT_LIST_GET_LEN(rseg->old_insert_list) == 0);
for (undo = UT_LIST_GET_FIRST(rseg->undo_cached); for (undo = UT_LIST_GET_FIRST(rseg->undo_cached);
undo != NULL; undo != NULL;
...@@ -399,45 +398,45 @@ trx_rseg_mem_create(ulint id, fil_space_t* space, ulint page_no) ...@@ -399,45 +398,45 @@ trx_rseg_mem_create(ulint id, fil_space_t* space, ulint page_no)
&rseg->mutex); &rseg->mutex);
UT_LIST_INIT(rseg->undo_list, &trx_undo_t::undo_list); UT_LIST_INIT(rseg->undo_list, &trx_undo_t::undo_list);
UT_LIST_INIT(rseg->old_insert_list, &trx_undo_t::undo_list);
UT_LIST_INIT(rseg->undo_cached, &trx_undo_t::undo_list); UT_LIST_INIT(rseg->undo_cached, &trx_undo_t::undo_list);
return(rseg); return(rseg);
} }
/** Read the undo log lists. /** Read the undo log lists.
@param[in,out] rseg rollback segment @param[in,out] rseg rollback segment
@param[in,out] max_trx_id maximum observed transaction identifier @param[in,out] max_trx_id maximum observed transaction identifier
@param[in] rseg_header rollback segment header @param[in] rseg_header rollback segment header
@return the combined size of undo log segments in pages */ @return error code */
static static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id,
ulint const trx_rsegf_t *rseg_header)
trx_undo_lists_init(trx_rseg_t* rseg, trx_id_t& max_trx_id,
const trx_rsegf_t* rseg_header)
{ {
ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN); ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN);
ulint size = 0; for (ulint i= 0; i < TRX_RSEG_N_SLOTS; i++)
{
for (ulint i = 0; i < TRX_RSEG_N_SLOTS; i++) { uint32_t page_no= trx_rsegf_get_nth_undo(rseg_header, i);
ulint page_no = trx_rsegf_get_nth_undo(rseg_header, i); if (page_no != FIL_NULL)
if (page_no != FIL_NULL) { {
size += trx_undo_mem_create_at_db_start( const trx_undo_t *undo= trx_undo_mem_create_at_db_start(rseg, i, page_no,
rseg, i, page_no, max_trx_id); max_trx_id);
MONITOR_INC(MONITOR_NUM_UNDO_SLOT_USED); if (!undo)
} return DB_CORRUPTION;
} rseg->curr_size+= undo->size;
MONITOR_INC(MONITOR_NUM_UNDO_SLOT_USED);
return(size); }
}
return DB_SUCCESS;
} }
/** Restore the state of a persistent rollback segment. /** Restore the state of a persistent rollback segment.
@param[in,out] rseg persistent rollback segment @param[in,out] rseg persistent rollback segment
@param[in,out] max_trx_id maximum observed transaction identifier @param[in,out] max_trx_id maximum observed transaction identifier
@param[in,out] mtr mini-transaction */ @param[in,out] mtr mini-transaction
static @return error code */
void static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr) mtr_t *mtr)
{ {
/* This is based on trx_rsegf_get_new(). /* This is based on trx_rsegf_get_new().
We need to access buf_block_t. */ We need to access buf_block_t. */
...@@ -484,13 +483,16 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr) ...@@ -484,13 +483,16 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr)
/* mariabackup --prepare only deals with /* mariabackup --prepare only deals with
the redo log and the data files, not with the redo log and the data files, not with
transactions or the data dictionary. */ transactions or the data dictionary. */
return; return DB_SUCCESS;
} }
/* Initialize the undo log lists according to the rseg header */ /* Initialize the undo log lists according to the rseg header */
rseg->curr_size = mach_read_from_4(rseg_header + TRX_RSEG_HISTORY_SIZE) rseg->curr_size = mach_read_from_4(rseg_header + TRX_RSEG_HISTORY_SIZE)
+ 1 + trx_undo_lists_init(rseg, max_trx_id, rseg_header); + 1;
if (dberr_t err = trx_undo_lists_init(rseg, max_trx_id, rseg_header)) {
return err;
}
if (ulint len = flst_get_len(rseg_header + TRX_RSEG_HISTORY)) { if (ulint len = flst_get_len(rseg_header + TRX_RSEG_HISTORY)) {
trx_sys.history_add(int32(len)); trx_sys.history_add(int32(len));
...@@ -498,8 +500,7 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr) ...@@ -498,8 +500,7 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr)
fil_addr_t node_addr = trx_purge_get_log_from_hist( fil_addr_t node_addr = trx_purge_get_log_from_hist(
flst_get_last(rseg_header + TRX_RSEG_HISTORY, mtr)); flst_get_last(rseg_header + TRX_RSEG_HISTORY, mtr));
rseg->last_page_no = node_addr.page; rseg->last_page_no = static_cast<uint32_t>(node_addr.page);
rseg->last_offset = node_addr.boffset;
const trx_ulogf_t* undo_log_hdr = trx_undo_page_get( const trx_ulogf_t* undo_log_hdr = trx_undo_page_get(
page_id_t(rseg->space->id, node_addr.page), mtr) page_id_t(rseg->space->id, node_addr.page), mtr)
...@@ -513,10 +514,10 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr) ...@@ -513,10 +514,10 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr)
if (id > max_trx_id) { if (id > max_trx_id) {
max_trx_id = id; max_trx_id = id;
} }
rseg->set_last_commit(node_addr.boffset, id);
unsigned purge = mach_read_from_2( unsigned purge = mach_read_from_2(
undo_log_hdr + TRX_UNDO_NEEDS_PURGE); undo_log_hdr + TRX_UNDO_NEEDS_PURGE);
ut_ad(purge <= 1); ut_ad(purge <= 1);
rseg->set_last_trx_no(id, purge != 0);
rseg->needs_purge = purge != 0; rseg->needs_purge = purge != 0;
if (rseg->last_page_no != FIL_NULL) { if (rseg->last_page_no != FIL_NULL) {
...@@ -526,6 +527,8 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr) ...@@ -526,6 +527,8 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr)
purge_sys.purge_queue.push(*rseg); purge_sys.purge_queue.push(*rseg);
} }
} }
return DB_SUCCESS;
} }
/** Read binlog metadata from the TRX_SYS page, in case we are upgrading /** Read binlog metadata from the TRX_SYS page, in case we are upgrading
...@@ -549,9 +552,8 @@ static void trx_rseg_init_binlog_info(const page_t* page) ...@@ -549,9 +552,8 @@ static void trx_rseg_init_binlog_info(const page_t* page)
#endif #endif
} }
/** Initialize the rollback segments in memory at database startup. */ /** Initialize or recover the rollback segments at startup. */
void dberr_t trx_rseg_array_init()
trx_rseg_array_init()
{ {
trx_id_t max_trx_id = 0; trx_id_t max_trx_id = 0;
...@@ -563,9 +565,9 @@ trx_rseg_array_init() ...@@ -563,9 +565,9 @@ trx_rseg_array_init()
wsrep_sys_xid.null(); wsrep_sys_xid.null();
bool wsrep_xid_in_rseg_found = false; bool wsrep_xid_in_rseg_found = false;
#endif #endif
mtr_t mtr;
for (ulint rseg_id = 0; rseg_id < TRX_SYS_N_RSEGS; rseg_id++) { for (ulint rseg_id = 0; rseg_id < TRX_SYS_N_RSEGS; rseg_id++) {
mtr_t mtr;
mtr.start(); mtr.start();
if (const buf_block_t* sys = trx_sysf_get(&mtr, false)) { if (const buf_block_t* sys = trx_sysf_get(&mtr, false)) {
if (rseg_id == 0) { if (rseg_id == 0) {
...@@ -593,7 +595,11 @@ trx_rseg_array_init() ...@@ -593,7 +595,11 @@ trx_rseg_array_init()
ut_ad(rseg->id == rseg_id); ut_ad(rseg->id == rseg_id);
ut_ad(!trx_sys.rseg_array[rseg_id]); ut_ad(!trx_sys.rseg_array[rseg_id]);
trx_sys.rseg_array[rseg_id] = rseg; trx_sys.rseg_array[rseg_id] = rseg;
trx_rseg_mem_restore(rseg, max_trx_id, &mtr); if (dberr_t err = trx_rseg_mem_restore(
rseg, max_trx_id, &mtr)) {
mtr.commit();
return err;
}
#ifdef WITH_WSREP #ifdef WITH_WSREP
if (!wsrep_sys_xid.is_null() && if (!wsrep_sys_xid.is_null() &&
!wsrep_sys_xid.eq(&trx_sys.recovered_wsrep_xid)) { !wsrep_sys_xid.eq(&trx_sys.recovered_wsrep_xid)) {
...@@ -620,7 +626,6 @@ trx_rseg_array_init() ...@@ -620,7 +626,6 @@ trx_rseg_array_init()
If no rollback segment has a WSREP XID set, If no rollback segment has a WSREP XID set,
we must copy the XID found in TRX_SYS page we must copy the XID found in TRX_SYS page
to rollback segments. */ to rollback segments. */
mtr_t mtr;
mtr.start(); mtr.start();
if (!wsrep_xid_in_rseg_found) { if (!wsrep_xid_in_rseg_found) {
...@@ -638,6 +643,7 @@ trx_rseg_array_init() ...@@ -638,6 +643,7 @@ trx_rseg_array_init()
#endif #endif
trx_sys.init_max_trx_id(max_trx_id + 1); trx_sys.init_max_trx_id(max_trx_id + 1);
return DB_SUCCESS;
} }
/** Create a persistent rollback segment. /** Create a persistent rollback segment.
......
...@@ -664,8 +664,7 @@ trx_resurrect_table_locks( ...@@ -664,8 +664,7 @@ trx_resurrect_table_locks(
static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg, static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
time_t start_time, ulonglong start_time_micro, time_t start_time, ulonglong start_time_micro,
uint64_t *rows_to_undo, uint64_t *rows_to_undo)
bool is_old_insert)
{ {
trx_state_t state; trx_state_t state;
/* /*
...@@ -688,8 +687,6 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg, ...@@ -688,8 +687,6 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
state= TRX_STATE_PREPARED; state= TRX_STATE_PREPARED;
break; break;
default: default:
if (is_old_insert && srv_force_recovery < SRV_FORCE_NO_TRX_UNDO)
trx_undo_commit_cleanup(undo, false);
return; return;
} }
...@@ -699,11 +696,7 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg, ...@@ -699,11 +696,7 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
ut_d(trx->start_line= __LINE__); ut_d(trx->start_line= __LINE__);
ut_ad(trx->no == TRX_ID_MAX); ut_ad(trx->no == TRX_ID_MAX);
if (is_old_insert) trx->rsegs.m_redo.undo= undo;
trx->rsegs.m_redo.old_insert= undo;
else
trx->rsegs.m_redo.undo= undo;
trx->undo_no= undo->top_undo_no + 1; trx->undo_no= undo->top_undo_no + 1;
trx->rsegs.m_redo.rseg= rseg; trx->rsegs.m_redo.rseg= rseg;
/* /*
...@@ -734,8 +727,7 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg, ...@@ -734,8 +727,7 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
/** Initialize (resurrect) transactions at startup. */ /** Initialize (resurrect) transactions at startup. */
void dberr_t trx_lists_init_at_db_start()
trx_lists_init_at_db_start()
{ {
ut_a(srv_is_being_started); ut_a(srv_is_being_started);
ut_ad(!srv_was_started); ut_ad(!srv_was_started);
...@@ -744,16 +736,18 @@ trx_lists_init_at_db_start() ...@@ -744,16 +736,18 @@ trx_lists_init_at_db_start()
/* mariabackup --prepare only deals with /* mariabackup --prepare only deals with
the redo log and the data files, not with the redo log and the data files, not with
transactions or the data dictionary. */ transactions or the data dictionary. */
trx_rseg_array_init(); return trx_rseg_array_init();
return;
} }
if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) { if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
return; return DB_SUCCESS;
} }
purge_sys.create(); purge_sys.create();
trx_rseg_array_init(); if (dberr_t err = trx_rseg_array_init()) {
ib::info() << "Retry with innodb_force_recovery=5";
return err;
}
/* Look from the rollback segments if there exist undo logs for /* Look from the rollback segments if there exist undo logs for
transactions. */ transactions. */
...@@ -771,17 +765,6 @@ trx_lists_init_at_db_start() ...@@ -771,17 +765,6 @@ trx_lists_init_at_db_start()
if (rseg == NULL) { if (rseg == NULL) {
continue; continue;
} }
/* Resurrect transactions that were doing inserts
using the old separate insert_undo log. */
undo = UT_LIST_GET_FIRST(rseg->old_insert_list);
while (undo) {
trx_undo_t* next = UT_LIST_GET_NEXT(undo_list, undo);
trx_resurrect(undo, rseg, start_time, start_time_micro,
&rows_to_undo, true);
undo = next;
}
/* Ressurrect other transactions. */ /* Ressurrect other transactions. */
for (undo = UT_LIST_GET_FIRST(rseg->undo_list); for (undo = UT_LIST_GET_FIRST(rseg->undo_list);
undo != NULL; undo != NULL;
...@@ -789,8 +772,7 @@ trx_lists_init_at_db_start() ...@@ -789,8 +772,7 @@ trx_lists_init_at_db_start()
trx_t *trx = trx_sys.find(0, undo->trx_id, false); trx_t *trx = trx_sys.find(0, undo->trx_id, false);
if (!trx) { if (!trx) {
trx_resurrect(undo, rseg, start_time, trx_resurrect(undo, rseg, start_time,
start_time_micro, start_time_micro, &rows_to_undo);
&rows_to_undo, false);
} else { } else {
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) || ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
trx_state_eq(trx, TRX_STATE_PREPARED)); trx_state_eq(trx, TRX_STATE_PREPARED));
...@@ -825,6 +807,7 @@ trx_lists_init_at_db_start() ...@@ -825,6 +807,7 @@ trx_lists_init_at_db_start()
ib::info() << "Trx id counter is " << trx_sys.get_max_trx_id(); ib::info() << "Trx id counter is " << trx_sys.get_max_trx_id();
} }
trx_sys.clone_oldest_view(); trx_sys.clone_oldest_view();
return DB_SUCCESS;
} }
/** Assign a persistent rollback segment in a round-robin fashion, /** Assign a persistent rollback segment in a round-robin fashion,
...@@ -1121,30 +1104,22 @@ trx_write_serialisation_history( ...@@ -1121,30 +1104,22 @@ trx_write_serialisation_history(
trx_rseg_t* rseg = trx->rsegs.m_redo.rseg; trx_rseg_t* rseg = trx->rsegs.m_redo.rseg;
if (!rseg) { if (!rseg) {
ut_ad(!trx->rsegs.m_redo.undo); ut_ad(!trx->rsegs.m_redo.undo);
ut_ad(!trx->rsegs.m_redo.old_insert);
return; return;
} }
trx_undo_t*& undo = trx->rsegs.m_redo.undo; trx_undo_t*& undo = trx->rsegs.m_redo.undo;
trx_undo_t*& old_insert = trx->rsegs.m_redo.old_insert;
if (!undo && !old_insert) { if (!undo) {
return; return;
} }
ut_ad(!trx->read_only); ut_ad(!trx->read_only);
ut_ad(!undo || undo->rseg == rseg); ut_ad(!undo || undo->rseg == rseg);
ut_ad(!old_insert || old_insert->rseg == rseg);
mutex_enter(&rseg->mutex); mutex_enter(&rseg->mutex);
/* Assign the transaction serialisation number and add any /* Assign the transaction serialisation number and add any
undo log to the purge queue. */ undo log to the purge queue. */
trx_serialise(trx); trx_serialise(trx);
if (UNIV_LIKELY_NULL(old_insert)) {
UT_LIST_REMOVE(rseg->old_insert_list, old_insert);
trx_purge_add_undo_to_history(trx, old_insert, mtr);
}
if (undo) { if (undo) {
UT_LIST_REMOVE(rseg->undo_list, undo); UT_LIST_REMOVE(rseg->undo_list, undo);
trx_purge_add_undo_to_history(trx, undo, mtr); trx_purge_add_undo_to_history(trx, undo, mtr);
...@@ -1382,20 +1357,12 @@ trx_commit_in_memory( ...@@ -1382,20 +1357,12 @@ trx_commit_in_memory(
ut_ad(rseg->trx_ref_count > 0); ut_ad(rseg->trx_ref_count > 0);
--rseg->trx_ref_count; --rseg->trx_ref_count;
mutex_exit(&rseg->mutex); mutex_exit(&rseg->mutex);
if (trx_undo_t*& insert = trx->rsegs.m_redo.old_insert) {
ut_ad(insert->rseg == rseg);
trx_undo_commit_cleanup(insert, false);
insert = NULL;
}
} }
ut_ad(!trx->rsegs.m_redo.old_insert);
if (mtr != NULL) { if (mtr != NULL) {
if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) { if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) {
ut_ad(undo->rseg == trx->rsegs.m_noredo.rseg); ut_ad(undo->rseg == trx->rsegs.m_noredo.rseg);
trx_undo_commit_cleanup(undo, true); trx_undo_commit_cleanup(undo);
undo = NULL; undo = NULL;
} }
...@@ -1490,7 +1457,7 @@ void trx_commit_low(trx_t* trx, mtr_t* mtr) ...@@ -1490,7 +1457,7 @@ void trx_commit_low(trx_t* trx, mtr_t* mtr)
ut_ad(!mtr || mtr->is_active()); ut_ad(!mtr || mtr->is_active());
ut_d(bool aborted = trx->in_rollback ut_d(bool aborted = trx->in_rollback
&& trx->error_state == DB_DEADLOCK); && trx->error_state == DB_DEADLOCK);
ut_ad(!mtr == (aborted || !trx->has_logged_or_recovered())); ut_ad(!mtr == (aborted || !trx->has_logged()));
ut_ad(!mtr || !aborted); ut_ad(!mtr || !aborted);
/* undo_no is non-zero if we're doing the final commit. */ /* undo_no is non-zero if we're doing the final commit. */
...@@ -1577,10 +1544,7 @@ trx_commit( ...@@ -1577,10 +1544,7 @@ trx_commit(
mtr_t* mtr; mtr_t* mtr;
mtr_t local_mtr; mtr_t local_mtr;
DBUG_EXECUTE_IF("ib_trx_commit_crash_before_trx_commit_start", if (trx->has_logged()) {
DBUG_SUICIDE(););
if (trx->has_logged_or_recovered()) {
mtr = &local_mtr; mtr = &local_mtr;
mtr->start(); mtr->start();
} else { } else {
...@@ -1986,11 +1950,8 @@ trx_weight_ge( ...@@ -1986,11 +1950,8 @@ trx_weight_ge(
/** Prepare a transaction. /** Prepare a transaction.
@return log sequence number that makes the XA PREPARE durable @return log sequence number that makes the XA PREPARE durable
@retval 0 if no changes needed to be made durable */ @retval 0 if no changes needed to be made durable */
static static lsn_t trx_prepare_low(trx_t *trx)
lsn_t
trx_prepare_low(trx_t* trx)
{ {
ut_ad(!trx->rsegs.m_redo.old_insert);
ut_ad(!trx->is_recovered); ut_ad(!trx->is_recovered);
mtr_t mtr; mtr_t mtr;
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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 the terms of the GNU General Public License as published by the Free Software
...@@ -34,6 +34,7 @@ Created 3/26/1996 Heikki Tuuri ...@@ -34,6 +34,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0purge.h" #include "trx0purge.h"
#include "trx0rec.h" #include "trx0rec.h"
#include "trx0rseg.h" #include "trx0rseg.h"
#include "log.h"
/* How should the old versions in the history list be managed? /* How should the old versions in the history list be managed?
---------------------------------------------------------- ----------------------------------------------------------
...@@ -1011,13 +1012,8 @@ trx_undo_truncate_start( ...@@ -1011,13 +1012,8 @@ trx_undo_truncate_start(
} }
/** Frees an undo log segment which is not in the history list. /** Frees an undo log segment which is not in the history list.
@param[in] undo undo log @param undo temporary undo log */
@param[in] noredo whether the undo tablespace is redo logged */ static void trx_undo_seg_free(const trx_undo_t *undo)
static
void
trx_undo_seg_free(
const trx_undo_t* undo,
bool noredo)
{ {
trx_rseg_t* rseg; trx_rseg_t* rseg;
fseg_header_t* file_seg; fseg_header_t* file_seg;
...@@ -1029,16 +1025,12 @@ trx_undo_seg_free( ...@@ -1029,16 +1025,12 @@ trx_undo_seg_free(
rseg = undo->rseg; rseg = undo->rseg;
do { do {
mtr.start();
mtr_start(&mtr); mtr.set_log_mode(MTR_LOG_NO_REDO);
if (noredo) {
mtr.set_log_mode(MTR_LOG_NO_REDO);
}
mutex_enter(&(rseg->mutex)); 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), undo->hdr_page_no),
&mtr) &mtr)
+ TRX_UNDO_SEG_HDR; + TRX_UNDO_SEG_HDR;
...@@ -1069,10 +1061,11 @@ trx_undo_seg_free( ...@@ -1069,10 +1061,11 @@ trx_undo_seg_free(
@param[in] id rollback segment slot @param[in] id rollback segment slot
@param[in] page_no undo log segment page number @param[in] page_no undo log segment page number
@param[in,out] max_trx_id the largest observed transaction ID @param[in,out] max_trx_id the largest observed transaction ID
@return size of the undo log in pages */ @return the undo log
ulint @retval nullptr on error */
trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no, trx_undo_t *
trx_id_t& max_trx_id) 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; mtr_t mtr;
XID xid; XID xid;
...@@ -1082,16 +1075,56 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no, ...@@ -1082,16 +1075,56 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
mtr.start(); mtr.start();
const page_t* undo_page = trx_undo_page_get( const page_t* undo_page = trx_undo_page_get(
page_id_t(rseg->space->id, page_no), &mtr); page_id_t(rseg->space->id, page_no), &mtr);
const ulint type = mach_read_from_2( const uint16_t type = mach_read_from_2(TRX_UNDO_PAGE_HDR
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + undo_page); + TRX_UNDO_PAGE_TYPE
ut_ad(type == 0 || type == TRX_UNDO_INSERT || type == TRX_UNDO_UPDATE); + 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 uint16_t offset = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG
+ undo_page); + undo_page);
uint offset = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG if (offset < TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE ||
+ undo_page); 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 /* Read X/Open XA transaction identification if it exists, or
set it to NULL. */ set it to NULL. */
...@@ -1103,6 +1136,10 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no, ...@@ -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); 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) { if (trx_id > max_trx_id) {
max_trx_id = 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, ...@@ -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( trx_undo_t* undo = trx_undo_mem_create(
rseg, id, trx_id, &xid, page_no, offset); rseg, id, trx_id, &xid, page_no, offset);
mutex_exit(&rseg->mutex); mutex_exit(&rseg->mutex);
if (!undo) {
return undo;
}
undo->dict_operation = undo_header[TRX_UNDO_DICT_TRANS]; undo->dict_operation = undo_header[TRX_UNDO_DICT_TRANS];
undo->table_id = mach_read_from_8(undo_header + TRX_UNDO_TABLE_ID); 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->size = flst_get_len(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST
+ undo_page); + undo_page);
if (UNIV_UNLIKELY(state == TRX_UNDO_TO_FREE)) { fil_addr_t last_addr = flst_get_last(
/* This is an old-format insert_undo log segment that TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + undo_page, &mtr);
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( undo->last_page_no = last_addr.page;
TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + undo_page, undo->top_page_no = last_addr.page;
&mtr);
undo->last_page_no = last_addr.page;
undo->top_page_no = last_addr.page;
page_t* last_page = trx_undo_page_get( page_t* last_page = trx_undo_page_get(
page_id_t(rseg->space->id, undo->last_page_no), &mtr); page_id_t(rseg->space->id, undo->last_page_no), &mtr);
if (const trx_undo_rec_t* rec = trx_undo_page_get_last_rec( if (const trx_undo_rec_t* rec = trx_undo_page_get_last_rec(
last_page, page_no, offset)) { last_page, page_no, offset)) {
undo->top_offset = ulint(rec - last_page); undo->top_offset = ulint(rec - last_page);
undo->top_undo_no = trx_undo_rec_get_undo_no(rec); undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
ut_ad(!undo->empty()); ut_ad(!undo->empty());
} else { } else {
undo->top_undo_no = IB_ID_MAX; undo->top_undo_no = IB_ID_MAX;
ut_ad(undo->empty()); ut_ad(undo->empty());
}
} }
undo->state = state; undo->state = state;
if (state != TRX_UNDO_CACHED) { if (state != TRX_UNDO_CACHED) {
UT_LIST_ADD_LAST(type == TRX_UNDO_INSERT UT_LIST_ADD_LAST(rseg->undo_list, undo);
? rseg->old_insert_list
: rseg->undo_list, undo);
} else { } else {
UT_LIST_ADD_LAST(rseg->undo_cached, undo); UT_LIST_ADD_LAST(rseg->undo_cached, undo);
MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED); MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED);
} }
mtr.commit(); mtr.commit();
return undo->size; return undo;
} }
/********************************************************************//** /********************************************************************//**
...@@ -1577,22 +1598,18 @@ trx_undo_set_state_at_prepare( ...@@ -1577,22 +1598,18 @@ trx_undo_set_state_at_prepare(
return(undo_page); 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 information is not needed after a commit or rollback, therefore
the data can be discarded. the data can be discarded.
@param[in,out] undo undo log @param undo temporary undo log */
@param[in] is_temp whether this is temporary undo log */ void trx_undo_commit_cleanup(trx_undo_t *undo)
void
trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
{ {
trx_rseg_t* rseg = undo->rseg; trx_rseg_t* rseg = undo->rseg;
ut_ad(is_temp == !rseg->is_persistent()); ut_ad(rseg->space == fil_system.temp_space);
ut_ad(!is_temp || 0 == UT_LIST_GET_LEN(rseg->old_insert_list));
mutex_enter(&rseg->mutex); mutex_enter(&rseg->mutex);
UT_LIST_REMOVE(is_temp ? rseg->undo_list : rseg->old_insert_list, UT_LIST_REMOVE(rseg->undo_list, undo);
undo);
if (undo->state == TRX_UNDO_CACHED) { if (undo->state == TRX_UNDO_CACHED) {
UT_LIST_ADD_FIRST(rseg->undo_cached, undo); UT_LIST_ADD_FIRST(rseg->undo_cached, undo);
...@@ -1602,7 +1619,7 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp) ...@@ -1602,7 +1619,7 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
/* Delete first the undo log segment in the file */ /* Delete first the undo log segment in the file */
mutex_exit(&rseg->mutex); mutex_exit(&rseg->mutex);
trx_undo_seg_free(undo, is_temp); trx_undo_seg_free(undo);
mutex_enter(&rseg->mutex); mutex_enter(&rseg->mutex);
ut_ad(rseg->curr_size > undo->size); ut_ad(rseg->curr_size > undo->size);
...@@ -1615,15 +1632,13 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp) ...@@ -1615,15 +1632,13 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
} }
/** At shutdown, frees the undo logs of a transaction. */ /** At shutdown, frees the undo logs of a transaction. */
void void trx_undo_free_at_shutdown(trx_t *trx)
trx_undo_free_at_shutdown(trx_t *trx)
{ {
if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) { if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) {
switch (undo->state) { switch (undo->state) {
case TRX_UNDO_PREPARED: case TRX_UNDO_PREPARED:
break; break;
case TRX_UNDO_CACHED: case TRX_UNDO_CACHED:
case TRX_UNDO_TO_FREE:
case TRX_UNDO_TO_PURGE: case TRX_UNDO_TO_PURGE:
ut_ad(trx_state_eq(trx, ut_ad(trx_state_eq(trx,
TRX_STATE_COMMITTED_IN_MEMORY)); TRX_STATE_COMMITTED_IN_MEMORY));
...@@ -1644,34 +1659,6 @@ trx_undo_free_at_shutdown(trx_t *trx) ...@@ -1644,34 +1659,6 @@ trx_undo_free_at_shutdown(trx_t *trx)
ut_free(undo); ut_free(undo);
undo = NULL; 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) { if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) {
ut_a(undo->state == TRX_UNDO_PREPARED); ut_a(undo->state == TRX_UNDO_PREPARED);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment