mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 05:52:27 +01:00
MDEV-14756 - Remove trx_sys_t::rw_trx_list
Let trx_rollback_recovered() iterate rw_trx_hash instead of rw_trx_list.
This commit is contained in:
parent
02270b44d0
commit
886af392d3
6 changed files with 96 additions and 148 deletions
|
@ -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 @@ func_exit:
|
|||
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;
|
||||
|
||||
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. */
|
||||
|
||||
/* Loop over the transaction list as long as there are
|
||||
recovered transactions to clean up or recover. */
|
||||
|
||||
do {
|
||||
trx_sys_mutex_enter();
|
||||
|
||||
for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
|
||||
trx != NULL;
|
||||
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
|
||||
|
||||
assert_trx_in_rw_list(trx);
|
||||
|
||||
/* 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. */
|
||||
|
||||
if (trx_rollback_resurrected(trx, &all)) {
|
||||
|
||||
trx_sys_mutex_enter();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
trx_sys_mutex_exit();
|
||||
|
||||
} while (trx != NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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
|
||||
is shutdown and they are still lingering in trx_sys_t::trx_list
|
||||
then the shutdown will hang.
|
||||
|
||||
@param[in] all true=roll back all recovered active transactions;
|
||||
false=roll back any incomplete dictionary transaction
|
||||
*/
|
||||
|
||||
void trx_rollback_recovered(bool all)
|
||||
{
|
||||
trx_ut_list_t trx_list;
|
||||
|
||||
ut_a(srv_force_recovery < SRV_FORCE_NO_TRX_UNDO);
|
||||
UT_LIST_INIT(trx_list, &trx_t::mysql_trx_list);
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
while (trx_t *trx= UT_LIST_GET_FIRST(trx_list))
|
||||
{
|
||||
UT_LIST_REMOVE(trx_list, trx);
|
||||
|
||||
#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
|
||||
|
||||
if (!srv_is_being_started && !srv_undo_sources && srv_fast_shutdown)
|
||||
goto discard;
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue