Commit 7b51d11c 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.
parent cc2651b7
...@@ -4123,7 +4123,7 @@ innobase_commit_low( ...@@ -4123,7 +4123,7 @@ innobase_commit_low(
if (trx_is_started(trx)) { if (trx_is_started(trx)) {
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
} else { } else {
trx->will_lock = 0; trx->will_lock = false;
#ifdef WITH_WSREP #ifdef WITH_WSREP
trx->wsrep = false; trx->wsrep = false;
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
...@@ -7610,7 +7610,7 @@ ha_innobase::write_row( ...@@ -7610,7 +7610,7 @@ ha_innobase::write_row(
ut_a(m_prebuilt->trx == trx); ut_a(m_prebuilt->trx == trx);
if (!trx_is_started(trx)) { if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
ins_mode_t vers_set_fields; ins_mode_t vers_set_fields;
...@@ -8369,7 +8369,7 @@ ha_innobase::update_row( ...@@ -8369,7 +8369,7 @@ ha_innobase::update_row(
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE); ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY); DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (!trx_is_started(trx)) { } else if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
if (m_upd_buf == NULL) { if (m_upd_buf == NULL) {
...@@ -8540,7 +8540,7 @@ ha_innobase::delete_row( ...@@ -8540,7 +8540,7 @@ ha_innobase::delete_row(
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE); ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY); DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (!trx_is_started(trx)) { } else if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
if (!m_prebuilt->upd_node) { if (!m_prebuilt->upd_node) {
...@@ -9377,7 +9377,7 @@ ha_innobase::ft_init() ...@@ -9377,7 +9377,7 @@ ha_innobase::ft_init()
them as regular read only transactions for now. */ them as regular read only transactions for now. */
if (!trx_is_started(trx)) { if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
DBUG_RETURN(rnd_init(false)); DBUG_RETURN(rnd_init(false));
...@@ -9443,7 +9443,7 @@ ha_innobase::ft_init_ext( ...@@ -9443,7 +9443,7 @@ ha_innobase::ft_init_ext(
them as regular read only transactions for now. */ them as regular read only transactions for now. */
if (!trx_is_started(trx)) { if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
dict_table_t* ft_table = m_prebuilt->table; dict_table_t* ft_table = m_prebuilt->table;
...@@ -12972,7 +12972,7 @@ create_table_info_t::allocate_trx() ...@@ -12972,7 +12972,7 @@ create_table_info_t::allocate_trx()
{ {
m_trx = innobase_trx_allocate(m_thd); m_trx = innobase_trx_allocate(m_thd);
m_trx->will_lock++; m_trx->will_lock = true;
m_trx->ddl = true; m_trx->ddl = true;
} }
...@@ -13296,13 +13296,7 @@ inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom) ...@@ -13296,13 +13296,7 @@ inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom)
ut_a(name_len < 1000); ut_a(name_len < 1000);
/* Either the transaction is already flagged as a locking transaction trx->will_lock = true;
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;
/* Drop the table in InnoDB */ /* Drop the table in InnoDB */
...@@ -13481,14 +13475,7 @@ innobase_drop_database( ...@@ -13481,14 +13475,7 @@ innobase_drop_database(
#endif /* _WIN32 */ #endif /* _WIN32 */
trx_t* trx = innobase_trx_allocate(thd); trx_t* trx = innobase_trx_allocate(thd);
trx->will_lock = true;
/* 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;
ulint dummy; ulint dummy;
...@@ -13532,7 +13519,7 @@ inline dberr_t innobase_rename_table(trx_t *trx, const char *from, ...@@ -13532,7 +13519,7 @@ inline dberr_t innobase_rename_table(trx_t *trx, const char *from,
DEBUG_SYNC_C("innodb_rename_table_ready"); DEBUG_SYNC_C("innodb_rename_table_ready");
trx_start_if_not_started(trx, true); trx_start_if_not_started(trx, true);
ut_ad(trx->will_lock > 0); ut_ad(trx->will_lock);
if (commit) { if (commit) {
/* Serialize data dictionary operations with dictionary mutex: /* Serialize data dictionary operations with dictionary mutex:
...@@ -13642,8 +13629,7 @@ int ha_innobase::truncate() ...@@ -13642,8 +13629,7 @@ int ha_innobase::truncate()
heap, ib_table->name.m_name, ib_table->id); heap, ib_table->name.m_name, ib_table->id);
const char* name = mem_heap_strdup(heap, ib_table->name.m_name); const char* name = mem_heap_strdup(heap, ib_table->name.m_name);
trx_t* trx = innobase_trx_allocate(m_user_thd); trx_t* trx = innobase_trx_allocate(m_user_thd);
trx->will_lock = true;
++trx->will_lock;
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
row_mysql_lock_data_dictionary(trx); row_mysql_lock_data_dictionary(trx);
dict_stats_wait_bg_to_stop_using_table(ib_table, trx); dict_stats_wait_bg_to_stop_using_table(ib_table, trx);
...@@ -13728,9 +13714,7 @@ ha_innobase::rename_table( ...@@ -13728,9 +13714,7 @@ ha_innobase::rename_table(
} }
trx_t* trx = innobase_trx_allocate(thd); trx_t* trx = innobase_trx_allocate(thd);
trx->will_lock = true;
/* We are doing a DDL operation. */
++trx->will_lock;
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
dberr_t error = innobase_rename_table(trx, from, to, true); dberr_t error = innobase_rename_table(trx, from, to, true);
...@@ -15602,7 +15586,7 @@ ha_innobase::start_stmt( ...@@ -15602,7 +15586,7 @@ ha_innobase::start_stmt(
innobase_register_trx(ht, thd, trx); innobase_register_trx(ht, thd, trx);
if (!trx_is_started(trx)) { if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -15828,7 +15812,7 @@ ha_innobase::external_lock( ...@@ -15828,7 +15812,7 @@ ha_innobase::external_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE && (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) { || m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock; trx->will_lock = true;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -15867,7 +15851,7 @@ ha_innobase::external_lock( ...@@ -15867,7 +15851,7 @@ ha_innobase::external_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE && (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) { || m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock; trx->will_lock = true;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -16540,7 +16524,7 @@ ha_innobase::store_lock( ...@@ -16540,7 +16524,7 @@ ha_innobase::store_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE && (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) { || m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock; trx->will_lock = true;
} }
return(to); return(to);
......
...@@ -2352,7 +2352,7 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -2352,7 +2352,7 @@ ha_innobase::check_if_supported_inplace_alter(
} }
} }
m_prebuilt->trx->will_lock++; m_prebuilt->trx->will_lock = true;
/* When changing a NULL column to NOT NULL and specifying a /* When changing a NULL column to NOT NULL and specifying a
DEFAULT value, ensure that the DEFAULT expression is a constant. DEFAULT value, ensure that the DEFAULT expression is a constant.
...@@ -11458,7 +11458,6 @@ ha_innobase::commit_inplace_alter_table( ...@@ -11458,7 +11458,6 @@ ha_innobase::commit_inplace_alter_table(
m_prebuilt = ctx->prebuilt; m_prebuilt = ctx->prebuilt;
} }
trx_start_if_not_started(user_trx, true); trx_start_if_not_started(user_trx, true);
user_trx->will_lock++;
m_prebuilt->trx = user_trx; m_prebuilt->trx = user_trx;
} }
DBUG_INJECT_CRASH("ib_commit_inplace_crash", DBUG_INJECT_CRASH("ib_commit_inplace_crash",
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -151,7 +151,7 @@ struct i_s_trx_row_t { ...@@ -151,7 +151,7 @@ struct i_s_trx_row_t {
bool trx_is_read_only; bool trx_is_read_only;
/*!< trx_t::read_only */ /*!< trx_t::read_only */
bool trx_is_autocommit_non_locking; bool trx_is_autocommit_non_locking;
/*!< trx_is_autocommit_non_locking(trx) /*!< trx:t::is_autocommit_non_locking()
*/ */
}; };
......
...@@ -513,7 +513,7 @@ class rw_trx_hash_t ...@@ -513,7 +513,7 @@ class rw_trx_hash_t
static void validate_element(trx_t *trx) static void validate_element(trx_t *trx)
{ {
ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg); ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg);
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx->is_autocommit_non_locking());
/* trx->state can be anything except TRX_STATE_NOT_STARTED */ /* trx->state can be anything except TRX_STATE_NOT_STARTED */
mutex_enter(&trx->mutex); mutex_enter(&trx->mutex);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) || ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
......
...@@ -393,64 +393,6 @@ from innodb_lock_wait_timeout via trx_t::mysql_thd. ...@@ -393,64 +393,6 @@ from innodb_lock_wait_timeout via trx_t::mysql_thd.
? thd_lock_wait_timeout((t)->mysql_thd) \ ? thd_lock_wait_timeout((t)->mysql_thd) \
: 0) : 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)))
/**
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)
#ifdef UNIV_DEBUG
/*******************************************************************//**
Assert that an autocommit non-locking select cannot be in the
rw_trx_hash and that it is a read-only transaction.
The transaction must have mysql_thd assigned. */
# 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)->mysql_thd); \
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_hash and that it is a read-only transaction.
The transaction must have mysql_thd assigned. */
# 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; typedef std::vector<ib_lock_t*, ut_allocator<ib_lock_t*> > lock_list;
/*******************************************************************//** /*******************************************************************//**
...@@ -947,16 +889,15 @@ struct trx_t : ilist_node<> { ...@@ -947,16 +889,15 @@ struct trx_t : ilist_node<> {
/*------------------------------*/ /*------------------------------*/
bool read_only; /*!< true if transaction is flagged bool read_only; /*!< true if transaction is flagged
as a READ-ONLY transaction. as a READ-ONLY transaction.
if auto_commit && will_lock == 0 if auto_commit && !will_lock
then it will be handled as a then it will be handled as a
AC-NL-RO-SELECT (Auto Commit Non-Locking AC-NL-RO-SELECT (Auto Commit Non-Locking
Read Only Select). A read only Read Only Select). A read only
transaction will not be assigned an transaction will not be assigned an
UNDO log. */ UNDO log. */
bool auto_commit; /*!< true if it is an autocommit */ bool auto_commit; /*!< true if it is an autocommit */
ib_uint32_t will_lock; /*!< Will acquire some locks. Increment bool will_lock; /*!< set to inform trx_start_low() that
each time we determine that a lock will the transaction may acquire locks */
be acquired by the MySQL layer. */
/*------------------------------*/ /*------------------------------*/
fts_trx_t* fts_trx; /*!< FTS information, or NULL if fts_trx_t* fts_trx; /*!< FTS information, or NULL if
transaction hasn't modified tables transaction hasn't modified tables
...@@ -1103,11 +1044,13 @@ struct trx_t : ilist_node<> { ...@@ -1103,11 +1044,13 @@ struct trx_t : ilist_node<> {
ut_ad(dict_operation == TRX_DICT_OP_NONE); 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: private:
/** Assign a rollback segment for modifying temporary tables. /** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */ @return the assigned rollback segment */
trx_rseg_t* assign_temp_rseg(); trx_rseg_t *assign_temp_rseg();
}; };
/** /**
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. 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 This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -49,11 +49,15 @@ trx_state_eq( ...@@ -49,11 +49,15 @@ trx_state_eq(
case TRX_STATE_PREPARED: case TRX_STATE_PREPARED:
case TRX_STATE_PREPARED_RECOVERED: case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY: case TRX_STATE_COMMITTED_IN_MEMORY:
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx->is_autocommit_non_locking());
return(trx->state == state); return(trx->state == state);
case TRX_STATE_ACTIVE: case TRX_STATE_ACTIVE:
assert_trx_nonlocking_or_in_list(trx); if (trx->is_autocommit_non_locking()) {
ut_ad(!trx->is_recovered);
ut_ad(trx->read_only);
ut_ad(trx->mysql_thd);
}
return(state == trx->state); return(state == trx->state);
case TRX_STATE_NOT_STARTED: case TRX_STATE_NOT_STARTED:
......
...@@ -1240,6 +1240,19 @@ wsrep_print_wait_locks( ...@@ -1240,6 +1240,19 @@ wsrep_print_wait_locks(
} }
#endif /* WITH_WSREP */ #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 auto 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, /** Create a new record lock and inserts it to the lock queue,
without checking for deadlocks or conflicts. without checking for deadlocks or conflicts.
@param[in] type_mode lock mode and wait flag; type will be replaced @param[in] type_mode lock mode and wait flag; type will be replaced
...@@ -3346,8 +3359,8 @@ lock_table_create( ...@@ -3346,8 +3359,8 @@ lock_table_create(
ut_ad(table && trx); ut_ad(table && trx);
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx)); ut_ad(trx_mutex_own(trx));
ut_ad(trx->is_recovered || trx->state == TRX_STATE_ACTIVE);
check_trx_state(trx); ut_ad(!trx->auto_commit || trx->will_lock);
if ((type_mode & LOCK_MODE_MASK) == LOCK_AUTO_INC) { if ((type_mode & LOCK_MODE_MASK) == LOCK_AUTO_INC) {
++table->n_waiting_or_granted_auto_inc_locks; ++table->n_waiting_or_granted_auto_inc_locks;
...@@ -4708,7 +4721,8 @@ lock_rec_queue_validate( ...@@ -4708,7 +4721,8 @@ lock_rec_queue_validate(
ut_ad(!index || lock->index == index); ut_ad(!index || lock->index == index);
trx_mutex_enter(lock->trx); 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, ut_ad(trx_state_eq(lock->trx,
TRX_STATE_COMMITTED_IN_MEMORY) TRX_STATE_COMMITTED_IN_MEMORY)
|| !lock_get_wait(lock) || !lock_get_wait(lock)
...@@ -4794,8 +4808,8 @@ lock_rec_queue_validate( ...@@ -4794,8 +4808,8 @@ lock_rec_queue_validate(
for (lock = lock_rec_get_first(&lock_sys.rec_hash, block, heap_no); for (lock = lock_rec_get_first(&lock_sys.rec_hash, block, heap_no);
lock != NULL; lock != NULL;
lock = lock_rec_get_next_const(heap_no, lock)) { lock = lock_rec_get_next_const(heap_no, lock)) {
ut_ad(!lock->trx->read_only
ut_ad(!trx_is_ac_nl_ro(lock->trx)); || !lock->trx->is_autocommit_non_locking());
ut_ad(!page_rec_is_metadata(rec)); ut_ad(!page_rec_is_metadata(rec));
if (index) { if (index) {
...@@ -4881,7 +4895,8 @@ lock_rec_validate_page( ...@@ -4881,7 +4895,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 /* Only validate the record queues when this thread is not
holding a space->latch. */ holding a space->latch. */
...@@ -4946,7 +4961,8 @@ lock_rec_validate( ...@@ -4946,7 +4961,8 @@ lock_rec_validate(
lock != NULL; lock != NULL;
lock = static_cast<const lock_t*>(HASH_GET_NEXT(hash, lock))) { lock = static_cast<const lock_t*>(HASH_GET_NEXT(hash, lock))) {
ut_ad(!trx_is_ac_nl_ro(lock->trx)); ut_ad(!lock->trx->read_only
|| !lock->trx->is_autocommit_non_locking());
ut_ad(lock_get_type(lock) == LOCK_REC); ut_ad(lock_get_type(lock) == LOCK_REC);
page_id_t current(lock->un_member.rec_lock.page_id); page_id_t current(lock->un_member.rec_lock.page_id);
...@@ -6514,7 +6530,8 @@ DeadlockChecker::search() ...@@ -6514,7 +6530,8 @@ DeadlockChecker::search()
ut_ad(m_start != NULL); ut_ad(m_start != NULL);
ut_ad(m_wait_lock != 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); ut_ad(m_mark_start <= s_lock_mark_counter);
/* Look at the locks ahead of wait_lock in the lock queue. */ /* Look at the locks ahead of wait_lock in the lock queue. */
...@@ -6679,7 +6696,8 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx) ...@@ -6679,7 +6696,8 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx)
{ {
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx)); 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); ut_ad(!srv_read_only_mode);
if (!innobase_deadlock_detect) { if (!innobase_deadlock_detect) {
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. 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 This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -221,7 +221,7 @@ void ReadView::open(trx_t *trx) ...@@ -221,7 +221,7 @@ void ReadView::open(trx_t *trx)
else if (likely(!srv_read_only_mode)) else if (likely(!srv_read_only_mode))
{ {
m_creator_trx_id= trx->id; m_creator_trx_id= trx->id;
if (trx_is_autocommit_non_locking(trx) && empty() && if (trx->is_autocommit_non_locking() && empty() &&
low_limit_id() == trx_sys.get_max_trx_id()) low_limit_id() == trx_sys.get_max_trx_id())
m_open.store(true, std::memory_order_relaxed); m_open.store(true, std::memory_order_relaxed);
else else
......
...@@ -518,7 +518,7 @@ fill_trx_row( ...@@ -518,7 +518,7 @@ fill_trx_row(
row->trx_is_read_only = trx->read_only; 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); return(TRUE);
} }
...@@ -1175,7 +1175,24 @@ static void fetch_data_into_cache_low(trx_i_s_cache_t *cache, const trx_t *trx) ...@@ -1175,7 +1175,24 @@ static void fetch_data_into_cache_low(trx_i_s_cache_t *cache, const trx_t *trx)
{ {
i_s_locks_row_t *requested_lock_row; i_s_locks_row_t *requested_lock_row;
assert_trx_nonlocking_or_in_list(trx); #ifdef UNIV_DEBUG
{
const auto state= trx->state;
if (trx->is_autocommit_non_locking())
{
ut_ad(trx->read_only);
ut_ad(!trx->is_recovered);
ut_ad(trx->mysql_thd);
ut_ad(state == TRX_STATE_NOT_STARTED || state == TRX_STATE_ACTIVE);
}
else
ut_ad(state == TRX_STATE_ACTIVE ||
state == TRX_STATE_PREPARED ||
state == TRX_STATE_PREPARED_RECOVERED ||
state == TRX_STATE_COMMITTED_IN_MEMORY);
}
#endif /* UNIV_DEBUG */
if (add_trx_relevant_locks_to_cache(cache, trx, &requested_lock_row)) if (add_trx_relevant_locks_to_cache(cache, trx, &requested_lock_row))
{ {
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2020, MariaDB Corporation. Copyright (c) 2016, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -101,10 +101,21 @@ inline void trx_t::rollback_low(trx_savept_t *savept) ...@@ -101,10 +101,21 @@ inline void trx_t::rollback_low(trx_savept_t *savept)
roll_node_t *roll_node= roll_node_create(heap); roll_node_t *roll_node= roll_node_create(heap);
roll_node->savept= savept; roll_node->savept= savept;
if (savept) ut_ad(!in_rollback);
check_trx_state(this); #ifdef UNIV_DEBUG
else {
assert_trx_nonlocking_or_in_list(this); const auto s= state;
ut_ad(s == TRX_STATE_ACTIVE ||
s == TRX_STATE_PREPARED ||
s == TRX_STATE_PREPARED_RECOVERED);
if (savept)
{
ut_ad(s == TRX_STATE_ACTIVE);
ut_ad(mysql_thd);
ut_ad(!is_recovered);
}
}
#endif
error_state = DB_SUCCESS; error_state = DB_SUCCESS;
...@@ -203,7 +214,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -203,7 +214,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
switch (trx->state) { switch (trx->state) {
case TRX_STATE_NOT_STARTED: case TRX_STATE_NOT_STARTED:
trx->will_lock = 0; trx->will_lock = false;
ut_ad(trx->mysql_thd); ut_ad(trx->mysql_thd);
#ifdef WITH_WSREP #ifdef WITH_WSREP
trx->wsrep= false; trx->wsrep= false;
...@@ -213,12 +224,13 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -213,12 +224,13 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
case TRX_STATE_ACTIVE: case TRX_STATE_ACTIVE:
ut_ad(trx->mysql_thd); ut_ad(trx->mysql_thd);
assert_trx_nonlocking_or_in_list(trx); ut_ad(!trx->is_recovered);
ut_ad(!trx->is_autocommit_non_locking() || trx->read_only);
return(trx_rollback_for_mysql_low(trx)); return(trx_rollback_for_mysql_low(trx));
case TRX_STATE_PREPARED: case TRX_STATE_PREPARED:
case TRX_STATE_PREPARED_RECOVERED: case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx->is_autocommit_non_locking());
if (trx->rsegs.m_redo.undo || trx->rsegs.m_redo.old_insert) { if (trx->rsegs.m_redo.undo || trx->rsegs.m_redo.old_insert) {
/* The XA ROLLBACK of a XA PREPARE transaction /* The XA ROLLBACK of a XA PREPARE transaction
will consist of multiple mini-transactions. will consist of multiple mini-transactions.
...@@ -265,7 +277,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -265,7 +277,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
return(trx_rollback_for_mysql_low(trx)); return(trx_rollback_for_mysql_low(trx));
case TRX_STATE_COMMITTED_IN_MEMORY: case TRX_STATE_COMMITTED_IN_MEMORY:
check_trx_state(trx); ut_ad(!trx->is_autocommit_non_locking());
break; break;
} }
...@@ -294,7 +306,9 @@ trx_rollback_last_sql_stat_for_mysql( ...@@ -294,7 +306,9 @@ trx_rollback_last_sql_stat_for_mysql(
return(DB_SUCCESS); return(DB_SUCCESS);
case TRX_STATE_ACTIVE: 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"; trx->op_info = "rollback of SQL statement";
......
...@@ -137,7 +137,7 @@ trx_init( ...@@ -137,7 +137,7 @@ trx_init(
trx->auto_commit = false; trx->auto_commit = false;
trx->will_lock = 0; trx->will_lock = false;
trx->ddl = false; trx->ddl = false;
...@@ -353,7 +353,7 @@ trx_t *trx_create() ...@@ -353,7 +353,7 @@ trx_t *trx_create()
ib_alloc_t* alloc; ib_alloc_t* alloc;
/* We just got trx from pool, it should be non locking */ /* 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->rw_trx_hash_pins); ut_ad(!trx->rw_trx_hash_pins);
DBUG_LOG("trx", "Create: " << trx); DBUG_LOG("trx", "Create: " << trx);
...@@ -564,7 +564,7 @@ void trx_disconnect_prepared(trx_t *trx) ...@@ -564,7 +564,7 @@ void trx_disconnect_prepared(trx_t *trx)
trx->is_recovered= true; trx->is_recovered= true;
trx->mysql_thd= NULL; trx->mysql_thd= NULL;
/* todo/fixme: suggest to do it at innodb prepare */ /* todo/fixme: suggest to do it at innodb prepare */
trx->will_lock= 0; trx->will_lock= false;
trx_sys.rw_trx_hash.put_pins(trx); trx_sys.rw_trx_hash.put_pins(trx);
} }
...@@ -911,11 +911,10 @@ static trx_rseg_t* trx_assign_rseg_low() ...@@ -911,11 +911,10 @@ static trx_rseg_t* trx_assign_rseg_low()
/** Assign a rollback segment for modifying temporary tables. /** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */ @return the assigned rollback segment */
trx_rseg_t* trx_rseg_t *trx_t::assign_temp_rseg()
trx_t::assign_temp_rseg()
{ {
ut_ad(!rsegs.m_noredo.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)); compile_time_assert(ut_is_2pow(TRX_SYS_N_RSEGS));
/* Choose a temporary rollback segment between 0 and 127 /* Choose a temporary rollback segment between 0 and 127
...@@ -962,8 +961,8 @@ trx_start_low( ...@@ -962,8 +961,8 @@ trx_start_low(
&& thd_trx_is_read_only(trx->mysql_thd)); && thd_trx_is_read_only(trx->mysql_thd));
if (!trx->auto_commit) { if (!trx->auto_commit) {
++trx->will_lock; trx->will_lock = true;
} else if (trx->will_lock == 0) { } else if (!trx->will_lock) {
trx->read_only = true; trx->read_only = true;
} }
...@@ -1001,7 +1000,7 @@ trx_start_low( ...@@ -1001,7 +1000,7 @@ trx_start_low(
trx_sys.register_rw(trx); trx_sys.register_rw(trx);
} else { } else {
if (!trx_is_autocommit_non_locking(trx)) { if (!trx->is_autocommit_non_locking()) {
/* If this is a read-only transaction that is writing /* If this is a read-only transaction that is writing
to a temporary table then it needs a transaction id to a temporary table then it needs a transaction id
...@@ -1302,12 +1301,15 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) ...@@ -1302,12 +1301,15 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr)
must_flush_log_later= false; must_flush_log_later= false;
read_view.close(); read_view.close();
if (trx_is_autocommit_non_locking(this)) if (is_autocommit_non_locking())
{ {
ut_ad(id == 0); ut_ad(id == 0);
ut_ad(read_only); ut_ad(read_only);
ut_ad(!will_lock);
ut_a(!is_recovered); ut_a(!is_recovered);
ut_ad(!rsegs.m_redo.rseg); ut_ad(!rsegs.m_redo.rseg);
ut_ad(mysql_thd);
ut_ad(state == TRX_STATE_ACTIVE);
/* Note: We are asserting without holding the lock mutex. But /* Note: We are asserting without holding the lock mutex. But
that is OK because this transaction is not waiting and cannot that is OK because this transaction is not waiting and cannot
...@@ -1321,12 +1323,11 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) ...@@ -1321,12 +1323,11 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr)
However, the freezing of trx_sys.trx_list will protect the trx_t However, the freezing of trx_sys.trx_list will protect the trx_t
instance and it cannot be removed from the trx_list and freed instance and it cannot be removed from the trx_list and freed
without first unfreezing trx_list. */ without first unfreezing trx_list. */
ut_ad(trx_state_eq(this, TRX_STATE_ACTIVE)); state= TRX_STATE_NOT_STARTED;
MONITOR_INC(MONITOR_TRX_NL_RO_COMMIT); MONITOR_INC(MONITOR_TRX_NL_RO_COMMIT);
DBUG_LOG("trx", "Autocommit in memory: " << this); DBUG_LOG("trx", "Autocommit in memory: " << this);
state= TRX_STATE_NOT_STARTED;
} }
else else
{ {
...@@ -1477,8 +1478,6 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) ...@@ -1477,8 +1478,6 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr)
@param mtr mini-transaction (if there are any persistent modifications) */ @param mtr mini-transaction (if there are any persistent modifications) */
void trx_t::commit_low(mtr_t *mtr) void trx_t::commit_low(mtr_t *mtr)
{ {
assert_trx_nonlocking_or_in_list(this);
ut_ad(!trx_state_eq(this, TRX_STATE_COMMITTED_IN_MEMORY));
ut_ad(!mtr || mtr->is_active()); ut_ad(!mtr || mtr->is_active());
ut_d(bool aborted = in_rollback && error_state == DB_DEADLOCK); ut_d(bool aborted = in_rollback && error_state == DB_DEADLOCK);
ut_ad(!mtr == (aborted || !has_logged_or_recovered())); ut_ad(!mtr == (aborted || !has_logged_or_recovered()));
...@@ -1487,13 +1486,13 @@ void trx_t::commit_low(mtr_t *mtr) ...@@ -1487,13 +1486,13 @@ void trx_t::commit_low(mtr_t *mtr)
/* undo_no is non-zero if we're doing the final commit. */ /* undo_no is non-zero if we're doing the final commit. */
if (fts_trx && undo_no) if (fts_trx && undo_no)
{ {
ut_a(!trx_is_autocommit_non_locking(this)); ut_a(!is_autocommit_non_locking());
dberr_t error= fts_commit(this);
/* FTS-FIXME: Temporarily tolerate DB_DUPLICATE_KEY instead of /* FTS-FIXME: Temporarily tolerate DB_DUPLICATE_KEY instead of
dying. This is a possible scenario if there is a crash between dying. This is a possible scenario if there is a crash between
insert to DELETED table committing and transaction committing. The insert to DELETED table committing and transaction committing. The
fix would be able to return error from this function */ fix would be able to return error from this function */
ut_a(error == DB_SUCCESS || error == DB_DUPLICATE_KEY); if (dberr_t error= fts_commit(this))
ut_a(error == DB_DUPLICATE_KEY);
} }
#ifndef DBUG_OFF #ifndef DBUG_OFF
...@@ -1753,8 +1752,6 @@ trx_print_low( ...@@ -1753,8 +1752,6 @@ trx_print_low(
/*!< in: mem_heap_get_size(trx->lock.lock_heap) */ /*!< in: mem_heap_get_size(trx->lock.lock_heap) */
{ {
ibool newline; ibool newline;
const char* op_info;
fprintf(f, "TRANSACTION " TRX_ID_FMT, trx_get_id_for_print(trx)); fprintf(f, "TRANSACTION " TRX_ID_FMT, trx_get_id_for_print(trx));
switch (trx->state) { switch (trx->state) {
...@@ -1778,10 +1775,7 @@ trx_print_low( ...@@ -1778,10 +1775,7 @@ trx_print_low(
ut_ad(0); ut_ad(0);
state_ok: state_ok:
/* prevent a race condition */ if (const char *op_info = trx->op_info) {
op_info = trx->op_info;
if (*op_info) {
putc(' ', f); putc(' ', f);
fputs(op_info, f); fputs(op_info, f);
} }
...@@ -2245,7 +2239,7 @@ trx_start_internal_low( ...@@ -2245,7 +2239,7 @@ trx_start_internal_low(
/* Ensure it is not flagged as an auto-commit-non-locking /* Ensure it is not flagged as an auto-commit-non-locking
transaction. */ transaction. */
trx->will_lock = 1; trx->will_lock = true;
trx->internal = true; trx->internal = true;
...@@ -2261,7 +2255,7 @@ trx_start_internal_read_only_low( ...@@ -2261,7 +2255,7 @@ trx_start_internal_read_only_low(
/* Ensure it is not flagged as an auto-commit-non-locking /* Ensure it is not flagged as an auto-commit-non-locking
transaction. */ transaction. */
trx->will_lock = 1; trx->will_lock = true;
trx->internal = true; trx->internal = true;
...@@ -2282,13 +2276,7 @@ trx_start_for_ddl_low( ...@@ -2282,13 +2276,7 @@ trx_start_for_ddl_low(
the data dictionary will be locked in crash recovery. */ the data dictionary will be locked in crash recovery. */
trx_set_dict_operation(trx, op); 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->ddl= true;
trx_start_internal_low(trx); trx_start_internal_low(trx);
return; return;
...@@ -2315,7 +2303,7 @@ trx_set_rw_mode( ...@@ -2315,7 +2303,7 @@ trx_set_rw_mode(
trx_t* trx) /*!< in/out: transaction that is RW */ trx_t* trx) /*!< in/out: transaction that is RW */
{ {
ut_ad(trx->rsegs.m_redo.rseg == 0); ut_ad(trx->rsegs.m_redo.rseg == 0);
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx->is_autocommit_non_locking());
ut_ad(!trx->read_only); ut_ad(!trx->read_only);
ut_ad(trx->id == 0); ut_ad(trx->id == 0);
......
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