summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-07-27 08:52:01 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-07-27 08:52:01 +0300
commitcf1fc59856daa4c5730737541126d5492a091722 (patch)
tree5a845894074aedceed8d71a4381aaab39c700fd3
parent0bd9f755b798718dab8e354d39238d5e1457fd39 (diff)
downloadmariadb-git-cf1fc59856daa4c5730737541126d5492a091722.tar.gz
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 7b51d11cca8898f319ddde5d7048cb81b43fef06 from 10.5.
-rw-r--r--storage/innobase/handler/ha_innodb.cc72
-rw-r--r--storage/innobase/handler/handler0alter.cc3
-rw-r--r--storage/innobase/include/trx0i_s.h6
-rw-r--r--storage/innobase/include/trx0sys.ic6
-rw-r--r--storage/innobase/include/trx0trx.h124
-rw-r--r--storage/innobase/include/trx0trx.ic19
-rw-r--r--storage/innobase/lock/lock0lock.cc39
-rw-r--r--storage/innobase/read/read0read.cc4
-rw-r--r--storage/innobase/trx/trx0i_s.cc20
-rw-r--r--storage/innobase/trx/trx0roll.cc39
-rw-r--r--storage/innobase/trx/trx0sys.cc7
-rw-r--r--storage/innobase/trx/trx0trx.cc84
12 files changed, 185 insertions, 238 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 81f1dae85b6..00c9595aa87 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -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);
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 24a7c4a74ad..88e02ee4e32 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -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 @@ foreign_fail:
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",
diff --git a/storage/innobase/include/trx0i_s.h b/storage/innobase/include/trx0i_s.h
index 7e766072272..ca65e053502 100644
--- a/storage/innobase/include/trx0i_s.h
+++ b/storage/innobase/include/trx0i_s.h
@@ -1,7 +1,7 @@
/*****************************************************************************
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()
*/
};
diff --git a/storage/innobase/include/trx0sys.ic b/storage/innobase/include/trx0sys.ic
index c85695630f0..8518934e94f 100644
--- a/storage/innobase/include/trx0sys.ic
+++ b/storage/innobase/include/trx0sys.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
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;
}
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index a7591fa1b19..90365400d72 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -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 @@ public:
/*------------------------------*/
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 @@ public:
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();
};
/**
diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic
index 4a5b1ba717f..2a53509b206 100644
--- a/storage/innobase/include/trx0trx.ic
+++ b/storage/innobase/include/trx0trx.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
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:
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 506106a2269..4daf4fb07b8 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -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 @@ loop:
}
}
- 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) {
diff --git a/storage/innobase/read/read0read.cc b/storage/innobase/read/read0read.cc
index 3fd52d5d6dd..a115672a8a6 100644
--- a/storage/innobase/read/read0read.cc
+++ b/storage/innobase/read/read0read.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
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;
diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc
index 2b9d6c96acd..05579aeb223 100644
--- a/storage/innobase/trx/trx0i_s.cc
+++ b/storage/innobase/trx/trx0i_s.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
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 @@ thd_done:
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);
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index c986a866fe2..ec2d3c1d03f 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
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
diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
index 9138e9475bf..c8c68c37333 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -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);
}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index d1b35bd84a3..3e558a7181d 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -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) {