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_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);
|
||||||
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.
|
||||||
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 @@ func_exit:
|
||||||
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()
|
||||||
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)
|
||||||
ut_a(srv_force_recovery < SRV_FORCE_NO_TRX_UNDO);
|
{
|
||||||
|
mutex_enter(&trx->mutex);
|
||||||
/* Note: For XA recovered transactions, we rely on MySQL to
|
assert_trx_in_rw_list(trx);
|
||||||
do rollback. They will be in TRX_STATE_PREPARED state. If the server
|
if (trx->is_recovered && trx_state_eq(trx, TRX_STATE_ACTIVE))
|
||||||
is shutdown and they are still lingering in trx_sys_t::trx_list
|
UT_LIST_ADD_FIRST(*trx_list, trx);
|
||||||
then the shutdown will hang. */
|
mutex_exit(&trx->mutex);
|
||||||
|
}
|
||||||
/* Loop over the transaction list as long as there are
|
mutex_exit(&element->mutex);
|
||||||
recovered transactions to clean up or recover. */
|
return 0;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
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)
|
||||||
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)
|
||||||
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(
|
||||||
/* 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(
|
||||||
/* 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
|
||||||
|
|
Loading…
Reference in a new issue