Commit 886af392 authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-14756 - Remove trx_sys_t::rw_trx_list

Let trx_rollback_recovered() iterate rw_trx_hash instead of rw_trx_list.
parent 02270b44
......@@ -503,7 +503,7 @@ class rw_trx_hash_t
(!srv_was_started ||
srv_read_only_mode ||
srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO)));
trx_free_prepared(trx);
trx_free_at_shutdown(trx);
}
element->~rw_trx_hash_element_t();
}
......
......@@ -114,12 +114,9 @@ trx_free_resurrected(trx_t* trx);
void
trx_free_for_background(trx_t* trx);
/********************************************************************//**
At shutdown, frees a transaction object that is in the PREPARED state. */
/** At shutdown, frees a transaction object. */
void
trx_free_prepared(
/*==============*/
trx_t* trx); /*!< in, own: trx object */
trx_free_at_shutdown(trx_t *trx);
/** Free a transaction object for MySQL.
@param[in,out] trx transaction */
......
......@@ -295,13 +295,9 @@ the data can be discarded.
void
trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp);
/********************************************************************//**
At shutdown, frees the undo logs of a PREPARED transaction. */
/** At shutdown, frees the undo logs of a transaction. */
void
trx_undo_free_prepared(
/*===================*/
trx_t* trx) /*!< in/out: PREPARED transaction */
ATTRIBUTE_COLD __attribute__((nonnull));
trx_undo_free_at_shutdown(trx_t *trx);
/* Forward declaration. */
namespace undo {
......
......@@ -723,74 +723,6 @@ trx_rollback_active(
trx_roll_crash_recv_trx = NULL;
}
/*******************************************************************//**
Rollback or clean up any resurrected incomplete transactions. It assumes
that the caller holds the trx_sys_t::mutex and it will release the
lock if it does a clean up or rollback.
@return TRUE if the transaction was cleaned up or rolled back
and trx_sys->mutex was released. */
static
ibool
trx_rollback_resurrected(
/*=====================*/
trx_t* trx, /*!< in: transaction to rollback or clean */
bool* all) /*!< in/out: FALSE=roll back dictionary transactions;
TRUE=roll back all non-PREPARED transactions */
{
ut_ad(trx_sys_mutex_own());
/* The trx->is_recovered flag and trx->state are set
atomically under the protection of the trx->mutex (and
lock_sys->mutex) in lock_trx_release_locks(). We do not want
to accidentally clean up a non-recovered transaction here. */
trx_mutex_enter(trx);
if (!trx->is_recovered) {
func_exit:
trx_mutex_exit(trx);
return(FALSE);
}
switch (trx->state) {
case TRX_STATE_ACTIVE:
if (!srv_is_being_started
&& !srv_undo_sources && srv_fast_shutdown) {
fake_prepared:
trx->state = TRX_STATE_PREPARED;
*all = false;
goto func_exit;
}
trx_mutex_exit(trx);
if (*all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
trx_sys_mutex_exit();
trx_rollback_active(trx);
if (trx->error_state != DB_SUCCESS) {
ut_ad(trx->error_state == DB_INTERRUPTED);
trx->error_state = DB_SUCCESS;
ut_ad(!srv_undo_sources);
ut_ad(srv_fast_shutdown);
mutex_enter(&trx_sys->mutex);
trx_mutex_enter(trx);
goto fake_prepared;
}
trx_free_for_background(trx);
return(TRUE);
}
return(FALSE);
case TRX_STATE_COMMITTED_IN_MEMORY:
ut_ad(trx->xid);
case TRX_STATE_PREPARED:
goto func_exit;
case TRX_STATE_NOT_STARTED:
case TRX_STATE_FORCED_ROLLBACK:
break;
}
ut_error;
goto func_exit;
}
struct trx_roll_count_callback_arg
{
......@@ -856,54 +788,88 @@ trx_roll_must_shutdown()
return false;
}
/*******************************************************************//**
Rollback or clean up any incomplete transactions which were
encountered in crash recovery. If the transaction already was
committed, then we clean up a possible insert undo log. If the
transaction was not yet committed, then we roll it back.
@param all true=roll back all recovered active transactions;
false=roll back any incomplete dictionary transaction */
void
trx_rollback_recovered(bool all)
static my_bool trx_rollback_recovered_callback(rw_trx_hash_element_t *element,
trx_ut_list_t *trx_list)
{
trx_t* trx;
mutex_enter(&element->mutex);
if (trx_t *trx= element->trx)
{
mutex_enter(&trx->mutex);
assert_trx_in_rw_list(trx);
if (trx->is_recovered && trx_state_eq(trx, TRX_STATE_ACTIVE))
UT_LIST_ADD_FIRST(*trx_list, trx);
mutex_exit(&trx->mutex);
}
mutex_exit(&element->mutex);
return 0;
}
ut_a(srv_force_recovery < SRV_FORCE_NO_TRX_UNDO);
/* Note: For XA recovered transactions, we rely on MySQL to
do rollback. They will be in TRX_STATE_PREPARED state. If the server
is shutdown and they are still lingering in trx_sys_t::trx_list
then the shutdown will hang. */
/**
Rollback any incomplete transactions which were encountered in crash recovery.
/* Loop over the transaction list as long as there are
recovered transactions to clean up or recover. */
If the transaction already was committed, then we clean up a possible insert
undo log. If the transaction was not yet committed, then we roll it back.
do {
trx_sys_mutex_enter();
Note: For XA recovered transactions, we rely on MySQL to
do rollback. They will be in TRX_STATE_PREPARED state. If the server
is shutdown and they are still lingering in trx_sys_t::trx_list
then the shutdown will hang.
for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
trx != NULL;
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
@param[in] all true=roll back all recovered active transactions;
false=roll back any incomplete dictionary transaction
*/
assert_trx_in_rw_list(trx);
void trx_rollback_recovered(bool all)
{
trx_ut_list_t trx_list;
/* If this function does a cleanup or rollback
then it will release the trx_sys->mutex, therefore
we need to reacquire it before retrying the loop. */
ut_a(srv_force_recovery < SRV_FORCE_NO_TRX_UNDO);
UT_LIST_INIT(trx_list, &trx_t::mysql_trx_list);
if (trx_rollback_resurrected(trx, &all)) {
/*
Collect list of recovered ACTIVE transaction ids first. Once collected, no
other thread is allowed to modify or remove these transactions from
rw_trx_hash.
*/
trx_sys->rw_trx_hash.iterate_no_dups(reinterpret_cast<my_hash_walk_action>
(trx_rollback_recovered_callback), &trx_list);
trx_sys_mutex_enter();
while (trx_t *trx= UT_LIST_GET_FIRST(trx_list))
{
UT_LIST_REMOVE(trx_list, trx);
break;
}
}
#ifdef UNIV_DEBUG
ut_ad(trx);
trx_mutex_enter(trx);
ut_ad(trx->is_recovered && trx_state_eq(trx, TRX_STATE_ACTIVE));
trx_mutex_exit(trx);
#endif
trx_sys_mutex_exit();
if (!srv_is_being_started && !srv_undo_sources && srv_fast_shutdown)
goto discard;
} while (trx != NULL);
if (all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE)
{
trx_rollback_active(trx);
if (trx->error_state != DB_SUCCESS)
{
ut_ad(trx->error_state == DB_INTERRUPTED);
trx->error_state= DB_SUCCESS;
ut_ad(!srv_undo_sources);
ut_ad(srv_fast_shutdown);
discard:
trx_sys->rw_trx_hash.erase(trx);
trx_free_at_shutdown(trx);
}
else
trx_free_for_background(trx);
}
}
}
/*******************************************************************//**
Rollback or clean up any incomplete transactions which were
encountered in crash recovery. If the transaction already was
......
......@@ -623,26 +623,24 @@ trx_free_for_background(trx_t* trx)
trx_free(trx);
}
/********************************************************************//**
At shutdown, frees a transaction object that is in the PREPARED state. */
/** At shutdown, frees a transaction object. */
void
trx_free_prepared(
/*==============*/
trx_t* trx) /*!< in, own: trx object */
trx_free_at_shutdown(trx_t *trx)
{
ut_ad(trx->is_recovered);
ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)
|| (trx->is_recovered
&& (trx_state_eq(trx, TRX_STATE_ACTIVE)
|| trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY))
|| (trx_state_eq(trx, TRX_STATE_ACTIVE)
&& (!srv_was_started
|| srv_operation == SRV_OPERATION_RESTORE
|| srv_operation == SRV_OPERATION_RESTORE_EXPORT
|| srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO)));
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
|| (!srv_is_being_started
&& !srv_undo_sources && srv_fast_shutdown))));
ut_a(trx->magic_n == TRX_MAGIC_N);
lock_trx_release_locks(trx);
trx_undo_free_prepared(trx);
trx_undo_free_at_shutdown(trx);
assert_trx_in_rw_list(trx);
UT_LIST_REMOVE(trx_sys->rw_trx_list, trx);
......
......@@ -1622,15 +1622,10 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
mutex_exit(&rseg->mutex);
}
/********************************************************************//**
At shutdown, frees the undo logs of a PREPARED transaction. */
/** At shutdown, frees the undo logs of a transaction. */
void
trx_undo_free_prepared(
/*===================*/
trx_t* trx) /*!< in/out: PREPARED transaction */
trx_undo_free_at_shutdown(trx_t *trx)
{
ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) {
switch (undo->state) {
case TRX_UNDO_PREPARED:
......@@ -1643,9 +1638,7 @@ trx_undo_free_prepared(
/* fall through */
case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns
trx->state = TRX_STATE_COMMITTED_IN_MEMORY,
also for transactions that we faked
to TRX_STATE_PREPARED in trx_rollback_resurrected(). */
trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
ut_a(!srv_was_started
|| srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
......@@ -1672,9 +1665,7 @@ trx_undo_free_prepared(
/* fall through */
case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns
trx->state = TRX_STATE_COMMITTED_IN_MEMORY,
also for transactions that we faked
to TRX_STATE_PREPARED in trx_rollback_resurrected(). */
trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
ut_a(!srv_was_started
|| srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
......
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