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.
|
2017-02-09 10:04:00 +02:00
|
|
|
Copyright (c) 2015, 2017, 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.,
|
|
|
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
|
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/**************************************************//**
|
|
|
|
@file trx/trx0trx.cc
|
|
|
|
The transaction
|
|
|
|
|
|
|
|
Created 3/26/1996 Heikki Tuuri
|
|
|
|
*******************************************************/
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
#include "ha_prototypes.h"
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
#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"
|
|
|
|
#include "read0read.h"
|
2016-08-12 11:17:45 +03:00
|
|
|
#include "srv0mon.h"
|
2012-08-01 17:27:34 +03:00
|
|
|
#include "srv0srv.h"
|
2016-08-12 11:17:45 +03:00
|
|
|
#include "fsp0sysspace.h"
|
|
|
|
#include "row0mysql.h"
|
2012-08-01 17:27:34 +03:00
|
|
|
#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 "usr0sess.h"
|
|
|
|
#include "ut0new.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>
|
|
|
|
|
2014-07-08 12:54:47 +02:00
|
|
|
extern "C"
|
|
|
|
int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2);
|
|
|
|
|
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
|
|
|
/** Dummy session used currently in MySQL interface */
|
2016-08-12 11:17:45 +03:00
|
|
|
sess_t* trx_dummy_sess = NULL;
|
|
|
|
|
|
|
|
/** Constructor */
|
|
|
|
TrxVersion::TrxVersion(trx_t* trx)
|
|
|
|
:
|
|
|
|
m_trx(trx),
|
|
|
|
m_version(trx->version)
|
|
|
|
{
|
|
|
|
/* No op */
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/** Set flush observer for the transaction
|
|
|
|
@param[in/out] trx transaction struct
|
|
|
|
@param[in] observer flush observer */
|
|
|
|
void
|
|
|
|
trx_set_flush_observer(
|
|
|
|
trx_t* trx,
|
|
|
|
FlushObserver* observer)
|
|
|
|
{
|
|
|
|
trx->flush_observer = observer;
|
|
|
|
}
|
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 */
|
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_strlcpy(trx->detailed_error, msg, MAX_DETAILED_ERROR_LEN);
|
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
|
|
|
/* This is called at the end of commit, do not reset the
|
|
|
|
trx_t::state here to NOT_STARTED. The FORCED_ROLLBACK
|
|
|
|
status is required for asynchronous handling. */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->id = 0;
|
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
|
|
|
|
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
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
trx->active_commit_ordered = 0;
|
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->support_xa = 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
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(!MVCC::is_view_active(trx->read_view));
|
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;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
/* During asynchronous rollback, we should reset forced rollback flag
|
|
|
|
only after rollback is complete to avoid race with the thread owning
|
|
|
|
the transaction. */
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
if (!TrxInInnoDB::is_async_rollback(trx)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-09 15:05:59 +04:00
|
|
|
my_atomic_storelong(&trx->killed_by, 0);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
/* Note: Do not set to 0, the ref count is decremented inside
|
|
|
|
the TrxInInnoDB() destructor. We only need to clear the flags. */
|
|
|
|
|
|
|
|
trx->in_innodb &= TRX_FORCE_ROLLBACK_MASK;
|
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
/* Note: It's possible that this list is not empty if a transaction
|
|
|
|
was interrupted after it collected the victim transactions and before
|
|
|
|
it got a chance to roll them back asynchronously. */
|
|
|
|
|
|
|
|
trx->hit_list.clear();
|
|
|
|
|
|
|
|
trx->flush_observer = NULL;
|
|
|
|
|
|
|
|
++trx->version;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** 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
|
|
|
|
ut_zalloc() in Pool::Pool() which would not call
|
|
|
|
the constructors of the trx_t members. */
|
|
|
|
new(&trx->mod_tables) trx_mod_tables_t();
|
|
|
|
|
|
|
|
new(&trx->lock.rec_pool) lock_pool_t();
|
|
|
|
|
|
|
|
new(&trx->lock.table_pool) lock_pool_t();
|
|
|
|
|
|
|
|
new(&trx->lock.table_locks) lock_pool_t();
|
|
|
|
|
|
|
|
new(&trx->hit_list) hit_list_t();
|
|
|
|
|
|
|
|
trx_init(trx);
|
|
|
|
|
|
|
|
trx->state = TRX_STATE_NOT_STARTED;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
UT_LIST_INIT(
|
|
|
|
trx->trx_savepoints,
|
|
|
|
&trx_named_savept_t::trx_savepoints);
|
|
|
|
|
|
|
|
mutex_create(LATCH_ID_TRX, &trx->mutex);
|
|
|
|
mutex_create(LATCH_ID_TRX_UNDO, &trx->undo_mutex);
|
|
|
|
|
|
|
|
lock_trx_alloc_locks(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Release resources held by the transaction object.
|
|
|
|
@param trx the transaction for which to release resources */
|
|
|
|
static void destroy(trx_t* trx)
|
|
|
|
{
|
|
|
|
ut_a(trx->magic_n == TRX_MAGIC_N);
|
|
|
|
ut_ad(!trx->in_rw_trx_list);
|
|
|
|
ut_ad(!trx->in_mysql_trx_list);
|
|
|
|
|
|
|
|
ut_a(trx->lock.wait_lock == NULL);
|
|
|
|
ut_a(trx->lock.wait_thr == NULL);
|
|
|
|
|
2017-02-23 23:05:12 +02:00
|
|
|
trx_assert_no_search_latch(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
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);
|
|
|
|
|
|
|
|
UT_DELETE(trx->xid);
|
|
|
|
ut_free(trx->detailed_error);
|
|
|
|
|
|
|
|
mutex_free(&trx->mutex);
|
|
|
|
mutex_free(&trx->undo_mutex);
|
|
|
|
|
|
|
|
trx->mod_tables.~trx_mod_tables_t();
|
|
|
|
|
|
|
|
ut_ad(trx->read_view == NULL);
|
|
|
|
|
|
|
|
if (!trx->lock.rec_pool.empty()) {
|
|
|
|
|
|
|
|
/* See lock_trx_alloc_locks() why we only free
|
|
|
|
the first element. */
|
|
|
|
|
|
|
|
ut_free(trx->lock.rec_pool[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!trx->lock.table_pool.empty()) {
|
|
|
|
|
|
|
|
/* See lock_trx_alloc_locks() why we only free
|
|
|
|
the first element. */
|
|
|
|
|
|
|
|
ut_free(trx->lock.table_pool[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->lock.rec_pool.~lock_pool_t();
|
|
|
|
|
|
|
|
trx->lock.table_pool.~lock_pool_t();
|
|
|
|
|
|
|
|
trx->lock.table_locks.~lock_pool_t();
|
|
|
|
|
|
|
|
trx->hit_list.~hit_list_t();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Enforce any invariants here, this is called before the transaction
|
|
|
|
is added to the pool.
|
|
|
|
@return true if all OK */
|
|
|
|
static bool debug(const trx_t* trx)
|
|
|
|
{
|
|
|
|
ut_a(trx->error_state == DB_SUCCESS);
|
|
|
|
|
|
|
|
ut_a(trx->magic_n == TRX_MAGIC_N);
|
|
|
|
|
|
|
|
ut_ad(!trx->read_only);
|
|
|
|
|
|
|
|
ut_ad(trx->state == TRX_STATE_NOT_STARTED
|
|
|
|
|| trx->state == TRX_STATE_FORCED_ROLLBACK);
|
|
|
|
|
|
|
|
ut_ad(trx->dict_operation == TRX_DICT_OP_NONE);
|
|
|
|
|
|
|
|
ut_ad(trx->mysql_thd == 0);
|
|
|
|
|
|
|
|
ut_ad(!trx->in_rw_trx_list);
|
|
|
|
ut_ad(!trx->in_mysql_trx_list);
|
|
|
|
|
|
|
|
ut_a(trx->lock.wait_thr == NULL);
|
|
|
|
ut_a(trx->lock.wait_lock == NULL);
|
|
|
|
|
2017-02-23 23:05:12 +02:00
|
|
|
trx_assert_no_search_latch(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
ut_a(trx->dict_operation_lock_mode == 0);
|
|
|
|
|
|
|
|
ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
|
|
|
|
|
|
|
|
ut_ad(trx->autoinc_locks == NULL);
|
|
|
|
|
|
|
|
ut_ad(trx->lock.table_locks.empty());
|
|
|
|
|
|
|
|
ut_ad(!trx->abort);
|
|
|
|
|
|
|
|
ut_ad(trx->hit_list.empty());
|
|
|
|
|
|
|
|
ut_ad(trx->killed_by == 0);
|
|
|
|
|
|
|
|
return(true);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @return a trx_t instance from trx_pools. */
|
|
|
|
static
|
|
|
|
trx_t*
|
|
|
|
trx_create_low()
|
|
|
|
{
|
|
|
|
trx_t* trx = trx_pools->get();
|
|
|
|
|
|
|
|
assert_trx_is_free(trx);
|
|
|
|
|
|
|
|
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);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Background trx should not be forced to rollback,
|
|
|
|
we will unset the flag for user trx. */
|
|
|
|
trx->in_innodb |= TRX_FORCE_ROLLBACK_DISABLE;
|
|
|
|
|
|
|
|
/* Trx state can be TRX_STATE_FORCED_ROLLBACK if
|
|
|
|
the trx was forced to rollback before it's reused.*/
|
|
|
|
trx->state = TRX_STATE_NOT_STARTED;
|
|
|
|
|
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
|
|
|
|
|
|
|
/* Remember to free the vector explicitly in trx_free(). */
|
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
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Should have been either just initialized or .clear()ed by
|
|
|
|
trx_free(). */
|
|
|
|
ut_a(trx->mod_tables.size() == 0);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2014-08-06 15:39:15 +03:00
|
|
|
#ifdef WITH_WSREP
|
|
|
|
trx->wsrep_event = NULL;
|
|
|
|
#endif /* WITH_WSREP */
|
2016-09-06 09:43:16 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
return(trx);
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/**
|
|
|
|
Release a trx_t instance back to the pool.
|
|
|
|
@param trx the instance to release. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_free(trx_t*& trx)
|
|
|
|
{
|
|
|
|
assert_trx_is_free(trx);
|
|
|
|
|
|
|
|
trx->mysql_thd = 0;
|
2016-09-22 17:21:21 +00:00
|
|
|
trx->mysql_log_file_name = 0;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
// FIXME: We need to avoid this heap free/alloc for each commit.
|
|
|
|
if (trx->autoinc_locks != NULL) {
|
|
|
|
ut_ad(ib_vector_is_empty(trx->autoinc_locks));
|
|
|
|
/* We allocated a dedicated heap for the vector. */
|
|
|
|
ib_vector_free(trx->autoinc_locks);
|
|
|
|
trx->autoinc_locks = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->mod_tables.clear();
|
|
|
|
|
|
|
|
ut_ad(trx->read_view == NULL);
|
|
|
|
|
|
|
|
/* trx locking state should have been reset before returning trx
|
|
|
|
to pool */
|
|
|
|
ut_ad(trx->will_lock == 0);
|
|
|
|
|
|
|
|
trx_pools->mem_free(trx);
|
|
|
|
|
|
|
|
trx = NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/********************************************************************//**
|
|
|
|
Creates a transaction object for background operations by the master thread.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return own: transaction object */
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_t*
|
|
|
|
trx_allocate_for_background(void)
|
|
|
|
/*=============================*/
|
|
|
|
{
|
|
|
|
trx_t* trx;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx = trx_create_low();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx->sess = trx_dummy_sess;
|
|
|
|
|
|
|
|
return(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************//**
|
|
|
|
Creates a transaction object for MySQL.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return own: transaction object */
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_t*
|
|
|
|
trx_allocate_for_mysql(void)
|
|
|
|
/*========================*/
|
|
|
|
{
|
|
|
|
trx_t* trx;
|
|
|
|
|
|
|
|
trx = trx_allocate_for_background();
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_enter();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
ut_d(trx->in_mysql_trx_list = TRUE);
|
2016-08-12 11:17:45 +03:00
|
|
|
UT_LIST_ADD_FIRST(trx_sys->mysql_trx_list, trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_exit();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
return(trx);
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/** Check state of transaction before freeing it.
|
|
|
|
@param trx trx object to validate */
|
2012-08-01 17:27:34 +03:00
|
|
|
static
|
|
|
|
void
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_validate_state_before_free(trx_t* trx)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2013-03-26 00:03:13 +02:00
|
|
|
if (trx->declared_to_be_inside_innodb) {
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::error() << "Freeing a trx (" << trx << ", "
|
|
|
|
<< trx_get_id_for_print(trx) << ") which is declared"
|
|
|
|
" to be processing inside InnoDB";
|
2013-03-26 00:03:13 +02:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_print(stderr, trx, 600);
|
|
|
|
putc('\n', stderr);
|
|
|
|
|
|
|
|
/* This is an error but not a fatal error. We must keep
|
|
|
|
the counters like srv_conc_n_threads accurate. */
|
|
|
|
srv_conc_force_exit_innodb(trx);
|
|
|
|
}
|
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
if (trx->n_mysql_tables_in_use != 0
|
|
|
|
|| trx->mysql_n_tables_locked != 0) {
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::error() << "MySQL is freeing a thd though"
|
|
|
|
" trx->n_mysql_tables_in_use is "
|
|
|
|
<< trx->n_mysql_tables_in_use
|
|
|
|
<< " and trx->mysql_n_tables_locked is "
|
|
|
|
<< trx->mysql_n_tables_locked << ".";
|
2013-03-26 00:03:13 +02:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_print(stderr, trx, 600);
|
|
|
|
ut_print_buf(stderr, trx, sizeof(trx_t));
|
|
|
|
putc('\n', stderr);
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->dict_operation = TRX_DICT_OP_NONE;
|
|
|
|
assert_trx_is_inactive(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Free and initialize a transaction object instantinated during recovery.
|
|
|
|
@param trx trx object to free and initialize during recovery */
|
|
|
|
void
|
|
|
|
trx_free_resurrected(trx_t* trx)
|
|
|
|
{
|
|
|
|
trx_validate_state_before_free(trx);
|
|
|
|
|
|
|
|
trx_init(trx);
|
|
|
|
|
|
|
|
trx_free(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Free a transaction that was allocated by background or user threads.
|
|
|
|
@param trx trx object to free */
|
|
|
|
void
|
|
|
|
trx_free_for_background(trx_t* trx)
|
|
|
|
{
|
|
|
|
trx_validate_state_before_free(trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx_free(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************//**
|
|
|
|
At shutdown, frees a transaction object that is in the PREPARED state. */
|
|
|
|
void
|
|
|
|
trx_free_prepared(
|
|
|
|
/*==============*/
|
|
|
|
trx_t* trx) /*!< in, own: trx object */
|
|
|
|
{
|
2017-02-03 12:25:42 +02:00
|
|
|
ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)
|
|
|
|
|| (trx_state_eq(trx, TRX_STATE_ACTIVE)
|
|
|
|
&& trx->is_recovered
|
2017-02-09 10:04:00 +02:00
|
|
|
&& (!srv_was_started
|
|
|
|
|| srv_read_only_mode
|
2017-02-03 12:25:42 +02:00
|
|
|
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO)));
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_a(trx->magic_n == TRX_MAGIC_N);
|
|
|
|
|
2015-06-16 10:57:05 +02:00
|
|
|
lock_trx_release_locks(trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_undo_free_prepared(trx);
|
|
|
|
|
|
|
|
assert_trx_in_rw_list(trx);
|
|
|
|
|
|
|
|
ut_a(!trx->read_only);
|
|
|
|
|
|
|
|
ut_d(trx->in_rw_trx_list = FALSE);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->state = TRX_STATE_NOT_STARTED;
|
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
/* Undo trx_resurrect_table_locks(). */
|
2016-08-12 11:17:45 +03:00
|
|
|
lock_trx_lock_list_init(&trx->lock.trx_locks);
|
|
|
|
|
|
|
|
/* Note: This vector is not guaranteed to be empty because the
|
|
|
|
transaction was never committed and therefore lock_trx_release()
|
|
|
|
was not called. */
|
|
|
|
trx->lock.table_locks.clear();
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_free(trx);
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/** Disconnect a transaction from MySQL and optionally mark it as if
|
|
|
|
it's been recovered. For the marking the transaction must be in prepared state.
|
|
|
|
The recovery-marked transaction is going to survive "alone" so its association
|
|
|
|
with the mysql handle is destroyed now rather than when it will be
|
|
|
|
finally freed.
|
|
|
|
@param[in,out] trx transaction
|
|
|
|
@param[in] prepared boolean value to specify whether trx is
|
|
|
|
for recovery or not. */
|
|
|
|
inline
|
2012-08-01 17:27:34 +03:00
|
|
|
void
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_disconnect_from_mysql(
|
|
|
|
trx_t* trx,
|
|
|
|
bool prepared)
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_enter();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
ut_ad(trx->in_mysql_trx_list);
|
|
|
|
ut_d(trx->in_mysql_trx_list = FALSE);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
UT_LIST_REMOVE(trx_sys->mysql_trx_list, trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->read_view != NULL) {
|
|
|
|
trx_sys->mvcc->view_close(trx->read_view, true);
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx_sys_validate_trx_list());
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (prepared) {
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED));
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->is_recovered = true;
|
|
|
|
trx_sys->n_prepared_recovered_trx++;
|
|
|
|
trx->mysql_thd = NULL;
|
|
|
|
/* todo/fixme: suggest to do it at innodb prepare */
|
|
|
|
trx->will_lock = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_exit();
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/** Disconnect a transaction from MySQL.
|
|
|
|
@param[in,out] trx transaction */
|
|
|
|
inline
|
|
|
|
void
|
|
|
|
trx_disconnect_plain(trx_t* trx)
|
|
|
|
{
|
|
|
|
trx_disconnect_from_mysql(trx, false);
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/** Disconnect a prepared transaction from MySQL.
|
|
|
|
@param[in,out] trx transaction */
|
|
|
|
void
|
|
|
|
trx_disconnect_prepared(trx_t* trx)
|
|
|
|
{
|
|
|
|
trx_disconnect_from_mysql(trx, true);
|
|
|
|
}
|
2014-02-26 19:23:04 +01:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/** Free a transaction object for MySQL.
|
|
|
|
@param[in,out] trx transaction */
|
|
|
|
void
|
|
|
|
trx_free_for_mysql(trx_t* trx)
|
|
|
|
{
|
|
|
|
trx_disconnect_plain(trx);
|
|
|
|
trx_free_for_background(trx);
|
2012-08-01 17:27:34 +03: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 */
|
2016-08-12 11:17:45 +03:00
|
|
|
const trx_undo_ptr_t* undo_ptr,
|
|
|
|
/*!< in: pointer to undo segment. */
|
2014-02-01 09:33:26 +01:00
|
|
|
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;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(undo == undo_ptr->insert_undo || undo == undo_ptr->update_undo);
|
|
|
|
|
|
|
|
if (trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY) || 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(
|
2017-03-09 22:06:22 +02:00
|
|
|
page_id_t(undo->space, 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)) {
|
|
|
|
if (table->ibd_file_missing
|
|
|
|
|| dict_table_is_temporary(table)) {
|
|
|
|
mutex_enter(&dict_sys->mutex);
|
|
|
|
dict_table_close(table, TRUE, FALSE);
|
|
|
|
dict_table_remove_from_cache(table);
|
|
|
|
mutex_exit(&dict_sys->mutex);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->state == TRX_STATE_PREPARED) {
|
|
|
|
trx->mod_tables.insert(table);
|
|
|
|
}
|
2014-02-01 09:33:26 +01:00
|
|
|
lock_table_ix_resurrect(table, trx);
|
|
|
|
|
|
|
|
DBUG_PRINT("ib_trx",
|
|
|
|
("resurrect" TRX_ID_FMT
|
|
|
|
" table '%s' IX lock from %s undo",
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_get_id_for_print(trx),
|
|
|
|
table->name.m_name,
|
|
|
|
undo == undo_ptr->insert_undo
|
2014-02-01 09:33:26 +01:00
|
|
|
? "insert" : "update"));
|
|
|
|
|
|
|
|
dict_table_close(table, FALSE, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/****************************************************************//**
|
|
|
|
Resurrect the transactions that were doing inserts the time of the
|
|
|
|
crash, they need to be undone.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return trx_t instance */
|
2012-08-01 17:27:34 +03:00
|
|
|
static
|
|
|
|
trx_t*
|
|
|
|
trx_resurrect_insert(
|
|
|
|
/*=================*/
|
|
|
|
trx_undo_t* undo, /*!< in: entry to UNDO */
|
|
|
|
trx_rseg_t* rseg) /*!< in: rollback segment */
|
|
|
|
{
|
|
|
|
trx_t* trx;
|
|
|
|
|
|
|
|
trx = trx_allocate_for_background();
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_d(trx->start_file = __FILE__);
|
|
|
|
ut_d(trx->start_line = __LINE__);
|
|
|
|
|
|
|
|
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;
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->id = undo->trx_id;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->rsegs.m_redo.insert_undo = undo;
|
|
|
|
trx->is_recovered = true;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* This is single-threaded startup code, we do not need the
|
|
|
|
protection of trx->mutex or trx_sys->mutex here. */
|
|
|
|
|
|
|
|
if (undo->state != TRX_UNDO_ACTIVE) {
|
|
|
|
|
|
|
|
/* Prepared transactions are left in the prepared state
|
|
|
|
waiting for a commit or abort decision from MySQL */
|
|
|
|
|
|
|
|
if (undo->state == TRX_UNDO_PREPARED) {
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::info() << "Transaction "
|
|
|
|
<< trx_get_id_for_print(trx)
|
|
|
|
<< " was in the XA prepared state.";
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
if (srv_force_recovery == 0) {
|
|
|
|
|
|
|
|
trx->state = TRX_STATE_PREPARED;
|
2016-08-12 11:17:45 +03:00
|
|
|
++trx_sys->n_prepared_trx;
|
|
|
|
++trx_sys->n_prepared_recovered_trx;
|
2012-08-01 17:27:34 +03:00
|
|
|
} else {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
ib::info() << "Since innodb_force_recovery"
|
|
|
|
" > 0, we will force a rollback.";
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx->state = TRX_STATE_ACTIVE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
trx->state = TRX_STATE_COMMITTED_IN_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We give a dummy value for the trx no; this should have no
|
|
|
|
relevance since purge is not interested in committed
|
|
|
|
transaction numbers, unless they are in the history
|
|
|
|
list, in which case it looks the number from the disk based
|
|
|
|
undo log structure */
|
|
|
|
|
|
|
|
trx->no = trx->id;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
} else {
|
|
|
|
trx->state = TRX_STATE_ACTIVE;
|
|
|
|
|
|
|
|
/* A running transaction always has the number
|
2014-02-01 09:33:26 +01:00
|
|
|
field inited to TRX_ID_MAX */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
trx->no = TRX_ID_MAX;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2014-05-05 18:20:28 +02:00
|
|
|
/* trx_start_low() is not called with resurrect, so need to initialize
|
|
|
|
start time here.*/
|
|
|
|
if (trx->state == TRX_STATE_ACTIVE
|
|
|
|
|| trx->state == TRX_STATE_PREPARED) {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2014-05-05 18:20:28 +02:00
|
|
|
trx->start_time = ut_time();
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
if (undo->dict_operation) {
|
|
|
|
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
|
|
|
|
trx->table_id = undo->table_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!undo->empty) {
|
|
|
|
trx->undo_no = undo->top_undo_no + 1;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->undo_rseg_space = undo->rseg->space;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
Prepared transactions are left in the prepared state waiting for a
|
|
|
|
commit or abort decision from MySQL */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_resurrect_update_in_prepared_state(
|
|
|
|
/*===================================*/
|
|
|
|
trx_t* trx, /*!< in,out: transaction */
|
|
|
|
const trx_undo_t* undo) /*!< in: update UNDO record */
|
|
|
|
{
|
|
|
|
/* This is single-threaded startup code, we do not need the
|
|
|
|
protection of trx->mutex or trx_sys->mutex here. */
|
|
|
|
|
|
|
|
if (undo->state == TRX_UNDO_PREPARED) {
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::info() << "Transaction " << trx_get_id_for_print(trx)
|
|
|
|
<< " was in the XA prepared state.";
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
if (srv_force_recovery == 0) {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
ut_ad(trx->state != TRX_STATE_FORCED_ROLLBACK);
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
++trx_sys->n_prepared_trx;
|
|
|
|
++trx_sys->n_prepared_recovered_trx;
|
2012-08-01 17:27:34 +03:00
|
|
|
} else {
|
|
|
|
ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED));
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->state = TRX_STATE_PREPARED;
|
|
|
|
} else {
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::info() << "Since innodb_force_recovery > 0, we"
|
|
|
|
" will rollback it anyway.";
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx->state = TRX_STATE_ACTIVE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
trx->state = TRX_STATE_COMMITTED_IN_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
Resurrect the transactions that were doing updates the time of the
|
|
|
|
crash, they need to be undone. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_resurrect_update(
|
|
|
|
/*=================*/
|
|
|
|
trx_t* trx, /*!< in/out: transaction */
|
|
|
|
trx_undo_t* undo, /*!< in/out: update UNDO record */
|
|
|
|
trx_rseg_t* rseg) /*!< in/out: rollback segment */
|
|
|
|
{
|
2016-08-12 11:17:45 +03: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;
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->id = undo->trx_id;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->rsegs.m_redo.update_undo = undo;
|
|
|
|
trx->is_recovered = true;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* This is single-threaded startup code, we do not need the
|
|
|
|
protection of trx->mutex or trx_sys->mutex here. */
|
|
|
|
|
|
|
|
if (undo->state != TRX_UNDO_ACTIVE) {
|
|
|
|
trx_resurrect_update_in_prepared_state(trx, undo);
|
|
|
|
|
|
|
|
/* We give a dummy value for the trx number */
|
|
|
|
|
|
|
|
trx->no = trx->id;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
trx->state = TRX_STATE_ACTIVE;
|
|
|
|
|
|
|
|
/* A running transaction always has the number field inited to
|
2014-02-01 09:33:26 +01:00
|
|
|
TRX_ID_MAX */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
trx->no = TRX_ID_MAX;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2014-05-05 18:20:28 +02:00
|
|
|
/* trx_start_low() is not called with resurrect, so need to initialize
|
|
|
|
start time here.*/
|
|
|
|
if (trx->state == TRX_STATE_ACTIVE
|
|
|
|
|| trx->state == TRX_STATE_PREPARED) {
|
|
|
|
trx->start_time = ut_time();
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
if (undo->dict_operation) {
|
|
|
|
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
|
|
|
|
trx->table_id = undo->table_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!undo->empty && undo->top_undo_no >= trx->undo_no) {
|
|
|
|
|
|
|
|
trx->undo_no = undo->top_undo_no + 1;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->undo_rseg_space = undo->rseg->space;
|
2012-08-01 17:27:34 +03: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);
|
|
|
|
ut_ad(!purge_sys);
|
|
|
|
|
2017-03-09 20:40:48 +02:00
|
|
|
purge_sys = UT_NEW_NOKEY(purge_sys_t());
|
|
|
|
|
|
|
|
if (srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
|
|
|
|
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. */
|
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;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_rseg_t* rseg = trx_sys->rseg_array[i];
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* At this stage non-redo rseg slots are all NULL as they are
|
|
|
|
re-created on server start and existing slots are not read. */
|
2012-08-01 17:27:34 +03:00
|
|
|
if (rseg == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resurrect transactions that were doing inserts. */
|
|
|
|
for (undo = UT_LIST_GET_FIRST(rseg->insert_undo_list);
|
|
|
|
undo != NULL;
|
|
|
|
undo = UT_LIST_GET_NEXT(undo_list, undo)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_t* trx;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx = trx_resurrect_insert(undo, rseg);
|
|
|
|
|
|
|
|
trx_sys_rw_trx_add(trx);
|
|
|
|
|
|
|
|
trx_resurrect_table_locks(
|
|
|
|
trx, &trx->rsegs.m_redo, undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ressurrect transactions that were doing updates. */
|
|
|
|
for (undo = UT_LIST_GET_FIRST(rseg->update_undo_list);
|
|
|
|
undo != NULL;
|
|
|
|
undo = UT_LIST_GET_NEXT(undo_list, undo)) {
|
|
|
|
|
|
|
|
/* Check the trx_sys->rw_trx_set first. */
|
|
|
|
trx_sys_mutex_enter();
|
|
|
|
|
|
|
|
trx_t* trx = trx_get_rw_trx_by_id(undo->trx_id);
|
|
|
|
|
|
|
|
trx_sys_mutex_exit();
|
|
|
|
|
|
|
|
if (trx == NULL) {
|
|
|
|
trx = trx_allocate_for_background();
|
|
|
|
|
|
|
|
ut_d(trx->start_file = __FILE__);
|
|
|
|
ut_d(trx->start_line = __LINE__);
|
|
|
|
}
|
|
|
|
|
|
|
|
trx_resurrect_update(trx, undo, rseg);
|
|
|
|
|
|
|
|
trx_sys_rw_trx_add(trx);
|
|
|
|
|
|
|
|
trx_resurrect_table_locks(
|
|
|
|
trx, &trx->rsegs.m_redo, undo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TrxIdSet::iterator end = trx_sys->rw_trx_set.end();
|
|
|
|
|
|
|
|
for (TrxIdSet::iterator it = trx_sys->rw_trx_set.begin();
|
|
|
|
it != end;
|
|
|
|
++it) {
|
|
|
|
|
|
|
|
ut_ad(it->m_trx->in_rw_trx_list);
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
if (it->m_trx->id > trx_sys->rw_max_trx_id) {
|
|
|
|
trx_sys->rw_max_trx_id = it->m_trx->id;
|
|
|
|
}
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
|
|
|
|
if (it->m_trx->state == TRX_STATE_ACTIVE
|
|
|
|
|| it->m_trx->state == TRX_STATE_PREPARED) {
|
|
|
|
|
|
|
|
trx_sys->rw_trx_ids.push_back(it->m_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
UT_LIST_ADD_FIRST(trx_sys->rw_trx_list, it->m_trx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************//**
|
|
|
|
Get next redo rollback segment. (Segment are assigned in round-robin fashion).
|
|
|
|
@return assigned rollback segment instance */
|
|
|
|
static
|
|
|
|
trx_rseg_t*
|
|
|
|
get_next_redo_rseg(
|
|
|
|
/*===============*/
|
|
|
|
ulong max_undo_logs, /*!< in: maximum number of UNDO logs to use */
|
|
|
|
ulint n_tablespaces) /*!< in: number of rollback tablespaces */
|
|
|
|
{
|
|
|
|
trx_rseg_t* rseg;
|
|
|
|
static ulint redo_rseg_slot = 0;
|
|
|
|
ulint slot = 0;
|
|
|
|
|
|
|
|
slot = redo_rseg_slot++;
|
|
|
|
slot = slot % max_undo_logs;
|
|
|
|
|
|
|
|
/* Skip slots alloted to non-redo also ensure even distribution
|
|
|
|
in selecting next redo slots.
|
|
|
|
For example: If we don't do even distribution then for any value of
|
|
|
|
slot between 1 - 32 ... 33rd slots will be alloted creating
|
|
|
|
skewed distribution. */
|
|
|
|
if (trx_sys_is_noredo_rseg_slot(slot)) {
|
|
|
|
|
|
|
|
if (max_undo_logs > srv_tmp_undo_logs) {
|
|
|
|
|
|
|
|
slot %= (max_undo_logs - srv_tmp_undo_logs);
|
|
|
|
|
|
|
|
if (trx_sys_is_noredo_rseg_slot(slot)) {
|
|
|
|
slot += srv_tmp_undo_logs;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
slot = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
ulint start_scan_slot = slot;
|
|
|
|
bool look_for_rollover = false;
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
|
|
|
|
bool allocated = false;
|
|
|
|
|
|
|
|
while (!allocated) {
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
rseg = trx_sys->rseg_array[slot];
|
|
|
|
|
|
|
|
#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 */
|
|
|
|
|
|
|
|
slot = (slot + 1) % max_undo_logs;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Skip slots allocated for noredo rsegs */
|
|
|
|
while (trx_sys_is_noredo_rseg_slot(slot)) {
|
|
|
|
slot = (slot + 1) % max_undo_logs;
|
|
|
|
}
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (rseg == NULL) {
|
|
|
|
continue;
|
|
|
|
} else if (rseg->space == srv_sys_space.space_id()
|
|
|
|
&& n_tablespaces > 0
|
|
|
|
&& trx_sys->rseg_array[slot] != NULL
|
|
|
|
&& trx_sys->rseg_array[slot]->space
|
|
|
|
!= srv_sys_space.space_id()) {
|
|
|
|
/** If undo-tablespace is configured, skip
|
|
|
|
rseg from system-tablespace and try to use
|
|
|
|
undo-tablespace rseg unless it is not possible
|
|
|
|
due to lower limit of undo-logs. */
|
|
|
|
continue;
|
|
|
|
} else if (rseg->skip_allocation) {
|
|
|
|
/** This rseg resides in the tablespace that
|
|
|
|
has been marked for truncate so avoid using this
|
|
|
|
rseg. Also, this is possible only if there are
|
|
|
|
at-least 2 UNDO tablespaces active and 2 redo
|
|
|
|
rsegs active (other than default system bound
|
|
|
|
rseg-0). */
|
|
|
|
ut_ad(n_tablespaces > 1);
|
|
|
|
ut_ad(max_undo_logs
|
|
|
|
>= (1 + srv_tmp_undo_logs + 2));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(rseg->trx_ref_count > 0);
|
|
|
|
ut_ad(!trx_sys_is_noredo_rseg_slot(rseg->id));
|
|
|
|
return(rseg);
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/******************************************************************//**
|
|
|
|
Get next noredo rollback segment.
|
|
|
|
@return assigned rollback segment instance */
|
|
|
|
static
|
|
|
|
trx_rseg_t*
|
|
|
|
get_next_noredo_rseg(
|
|
|
|
/*=================*/
|
|
|
|
ulong max_undo_logs) /*!< in: maximum number of UNDO logs to use */
|
|
|
|
{
|
|
|
|
trx_rseg_t* rseg;
|
|
|
|
static ulint noredo_rseg_slot = 1;
|
|
|
|
ulint slot = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
slot = noredo_rseg_slot++;
|
|
|
|
slot = slot % max_undo_logs;
|
|
|
|
while (!trx_sys_is_noredo_rseg_slot(slot)) {
|
|
|
|
slot = (slot + 1) % max_undo_logs;
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
for (;;) {
|
|
|
|
rseg = trx_sys->rseg_array[slot];
|
|
|
|
|
|
|
|
slot = (slot + 1) % max_undo_logs;
|
|
|
|
|
|
|
|
while (!trx_sys_is_noredo_rseg_slot(slot)) {
|
|
|
|
slot = (slot + 1) % max_undo_logs;
|
|
|
|
}
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (rseg != NULL) {
|
|
|
|
break;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
ut_ad(fsp_is_system_temporary(rseg->space));
|
|
|
|
ut_ad(trx_sys_is_noredo_rseg_slot(rseg->id));
|
|
|
|
return(rseg);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************//**
|
|
|
|
Assigns a rollback segment to a transaction in a round-robin fashion.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return assigned rollback segment instance */
|
2013-03-26 00:03:13 +02:00
|
|
|
static
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_rseg_t*
|
2013-03-26 00:03:13 +02:00
|
|
|
trx_assign_rseg_low(
|
|
|
|
/*================*/
|
2016-08-12 11:17:45 +03:00
|
|
|
ulong max_undo_logs, /*!< in: maximum number of UNDO logs
|
|
|
|
to use */
|
|
|
|
ulint n_tablespaces, /*!< in: number of rollback
|
|
|
|
tablespaces */
|
|
|
|
trx_rseg_type_t rseg_type) /*!< in: type of rseg to assign. */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
2014-02-26 19:23:04 +01:00
|
|
|
if (srv_read_only_mode) {
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_a(max_undo_logs == ULONG_UNDEFINED);
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This breaks true round robin but that should be OK. */
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(max_undo_logs > 0 && max_undo_logs <= TRX_SYS_N_RSEGS);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* Note: The assumption here is that there can't be any gaps in
|
|
|
|
the array. Once we implement more flexible rollback segment
|
|
|
|
management this may not hold. The assertion checks for that case. */
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx_sys->rseg_array[0] != NULL);
|
|
|
|
ut_ad(rseg_type == TRX_RSEG_TYPE_REDO
|
|
|
|
|| trx_sys->rseg_array[1] != NULL);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Slot-0 is always assigned to system-tablespace rseg. */
|
|
|
|
ut_ad(trx_sys->rseg_array[0]->space == srv_sys_space.space_id());
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Slot-1 is always assigned to temp-tablespace rseg. */
|
|
|
|
ut_ad(rseg_type == TRX_RSEG_TYPE_REDO
|
|
|
|
|| fsp_is_system_temporary(trx_sys->rseg_array[1]->space));
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_rseg_t* rseg = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
switch (rseg_type) {
|
|
|
|
case TRX_RSEG_TYPE_NONE:
|
|
|
|
ut_error;
|
|
|
|
|
|
|
|
case TRX_RSEG_TYPE_REDO:
|
|
|
|
rseg = get_next_redo_rseg(max_undo_logs, n_tablespaces);
|
|
|
|
break;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
case TRX_RSEG_TYPE_NOREDO:
|
|
|
|
rseg = get_next_noredo_rseg(srv_tmp_undo_logs + 1);
|
|
|
|
break;
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
return(rseg);
|
|
|
|
}
|
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
/****************************************************************//**
|
2016-08-12 11:17:45 +03:00
|
|
|
Assign a transaction temp-tablespace bounded rollback-segment. */
|
2013-03-26 00:03:13 +02:00
|
|
|
void
|
|
|
|
trx_assign_rseg(
|
|
|
|
/*============*/
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_t* trx) /*!< transaction that involves write
|
|
|
|
to temp-table. */
|
2013-03-26 00:03:13 +02:00
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_a(trx->rsegs.m_noredo.rseg == 0);
|
2013-03-26 00:03:13 +02:00
|
|
|
ut_a(!trx_is_autocommit_non_locking(trx));
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->rsegs.m_noredo.rseg = trx_assign_rseg_low(
|
|
|
|
srv_undo_logs, srv_undo_tablespaces, TRX_RSEG_TYPE_NOREDO);
|
|
|
|
|
|
|
|
if (trx->id == 0) {
|
|
|
|
mutex_enter(&trx_sys->mutex);
|
|
|
|
|
|
|
|
trx->id = trx_sys_get_new_trx_id();
|
|
|
|
|
|
|
|
trx_sys->rw_trx_ids.push_back(trx->id);
|
|
|
|
|
|
|
|
trx_sys->rw_trx_set.insert(TrxTrack(trx->id, trx));
|
|
|
|
|
|
|
|
mutex_exit(&trx_sys->mutex);
|
|
|
|
}
|
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->hit_list.empty());
|
|
|
|
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);
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK));
|
|
|
|
ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC));
|
|
|
|
|
|
|
|
++trx->version;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* 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
|
2016-09-06 09:43:16 +03:00
|
|
|
memset(trx->xid, 0, sizeof(xid_t));
|
|
|
|
trx->xid->formatID = -1;
|
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
|
|
|
|
|
|
|
/* If this transaction came from trx_allocate_for_mysql(),
|
|
|
|
trx->in_mysql_trx_list would hold. In that case, the trx->state
|
|
|
|
change must be protected by the trx_sys->mutex, so that
|
|
|
|
lock_print_info_all_transactions() will have a consistent view. */
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(!trx->in_rw_trx_list);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* We tend to over assert and that complicates the code somewhat.
|
|
|
|
e.g., the transaction state can be set earlier but we are forced to
|
|
|
|
set it under the protection of the trx_sys_t::mutex because some
|
|
|
|
trx list assertions are triggered unnecessarily. */
|
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
|
|
|
trx->rsegs.m_redo.rseg = trx_assign_rseg_low(
|
|
|
|
srv_undo_logs, srv_undo_tablespaces,
|
|
|
|
TRX_RSEG_TYPE_REDO);
|
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 */
|
|
|
|
|
|
|
|
trx_sys_mutex_enter();
|
|
|
|
|
|
|
|
trx->id = trx_sys_get_new_trx_id();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys->rw_trx_ids.push_back(trx->id);
|
|
|
|
|
|
|
|
trx_sys_rw_trx_add(trx);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
UT_LIST_ADD_FIRST(trx_sys->rw_trx_list, trx);
|
|
|
|
|
|
|
|
ut_d(trx->in_rw_trx_list = true);
|
2014-02-26 19:23:04 +01:00
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
if (trx->id > trx_sys->rw_max_trx_id) {
|
|
|
|
trx_sys->rw_max_trx_id = trx->id;
|
|
|
|
}
|
|
|
|
#endif /* UNIV_DEBUG */
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->state = TRX_STATE_ACTIVE;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx_sys_validate_trx_list());
|
|
|
|
|
2016-10-23 13:36:26 -04:00
|
|
|
trx_sys_mutex_exit();
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
} else {
|
|
|
|
trx->id = 0;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
|
|
|
trx_sys_mutex_enter();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(!srv_read_only_mode);
|
|
|
|
|
|
|
|
trx->id = trx_sys_get_new_trx_id();
|
|
|
|
|
|
|
|
trx_sys->rw_trx_ids.push_back(trx->id);
|
|
|
|
|
|
|
|
trx_sys->rw_trx_set.insert(
|
|
|
|
TrxTrack(trx->id, trx));
|
|
|
|
|
|
|
|
trx_sys_mutex_exit();
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->state = TRX_STATE_ACTIVE;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
ut_ad(!read_write);
|
|
|
|
trx->state = TRX_STATE_ACTIVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trx->mysql_thd != NULL) {
|
|
|
|
trx->start_time = thd_start_time_in_secs(trx->mysql_thd);
|
|
|
|
} else {
|
|
|
|
trx->start_time = ut_time();
|
|
|
|
}
|
2016-10-23 13:36:26 -04:00
|
|
|
trx->start_time_micro = clock();
|
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-25 18:57:03 -04:00
|
|
|
trx->start_time_micro = clock();
|
|
|
|
|
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.
|
|
|
|
@param[in,out] trx committed transaction with persistent changes
|
|
|
|
@param[in,out] rseg rollback segment for update_undo, or NULL */
|
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
|
|
|
|
trx_serialise(trx_t* trx, trx_rseg_t* 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
|
|
|
ut_ad(!rseg || rseg == trx->rsegs.m_redo.rseg);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_enter();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx->no = trx_sys_get_new_trx_id();
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/* Track the minimum serialisation number. */
|
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_LIST_ADD_LAST(trx_sys->serialisation_list, trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/* If the rollack segment is not empty then the
|
|
|
|
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. */
|
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 (rseg && rseg->last_page_no == FIL_NULL) {
|
2016-08-12 11:17:45 +03:00
|
|
|
TrxUndoRsegs elem(trx->no);
|
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
|
|
|
elem.push_back(rseg);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
mutex_enter(&purge_sys->pq_mutex);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* This is to reduce the pressure on the trx_sys_t::mutex
|
|
|
|
though in reality it should make very little (read no)
|
|
|
|
difference because this code path is only taken when the
|
|
|
|
rbs is empty. */
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_exit();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2017-03-09 20:40:48 +02:00
|
|
|
purge_sys->purge_queue.push(elem);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
mutex_exit(&purge_sys->pq_mutex);
|
2012-08-01 17:27:34 +03:00
|
|
|
} else {
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_exit();
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
Assign the transaction its history serialisation number and write the
|
2016-08-12 11:17:45 +03:00
|
|
|
update UNDO log record to the assigned rollback segment.
|
|
|
|
@return true if a serialisation log was written */
|
2015-05-26 10:01:12 +03:00
|
|
|
static
|
2016-08-12 11:17:45 +03:00
|
|
|
bool
|
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
|
|
|
|
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->rsegs.m_redo.rseg) {
|
|
|
|
ut_ad(!trx->rsegs.m_redo.insert_undo);
|
|
|
|
ut_ad(!trx->rsegs.m_redo.update_undo);
|
|
|
|
return false;
|
2016-08-12 11:17:45 +03:00
|
|
|
}
|
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_undo_t* insert = trx->rsegs.m_redo.insert_undo;
|
|
|
|
trx_undo_t* update = trx->rsegs.m_redo.update_undo;
|
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
|
|
|
if (!insert && !update) {
|
|
|
|
return false;
|
|
|
|
}
|
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);
|
|
|
|
trx_rseg_t* update_rseg = update ? trx->rsegs.m_redo.rseg : NULL;
|
|
|
|
mutex_enter(&trx->rsegs.m_redo.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
|
|
|
|
update_undo log to the purge queue. */
|
|
|
|
trx_serialise(trx, update_rseg);
|
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
|
|
|
/* It is not necessary to acquire trx->undo_mutex here because
|
|
|
|
only a single OS thread is allowed to commit this transaction. */
|
|
|
|
if (insert) {
|
|
|
|
trx_undo_set_state_at_finish(insert, 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 (update) {
|
|
|
|
/* The undo logs and possible delete-marked records
|
|
|
|
for updates and deletes will be purged later. */
|
|
|
|
page_t* undo_hdr_page = trx_undo_set_state_at_finish(
|
|
|
|
update, 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
|
|
|
trx_undo_update_cleanup(trx, undo_hdr_page, 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
|
|
|
mutex_exit(&trx->rsegs.m_redo.rseg->mutex);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
|
|
|
|
|
2017-03-09 22:06:22 +02:00
|
|
|
trx_sysf_t* sys_header = trx_sysf_get(mtr);
|
2014-08-06 15:39:15 +03:00
|
|
|
#ifdef WITH_WSREP
|
|
|
|
/* Update latest MySQL wsrep XID in trx sys header. */
|
2016-08-12 11:17:45 +03:00
|
|
|
if (wsrep_is_wsrep_xid(trx->xid)) {
|
|
|
|
trx_sys_update_wsrep_checkpoint(trx->xid, sys_header, mtr);
|
2014-08-06 15:39:15 +03:00
|
|
|
}
|
|
|
|
#endif /* WITH_WSREP */
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/* Update the latest MySQL binlog name and offset info
|
|
|
|
in trx sys header if MySQL binlogging is on or the database
|
|
|
|
server is a MySQL replication slave */
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->mysql_log_file_name != NULL
|
2012-08-01 17:27:34 +03:00
|
|
|
&& trx->mysql_log_file_name[0] != '\0') {
|
|
|
|
|
|
|
|
trx_sys_update_mysql_binlog_offset(
|
|
|
|
trx->mysql_log_file_name,
|
|
|
|
trx->mysql_log_offset,
|
2016-08-12 11:17:45 +03:00
|
|
|
TRX_SYS_MYSQL_LOG_INFO,
|
2016-09-06 09:43:16 +03:00
|
|
|
sys_header,
|
2014-08-06 15:39:15 +03:00
|
|
|
mtr);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx->mysql_log_file_name = NULL;
|
|
|
|
}
|
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
|
|
|
return(true);
|
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
|
|
|
|
|
|
|
mutex_enter(&fts->bg_threads_mutex);
|
|
|
|
|
|
|
|
if (fts->fts_status & BG_THREAD_STOP) {
|
|
|
|
/* The table is about to be dropped, no use
|
|
|
|
adding anything to its work queue. */
|
|
|
|
|
|
|
|
mutex_exit(&fts->bg_threads_mutex);
|
|
|
|
} else {
|
|
|
|
mem_heap_t* heap;
|
|
|
|
mutex_exit(&fts->bg_threads_mutex);
|
|
|
|
|
|
|
|
ut_a(fts->add_wq);
|
|
|
|
|
|
|
|
heap = static_cast<mem_heap_t*>(doc_ids->self_heap->arg);
|
|
|
|
|
|
|
|
ib_wqueue_add(fts->add_wq, doc_ids, heap);
|
|
|
|
|
|
|
|
/* fts_trx_table_t no longer owns the list. */
|
|
|
|
ftt->added_doc_ids = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
{
|
|
|
|
|
|
|
|
ut_ad(trx->id != 0);
|
|
|
|
|
|
|
|
/* consider using trx->start_time if calling time() is too
|
|
|
|
expensive here */
|
|
|
|
time_t now = ut_time();
|
|
|
|
|
|
|
|
trx_mod_tables_t::const_iterator end = trx->mod_tables.end();
|
|
|
|
|
|
|
|
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. */
|
|
|
|
(*it)->update_time = now;
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->mod_tables.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Erase the transaction from running transaction lists and serialization
|
|
|
|
list. Active RW transaction list of a MVCC snapshot(ReadView::prepare)
|
|
|
|
won't include this transaction after this call. All implicit locks are
|
|
|
|
also released by this call as trx is removed from rw_trx_list.
|
|
|
|
@param[in] trx Transaction to erase, must have an ID > 0
|
|
|
|
@param[in] serialised true if serialisation log was written */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
trx_erase_lists(
|
|
|
|
trx_t* trx,
|
|
|
|
bool serialised)
|
|
|
|
{
|
|
|
|
ut_ad(trx->id > 0);
|
|
|
|
trx_sys_mutex_enter();
|
|
|
|
|
|
|
|
if (serialised) {
|
|
|
|
UT_LIST_REMOVE(trx_sys->serialisation_list, trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
trx_ids_t::iterator it = std::lower_bound(
|
|
|
|
trx_sys->rw_trx_ids.begin(),
|
|
|
|
trx_sys->rw_trx_ids.end(),
|
|
|
|
trx->id);
|
|
|
|
ut_ad(*it == trx->id);
|
|
|
|
trx_sys->rw_trx_ids.erase(it);
|
|
|
|
|
|
|
|
if (trx->read_only || trx->rsegs.m_redo.rseg == NULL) {
|
|
|
|
|
|
|
|
ut_ad(!trx->in_rw_trx_list);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
UT_LIST_REMOVE(trx_sys->rw_trx_list, trx);
|
|
|
|
ut_d(trx->in_rw_trx_list = false);
|
|
|
|
ut_ad(trx_sys_validate_trx_list());
|
|
|
|
|
|
|
|
if (trx->read_view != NULL) {
|
|
|
|
trx_sys->mvcc->view_close(trx->read_view, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
trx_sys->rw_trx_set.erase(TrxTrack(trx->id));
|
|
|
|
|
|
|
|
trx_sys_mutex_exit();
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/****************************************************************//**
|
2014-02-01 09:33:26 +01:00
|
|
|
Commits a transaction in memory. */
|
2016-09-06 09:43:16 +03:00
|
|
|
static
|
2012-08-01 17:27:34 +03:00
|
|
|
void
|
2014-02-01 09:33:26 +01:00
|
|
|
trx_commit_in_memory(
|
|
|
|
/*=================*/
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_t* trx, /*!< in/out: transaction */
|
|
|
|
const mtr_t* mtr, /*!< in: mini-transaction of
|
|
|
|
trx_write_serialisation_history(), or NULL if
|
|
|
|
the transaction did not modify anything */
|
|
|
|
bool serialised)
|
|
|
|
/*!< in: true if serialisation log was
|
|
|
|
written */
|
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
|
|
|
|
|
|
|
if (trx_is_autocommit_non_locking(trx)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx->id == 0);
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_ad(trx->read_only);
|
|
|
|
ut_a(!trx->is_recovered);
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx->rsegs.m_redo.rseg == NULL);
|
2012-08-01 17:27:34 +03:00
|
|
|
ut_ad(!trx->in_rw_trx_list);
|
|
|
|
|
|
|
|
/* 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 not) be added
|
|
|
|
becuase it is flagged as a non-locking read-only transaction. */
|
|
|
|
|
|
|
|
ut_a(UT_LIST_GET_LEN(trx->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 mysql_trx_list and freed
|
|
|
|
without first acquiring the trx_sys_t::mutex. */
|
|
|
|
|
|
|
|
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->read_view != NULL) {
|
|
|
|
trx_sys->mvcc->view_close(trx->read_view, false);
|
|
|
|
}
|
2013-03-26 00:03:13 +02:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
MONITOR_INC(MONITOR_TRX_NL_RO_COMMIT);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
/* AC-NL-RO transactions can't be rolled back asynchronously. */
|
|
|
|
ut_ad(!trx->abort);
|
|
|
|
ut_ad(!(trx->in_innodb
|
|
|
|
& (TRX_FORCE_ROLLBACK | TRX_FORCE_ROLLBACK_ASYNC)));
|
|
|
|
|
|
|
|
trx->state = TRX_STATE_NOT_STARTED;
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
} else {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
if (trx->id > 0) {
|
|
|
|
/* For consistent snapshot, we need to remove current
|
|
|
|
transaction from running transaction id list for mvcc
|
|
|
|
before doing commit and releasing locks. */
|
|
|
|
trx_erase_lists(trx, serialised);
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
lock_trx_release_locks(trx);
|
|
|
|
|
|
|
|
/* Remove the transaction from the list of active
|
|
|
|
transactions now that it no longer holds any user locks. */
|
|
|
|
|
|
|
|
ut_ad(trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY));
|
2016-08-12 11:17:45 +03:00
|
|
|
DEBUG_SYNC_C("after_trx_committed_in_memory");
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->read_only || trx->rsegs.m_redo.rseg == NULL) {
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
MONITOR_INC(MONITOR_TRX_RO_COMMIT);
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->read_view != NULL) {
|
|
|
|
trx_sys->mvcc->view_close(
|
|
|
|
trx->read_view, false);
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
} else {
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx->id > 0);
|
2012-08-01 17:27:34 +03:00
|
|
|
MONITOR_INC(MONITOR_TRX_RW_COMMIT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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->rsegs.m_redo.update_undo);
|
|
|
|
|
|
|
|
if (trx_rseg_t* rseg = trx->rsegs.m_redo.rseg) {
|
2016-08-12 11:17:45 +03:00
|
|
|
mutex_enter(&rseg->mutex);
|
|
|
|
ut_ad(rseg->trx_ref_count > 0);
|
|
|
|
--rseg->trx_ref_count;
|
|
|
|
mutex_exit(&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
|
|
|
if (trx_undo_t*& insert = trx->rsegs.m_redo.insert_undo) {
|
|
|
|
ut_ad(insert->rseg == rseg);
|
|
|
|
trx_undo_commit_cleanup(insert, false);
|
|
|
|
insert = NULL;
|
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
|
|
|
}
|
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
|
|
|
ut_ad(!trx->rsegs.m_redo.insert_undo);
|
|
|
|
|
|
|
|
if (mtr != NULL) {
|
|
|
|
if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) {
|
|
|
|
ut_ad(undo->rseg == trx->rsegs.m_noredo.rseg);
|
|
|
|
trx_undo_commit_cleanup(undo, true);
|
|
|
|
undo = NULL;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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_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. */
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
lsn_t lsn = mtr->commit_lsn();
|
|
|
|
|
|
|
|
if (lsn == 0) {
|
|
|
|
/* Nothing to be done. */
|
|
|
|
} else if (trx->flush_log_later) {
|
2012-08-01 17:27:34 +03:00
|
|
|
/* Do nothing yet */
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->must_flush_log_later = true;
|
|
|
|
} else if (srv_flush_log_at_trx_commit == 0
|
|
|
|
|| thd_requested_durability(trx->mysql_thd)
|
|
|
|
== HA_IGNORE_DURABILITY) {
|
2012-08-01 17:27:34 +03:00
|
|
|
/* Do nothing */
|
|
|
|
} else {
|
2013-03-26 00:03:13 +02:00
|
|
|
trx_flush_log_if_needed(lsn, trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
trx->commit_lsn = lsn;
|
2014-11-18 17:41:12 +01: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();
|
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
|
|
|
ut_ad(!trx->rsegs.m_noredo.undo);
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/* Free all savepoints, starting from the first. */
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_named_savept_t* savep = UT_LIST_GET_FIRST(trx->trx_savepoints);
|
2013-03-26 00:03:13 +02:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_roll_savepoints_free(trx, savep);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->fts_trx != NULL) {
|
|
|
|
trx_finalize_for_fts(trx, trx->undo_no != 0);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
trx_mutex_enter(trx);
|
|
|
|
trx->dict_operation = TRX_DICT_OP_NONE;
|
|
|
|
|
2014-08-06 15:39:15 +03:00
|
|
|
#ifdef WITH_WSREP
|
2017-01-03 10:45:55 +05:30
|
|
|
if (trx->mysql_thd && wsrep_on(trx->mysql_thd)) {
|
2014-08-06 15:39:15 +03:00
|
|
|
trx->lock.was_chosen_as_deadlock_victim = FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
/* Because we can rollback transactions asynchronously, we change
|
|
|
|
the state at the last step. trx_t::abort cannot change once commit
|
|
|
|
or rollback has started because we will have released the locks by
|
|
|
|
the time we get here. */
|
|
|
|
|
|
|
|
if (trx->abort) {
|
|
|
|
|
|
|
|
trx->abort = false;
|
|
|
|
trx->state = TRX_STATE_FORCED_ROLLBACK;
|
|
|
|
} else {
|
|
|
|
trx->state = TRX_STATE_NOT_STARTED;
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* trx->in_mysql_trx_list would hold between
|
|
|
|
trx_allocate_for_mysql() and trx_free_for_mysql(). It does not
|
|
|
|
hold for recovered transactions or system transactions. */
|
2016-08-12 11:17:45 +03:00
|
|
|
assert_trx_is_free(trx);
|
|
|
|
|
|
|
|
trx_init(trx);
|
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
trx_mutex_exit(trx);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_a(trx->error_state == DB_SUCCESS);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
/****************************************************************//**
|
|
|
|
Commits a transaction and a mini-transaction. */
|
|
|
|
void
|
|
|
|
trx_commit_low(
|
|
|
|
/*===========*/
|
|
|
|
trx_t* trx, /*!< in/out: transaction */
|
|
|
|
mtr_t* mtr) /*!< in/out: mini-transaction (will be committed),
|
|
|
|
or NULL if trx made no modifications */
|
|
|
|
{
|
|
|
|
assert_trx_nonlocking_or_in_list(trx);
|
|
|
|
ut_ad(!trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY));
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(!mtr || mtr->is_active());
|
|
|
|
ut_ad(!mtr == !(trx_is_rseg_updated(trx)));
|
2014-02-01 09:33:26 +01:00
|
|
|
|
|
|
|
/* undo_no is non-zero if we're doing the final commit. */
|
2016-08-12 11:17:45 +03:00
|
|
|
if (trx->fts_trx != NULL && trx->undo_no != 0) {
|
2014-02-01 09:33:26 +01:00
|
|
|
dberr_t error;
|
|
|
|
|
|
|
|
ut_a(!trx_is_autocommit_non_locking(trx));
|
|
|
|
|
|
|
|
error = fts_commit(trx);
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
if (error != DB_SUCCESS && error != DB_DUPLICATE_KEY) {
|
|
|
|
/* FTS-FIXME: once we can return values from this
|
|
|
|
function, we should do so and signal an error
|
|
|
|
instead of just dying. */
|
|
|
|
|
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
bool serialised;
|
|
|
|
|
|
|
|
if (mtr != NULL) {
|
|
|
|
|
|
|
|
mtr->set_sync();
|
|
|
|
|
|
|
|
serialised = trx_write_serialisation_history(trx, mtr);
|
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
/* 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(mtr);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
DBUG_EXECUTE_IF("ib_crash_during_trx_commit_in_mem",
|
|
|
|
if (trx_is_rseg_updated(trx)) {
|
|
|
|
log_make_checkpoint_at(LSN_MAX, TRUE);
|
|
|
|
DBUG_SUICIDE();
|
|
|
|
});
|
2014-02-01 09:33:26 +01:00
|
|
|
/*--------------*/
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
} else {
|
2016-08-12 11:17:45 +03:00
|
|
|
serialised = false;
|
|
|
|
}
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
/* In case of this function is called from a stack executing
|
|
|
|
THD::release_resources -> ...
|
|
|
|
innobase_connection_close() ->
|
|
|
|
trx_rollback_for_mysql... -> .
|
|
|
|
mysql's thd does not seem to have
|
|
|
|
thd->debug_sync_control defined any longer. However the stack
|
|
|
|
is possible only with a prepared trx not updating any data.
|
|
|
|
*/
|
|
|
|
if (trx->mysql_thd != NULL && trx_is_redo_rseg_updated(trx)) {
|
|
|
|
DEBUG_SYNC_C("before_trx_state_committed_in_memory");
|
2014-02-01 09:33:26 +01:00
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
#endif
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_commit_in_memory(trx, mtr, serialised);
|
2014-02-01 09:33:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
Commits a transaction. */
|
|
|
|
void
|
|
|
|
trx_commit(
|
|
|
|
/*=======*/
|
|
|
|
trx_t* trx) /*!< in/out: transaction */
|
|
|
|
{
|
|
|
|
mtr_t* mtr;
|
2016-08-12 11:17:45 +03:00
|
|
|
mtr_t local_mtr;
|
2014-02-01 09:33:26 +01:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
DBUG_EXECUTE_IF("ib_trx_commit_crash_before_trx_commit_start",
|
|
|
|
DBUG_SUICIDE(););
|
|
|
|
|
|
|
|
if (trx_is_rseg_updated(trx)) {
|
2014-02-01 09:33:26 +01:00
|
|
|
mtr = &local_mtr;
|
2016-08-12 11:17:45 +03:00
|
|
|
mtr_start_sync(mtr);
|
2014-02-01 09:33:26 +01:00
|
|
|
} else {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2014-02-01 09:33:26 +01:00
|
|
|
mtr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
trx_commit_low(trx, mtr);
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/****************************************************************//**
|
|
|
|
Cleans up a transaction at database startup. The cleanup is needed if
|
|
|
|
the transaction already got to the middle of a commit when the database
|
|
|
|
crashed, and we cannot roll it back. */
|
|
|
|
void
|
|
|
|
trx_cleanup_at_db_startup(
|
|
|
|
/*======================*/
|
|
|
|
trx_t* trx) /*!< in: transaction */
|
|
|
|
{
|
|
|
|
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
|
|
|
ut_ad(!trx->rsegs.m_noredo.undo);
|
|
|
|
ut_ad(!trx->rsegs.m_redo.update_undo);
|
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_redo.insert_undo) {
|
|
|
|
ut_ad(undo->rseg == trx->rsegs.m_redo.rseg);
|
|
|
|
trx_undo_commit_cleanup(undo, false);
|
|
|
|
undo = NULL;
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
memset(&trx->rsegs, 0x0, sizeof(trx->rsegs));
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->undo_no = 0;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->undo_rseg_space = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->last_sql_stat_start.least_undo_no = 0;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_enter();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
ut_a(!trx->read_only);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
UT_LIST_REMOVE(trx_sys->rw_trx_list, trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
ut_d(trx->in_rw_trx_list = FALSE);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_exit();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* Change the transaction state without mutex protection, now
|
|
|
|
that it no longer is in the trx_list. Recovered transactions
|
|
|
|
are never placed in the mysql_trx_list. */
|
|
|
|
ut_ad(trx->is_recovered);
|
|
|
|
ut_ad(!trx->in_rw_trx_list);
|
|
|
|
ut_ad(!trx->in_mysql_trx_list);
|
|
|
|
trx->state = TRX_STATE_NOT_STARTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************//**
|
|
|
|
Assigns a read view for a consistent read query. All the consistent reads
|
|
|
|
within the same transaction will get the same read view, which is created
|
|
|
|
when this function is first called for a new started transaction.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return consistent read view */
|
|
|
|
ReadView*
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_assign_read_view(
|
|
|
|
/*=================*/
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_t* trx) /*!< in/out: active transaction */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
|
|
|
ut_ad(trx->state == TRX_STATE_ACTIVE);
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
if (srv_read_only_mode) {
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx->read_view == NULL);
|
|
|
|
return(NULL);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
} else if (!MVCC::is_view_active(trx->read_view)) {
|
|
|
|
trx_sys->mvcc->view_open(trx->read_view, trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return(trx->read_view);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
Prepares a transaction for commit/rollback. */
|
|
|
|
void
|
|
|
|
trx_commit_or_rollback_prepare(
|
|
|
|
/*===========================*/
|
|
|
|
trx_t* trx) /*!< in/out: transaction */
|
|
|
|
{
|
|
|
|
/* We are reading trx->state without holding trx_sys->mutex
|
|
|
|
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
|
|
|
case TRX_STATE_FORCED_ROLLBACK:
|
2016-09-06 09:43:16 +03:00
|
|
|
|
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:
|
2016-08-12 11:17:45 +03:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
trx_commit(trx);
|
|
|
|
|
|
|
|
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 */
|
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
TrxInInnoDB trx_in_innodb(trx, true);
|
|
|
|
|
|
|
|
if (trx_in_innodb.is_aborted()
|
|
|
|
&& trx->killed_by != os_thread_get_curr_id()) {
|
|
|
|
|
|
|
|
return(DB_FORCED_ABORT);
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
/* 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:
|
2016-08-12 11:17:45 +03:00
|
|
|
case TRX_STATE_FORCED_ROLLBACK:
|
|
|
|
|
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:
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->op_info = "committing";
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
if (trx->id != 0) {
|
|
|
|
trx_update_mod_tables_timestamp(trx);
|
|
|
|
}
|
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_commit(trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
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
|
|
|
|
|| thd_requested_durability(trx->mysql_thd)
|
|
|
|
== HA_IGNORE_DURABILITY) {
|
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:
|
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
break;
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
2016-08-12 11:17:45 +03:00
|
|
|
case TRX_STATE_FORCED_ROLLBACK:
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->undo_no = 0;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx->undo_rseg_space = 0;
|
2012-08-01 17:27:34 +03:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
Prints info about a transaction.
|
|
|
|
Caller must hold trx_sys->mutex. */
|
|
|
|
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
|
|
|
ut_ad(trx_sys_mutex_own());
|
2012-08-01 17:27:34 +03:00
|
|
|
|
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
|
|
|
|
are holding the trx_sys->mutex. It may change from ACTIVE to
|
|
|
|
PREPARED or COMMITTED. */
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
|
|
|
fputs(", not started", f);
|
|
|
|
goto state_ok;
|
2016-08-12 11:17:45 +03:00
|
|
|
case TRX_STATE_FORCED_ROLLBACK:
|
|
|
|
fputs(", forced rollback", f);
|
|
|
|
goto state_ok;
|
2012-08-01 17:27:34 +03:00
|
|
|
case TRX_STATE_ACTIVE:
|
|
|
|
fprintf(f, ", ACTIVE %lu sec",
|
|
|
|
(ulong) difftime(time(NULL), trx->start_time));
|
|
|
|
goto state_ok;
|
|
|
|
case TRX_STATE_PREPARED:
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-02-23 23:05:12 +02:00
|
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
2012-08-01 17:27:34 +03:00
|
|
|
if (trx->has_search_latch) {
|
|
|
|
newline = TRUE;
|
|
|
|
fputs(", holds adaptive hash latch", f);
|
|
|
|
}
|
2017-02-23 23:05:12 +02:00
|
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
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.
|
|
|
|
The caller must hold lock_sys->mutex and trx_sys->mutex.
|
|
|
|
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());
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx_sys_mutex_own());
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
Prints info about a transaction.
|
|
|
|
Acquires and releases lock_sys->mutex and trx_sys->mutex. */
|
|
|
|
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();
|
|
|
|
|
|
|
|
mutex_enter(&trx_sys->mutex);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_print_low(f, trx, max_query_len,
|
2013-03-26 00:03:13 +02:00
|
|
|
n_rec_locks, n_trx_locks, heap_size);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2012-08-01 17:27:34 +03:00
|
|
|
mutex_exit(&trx_sys->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
/**********************************************************************//**
|
|
|
|
Asserts that a transaction has been started.
|
|
|
|
The caller must hold trx_sys->mutex.
|
|
|
|
@return TRUE if started */
|
|
|
|
ibool
|
|
|
|
trx_assert_started(
|
|
|
|
/*===============*/
|
|
|
|
const trx_t* trx) /*!< in: transaction */
|
|
|
|
{
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx_sys_mutex_own());
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* Non-locking autocommits should not hold any locks and this
|
|
|
|
function is only called from the locking code. */
|
2016-08-12 11:17:45 +03:00
|
|
|
check_trx_state(trx);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* trx->state can change from or to NOT_STARTED while we are holding
|
|
|
|
trx_sys->mutex for non-locking autocommit selects but not for other
|
|
|
|
types of transactions. It may change from ACTIVE to PREPARED. Unless
|
|
|
|
we are holding lock_sys->mutex, it may also change to COMMITTED. */
|
|
|
|
|
|
|
|
switch (trx->state) {
|
|
|
|
case TRX_STATE_PREPARED:
|
|
|
|
return(TRUE);
|
|
|
|
|
|
|
|
case TRX_STATE_ACTIVE:
|
|
|
|
case TRX_STATE_COMMITTED_IN_MEMORY:
|
|
|
|
return(TRUE);
|
|
|
|
|
|
|
|
case TRX_STATE_NOT_STARTED:
|
2016-08-12 11:17:45 +03:00
|
|
|
case TRX_STATE_FORCED_ROLLBACK:
|
2012-08-01 17:27:34 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_error;
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
|
|
|
|
/*******************************************************************//**
|
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-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
|
|
|
/* It is not necessary to acquire trx->undo_mutex here because
|
|
|
|
only the owning (connection) thread of the transaction is
|
|
|
|
allowed to perform XA PREPARE. */
|
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-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_undo_t* insert = trx->rsegs.m_redo.insert_undo;
|
|
|
|
trx_undo_t* update = trx->rsegs.m_redo.update_undo;
|
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 (!insert && !update) {
|
|
|
|
/* 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;
|
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(true);
|
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);
|
|
|
|
|
|
|
|
if (insert) {
|
|
|
|
ut_ad(insert->rseg == rseg);
|
|
|
|
trx_undo_set_state_at_prepare(trx, insert, false, &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 (update) {
|
|
|
|
ut_ad(update->rseg == rseg);
|
|
|
|
trx_undo_set_state_at_prepare(trx, update, false, &mtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
|
|
|
{
|
|
|
|
/* This transaction has crossed the point of no return and cannot
|
|
|
|
be rolled back asynchronously now. It must commit or rollback
|
|
|
|
synhronously. */
|
|
|
|
|
|
|
|
/* 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);
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_enter();
|
2012-08-01 17:27:34 +03:00
|
|
|
trx->state = TRX_STATE_PREPARED;
|
|
|
|
trx_sys->n_prepared_trx++;
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_exit();
|
2012-08-01 17:27:34 +03:00
|
|
|
/*--------------------------------------*/
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
switch (thd_requested_durability(trx->mysql_thd)) {
|
|
|
|
case HA_IGNORE_DURABILITY:
|
|
|
|
/* We set the HA_IGNORE_DURABILITY during prepare phase of
|
|
|
|
binlog group commit to not flush redo log for every transaction
|
|
|
|
here. So that we can flush prepared records of transactions to
|
|
|
|
redo log in a group right before writing them to binary log
|
|
|
|
during flush stage of binlog group commit. */
|
|
|
|
break;
|
|
|
|
case HA_REGULAR_DURABILITY:
|
|
|
|
if (lsn == 0) {
|
|
|
|
break;
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
/**
|
|
|
|
Does the transaction prepare for MySQL.
|
|
|
|
@param[in, out] trx Transaction instance to prepare */
|
|
|
|
dberr_t
|
|
|
|
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);
|
|
|
|
|
|
|
|
TrxInInnoDB trx_in_innodb(trx, true);
|
|
|
|
|
|
|
|
if (trx_in_innodb.is_aborted()
|
|
|
|
&& trx->killed_by != os_thread_get_curr_id()) {
|
|
|
|
|
|
|
|
return(DB_FORCED_ABORT);
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
trx->op_info = "preparing";
|
|
|
|
|
|
|
|
trx_prepare(trx);
|
|
|
|
|
|
|
|
trx->op_info = "";
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
return(DB_SUCCESS);
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
This function is used to find number of prepared transactions and
|
|
|
|
their transaction objects for a recovery.
|
2016-08-12 11:17:45 +03:00
|
|
|
@return number of prepared transactions stored in xid_list */
|
2012-08-01 17:27:34 +03:00
|
|
|
int
|
|
|
|
trx_recover_for_mysql(
|
|
|
|
/*==================*/
|
|
|
|
XID* xid_list, /*!< in/out: prepared transactions */
|
|
|
|
ulint len) /*!< in: number of slots in xid_list */
|
|
|
|
{
|
|
|
|
const trx_t* trx;
|
|
|
|
ulint count = 0;
|
|
|
|
|
|
|
|
ut_ad(xid_list);
|
|
|
|
ut_ad(len);
|
|
|
|
|
|
|
|
/* We should set those transactions which are in the prepared state
|
|
|
|
to the xid_list */
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_enter();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
|
|
|
|
trx != NULL;
|
|
|
|
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
|
|
|
|
|
|
|
|
assert_trx_in_rw_list(trx);
|
|
|
|
|
|
|
|
/* The state of a read-write transaction cannot change
|
|
|
|
from or to NOT_STARTED while we are holding the
|
|
|
|
trx_sys->mutex. It may change to PREPARED, but not if
|
|
|
|
trx->is_recovered. It may also change to COMMITTED. */
|
|
|
|
if (trx_state_eq(trx, TRX_STATE_PREPARED)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
xid_list[count] = *trx->xid;
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
if (count == 0) {
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::info() << "Starting recovery for"
|
|
|
|
" XA transactions...";
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::info() << "Transaction "
|
|
|
|
<< trx_get_id_for_print(trx)
|
|
|
|
<< " in prepared state after recovery";
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::info() << "Transaction contains changes to "
|
|
|
|
<< trx->undo_no << " rows";
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
if (count == len) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_exit();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
if (count > 0){
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::info() << count << " transactions in prepared state"
|
|
|
|
" after recovery";
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
return(int (count));
|
2012-08-01 17:27:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************//**
|
|
|
|
This function is used to find one X/Open XA distributed transaction
|
|
|
|
which is in the prepared state
|
2016-08-12 11:17:45 +03:00
|
|
|
@return trx on match, the trx->xid will be invalidated;
|
2012-08-01 17:27:34 +03:00
|
|
|
note that the trx may have been committed, unless the caller is
|
|
|
|
holding lock_sys->mutex */
|
2016-09-06 09:43:16 +03:00
|
|
|
static MY_ATTRIBUTE((warn_unused_result))
|
2012-08-01 17:27:34 +03:00
|
|
|
trx_t*
|
|
|
|
trx_get_trx_by_xid_low(
|
|
|
|
/*===================*/
|
2016-09-06 09:43:16 +03:00
|
|
|
XID* xid) /*!< in: X/Open XA transaction
|
2012-08-01 17:27:34 +03:00
|
|
|
identifier */
|
|
|
|
{
|
|
|
|
trx_t* trx;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(trx_sys_mutex_own());
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
|
|
|
|
trx != NULL;
|
|
|
|
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
|
|
|
|
|
|
|
|
assert_trx_in_rw_list(trx);
|
|
|
|
|
|
|
|
/* Compare two X/Open XA transaction id's: their
|
|
|
|
length should be the same and binary comparison
|
|
|
|
of gtrid_length+bqual_length bytes should be
|
|
|
|
the same */
|
|
|
|
|
|
|
|
if (trx->is_recovered
|
|
|
|
&& trx_state_eq(trx, TRX_STATE_PREPARED)
|
2016-09-06 09:43:16 +03:00
|
|
|
&& xid->eq((XID*)trx->xid)) {
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* Invalidate the XID, so that subsequent calls
|
|
|
|
will not find it. */
|
2016-09-10 16:04:44 +02:00
|
|
|
trx->xid->null();
|
2012-08-01 17:27:34 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************//**
|
|
|
|
This function is used to find one X/Open XA distributed transaction
|
|
|
|
which is in the prepared state
|
2016-08-12 11:17:45 +03:00
|
|
|
@return trx or NULL; on match, the trx->xid will be invalidated;
|
2012-08-01 17:27:34 +03:00
|
|
|
note that the trx may have been committed, unless the caller is
|
|
|
|
holding lock_sys->mutex */
|
|
|
|
trx_t*
|
|
|
|
trx_get_trx_by_xid(
|
|
|
|
/*===============*/
|
2016-09-06 09:43:16 +03:00
|
|
|
XID* xid) /*!< in: X/Open XA transaction identifier */
|
2012-08-01 17:27:34 +03:00
|
|
|
{
|
|
|
|
trx_t* trx;
|
|
|
|
|
|
|
|
if (xid == NULL) {
|
|
|
|
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_enter();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
/* Recovered/Resurrected transactions are always only on the
|
|
|
|
trx_sys_t::rw_trx_list. */
|
2016-09-06 09:43:16 +03:00
|
|
|
trx = trx_get_trx_by_xid_low((XID*)xid);
|
2012-08-01 17:27:34 +03:00
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
trx_sys_mutex_exit();
|
2012-08-01 17:27:34 +03:00
|
|
|
|
|
|
|
return(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************//**
|
|
|
|
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
|
|
|
case TRX_STATE_FORCED_ROLLBACK:
|
|
|
|
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
|
|
|
|
trx_sys_t::rw_trx_list. */
|
|
|
|
if (!trx->read_only) {
|
|
|
|
trx_set_rw_mode(trx);
|
|
|
|
} else if (!srv_read_only_mode) {
|
|
|
|
trx_assign_rseg(trx);
|
|
|
|
}
|
|
|
|
}
|
2012-08-01 17:27:34 +03:00
|
|
|
return;
|
|
|
|
case TRX_STATE_PREPARED:
|
|
|
|
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
|
|
|
case TRX_STATE_FORCED_ROLLBACK:
|
2016-09-06 09:43:16 +03:00
|
|
|
|
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:
|
|
|
|
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:
|
2016-08-12 11:17:45 +03:00
|
|
|
case TRX_STATE_FORCED_ROLLBACK:
|
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
/* 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:
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
/* We have this start if not started idiom, therefore we
|
|
|
|
can't add stronger checks here. */
|
|
|
|
trx->ddl = true;
|
|
|
|
|
|
|
|
ut_ad(trx->dict_operation != TRX_DICT_OP_NONE);
|
|
|
|
ut_ad(trx->will_lock > 0);
|
|
|
|
return;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2013-03-26 00:03:13 +02:00
|
|
|
case TRX_STATE_PREPARED:
|
|
|
|
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->in_rw_trx_list);
|
|
|
|
ut_ad(!trx_is_autocommit_non_locking(trx));
|
|
|
|
|
|
|
|
if (srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function is promoting existing trx from ro mode to rw mode.
|
|
|
|
In this process it has acquired trx_sys->mutex as it plan to
|
|
|
|
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. */
|
|
|
|
|
|
|
|
trx->rsegs.m_redo.rseg = trx_assign_rseg_low(
|
|
|
|
srv_undo_logs, srv_undo_tablespaces, TRX_RSEG_TYPE_REDO);
|
|
|
|
|
|
|
|
ut_ad(trx->rsegs.m_redo.rseg != 0);
|
|
|
|
|
|
|
|
mutex_enter(&trx_sys->mutex);
|
|
|
|
|
|
|
|
ut_ad(trx->id == 0);
|
|
|
|
trx->id = trx_sys_get_new_trx_id();
|
|
|
|
|
|
|
|
trx_sys->rw_trx_ids.push_back(trx->id);
|
|
|
|
|
|
|
|
trx_sys->rw_trx_set.insert(TrxTrack(trx->id, trx));
|
|
|
|
|
|
|
|
/* So that we can see our own changes. */
|
|
|
|
if (MVCC::is_view_active(trx->read_view)) {
|
|
|
|
MVCC::set_view_creator_trx_id(trx->read_view, trx->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
if (trx->id > trx_sys->rw_max_trx_id) {
|
|
|
|
trx_sys->rw_max_trx_id = trx->id;
|
|
|
|
}
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
|
|
|
|
if (!trx->read_only) {
|
|
|
|
UT_LIST_ADD_FIRST(trx_sys->rw_trx_list, trx);
|
|
|
|
|
|
|
|
ut_d(trx->in_rw_trx_list = true);
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&trx_sys->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Kill all transactions that are blocking this transaction from acquiring locks.
|
|
|
|
@param[in,out] trx High priority transaction */
|
|
|
|
|
|
|
|
void
|
|
|
|
trx_kill_blocking(trx_t* trx)
|
|
|
|
{
|
|
|
|
if (trx->hit_list.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_SYNC_C("trx_kill_blocking_enter");
|
|
|
|
|
|
|
|
ulint had_dict_lock = trx->dict_operation_lock_mode;
|
|
|
|
|
|
|
|
switch (had_dict_lock) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RW_S_LATCH:
|
|
|
|
/* Release foreign key check latch */
|
|
|
|
row_mysql_unfreeze_data_dictionary(trx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* There should never be a lock wait when the
|
|
|
|
dictionary latch is reserved in X mode. Dictionary
|
|
|
|
transactions should only acquire locks on dictionary
|
|
|
|
tables, not other tables. All access to dictionary
|
|
|
|
tables should be covered by dictionary
|
|
|
|
transactions. */
|
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_a(trx->dict_operation_lock_mode == 0);
|
|
|
|
|
|
|
|
/** Kill the transactions in the lock acquisition order old -> new. */
|
|
|
|
hit_list_t::reverse_iterator end = trx->hit_list.rend();
|
|
|
|
|
|
|
|
for (hit_list_t::reverse_iterator it = trx->hit_list.rbegin();
|
|
|
|
it != end;
|
|
|
|
++it) {
|
|
|
|
|
|
|
|
trx_t* victim_trx = it->m_trx;
|
|
|
|
ulint version = it->m_version;
|
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
/* Shouldn't commit suicide. */
|
2016-08-12 11:17:45 +03:00
|
|
|
ut_ad(victim_trx != trx);
|
|
|
|
ut_ad(victim_trx->mysql_thd != trx->mysql_thd);
|
|
|
|
|
|
|
|
/* Check that the transaction isn't active inside
|
|
|
|
InnoDB code. We have to wait while it is executing
|
|
|
|
in the InnoDB context. This can potentially take a
|
|
|
|
long time */
|
|
|
|
|
|
|
|
trx_mutex_enter(victim_trx);
|
2016-09-06 09:43:16 +03:00
|
|
|
ut_ad(version <= victim_trx->version);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
ulint loop_count = 0;
|
|
|
|
/* start with optimistic sleep time of 20 micro seconds. */
|
|
|
|
ulint sleep_time = 20;
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
while ((victim_trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) > 0
|
|
|
|
&& victim_trx->version == version) {
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
trx_mutex_exit(victim_trx);
|
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
loop_count++;
|
|
|
|
/* If the wait is long, don't hog the cpu. */
|
|
|
|
if (loop_count < 100) {
|
|
|
|
/* 20 microseconds */
|
|
|
|
sleep_time = 20;
|
|
|
|
} else if (loop_count < 1000) {
|
|
|
|
/* 1 millisecond */
|
|
|
|
sleep_time = 1000;
|
|
|
|
} else {
|
|
|
|
/* 100 milliseconds */
|
|
|
|
sleep_time = 100000;
|
|
|
|
}
|
|
|
|
|
|
|
|
os_thread_sleep(sleep_time);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
trx_mutex_enter(victim_trx);
|
|
|
|
}
|
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
/* Compare the version to check if the transaction has
|
|
|
|
already finished */
|
|
|
|
if (victim_trx->version != version) {
|
|
|
|
trx_mutex_exit(victim_trx);
|
|
|
|
continue;
|
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
/* We should never kill background transactions. */
|
|
|
|
ut_ad(victim_trx->mysql_thd != NULL);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE));
|
|
|
|
ut_ad(victim_trx->in_innodb & TRX_FORCE_ROLLBACK);
|
|
|
|
ut_ad(victim_trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC);
|
|
|
|
ut_ad(victim_trx->killed_by == os_thread_get_curr_id());
|
|
|
|
ut_ad(victim_trx->version == it->m_version);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
/* We don't kill Read Only, Background or high priority
|
|
|
|
transactions. */
|
|
|
|
ut_a(!victim_trx->read_only);
|
|
|
|
ut_a(victim_trx->mysql_thd != NULL);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
trx_mutex_exit(victim_trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2017-01-12 13:30:10 +02:00
|
|
|
#ifndef DBUG_OFF
|
2016-09-06 09:43:16 +03:00
|
|
|
char buffer[1024];
|
2017-01-12 13:30:10 +02:00
|
|
|
#endif /* !DBUG_OFF */
|
2016-09-06 09:43:16 +03:00
|
|
|
|
2017-01-12 13:30:10 +02:00
|
|
|
DBUG_LOG("trx",
|
|
|
|
"High Priority Transaction "
|
|
|
|
<< trx->id << " killed transaction "
|
|
|
|
<< victim_trx->id << " in hit list"
|
|
|
|
<< " - "
|
|
|
|
<< thd_get_error_context_description(
|
|
|
|
victim_trx->mysql_thd,
|
|
|
|
buffer, sizeof(buffer), 512));
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2017-01-12 13:30:10 +02:00
|
|
|
trx_rollback_for_mysql(victim_trx);
|
2016-09-06 09:43:16 +03:00
|
|
|
trx_mutex_enter(victim_trx);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-06 09:43:16 +03:00
|
|
|
version++;
|
|
|
|
ut_ad(victim_trx->version == version);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
2016-09-09 15:05:59 +04:00
|
|
|
my_atomic_storelong(&victim_trx->killed_by, 0);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
victim_trx->in_innodb &= TRX_FORCE_ROLLBACK_MASK;
|
|
|
|
|
|
|
|
trx_mutex_exit(victim_trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->hit_list.clear();
|
|
|
|
|
|
|
|
if (had_dict_lock) {
|
|
|
|
|
|
|
|
row_mysql_freeze_data_dictionary(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|