2012-08-01 17:27:34 +03:00
|
|
|
/*****************************************************************************
|
|
|
|
|
2016-06-21 14:21:03 +02:00
|
|
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
2021-01-11 10:35:06 +02:00
|
|
|
Copyright (c) 2015, 2021, MariaDB Corporation.
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
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
|
|
|
|
Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
2019-05-11 19:25:02 +03:00
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/**************************************************//**
|
|
|
|
@file trx/trx0trx.cc
|
|
|
|
The transaction
|
|
|
|
|
|
|
|
Created 3/26/1996 Heikki Tuuri
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#include "trx0trx.h"
|
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
#ifdef WITH_WSREP
|
2014-09-27 22:29:10 +02:00
|
|
|
#include <mysql/service_wsrep.h>
|
2016-09-06 09:43:16 +03:00
|
|
|
#endif
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
#include <mysql/service_thd_error_context.h>
|
2016-09-06 09:43:16 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
#include "btr0sea.h"
|
|
|
|
#include "lock0lock.h"
|
2012-08-01 17:27:34 +03:00
|
|
|
#include "log0log.h"
|
2016-08-12 11:17:45 +03:00
|
|
|
#include "os0proc.h"
|
2012-08-01 17:27:34 +03:00
|
|
|
#include "que0que.h"
|
2016-08-12 11:17:45 +03:00
|
|
|
#include "srv0mon.h"
|
2012-08-01 17:27:34 +03:00
|
|
|
#include "srv0srv.h"
|
|
|
|
#include "srv0start.h"
|
|
|
|
#include "trx0purge.h"
|
2016-08-12 11:17:45 +03:00
|
|
|
#include "trx0rec.h"
|
|
|
|
#include "trx0roll.h"
|
|
|
|
#include "trx0rseg.h"
|
|
|
|
#include "trx0undo.h"
|
|
|
|
#include "trx0xa.h"
|
|
|
|
#include "ut0pool.h"
|
2012-08-01 17:27:34 +03:00
|
|
|
#include "ut0vec.h"
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
#include <set>
|
|
|
|
#include <new>
|
|
|
|
|
2017-11-22 22:21:37 +02:00
|
|
|
/** The bit pattern corresponding to TRX_ID_MAX */
|
2017-12-18 21:01:44 +03:00
|
|
|
const byte trx_id_max_bytes[8] = {
|
2017-12-18 19:03:51 +03:00
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
2017-11-22 22:21:37 +02:00
|
|
|
};
|
|
|
|
|
2017-12-18 19:03:51 +03:00
|
|
|
/** The bit pattern corresponding to max timestamp */
|
2017-12-18 21:01:44 +03:00
|
|
|
const byte timestamp_max_bytes[7] = {
|
2017-12-18 19:03:51 +03:00
|
|
|
0x7f, 0xff, 0xff, 0xff, 0x0f, 0x42, 0x3f
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
static const ulint MAX_DETAILED_ERROR_LEN = 256;
|
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
/** Set of table_id */
|
2016-08-12 11:17:45 +03:00
|
|
|
typedef std::set<
|
|
|
|
table_id_t,
|
|
|
|
std::less<table_id_t>,
|
|
|
|
ut_allocator<table_id_t> > table_id_set;
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/*************************************************************//**
|
|
|
|
Set detailed error message for the transaction. */
|
|
|
|
void
|
|
|
|
trx_set_detailed_error(
|
|
|
|
/*===================*/
|
|
|
|
trx_t* trx, /*!< in: transaction struct */
|
|
|
|
const char* msg) /*!< in: detailed error message */
|
|
|
|
{
|
2019-10-30 06:42:51 +02:00
|
|
|
strncpy(trx->detailed_error, msg, MAX_DETAILED_ERROR_LEN - 1);
|
|
|
|
trx->detailed_error[MAX_DETAILED_ERROR_LEN - 1] = '\0';
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************//**
|
|
|
|
Set detailed error message for the transaction from a file. Note that the
|
|
|
|
file is rewinded before reading from it. */
|
|
|
|
void
|
|
|
|
trx_set_detailed_error_from_file(
|
|
|
|
/*=============================*/
|
|
|
|
trx_t* trx, /*!< in: transaction struct */
|
|
|
|
FILE* file) /*!< in: file to read message from */
|
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
os_file_read_string(file, trx->detailed_error, MAX_DETAILED_ERROR_LEN);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/********************************************************************//**
|
|
|
|
Initialize transaction object.
|
|
|
|
@param trx trx to initialize */
|
2012-08-01 17:27:34 +03:00
|
|
|
static
|
2016-08-12 11:17:45 +03:00
|
|
|
void
|
|
|
|
trx_init(
|
|
|
|
/*=====*/
|
|
|
|
trx_t* trx)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->no = TRX_ID_MAX;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2018-03-11 23:34:23 +02:00
|
|
|
trx->state = TRX_STATE_NOT_STARTED;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->is_recovered = false;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->op_info = "";
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2020-08-21 18:22:55 +03:00
|
|
|
trx->active_commit_ordered = false;
|
2016-09-06 09:43:16 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->isolation_level = TRX_ISO_REPEATABLE_READ;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->check_foreigns = true;
|
|
|
|
|
|
|
|
trx->check_unique_secondary = true;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->lock.n_rec_locks = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx->dict_operation = TRX_DICT_OP_NONE;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->table_id = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx->error_state = DB_SUCCESS;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->error_key_num = ULINT_UNDEFINED;
|
|
|
|
|
|
|
|
trx->undo_no = 0;
|
|
|
|
|
|
|
|
trx->rsegs.m_redo.rseg = NULL;
|
|
|
|
|
|
|
|
trx->rsegs.m_noredo.rseg = NULL;
|
|
|
|
|
|
|
|
trx->read_only = false;
|
|
|
|
|
|
|
|
trx->auto_commit = false;
|
|
|
|
|
|
|
|
trx->will_lock = 0;
|
|
|
|
|
|
|
|
trx->ddl = false;
|
|
|
|
|
|
|
|
trx->internal = false;
|
|
|
|
|
|
|
|
ut_d(trx->start_file = 0);
|
|
|
|
|
|
|
|
ut_d(trx->start_line = 0);
|
|
|
|
|
|
|
|
trx->magic_n = TRX_MAGIC_N;
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->lock.que_state = TRX_QUE_RUNNING;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->last_sql_stat_start.least_undo_no = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2018-01-20 17:45:42 +04:00
|
|
|
ut_ad(!trx->read_view.is_open());
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->lock.rec_cached = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->lock.table_cached = 0;
|
MDEV-23851 BF-BF Conflict issue because of UK GAP locks
Some DML operations on tables having unique secondary keys cause scanning
in the secondary index, for instance to find potential unique key violations
in the seconday index. This scanning may involve GAP locking in the index.
As this locking happens also when applying replication events in high priority
applier threads, there is a probabality for lock conflicts between two wsrep
high priority threads.
This PR avoids lock conflicts of high priority wsrep threads, which do
secondary index scanning e.g. for duplicate key detection.
The actual fix is the patch in sql_class.cc:thd_need_ordering_with(), where
we allow relaxed GAP locking protocol between wsrep high priority threads.
wsrep high priority threads (replication appliers, replayers and TOI processors)
are ordered by the replication provider, and they will not need serializability
support gained by secondary index GAP locks.
PR contains also a mtr test, which exercises a scenario where two replication
applier threads have a false positive conflict in GAP of unique secondary index.
The conflicting local committing transaction has to replay, and the test verifies
also that the replaying phase will not conflict with the latter repllication applier.
Commit also contains new test scenario for galera.galera_UK_conflict.test,
where replayer starts applying after a slave applier thread, with later seqno,
has advanced to commit phase. The applier and replayer have false positive GAP
lock conflict on secondary unique index, and replayer should ignore this.
This test scenario caused crash with earlier version in this PR, and to fix this,
the secondary index uniquenes checking has been relaxed even further.
Now innodb trx_t structure has new member: bool wsrep_UK_scan, which is set to
true, when high priority thread is performing unique secondary index scanning.
The member trx_t::wsrep_UK_scan is defined inside WITH_WSREP directive, to make
it possible to prepare a MariaDB build where this additional trx_t member is
not present and is not used in the code base. trx->wsrep_UK_scan is set to true
only for the duration of function call for: lock_rec_lock() trx->wsrep_UK_scan
is used only in lock_rec_has_to_wait() function to relax the need to wait if
wsrep_UK_scan is set and conflicting transaction is also high priority.
Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
2020-12-09 21:53:18 +02:00
|
|
|
#ifdef WITH_WSREP
|
|
|
|
ut_ad(!trx->wsrep);
|
|
|
|
ut_ad(!trx->wsrep_event);
|
|
|
|
ut_ad(!trx->wsrep_UK_scan);
|
|
|
|
#endif /* WITH_WSREP */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2019-03-27 18:58:43 +05:30
|
|
|
ut_ad(trx->get_flush_observer() == NULL);
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** For managing the life-cycle of the trx_t instance that we get
|
|
|
|
from the pool. */
|
|
|
|
struct TrxFactory {
|
|
|
|
|
|
|
|
/** Initializes a transaction object. It must be explicitly started
|
|
|
|
with trx_start_if_not_started() before using it. The default isolation
|
|
|
|
level is TRX_ISO_REPEATABLE_READ.
|
|
|
|
@param trx Transaction instance to initialise */
|
|
|
|
static void init(trx_t* trx)
|
|
|
|
{
|
|
|
|
/* Explicitly call the constructor of the already
|
|
|
|
allocated object. trx_t objects are allocated by
|
2018-03-11 23:34:23 +02:00
|
|
|
ut_zalloc_nokey() in Pool::Pool() which would not call
|
2016-08-12 11:17:45 +03:00
|
|
|
the constructors of the trx_t members. */
|
|
|
|
new(&trx->mod_tables) trx_mod_tables_t();
|
|
|
|
|
2018-08-13 12:34:12 +03:00
|
|
|
new(&trx->lock.table_locks) lock_list();
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2018-01-20 17:45:42 +04:00
|
|
|
new(&trx->read_view) ReadView();
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2017-12-13 15:40:41 +04:00
|
|
|
trx->rw_trx_hash_pins = 0;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_init(trx);
|
|
|
|
|
|
|
|
trx->dict_operation_lock_mode = 0;
|
|
|
|
|
|
|
|
trx->xid = UT_NEW_NOKEY(xid_t());
|
|
|
|
|
|
|
|
trx->detailed_error = reinterpret_cast<char*>(
|
|
|
|
ut_zalloc_nokey(MAX_DETAILED_ERROR_LEN));
|
|
|
|
|
|
|
|
trx->lock.lock_heap = mem_heap_create_typed(
|
|
|
|
1024, MEM_HEAP_FOR_LOCK_HEAP);
|
|
|
|
|
|
|
|
lock_trx_lock_list_init(&trx->lock.trx_locks);
|
|
|
|
|
2018-10-10 12:44:10 +03:00
|
|
|
UT_LIST_INIT(trx->lock.evicted_tables,
|
|
|
|
&dict_table_t::table_LRU);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
UT_LIST_INIT(
|
|
|
|
trx->trx_savepoints,
|
|
|
|
&trx_named_savept_t::trx_savepoints);
|
|
|
|
|
|
|
|
mutex_create(LATCH_ID_TRX, &trx->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Release resources held by the transaction object.
|
|
|
|
@param trx the transaction for which to release resources */
|
|
|
|
static void destroy(trx_t* trx)
|
|
|
|
{
|
2020-08-21 18:22:55 +03:00
|
|
|
#ifdef __SANITIZE_ADDRESS__
|
|
|
|
/* Unpoison the memory for AddressSanitizer */
|
2020-08-21 19:18:34 +03:00
|
|
|
MEM_MAKE_ADDRESSABLE(trx, sizeof *trx);
|
2020-08-21 18:22:55 +03:00
|
|
|
#else
|
|
|
|
/* Declare the contents as initialized for Valgrind;
|
|
|
|
we checked this in trx_t::free(). */
|
|
|
|
MEM_MAKE_DEFINED(trx, sizeof *trx);
|
|
|
|
#endif
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_a(trx->magic_n == TRX_MAGIC_N);
|
2018-03-29 23:09:16 +04:00
|
|
|
ut_ad(!trx->mysql_thd);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
ut_a(trx->lock.wait_lock == NULL);
|
|
|
|
ut_a(trx->lock.wait_thr == NULL);
|
|
|
|
ut_a(trx->dict_operation_lock_mode == 0);
|
|
|
|
|
|
|
|
if (trx->lock.lock_heap != NULL) {
|
|
|
|
mem_heap_free(trx->lock.lock_heap);
|
|
|
|
trx->lock.lock_heap = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
|
2018-10-10 12:44:10 +03:00
|
|
|
ut_ad(UT_LIST_GET_LEN(trx->lock.evicted_tables) == 0);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
UT_DELETE(trx->xid);
|
|
|
|
ut_free(trx->detailed_error);
|
|
|
|
|
|
|
|
mutex_free(&trx->mutex);
|
|
|
|
|
|
|
|
trx->mod_tables.~trx_mod_tables_t();
|
|
|
|
|
2018-01-20 17:45:42 +04:00
|
|
|
ut_ad(!trx->read_view.is_open());
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2018-08-13 12:34:12 +03:00
|
|
|
trx->lock.table_locks.~lock_list();
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2018-01-24 14:00:42 +02:00
|
|
|
trx->read_view.~ReadView();
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** The lock strategy for TrxPool */
|
|
|
|
struct TrxPoolLock {
|
|
|
|
TrxPoolLock() { }
|
|
|
|
|
|
|
|
/** Create the mutex */
|
|
|
|
void create()
|
|
|
|
{
|
|
|
|
mutex_create(LATCH_ID_TRX_POOL, &m_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Acquire the mutex */
|
|
|
|
void enter() { mutex_enter(&m_mutex); }
|
|
|
|
|
|
|
|
/** Release the mutex */
|
|
|
|
void exit() { mutex_exit(&m_mutex); }
|
|
|
|
|
|
|
|
/** Free the mutex */
|
|
|
|
void destroy() { mutex_free(&m_mutex); }
|
|
|
|
|
|
|
|
/** Mutex to use */
|
|
|
|
ib_mutex_t m_mutex;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** The lock strategy for the TrxPoolManager */
|
|
|
|
struct TrxPoolManagerLock {
|
|
|
|
TrxPoolManagerLock() { }
|
|
|
|
|
|
|
|
/** Create the mutex */
|
|
|
|
void create()
|
|
|
|
{
|
|
|
|
mutex_create(LATCH_ID_TRX_POOL_MANAGER, &m_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Acquire the mutex */
|
|
|
|
void enter() { mutex_enter(&m_mutex); }
|
|
|
|
|
|
|
|
/** Release the mutex */
|
|
|
|
void exit() { mutex_exit(&m_mutex); }
|
|
|
|
|
|
|
|
/** Free the mutex */
|
|
|
|
void destroy() { mutex_free(&m_mutex); }
|
|
|
|
|
|
|
|
/** Mutex to use */
|
|
|
|
ib_mutex_t m_mutex;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Use explicit mutexes for the trx_t pool and its manager. */
|
|
|
|
typedef Pool<trx_t, TrxFactory, TrxPoolLock> trx_pool_t;
|
|
|
|
typedef PoolManager<trx_pool_t, TrxPoolManagerLock > trx_pools_t;
|
|
|
|
|
|
|
|
/** The trx_t pool manager */
|
|
|
|
static trx_pools_t* trx_pools;
|
|
|
|
|
|
|
|
/** Size of on trx_t pool in bytes. */
|
|
|
|
static const ulint MAX_TRX_BLOCK_SIZE = 1024 * 1024 * 4;
|
|
|
|
|
|
|
|
/** Create the trx_t pool */
|
|
|
|
void
|
|
|
|
trx_pool_init()
|
|
|
|
{
|
|
|
|
trx_pools = UT_NEW_NOKEY(trx_pools_t(MAX_TRX_BLOCK_SIZE));
|
|
|
|
|
|
|
|
ut_a(trx_pools != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Destroy the trx_t pool */
|
|
|
|
void
|
|
|
|
trx_pool_close()
|
|
|
|
{
|
|
|
|
UT_DELETE(trx_pools);
|
|
|
|
|
|
|
|
trx_pools = 0;
|
|
|
|
}
|
|
|
|
|
2020-08-21 19:18:34 +03:00
|
|
|
/** @return an allocated transaction */
|
2018-03-29 22:38:26 +04:00
|
|
|
trx_t *trx_create()
|
2016-08-12 11:17:45 +03:00
|
|
|
{
|
|
|
|
trx_t* trx = trx_pools->get();
|
|
|
|
|
2020-08-21 18:22:55 +03:00
|
|
|
#ifdef __SANITIZE_ADDRESS__
|
|
|
|
/* Unpoison the memory for AddressSanitizer.
|
|
|
|
It may have been poisoned in trx_t::free().*/
|
2020-08-21 19:18:34 +03:00
|
|
|
MEM_MAKE_ADDRESSABLE(trx, sizeof *trx);
|
2020-08-21 18:22:55 +03:00
|
|
|
#else
|
|
|
|
/* Declare the memory initialized for Valgrind.
|
|
|
|
The trx_t that are released to the pool are
|
|
|
|
actually initialized; we checked that by
|
|
|
|
MEM_CHECK_DEFINED() in trx_t::free(). */
|
|
|
|
MEM_MAKE_DEFINED(trx, sizeof *trx);
|
|
|
|
#endif
|
|
|
|
|
2020-05-14 09:17:14 +03:00
|
|
|
trx->assert_freed();
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
mem_heap_t* heap;
|
|
|
|
ib_alloc_t* alloc;
|
|
|
|
|
|
|
|
/* We just got trx from pool, it should be non locking */
|
|
|
|
ut_ad(trx->will_lock == 0);
|
2017-12-13 15:40:41 +04:00
|
|
|
ut_ad(!trx->rw_trx_hash_pins);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-08-08 15:32:23 +03:00
|
|
|
DBUG_LOG("trx", "Create: " << trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
heap = mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 8);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
alloc = ib_heap_allocator_create(heap);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->autoinc_locks = ib_vector_create(alloc, sizeof(void**), 4);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2018-08-13 11:46:22 +03:00
|
|
|
ut_ad(trx->mod_tables.empty());
|
|
|
|
ut_ad(trx->lock.n_rec_locks == 0);
|
|
|
|
ut_ad(trx->lock.table_cached == 0);
|
|
|
|
ut_ad(trx->lock.rec_cached == 0);
|
2018-10-10 12:44:10 +03:00
|
|
|
ut_ad(UT_LIST_GET_LEN(trx->lock.evicted_tables) == 0);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2014-08-06 15:39:15 +03:00
|
|
|
#ifdef WITH_WSREP
|
2020-05-14 09:17:14 +03:00
|
|
|
trx->wsrep_event= NULL;
|
MDEV-23851 BF-BF Conflict issue because of UK GAP locks
Some DML operations on tables having unique secondary keys cause scanning
in the secondary index, for instance to find potential unique key violations
in the seconday index. This scanning may involve GAP locking in the index.
As this locking happens also when applying replication events in high priority
applier threads, there is a probabality for lock conflicts between two wsrep
high priority threads.
This PR avoids lock conflicts of high priority wsrep threads, which do
secondary index scanning e.g. for duplicate key detection.
The actual fix is the patch in sql_class.cc:thd_need_ordering_with(), where
we allow relaxed GAP locking protocol between wsrep high priority threads.
wsrep high priority threads (replication appliers, replayers and TOI processors)
are ordered by the replication provider, and they will not need serializability
support gained by secondary index GAP locks.
PR contains also a mtr test, which exercises a scenario where two replication
applier threads have a false positive conflict in GAP of unique secondary index.
The conflicting local committing transaction has to replay, and the test verifies
also that the replaying phase will not conflict with the latter repllication applier.
Commit also contains new test scenario for galera.galera_UK_conflict.test,
where replayer starts applying after a slave applier thread, with later seqno,
has advanced to commit phase. The applier and replayer have false positive GAP
lock conflict on secondary unique index, and replayer should ignore this.
This test scenario caused crash with earlier version in this PR, and to fix this,
the secondary index uniquenes checking has been relaxed even further.
Now innodb trx_t structure has new member: bool wsrep_UK_scan, which is set to
true, when high priority thread is performing unique secondary index scanning.
The member trx_t::wsrep_UK_scan is defined inside WITH_WSREP directive, to make
it possible to prepare a MariaDB build where this additional trx_t member is
not present and is not used in the code base. trx->wsrep_UK_scan is set to true
only for the duration of function call for: lock_rec_lock() trx->wsrep_UK_scan
is used only in lock_rec_has_to_wait() function to relax the need to wait if
wsrep_UK_scan is set and conflicting transaction is also high priority.
Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
2020-12-09 21:53:18 +02:00
|
|
|
ut_ad(!trx->wsrep_UK_scan);
|
2014-08-06 15:39:15 +03:00
|
|
|
#endif /* WITH_WSREP */
|
2016-09-06 09:43:16 +03:00
|
|
|
|
2018-03-30 16:16:27 +04:00
|
|
|
trx_sys.register_trx(trx);
|
2018-03-30 00:33:58 +04:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
return(trx);
|
|
|
|
}
|
|
|
|
|
2020-08-21 18:22:55 +03:00
|
|
|
/** Free the memory to trx_pools */
|
2020-08-21 19:18:34 +03:00
|
|
|
void trx_t::free()
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2020-08-21 18:22:55 +03:00
|
|
|
MEM_CHECK_DEFINED(this, sizeof *this);
|
|
|
|
|
2020-08-21 19:18:34 +03:00
|
|
|
ut_ad(!n_mysql_tables_in_use);
|
|
|
|
ut_ad(!mysql_n_tables_locked);
|
|
|
|
ut_ad(!internal);
|
|
|
|
ut_ad(!declared_to_be_inside_innodb);
|
2020-08-21 18:22:55 +03:00
|
|
|
ut_ad(!will_lock);
|
|
|
|
ut_ad(error_state == DB_SUCCESS);
|
|
|
|
ut_ad(magic_n == TRX_MAGIC_N);
|
|
|
|
ut_ad(!read_only);
|
|
|
|
ut_ad(!lock.wait_lock);
|
|
|
|
|
2020-08-21 19:18:34 +03:00
|
|
|
dict_operation= TRX_DICT_OP_NONE;
|
|
|
|
trx_sys.deregister_trx(this);
|
2020-08-21 19:57:22 +03:00
|
|
|
assert_freed();
|
2020-08-21 19:18:34 +03:00
|
|
|
trx_sys.rw_trx_hash.put_pins(this);
|
|
|
|
|
2020-08-21 18:22:55 +03:00
|
|
|
mysql_thd= NULL;
|
|
|
|
mysql_log_file_name= NULL;
|
|
|
|
|
|
|
|
// FIXME: We need to avoid this heap free/alloc for each commit.
|
|
|
|
if (autoinc_locks)
|
|
|
|
{
|
|
|
|
ut_ad(ib_vector_is_empty(autoinc_locks));
|
|
|
|
/* We allocated a dedicated heap for the vector. */
|
|
|
|
ib_vector_free(autoinc_locks);
|
|
|
|
autoinc_locks= NULL;
|
|
|
|
}
|
2018-03-30 15:10:40 +04:00
|
|
|
|
2020-08-21 18:22:55 +03:00
|
|
|
mod_tables.clear();
|
2018-03-30 15:10:40 +04:00
|
|
|
|
2020-08-21 18:22:55 +03:00
|
|
|
MEM_NOACCESS(&n_ref, sizeof n_ref);
|
|
|
|
/* do not poison mutex */
|
|
|
|
MEM_NOACCESS(&id, sizeof id);
|
|
|
|
MEM_NOACCESS(&no, sizeof no);
|
2020-12-17 14:20:23 +02:00
|
|
|
MEM_NOACCESS(&state, sizeof state);
|
2020-08-21 18:22:55 +03:00
|
|
|
MEM_NOACCESS(&is_recovered, sizeof is_recovered);
|
|
|
|
#ifdef WITH_WSREP
|
|
|
|
MEM_NOACCESS(&wsrep, sizeof wsrep);
|
2020-05-25 19:41:58 +03:00
|
|
|
#endif
|
2020-08-21 18:22:55 +03:00
|
|
|
MEM_NOACCESS(&read_view, sizeof read_view);
|
|
|
|
MEM_NOACCESS(&trx_list, sizeof trx_list);
|
|
|
|
MEM_NOACCESS(&lock, sizeof lock);
|
|
|
|
MEM_NOACCESS(&op_info, sizeof op_info);
|
|
|
|
MEM_NOACCESS(&isolation_level, sizeof isolation_level);
|
|
|
|
MEM_NOACCESS(&check_foreigns, sizeof check_foreigns);
|
|
|
|
MEM_NOACCESS(&is_registered, sizeof is_registered);
|
|
|
|
MEM_NOACCESS(&active_commit_ordered, sizeof active_commit_ordered);
|
|
|
|
MEM_NOACCESS(&check_unique_secondary, sizeof check_unique_secondary);
|
|
|
|
MEM_NOACCESS(&flush_log_later, sizeof flush_log_later);
|
|
|
|
MEM_NOACCESS(&must_flush_log_later, sizeof must_flush_log_later);
|
|
|
|
MEM_NOACCESS(&duplicates, sizeof duplicates);
|
|
|
|
MEM_NOACCESS(&dict_operation, sizeof dict_operation);
|
|
|
|
MEM_NOACCESS(&declared_to_be_inside_innodb, sizeof declared_to_be_inside_innodb);
|
|
|
|
MEM_NOACCESS(&n_tickets_to_enter_innodb, sizeof n_tickets_to_enter_innodb);
|
|
|
|
MEM_NOACCESS(&dict_operation_lock_mode, sizeof dict_operation_lock_mode);
|
|
|
|
MEM_NOACCESS(&start_time, sizeof start_time);
|
|
|
|
MEM_NOACCESS(&start_time_micro, sizeof start_time_micro);
|
|
|
|
MEM_NOACCESS(&commit_lsn, sizeof commit_lsn);
|
|
|
|
MEM_NOACCESS(&table_id, sizeof table_id);
|
2020-12-17 14:20:23 +02:00
|
|
|
MEM_NOACCESS(&mysql_thd, sizeof mysql_thd);
|
2020-08-21 18:22:55 +03:00
|
|
|
MEM_NOACCESS(&mysql_log_file_name, sizeof mysql_log_file_name);
|
|
|
|
MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset);
|
|
|
|
MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use);
|
|
|
|
MEM_NOACCESS(&mysql_n_tables_locked, sizeof mysql_n_tables_locked);
|
|
|
|
MEM_NOACCESS(&error_state, sizeof error_state);
|
|
|
|
MEM_NOACCESS(&error_info, sizeof error_info);
|
|
|
|
MEM_NOACCESS(&error_key_num, sizeof error_key_num);
|
|
|
|
MEM_NOACCESS(&graph, sizeof graph);
|
|
|
|
MEM_NOACCESS(&trx_savepoints, sizeof trx_savepoints);
|
|
|
|
MEM_NOACCESS(&undo_no, sizeof undo_no);
|
|
|
|
MEM_NOACCESS(&last_sql_stat_start, sizeof last_sql_stat_start);
|
|
|
|
MEM_NOACCESS(&rsegs, sizeof rsegs);
|
|
|
|
MEM_NOACCESS(&roll_limit, sizeof roll_limit);
|
|
|
|
MEM_NOACCESS(&in_rollback, sizeof in_rollback);
|
|
|
|
MEM_NOACCESS(&pages_undone, sizeof pages_undone);
|
|
|
|
MEM_NOACCESS(&n_autoinc_rows, sizeof n_autoinc_rows);
|
|
|
|
MEM_NOACCESS(&autoinc_locks, sizeof autoinc_locks);
|
|
|
|
MEM_NOACCESS(&read_only, sizeof read_only);
|
|
|
|
MEM_NOACCESS(&auto_commit, sizeof auto_commit);
|
|
|
|
MEM_NOACCESS(&will_lock, sizeof will_lock);
|
|
|
|
MEM_NOACCESS(&fts_trx, sizeof fts_trx);
|
|
|
|
MEM_NOACCESS(&fts_next_doc_id, sizeof fts_next_doc_id);
|
|
|
|
MEM_NOACCESS(&flush_tables, sizeof flush_tables);
|
|
|
|
MEM_NOACCESS(&ddl, sizeof ddl);
|
|
|
|
MEM_NOACCESS(&internal, sizeof internal);
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
MEM_NOACCESS(&start_line, sizeof start_line);
|
|
|
|
MEM_NOACCESS(&start_file, sizeof start_file);
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
MEM_NOACCESS(&xid, sizeof xid);
|
|
|
|
MEM_NOACCESS(&mod_tables, sizeof mod_tables);
|
|
|
|
MEM_NOACCESS(&detailed_error, sizeof detailed_error);
|
|
|
|
MEM_NOACCESS(&flush_observer, sizeof flush_observer);
|
|
|
|
#ifdef WITH_WSREP
|
|
|
|
MEM_NOACCESS(&wsrep_event, sizeof wsrep_event);
|
MDEV-23851 BF-BF Conflict issue because of UK GAP locks
Some DML operations on tables having unique secondary keys cause scanning
in the secondary index, for instance to find potential unique key violations
in the seconday index. This scanning may involve GAP locking in the index.
As this locking happens also when applying replication events in high priority
applier threads, there is a probabality for lock conflicts between two wsrep
high priority threads.
This PR avoids lock conflicts of high priority wsrep threads, which do
secondary index scanning e.g. for duplicate key detection.
The actual fix is the patch in sql_class.cc:thd_need_ordering_with(), where
we allow relaxed GAP locking protocol between wsrep high priority threads.
wsrep high priority threads (replication appliers, replayers and TOI processors)
are ordered by the replication provider, and they will not need serializability
support gained by secondary index GAP locks.
PR contains also a mtr test, which exercises a scenario where two replication
applier threads have a false positive conflict in GAP of unique secondary index.
The conflicting local committing transaction has to replay, and the test verifies
also that the replaying phase will not conflict with the latter repllication applier.
Commit also contains new test scenario for galera.galera_UK_conflict.test,
where replayer starts applying after a slave applier thread, with later seqno,
has advanced to commit phase. The applier and replayer have false positive GAP
lock conflict on secondary unique index, and replayer should ignore this.
This test scenario caused crash with earlier version in this PR, and to fix this,
the secondary index uniquenes checking has been relaxed even further.
Now innodb trx_t structure has new member: bool wsrep_UK_scan, which is set to
true, when high priority thread is performing unique secondary index scanning.
The member trx_t::wsrep_UK_scan is defined inside WITH_WSREP directive, to make
it possible to prepare a MariaDB build where this additional trx_t member is
not present and is not used in the code base. trx->wsrep_UK_scan is set to true
only for the duration of function call for: lock_rec_lock() trx->wsrep_UK_scan
is used only in lock_rec_has_to_wait() function to relax the need to wait if
wsrep_UK_scan is set and conflicting transaction is also high priority.
Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
2020-12-09 21:53:18 +02:00
|
|
|
ut_ad(!wsrep_UK_scan);
|
|
|
|
MEM_NOACCESS(&wsrep_UK_scan, sizeof wsrep_UK_scan);
|
2020-08-21 18:22:55 +03:00
|
|
|
#endif /* WITH_WSREP */
|
|
|
|
MEM_NOACCESS(&magic_n, sizeof magic_n);
|
|
|
|
trx_pools->mem_free(this);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
/** Transition to committed state, to release implicit locks. */
|
|
|
|
inline void trx_t::commit_state()
|
|
|
|
{
|
2019-09-05 15:57:39 +03:00
|
|
|
ut_ad(state == TRX_STATE_PREPARED
|
|
|
|
|| state == TRX_STATE_PREPARED_RECOVERED
|
|
|
|
|| state == TRX_STATE_ACTIVE);
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
/* This makes the transaction committed in memory and makes its
|
|
|
|
changes to data visible to other transactions. NOTE that there is a
|
|
|
|
small discrepancy from the strict formal visibility rules here: a
|
|
|
|
user of the database can see modifications made by another
|
|
|
|
transaction T even before the necessary redo log segment has been
|
|
|
|
flushed to the disk. If the database happens to crash before the
|
|
|
|
flush, the user has seen modifications from T which will never be a
|
|
|
|
committed transaction. However, any transaction T2 which sees the
|
|
|
|
modifications of the committing transaction T, and which also itself
|
|
|
|
makes modifications to the database, will get an lsn larger than the
|
|
|
|
committing transaction T. In the case where the log flush fails, and
|
|
|
|
T never gets committed, also T2 will never get committed. */
|
2019-09-05 15:57:39 +03:00
|
|
|
trx_mutex_enter(this);
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
state= TRX_STATE_COMMITTED_IN_MEMORY;
|
2019-09-05 15:57:39 +03:00
|
|
|
trx_mutex_exit(this);
|
2019-09-03 13:04:05 +03:00
|
|
|
ut_ad(id || !is_referenced());
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Release any explicit locks of a committing transaction. */
|
|
|
|
inline void trx_t::release_locks()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(state == TRX_STATE_COMMITTED_IN_MEMORY);
|
2019-09-05 15:57:39 +03:00
|
|
|
DBUG_ASSERT(!is_referenced());
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
|
|
|
|
if (UT_LIST_GET_LEN(lock.trx_locks))
|
2019-09-05 15:57:39 +03:00
|
|
|
{
|
|
|
|
lock_release(this);
|
|
|
|
lock.n_rec_locks = 0;
|
|
|
|
ut_ad(UT_LIST_GET_LEN(lock.trx_locks) == 0);
|
|
|
|
ut_ad(ib_vector_is_empty(autoinc_locks));
|
|
|
|
mem_heap_empty(lock.lock_heap);
|
|
|
|
}
|
|
|
|
|
2019-09-23 10:25:34 +03:00
|
|
|
lock.table_locks.clear();
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
}
|
|
|
|
|
2017-12-27 14:24:34 +04:00
|
|
|
/** At shutdown, frees a transaction object. */
|
2012-08-01 17:27:34 +03:00
|
|
|
void
|
2017-12-27 14:24:34 +04:00
|
|
|
trx_free_at_shutdown(trx_t *trx)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2017-12-27 14:24:34 +04:00
|
|
|
ut_ad(trx->is_recovered);
|
2017-02-03 12:25:42 +02:00
|
|
|
ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)
|
2019-04-24 12:03:11 +03:00
|
|
|
|| trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)
|
2017-12-27 14:24:34 +04:00
|
|
|
|| (trx_state_eq(trx, TRX_STATE_ACTIVE)
|
2020-04-03 00:43:09 +03:00
|
|
|
&& (!srv_was_started || is_mariabackup_restore_or_export()
|
2017-02-09 10:04:00 +02:00
|
|
|
|| srv_read_only_mode
|
2017-12-27 14:24:34 +04:00
|
|
|
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
|
|
|
|
|| (!srv_is_being_started
|
|
|
|
&& !srv_undo_sources && srv_fast_shutdown))));
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_a(trx->magic_n == TRX_MAGIC_N);
|
|
|
|
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
trx->commit_state();
|
|
|
|
trx->release_locks();
|
2017-12-27 14:24:34 +04:00
|
|
|
trx_undo_free_at_shutdown(trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
ut_a(!trx->read_only);
|
|
|
|
|
2017-08-08 15:32:23 +03:00
|
|
|
DBUG_LOG("trx", "Free prepared: " << trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->state = TRX_STATE_NOT_STARTED;
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
ut_ad(!UT_LIST_GET_LEN(trx->lock.trx_locks));
|
2019-08-27 15:48:46 +03:00
|
|
|
trx->id = 0;
|
2020-08-21 18:22:55 +03:00
|
|
|
trx->free();
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2018-01-28 17:17:11 +04:00
|
|
|
|
2018-03-30 00:33:58 +04:00
|
|
|
/**
|
|
|
|
Disconnect a prepared transaction from MySQL
|
|
|
|
@param[in,out] trx transaction
|
|
|
|
*/
|
|
|
|
void trx_disconnect_prepared(trx_t *trx)
|
2016-08-12 11:17:45 +03:00
|
|
|
{
|
2018-03-30 00:33:58 +04:00
|
|
|
ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED));
|
|
|
|
ut_ad(trx->mysql_thd);
|
|
|
|
trx->read_view.close();
|
|
|
|
trx->is_recovered= true;
|
|
|
|
trx->mysql_thd= NULL;
|
|
|
|
/* todo/fixme: suggest to do it at innodb prepare */
|
|
|
|
trx->will_lock= 0;
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
2014-02-26 19:23:04 +01:00
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
/****************************************************************//**
|
|
|
|
Resurrect the table locks for a resurrected transaction. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_resurrect_table_locks(
|
|
|
|
/*======================*/
|
|
|
|
trx_t* trx, /*!< in/out: transaction */
|
|
|
|
const trx_undo_t* undo) /*!< in: undo log */
|
|
|
|
{
|
|
|
|
mtr_t mtr;
|
|
|
|
page_t* undo_page;
|
|
|
|
trx_undo_rec_t* undo_rec;
|
|
|
|
table_id_set tables;
|
|
|
|
|
2017-12-13 15:40:41 +04:00
|
|
|
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
|
|
|
|
trx_state_eq(trx, TRX_STATE_PREPARED));
|
2018-03-26 17:23:47 +03:00
|
|
|
ut_ad(undo->rseg == trx->rsegs.m_redo.rseg);
|
|
|
|
|
2018-04-25 09:56:03 +03:00
|
|
|
if (undo->empty()) {
|
2014-02-01 09:33:26 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mtr_start(&mtr);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
/* trx_rseg_mem_create() may have acquired an X-latch on this
|
|
|
|
page, so we cannot acquire an S-latch. */
|
|
|
|
undo_page = trx_undo_page_get(
|
2018-03-26 17:23:47 +03:00
|
|
|
page_id_t(trx->rsegs.m_redo.rseg->space->id,
|
|
|
|
undo->top_page_no), &mtr);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
undo_rec = undo_page + undo->top_offset;
|
|
|
|
|
|
|
|
do {
|
|
|
|
ulint type;
|
|
|
|
undo_no_t undo_no;
|
|
|
|
table_id_t table_id;
|
2016-08-12 11:17:45 +03:00
|
|
|
ulint cmpl_info;
|
|
|
|
bool updated_extern;
|
2014-02-01 09:33:26 +01:00
|
|
|
|
|
|
|
page_t* undo_rec_page = page_align(undo_rec);
|
|
|
|
|
|
|
|
if (undo_rec_page != undo_page) {
|
2016-09-06 09:43:16 +03:00
|
|
|
mtr.release_page(undo_page, MTR_MEMO_PAGE_X_FIX);
|
2014-02-01 09:33:26 +01:00
|
|
|
undo_page = undo_rec_page;
|
|
|
|
}
|
|
|
|
|
|
|
|
trx_undo_rec_get_pars(
|
|
|
|
undo_rec, &type, &cmpl_info,
|
|
|
|
&updated_extern, &undo_no, &table_id);
|
|
|
|
tables.insert(table_id);
|
|
|
|
|
|
|
|
undo_rec = trx_undo_get_prev_rec(
|
|
|
|
undo_rec, undo->hdr_page_no,
|
|
|
|
undo->hdr_offset, false, &mtr);
|
|
|
|
} while (undo_rec);
|
|
|
|
|
|
|
|
mtr_commit(&mtr);
|
|
|
|
|
|
|
|
for (table_id_set::const_iterator i = tables.begin();
|
|
|
|
i != tables.end(); i++) {
|
|
|
|
if (dict_table_t* table = dict_table_open_on_id(
|
|
|
|
*i, FALSE, DICT_TABLE_OP_LOAD_TABLESPACE)) {
|
2017-07-06 02:14:33 +03:00
|
|
|
if (!table->is_readable()) {
|
2019-05-17 14:32:53 +03:00
|
|
|
mutex_enter(&dict_sys.mutex);
|
2014-02-01 09:33:26 +01:00
|
|
|
dict_table_close(table, TRUE, FALSE);
|
2019-05-17 14:32:53 +03:00
|
|
|
dict_sys.remove(table);
|
|
|
|
mutex_exit(&dict_sys.mutex);
|
2014-02-01 09:33:26 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->state == TRX_STATE_PREPARED) {
|
2017-11-22 16:27:59 +02:00
|
|
|
trx->mod_tables.insert(
|
|
|
|
trx_mod_tables_t::value_type(table,
|
|
|
|
0));
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
2014-02-01 09:33:26 +01:00
|
|
|
lock_table_ix_resurrect(table, trx);
|
|
|
|
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
DBUG_LOG("ib_trx",
|
|
|
|
"resurrect " << ib::hex(trx->id)
|
|
|
|
<< " IX lock on " << table->name);
|
2014-02-01 09:33:26 +01:00
|
|
|
|
|
|
|
dict_table_close(table, FALSE, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-21 15:45:40 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
Resurrect the transactions that were doing inserts/updates the time of the
|
|
|
|
crash, they need to be undone.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
|
2019-07-25 15:31:11 +03:00
|
|
|
time_t start_time, ulonglong start_time_micro,
|
|
|
|
uint64_t *rows_to_undo,
|
2017-12-27 16:23:53 +04:00
|
|
|
bool is_old_insert)
|
2017-12-13 15:40:41 +04:00
|
|
|
{
|
2017-12-21 15:45:40 +04:00
|
|
|
trx_state_t state;
|
|
|
|
/*
|
|
|
|
This is single-threaded startup code, we do not need the
|
2017-12-22 16:15:41 +02:00
|
|
|
protection of trx->mutex or trx_sys.mutex here.
|
2017-12-21 15:45:40 +04:00
|
|
|
*/
|
|
|
|
switch (undo->state)
|
|
|
|
{
|
|
|
|
case TRX_UNDO_ACTIVE:
|
|
|
|
state= TRX_STATE_ACTIVE;
|
|
|
|
break;
|
|
|
|
case TRX_UNDO_PREPARED:
|
|
|
|
/*
|
|
|
|
Prepared transactions are left in the prepared state
|
|
|
|
waiting for a commit or abort decision from MySQL
|
|
|
|
*/
|
|
|
|
ib::info() << "Transaction " << undo->trx_id
|
|
|
|
<< " was in the XA prepared state.";
|
|
|
|
|
|
|
|
state= TRX_STATE_PREPARED;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (is_old_insert && srv_force_recovery < SRV_FORCE_NO_TRX_UNDO)
|
|
|
|
trx_undo_commit_cleanup(undo, false);
|
|
|
|
return;
|
|
|
|
}
|
2017-12-13 15:40:41 +04:00
|
|
|
|
2018-03-29 22:38:26 +04:00
|
|
|
trx_t *trx= trx_create();
|
2017-12-21 15:45:40 +04:00
|
|
|
trx->state= state;
|
|
|
|
ut_d(trx->start_file= __FILE__);
|
|
|
|
ut_d(trx->start_line= __LINE__);
|
|
|
|
ut_ad(trx->no == TRX_ID_MAX);
|
|
|
|
|
|
|
|
if (is_old_insert)
|
|
|
|
trx->rsegs.m_redo.old_insert= undo;
|
|
|
|
else
|
|
|
|
trx->rsegs.m_redo.undo= undo;
|
|
|
|
|
2018-04-25 09:56:03 +03:00
|
|
|
trx->undo_no= undo->top_undo_no + 1;
|
2017-12-21 15:45:40 +04:00
|
|
|
trx->rsegs.m_redo.rseg= rseg;
|
|
|
|
/*
|
|
|
|
For transactions with active data will not have rseg size = 1
|
|
|
|
or will not qualify for purge limit criteria. So it is safe to increment
|
|
|
|
this trx_ref_count w/o mutex protection.
|
|
|
|
*/
|
|
|
|
++trx->rsegs.m_redo.rseg->trx_ref_count;
|
|
|
|
*trx->xid= undo->xid;
|
|
|
|
trx->id= undo->trx_id;
|
|
|
|
trx->is_recovered= true;
|
|
|
|
trx->start_time= start_time;
|
2019-07-25 15:31:11 +03:00
|
|
|
trx->start_time_micro= start_time_micro;
|
2017-12-21 15:45:40 +04:00
|
|
|
|
|
|
|
if (undo->dict_operation)
|
|
|
|
{
|
|
|
|
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
|
2018-09-10 15:40:11 +03:00
|
|
|
if (!trx->table_id)
|
|
|
|
trx->table_id= undo->table_id;
|
2017-12-21 15:45:40 +04:00
|
|
|
}
|
|
|
|
|
2017-12-22 16:15:41 +02:00
|
|
|
trx_sys.rw_trx_hash.insert(trx);
|
|
|
|
trx_sys.rw_trx_hash.put_pins(trx);
|
2017-12-21 15:45:40 +04:00
|
|
|
trx_resurrect_table_locks(trx, undo);
|
|
|
|
if (trx_state_eq(trx, TRX_STATE_ACTIVE))
|
|
|
|
*rows_to_undo+= trx->undo_no;
|
2017-12-13 15:40:41 +04:00
|
|
|
}
|
|
|
|
|
2017-12-21 15:45:40 +04:00
|
|
|
|
2017-03-09 17:28:06 +02:00
|
|
|
/** Initialize (resurrect) transactions at startup. */
|
2012-08-01 17:27:34 +03:00
|
|
|
void
|
2017-03-09 17:28:06 +02:00
|
|
|
trx_lists_init_at_db_start()
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
|
|
|
ut_a(srv_is_being_started);
|
2017-03-09 17:28:06 +02:00
|
|
|
ut_ad(!srv_was_started);
|
2017-03-09 20:40:48 +02:00
|
|
|
|
2018-02-20 15:10:03 +02:00
|
|
|
if (srv_operation == SRV_OPERATION_RESTORE) {
|
|
|
|
/* mariabackup --prepare only deals with
|
|
|
|
the redo log and the data files, not with
|
|
|
|
transactions or the data dictionary. */
|
|
|
|
trx_rseg_array_init();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-18 16:13:50 +02:00
|
|
|
if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
|
|
|
|
return;
|
2017-03-09 20:40:48 +02:00
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2018-02-22 09:30:41 +02:00
|
|
|
purge_sys.create();
|
2018-01-18 16:13:50 +02:00
|
|
|
trx_rseg_array_init();
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/* Look from the rollback segments if there exist undo logs for
|
2016-08-12 11:17:45 +03:00
|
|
|
transactions. */
|
2019-07-25 15:31:11 +03:00
|
|
|
const time_t start_time = time(NULL);
|
|
|
|
const ulonglong start_time_micro= microsecond_interval_timer();
|
2018-01-30 14:16:09 +02:00
|
|
|
uint64_t rows_to_undo = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) {
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_undo_t* undo;
|
2017-12-22 16:15:41 +02:00
|
|
|
trx_rseg_t* rseg = trx_sys.rseg_array[i];
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2018-01-18 16:13:50 +02:00
|
|
|
/* Some rollback segment may be unavailable,
|
|
|
|
especially if the server was previously run with a
|
|
|
|
non-default value of innodb_undo_logs. */
|
2012-08-01 17:27:34 +03:00
|
|
|
if (rseg == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
/* Resurrect transactions that were doing inserts
|
|
|
|
using the old separate insert_undo log. */
|
2017-12-21 15:45:40 +04:00
|
|
|
undo = UT_LIST_GET_FIRST(rseg->old_insert_list);
|
|
|
|
while (undo) {
|
|
|
|
trx_undo_t* next = UT_LIST_GET_NEXT(undo_list, undo);
|
2019-07-25 15:31:11 +03:00
|
|
|
trx_resurrect(undo, rseg, start_time, start_time_micro,
|
|
|
|
&rows_to_undo, true);
|
2017-12-21 15:45:40 +04:00
|
|
|
undo = next;
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
/* Ressurrect other transactions. */
|
|
|
|
for (undo = UT_LIST_GET_FIRST(rseg->undo_list);
|
2016-08-12 11:17:45 +03:00
|
|
|
undo != NULL;
|
|
|
|
undo = UT_LIST_GET_NEXT(undo_list, undo)) {
|
2018-07-03 15:10:06 +03:00
|
|
|
trx_t *trx = trx_sys.find(0, undo->trx_id, false);
|
2017-12-21 15:45:40 +04:00
|
|
|
if (!trx) {
|
|
|
|
trx_resurrect(undo, rseg, start_time,
|
2019-07-25 15:31:11 +03:00
|
|
|
start_time_micro,
|
2017-12-27 16:23:53 +04:00
|
|
|
&rows_to_undo, false);
|
2017-12-21 15:45:40 +04:00
|
|
|
} else {
|
|
|
|
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
|
|
|
|
trx_state_eq(trx, TRX_STATE_PREPARED));
|
|
|
|
ut_ad(trx->start_time == start_time);
|
|
|
|
ut_ad(trx->is_recovered);
|
|
|
|
ut_ad(trx->rsegs.m_redo.rseg == rseg);
|
|
|
|
ut_ad(trx->rsegs.m_redo.rseg->trx_ref_count);
|
|
|
|
|
|
|
|
trx->rsegs.m_redo.undo = undo;
|
2018-04-25 09:56:03 +03:00
|
|
|
if (undo->top_undo_no >= trx->undo_no) {
|
2017-12-21 15:45:40 +04:00
|
|
|
if (trx_state_eq(trx,
|
|
|
|
TRX_STATE_ACTIVE)) {
|
|
|
|
rows_to_undo -= trx->undo_no;
|
|
|
|
rows_to_undo +=
|
|
|
|
undo->top_undo_no + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->undo_no = undo->top_undo_no + 1;
|
|
|
|
}
|
|
|
|
trx_resurrect_table_locks(trx, undo);
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-22 16:15:41 +02:00
|
|
|
if (trx_sys.rw_trx_hash.size()) {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2017-12-22 16:15:41 +02:00
|
|
|
ib::info() << trx_sys.rw_trx_hash.size()
|
2017-12-13 15:40:41 +04:00
|
|
|
<< " transaction(s) which must be rolled back or"
|
|
|
|
" cleaned up in total " << rows_to_undo
|
|
|
|
<< " row operations to undo";
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2017-12-22 16:15:41 +02:00
|
|
|
ib::info() << "Trx id counter is " << trx_sys.get_max_trx_id();
|
2017-12-13 15:40:41 +04:00
|
|
|
}
|
2018-01-30 20:59:42 +04:00
|
|
|
trx_sys.clone_oldest_view();
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
/** Assign a persistent rollback segment in a round-robin fashion,
|
|
|
|
evenly distributed between 0 and innodb_undo_logs-1
|
|
|
|
@return persistent rollback segment
|
|
|
|
@retval NULL if innodb_read_only */
|
2018-11-27 14:02:24 +02:00
|
|
|
static trx_rseg_t* trx_assign_rseg_low()
|
2016-08-12 11:17:45 +03:00
|
|
|
{
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
if (srv_read_only_mode) {
|
|
|
|
ut_ad(srv_undo_logs == ULONG_UNDEFINED);
|
|
|
|
return(NULL);
|
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
/* The first slot is always assigned to the system tablespace. */
|
2018-03-26 17:23:47 +03:00
|
|
|
ut_ad(trx_sys.rseg_array[0]->space == fil_system.sys_space);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
/* Choose a rollback segment evenly distributed between 0 and
|
|
|
|
innodb_undo_logs-1 in a round-robin fashion, skipping those
|
2020-06-04 18:37:18 +08:00
|
|
|
undo tablespaces that are scheduled for truncation. */
|
|
|
|
static Atomic_counter<unsigned> rseg_slot;
|
|
|
|
ulong slot = ulong{rseg_slot++} % srv_undo_logs;
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
trx_rseg_t* rseg;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
ulint start_scan_slot = slot;
|
|
|
|
bool look_for_rollover = false;
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
|
|
|
|
bool allocated = false;
|
|
|
|
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
do {
|
2016-08-12 11:17:45 +03:00
|
|
|
for (;;) {
|
2017-12-22 16:15:41 +02:00
|
|
|
rseg = trx_sys.rseg_array[slot];
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
/* Ensure that we are not revisiting the same
|
|
|
|
slot that we have already inspected. */
|
|
|
|
if (look_for_rollover) {
|
|
|
|
ut_ad(start_scan_slot != slot);
|
|
|
|
}
|
|
|
|
look_for_rollover = true;
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
slot = (slot + 1) % srv_undo_logs;
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (rseg == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
|
|
|
|
ut_ad(rseg->is_persistent());
|
|
|
|
|
2018-03-26 17:23:47 +03:00
|
|
|
if (rseg->space != fil_system.sys_space) {
|
2018-11-27 14:02:24 +02:00
|
|
|
if (rseg->skip_allocation
|
|
|
|
|| !srv_undo_tablespaces) {
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (trx_rseg_t* next
|
2017-12-22 16:15:41 +02:00
|
|
|
= trx_sys.rseg_array[slot]) {
|
2018-03-26 17:23:47 +03:00
|
|
|
if (next->space != fil_system.sys_space
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
&& srv_undo_tablespaces > 0) {
|
|
|
|
/** If dedicated
|
|
|
|
innodb_undo_tablespaces have
|
|
|
|
been configured, try to use them
|
|
|
|
instead of the system tablespace. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
break;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* By now we have only selected the rseg but not marked it
|
|
|
|
allocated. By marking it allocated we are ensuring that it will
|
|
|
|
never be selected for UNDO truncate purge. */
|
|
|
|
mutex_enter(&rseg->mutex);
|
|
|
|
if (!rseg->skip_allocation) {
|
|
|
|
rseg->trx_ref_count++;
|
|
|
|
allocated = true;
|
|
|
|
}
|
|
|
|
mutex_exit(&rseg->mutex);
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
} while (!allocated);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(rseg->trx_ref_count > 0);
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
ut_ad(rseg->is_persistent());
|
2016-08-12 11:17:45 +03:00
|
|
|
return(rseg);
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2019-03-27 18:58:43 +05:30
|
|
|
/** Set the innodb_log_optimize_ddl page flush observer
|
2019-03-29 19:40:56 +01:00
|
|
|
@param[in,out] space tablespace
|
|
|
|
@param[in,out] stage performance_schema accounting */
|
|
|
|
void trx_t::set_flush_observer(fil_space_t* space, ut_stage_alter_t* stage)
|
2019-03-27 18:58:43 +05:30
|
|
|
{
|
2019-03-29 19:40:56 +01:00
|
|
|
flush_observer = UT_NEW_NOKEY(FlushObserver(space, this, stage));
|
2019-03-27 18:58:43 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/** Remove the flush observer */
|
|
|
|
void trx_t::remove_flush_observer()
|
|
|
|
{
|
|
|
|
UT_DELETE(flush_observer);
|
|
|
|
flush_observer = NULL;
|
|
|
|
}
|
|
|
|
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
/** Assign a rollback segment for modifying temporary tables.
|
|
|
|
@return the assigned rollback segment */
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_rseg_t*
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
trx_t::assign_temp_rseg()
|
|
|
|
{
|
|
|
|
ut_ad(!rsegs.m_noredo.rseg);
|
|
|
|
ut_ad(!trx_is_autocommit_non_locking(this));
|
|
|
|
compile_time_assert(ut_is_2pow(TRX_SYS_N_RSEGS));
|
|
|
|
|
|
|
|
/* Choose a temporary rollback segment between 0 and 127
|
2020-06-04 18:37:18 +08:00
|
|
|
in a round-robin fashion. */
|
|
|
|
static Atomic_counter<unsigned> rseg_slot;
|
2017-12-22 16:15:41 +02:00
|
|
|
trx_rseg_t* rseg = trx_sys.temp_rsegs[
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
rseg_slot++ & (TRX_SYS_N_RSEGS - 1)];
|
|
|
|
ut_ad(!rseg->is_persistent());
|
|
|
|
rsegs.m_noredo.rseg = rseg;
|
|
|
|
|
|
|
|
if (id == 0) {
|
2018-01-25 18:29:59 +04:00
|
|
|
trx_sys.register_rw(this);
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
|
|
|
|
ut_ad(!rseg->is_persistent());
|
|
|
|
return(rseg);
|
2013-03-26 00:03:13 +02:00
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/****************************************************************//**
|
|
|
|
Starts a transaction. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_start_low(
|
|
|
|
/*==========*/
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_t* trx, /*!< in: transaction */
|
|
|
|
bool read_write) /*!< in: true if read-write transaction */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(!trx->in_rollback);
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_ad(!trx->is_recovered);
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx->start_line != 0);
|
|
|
|
ut_ad(trx->start_file != 0);
|
|
|
|
ut_ad(trx->roll_limit == 0);
|
|
|
|
ut_ad(trx->error_state == DB_SUCCESS);
|
|
|
|
ut_ad(trx->rsegs.m_redo.rseg == NULL);
|
|
|
|
ut_ad(trx->rsegs.m_noredo.rseg == NULL);
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_ad(trx_state_eq(trx, TRX_STATE_NOT_STARTED));
|
|
|
|
ut_ad(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
|
|
|
|
|
|
|
|
/* Check whether it is an AUTOCOMMIT SELECT */
|
2017-02-11 17:45:36 +02:00
|
|
|
trx->auto_commit = thd_trx_is_auto_commit(trx->mysql_thd);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-02-11 17:45:36 +02:00
|
|
|
trx->read_only = srv_read_only_mode
|
2016-08-12 11:17:45 +03:00
|
|
|
|| (!trx->ddl && !trx->internal
|
2017-02-11 17:45:36 +02:00
|
|
|
&& thd_trx_is_read_only(trx->mysql_thd));
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
if (!trx->auto_commit) {
|
|
|
|
++trx->will_lock;
|
|
|
|
} else if (trx->will_lock == 0) {
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->read_only = true;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2014-08-06 15:39:15 +03:00
|
|
|
#ifdef WITH_WSREP
|
2018-08-03 13:02:56 +03:00
|
|
|
trx->xid->null();
|
2014-08-06 15:39:15 +03:00
|
|
|
#endif /* WITH_WSREP */
|
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
/* The initial value for trx->no: TRX_ID_MAX is used in
|
2012-08-01 17:27:34 +03:00
|
|
|
read_view_open_now: */
|
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
trx->no = TRX_ID_MAX;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
ut_a(ib_vector_is_empty(trx->autoinc_locks));
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_a(trx->lock.table_locks.empty());
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-12-13 15:40:41 +04:00
|
|
|
/* No other thread can access this trx object through rw_trx_hash, thus
|
2017-12-22 16:15:41 +02:00
|
|
|
we don't need trx_sys.mutex protection for that purpose. Still this
|
2018-03-30 00:33:58 +04:00
|
|
|
trx can be found through trx_sys.trx_list, which means state
|
2017-12-13 15:40:41 +04:00
|
|
|
change must be protected by e.g. trx->mutex.
|
|
|
|
|
|
|
|
For now we update it without mutex protection, because original code
|
|
|
|
did it this way. It has to be reviewed and fixed properly. */
|
|
|
|
trx->state = TRX_STATE_ACTIVE;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* By default all transactions are in the read-only list unless they
|
|
|
|
are non-locking auto-commit read only transactions or background
|
|
|
|
(internal) transactions. Note: Transactions marked explicitly as
|
|
|
|
read only can write to temporary tables, we put those on the RO
|
|
|
|
list too. */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (!trx->read_only
|
|
|
|
&& (trx->mysql_thd == 0 || read_write || trx->ddl)) {
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Temporary rseg is assigned only if the transaction
|
|
|
|
updates a temporary table */
|
2018-01-19 19:05:43 +04:00
|
|
|
trx->rsegs.m_redo.rseg = trx_assign_rseg_low();
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx->rsegs.m_redo.rseg != 0
|
|
|
|
|| srv_read_only_mode
|
2012-08-01 17:27:34 +03:00
|
|
|
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
|
|
|
|
|
2018-01-25 18:29:59 +04:00
|
|
|
trx_sys.register_rw(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
} else {
|
|
|
|
if (!trx_is_autocommit_non_locking(trx)) {
|
|
|
|
|
|
|
|
/* If this is a read-only transaction that is writing
|
|
|
|
to a temporary table then it needs a transaction id
|
|
|
|
to write to the temporary table. */
|
|
|
|
|
|
|
|
if (read_write) {
|
|
|
|
ut_ad(!srv_read_only_mode);
|
2018-01-25 18:29:59 +04:00
|
|
|
trx_sys.register_rw(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ut_ad(!read_write);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-25 12:08:50 +03:00
|
|
|
trx->start_time = time(NULL);
|
2019-07-24 20:43:24 +03:00
|
|
|
trx->start_time_micro = trx->mysql_thd
|
|
|
|
? thd_query_start_micro(trx->mysql_thd)
|
|
|
|
: microsecond_interval_timer();
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
ut_a(trx->error_state == DB_SUCCESS);
|
2013-03-26 00:03:13 +02:00
|
|
|
|
2016-10-23 13:36:26 -04:00
|
|
|
MONITOR_INC(MONITOR_TRX_ACTIVE);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
/** Set the serialisation number for a persistent committed transaction.
|
2018-01-28 16:02:48 +04:00
|
|
|
@param[in,out] trx committed transaction with persistent changes */
|
2012-08-01 17:27:34 +03:00
|
|
|
static
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
void
|
2018-01-28 16:02:48 +04:00
|
|
|
trx_serialise(trx_t* trx)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2018-01-28 16:02:48 +04:00
|
|
|
trx_rseg_t *rseg = trx->rsegs.m_redo.rseg;
|
|
|
|
ut_ad(rseg);
|
|
|
|
ut_ad(mutex_own(&rseg->mutex));
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2018-01-28 16:02:48 +04:00
|
|
|
if (rseg->last_page_no == FIL_NULL) {
|
2018-02-22 09:30:41 +02:00
|
|
|
mutex_enter(&purge_sys.pq_mutex);
|
2018-01-28 16:02:48 +04:00
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2018-02-13 19:51:13 +04:00
|
|
|
trx_sys.assign_new_trx_no(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2018-02-21 16:15:20 +02:00
|
|
|
/* If the rollback segment is not empty then the
|
2012-08-01 17:27:34 +03:00
|
|
|
new trx_t::no can't be less than any trx_t::no
|
|
|
|
already in the rollback segment. User threads only
|
|
|
|
produce events when a rollback segment is empty. */
|
2018-01-28 16:02:48 +04:00
|
|
|
if (rseg->last_page_no == FIL_NULL) {
|
2018-02-22 09:30:41 +02:00
|
|
|
purge_sys.purge_queue.push(TrxUndoRsegs(trx->no, *rseg));
|
|
|
|
mutex_exit(&purge_sys.pq_mutex);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
Assign the transaction its history serialisation number and write the
|
2018-01-28 16:02:48 +04:00
|
|
|
update UNDO log record to the assigned rollback segment. */
|
2015-05-26 10:01:12 +03:00
|
|
|
static
|
2018-01-28 16:02:48 +04:00
|
|
|
void
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_write_serialisation_history(
|
|
|
|
/*============================*/
|
2014-02-01 09:33:26 +01:00
|
|
|
trx_t* trx, /*!< in/out: transaction */
|
|
|
|
mtr_t* mtr) /*!< in/out: mini-transaction */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Change the undo log segment states from TRX_UNDO_ACTIVE to some
|
|
|
|
other state: these modifications to the file data structure define
|
|
|
|
the transaction as committed in the file based domain, at the
|
|
|
|
serialization point of the log sequence number lsn obtained below. */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* We have to hold the rseg mutex because update log headers have
|
|
|
|
to be put to the history list in the (serialisation) order of the
|
|
|
|
UNDO trx number. This is required for the purge in-memory data
|
|
|
|
structures too. */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
if (trx_undo_t* undo = trx->rsegs.m_noredo.undo) {
|
|
|
|
/* Undo log for temporary tables is discarded at transaction
|
|
|
|
commit. There is no purge for temporary tables, and also no
|
|
|
|
MVCC, because they are private to a session. */
|
2016-08-12 11:17:45 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
mtr_t temp_mtr;
|
|
|
|
temp_mtr.start();
|
2016-08-12 11:17:45 +03:00
|
|
|
temp_mtr.set_log_mode(MTR_LOG_NO_REDO);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
mutex_enter(&trx->rsegs.m_noredo.rseg->mutex);
|
|
|
|
trx_undo_set_state_at_finish(undo, &temp_mtr);
|
|
|
|
mutex_exit(&trx->rsegs.m_noredo.rseg->mutex);
|
|
|
|
temp_mtr.commit();
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-08-11 12:47:54 +03:00
|
|
|
trx_rseg_t* rseg = trx->rsegs.m_redo.rseg;
|
|
|
|
if (!rseg) {
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
ut_ad(!trx->rsegs.m_redo.undo);
|
|
|
|
ut_ad(!trx->rsegs.m_redo.old_insert);
|
2018-01-28 16:02:48 +04:00
|
|
|
return;
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-08-11 12:47:54 +03:00
|
|
|
trx_undo_t*& undo = trx->rsegs.m_redo.undo;
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
trx_undo_t*& old_insert = trx->rsegs.m_redo.old_insert;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
if (!undo && !old_insert) {
|
2018-01-28 16:02:48 +04:00
|
|
|
return;
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
ut_ad(!trx->read_only);
|
2017-08-11 12:47:54 +03:00
|
|
|
ut_ad(!undo || undo->rseg == rseg);
|
|
|
|
ut_ad(!old_insert || old_insert->rseg == rseg);
|
|
|
|
mutex_enter(&rseg->mutex);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
/* Assign the transaction serialisation number and add any
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
undo log to the purge queue. */
|
2018-01-28 16:02:48 +04:00
|
|
|
trx_serialise(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
if (UNIV_LIKELY_NULL(old_insert)) {
|
|
|
|
UT_LIST_REMOVE(rseg->old_insert_list, old_insert);
|
2017-08-11 12:47:54 +03:00
|
|
|
trx_purge_add_undo_to_history(trx, old_insert, mtr);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
if (undo) {
|
2017-08-11 12:47:54 +03:00
|
|
|
UT_LIST_REMOVE(rseg->undo_list, undo);
|
|
|
|
trx_purge_add_undo_to_history(trx, undo, mtr);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2017-08-11 12:47:54 +03:00
|
|
|
mutex_exit(&rseg->mutex);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
|
|
|
|
|
2018-02-20 15:10:03 +02:00
|
|
|
trx->mysql_log_file_name = NULL;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************
|
|
|
|
Finalize a transaction containing updates for a FTS table. */
|
2016-09-06 09:43:16 +03:00
|
|
|
static
|
2012-08-01 17:27:34 +03:00
|
|
|
void
|
|
|
|
trx_finalize_for_fts_table(
|
|
|
|
/*=======================*/
|
2016-08-12 11:17:45 +03:00
|
|
|
fts_trx_table_t* ftt) /* in: FTS trx table */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
fts_t* fts = ftt->table->fts;
|
|
|
|
fts_doc_ids_t* doc_ids = ftt->added_doc_ids;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2019-09-18 13:22:08 +05:30
|
|
|
ut_a(fts->add_wq);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2019-09-18 16:24:48 +03:00
|
|
|
mem_heap_t* heap = static_cast<mem_heap_t*>(doc_ids->self_heap->arg);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2019-09-18 13:22:08 +05:30
|
|
|
ib_wqueue_add(fts->add_wq, doc_ids, heap);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2019-09-18 13:22:08 +05:30
|
|
|
/* fts_trx_table_t no longer owns the list. */
|
|
|
|
ftt->added_doc_ids = NULL;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
/******************************************************************//**
|
2012-08-01 17:27:34 +03:00
|
|
|
Finalize a transaction containing updates to FTS tables. */
|
2016-09-06 09:43:16 +03:00
|
|
|
static
|
2012-08-01 17:27:34 +03:00
|
|
|
void
|
|
|
|
trx_finalize_for_fts(
|
|
|
|
/*=================*/
|
2014-02-01 09:33:26 +01:00
|
|
|
trx_t* trx, /*!< in/out: transaction */
|
|
|
|
bool is_commit) /*!< in: true if the transaction was
|
|
|
|
committed, false if it was rolled back. */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
|
|
|
if (is_commit) {
|
2014-02-01 09:33:26 +01:00
|
|
|
const ib_rbt_node_t* node;
|
|
|
|
ib_rbt_t* tables;
|
|
|
|
fts_savepoint_t* savepoint;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
savepoint = static_cast<fts_savepoint_t*>(
|
|
|
|
ib_vector_last(trx->fts_trx->savepoints));
|
|
|
|
|
|
|
|
tables = savepoint->tables;
|
|
|
|
|
|
|
|
for (node = rbt_first(tables);
|
|
|
|
node;
|
|
|
|
node = rbt_next(tables, node)) {
|
2014-02-01 09:33:26 +01:00
|
|
|
fts_trx_table_t** ftt;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
ftt = rbt_value(fts_trx_table_t*, node);
|
|
|
|
|
|
|
|
if ((*ftt)->added_doc_ids) {
|
|
|
|
trx_finalize_for_fts_table(*ftt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fts_trx_free(trx->fts_trx);
|
|
|
|
trx->fts_trx = NULL;
|
|
|
|
}
|
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
/**********************************************************************//**
|
|
|
|
If required, flushes the log to disk based on the value of
|
|
|
|
innodb_flush_log_at_trx_commit. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_flush_log_if_needed_low(
|
|
|
|
/*========================*/
|
|
|
|
lsn_t lsn) /*!< in: lsn up to which logs are to be
|
|
|
|
flushed. */
|
|
|
|
{
|
2017-03-09 14:32:17 +00:00
|
|
|
bool flush = srv_file_flush_method != SRV_NOSYNC;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
switch (srv_flush_log_at_trx_commit) {
|
2016-09-06 09:43:16 +03:00
|
|
|
case 3:
|
2013-03-26 00:03:13 +02:00
|
|
|
case 2:
|
|
|
|
/* Write the log but do not flush it to disk */
|
2016-08-12 11:17:45 +03:00
|
|
|
flush = false;
|
|
|
|
/* fall through */
|
|
|
|
case 1:
|
|
|
|
/* Write the log and optionally flush it to disk */
|
|
|
|
log_write_up_to(lsn, flush);
|
|
|
|
return;
|
|
|
|
case 0:
|
|
|
|
/* Do nothing */
|
|
|
|
return;
|
2013-03-26 00:03:13 +02:00
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
ut_error;
|
2013-03-26 00:03:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
If required, flushes the log to disk based on the value of
|
|
|
|
innodb_flush_log_at_trx_commit. */
|
2016-09-06 09:43:16 +03:00
|
|
|
static
|
2013-03-26 00:03:13 +02:00
|
|
|
void
|
|
|
|
trx_flush_log_if_needed(
|
|
|
|
/*====================*/
|
|
|
|
lsn_t lsn, /*!< in: lsn up to which logs are to be
|
|
|
|
flushed. */
|
|
|
|
trx_t* trx) /*!< in/out: transaction */
|
|
|
|
{
|
|
|
|
trx->op_info = "flushing log";
|
|
|
|
trx_flush_log_if_needed_low(lsn);
|
|
|
|
trx->op_info = "";
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/**********************************************************************//**
|
|
|
|
For each table that has been modified by the given transaction: update
|
|
|
|
its dict_table_t::update_time with the current timestamp. Clear the list
|
|
|
|
of the modified tables at the end. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_update_mod_tables_timestamp(
|
|
|
|
/*============================*/
|
|
|
|
trx_t* trx) /*!< in: transaction */
|
|
|
|
{
|
|
|
|
/* consider using trx->start_time if calling time() is too
|
|
|
|
expensive here */
|
2019-07-25 15:31:11 +03:00
|
|
|
const time_t now = time(NULL);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
trx_mod_tables_t::const_iterator end = trx->mod_tables.end();
|
2019-08-23 17:43:55 +03:00
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
const bool preserve_tables = !innodb_evict_tables_on_commit_debug
|
|
|
|
|| trx->is_recovered /* avoid trouble with XA recovery */
|
|
|
|
# if 1 /* if dict_stats_exec_sql() were not playing dirty tricks */
|
2019-09-23 10:33:10 +03:00
|
|
|
|| mutex_own(&dict_sys.mutex)
|
2019-08-23 17:43:55 +03:00
|
|
|
# else /* this would be more proper way to do it */
|
|
|
|
|| trx->dict_operation_lock_mode || trx->dict_operation
|
|
|
|
# endif
|
|
|
|
;
|
|
|
|
#endif
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
for (trx_mod_tables_t::const_iterator it = trx->mod_tables.begin();
|
|
|
|
it != end;
|
|
|
|
++it) {
|
|
|
|
|
|
|
|
/* This could be executed by multiple threads concurrently
|
|
|
|
on the same table object. This is fine because time_t is
|
|
|
|
word size or less. And _purely_ _theoretically_, even if
|
|
|
|
time_t write is not atomic, likely the value of 'now' is
|
|
|
|
the same in all threads and even if it is not, getting a
|
|
|
|
"garbage" in table->update_time is justified because
|
|
|
|
protecting it with a latch here would be too performance
|
|
|
|
intrusive. */
|
2019-08-23 17:43:55 +03:00
|
|
|
dict_table_t* table = it->first;
|
|
|
|
table->update_time = now;
|
|
|
|
#ifdef UNIV_DEBUG
|
2020-07-21 15:59:45 +03:00
|
|
|
if (preserve_tables || table->get_ref_count()
|
|
|
|
|| UT_LIST_GET_LEN(table->locks)) {
|
2019-08-23 17:43:55 +03:00
|
|
|
/* do not evict when committing DDL operations
|
|
|
|
or if some other transaction is holding the
|
|
|
|
table handle */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* recheck while holding the mutex that blocks
|
|
|
|
table->acquire() */
|
2019-09-23 10:33:10 +03:00
|
|
|
mutex_enter(&dict_sys.mutex);
|
2020-07-21 15:59:45 +03:00
|
|
|
mutex_enter(&lock_sys.mutex);
|
|
|
|
const bool do_evict = !table->get_ref_count()
|
|
|
|
&& !UT_LIST_GET_LEN(table->locks);
|
|
|
|
mutex_exit(&lock_sys.mutex);
|
|
|
|
if (do_evict) {
|
2019-08-23 17:43:55 +03:00
|
|
|
dict_sys.remove(table, true);
|
|
|
|
}
|
2019-09-23 10:33:10 +03:00
|
|
|
mutex_exit(&dict_sys.mutex);
|
2019-08-23 17:43:55 +03:00
|
|
|
#endif
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
trx->mod_tables.clear();
|
|
|
|
}
|
|
|
|
|
2018-10-10 12:44:10 +03:00
|
|
|
/** Evict a table definition due to the rollback of ALTER TABLE.
|
|
|
|
@param[in] table_id table identifier */
|
|
|
|
void trx_t::evict_table(table_id_t table_id)
|
|
|
|
{
|
|
|
|
ut_ad(in_rollback);
|
|
|
|
|
|
|
|
dict_table_t* table = dict_table_open_on_id(
|
|
|
|
table_id, true, DICT_TABLE_OP_OPEN_ONLY_IF_CACHED);
|
|
|
|
if (!table) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!table->release()) {
|
|
|
|
/* This must be a DDL operation that is being rolled
|
|
|
|
back in an active connection. */
|
|
|
|
ut_a(table->get_ref_count() == 1);
|
|
|
|
ut_ad(!is_recovered);
|
|
|
|
ut_ad(mysql_thd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This table should only be locked by this transaction, if at all. */
|
|
|
|
ut_ad(UT_LIST_GET_LEN(table->locks) <= 1);
|
|
|
|
const bool locked = UT_LIST_GET_LEN(table->locks);
|
|
|
|
ut_ad(!locked || UT_LIST_GET_FIRST(table->locks)->trx == this);
|
2019-05-17 14:32:53 +03:00
|
|
|
dict_sys.remove(table, true, locked);
|
2018-10-10 12:44:10 +03:00
|
|
|
if (locked) {
|
|
|
|
UT_LIST_ADD_FIRST(lock.evicted_tables, table);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
/** Mark a transaction committed in the main memory data structures. */
|
|
|
|
inline void trx_t::commit_in_memory(const mtr_t *mtr)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2020-04-29 11:50:03 +03:00
|
|
|
must_flush_log_later= false;
|
|
|
|
read_view.close();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
if (trx_is_autocommit_non_locking(this))
|
|
|
|
{
|
|
|
|
ut_ad(id == 0);
|
|
|
|
ut_ad(read_only);
|
|
|
|
ut_a(!is_recovered);
|
|
|
|
ut_ad(!rsegs.m_redo.rseg);
|
|
|
|
|
|
|
|
/* Note: We are asserting without holding the lock mutex. But
|
|
|
|
that is OK because this transaction is not waiting and cannot
|
|
|
|
be rolled back and no new locks can (or should) be added
|
|
|
|
because it is flagged as a non-locking read-only transaction. */
|
|
|
|
ut_a(UT_LIST_GET_LEN(lock.trx_locks) == 0);
|
|
|
|
|
|
|
|
/* This state change is not protected by any mutex, therefore
|
|
|
|
there is an inherent race here around state transition during
|
|
|
|
printouts. We ignore this race for the sake of efficiency.
|
|
|
|
However, the trx_sys_t::mutex will protect the trx_t instance
|
|
|
|
and it cannot be removed from the trx_list and freed
|
|
|
|
without first acquiring the trx_sys_t::mutex. */
|
|
|
|
ut_ad(trx_state_eq(this, TRX_STATE_ACTIVE));
|
|
|
|
|
|
|
|
MONITOR_INC(MONITOR_TRX_NL_RO_COMMIT);
|
|
|
|
|
|
|
|
DBUG_LOG("trx", "Autocommit in memory: " << this);
|
|
|
|
state= TRX_STATE_NOT_STARTED;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-09-18 20:19:03 +05:30
|
|
|
#ifdef UNIV_DEBUG
|
2020-04-29 11:50:03 +03:00
|
|
|
if (!UT_LIST_GET_LEN(lock.trx_locks))
|
|
|
|
for (auto l : lock.table_locks)
|
|
|
|
ut_ad(!l);
|
2019-09-18 20:19:03 +05:30
|
|
|
#endif /* UNIV_DEBUG */
|
2020-04-29 11:50:03 +03:00
|
|
|
commit_state();
|
|
|
|
|
|
|
|
if (id)
|
|
|
|
{
|
|
|
|
trx_sys.deregister_rw(this);
|
|
|
|
|
|
|
|
/* Wait for any implicit-to-explicit lock conversions to cease,
|
|
|
|
so that there will be no race condition in lock_release(). */
|
|
|
|
while (UNIV_UNLIKELY(is_referenced()))
|
|
|
|
ut_delay(srv_spin_wait_delay);
|
|
|
|
release_locks();
|
|
|
|
id= 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ut_ad(read_only || !rsegs.m_redo.rseg);
|
|
|
|
release_locks();
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_SYNC_C("after_trx_committed_in_memory");
|
|
|
|
|
|
|
|
if (read_only || !rsegs.m_redo.rseg)
|
|
|
|
{
|
|
|
|
MONITOR_INC(MONITOR_TRX_RO_COMMIT);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
trx_update_mod_tables_timestamp(this);
|
|
|
|
MONITOR_INC(MONITOR_TRX_RW_COMMIT);
|
|
|
|
is_recovered= false;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (dict_table_t *table= UT_LIST_GET_FIRST(lock.evicted_tables))
|
|
|
|
{
|
|
|
|
UT_LIST_REMOVE(lock.evicted_tables, table);
|
|
|
|
dict_mem_table_free(table);
|
|
|
|
}
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
ut_ad(!rsegs.m_redo.undo);
|
|
|
|
ut_ad(UT_LIST_GET_LEN(lock.evicted_tables) == 0);
|
2014-11-18 17:41:12 +01:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
if (trx_rseg_t *rseg= rsegs.m_redo.rseg)
|
|
|
|
{
|
|
|
|
mutex_enter(&rseg->mutex);
|
|
|
|
ut_ad(rseg->trx_ref_count > 0);
|
|
|
|
--rseg->trx_ref_count;
|
|
|
|
mutex_exit(&rseg->mutex);
|
|
|
|
|
|
|
|
if (trx_undo_t *&insert= rsegs.m_redo.old_insert)
|
|
|
|
{
|
|
|
|
ut_ad(insert->rseg == rseg);
|
|
|
|
trx_undo_commit_cleanup(insert, false);
|
|
|
|
insert= nullptr;
|
|
|
|
}
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
ut_ad(!rsegs.m_redo.old_insert);
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
if (mtr)
|
|
|
|
{
|
|
|
|
if (trx_undo_t *&undo= rsegs.m_noredo.undo)
|
|
|
|
{
|
|
|
|
ut_ad(undo->rseg == rsegs.m_noredo.rseg);
|
|
|
|
trx_undo_commit_cleanup(undo, true);
|
|
|
|
undo= nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NOTE that we could possibly make a group commit more efficient
|
|
|
|
here: call os_thread_yield here to allow also other trxs to come
|
|
|
|
to commit! */
|
|
|
|
|
|
|
|
/*-------------------------------------*/
|
|
|
|
|
|
|
|
/* Depending on the my.cnf options, we may now write the log
|
|
|
|
buffer to the log files, making the transaction durable if the OS
|
|
|
|
does not crash. We may also flush the log files to disk, making
|
|
|
|
the transaction durable also at an OS crash or a power outage.
|
|
|
|
|
|
|
|
The idea in InnoDB's group commit is that a group of transactions
|
|
|
|
gather behind a trx doing a physical disk write to log files, and
|
|
|
|
when that physical write has been completed, one of those
|
|
|
|
transactions does a write which commits the whole group. Note that
|
|
|
|
this group commit will only bring benefit if there are > 2 users
|
|
|
|
in the database. Then at least 2 users can gather behind one doing
|
|
|
|
the physical log write to disk.
|
|
|
|
|
|
|
|
If we are calling trx_t::commit() under prepare_commit_mutex, we
|
|
|
|
will delay possible log write and flush to a separate function
|
|
|
|
trx_commit_complete_for_mysql(), which is only called when the
|
|
|
|
thread has released the mutex. This is to make the group commit
|
|
|
|
algorithm to work. Otherwise, the prepare_commit mutex would
|
|
|
|
serialize all commits and prevent a group of transactions from
|
|
|
|
gathering. */
|
|
|
|
|
|
|
|
commit_lsn= mtr->commit_lsn();
|
|
|
|
if (!commit_lsn)
|
|
|
|
/* Nothing to be done. */;
|
|
|
|
else if (flush_log_later)
|
|
|
|
/* Do nothing yet */
|
|
|
|
must_flush_log_later= true;
|
|
|
|
else if (srv_flush_log_at_trx_commit)
|
|
|
|
trx_flush_log_if_needed(commit_lsn, this);
|
2020-08-20 11:01:47 +03:00
|
|
|
|
|
|
|
/* Tell server some activity has happened, since the trx does
|
|
|
|
changes something. Background utility threads like master thread,
|
|
|
|
purge thread or page_cleaner thread might have some work to do. */
|
|
|
|
srv_active_wake_master_thread();
|
2020-04-29 11:50:03 +03:00
|
|
|
}
|
2013-03-26 00:03:13 +02:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
ut_ad(!rsegs.m_noredo.undo);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
/* Free all savepoints, starting from the first. */
|
|
|
|
trx_named_savept_t *savep= UT_LIST_GET_FIRST(trx_savepoints);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
trx_roll_savepoints_free(this, savep);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
if (fts_trx)
|
|
|
|
trx_finalize_for_fts(this, undo_no != 0);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2020-05-04 18:19:13 +03:00
|
|
|
#ifdef WITH_WSREP
|
|
|
|
/* Serialization history has been written and the transaction is
|
|
|
|
committed in memory, which makes this commit ordered. Release commit
|
|
|
|
order critical section. */
|
|
|
|
if (wsrep)
|
|
|
|
{
|
|
|
|
wsrep= false;
|
|
|
|
wsrep_commit_ordered(mysql_thd);
|
|
|
|
}
|
2020-05-14 09:17:14 +03:00
|
|
|
lock.was_chosen_as_wsrep_victim= false;
|
2020-05-04 18:19:13 +03:00
|
|
|
#endif /* WITH_WSREP */
|
2020-05-25 14:23:42 +03:00
|
|
|
trx_mutex_enter(this);
|
|
|
|
dict_operation= TRX_DICT_OP_NONE;
|
|
|
|
|
|
|
|
DBUG_LOG("trx", "Commit in memory: " << this);
|
|
|
|
state= TRX_STATE_NOT_STARTED;
|
2020-05-04 18:19:13 +03:00
|
|
|
|
2020-05-14 09:17:14 +03:00
|
|
|
assert_freed();
|
2020-04-29 11:50:03 +03:00
|
|
|
trx_init(this);
|
|
|
|
trx_mutex_exit(this);
|
2016-09-06 09:43:16 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
ut_a(error_state == DB_SUCCESS);
|
|
|
|
if (!srv_read_only_mode)
|
|
|
|
srv_wake_purge_thread_if_not_active();
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
/** Commit the transaction in a mini-transaction.
|
|
|
|
@param mtr mini-transaction (if there are any persistent modifications) */
|
|
|
|
void trx_t::commit_low(mtr_t *mtr)
|
2014-02-01 09:33:26 +01:00
|
|
|
{
|
2020-04-29 11:50:03 +03:00
|
|
|
assert_trx_nonlocking_or_in_list(this);
|
|
|
|
ut_ad(!trx_state_eq(this, TRX_STATE_COMMITTED_IN_MEMORY));
|
|
|
|
ut_ad(!mtr || mtr->is_active());
|
|
|
|
ut_d(bool aborted = in_rollback && error_state == DB_DEADLOCK);
|
|
|
|
ut_ad(!mtr == (aborted || !has_logged_or_recovered()));
|
|
|
|
ut_ad(!mtr || !aborted);
|
|
|
|
|
|
|
|
/* undo_no is non-zero if we're doing the final commit. */
|
|
|
|
if (fts_trx && undo_no)
|
|
|
|
{
|
|
|
|
ut_a(!trx_is_autocommit_non_locking(this));
|
|
|
|
dberr_t error= fts_commit(this);
|
|
|
|
/* FTS-FIXME: Temporarily tolerate DB_DUPLICATE_KEY instead of
|
|
|
|
dying. This is a possible scenario if there is a crash between
|
|
|
|
insert to DELETED table committing and transaction committing. The
|
|
|
|
fix would be able to return error from this function */
|
|
|
|
ut_a(error == DB_SUCCESS || error == DB_DUPLICATE_KEY);
|
|
|
|
}
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2018-09-10 15:40:11 +03:00
|
|
|
#ifndef DBUG_OFF
|
2020-04-29 11:50:03 +03:00
|
|
|
const bool debug_sync= mysql_thd && has_logged_persistent();
|
2018-09-10 15:40:11 +03:00
|
|
|
#endif
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
if (mtr)
|
|
|
|
{
|
|
|
|
trx_write_serialisation_history(this, mtr);
|
|
|
|
|
|
|
|
/* The following call commits the mini-transaction, making the
|
|
|
|
whole transaction committed in the file-based world, at this log
|
|
|
|
sequence number. The transaction becomes 'durable' when we write
|
|
|
|
the log to disk, but in the logical sense the commit in the
|
|
|
|
file-based data structures (undo logs etc.) happens here.
|
|
|
|
|
|
|
|
NOTE that transaction numbers, which are assigned only to
|
|
|
|
transactions with an update undo log, do not necessarily come in
|
|
|
|
exactly the same order as commit lsn's, if the transactions have
|
|
|
|
different rollback segments. To get exactly the same order we
|
|
|
|
should hold the kernel mutex up to this point, adding to the
|
|
|
|
contention of the kernel mutex. However, if a transaction T2 is
|
|
|
|
able to see modifications made by a transaction T1, T2 will always
|
|
|
|
get a bigger transaction number and a bigger commit lsn than T1. */
|
|
|
|
|
|
|
|
mtr->commit();
|
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
#ifndef DBUG_OFF
|
2020-04-29 11:50:03 +03:00
|
|
|
if (debug_sync)
|
|
|
|
DEBUG_SYNC_C("before_trx_state_committed_in_memory");
|
2016-08-12 11:17:45 +03:00
|
|
|
#endif
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
commit_in_memory(mtr);
|
2014-02-01 09:33:26 +01:00
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
void trx_t::commit()
|
|
|
|
{
|
|
|
|
mtr_t *mtr= nullptr;
|
|
|
|
mtr_t local_mtr;
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2020-04-29 11:50:03 +03:00
|
|
|
if (has_logged_or_recovered())
|
|
|
|
{
|
|
|
|
mtr= &local_mtr;
|
|
|
|
local_mtr.start();
|
|
|
|
}
|
|
|
|
commit_low(mtr);
|
2014-02-01 09:33:26 +01:00
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/****************************************************************//**
|
|
|
|
Prepares a transaction for commit/rollback. */
|
|
|
|
void
|
|
|
|
trx_commit_or_rollback_prepare(
|
|
|
|
/*===========================*/
|
|
|
|
trx_t* trx) /*!< in/out: transaction */
|
|
|
|
{
|
2017-12-22 16:15:41 +02:00
|
|
|
/* We are reading trx->state without holding trx_sys.mutex
|
2012-08-01 17:27:34 +03:00
|
|
|
here, because the commit or rollback should be invoked for a
|
|
|
|
running (or recovered prepared) transaction that is associated
|
|
|
|
with the current thread. */
|
|
|
|
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_start_low(trx, true);
|
2012-08-01 17:27:34 +03:00
|
|
|
/* fall through */
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_ACTIVE:
|
|
|
|
case TRX_STATE_PREPARED:
|
2019-04-24 12:03:11 +03:00
|
|
|
case TRX_STATE_PREPARED_RECOVERED:
|
2012-08-01 17:27:34 +03:00
|
|
|
/* If the trx is in a lock wait state, moves the waiting
|
|
|
|
query thread to the suspended state */
|
|
|
|
|
|
|
|
if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
|
|
|
|
|
|
|
|
ut_a(trx->lock.wait_thr != NULL);
|
|
|
|
trx->lock.wait_thr->state = QUE_THR_SUSPENDED;
|
|
|
|
trx->lock.wait_thr = NULL;
|
|
|
|
|
|
|
|
trx->lock.que_state = TRX_QUE_RUNNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_a(trx->lock.n_active_thrs == 1);
|
|
|
|
return;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************//**
|
|
|
|
Creates a commit command node struct.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return own: commit node struct */
|
2012-08-01 17:27:34 +03:00
|
|
|
commit_node_t*
|
|
|
|
trx_commit_node_create(
|
|
|
|
/*===================*/
|
|
|
|
mem_heap_t* heap) /*!< in: mem heap where created */
|
|
|
|
{
|
|
|
|
commit_node_t* node;
|
|
|
|
|
|
|
|
node = static_cast<commit_node_t*>(mem_heap_alloc(heap, sizeof(*node)));
|
|
|
|
node->common.type = QUE_NODE_COMMIT;
|
|
|
|
node->state = COMMIT_NODE_SEND;
|
|
|
|
|
|
|
|
return(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************//**
|
|
|
|
Performs an execution step for a commit type node in a query graph.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return query thread to run next, or NULL */
|
2012-08-01 17:27:34 +03:00
|
|
|
que_thr_t*
|
|
|
|
trx_commit_step(
|
|
|
|
/*============*/
|
|
|
|
que_thr_t* thr) /*!< in: query thread */
|
|
|
|
{
|
|
|
|
commit_node_t* node;
|
|
|
|
|
|
|
|
node = static_cast<commit_node_t*>(thr->run_node);
|
|
|
|
|
|
|
|
ut_ad(que_node_get_type(node) == QUE_NODE_COMMIT);
|
|
|
|
|
|
|
|
if (thr->prev_node == que_node_get_parent(node)) {
|
|
|
|
node->state = COMMIT_NODE_SEND;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->state == COMMIT_NODE_SEND) {
|
|
|
|
trx_t* trx;
|
|
|
|
|
|
|
|
node->state = COMMIT_NODE_WAIT;
|
|
|
|
|
|
|
|
trx = thr_get_trx(thr);
|
|
|
|
|
|
|
|
ut_a(trx->lock.wait_thr == NULL);
|
|
|
|
ut_a(trx->lock.que_state != TRX_QUE_LOCK_WAIT);
|
|
|
|
|
|
|
|
trx_commit_or_rollback_prepare(trx);
|
|
|
|
|
|
|
|
trx->lock.que_state = TRX_QUE_COMMITTING;
|
2020-04-29 11:50:03 +03:00
|
|
|
trx->commit();
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_ad(trx->lock.wait_thr == NULL);
|
|
|
|
trx->lock.que_state = TRX_QUE_RUNNING;
|
|
|
|
|
|
|
|
thr = NULL;
|
|
|
|
} else {
|
|
|
|
ut_ad(node->state == COMMIT_NODE_WAIT);
|
|
|
|
|
|
|
|
node->state = COMMIT_NODE_SEND;
|
|
|
|
|
|
|
|
thr->run_node = que_node_get_parent(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(thr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
Does the transaction commit for MySQL.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return DB_SUCCESS or error number */
|
2013-03-26 00:03:13 +02:00
|
|
|
dberr_t
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_commit_for_mysql(
|
|
|
|
/*=================*/
|
|
|
|
trx_t* trx) /*!< in/out: transaction */
|
|
|
|
{
|
|
|
|
/* Because we do not do the commit by sending an Innobase
|
|
|
|
sig to the transaction, we must here make sure that trx has been
|
|
|
|
started. */
|
|
|
|
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
2013-03-26 00:03:13 +02:00
|
|
|
ut_d(trx->start_file = __FILE__);
|
|
|
|
ut_d(trx->start_line = __LINE__);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_start_low(trx, true);
|
2012-08-01 17:27:34 +03:00
|
|
|
/* fall through */
|
|
|
|
case TRX_STATE_ACTIVE:
|
|
|
|
case TRX_STATE_PREPARED:
|
2019-04-24 12:03:11 +03:00
|
|
|
case TRX_STATE_PREPARED_RECOVERED:
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->op_info = "committing";
|
2020-04-29 11:50:03 +03:00
|
|
|
trx->commit();
|
2012-08-01 17:27:34 +03:00
|
|
|
MONITOR_DEC(MONITOR_TRX_ACTIVE);
|
|
|
|
trx->op_info = "";
|
|
|
|
return(DB_SUCCESS);
|
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ut_error;
|
|
|
|
return(DB_CORRUPTION);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
If required, flushes the log to disk if we called trx_commit_for_mysql()
|
2013-03-26 00:03:13 +02:00
|
|
|
with trx->flush_log_later == TRUE. */
|
|
|
|
void
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_commit_complete_for_mysql(
|
|
|
|
/*==========================*/
|
2013-03-26 00:03:13 +02:00
|
|
|
trx_t* trx) /*!< in/out: transaction */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->id != 0
|
|
|
|
|| !trx->must_flush_log_later
|
2017-08-07 12:38:47 +02:00
|
|
|
|| (srv_flush_log_at_trx_commit == 1 && trx->active_commit_ordered)) {
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
return;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
trx_flush_log_if_needed(trx->commit_lsn, trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->must_flush_log_later = false;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
Marks the latest SQL statement ended. */
|
|
|
|
void
|
|
|
|
trx_mark_sql_stat_end(
|
|
|
|
/*==================*/
|
|
|
|
trx_t* trx) /*!< in: trx handle */
|
|
|
|
{
|
|
|
|
ut_a(trx);
|
|
|
|
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_PREPARED:
|
2019-04-24 12:03:11 +03:00
|
|
|
case TRX_STATE_PREPARED_RECOVERED:
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
break;
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
|
|
|
trx->undo_no = 0;
|
|
|
|
/* fall through */
|
|
|
|
case TRX_STATE_ACTIVE:
|
|
|
|
trx->last_sql_stat_start.least_undo_no = trx->undo_no;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->fts_trx != NULL) {
|
2012-08-01 17:27:34 +03:00
|
|
|
fts_savepoint_laststmt_refresh(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
2017-12-27 15:38:23 +04:00
|
|
|
Prints info about a transaction. */
|
2012-08-01 17:27:34 +03:00
|
|
|
void
|
|
|
|
trx_print_low(
|
|
|
|
/*==========*/
|
|
|
|
FILE* f,
|
|
|
|
/*!< in: output stream */
|
|
|
|
const trx_t* trx,
|
|
|
|
/*!< in: transaction */
|
|
|
|
ulint max_query_len,
|
|
|
|
/*!< in: max query length to print,
|
|
|
|
or 0 to use the default max length */
|
2013-03-26 00:03:13 +02:00
|
|
|
ulint n_rec_locks,
|
2012-08-01 17:27:34 +03:00
|
|
|
/*!< in: lock_number_of_rows_locked(&trx->lock) */
|
2013-03-26 00:03:13 +02:00
|
|
|
ulint n_trx_locks,
|
2012-08-01 17:27:34 +03:00
|
|
|
/*!< in: length of trx->lock.trx_locks */
|
|
|
|
ulint heap_size)
|
|
|
|
/*!< in: mem_heap_get_size(trx->lock.lock_heap) */
|
|
|
|
{
|
|
|
|
ibool newline;
|
|
|
|
const char* op_info;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
fprintf(f, "TRANSACTION " TRX_ID_FMT, trx_get_id_for_print(trx));
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* trx->state cannot change from or to NOT_STARTED while we
|
2017-12-22 16:15:41 +02:00
|
|
|
are holding the trx_sys.mutex. It may change from ACTIVE to
|
2012-08-01 17:27:34 +03:00
|
|
|
PREPARED or COMMITTED. */
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
|
|
|
fputs(", not started", f);
|
|
|
|
goto state_ok;
|
|
|
|
case TRX_STATE_ACTIVE:
|
|
|
|
fprintf(f, ", ACTIVE %lu sec",
|
|
|
|
(ulong) difftime(time(NULL), trx->start_time));
|
|
|
|
goto state_ok;
|
|
|
|
case TRX_STATE_PREPARED:
|
2019-04-24 12:03:11 +03:00
|
|
|
case TRX_STATE_PREPARED_RECOVERED:
|
2012-08-01 17:27:34 +03:00
|
|
|
fprintf(f, ", ACTIVE (PREPARED) %lu sec",
|
|
|
|
(ulong) difftime(time(NULL), trx->start_time));
|
|
|
|
goto state_ok;
|
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
fputs(", COMMITTED IN MEMORY", f);
|
|
|
|
goto state_ok;
|
|
|
|
}
|
|
|
|
fprintf(f, ", state %lu", (ulong) trx->state);
|
|
|
|
ut_ad(0);
|
|
|
|
state_ok:
|
|
|
|
|
|
|
|
/* prevent a race condition */
|
|
|
|
op_info = trx->op_info;
|
|
|
|
|
|
|
|
if (*op_info) {
|
|
|
|
putc(' ', f);
|
|
|
|
fputs(op_info, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trx->is_recovered) {
|
|
|
|
fputs(" recovered trx", f);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trx->declared_to_be_inside_innodb) {
|
|
|
|
fprintf(f, ", thread declared inside InnoDB %lu",
|
|
|
|
(ulong) trx->n_tickets_to_enter_innodb);
|
|
|
|
}
|
|
|
|
|
|
|
|
putc('\n', f);
|
|
|
|
|
|
|
|
if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
|
|
|
|
fprintf(f, "mysql tables in use %lu, locked %lu\n",
|
|
|
|
(ulong) trx->n_mysql_tables_in_use,
|
|
|
|
(ulong) trx->mysql_n_tables_locked);
|
|
|
|
}
|
|
|
|
|
|
|
|
newline = TRUE;
|
|
|
|
|
|
|
|
/* trx->lock.que_state of an ACTIVE transaction may change
|
|
|
|
while we are not holding trx->mutex. We perform a dirty read
|
|
|
|
for performance reasons. */
|
|
|
|
|
|
|
|
switch (trx->lock.que_state) {
|
|
|
|
case TRX_QUE_RUNNING:
|
|
|
|
newline = FALSE; break;
|
|
|
|
case TRX_QUE_LOCK_WAIT:
|
|
|
|
fputs("LOCK WAIT ", f); break;
|
|
|
|
case TRX_QUE_ROLLING_BACK:
|
|
|
|
fputs("ROLLING BACK ", f); break;
|
|
|
|
case TRX_QUE_COMMITTING:
|
|
|
|
fputs("COMMITTING ", f); break;
|
|
|
|
default:
|
|
|
|
fprintf(f, "que state %lu ", (ulong) trx->lock.que_state);
|
|
|
|
}
|
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
if (n_trx_locks > 0 || heap_size > 400) {
|
2012-08-01 17:27:34 +03:00
|
|
|
newline = TRUE;
|
|
|
|
|
|
|
|
fprintf(f, "%lu lock struct(s), heap size %lu,"
|
|
|
|
" %lu row lock(s)",
|
2013-03-26 00:03:13 +02:00
|
|
|
(ulong) n_trx_locks,
|
2012-08-01 17:27:34 +03:00
|
|
|
(ulong) heap_size,
|
2013-03-26 00:03:13 +02:00
|
|
|
(ulong) n_rec_locks);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (trx->undo_no != 0) {
|
|
|
|
newline = TRUE;
|
2014-06-09 18:16:00 +02:00
|
|
|
fprintf(f, ", undo log entries " TRX_ID_FMT, trx->undo_no);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (newline) {
|
|
|
|
putc('\n', f);
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->state != TRX_STATE_NOT_STARTED && trx->mysql_thd != NULL) {
|
2014-05-06 21:13:16 +02:00
|
|
|
innobase_mysql_print_thd(
|
|
|
|
f, trx->mysql_thd, static_cast<uint>(max_query_len));
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
Prints info about a transaction.
|
2018-02-22 20:46:42 +04:00
|
|
|
The caller must hold lock_sys.mutex.
|
2012-08-01 17:27:34 +03:00
|
|
|
When possible, use trx_print() instead. */
|
|
|
|
void
|
|
|
|
trx_print_latched(
|
|
|
|
/*==============*/
|
|
|
|
FILE* f, /*!< in: output stream */
|
|
|
|
const trx_t* trx, /*!< in: transaction */
|
|
|
|
ulint max_query_len) /*!< in: max query length to print,
|
|
|
|
or 0 to use the default max length */
|
|
|
|
{
|
|
|
|
ut_ad(lock_mutex_own());
|
|
|
|
|
|
|
|
trx_print_low(f, trx, max_query_len,
|
|
|
|
lock_number_of_rows_locked(&trx->lock),
|
|
|
|
UT_LIST_GET_LEN(trx->lock.trx_locks),
|
|
|
|
mem_heap_get_size(trx->lock.lock_heap));
|
|
|
|
}
|
|
|
|
|
2017-03-23 15:46:11 +05:30
|
|
|
/**********************************************************************//**
|
|
|
|
Prints info about a transaction.
|
2018-02-22 20:46:42 +04:00
|
|
|
Acquires and releases lock_sys.mutex. */
|
2012-08-01 17:27:34 +03:00
|
|
|
void
|
|
|
|
trx_print(
|
|
|
|
/*======*/
|
|
|
|
FILE* f, /*!< in: output stream */
|
|
|
|
const trx_t* trx, /*!< in: transaction */
|
|
|
|
ulint max_query_len) /*!< in: max query length to print,
|
|
|
|
or 0 to use the default max length */
|
|
|
|
{
|
2013-03-26 00:03:13 +02:00
|
|
|
ulint n_rec_locks;
|
|
|
|
ulint n_trx_locks;
|
2012-08-01 17:27:34 +03:00
|
|
|
ulint heap_size;
|
|
|
|
|
|
|
|
lock_mutex_enter();
|
2013-03-26 00:03:13 +02:00
|
|
|
n_rec_locks = lock_number_of_rows_locked(&trx->lock);
|
|
|
|
n_trx_locks = UT_LIST_GET_LEN(trx->lock.trx_locks);
|
2012-08-01 17:27:34 +03:00
|
|
|
heap_size = mem_heap_get_size(trx->lock.lock_heap);
|
|
|
|
lock_mutex_exit();
|
|
|
|
|
|
|
|
trx_print_low(f, trx, max_query_len,
|
2013-03-26 00:03:13 +02:00
|
|
|
n_rec_locks, n_trx_locks, heap_size);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************//**
|
2016-08-12 11:17:45 +03:00
|
|
|
Compares the "weight" (or size) of two transactions. Transactions that
|
|
|
|
have edited non-transactional tables are considered heavier than ones
|
|
|
|
that have not.
|
|
|
|
@return TRUE if weight(a) >= weight(b) */
|
|
|
|
bool
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_weight_ge(
|
|
|
|
/*==========*/
|
2016-08-12 11:17:45 +03:00
|
|
|
const trx_t* a, /*!< in: transaction to be compared */
|
|
|
|
const trx_t* b) /*!< in: transaction to be compared */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
ibool a_notrans_edit;
|
|
|
|
ibool b_notrans_edit;
|
|
|
|
|
|
|
|
/* If mysql_thd is NULL for a transaction we assume that it has
|
|
|
|
not edited non-transactional tables. */
|
|
|
|
|
|
|
|
a_notrans_edit = a->mysql_thd != NULL
|
|
|
|
&& thd_has_edited_nontrans_tables(a->mysql_thd);
|
|
|
|
|
|
|
|
b_notrans_edit = b->mysql_thd != NULL
|
|
|
|
&& thd_has_edited_nontrans_tables(b->mysql_thd);
|
|
|
|
|
|
|
|
if (a_notrans_edit != b_notrans_edit) {
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
return(a_notrans_edit);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Either both had edited non-transactional tables or both had
|
|
|
|
not, we fall back to comparing the number of altered/locked
|
|
|
|
rows. */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
return(TRX_WEIGHT(a) >= TRX_WEIGHT(b));
|
|
|
|
}
|
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
/** Prepare a transaction.
|
|
|
|
@return log sequence number that makes the XA PREPARE durable
|
|
|
|
@retval 0 if no changes needed to be made durable */
|
2012-08-01 17:27:34 +03:00
|
|
|
static
|
2016-08-12 11:17:45 +03:00
|
|
|
lsn_t
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
trx_prepare_low(trx_t* trx)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
ut_ad(!trx->rsegs.m_redo.old_insert);
|
|
|
|
ut_ad(!trx->is_recovered);
|
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
mtr_t mtr;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
if (trx_undo_t* undo = trx->rsegs.m_noredo.undo) {
|
|
|
|
ut_ad(undo->rseg == trx->rsegs.m_noredo.rseg);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
mtr.start();
|
|
|
|
mtr.set_log_mode(MTR_LOG_NO_REDO);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
mutex_enter(&undo->rseg->mutex);
|
|
|
|
trx_undo_set_state_at_prepare(trx, undo, false, &mtr);
|
|
|
|
mutex_exit(&undo->rseg->mutex);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
mtr.commit();
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
trx_undo_t* undo = trx->rsegs.m_redo.undo;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
if (!undo) {
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
/* There were no changes to persistent tables. */
|
|
|
|
return(0);
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
trx_rseg_t* rseg = trx->rsegs.m_redo.rseg;
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
ut_ad(undo->rseg == rseg);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2018-11-01 10:48:56 +02:00
|
|
|
mtr.start();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
/* Change the undo log segment states from TRX_UNDO_ACTIVE to
|
|
|
|
TRX_UNDO_PREPARED: these modifications to the file data
|
|
|
|
structure define the transaction as prepared in the file-based
|
|
|
|
world, at the serialization point of lsn. */
|
2016-08-12 11:17:45 +03:00
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
mutex_enter(&rseg->mutex);
|
MDEV-12288 Reset DB_TRX_ID when the history is removed, to speed up MVCC
Let InnoDB purge reset DB_TRX_ID,DB_ROLL_PTR when the history is removed.
[TODO: It appears that the resetting is not taking place as often as
it could be. We should test that a simple INSERT should eventually
cause row_purge_reset_trx_id() to be invoked unless DROP TABLE is
invoked soon enough.]
The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).
When a reader sees 0 in the DB_TRX_ID column, it can instantly determine
that the record is present the read view. There is no need to acquire
the transaction system mutex to check if the transaction exists, because
writes can never be conducted by a transaction whose ID is 0.
The persistent InnoDB undo log used to be split into two parts:
insert_undo and update_undo. The insert_undo log was discarded at
transaction commit or rollback, and the update_undo log was processed
by the purge subsystem. As part of this change, we will only generate
a single undo log for new transactions, and the purge subsystem will
reset the DB_TRX_ID whenever a clustered index record is touched.
That is, all persistent undo log will be preserved at transaction commit
or rollback, to be removed by purge.
The InnoDB redo log format is changed in two ways:
We remove the redo log record type MLOG_UNDO_HDR_REUSE, and
we introduce the MLOG_ZIP_WRITE_TRX_ID record for updating the
DB_TRX_ID,DB_ROLL_PTR in a ROW_FORMAT=COMPRESSED table.
This is also changing the format of persistent InnoDB data files:
undo log and clustered index leaf page records. It will still be
possible via import and export to exchange data files with earlier
versions of MariaDB. The change to clustered index leaf page records
is simple: we allow DB_TRX_ID to be 0.
When it comes to the undo log, we must be able to upgrade from earlier
MariaDB versions after a clean shutdown (no redo log to apply).
While it would be nice to perform a slow shutdown (innodb_fast_shutdown=0)
before an upgrade, to empty the undo logs, we cannot assume that this
has been done. So, separate insert_undo log may exist for recovered
uncommitted transactions. These transactions may be automatically
rolled back, or they may be in XA PREPARE state, in which case InnoDB
will preserve the transaction until an explicit XA COMMIT or XA ROLLBACK.
Upgrade has been tested by starting up MariaDB 10.2 with
./mysql-test-run --manual-gdb innodb.read_only_recovery
and then starting up this patched server with
and without --innodb-read-only.
trx_undo_ptr_t::undo: Renamed from update_undo.
trx_undo_ptr_t::old_insert: Renamed from insert_undo.
trx_rseg_t::undo_list: Renamed from update_undo_list.
trx_rseg_t::undo_cached: Merged from update_undo_cached
and insert_undo_cached.
trx_rseg_t::old_insert_list: Renamed from insert_undo_list.
row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all undo processing in purge
that does not remove the clustered index record.
trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.
ReadView::changes_visible(): Allow id==0. (Return true for it.
This is what speeds up the MVCC.)
row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.
MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!
innobase_start_or_create_for_mysql(): Set srv_undo_sources before
starting any transactions.
The parsing of the MLOG_ZIP_WRITE_TRX_ID record was successfully
tested by running the following:
./mtr --parallel=auto --mysqld=--debug=d,ib_log innodb_zip.bug56680
grep MLOG_ZIP_WRITE_TRX_ID var/*/log/mysqld.1.err
2017-07-07 13:08:16 +03:00
|
|
|
trx_undo_set_state_at_prepare(trx, undo, false, &mtr);
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
mutex_exit(&rseg->mutex);
|
|
|
|
|
|
|
|
/* Make the XA PREPARE durable. */
|
|
|
|
mtr.commit();
|
|
|
|
ut_ad(mtr.commit_lsn() > 0);
|
|
|
|
return(mtr.commit_lsn());
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
Prepares a transaction. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_prepare(
|
|
|
|
/*========*/
|
|
|
|
trx_t* trx) /*!< in/out: transaction */
|
|
|
|
{
|
|
|
|
/* Only fresh user transactions can be prepared.
|
|
|
|
Recovered transactions cannot. */
|
|
|
|
ut_a(!trx->is_recovered);
|
|
|
|
|
MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.
Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.
trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.
trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)
trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.
trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.
trx_undo_free_last_page(): Remove the parameter trx.
trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.
trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.
trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.
trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.
trx_serialise(): Renamed from trx_serialisation_number_get().
trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.
trx_commit_in_memory(): Simplify the logic, and add assertions.
trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.
trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.
trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.
trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.
trx_roll_pop_top_rec_of_trx_low(): Remove.
trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.
row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-09 23:20:51 +02:00
|
|
|
lsn_t lsn = trx_prepare_low(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
DBUG_EXECUTE_IF("ib_trx_crash_during_xa_prepare_step", DBUG_SUICIDE(););
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_a(trx->state == TRX_STATE_ACTIVE);
|
2018-01-28 17:17:11 +04:00
|
|
|
trx_mutex_enter(trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->state = TRX_STATE_PREPARED;
|
2018-01-28 17:17:11 +04:00
|
|
|
trx_mutex_exit(trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-08-07 12:38:47 +02:00
|
|
|
if (lsn) {
|
2012-08-01 17:27:34 +03:00
|
|
|
/* Depending on the my.cnf options, we may now write the log
|
|
|
|
buffer to the log files, making the prepared state of the
|
|
|
|
transaction durable if the OS does not crash. We may also
|
|
|
|
flush the log files to disk, making the prepared state of the
|
|
|
|
transaction durable also at an OS crash or a power outage.
|
|
|
|
|
|
|
|
The idea in InnoDB's group prepare is that a group of
|
|
|
|
transactions gather behind a trx doing a physical disk write
|
|
|
|
to log files, and when that physical write has been completed,
|
|
|
|
one of those transactions does a write which prepares the whole
|
|
|
|
group. Note that this group prepare will only bring benefit if
|
|
|
|
there are > 2 users in the database. Then at least 2 users can
|
|
|
|
gather behind one doing the physical log write to disk.
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
We must not be holding any mutexes or latches here. */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
trx_flush_log_if_needed(lsn, trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-11 23:34:23 +02:00
|
|
|
/** XA PREPARE a transaction.
|
|
|
|
@param[in,out] trx transaction to prepare */
|
|
|
|
void trx_prepare_for_mysql(trx_t* trx)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_start_if_not_started_xa(trx, false);
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->op_info = "preparing";
|
|
|
|
|
|
|
|
trx_prepare(trx);
|
|
|
|
|
|
|
|
trx->op_info = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
struct trx_recover_for_mysql_callback_arg
|
|
|
|
{
|
|
|
|
XID *xid_list;
|
|
|
|
uint len;
|
|
|
|
uint count;
|
|
|
|
};
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
static my_bool trx_recover_for_mysql_callback(rw_trx_hash_element_t *element,
|
|
|
|
trx_recover_for_mysql_callback_arg *arg)
|
|
|
|
{
|
2019-04-25 09:05:52 +03:00
|
|
|
DBUG_ASSERT(arg->len > 0);
|
2017-12-24 21:23:10 +04:00
|
|
|
mutex_enter(&element->mutex);
|
|
|
|
if (trx_t *trx= element->trx)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The state of a read-write transaction can only change from ACTIVE to
|
|
|
|
PREPARED while we are holding the element->mutex. But since it is
|
|
|
|
executed at startup no state change should occur.
|
|
|
|
*/
|
|
|
|
if (trx_state_eq(trx, TRX_STATE_PREPARED))
|
|
|
|
{
|
|
|
|
ut_ad(trx->is_recovered);
|
2019-04-25 09:05:52 +03:00
|
|
|
ut_ad(trx->id);
|
2017-12-24 21:23:10 +04:00
|
|
|
if (arg->count == 0)
|
|
|
|
ib::info() << "Starting recovery for XA transactions...";
|
2019-04-25 09:05:52 +03:00
|
|
|
XID& xid= arg->xid_list[arg->count];
|
|
|
|
if (arg->count++ < arg->len)
|
|
|
|
{
|
|
|
|
trx->state= TRX_STATE_PREPARED_RECOVERED;
|
|
|
|
ib::info() << "Transaction " << trx->id
|
|
|
|
<< " in prepared state after recovery";
|
|
|
|
ib::info() << "Transaction contains changes to " << trx->undo_no
|
|
|
|
<< " rows";
|
|
|
|
xid= *trx->xid;
|
|
|
|
}
|
2017-12-24 21:23:10 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mutex_exit(&element->mutex);
|
2019-04-25 09:05:52 +03:00
|
|
|
/* Do not terminate upon reaching arg->len; count all transactions */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static my_bool trx_recover_reset_callback(rw_trx_hash_element_t *element,
|
|
|
|
void*)
|
|
|
|
{
|
|
|
|
mutex_enter(&element->mutex);
|
|
|
|
if (trx_t *trx= element->trx)
|
|
|
|
{
|
|
|
|
if (trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED))
|
|
|
|
trx->state= TRX_STATE_PREPARED;
|
|
|
|
}
|
|
|
|
mutex_exit(&element->mutex);
|
|
|
|
return false;
|
2017-12-24 21:23:10 +04:00
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
/**
|
|
|
|
Find prepared transaction objects for recovery.
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
@param[out] xid_list prepared transactions
|
|
|
|
@param[in] len number of slots in xid_list
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
@return number of prepared transactions stored in xid_list
|
|
|
|
*/
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
int trx_recover_for_mysql(XID *xid_list, uint len)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2017-12-24 21:23:10 +04:00
|
|
|
trx_recover_for_mysql_callback_arg arg= { xid_list, len, 0 };
|
|
|
|
|
|
|
|
ut_ad(xid_list);
|
|
|
|
ut_ad(len);
|
|
|
|
|
|
|
|
/* Fill xid_list with PREPARED transactions. */
|
2017-12-22 16:15:41 +02:00
|
|
|
trx_sys.rw_trx_hash.iterate_no_dups(reinterpret_cast<my_hash_walk_action>
|
|
|
|
(trx_recover_for_mysql_callback), &arg);
|
2017-12-24 21:23:10 +04:00
|
|
|
if (arg.count)
|
2019-04-25 09:05:52 +03:00
|
|
|
{
|
2017-12-24 21:23:10 +04:00
|
|
|
ib::info() << arg.count
|
2019-04-25 09:05:52 +03:00
|
|
|
<< " transactions in prepared state after recovery";
|
|
|
|
/* After returning the full list, reset the state, because
|
|
|
|
init_server_components() wants to recover the collection of
|
|
|
|
transactions twice, by first calling tc_log->open() and then
|
|
|
|
ha_recover() directly. */
|
|
|
|
if (arg.count <= len)
|
|
|
|
trx_sys.rw_trx_hash.iterate(reinterpret_cast<my_hash_walk_action>
|
|
|
|
(trx_recover_reset_callback), NULL);
|
|
|
|
}
|
|
|
|
return int(std::min(arg.count, len));
|
2017-12-24 21:23:10 +04:00
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
struct trx_get_trx_by_xid_callback_arg
|
|
|
|
{
|
2019-09-04 17:52:04 +03:00
|
|
|
const XID *xid;
|
2017-12-24 21:23:10 +04:00
|
|
|
trx_t *trx;
|
|
|
|
};
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
static my_bool trx_get_trx_by_xid_callback(rw_trx_hash_element_t *element,
|
|
|
|
trx_get_trx_by_xid_callback_arg *arg)
|
|
|
|
{
|
|
|
|
my_bool found= 0;
|
|
|
|
mutex_enter(&element->mutex);
|
|
|
|
if (trx_t *trx= element->trx)
|
|
|
|
{
|
2019-09-04 17:52:04 +03:00
|
|
|
trx_mutex_enter(trx);
|
2019-04-25 09:05:52 +03:00
|
|
|
if (trx->is_recovered &&
|
|
|
|
(trx_state_eq(trx, TRX_STATE_PREPARED) ||
|
|
|
|
trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)) &&
|
2017-12-24 21:23:10 +04:00
|
|
|
arg->xid->eq(reinterpret_cast<XID*>(trx->xid)))
|
|
|
|
{
|
2019-01-07 12:12:30 +02:00
|
|
|
#ifdef WITH_WSREP
|
2019-01-14 14:55:50 +02:00
|
|
|
/* The commit of a prepared recovered Galera
|
|
|
|
transaction needs a valid trx->xid for
|
|
|
|
invoking trx_sys_update_wsrep_checkpoint(). */
|
|
|
|
if (!wsrep_is_wsrep_xid(trx->xid))
|
2019-01-23 15:30:00 +04:00
|
|
|
#endif /* WITH_WSREP */
|
2017-12-24 21:23:10 +04:00
|
|
|
/* Invalidate the XID, so that subsequent calls will not find it. */
|
|
|
|
trx->xid->null();
|
|
|
|
arg->trx= trx;
|
|
|
|
found= 1;
|
|
|
|
}
|
2019-09-04 17:52:04 +03:00
|
|
|
trx_mutex_exit(trx);
|
2017-12-24 21:23:10 +04:00
|
|
|
}
|
|
|
|
mutex_exit(&element->mutex);
|
|
|
|
return found;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
MDEV-15326: InnoDB: Failing assertion: !other_lock
MySQL 5.7.9 (and MariaDB 10.2.2) introduced a race condition
between InnoDB transaction commit and the conversion of implicit
locks into explicit ones.
The assertion failure can be triggered with a test that runs
3 concurrent single-statement transactions in a loop on a simple
table:
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=InnoDB;
thread1: INSERT INTO t SET a=1;
thread2: DELETE FROM t;
thread3: SELECT * FROM t FOR UPDATE; -- or DELETE FROM t;
The failure scenarios are like the following:
(1) The INSERT statement is being committed, waiting for lock_sys->mutex.
(2) At the time of the failure, both the DELETE and SELECT transactions
are active but have not logged any changes yet.
(3) The transaction where the !other_lock assertion fails started
lock_rec_convert_impl_to_expl().
(4) After this point, the commit of the INSERT removed the transaction from
trx_sys->rw_trx_set, in trx_erase_lists().
(5) The other transaction consulted trx_sys->rw_trx_set and determined
that there is no implicit lock. Hence, it grabbed the lock.
(6) The !other_lock assertion fails in lock_rec_add_to_queue()
for the lock_rec_convert_impl_to_expl(), because the lock was 'stolen'.
This assertion failure looks genuine, because the INSERT transaction
is still active (trx->state=TRX_STATE_ACTIVE).
The problematic step (4) was introduced in
mysql/mysql-server@e27e0e0bb75b4d35e87059816f1cc370c09890ad
which fixed something related to MVCC (covered by the test
innodb.innodb-read-view). Basically, it reintroduced an error
that had been mentioned in an earlier commit
mysql/mysql-server@a17be6963fc0d9210fa0642d3985b7219cdaf0c5:
"The active transaction was removed from trx_sys->rw_trx_set prematurely."
Our fix goes along the following lines:
(a) Implicit locks will released by assigning
trx->state=TRX_STATE_COMMITTED_IN_MEMORY as the first step.
This transition will no longer be protected by lock_sys_t::mutex,
only by trx->mutex. This idea is by Sergey Vojtovich.
(b) We detach the transaction from trx_sys before starting to release
explicit locks.
(c) All callers of trx_rw_is_active() and trx_rw_is_active_low() must
recheck trx->state after acquiring trx->mutex.
(d) Before releasing any explicit locks, we will ensure that any activity
by other threads to convert implicit locks into explicit will have ceased,
by checking !trx_is_referenced(trx). There was a glitch
in this check when it was part of lock_trx_release_locks(); at the end
we would release trx->mutex and acquire lock_sys->mutex and trx->mutex,
and fail to recheck (trx_is_referenced() is protected by trx_t::mutex).
(e) Explicit locks can be released in batches (LOCK_RELEASE_INTERVAL=1000)
just like we did before.
trx_t::state: Document that the transition to COMMITTED is only
protected by trx_t::mutex, no longer by lock_sys_t::mutex.
trx_rw_is_active_low(), trx_rw_is_active(): Document that the transaction
state should be rechecked after acquiring trx_t::mutex.
trx_t::commit_state(): New function to change a transaction to committed
state, to release implicit locks.
trx_t::release_locks(): New function to release the explicit locks
after commit_state().
lock_trx_release_locks(): Move much of the logic to the caller
(which must invoke trx_t::commit_state() and trx_t::release_locks()
as needed), and assert that the transaction will have locks.
trx_get_trx_by_xid(): Make the parameter a pointer to const.
lock_rec_other_trx_holds_expl(): Recheck trx->state after acquiring
trx->mutex, and avoid a redundant lookup of the transaction.
lock_rec_queue_validate(): Recheck impl_trx->state while holding
impl_trx->mutex.
row_vers_impl_x_locked(), row_vers_impl_x_locked_low():
Document that the transaction state must be rechecked after
trx_mutex_enter().
trx_free_prepared(): Adjust for the changes to lock_trx_release_locks().
2019-09-03 12:31:37 +03:00
|
|
|
/** Look up an X/Open distributed transaction in XA PREPARE state.
|
|
|
|
@param[in] xid X/Open XA transaction identifier
|
|
|
|
@return transaction on match (the trx_t::xid will be invalidated);
|
|
|
|
note that the trx may have been committed before the caller acquires
|
|
|
|
trx_t::mutex
|
|
|
|
@retval NULL if no match */
|
|
|
|
trx_t* trx_get_trx_by_xid(const XID* xid)
|
2017-12-24 21:23:10 +04:00
|
|
|
{
|
|
|
|
trx_get_trx_by_xid_callback_arg arg= { xid, 0 };
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
if (xid)
|
2017-12-22 16:15:41 +02:00
|
|
|
trx_sys.rw_trx_hash.iterate(reinterpret_cast<my_hash_walk_action>
|
|
|
|
(trx_get_trx_by_xid_callback), &arg);
|
2017-12-24 21:23:10 +04:00
|
|
|
return arg.trx;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2017-12-24 21:23:10 +04:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/*************************************************************//**
|
|
|
|
Starts the transaction if it is not yet started. */
|
|
|
|
void
|
2013-03-26 00:03:13 +02:00
|
|
|
trx_start_if_not_started_xa_low(
|
|
|
|
/*============================*/
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_t* trx, /*!< in/out: transaction */
|
|
|
|
bool read_write) /*!< in: true if read write transaction */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_start_low(trx, read_write);
|
|
|
|
return;
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_ACTIVE:
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->id == 0 && read_write) {
|
|
|
|
/* If the transaction is tagged as read-only then
|
|
|
|
it can only write to temp tables and for such
|
|
|
|
transactions we don't want to move them to the
|
2017-12-27 16:23:53 +04:00
|
|
|
trx_sys_t::rw_trx_hash. */
|
2016-08-12 11:17:45 +03:00
|
|
|
if (!trx->read_only) {
|
|
|
|
trx_set_rw_mode(trx);
|
|
|
|
}
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
return;
|
|
|
|
case TRX_STATE_PREPARED:
|
2019-04-24 12:03:11 +03:00
|
|
|
case TRX_STATE_PREPARED_RECOVERED:
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************//**
|
|
|
|
Starts the transaction if it is not yet started. */
|
|
|
|
void
|
2013-03-26 00:03:13 +02:00
|
|
|
trx_start_if_not_started_low(
|
2016-08-12 11:17:45 +03:00
|
|
|
/*==========================*/
|
|
|
|
trx_t* trx, /*!< in: transaction */
|
|
|
|
bool read_write) /*!< in: true if read write transaction */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_start_low(trx, read_write);
|
|
|
|
return;
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_ACTIVE:
|
2016-08-12 11:17:45 +03:00
|
|
|
if (read_write && trx->id == 0 && !trx->read_only) {
|
|
|
|
trx_set_rw_mode(trx);
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
return;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_PREPARED:
|
2019-04-24 12:03:11 +03:00
|
|
|
case TRX_STATE_PREPARED_RECOVERED:
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_error;
|
|
|
|
}
|
2013-03-26 00:03:13 +02:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/*************************************************************//**
|
|
|
|
Starts a transaction for internal processing. */
|
|
|
|
void
|
|
|
|
trx_start_internal_low(
|
|
|
|
/*===================*/
|
|
|
|
trx_t* trx) /*!< in/out: transaction */
|
|
|
|
{
|
|
|
|
/* Ensure it is not flagged as an auto-commit-non-locking
|
|
|
|
transaction. */
|
|
|
|
|
|
|
|
trx->will_lock = 1;
|
|
|
|
|
|
|
|
trx->internal = true;
|
|
|
|
|
|
|
|
trx_start_low(trx, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Starts a read-only transaction for internal processing.
|
|
|
|
@param[in,out] trx transaction to be started */
|
|
|
|
void
|
|
|
|
trx_start_internal_read_only_low(
|
|
|
|
trx_t* trx)
|
|
|
|
{
|
|
|
|
/* Ensure it is not flagged as an auto-commit-non-locking
|
|
|
|
transaction. */
|
|
|
|
|
|
|
|
trx->will_lock = 1;
|
|
|
|
|
|
|
|
trx->internal = true;
|
|
|
|
|
|
|
|
trx_start_low(trx, false);
|
|
|
|
}
|
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
/*************************************************************//**
|
|
|
|
Starts the transaction for a DDL operation. */
|
|
|
|
void
|
|
|
|
trx_start_for_ddl_low(
|
|
|
|
/*==================*/
|
|
|
|
trx_t* trx, /*!< in/out: transaction */
|
|
|
|
trx_dict_op_t op) /*!< in: dictionary operation type */
|
|
|
|
{
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
|
|
|
/* Flag this transaction as a dictionary operation, so that
|
|
|
|
the data dictionary will be locked in crash recovery. */
|
|
|
|
|
|
|
|
trx_set_dict_operation(trx, op);
|
|
|
|
|
|
|
|
/* Ensure it is not flagged as an auto-commit-non-locking
|
|
|
|
transation. */
|
|
|
|
trx->will_lock = 1;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->ddl= true;
|
2013-03-26 00:03:13 +02:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_start_internal_low(trx);
|
2013-03-26 00:03:13 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case TRX_STATE_ACTIVE:
|
|
|
|
case TRX_STATE_PREPARED:
|
2019-04-24 12:03:11 +03:00
|
|
|
case TRX_STATE_PREPARED_RECOVERED:
|
2013-03-26 00:03:13 +02:00
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/*************************************************************//**
|
|
|
|
Set the transaction as a read-write transaction if it is not already
|
|
|
|
tagged as such. Read-only transactions that are writing to temporary
|
|
|
|
tables are assigned an ID and a rollback segment but are not added
|
|
|
|
to the trx read-write list because their updates should not be visible
|
|
|
|
to other transactions and therefore their changes can be ignored by
|
|
|
|
by MVCC. */
|
|
|
|
void
|
|
|
|
trx_set_rw_mode(
|
|
|
|
/*============*/
|
|
|
|
trx_t* trx) /*!< in/out: transaction that is RW */
|
|
|
|
{
|
|
|
|
ut_ad(trx->rsegs.m_redo.rseg == 0);
|
|
|
|
ut_ad(!trx_is_autocommit_non_locking(trx));
|
2017-11-30 18:07:28 +04:00
|
|
|
ut_ad(!trx->read_only);
|
2017-12-13 15:40:41 +04:00
|
|
|
ut_ad(trx->id == 0);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2017-08-14 15:55:04 +03:00
|
|
|
if (high_level_read_only) {
|
2016-08-12 11:17:45 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function is promoting existing trx from ro mode to rw mode.
|
2017-12-22 16:15:41 +02:00
|
|
|
In this process it has acquired trx_sys.mutex as it plan to
|
2016-08-12 11:17:45 +03:00
|
|
|
move trx from ro list to rw list. If in future, some other thread
|
|
|
|
looks at this trx object while it is being promoted then ensure
|
|
|
|
that both threads are synced by acquring trx->mutex to avoid decision
|
|
|
|
based on in-consistent view formed during promotion. */
|
|
|
|
|
MDEV-12289 Keep 128 persistent rollback segments for compatibility and performance
InnoDB divides the allocation of undo logs into rollback segments.
The DB_ROLL_PTR system column of clustered indexes can address up to
128 rollback segments (TRX_SYS_N_RSEGS). Originally, InnoDB only
created one rollback segment. In MySQL 5.5 or in the InnoDB Plugin
for MySQL 5.1, all 128 rollback segments were created.
MySQL 5.7 hard-codes the rollback segment IDs 1..32 for temporary undo logs.
On upgrade, unless a slow shutdown (innodb_fast_shutdown=0)
was performed on the old server instance, these rollback segments
could be in use by transactions that are in XA PREPARE state or
transactions that were left behind by a server kill followed by a
normal shutdown immediately after restart.
Persistent tables cannot refer to temporary undo logs or vice versa.
Therefore, we should keep two distinct sets of rollback segments:
one for persistent tables and another for temporary tables. In this way,
all 128 rollback segments will be available for both types of tables,
which could improve performance. Also, MariaDB 10.2 will remain more
compatible than MySQL 5.7 with data files from earlier versions of
MySQL or MariaDB.
trx_sys_t::temp_rsegs[TRX_SYS_N_RSEGS]: A new array of temporary
rollback segments. The trx_sys_t::rseg_array[TRX_SYS_N_RSEGS] will
be solely for persistent undo logs.
srv_tmp_undo_logs. Remove. Use the constant TRX_SYS_N_RSEGS.
srv_available_undo_logs: Change the type to ulong.
trx_rseg_get_on_id(): Remove. Instead, let the callers refer to
trx_sys directly.
trx_rseg_create(), trx_sysf_rseg_find_free(): Remove unneeded parameters.
These functions only deal with persistent undo logs.
trx_temp_rseg_create(): New function, to create all temporary rollback
segments at server startup.
trx_rseg_t::is_persistent(): Determine if the rollback segment is for
persistent tables.
trx_sys_is_noredo_rseg_slot(): Remove. The callers must know based on
context (such as table handle) whether the DB_ROLL_PTR is referring to
a persistent undo log.
trx_sys_create_rsegs(): Remove all parameters, which were always passed
as global variables. Instead, modify the global variables directly.
enum trx_rseg_type_t: Remove.
trx_t::get_temp_rseg(): A method to ensure that a temporary
rollback segment has been assigned for the transaction.
trx_t::assign_temp_rseg(): Replaces trx_assign_rseg().
trx_purge_free_segment(), trx_purge_truncate_rseg_history():
Remove the redundant variable noredo=false.
Temporary undo logs are discarded immediately at transaction commit
or rollback, not lazily by purge.
trx_purge_mark_undo_for_truncate(): Remove references to the
temporary rollback segments.
trx_purge_mark_undo_for_truncate(): Remove a check for temporary
rollback segments. Only the dedicated persistent undo log tablespaces
can be truncated.
trx_undo_get_undo_rec_low(), trx_undo_get_undo_rec(): Add the
parameter is_temp.
trx_rseg_mem_restore(): Split from trx_rseg_mem_create().
Initialize the undo log and the rollback segment from the file
data structures.
trx_sysf_get_n_rseg_slots(): Renamed from
trx_sysf_used_slots_for_redo_rseg(). Count the persistent
rollback segment headers that have been initialized.
trx_sys_close(): Also free trx_sys->temp_rsegs[].
get_next_redo_rseg(): Merged to trx_assign_rseg_low().
trx_assign_rseg_low(): Remove the parameters and access the
global variables directly. Revert to simple round-robin, now that
the whole trx_sys->rseg_array[] is for persistent undo log again.
get_next_noredo_rseg(): Moved to trx_t::assign_temp_rseg().
srv_undo_tablespaces_init(): Remove some parameters and use the
global variables directly. Clarify some error messages.
Adjust the test innodb.log_file. Apparently, before these changes,
InnoDB somehow ignored missing dedicated undo tablespace files that
are pointed by the TRX_SYS header page, possibly losing part of
essential transaction system state.
2017-03-30 13:11:34 +03:00
|
|
|
trx->rsegs.m_redo.rseg = trx_assign_rseg_low();
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx->rsegs.m_redo.rseg != 0);
|
|
|
|
|
2018-01-25 18:29:59 +04:00
|
|
|
trx_sys.register_rw(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
/* So that we can see our own changes. */
|
2018-01-20 17:45:42 +04:00
|
|
|
if (trx->read_view.is_open()) {
|
2018-01-24 22:10:16 +04:00
|
|
|
trx->read_view.set_creator_trx_id(trx->id);
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
|
|
|
}
|