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( ...@@ -4503,7 +4503,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 */
...@@ -4860,7 +4860,7 @@ innobase_rollback_trx( ...@@ -4860,7 +4860,7 @@ innobase_rollback_trx(
lock_unlock_table_autoinc(trx); lock_unlock_table_autoinc(trx);
if (!trx->has_logged()) { if (!trx->has_logged()) {
trx->will_lock = 0; trx->will_lock = false;
#ifdef WITH_WSREP #ifdef WITH_WSREP
trx->wsrep = false; trx->wsrep = false;
#endif #endif
...@@ -8176,20 +8176,12 @@ ha_innobase::write_row( ...@@ -8176,20 +8176,12 @@ ha_innobase::write_row(
if (high_level_read_only) { if (high_level_read_only) {
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 (UNIV_UNLIKELY(m_prebuilt->trx != trx)) { }
ib::error() << "The transaction object for the table handle is"
" at " << static_cast<const void*>(m_prebuilt->trx) ut_a(m_prebuilt->trx == trx);
<< ", but for the current thread it is at "
<< static_cast<const void*>(trx); if (!trx_is_started(trx)) {
trx->will_lock = true;
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;
} }
#ifdef WITH_WSREP #ifdef WITH_WSREP
...@@ -8964,7 +8956,7 @@ ha_innobase::update_row( ...@@ -8964,7 +8956,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) {
...@@ -9110,7 +9102,7 @@ ha_innobase::delete_row( ...@@ -9110,7 +9102,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) {
...@@ -9990,7 +9982,7 @@ ha_innobase::ft_init() ...@@ -9990,7 +9982,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));
...@@ -10056,7 +10048,7 @@ ha_innobase::ft_init_ext( ...@@ -10056,7 +10048,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;
...@@ -13081,7 +13073,7 @@ create_table_info_t::allocate_trx() ...@@ -13081,7 +13073,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;
} }
...@@ -13372,13 +13364,7 @@ inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom) ...@@ -13372,13 +13364,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 */
...@@ -13555,14 +13541,7 @@ innobase_drop_database( ...@@ -13555,14 +13541,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;
...@@ -13606,7 +13585,7 @@ inline dberr_t innobase_rename_table(trx_t *trx, const char *from, ...@@ -13606,7 +13585,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:
...@@ -13651,7 +13630,7 @@ inline dberr_t innobase_rename_table(trx_t *trx, const char *from, ...@@ -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 /* Transaction must be flagged as a locking transaction or it hasn't
been started yet. */ 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, error = row_rename_table_for_mysql(norm_from, norm_to, trx, commit,
commit); commit);
...@@ -13737,7 +13716,7 @@ int ha_innobase::truncate() ...@@ -13737,7 +13716,7 @@ int ha_innobase::truncate()
if (!srv_safe_truncate) { if (!srv_safe_truncate) {
if (!trx_is_started(m_prebuilt->trx)) { 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( dberr_t err = row_truncate_table_for_mysql(
...@@ -13791,8 +13770,7 @@ int ha_innobase::truncate() ...@@ -13791,8 +13770,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);
...@@ -13877,9 +13855,7 @@ ha_innobase::rename_table( ...@@ -13877,9 +13855,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);
...@@ -15880,7 +15856,7 @@ ha_innobase::start_stmt( ...@@ -15880,7 +15856,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);
...@@ -16103,7 +16079,7 @@ ha_innobase::external_lock( ...@@ -16103,7 +16079,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);
...@@ -16150,7 +16126,7 @@ ha_innobase::external_lock( ...@@ -16150,7 +16126,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);
...@@ -16829,7 +16805,7 @@ ha_innobase::store_lock( ...@@ -16829,7 +16805,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);
......
...@@ -967,7 +967,7 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -967,7 +967,7 @@ ha_innobase::check_if_supported_inplace_alter(
} }
} }
m_prebuilt->trx->will_lock++; m_prebuilt->trx->will_lock = true;
if (!online) { if (!online) {
/* We already determined that only a non-locking /* We already determined that only a non-locking
...@@ -8954,7 +8954,6 @@ ha_innobase::commit_inplace_alter_table( ...@@ -8954,7 +8954,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, 2019, 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
...@@ -164,8 +164,8 @@ struct i_s_trx_row_t { ...@@ -164,8 +164,8 @@ struct i_s_trx_row_t {
/*!< detailed_error in trx_t */ /*!< detailed_error in trx_t */
ulint trx_is_read_only; ulint trx_is_read_only;
/*!< trx_t::read_only */ /*!< trx_t::read_only */
ulint trx_is_autocommit_non_locking; bool trx_is_autocommit_non_locking;
/*!< trx_is_autocommit_non_locking(trx) /*!< trx:t::is_autocommit_non_locking()
*/ */
}; };
......
/***************************************************************************** /*****************************************************************************
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
...@@ -251,7 +251,9 @@ trx_rw_min_trx_id_low(void) ...@@ -251,7 +251,9 @@ trx_rw_min_trx_id_low(void)
if (trx == NULL) { if (trx == NULL) {
id = trx_sys->max_trx_id; id = trx_sys->max_trx_id;
} else { } 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; id = trx->id;
} }
......
...@@ -502,99 +502,6 @@ from innodb_lock_wait_timeout via trx_t::mysql_thd. ...@@ -502,99 +502,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)))
/**
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; typedef std::vector<ib_lock_t*, ut_allocator<ib_lock_t*> > lock_list;
/*******************************************************************//** /*******************************************************************//**
...@@ -1070,16 +977,15 @@ struct trx_t { ...@@ -1070,16 +977,15 @@ struct trx_t {
/*------------------------------*/ /*------------------------------*/
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
...@@ -1199,10 +1105,28 @@ struct trx_t { ...@@ -1199,10 +1105,28 @@ struct trx_t {
inline void free(); 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: 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
...@@ -50,17 +50,18 @@ trx_state_eq( ...@@ -50,17 +50,18 @@ trx_state_eq(
switch (trx->state) { switch (trx->state) {
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)); case TRX_STATE_COMMITTED_IN_MEMORY:
ut_ad(!trx->is_autocommit_non_locking());
return(trx->state == state); return(trx->state == state);
case TRX_STATE_ACTIVE: case TRX_STATE_ACTIVE:
if (trx->is_autocommit_non_locking()) {
assert_trx_nonlocking_or_in_list(trx); ut_ad(!trx->is_recovered);
return(state == trx->state); ut_ad(trx->read_only);
ut_ad(trx->mysql_thd);
case TRX_STATE_COMMITTED_IN_MEMORY: ut_ad(!trx->in_rw_trx_list);
ut_ad(trx->in_mysql_trx_list);
check_trx_state(trx); }
return(state == trx->state); return(state == trx->state);
case TRX_STATE_NOT_STARTED: case TRX_STATE_NOT_STARTED:
......
...@@ -1376,6 +1376,19 @@ wsrep_print_wait_locks( ...@@ -1376,6 +1376,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 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, /** 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
...@@ -3589,8 +3602,8 @@ lock_table_create( ...@@ -3589,8 +3602,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;
...@@ -4545,7 +4558,10 @@ lock_remove_recovered_trx_record_locks( ...@@ -4545,7 +4558,10 @@ lock_remove_recovered_trx_record_locks(
trx != NULL; trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) { 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) { if (!trx->is_recovered) {
continue; continue;
...@@ -5181,7 +5197,8 @@ lock_rec_queue_validate( ...@@ -5181,7 +5197,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)
...@@ -5260,8 +5277,7 @@ lock_rec_queue_validate( ...@@ -5260,8 +5277,7 @@ 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->is_autocommit_non_locking());
ut_ad(!trx_is_ac_nl_ro(lock->trx));
if (index) { if (index) {
ut_a(lock->index == index); ut_a(lock->index == index);
...@@ -5357,7 +5373,8 @@ lock_rec_validate_page( ...@@ -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 /* Only validate the record queues when this thread is not
holding a space->latch. */ holding a space->latch. */
...@@ -5465,7 +5482,7 @@ lock_rec_validate( ...@@ -5465,7 +5482,7 @@ lock_rec_validate(
ib_uint64_t current; 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); ut_ad(lock_get_type(lock) == LOCK_REC);
current = ut_ull_create( current = ut_ull_create(
...@@ -7075,7 +7092,8 @@ DeadlockChecker::search() ...@@ -7075,7 +7092,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. */
...@@ -7235,7 +7253,8 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx) ...@@ -7235,7 +7253,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) 2019, MariaDB Corporation. Copyright (c) 2019, 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
...@@ -574,7 +574,7 @@ MVCC::view_open(ReadView*& view, trx_t* trx) ...@@ -574,7 +574,7 @@ MVCC::view_open(ReadView*& view, trx_t* trx)
Therefore we must set the low limit id after we reset the Therefore we must set the low limit id after we reset the
closed status after the check. */ 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; view->m_closed = false;
......
/***************************************************************************** /*****************************************************************************
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, 2019, 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
...@@ -577,7 +577,7 @@ fill_trx_row( ...@@ -577,7 +577,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);
} }
...@@ -1259,7 +1259,21 @@ fetch_data_into_cache_low( ...@@ -1259,7 +1259,21 @@ fetch_data_into_cache_low(
continue; 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); ut_ad(trx->in_rw_trx_list == rw_trx_list);
......
/***************************************************************************** /*****************************************************************************
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
...@@ -81,12 +81,19 @@ trx_rollback_to_savepoint_low( ...@@ -81,12 +81,19 @@ trx_rollback_to_savepoint_low(
heap = mem_heap_create(512); heap = mem_heap_create(512);
roll_node = roll_node_create(heap); roll_node = roll_node_create(heap);
ut_ad(!trx->in_rollback);
if (savept != NULL) { if (savept != NULL) {
roll_node->savept = savept; 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 { } 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; trx->error_state = DB_SUCCESS;
...@@ -187,7 +194,8 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -187,7 +194,8 @@ 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->in_mysql_trx_list); ut_ad(trx->in_mysql_trx_list);
#ifdef WITH_WSREP #ifdef WITH_WSREP
trx->wsrep = false; trx->wsrep = false;
...@@ -196,12 +204,14 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -196,12 +204,14 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
case TRX_STATE_ACTIVE: case TRX_STATE_ACTIVE:
ut_ad(trx->in_mysql_trx_list); 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)); 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->has_logged_persistent()) { if (trx->has_logged_persistent()) {
/* 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.
...@@ -245,7 +255,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ...@@ -245,7 +255,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;
} }
...@@ -274,7 +284,9 @@ trx_rollback_last_sql_stat_for_mysql( ...@@ -274,7 +284,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";
...@@ -768,7 +780,11 @@ trx_roll_must_shutdown() ...@@ -768,7 +780,11 @@ trx_roll_must_shutdown()
t != NULL; t != NULL;
t = UT_LIST_GET_NEXT(trx_list, t)) { 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 if (t->is_recovered
&& trx_state_eq(t, TRX_STATE_ACTIVE)) { && trx_state_eq(t, TRX_STATE_ACTIVE)) {
n_trx++; n_trx++;
...@@ -831,7 +847,10 @@ trx_rollback_or_clean_recovered( ...@@ -831,7 +847,10 @@ trx_rollback_or_clean_recovered(
trx != NULL; trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) { 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 /* If this function does a cleanup or rollback
then it will release the trx_sys->mutex, therefore then it will release the trx_sys->mutex, therefore
......
...@@ -513,7 +513,9 @@ trx_sys_init_at_db_start() ...@@ -513,7 +513,9 @@ trx_sys_init_at_db_start()
trx = UT_LIST_GET_NEXT(trx_list, trx)) { trx = UT_LIST_GET_NEXT(trx_list, trx)) {
ut_ad(trx->is_recovered); 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)) { if (trx_state_eq(trx, TRX_STATE_ACTIVE)) {
rows_to_undo += trx->undo_no; rows_to_undo += trx->undo_no;
...@@ -1026,7 +1028,8 @@ trx_sys_validate_trx_list_low( ...@@ -1026,7 +1028,8 @@ trx_sys_validate_trx_list_low(
trx != NULL; trx != NULL;
prev_trx = trx, trx = UT_LIST_GET_NEXT(trx_list, prev_trx)) { 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); ut_a(prev_trx == NULL || prev_trx->id > trx->id);
} }
......
...@@ -133,7 +133,7 @@ trx_init( ...@@ -133,7 +133,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;
...@@ -336,13 +336,13 @@ trx_t *trx_allocate_for_background() ...@@ -336,13 +336,13 @@ trx_t *trx_allocate_for_background()
MEM_MAKE_DEFINED(trx, sizeof *trx); MEM_MAKE_DEFINED(trx, sizeof *trx);
#endif #endif
assert_trx_is_free(trx); trx->assert_freed();
mem_heap_t* heap; mem_heap_t* heap;
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->state == TRX_STATE_NOT_STARTED); ut_ad(trx->state == TRX_STATE_NOT_STARTED);
DBUG_LOG("trx", "Create: " << trx); DBUG_LOG("trx", "Create: " << trx);
...@@ -369,7 +369,8 @@ trx_t *trx_allocate_for_background() ...@@ -369,7 +369,8 @@ trx_t *trx_allocate_for_background()
/** Free the memory to trx_pools */ /** Free the memory to trx_pools */
inline void trx_t::free() inline void trx_t::free()
{ {
assert_trx_is_inactive(this); assert_freed();
ut_ad(!dict_operation_lock_mode);
MEM_CHECK_DEFINED(this, sizeof *this); MEM_CHECK_DEFINED(this, sizeof *this);
...@@ -539,7 +540,8 @@ trx_validate_state_before_free(trx_t* trx) ...@@ -539,7 +540,8 @@ trx_validate_state_before_free(trx_t* trx)
} }
trx->dict_operation = TRX_DICT_OP_NONE; 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. /** Free and initialize a transaction object instantinated during recovery.
...@@ -636,7 +638,9 @@ trx_free_prepared( ...@@ -636,7 +638,9 @@ trx_free_prepared(
trx->release_locks(); trx->release_locks();
trx_undo_free_prepared(trx); 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); ut_a(!trx->read_only);
...@@ -685,7 +689,7 @@ trx_disconnect_from_mysql( ...@@ -685,7 +689,7 @@ trx_disconnect_from_mysql(
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_mutex_exit(); trx_sys_mutex_exit();
...@@ -1177,11 +1181,10 @@ void trx_t::remove_flush_observer() ...@@ -1177,11 +1181,10 @@ void trx_t::remove_flush_observer()
/** 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
...@@ -1235,8 +1238,8 @@ trx_start_low( ...@@ -1235,8 +1238,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;
} }
...@@ -1305,7 +1308,7 @@ trx_start_low( ...@@ -1305,7 +1308,7 @@ trx_start_low(
trx_sys_mutex_exit(); trx_sys_mutex_exit();
} 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
...@@ -1691,12 +1694,16 @@ trx_commit_in_memory( ...@@ -1691,12 +1694,16 @@ trx_commit_in_memory(
{ {
trx->must_flush_log_later = false; 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->id == 0);
ut_ad(trx->read_only); ut_ad(trx->read_only);
ut_ad(!trx->will_lock);
ut_a(!trx->is_recovered); ut_a(!trx->is_recovered);
ut_ad(trx->rsegs.m_redo.rseg == NULL); ut_ad(trx->rsegs.m_redo.rseg == NULL);
ut_ad(!trx->in_rw_trx_list); 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 /* 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
...@@ -1712,8 +1719,6 @@ trx_commit_in_memory( ...@@ -1712,8 +1719,6 @@ trx_commit_in_memory(
and it cannot be removed from the mysql_trx_list and freed and it cannot be removed from the mysql_trx_list and freed
without first acquiring the trx_sys_t::mutex. */ without first acquiring the trx_sys_t::mutex. */
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
if (trx->read_view != NULL) { if (trx->read_view != NULL) {
trx_sys->mvcc->view_close(trx->read_view, false); trx_sys->mvcc->view_close(trx->read_view, false);
} }
...@@ -1866,7 +1871,7 @@ trx_commit_in_memory( ...@@ -1866,7 +1871,7 @@ trx_commit_in_memory(
/* trx->in_mysql_trx_list would hold between /* trx->in_mysql_trx_list would hold between
trx_allocate_for_mysql() and trx_free_for_mysql(). It does not trx_allocate_for_mysql() and trx_free_for_mysql(). It does not
hold for recovered transactions or system transactions. */ hold for recovered transactions or system transactions. */
assert_trx_is_free(trx); trx->assert_freed();
trx_init(trx); trx_init(trx);
...@@ -1885,30 +1890,20 @@ trx_commit_low( ...@@ -1885,30 +1890,20 @@ trx_commit_low(
mtr_t* mtr) /*!< in/out: mini-transaction (will be committed), mtr_t* mtr) /*!< in/out: mini-transaction (will be committed),
or NULL if trx made no modifications */ 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 || mtr->is_active());
ut_ad(!mtr == !trx->has_logged()); ut_ad(!mtr == !trx->has_logged());
/* 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 (trx->fts_trx != NULL && trx->undo_no != 0) { if (trx->fts_trx != NULL && trx->undo_no != 0) {
dberr_t error; ut_a(!trx->is_autocommit_non_locking());
ut_a(!trx_is_autocommit_non_locking(trx));
error = fts_commit(trx);
/* FTS-FIXME: Temporarily tolerate DB_DUPLICATE_KEY /* FTS-FIXME: Temporarily tolerate DB_DUPLICATE_KEY
instead of dying. This is a possible scenario if there instead of dying. This is a possible scenario if there
is a crash between insert to DELETED table committing is a crash between insert to DELETED table committing
and transaction committing. The fix would be able to and transaction committing. The fix would be able to
return error from this function */ return error from this function */
if (error != DB_SUCCESS && error != DB_DUPLICATE_KEY) { if (dberr_t error = fts_commit(trx)) {
/* FTS-FIXME: once we can return values from this ut_a(error == DB_DUPLICATE_KEY);
function, we should do so and signal an error
instead of just dying. */
ut_error;
} }
} }
...@@ -2279,7 +2274,6 @@ trx_print_low( ...@@ -2279,7 +2274,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;
ut_ad(trx_sys_mutex_own()); ut_ad(trx_sys_mutex_own());
...@@ -2308,9 +2302,7 @@ trx_print_low( ...@@ -2308,9 +2302,7 @@ trx_print_low(
fprintf(f, ", state %lu", (ulong) trx->state); fprintf(f, ", state %lu", (ulong) trx->state);
ut_ad(0); ut_ad(0);
state_ok: state_ok:
const char* op_info = trx->op_info;
/* prevent a race condition */
op_info = trx->op_info;
if (*op_info) { if (*op_info) {
putc(' ', f); putc(' ', f);
...@@ -2549,7 +2541,7 @@ trx_assert_started( ...@@ -2549,7 +2541,7 @@ trx_assert_started(
/* Non-locking autocommits should not hold any locks and this /* Non-locking autocommits should not hold any locks and this
function is only called from the locking code. */ 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->state can change from or to NOT_STARTED while we are holding
trx_sys->mutex for non-locking autocommit selects but not for other trx_sys->mutex for non-locking autocommit selects but not for other
...@@ -2754,7 +2746,9 @@ trx_recover_for_mysql( ...@@ -2754,7 +2746,9 @@ trx_recover_for_mysql(
trx != NULL; trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) { 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 /* The state of a read-write transaction cannot change
from or to NOT_STARTED while we are holding the 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) ...@@ -2821,7 +2815,9 @@ trx_t* trx_get_trx_by_xid_low(const XID* xid)
trx != NULL; trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) { trx = UT_LIST_GET_NEXT(trx_list, trx)) {
trx_mutex_enter(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 /* Compare two X/Open XA transaction id's: their
length should be the same and binary comparison length should be the same and binary comparison
...@@ -2948,7 +2944,7 @@ trx_start_internal_low( ...@@ -2948,7 +2944,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;
...@@ -2964,7 +2960,7 @@ trx_start_internal_read_only_low( ...@@ -2964,7 +2960,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;
...@@ -2985,13 +2981,7 @@ trx_start_for_ddl_low( ...@@ -2985,13 +2981,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;
...@@ -3002,7 +2992,7 @@ trx_start_for_ddl_low( ...@@ -3002,7 +2992,7 @@ trx_start_for_ddl_low(
trx->ddl = true; trx->ddl = true;
ut_ad(trx->dict_operation != TRX_DICT_OP_NONE); ut_ad(trx->dict_operation != TRX_DICT_OP_NONE);
ut_ad(trx->will_lock > 0); ut_ad(trx->will_lock);
return; return;
case TRX_STATE_PREPARED: case TRX_STATE_PREPARED:
...@@ -3028,7 +3018,7 @@ trx_set_rw_mode( ...@@ -3028,7 +3018,7 @@ trx_set_rw_mode(
{ {
ut_ad(trx->rsegs.m_redo.rseg == 0); ut_ad(trx->rsegs.m_redo.rseg == 0);
ut_ad(!trx->in_rw_trx_list); 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); ut_ad(!trx->read_only);
if (high_level_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