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

MDEV-25594: Improve debug checks

trx_t::will_lock: Changed the type to bool.

trx_t::is_autocommit_non_locking(): Replaces
trx_is_autocommit_non_locking().

trx_is_ac_nl_ro(): Remove (replaced with equivalent assertion expressions).

assert_trx_nonlocking_or_in_list(): Remove.
Replaced with at least as strict checks in each place.

check_trx_state(): Moved to a static function; partially replaced with
individual debug assertions implementing equivalent or stricter checks.

This is a backport of commit 7b51d11c
from 10.5.
parent 0bd9f755
......@@ -4503,7 +4503,7 @@ innobase_commit_low(
if (trx_is_started(trx)) {
trx_commit_for_mysql(trx);
} else {
trx->will_lock = 0;
trx->will_lock = false;
#ifdef WITH_WSREP
trx->wsrep = false;
#endif /* WITH_WSREP */
......@@ -4860,7 +4860,7 @@ innobase_rollback_trx(
lock_unlock_table_autoinc(trx);
if (!trx->has_logged()) {
trx->will_lock = 0;
trx->will_lock = false;
#ifdef WITH_WSREP
trx->wsrep = false;
#endif
......@@ -8176,20 +8176,12 @@ ha_innobase::write_row(
if (high_level_read_only) {
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (UNIV_UNLIKELY(m_prebuilt->trx != trx)) {
ib::error() << "The transaction object for the table handle is"
" at " << static_cast<const void*>(m_prebuilt->trx)
<< ", but for the current thread it is at "
<< static_cast<const void*>(trx);
fputs("InnoDB: Dump of 200 bytes around m_prebuilt: ", stderr);
ut_print_buf(stderr, ((const byte*) m_prebuilt) - 100, 200);
fputs("\nInnoDB: Dump of 200 bytes around ha_data: ", stderr);
ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
putc('\n', stderr);
ut_error;
} else if (!trx_is_started(trx)) {
++trx->will_lock;
}
ut_a(m_prebuilt->trx == trx);
if (!trx_is_started(trx)) {
trx->will_lock = true;
}
#ifdef WITH_WSREP
......@@ -8964,7 +8956,7 @@ ha_innobase::update_row(
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (!trx_is_started(trx)) {
++trx->will_lock;
trx->will_lock = true;
}
if (m_upd_buf == NULL) {
......@@ -9110,7 +9102,7 @@ ha_innobase::delete_row(
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (!trx_is_started(trx)) {
++trx->will_lock;
trx->will_lock = true;
}
if (!m_prebuilt->upd_node) {
......@@ -9990,7 +9982,7 @@ ha_innobase::ft_init()
them as regular read only transactions for now. */
if (!trx_is_started(trx)) {
++trx->will_lock;
trx->will_lock = true;
}
DBUG_RETURN(rnd_init(false));
......@@ -10056,7 +10048,7 @@ ha_innobase::ft_init_ext(
them as regular read only transactions for now. */
if (!trx_is_started(trx)) {
++trx->will_lock;
trx->will_lock = true;
}
dict_table_t* ft_table = m_prebuilt->table;
......@@ -13081,7 +13073,7 @@ create_table_info_t::allocate_trx()
{
m_trx = innobase_trx_allocate(m_thd);
m_trx->will_lock++;
m_trx->will_lock = true;
m_trx->ddl = true;
}
......@@ -13372,13 +13364,7 @@ inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom)
ut_a(name_len < 1000);
/* Either the transaction is already flagged as a locking transaction
or it hasn't been started yet. */
ut_a(!trx_is_started(trx) || trx->will_lock > 0);
/* We are doing a DDL operation. */
++trx->will_lock;
trx->will_lock = true;
/* Drop the table in InnoDB */
......@@ -13555,14 +13541,7 @@ innobase_drop_database(
#endif /* _WIN32 */
trx_t* trx = innobase_trx_allocate(thd);
/* Either the transaction is already flagged as a locking transaction
or it hasn't been started yet. */
ut_a(!trx_is_started(trx) || trx->will_lock > 0);
/* We are doing a DDL operation. */
++trx->will_lock;
trx->will_lock = true;
ulint dummy;
......@@ -13606,7 +13585,7 @@ inline dberr_t innobase_rename_table(trx_t *trx, const char *from,
DEBUG_SYNC_C("innodb_rename_table_ready");
trx_start_if_not_started(trx, true);
ut_ad(trx->will_lock > 0);
ut_ad(trx->will_lock);
if (commit) {
/* Serialize data dictionary operations with dictionary mutex:
......@@ -13651,7 +13630,7 @@ inline dberr_t innobase_rename_table(trx_t *trx, const char *from,
/* Transaction must be flagged as a locking transaction or it hasn't
been started yet. */
ut_a(trx->will_lock > 0);
ut_a(trx->will_lock);
error = row_rename_table_for_mysql(norm_from, norm_to, trx, commit,
commit);
......@@ -13737,7 +13716,7 @@ int ha_innobase::truncate()
if (!srv_safe_truncate) {
if (!trx_is_started(m_prebuilt->trx)) {
++m_prebuilt->trx->will_lock;
m_prebuilt->trx->will_lock = true;
}
dberr_t err = row_truncate_table_for_mysql(
......@@ -13791,8 +13770,7 @@ int ha_innobase::truncate()
heap, ib_table->name.m_name, ib_table->id);
const char* name = mem_heap_strdup(heap, ib_table->name.m_name);
trx_t* trx = innobase_trx_allocate(m_user_thd);
++trx->will_lock;
trx->will_lock = true;
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
row_mysql_lock_data_dictionary(trx);
dict_stats_wait_bg_to_stop_using_table(ib_table, trx);
......@@ -13877,9 +13855,7 @@ ha_innobase::rename_table(
}
trx_t* trx = innobase_trx_allocate(thd);
/* We are doing a DDL operation. */
++trx->will_lock;
trx->will_lock = true;
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
dberr_t error = innobase_rename_table(trx, from, to, true);
......@@ -15880,7 +15856,7 @@ ha_innobase::start_stmt(
innobase_register_trx(ht, thd, trx);
if (!trx_is_started(trx)) {
++trx->will_lock;
trx->will_lock = true;
}
DBUG_RETURN(0);
......@@ -16103,7 +16079,7 @@ ha_innobase::external_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock;
trx->will_lock = true;
}
DBUG_RETURN(0);
......@@ -16150,7 +16126,7 @@ ha_innobase::external_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock;
trx->will_lock = true;
}
DBUG_RETURN(0);
......@@ -16829,7 +16805,7 @@ ha_innobase::store_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock;
trx->will_lock = true;
}
return(to);
......
......@@ -967,7 +967,7 @@ ha_innobase::check_if_supported_inplace_alter(
}
}
m_prebuilt->trx->will_lock++;
m_prebuilt->trx->will_lock = true;
if (!online) {
/* We already determined that only a non-locking
......@@ -8954,7 +8954,6 @@ ha_innobase::commit_inplace_alter_table(
m_prebuilt = ctx->prebuilt;
}
trx_start_if_not_started(user_trx, true);
user_trx->will_lock++;
m_prebuilt->trx = user_trx;
}
DBUG_INJECT_CRASH("ib_commit_inplace_crash",
......
/*****************************************************************************
Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2019, MariaDB Corporation.
Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -164,8 +164,8 @@ struct i_s_trx_row_t {
/*!< detailed_error in trx_t */
ulint trx_is_read_only;
/*!< trx_t::read_only */
ulint trx_is_autocommit_non_locking;
/*!< trx_is_autocommit_non_locking(trx)
bool trx_is_autocommit_non_locking;
/*!< trx:t::is_autocommit_non_locking()
*/
};
......
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, 2019, MariaDB Corporation.
Copyright (c) 2018, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -251,7 +251,9 @@ trx_rw_min_trx_id_low(void)
if (trx == NULL) {
id = trx_sys->max_trx_id;
} else {
assert_trx_in_rw_list(trx);
ut_ad(!trx->read_only);
ut_ad(trx->in_rw_trx_list);
ut_ad(!trx->is_autocommit_non_locking());
id = trx->id;
}
......
......@@ -502,99 +502,6 @@ from innodb_lock_wait_timeout via trx_t::mysql_thd.
? thd_lock_wait_timeout((t)->mysql_thd) \
: 0)
/**
Determine if the transaction is a non-locking autocommit select
(implied read-only).
@param t transaction
@return true if non-locking autocommit select transaction. */
#define trx_is_autocommit_non_locking(t) \
((t)->auto_commit && (t)->will_lock == 0)
/**
Determine if the transaction is a non-locking autocommit select
with an explicit check for the read-only status.
@param t transaction
@return true if non-locking autocommit read-only transaction. */
#define trx_is_ac_nl_ro(t) \
((t)->read_only && trx_is_autocommit_non_locking((t)))
/**
Assert that the transaction is in the trx_sys_t::rw_trx_list */
#define assert_trx_in_rw_list(t) do { \
ut_ad(!(t)->read_only); \
ut_ad((t)->in_rw_trx_list \
== !((t)->read_only || !(t)->rsegs.m_redo.rseg)); \
check_trx_state(t); \
} while (0)
/**
Check transaction state */
#define check_trx_state(t) do { \
ut_ad(!trx_is_autocommit_non_locking((t))); \
switch ((t)->state) { \
case TRX_STATE_PREPARED: \
case TRX_STATE_PREPARED_RECOVERED: \
case TRX_STATE_ACTIVE: \
case TRX_STATE_COMMITTED_IN_MEMORY: \
continue; \
case TRX_STATE_NOT_STARTED: \
break; \
} \
ut_error; \
} while (0)
/** Check if transaction is free so that it can be re-initialized.
@param t transaction handle */
#define assert_trx_is_free(t) do { \
ut_ad(trx_state_eq((t), TRX_STATE_NOT_STARTED)); \
ut_ad(!(t)->id); \
ut_ad(!(t)->has_logged()); \
ut_ad(!(t)->is_referenced()); \
ut_ad(!(t)->is_wsrep()); \
ut_ad(!MVCC::is_view_active((t)->read_view)); \
ut_ad((t)->lock.wait_thr == NULL); \
ut_ad(UT_LIST_GET_LEN((t)->lock.trx_locks) == 0); \
ut_ad((t)->lock.table_locks.empty()); \
ut_ad(!(t)->autoinc_locks \
|| ib_vector_is_empty((t)->autoinc_locks)); \
ut_ad((t)->dict_operation == TRX_DICT_OP_NONE); \
} while(0)
/** Check if transaction is in-active so that it can be freed and put back to
transaction pool.
@param t transaction handle */
#define assert_trx_is_inactive(t) do { \
assert_trx_is_free((t)); \
ut_ad((t)->dict_operation_lock_mode == 0); \
} while(0)
#ifdef UNIV_DEBUG
/*******************************************************************//**
Assert that an autocommit non-locking select cannot be in the
rw_trx_list and that it is a read-only transaction.
The tranasction must be in the mysql_trx_list. */
# define assert_trx_nonlocking_or_in_list(t) \
do { \
if (trx_is_autocommit_non_locking(t)) { \
trx_state_t t_state = (t)->state; \
ut_ad((t)->read_only); \
ut_ad(!(t)->is_recovered); \
ut_ad(!(t)->in_rw_trx_list); \
ut_ad((t)->in_mysql_trx_list); \
ut_ad(t_state == TRX_STATE_NOT_STARTED \
|| t_state == TRX_STATE_ACTIVE); \
} else { \
check_trx_state(t); \
} \
} while (0)
#else /* UNIV_DEBUG */
/*******************************************************************//**
Assert that an autocommit non-locking slect cannot be in the
rw_trx_list and that it is a read-only transaction.
The tranasction must be in the mysql_trx_list. */
# define assert_trx_nonlocking_or_in_list(trx) ((void)0)
#endif /* UNIV_DEBUG */
typedef std::vector<ib_lock_t*, ut_allocator<ib_lock_t*> > lock_list;
/*******************************************************************//**
......@@ -1070,16 +977,15 @@ struct trx_t {
/*------------------------------*/
bool read_only; /*!< true if transaction is flagged
as a READ-ONLY transaction.
if auto_commit && will_lock == 0
if auto_commit && !will_lock
then it will be handled as a
AC-NL-RO-SELECT (Auto Commit Non-Locking
Read Only Select). A read only
transaction will not be assigned an
UNDO log. */
bool auto_commit; /*!< true if it is an autocommit */
ib_uint32_t will_lock; /*!< Will acquire some locks. Increment
each time we determine that a lock will
be acquired by the MySQL layer. */
bool will_lock; /*!< set to inform trx_start_low() that
the transaction may acquire locks */
/*------------------------------*/
fts_trx_t* fts_trx; /*!< FTS information, or NULL if
transaction hasn't modified tables
......@@ -1199,10 +1105,28 @@ struct trx_t {
inline void free();
void assert_freed() const
{
ut_ad(state == TRX_STATE_NOT_STARTED);
ut_ad(!id);
ut_ad(!has_logged());
ut_ad(!const_cast<trx_t*>(this)->is_referenced());
ut_ad(!is_wsrep());
ut_ad(!trx_get_read_view(this));
ut_ad(!lock.wait_thr);
ut_ad(UT_LIST_GET_LEN(lock.trx_locks) == 0);
ut_ad(lock.table_locks.empty());
ut_ad(!autoinc_locks || ib_vector_is_empty(autoinc_locks));
ut_ad(dict_operation == TRX_DICT_OP_NONE);
}
/** @return whether this is a non-locking autocommit transaction */
bool is_autocommit_non_locking() const { return auto_commit && !will_lock; }
private:
/** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */
trx_rseg_t* assign_temp_rseg();
/** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */
trx_rseg_t *assign_temp_rseg();
};
/**
......
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2019, MariaDB Corporation.
Copyright (c) 2016, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -50,17 +50,18 @@ trx_state_eq(
switch (trx->state) {
case TRX_STATE_PREPARED:
case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx));
case TRX_STATE_COMMITTED_IN_MEMORY:
ut_ad(!trx->is_autocommit_non_locking());
return(trx->state == state);
case TRX_STATE_ACTIVE:
assert_trx_nonlocking_or_in_list(trx);
return(state == trx->state);
case TRX_STATE_COMMITTED_IN_MEMORY:
check_trx_state(trx);
if (trx->is_autocommit_non_locking()) {
ut_ad(!trx->is_recovered);
ut_ad(trx->read_only);
ut_ad(trx->mysql_thd);
ut_ad(!trx->in_rw_trx_list);
ut_ad(trx->in_mysql_trx_list);
}
return(state == trx->state);
case TRX_STATE_NOT_STARTED:
......
......@@ -1376,6 +1376,19 @@ wsrep_print_wait_locks(
}
#endif /* WITH_WSREP */
#ifdef UNIV_DEBUG
/** Check transaction state */
static void check_trx_state(const trx_t *trx)
{
ut_ad(!trx->auto_commit || trx->will_lock);
const trx_state_t state= trx->state;
ut_ad(state == TRX_STATE_ACTIVE ||
state == TRX_STATE_PREPARED_RECOVERED ||
state == TRX_STATE_PREPARED ||
state == TRX_STATE_COMMITTED_IN_MEMORY);
}
#endif
/** Create a new record lock and inserts it to the lock queue,
without checking for deadlocks or conflicts.
@param[in] type_mode lock mode and wait flag; type will be replaced
......@@ -3589,8 +3602,8 @@ lock_table_create(
ut_ad(table && trx);
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
check_trx_state(trx);
ut_ad(trx->is_recovered || trx->state == TRX_STATE_ACTIVE);
ut_ad(!trx->auto_commit || trx->will_lock);
if ((type_mode & LOCK_MODE_MASK) == LOCK_AUTO_INC) {
++table->n_waiting_or_granted_auto_inc_locks;
......@@ -4545,7 +4558,10 @@ lock_remove_recovered_trx_record_locks(
trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
assert_trx_in_rw_list(trx);
ut_ad(!trx->read_only);
ut_ad(trx->in_rw_trx_list);
ut_ad(!trx->is_autocommit_non_locking());
ut_ad(trx->state != TRX_STATE_NOT_STARTED);
if (!trx->is_recovered) {
continue;
......@@ -5181,7 +5197,8 @@ lock_rec_queue_validate(
ut_ad(!index || lock->index == index);
trx_mutex_enter(lock->trx);
ut_ad(!trx_is_ac_nl_ro(lock->trx));
ut_ad(!lock->trx->read_only
|| !lock->trx->is_autocommit_non_locking());
ut_ad(trx_state_eq(lock->trx,
TRX_STATE_COMMITTED_IN_MEMORY)
|| !lock_get_wait(lock)
......@@ -5260,8 +5277,7 @@ lock_rec_queue_validate(
for (lock = lock_rec_get_first(lock_sys->rec_hash, block, heap_no);
lock != NULL;
lock = lock_rec_get_next_const(heap_no, lock)) {
ut_ad(!trx_is_ac_nl_ro(lock->trx));
ut_ad(!lock->trx->is_autocommit_non_locking());
if (index) {
ut_a(lock->index == index);
......@@ -5357,7 +5373,8 @@ lock_rec_validate_page(
}
}
ut_ad(!trx_is_ac_nl_ro(lock->trx));
ut_ad(!lock->trx->read_only
|| !lock->trx->is_autocommit_non_locking());
/* Only validate the record queues when this thread is not
holding a space->latch. */
......@@ -5465,7 +5482,7 @@ lock_rec_validate(
ib_uint64_t current;
ut_ad(!trx_is_ac_nl_ro(lock->trx));
ut_ad(!lock->trx->is_autocommit_non_locking());
ut_ad(lock_get_type(lock) == LOCK_REC);
current = ut_ull_create(
......@@ -7075,7 +7092,8 @@ DeadlockChecker::search()
ut_ad(m_start != NULL);
ut_ad(m_wait_lock != NULL);
check_trx_state(m_wait_lock->trx);
ut_ad(!m_wait_lock->trx->auto_commit || m_wait_lock->trx->will_lock);
ut_d(check_trx_state(m_wait_lock->trx));
ut_ad(m_mark_start <= s_lock_mark_counter);
/* Look at the locks ahead of wait_lock in the lock queue. */
......@@ -7235,7 +7253,8 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx)
{
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
check_trx_state(trx);
ut_ad(trx->state == TRX_STATE_ACTIVE);
ut_ad(!trx->auto_commit || trx->will_lock);
ut_ad(!srv_read_only_mode);
if (!innobase_deadlock_detect) {
......
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2019, MariaDB Corporation.
Copyright (c) 2019, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -574,7 +574,7 @@ MVCC::view_open(ReadView*& view, trx_t* trx)
Therefore we must set the low limit id after we reset the
closed status after the check. */
if (trx_is_autocommit_non_locking(trx) && view->empty()) {
if (trx->is_autocommit_non_locking() && view->empty()) {
view->m_closed = false;
......
/*****************************************************************************
Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2019, MariaDB Corporation.
Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -577,7 +577,7 @@ fill_trx_row(
row->trx_is_read_only = trx->read_only;
row->trx_is_autocommit_non_locking = trx_is_autocommit_non_locking(trx);
row->trx_is_autocommit_non_locking = trx->is_autocommit_non_locking();
return(TRUE);
}
......@@ -1259,7 +1259,21 @@ fetch_data_into_cache_low(
continue;
}
assert_trx_nonlocking_or_in_list(trx);
#ifdef UNIV_DEBUG
if (trx->is_autocommit_non_locking()) {
ut_ad(trx->read_only);
ut_ad(!trx->is_recovered);
ut_ad(trx->mysql_thd);
ut_ad(trx->in_mysql_trx_list);
const trx_state_t state = trx->state;
ut_ad(state == TRX_STATE_NOT_STARTED
|| state == TRX_STATE_ACTIVE);
}
else {
ut_ad(trx->state != TRX_STATE_NOT_STARTED);
}
#endif /* UNIV_DEBUG */
ut_ad(trx->in_rw_trx_list == rw_trx_list);
......
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2020, MariaDB Corporation.
Copyright (c) 2016, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -81,12 +81,19 @@ trx_rollback_to_savepoint_low(
heap = mem_heap_create(512);
roll_node = roll_node_create(heap);
ut_ad(!trx->in_rollback);
if (savept != NULL) {
roll_node->savept = savept;
check_trx_state(trx);
ut_ad(trx->mysql_thd);
ut_ad(trx->in_mysql_trx_list);
ut_ad(!trx->is_recovered);
ut_ad(trx->state == TRX_STATE_ACTIVE);
} else {
assert_trx_nonlocking_or_in_list(trx);
ut_d(trx_state_t state = trx->state);
ut_ad(state == TRX_STATE_ACTIVE
|| state == TRX_STATE_PREPARED
|| state == TRX_STATE_PREPARED_RECOVERED);
}
trx->error_state = DB_SUCCESS;
......@@ -187,7 +194,8 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
switch (trx->state) {
case TRX_STATE_NOT_STARTED:
trx->will_lock = 0;
trx->will_lock = false;
ut_ad(trx->mysql_thd);
ut_ad(trx->in_mysql_trx_list);
#ifdef WITH_WSREP
trx->wsrep = false;
......@@ -196,12 +204,14 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
case TRX_STATE_ACTIVE:
ut_ad(trx->in_mysql_trx_list);
assert_trx_nonlocking_or_in_list(trx);
ut_ad(trx->mysql_thd);
ut_ad(!trx->is_recovered);
ut_ad(!trx->is_autocommit_non_locking() || trx->read_only);
return(trx_rollback_for_mysql_low(trx));
case TRX_STATE_PREPARED:
case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx));
ut_ad(!trx->is_autocommit_non_locking());
if (trx->has_logged_persistent()) {
/* The XA ROLLBACK of a XA PREPARE transaction
will consist of multiple mini-transactions.
......@@ -245,7 +255,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
return(trx_rollback_for_mysql_low(trx));
case TRX_STATE_COMMITTED_IN_MEMORY:
check_trx_state(trx);
ut_ad(!trx->is_autocommit_non_locking());
break;
}
......@@ -274,7 +284,9 @@ trx_rollback_last_sql_stat_for_mysql(
return(DB_SUCCESS);
case TRX_STATE_ACTIVE:
assert_trx_nonlocking_or_in_list(trx);
ut_ad(trx->mysql_thd);
ut_ad(!trx->is_recovered);
ut_ad(!trx->is_autocommit_non_locking() || trx->read_only);
trx->op_info = "rollback of SQL statement";
......@@ -768,7 +780,11 @@ trx_roll_must_shutdown()
t != NULL;
t = UT_LIST_GET_NEXT(trx_list, t)) {
assert_trx_in_rw_list(t);
ut_ad(!t->read_only);
ut_ad(t->in_rw_trx_list);
ut_ad(!t->is_autocommit_non_locking());
ut_ad(t->state != TRX_STATE_NOT_STARTED);
if (t->is_recovered
&& trx_state_eq(t, TRX_STATE_ACTIVE)) {
n_trx++;
......@@ -831,7 +847,10 @@ trx_rollback_or_clean_recovered(
trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
assert_trx_in_rw_list(trx);
ut_ad(!trx->read_only);
ut_ad(trx->in_rw_trx_list);
ut_ad(!trx->is_autocommit_non_locking());
ut_ad(trx->state != TRX_STATE_NOT_STARTED);
/* If this function does a cleanup or rollback
then it will release the trx_sys->mutex, therefore
......
......@@ -513,7 +513,9 @@ trx_sys_init_at_db_start()
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
ut_ad(trx->is_recovered);
assert_trx_in_rw_list(trx);
ut_ad(!trx->read_only);
ut_ad(trx->in_rw_trx_list);
ut_ad(!trx->is_autocommit_non_locking());
if (trx_state_eq(trx, TRX_STATE_ACTIVE)) {
rows_to_undo += trx->undo_no;
......@@ -1026,7 +1028,8 @@ trx_sys_validate_trx_list_low(
trx != NULL;
prev_trx = trx, trx = UT_LIST_GET_NEXT(trx_list, prev_trx)) {
check_trx_state(trx);
ut_ad(!trx->is_autocommit_non_locking());
ut_ad(trx->state != TRX_STATE_NOT_STARTED);
ut_a(prev_trx == NULL || prev_trx->id > trx->id);
}
......
......@@ -133,7 +133,7 @@ trx_init(
trx->auto_commit = false;
trx->will_lock = 0;
trx->will_lock = false;
trx->ddl = false;
......@@ -336,13 +336,13 @@ trx_t *trx_allocate_for_background()
MEM_MAKE_DEFINED(trx, sizeof *trx);
#endif
assert_trx_is_free(trx);
trx->assert_freed();
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);
ut_ad(!trx->will_lock);
ut_ad(trx->state == TRX_STATE_NOT_STARTED);
DBUG_LOG("trx", "Create: " << trx);
......@@ -369,7 +369,8 @@ trx_t *trx_allocate_for_background()
/** Free the memory to trx_pools */
inline void trx_t::free()
{
assert_trx_is_inactive(this);
assert_freed();
ut_ad(!dict_operation_lock_mode);
MEM_CHECK_DEFINED(this, sizeof *this);
......@@ -539,7 +540,8 @@ trx_validate_state_before_free(trx_t* trx)
}
trx->dict_operation = TRX_DICT_OP_NONE;
assert_trx_is_inactive(trx);
trx->assert_freed();
ut_ad(!trx->dict_operation_lock_mode);
}
/** Free and initialize a transaction object instantinated during recovery.
......@@ -636,7 +638,9 @@ trx_free_prepared(
trx->release_locks();
trx_undo_free_prepared(trx);
assert_trx_in_rw_list(trx);
ut_ad(!trx->read_only);
ut_ad(trx->in_rw_trx_list);
ut_ad(!trx->is_autocommit_non_locking());
ut_a(!trx->read_only);
......@@ -685,7 +689,7 @@ trx_disconnect_from_mysql(
trx->is_recovered = true;
trx->mysql_thd = NULL;
/* todo/fixme: suggest to do it at innodb prepare */
trx->will_lock = 0;
trx->will_lock = false;
}
trx_sys_mutex_exit();
......@@ -1177,11 +1181,10 @@ void trx_t::remove_flush_observer()
/** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */
trx_rseg_t*
trx_t::assign_temp_rseg()
trx_rseg_t *trx_t::assign_temp_rseg()
{
ut_ad(!rsegs.m_noredo.rseg);
ut_ad(!trx_is_autocommit_non_locking(this));
ut_ad(!is_autocommit_non_locking());
compile_time_assert(ut_is_2pow(TRX_SYS_N_RSEGS));
/* Choose a temporary rollback segment between 0 and 127
......@@ -1235,8 +1238,8 @@ trx_start_low(
&& thd_trx_is_read_only(trx->mysql_thd));
if (!trx->auto_commit) {
++trx->will_lock;
} else if (trx->will_lock == 0) {
trx->will_lock = true;
} else if (!trx->will_lock) {
trx->read_only = true;
}
......@@ -1305,7 +1308,7 @@ trx_start_low(
trx_sys_mutex_exit();
} else {
if (!trx_is_autocommit_non_locking(trx)) {
if (!trx->is_autocommit_non_locking()) {
/* If this is a read-only transaction that is writing
to a temporary table then it needs a transaction id
......@@ -1691,12 +1694,16 @@ trx_commit_in_memory(
{
trx->must_flush_log_later = false;
if (trx_is_autocommit_non_locking(trx)) {
if (trx->is_autocommit_non_locking()) {
ut_ad(trx->id == 0);
ut_ad(trx->read_only);
ut_ad(!trx->will_lock);
ut_a(!trx->is_recovered);
ut_ad(trx->rsegs.m_redo.rseg == NULL);
ut_ad(!trx->in_rw_trx_list);
ut_ad(trx->in_mysql_trx_list);
ut_ad(trx->mysql_thd);
ut_ad(trx->state == TRX_STATE_ACTIVE);
/* Note: We are asserting without holding the lock mutex. But
that is OK because this transaction is not waiting and cannot
......@@ -1712,8 +1719,6 @@ trx_commit_in_memory(
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));
if (trx->read_view != NULL) {
trx_sys->mvcc->view_close(trx->read_view, false);
}
......@@ -1866,7 +1871,7 @@ trx_commit_in_memory(
/* 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. */
assert_trx_is_free(trx);
trx->assert_freed();
trx_init(trx);
......@@ -1885,30 +1890,20 @@ trx_commit_low(
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));
ut_ad(!mtr || mtr->is_active());
ut_ad(!mtr == !trx->has_logged());
/* undo_no is non-zero if we're doing the final commit. */
if (trx->fts_trx != NULL && trx->undo_no != 0) {
dberr_t error;
ut_a(!trx_is_autocommit_non_locking(trx));
error = fts_commit(trx);
ut_a(!trx->is_autocommit_non_locking());
/* 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;
if (dberr_t error = fts_commit(trx)) {
ut_a(error == DB_DUPLICATE_KEY);
}
}
......@@ -2279,7 +2274,6 @@ trx_print_low(
/*!< in: mem_heap_get_size(trx->lock.lock_heap) */
{
ibool newline;
const char* op_info;
ut_ad(trx_sys_mutex_own());
......@@ -2308,9 +2302,7 @@ trx_print_low(
fprintf(f, ", state %lu", (ulong) trx->state);
ut_ad(0);
state_ok:
/* prevent a race condition */
op_info = trx->op_info;
const char* op_info = trx->op_info;
if (*op_info) {
putc(' ', f);
......@@ -2549,7 +2541,7 @@ trx_assert_started(
/* Non-locking autocommits should not hold any locks and this
function is only called from the locking code. */
check_trx_state(trx);
ut_ad(!trx->is_autocommit_non_locking());
/* 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
......@@ -2754,7 +2746,9 @@ trx_recover_for_mysql(
trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
assert_trx_in_rw_list(trx);
ut_ad(!trx->read_only);
ut_ad(trx->in_rw_trx_list);
ut_ad(!trx->is_autocommit_non_locking());
/* The state of a read-write transaction cannot change
from or to NOT_STARTED while we are holding the
......@@ -2821,7 +2815,9 @@ trx_t* trx_get_trx_by_xid_low(const XID* xid)
trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
trx_mutex_enter(trx);
assert_trx_in_rw_list(trx);
ut_ad(!trx->read_only);
ut_ad(trx->in_rw_trx_list);
ut_ad(!trx->is_autocommit_non_locking());
/* Compare two X/Open XA transaction id's: their
length should be the same and binary comparison
......@@ -2948,7 +2944,7 @@ trx_start_internal_low(
/* Ensure it is not flagged as an auto-commit-non-locking
transaction. */
trx->will_lock = 1;
trx->will_lock = true;
trx->internal = true;
......@@ -2964,7 +2960,7 @@ trx_start_internal_read_only_low(
/* Ensure it is not flagged as an auto-commit-non-locking
transaction. */
trx->will_lock = 1;
trx->will_lock = true;
trx->internal = true;
......@@ -2985,13 +2981,7 @@ trx_start_for_ddl_low(
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;
trx->ddl= true;
trx_start_internal_low(trx);
return;
......@@ -3002,7 +2992,7 @@ trx_start_for_ddl_low(
trx->ddl = true;
ut_ad(trx->dict_operation != TRX_DICT_OP_NONE);
ut_ad(trx->will_lock > 0);
ut_ad(trx->will_lock);
return;
case TRX_STATE_PREPARED:
......@@ -3028,7 +3018,7 @@ trx_set_rw_mode(
{
ut_ad(trx->rsegs.m_redo.rseg == 0);
ut_ad(!trx->in_rw_trx_list);
ut_ad(!trx_is_autocommit_non_locking(trx));
ut_ad(!trx->is_autocommit_non_locking());
ut_ad(!trx->read_only);
if (high_level_read_only) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment