summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2018-01-31 10:24:19 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2018-01-31 10:24:19 +0200
commitc7d0448797a2013079c3e0b7ca97f7bdc1138696 (patch)
tree32229a9a3f46ebafef475cc45757ca1df4368c0b /storage
parentbb441ca4ade0684603c3c5b8cd999f25def62105 (diff)
downloadmariadb-git-c7d0448797a2013079c3e0b7ca97f7bdc1138696.tar.gz
MDEV-15132 Avoid accessing the TRX_SYS page
InnoDB maintains an internal persistent sequence of transaction identifiers. This sequence is used for assigning both transaction start identifiers (DB_TRX_ID=trx->id) and end identifiers (trx->no) as well as end identifiers for the mysql.transaction_registry table that was introduced in MDEV-12894. TRX_SYS_TRX_ID_WRITE_MARGIN: Remove. After this many updates of the sequence we used to update the TRX_SYS page. We can avoid accessing the TRX_SYS page if we modify the InnoDB startup so that resurrecting the sequence from other pages of the transaction system. TRX_SYS_TRX_ID_STORE: Deprecate. The field only exists for the purpose of upgrading from an earlier version of MySQL or MariaDB. Starting with this fix, MariaDB will rely on the fields TRX_UNDO_TRX_ID, TRX_UNDO_TRX_NO in the undo log header page of each non-committed transaction, and on the new field TRX_RSEG_MAX_TRX_ID in rollback segment header pages. Because of this change, setting innodb_force_recovery=5 or 6 may cause the system to recover with trx_sys.get_max_trx_id()==0. We must adjust checks for invalid DB_TRX_ID and PAGE_MAX_TRX_ID accordingly. We will change the startup and shutdown messages to display the trx_sys.get_max_trx_id() in addition to the log sequence number. trx_sys_t::flush_max_trx_id(): Remove. trx_undo_mem_create_at_db_start(), trx_undo_lists_init(): Add an output parameter max_trx_id, to be updated from TRX_UNDO_TRX_ID, TRX_UNDO_TRX_NO. TRX_RSEG_MAX_TRX_ID: New field, for persisting trx_sys.get_max_trx_id() at the time of the latest transaction commit. Startup is not reading the undo log pages of committed transactions. We want to avoid additional page accesses on startup, as well as trouble when all undo logs have been emptied. On startup, we will simply determine the maximum value from all pages that are being read anyway. TRX_RSEG_FORMAT: Redefined from TRX_RSEG_MAX_SIZE. Old versions of InnoDB wrote uninitialized garbage to unused data fields. Because of this, we cannot simply introduce a new field in the rollback segment pages and expect it to be always zero, like it would if the database was created by a recent enough InnoDB version. Luckily, it looks like the field TRX_RSEG_MAX_SIZE was always written as 0xfffffffe. We will indicate a new subformat of the page by writing 0 to this field. This has the nice side effect that after a downgrade to older versions of InnoDB, transactions should fail to allocate any undo log, that is, writes will be blocked. So, there is no problem of getting corrupted transaction identifiers after downgrading. trx_rseg_t::max_size: Remove. trx_rseg_header_create(): Remove the parameter max_size=ULINT_MAX. trx_purge_add_undo_to_history(): Update TRX_RSEG_MAX_SIZE (and TRX_RSEG_FORMAT if needed). This is invoked on transaction commit. trx_rseg_mem_restore(): If TRX_RSEG_FORMAT contains 0, read TRX_RSEG_MAX_SIZE. trx_rseg_array_init(): Invoke trx_sys.init_max_trx_id(max_trx_id + 1) where max_trx_id was the maximum that was encountered in the rollback segment pages and the undo log pages of recovered active, XA PREPARE, or some committed transactions. (See trx_purge_add_undo_to_history() which invokes trx_rsegf_set_nth_undo(..., FIL_NULL, ...); not all committed transactions will be immediately detached from the rollback segment header.)
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/include/trx0rseg.h12
-rw-r--r--storage/innobase/include/trx0sys.h45
-rw-r--r--storage/innobase/include/trx0undo.h10
-rw-r--r--storage/innobase/lock/lock0lock.cc3
-rw-r--r--storage/innobase/page/page0page.cc13
-rw-r--r--storage/innobase/srv/srv0start.cc11
-rw-r--r--storage/innobase/trx/trx0purge.cc18
-rw-r--r--storage/innobase/trx/trx0rseg.cc52
-rw-r--r--storage/innobase/trx/trx0sys.cc24
-rw-r--r--storage/innobase/trx/trx0trx.cc5
-rw-r--r--storage/innobase/trx/trx0undo.cc77
11 files changed, 104 insertions, 166 deletions
diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h
index f77d0fe40bd..73bfb4ac50a 100644
--- a/storage/innobase/include/trx0rseg.h
+++ b/storage/innobase/include/trx0rseg.h
@@ -77,7 +77,6 @@ trx_rsegf_undo_find_free(const trx_rsegf_t* rsegf);
This function is called only when a new rollback segment is created in
the database.
@param[in] space space id
-@param[in] max_size max size in pages
@param[in] rseg_id rollback segment identifier
@param[in,out] sys_header the TRX_SYS page (NULL for temporary rseg)
@param[in,out] mtr mini-transaction
@@ -85,7 +84,6 @@ the database.
ulint
trx_rseg_header_create(
ulint space,
- ulint max_size,
ulint rseg_id,
buf_block_t* sys_header,
mtr_t* mtr);
@@ -144,9 +142,6 @@ struct trx_rseg_t {
/** page number of the rollback segment header */
ulint page_no;
- /** maximum allowed size in pages */
- ulint max_size;
-
/** current size in pages */
ulint curr_size;
@@ -217,8 +212,8 @@ struct trx_rseg_t {
/* Transaction rollback segment header */
/*-------------------------------------------------------------*/
-#define TRX_RSEG_MAX_SIZE 0 /* Maximum allowed size for rollback
- segment in pages */
+#define TRX_RSEG_FORMAT 0 /* -2 = pre-MariaDB 10.3.5 format;
+ 0=MariaDB 10.3.5 or later */
#define TRX_RSEG_HISTORY_SIZE 4 /* Number of file pages occupied
by the logs in the history list */
#define TRX_RSEG_HISTORY 8 /* The update undo logs for committed
@@ -228,6 +223,9 @@ struct trx_rseg_t {
this page is placed */
#define TRX_RSEG_UNDO_SLOTS (8 + FLST_BASE_NODE_SIZE + FSEG_HEADER_SIZE)
/* Undo log segment slots */
+/** Maximum transaction ID (valid only if TRX_RSEG_FORMAT is 0) */
+#define TRX_RSEG_MAX_TRX_ID (TRX_RSEG_UNDO_SLOTS + TRX_RSEG_N_SLOTS \
+ * TRX_RSEG_SLOT_SIZE)
/*-------------------------------------------------------------*/
/** Read the page number of an undo log slot.
diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h
index 41ce37e81b9..e7b0e75de10 100644
--- a/storage/innobase/include/trx0sys.h
+++ b/storage/innobase/include/trx0sys.h
@@ -175,18 +175,13 @@ trx_sys_create_rsegs();
/** Transaction system header */
/*------------------------------------------------------------- @{ */
-#define TRX_SYS_TRX_ID_STORE 0 /*!< the maximum trx id or trx
- number modulo
- TRX_SYS_TRX_ID_UPDATE_MARGIN
- written to a file page by any
- transaction; the assignment of
- transaction ids continues from
- this number rounded up by
- TRX_SYS_TRX_ID_UPDATE_MARGIN
- plus
- TRX_SYS_TRX_ID_UPDATE_MARGIN
- when the database is
- started */
+/** In old versions of InnoDB, this persisted the value of
+trx_sys.get_max_trx_id(). Starting with MariaDB 10.3.5,
+the field TRX_RSEG_MAX_TRX_ID in rollback segment header pages
+and the fields TRX_UNDO_TRX_ID, TRX_UNDO_TRX_NO in undo log pages
+are used instead. The field only exists for the purpose of upgrading
+from older MySQL or MariaDB versions. */
+#define TRX_SYS_TRX_ID_STORE 0
#define TRX_SYS_FSEG_HEADER 8 /*!< segment header for the
tablespace segment the trx
system is created into */
@@ -379,11 +374,6 @@ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID. */
/** Size of the doublewrite block in pages */
#define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE
-
-/** When a trx id which is zero modulo this number (which must be a power of
-two) is assigned, the field TRX_SYS_TRX_ID_STORE on the transaction system
-page is updated */
-#define TRX_SYS_TRX_ID_WRITE_MARGIN ((trx_id_t) 256)
/* @} */
trx_t* current_trx();
@@ -925,26 +915,14 @@ public:
/**
Allocates a new transaction id.
-
- VERY important: after the database is started, m_max_trx_id value is
- divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the following if
- will evaluate to TRUE when this function is first time called,
- and the value for trx id will be written to disk-based header!
- Thus trx id values will not overlap when the database is
- repeatedly started!
-
@return new, allocated trx id
*/
trx_id_t get_new_trx_id()
{
ut_ad(mutex_own(&mutex));
- trx_id_t id= static_cast<trx_id_t>(my_atomic_add64_explicit(
+ return static_cast<trx_id_t>(my_atomic_add64_explicit(
reinterpret_cast<int64*>(&m_max_trx_id), 1, MY_MEMORY_ORDER_RELAXED));
-
- if (UNIV_UNLIKELY(!(id % TRX_SYS_TRX_ID_WRITE_MARGIN)))
- flush_max_trx_id();
- return(id);
}
@@ -1004,13 +982,6 @@ private:
}
return 0;
}
-
-
- /**
- Writes the value of m_max_trx_id to the file based trx system header.
- */
-
- void flush_max_trx_id();
};
diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h
index c129bad3dcb..aeffbf1a65e 100644
--- a/storage/innobase/include/trx0undo.h
+++ b/storage/innobase/include/trx0undo.h
@@ -318,12 +318,14 @@ trx_undo_parse_page_header(
page_t* page,
mtr_t* mtr);
/** Read an undo log when starting up the database.
-@param[in,out] rseg rollback segment
-@param[in] id rollback segment slot
-@param[in] page_no undo log segment page number
+@param[in,out] rseg rollback segment
+@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_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
+ trx_id_t& max_trx_id);
/************************************************************************
Frees an undo log memory copy. */
void
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 792fb8ffc8b..d8d01f88a05 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -383,8 +383,9 @@ lock_check_trx_id_sanity(
ut_ad(!rec_is_default_row(rec, index));
trx_id_t max_trx_id = trx_sys.get_max_trx_id();
+ ut_ad(max_trx_id || srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN);
- if (trx_id >= max_trx_id) {
+ if (max_trx_id && trx_id >= max_trx_id) {
lock_report_trx_id_insanity(
trx_id, rec, index, offsets, max_trx_id);
return false;
diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc
index e8df8d29020..e3e95bea937 100644
--- a/storage/innobase/page/page0page.cc
+++ b/storage/innobase/page/page0page.cc
@@ -2,7 +2,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 2017, 2018, 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
@@ -2427,18 +2427,19 @@ page_validate(
same temp-table in parallel.
max_trx_id is ignored for temp tables because it not required
for MVCC. */
- if (dict_index_is_sec_or_ibuf(index)
- && !dict_table_is_temporary(index->table)
- && page_is_leaf(page)
- && !page_is_empty(page)) {
+ if (!page_is_leaf(page) || page_is_empty(page)
+ || !dict_index_is_sec_or_ibuf(index)
+ || index->table->is_temporary()) {
+ } else if (trx_id_t sys_max_trx_id = trx_sys.get_max_trx_id()) {
trx_id_t max_trx_id = page_get_max_trx_id(page);
- trx_id_t sys_max_trx_id = trx_sys.get_max_trx_id();
if (max_trx_id == 0 || max_trx_id > sys_max_trx_id) {
ib::error() << "PAGE_MAX_TRX_ID out of bounds: "
<< max_trx_id << ", " << sys_max_trx_id;
goto func_exit2;
}
+ } else {
+ ut_ad(srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN);
}
heap = mem_heap_create(UNIV_PAGE_SIZE + 200);
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 723e751c6dc..e45032955d7 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -1088,8 +1088,7 @@ srv_undo_tablespaces_init(bool create_new_db)
if (trx_sysf_rseg_get_space(sys_header, i)
== *it) {
trx_rseg_header_create(
- *it, ULINT_MAX, i,
- sys_header, &mtr);
+ *it, i, sys_header, &mtr);
}
}
@@ -2679,8 +2678,9 @@ files_checked:
if (srv_print_verbose_log) {
ib::info() << INNODB_VERSION_STR
- << " started; log sequence number "
- << srv_start_lsn;
+ << " started; log sequence number "
+ << srv_start_lsn
+ << "; transaction id " << trx_sys.get_max_trx_id();
}
if (srv_force_recovery > 0) {
@@ -2929,7 +2929,8 @@ innodb_shutdown()
if (srv_was_started && srv_print_verbose_log) {
ib::info() << "Shutdown completed; log sequence number "
- << srv_shutdown_lsn;
+ << srv_shutdown_lsn
+ << "; transaction id " << trx_sys.get_max_trx_id();
}
srv_start_state = SRV_START_STATE_NONE;
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index 4ac3585c939..a7c0f350217 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -277,10 +277,28 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr)
ut_ad(undo->size == flst_get_len(
seg_header + TRX_UNDO_PAGE_LIST));
+ byte* rseg_format = rseg_header + TRX_RSEG_FORMAT;
+ if (UNIV_UNLIKELY(mach_read_from_4(rseg_format))) {
+ /* This database must have been upgraded from
+ before MariaDB 10.3.5. */
+ mlog_write_ulint(rseg_format, 0, MLOG_4BYTES, mtr);
+ /* Clear also possible garbage at the end of
+ the page. Old InnoDB versions did not initialize
+ unused parts of pages. */
+ ut_ad(page_offset(rseg_header) == TRX_RSEG);
+ byte* b = rseg_header + TRX_RSEG_MAX_TRX_ID + 8;
+ ulint len = UNIV_PAGE_SIZE
+ - (FIL_PAGE_DATA_END
+ + TRX_RSEG + TRX_RSEG_MAX_TRX_ID + 8);
+ memset(b, 0, len);
+ mlog_log_string(b, len, mtr);
+ }
mlog_write_ulint(
rseg_header + TRX_RSEG_HISTORY_SIZE,
hist_size + undo->size, MLOG_4BYTES, mtr);
+ mlog_write_ull(rseg_header + TRX_RSEG_MAX_TRX_ID,
+ trx_sys.get_max_trx_id(), mtr);
}
/* Before any transaction-generating background threads or the
diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc
index a9dfae5abe9..8d4a9a89689 100644
--- a/storage/innobase/trx/trx0rseg.cc
+++ b/storage/innobase/trx/trx0rseg.cc
@@ -38,7 +38,6 @@ Created 3/26/1996 Heikki Tuuri
This function is called only when a new rollback segment is created in
the database.
@param[in] space space id
-@param[in] max_size max size in pages
@param[in] rseg_id rollback segment identifier
@param[in,out] sys_header the TRX_SYS page (NULL for temporary rseg)
@param[in,out] mtr mini-transaction
@@ -46,7 +45,6 @@ the database.
ulint
trx_rseg_header_create(
ulint space,
- ulint max_size,
ulint rseg_id,
buf_block_t* sys_header,
mtr_t* mtr)
@@ -76,9 +74,7 @@ trx_rseg_header_create(
/* Get the rollback segment file page */
rsegf = trx_rsegf_get_new(space, page_no, mtr);
- /* Initialize max size field */
- mlog_write_ulint(rsegf + TRX_RSEG_MAX_SIZE, max_size,
- MLOG_4BYTES, mtr);
+ mlog_write_ulint(rsegf + TRX_RSEG_FORMAT, 0, MLOG_4BYTES, mtr);
/* Initialize the history list */
@@ -155,7 +151,6 @@ trx_rseg_mem_create(ulint id, ulint space, ulint page_no)
rseg->page_no = page_no;
rseg->last_page_no = FIL_NULL;
rseg->curr_size = 1;
- rseg->max_size = ULINT_UNDEFINED;
mutex_create(rseg->is_persistent()
? LATCH_ID_REDO_RSEG : LATCH_ID_NOREDO_RSEG,
@@ -170,13 +165,13 @@ trx_rseg_mem_create(ulint id, ulint space, ulint page_no)
/** Read the undo log lists.
@param[in,out] rseg rollback segment
+@param[in,out] max_trx_id maximum observed transaction identifier
@param[in] rseg_header rollback segment header
-@param[in,out] mtr mini-transaction
@return the combined size of undo log segments in pages */
static
ulint
-trx_undo_lists_init(trx_rseg_t* rseg, const trx_rsegf_t* rseg_header,
- mtr_t* mtr)
+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);
@@ -186,7 +181,7 @@ trx_undo_lists_init(trx_rseg_t* rseg, const trx_rsegf_t* rseg_header,
ulint page_no = trx_rsegf_get_nth_undo(rseg_header, i);
if (page_no != FIL_NULL) {
size += trx_undo_mem_create_at_db_start(
- rseg, i, page_no);
+ rseg, i, page_no, max_trx_id);
MONITOR_INC(MONITOR_NUM_UNDO_SLOT_USED);
}
}
@@ -204,12 +199,18 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, trx_id_t& max_trx_id, mtr_t* mtr)
{
const trx_rsegf_t* rseg_header = trx_rsegf_get_new(
rseg->space, rseg->page_no, mtr);
- rseg->max_size = mach_read_from_4(rseg_header + TRX_RSEG_MAX_SIZE);
+ if (mach_read_from_4(rseg_header + TRX_RSEG_FORMAT) == 0) {
+ trx_id_t id = mach_read_from_8(rseg_header
+ + TRX_RSEG_MAX_TRX_ID);
+ if (id > max_trx_id) {
+ max_trx_id = id;
+ }
+ }
/* Initialize the undo log lists according to the rseg header */
rseg->curr_size = mach_read_from_4(rseg_header + TRX_RSEG_HISTORY_SIZE)
- + 1 + trx_undo_lists_init(rseg, rseg_header, mtr);
+ + 1 + trx_undo_lists_init(rseg, max_trx_id, rseg_header);
if (ulint len = flst_get_len(rseg_header + TRX_RSEG_HISTORY)) {
my_atomic_addlint(&trx_sys.rseg_history_len, len);
@@ -262,22 +263,9 @@ trx_rseg_array_init()
mtr.start();
if (const buf_block_t* sys = trx_sysf_get(&mtr, false)) {
if (rseg_id == 0) {
- /* VERY important: after the database
- is started, max_trx_id value is
- divisible by TRX_SYS_TRX_ID_WRITE_MARGIN,
- and the first call of
- trx_sys.get_new_trx_id() will invoke
- flush_max_trx_id()! Thus trx id values
- will not overlap when the database is
- repeatedly started! */
-
- max_trx_id = 2 * TRX_SYS_TRX_ID_WRITE_MARGIN
- + ut_uint64_align_up(
- mach_read_from_8(
- TRX_SYS
- + TRX_SYS_TRX_ID_STORE
- + sys->frame),
- TRX_SYS_TRX_ID_WRITE_MARGIN);
+ max_trx_id = mach_read_from_8(
+ TRX_SYS + TRX_SYS_TRX_ID_STORE
+ + sys->frame);
}
const uint32_t page_no = trx_sysf_rseg_get_page_no(
sys, rseg_id);
@@ -297,7 +285,7 @@ trx_rseg_array_init()
mtr.commit();
}
- trx_sys.init_max_trx_id(max_trx_id);
+ trx_sys.init_max_trx_id(max_trx_id + 1);
}
/** Create a persistent rollback segment.
@@ -324,8 +312,8 @@ trx_rseg_create(ulint space_id)
ulint rseg_id = trx_sys_rseg_find_free(sys_header);
ulint page_no = rseg_id == ULINT_UNDEFINED
? FIL_NULL
- : trx_rseg_header_create(space_id, ULINT_MAX,
- rseg_id, sys_header, &mtr);
+ : trx_rseg_header_create(space_id, rseg_id, sys_header,
+ &mtr);
if (page_no != FIL_NULL) {
ut_ad(trx_sysf_rseg_get_space(sys_header, rseg_id)
== space_id);
@@ -358,7 +346,7 @@ trx_temp_rseg_create()
ut_ad(space->purpose == FIL_TYPE_TEMPORARY);
ulint page_no = trx_rseg_header_create(
- SRV_TMP_SPACE_ID, ULINT_MAX, i, NULL, &mtr);
+ SRV_TMP_SPACE_ID, i, NULL, &mtr);
trx_rseg_t* rseg = trx_rseg_mem_create(
i, SRV_TMP_SPACE_ID, page_no);
ut_ad(!rseg->is_persistent());
diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
index 438864f2093..08f3d6be5a6 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -90,24 +90,6 @@ uint trx_rseg_n_slots_debug = 0;
#endif
-/**
- Writes the value of m_max_trx_id to the file based trx system header.
-*/
-
-void trx_sys_t::flush_max_trx_id()
-{
- ut_ad(trx_sys.mutex.is_owned());
- if (!srv_read_only_mode)
- {
- mtr_t mtr;
- mtr.start();
- mlog_write_ull(TRX_SYS + TRX_SYS_TRX_ID_STORE + trx_sysf_get(&mtr)->frame,
- trx_sys.get_max_trx_id(), &mtr);
- mtr.commit();
- }
-}
-
-
/*****************************************************************//**
Updates the offset information about the end of the MySQL binlog entry
which corresponds to the transaction just being committed. In a MySQL
@@ -388,9 +370,6 @@ trx_sysf_create(
mlog_write_ulint(page + TRX_SYS_DOUBLEWRITE
+ TRX_SYS_DOUBLEWRITE_MAGIC, 0, MLOG_4BYTES, mtr);
- /* Start counting transaction ids from number 1 up */
- mach_write_to_8(TRX_SYS + TRX_SYS_TRX_ID_STORE + page, 1);
-
/* Reset the rollback segment slots. Old versions of InnoDB
(before MySQL 5.5) define TRX_SYS_N_RSEGS as 256 and expect
that the whole array is initialized. */
@@ -408,8 +387,7 @@ trx_sysf_create(
/* Create the first rollback segment in the SYSTEM tablespace */
slot_no = trx_sys_rseg_find_free(block);
- page_no = trx_rseg_header_create(TRX_SYS_SPACE,
- ULINT_MAX, slot_no, block, mtr);
+ page_no = trx_rseg_header_create(TRX_SYS_SPACE, slot_no, block, mtr);
ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID);
ut_a(page_no == FSP_FIRST_RSEG_PAGE_NO);
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 9334274cb89..6dfefec8e21 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -900,12 +900,13 @@ trx_lists_init_at_db_start()
ut_ad(!purge_sys);
ut_ad(!trx_dummy_sess);
+ trx_dummy_sess = sess_open();
+ purge_sys = UT_NEW_NOKEY(purge_sys_t());
+
if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
return;
}
- trx_dummy_sess = sess_open();
- purge_sys = UT_NEW_NOKEY(purge_sys_t());
trx_rseg_array_init();
/* Look from the rollback segments if there exist undo logs for
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index 7a9c7202430..2e6078bd2f6 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -780,9 +780,6 @@ trx_undo_add_page(trx_t* trx, trx_undo_t* undo, mtr_t* mtr)
counterpart of the tree latch, which is the rseg mutex. */
mutex_enter(&rseg->mutex);
- if (rseg->curr_size == rseg->max_size) {
- goto func_exit;
- }
header_page = trx_undo_page_get(
page_id_t(undo->space, undo->hdr_page_no), mtr);
@@ -893,34 +890,6 @@ trx_undo_free_last_page(trx_undo_t* undo, mtr_t* mtr)
undo->size--;
}
-/** Empties an undo log header page of undo records for that undo log.
-Other undo logs may still have records on that page, if it is an update
-undo log.
-@param[in] space space
-@param[in] hdr_page_no header page number
-@param[in] hdr_offset header offset
-@param[in,out] mtr mini-transaction */
-static
-void
-trx_undo_empty_header_page(
- ulint space,
- ulint hdr_page_no,
- ulint hdr_offset,
- mtr_t* mtr)
-{
- page_t* header_page;
- trx_ulogf_t* log_hdr;
- ulint end;
-
- header_page = trx_undo_page_get(page_id_t(space, hdr_page_no), mtr);
-
- log_hdr = header_page + hdr_offset;
-
- end = trx_undo_page_get_end(header_page, hdr_page_no, hdr_offset);
-
- mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);
-}
-
/** Truncate the tail of an undo log during rollback.
@param[in,out] undo undo log
@param[in] limit all undo logs after this limit will be discarded
@@ -1032,9 +1001,16 @@ loop:
page_no = page_get_page_no(undo_page);
if (page_no == hdr_page_no) {
- trx_undo_empty_header_page(rseg->space,
- hdr_page_no, hdr_offset,
- &mtr);
+ uint16_t end = mach_read_from_2(hdr_offset + TRX_UNDO_NEXT_LOG
+ + undo_page);
+ if (end == 0) {
+ end = mach_read_from_2(TRX_UNDO_PAGE_HDR
+ + TRX_UNDO_PAGE_FREE
+ + undo_page);
+ }
+
+ mlog_write_ulint(undo_page + hdr_offset + TRX_UNDO_LOG_START,
+ end, MLOG_2BYTES, &mtr);
} else {
trx_undo_free_page(rseg, TRUE, rseg->space, hdr_page_no,
page_no, &mtr);
@@ -1100,12 +1076,14 @@ trx_undo_seg_free(
/*========== UNDO LOG MEMORY COPY INITIALIZATION =====================*/
/** Read an undo log when starting up the database.
-@param[in,out] rseg rollback segment
-@param[in] id rollback segment slot
-@param[in] page_no undo log segment page number
+@param[in,out] rseg rollback segment
+@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_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
+ trx_id_t& max_trx_id)
{
mtr_t mtr;
XID xid;
@@ -1135,10 +1113,19 @@ trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no)
xid.null();
}
+ trx_id_t trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_NO);
+ if (trx_id > max_trx_id) {
+ max_trx_id = trx_id;
+ }
+
+ trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
+ if (trx_id > max_trx_id) {
+ max_trx_id = trx_id;
+ }
+
mutex_enter(&rseg->mutex);
trx_undo_t* undo = trx_undo_mem_create(
- rseg, id, mach_read_from_8(undo_header + TRX_UNDO_TRX_ID),
- &xid, page_no, offset);
+ rseg, id, trx_id, &xid, page_no, offset);
mutex_exit(&rseg->mutex);
undo->dict_operation = undo_header[TRX_UNDO_DICT_TRANS];
@@ -1293,11 +1280,6 @@ trx_undo_create(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
ut_ad(mutex_own(&(rseg->mutex)));
- if (rseg->curr_size == rseg->max_size) {
- *err = DB_OUT_OF_FILE_SPACE;
- return NULL;
- }
-
buf_block_t* block = trx_undo_seg_create(
trx_rsegf_get(rseg->space, rseg->page_no, mtr), &id, err, mtr);
@@ -1754,7 +1736,7 @@ trx_undo_truncate_tablespace(
trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i);
rseg->page_no = trx_rseg_header_create(
- space_id, ULINT_MAX, rseg->id, sys_header, &mtr);
+ space_id, rseg->id, sys_header, &mtr);
rseg_header = trx_rsegf_get_new(space_id, rseg->page_no, &mtr);
@@ -1777,9 +1759,6 @@ trx_undo_truncate_tablespace(
UT_LIST_INIT(rseg->undo_list, &trx_undo_t::undo_list);
UT_LIST_INIT(rseg->undo_cached, &trx_undo_t::undo_list);
- rseg->max_size = mtr_read_ulint(
- rseg_header + TRX_RSEG_MAX_SIZE, MLOG_4BYTES, &mtr);
-
/* Initialize the undo log lists according to the rseg header */
rseg->curr_size = mtr_read_ulint(
rseg_header + TRX_RSEG_HISTORY_SIZE, MLOG_4BYTES, &mtr)