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 ...@@ -503,7 +503,7 @@ class rw_trx_hash_t
(!srv_was_started || (!srv_was_started ||
srv_read_only_mode || srv_read_only_mode ||
srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO))); srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO)));
trx_free_prepared(trx); trx_free_at_shutdown(trx);
} }
element->~rw_trx_hash_element_t(); element->~rw_trx_hash_element_t();
} }
......
...@@ -114,12 +114,9 @@ trx_free_resurrected(trx_t* trx); ...@@ -114,12 +114,9 @@ trx_free_resurrected(trx_t* trx);
void void
trx_free_for_background(trx_t* trx); trx_free_for_background(trx_t* trx);
/********************************************************************//** /** At shutdown, frees a transaction object. */
At shutdown, frees a transaction object that is in the PREPARED state. */
void void
trx_free_prepared( trx_free_at_shutdown(trx_t *trx);
/*==============*/
trx_t* trx); /*!< in, own: trx object */
/** Free a transaction object for MySQL. /** Free a transaction object for MySQL.
@param[in,out] trx transaction */ @param[in,out] trx transaction */
......
...@@ -295,13 +295,9 @@ the data can be discarded. ...@@ -295,13 +295,9 @@ the data can be discarded.
void void
trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp); trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp);
/********************************************************************//** /** At shutdown, frees the undo logs of a transaction. */
At shutdown, frees the undo logs of a PREPARED transaction. */
void void
trx_undo_free_prepared( trx_undo_free_at_shutdown(trx_t *trx);
/*===================*/
trx_t* trx) /*!< in/out: PREPARED transaction */
ATTRIBUTE_COLD __attribute__((nonnull));
/* Forward declaration. */ /* Forward declaration. */
namespace undo { namespace undo {
......
...@@ -723,74 +723,6 @@ trx_rollback_active( ...@@ -723,74 +723,6 @@ trx_rollback_active(
trx_roll_crash_recv_trx = NULL; 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 struct trx_roll_count_callback_arg
{ {
...@@ -856,54 +788,88 @@ trx_roll_must_shutdown() ...@@ -856,54 +788,88 @@ trx_roll_must_shutdown()
return false; return false;
} }
/*******************************************************************//**
Rollback or clean up any incomplete transactions which were static my_bool trx_rollback_recovered_callback(rw_trx_hash_element_t *element,
encountered in crash recovery. If the transaction already was trx_ut_list_t *trx_list)
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)
{ {
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 /**
Rollback 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.
Note: For XA recovered transactions, we rely on MySQL to
do rollback. They will be in TRX_STATE_PREPARED state. If the server 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 is shutdown and they are still lingering in trx_sys_t::trx_list
then the shutdown will hang. */ then the shutdown will hang.
/* Loop over the transaction list as long as there are @param[in] all true=roll back all recovered active transactions;
recovered transactions to clean up or recover. */ false=roll back any incomplete dictionary transaction
*/
do { void trx_rollback_recovered(bool all)
trx_sys_mutex_enter(); {
trx_ut_list_t trx_list;
for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list); ut_a(srv_force_recovery < SRV_FORCE_NO_TRX_UNDO);
trx != NULL; UT_LIST_INIT(trx_list, &trx_t::mysql_trx_list);
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
assert_trx_in_rw_list(trx); /*
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);
/* If this function does a cleanup or rollback while (trx_t *trx= UT_LIST_GET_FIRST(trx_list))
then it will release the trx_sys->mutex, therefore {
we need to reacquire it before retrying the loop. */ UT_LIST_REMOVE(trx_list, trx);
if (trx_rollback_resurrected(trx, &all)) { #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_enter(); if (!srv_is_being_started && !srv_undo_sources && srv_fast_shutdown)
goto discard;
break; 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);
} }
} }
trx_sys_mutex_exit();
} while (trx != NULL);
} }
/*******************************************************************//** /*******************************************************************//**
Rollback or clean up any incomplete transactions which were Rollback or clean up any incomplete transactions which were
encountered in crash recovery. If the transaction already was encountered in crash recovery. If the transaction already was
......
...@@ -623,26 +623,24 @@ trx_free_for_background(trx_t* trx) ...@@ -623,26 +623,24 @@ trx_free_for_background(trx_t* trx)
trx_free(trx); trx_free(trx);
} }
/********************************************************************//** /** At shutdown, frees a transaction object. */
At shutdown, frees a transaction object that is in the PREPARED state. */
void void
trx_free_prepared( trx_free_at_shutdown(trx_t *trx)
/*==============*/
trx_t* trx) /*!< in, own: trx object */
{ {
ut_ad(trx->is_recovered);
ut_a(trx_state_eq(trx, TRX_STATE_PREPARED) 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_ACTIVE)
|| trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY))
&& (!srv_was_started && (!srv_was_started
|| srv_operation == SRV_OPERATION_RESTORE || srv_operation == SRV_OPERATION_RESTORE
|| srv_operation == SRV_OPERATION_RESTORE_EXPORT || srv_operation == SRV_OPERATION_RESTORE_EXPORT
|| srv_read_only_mode || 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); ut_a(trx->magic_n == TRX_MAGIC_N);
lock_trx_release_locks(trx); lock_trx_release_locks(trx);
trx_undo_free_prepared(trx); trx_undo_free_at_shutdown(trx);
assert_trx_in_rw_list(trx); assert_trx_in_rw_list(trx);
UT_LIST_REMOVE(trx_sys->rw_trx_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) ...@@ -1622,15 +1622,10 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
mutex_exit(&rseg->mutex); mutex_exit(&rseg->mutex);
} }
/********************************************************************//** /** At shutdown, frees the undo logs of a transaction. */
At shutdown, frees the undo logs of a PREPARED transaction. */
void void
trx_undo_free_prepared( trx_undo_free_at_shutdown(trx_t *trx)
/*===================*/
trx_t* trx) /*!< in/out: PREPARED transaction */
{ {
ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) { if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) {
switch (undo->state) { switch (undo->state) {
case TRX_UNDO_PREPARED: case TRX_UNDO_PREPARED:
...@@ -1643,9 +1638,7 @@ trx_undo_free_prepared( ...@@ -1643,9 +1638,7 @@ trx_undo_free_prepared(
/* fall through */ /* fall through */
case TRX_UNDO_ACTIVE: case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns /* lock_trx_release_locks() assigns
trx->state = TRX_STATE_COMMITTED_IN_MEMORY, trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
also for transactions that we faked
to TRX_STATE_PREPARED in trx_rollback_resurrected(). */
ut_a(!srv_was_started ut_a(!srv_was_started
|| srv_read_only_mode || srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
...@@ -1672,9 +1665,7 @@ trx_undo_free_prepared( ...@@ -1672,9 +1665,7 @@ trx_undo_free_prepared(
/* fall through */ /* fall through */
case TRX_UNDO_ACTIVE: case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns /* lock_trx_release_locks() assigns
trx->state = TRX_STATE_COMMITTED_IN_MEMORY, trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
also for transactions that we faked
to TRX_STATE_PREPARED in trx_rollback_resurrected(). */
ut_a(!srv_was_started ut_a(!srv_was_started
|| srv_read_only_mode || srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO || 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