MDEV-14756 - Remove trx_sys_t::rw_trx_list

Remove rw_trx_list.
This commit is contained in:
Sergey Vojtovich 2017-12-27 16:23:53 +04:00
parent a447980ff3
commit c6d2842d9a
7 changed files with 59 additions and 131 deletions

View file

@ -575,6 +575,37 @@ class rw_trx_hash_t
}
#ifdef UNIV_DEBUG
static void validate_element(trx_t *trx)
{
ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg);
ut_ad(!trx_is_autocommit_non_locking(trx));
mutex_enter(&trx->mutex);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
trx_state_eq(trx, TRX_STATE_PREPARED));
mutex_exit(&trx->mutex);
}
struct debug_iterator_arg
{
my_hash_walk_action action;
void *argument;
};
static my_bool debug_iterator(rw_trx_hash_element_t *element,
debug_iterator_arg *arg)
{
mutex_enter(&element->mutex);
if (element->trx)
validate_element(element->trx);
mutex_exit(&element->mutex);
return arg->action(element, arg->argument);
}
#endif
public:
void init()
{
@ -675,12 +706,7 @@ public:
{
if (do_ref_count)
trx->reference();
#ifdef UNIV_DEBUG
mutex_enter(&trx->mutex);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
trx_state_eq(trx, TRX_STATE_PREPARED));
mutex_exit(&trx->mutex);
#endif
ut_d(validate_element(trx));
}
mutex_exit(&element->mutex);
}
@ -704,8 +730,7 @@ public:
void insert(trx_t *trx)
{
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
trx_state_eq(trx, TRX_STATE_PREPARED));
ut_d(validate_element(trx));
int res= lf_hash_insert(&hash, get_pins(trx),
reinterpret_cast<void*>(trx));
ut_a(res == 0);
@ -722,8 +747,7 @@ public:
void erase(trx_t *trx)
{
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
trx_state_eq(trx, TRX_STATE_PREPARED));
ut_d(validate_element(trx));
mutex_enter(&trx->rw_trx_hash_element->mutex);
trx->rw_trx_hash_element->trx= 0;
mutex_exit(&trx->rw_trx_hash_element->mutex);
@ -781,6 +805,11 @@ public:
{
LF_PINS *pins= caller_trx ? get_pins(caller_trx) : lf_hash_get_pins(&hash);
ut_a(pins);
#ifdef UNIV_DEBUG
debug_iterator_arg debug_arg= { action, argument };
action= reinterpret_cast<my_hash_walk_action>(debug_iterator);
argument= &debug_arg;
#endif
int res= lf_hash_iterate(&hash, pins, action, argument);
if (!caller_trx)
lf_hash_put_pins(pins);
@ -840,18 +869,11 @@ struct trx_sys_t {
transactions which exist or existed */
#endif /* UNIV_DEBUG */
/** Avoid false sharing */
const char pad1[CACHE_LINE_SIZE];
trx_ut_list_t rw_trx_list; /*!< List of active and committed in
memory read-write transactions, sorted
on trx id, biggest first. Recovered
transactions are always on this list. */
/** Avoid false sharing */
const char pad2[CACHE_LINE_SIZE];
trx_ut_list_t mysql_trx_list; /*!< List of transactions created
for MySQL. All user transactions are
on mysql_trx_list. The rw_trx_list
on mysql_trx_list. The rw_trx_hash
can contain system transactions and
recovered transactions that will not
be in the mysql_trx_list.

View file

@ -402,7 +402,7 @@ trx_set_dict_operation(
Determines if a transaction is in the given state.
The caller must hold trx_sys->mutex, or it must be the thread
that is serving a running transaction.
A running RW transaction must be in trx_sys->rw_trx_list.
A running RW transaction must be in trx_sys->rw_trx_hash.
@return TRUE if trx->state == state */
UNIV_INLINE
bool
@ -556,15 +556,6 @@ with an explicit check for the read-only status.
#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 { \
@ -605,7 +596,7 @@ transaction pool.
#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.
rw_trx_hash 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 { \
@ -613,7 +604,6 @@ The tranasction must be in the mysql_trx_list. */
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_FORCED_ROLLBACK \
@ -625,7 +615,7 @@ The tranasction must be in the mysql_trx_list. */
#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.
rw_trx_hash 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 */
@ -946,7 +936,7 @@ public:
transaction is moved to
COMMITTED_IN_MEMORY state.
Protected by trx_sys_t::mutex
when trx->in_rw_trx_list. Initially
when trx is in rw_trx_hash. Initially
set to TRX_ID_MAX. */
/** State of the trx from the point of view of concurrency control
@ -987,11 +977,11 @@ public:
XA (2PC) transactions are always treated as non-autocommit.
Transitions to ACTIVE or NOT_STARTED occur when
!in_rw_trx_list (no trx_sys->mutex needed).
Transitions to ACTIVE or NOT_STARTED occur when transaction
is not in rw_trx_hash (no trx_sys->mutex needed).
Autocommit non-locking read-only transactions move between states
without holding any mutex. They are !in_rw_trx_list.
without holding any mutex. They are not in rw_trx_hash.
All transactions, unless they are determined to be ac-nl-ro,
explicitly tagged as read-only or read-write, will first be put
@ -1001,13 +991,13 @@ public:
list. During this switch we assign it a rollback segment.
When a transaction is NOT_STARTED, it can be in_mysql_trx_list if
it is a user transaction. It cannot be in rw_trx_list.
it is a user transaction. It cannot be in rw_trx_hash.
ACTIVE->PREPARED->COMMITTED is only possible when trx->in_rw_trx_list.
ACTIVE->PREPARED->COMMITTED is only possible when trx is in rw_trx_hash.
The transition ACTIVE->PREPARED is protected by trx_sys->mutex.
ACTIVE->COMMITTED is possible when the transaction is in
rw_trx_list.
rw_trx_hash.
Transitions to COMMITTED are protected by both lock_sys->mutex
and trx->mutex.
@ -1021,9 +1011,6 @@ public:
ReadView* read_view; /*!< consistent read view used in the
transaction, or NULL if not yet set */
UT_LIST_NODE_T(trx_t)
trx_list; /*!< list of transactions;
protected by trx_sys->mutex. */
UT_LIST_NODE_T(trx_t)
no_list; /*!< Required during view creation
to check for the view limit for
@ -1036,7 +1023,7 @@ public:
bool is_recovered; /*!< 0=normal transaction,
1=recovered, must be rolled back,
protected by trx_sys->mutex when
trx->in_rw_trx_list holds */
trx is in rw_trx_hash */
hit_list_t hit_list; /*!< List of transactions to kill,
when a high priority transaction
@ -1145,13 +1132,6 @@ public:
statement uses, except those
in consistent read */
/*------------------------------*/
#ifdef UNIV_DEBUG
/** The following two fields are mutually exclusive. */
/* @{ */
bool in_rw_trx_list; /*!< true if in trx_sys->rw_trx_list */
/* @} */
#endif /* UNIV_DEBUG */
UT_LIST_NODE_T(trx_t)
mysql_trx_list; /*!< list of transactions created for
MySQL; protected by trx_sys->mutex */

View file

@ -30,7 +30,7 @@ Created 3/26/1996 Heikki Tuuri
Determines if a transaction is in the given state.
The caller must hold trx_sys->mutex, or it must be the thread
that is serving a running transaction.
A running RW transaction must be in trx_sys->rw_trx_list.
A running RW transaction must be in trx_sys->rw_trx_hash.
@return TRUE if trx->state == state */
UNIV_INLINE
bool
@ -72,8 +72,6 @@ trx_state_eq(
|| (relaxed
&& thd_get_error_number(trx->mysql_thd)));
ut_ad(!trx->in_rw_trx_list);
return(true);
}
ut_error;

View file

@ -1280,10 +1280,7 @@ static my_bool fetch_data_into_cache_callback(
{
mutex_enter(&element->mutex);
if (element->trx)
{
assert_trx_in_rw_list(element->trx);
fetch_data_into_cache_low(cache, element->trx);
}
mutex_exit(&element->mutex);
return cache->is_truncated;
}

View file

@ -738,7 +738,6 @@ static my_bool trx_roll_count_callback(rw_trx_hash_element_t *element,
mutex_enter(&element->mutex);
if (trx_t *trx= element->trx)
{
assert_trx_in_rw_list(trx);
if (trx->is_recovered && trx_state_eq(trx, TRX_STATE_ACTIVE))
{
arg->n_trx++;
@ -796,7 +795,6 @@ static my_bool trx_rollback_recovered_callback(rw_trx_hash_element_t *element,
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);

View file

@ -469,7 +469,6 @@ trx_sys_create(void)
mutex_create(LATCH_ID_TRX_SYS, &trx_sys->mutex);
UT_LIST_INIT(trx_sys->serialisation_list, &trx_t::no_list);
UT_LIST_INIT(trx_sys->rw_trx_list, &trx_t::trx_list);
UT_LIST_INIT(trx_sys->mysql_trx_list, &trx_t::mysql_trx_list);
trx_sys->mvcc = UT_NEW_NOKEY(MVCC(1024));
@ -607,7 +606,6 @@ trx_sys_close(void)
UT_DELETE(trx_sys->mvcc);
ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->serialisation_list) == 0);

View file

@ -280,7 +280,6 @@ struct TrxFactory {
static void destroy(trx_t* trx)
{
ut_a(trx->magic_n == TRX_MAGIC_N);
ut_ad(!trx->in_rw_trx_list);
ut_ad(!trx->in_mysql_trx_list);
ut_a(trx->lock.wait_lock == NULL);
@ -347,7 +346,6 @@ struct TrxFactory {
ut_ad(trx->mysql_thd == 0);
ut_ad(!trx->in_rw_trx_list);
ut_ad(!trx->in_mysql_trx_list);
ut_a(trx->lock.wait_thr == NULL);
@ -642,13 +640,8 @@ trx_free_at_shutdown(trx_t *trx)
lock_trx_release_locks(trx);
trx_undo_free_at_shutdown(trx);
assert_trx_in_rw_list(trx);
UT_LIST_REMOVE(trx_sys->rw_trx_list, trx);
ut_a(!trx->read_only);
ut_d(trx->in_rw_trx_list = FALSE);
DBUG_LOG("trx", "Free prepared: " << trx);
trx->state = TRX_STATE_NOT_STARTED;
@ -811,34 +804,6 @@ trx_resurrect_table_locks(
}
}
/** Mapping read-write transactions from id to transaction instance, for
creating read views and during trx id lookup for MVCC and locking. */
struct TrxTrack {
explicit TrxTrack(trx_id_t id, trx_t* trx = NULL)
:
m_id(id),
m_trx(trx)
{
// Do nothing
}
trx_id_t m_id;
trx_t* m_trx;
};
/**
Comparator for TrxMap */
struct TrxTrackCmp {
bool operator() (const TrxTrack& lhs, const TrxTrack& rhs) const
{
return(lhs.m_id < rhs.m_id);
}
};
typedef std::set<TrxTrack, TrxTrackCmp, ut_allocator<TrxTrack> >
TrxIdSet;
/**
Resurrect the transactions that were doing inserts/updates the time of the
@ -847,7 +812,7 @@ typedef std::set<TrxTrack, TrxTrackCmp, ut_allocator<TrxTrack> >
static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
ib_time_t start_time, uint64_t *rows_to_undo,
TrxIdSet *set, bool is_old_insert)
bool is_old_insert)
{
trx_state_t state;
/*
@ -910,7 +875,6 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
trx->table_id= undo->table_id;
}
set->insert(TrxTrack(trx->id, trx));
trx_sys->rw_trx_hash.insert(trx);
trx_sys->rw_trx_hash.put_pins(trx);
trx_sys->rw_trx_ids.push_back(trx->id);
@ -918,7 +882,6 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
if (trx_state_eq(trx, TRX_STATE_ACTIVE))
*rows_to_undo+= trx->undo_no;
#ifdef UNIV_DEBUG
trx->in_rw_trx_list= true;
if (trx->id > trx_sys->rw_max_trx_id)
trx_sys->rw_max_trx_id= trx->id;
#endif
@ -929,7 +892,6 @@ static void trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
void
trx_lists_init_at_db_start()
{
TrxIdSet set;
uint64_t rows_to_undo = 0;
ut_a(srv_is_being_started);
ut_ad(!srv_was_started);
@ -961,7 +923,7 @@ trx_lists_init_at_db_start()
while (undo) {
trx_undo_t* next = UT_LIST_GET_NEXT(undo_list, undo);
trx_resurrect(undo, rseg, start_time, &rows_to_undo,
&set, true);
true);
undo = next;
}
@ -972,7 +934,7 @@ trx_lists_init_at_db_start()
trx_t *trx = trx_sys->rw_trx_hash.find(undo->trx_id);
if (!trx) {
trx_resurrect(undo, rseg, start_time,
&rows_to_undo, &set, false);
&rows_to_undo, false);
} else {
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
trx_state_eq(trx, TRX_STATE_PREPARED));
@ -1000,9 +962,9 @@ trx_lists_init_at_db_start()
}
}
if (set.size()) {
if (trx_sys->rw_trx_hash.size()) {
ib::info() << set.size()
ib::info() << trx_sys->rw_trx_hash.size()
<< " transaction(s) which must be rolled back or"
" cleaned up in total " << rows_to_undo
<< " row operations to undo";
@ -1010,14 +972,6 @@ trx_lists_init_at_db_start()
ib::info() << "Trx id counter is " << trx_sys->max_trx_id;
}
TrxIdSet::iterator end = set.end();
for (TrxIdSet::iterator it = set.begin();
it != end;
++it) {
UT_LIST_ADD_FIRST(trx_sys->rw_trx_list, it->m_trx);
}
std::sort(trx_sys->rw_trx_ids.begin(), trx_sys->rw_trx_ids.end());
}
@ -1201,8 +1155,6 @@ trx_start_low(
change must be protected by the trx_sys->mutex, so that
lock_print_info_all_transactions() will have a consistent view. */
ut_ad(!trx->in_rw_trx_list);
/* No other thread can access this trx object through rw_trx_hash, thus
we don't need trx_sys->mutex protection for that purpose. Still this
trx can be found through trx_sys->mysql_trx_list, which means state
@ -1236,9 +1188,6 @@ trx_start_low(
|| srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
UT_LIST_ADD_FIRST(trx_sys->rw_trx_list, trx);
ut_d(trx->in_rw_trx_list = true);
#ifdef UNIV_DEBUG
if (trx->id > trx_sys->rw_max_trx_id) {
trx_sys->rw_max_trx_id = trx->id;
@ -1591,7 +1540,7 @@ trx_update_mod_tables_timestamp(
Erase the transaction from running transaction lists and serialization
list. Active RW transaction list of a MVCC snapshot(ReadView::prepare)
won't include this transaction after this call. All implicit locks are
also released by this call as trx is removed from rw_trx_list.
also released by this call as trx is removed from rw_trx_hash.
@param[in] trx Transaction to erase, must have an ID > 0
@param[in] serialised true if serialisation log was written */
static
@ -1605,13 +1554,9 @@ trx_erase_lists(
if (trx->read_only || trx->rsegs.m_redo.rseg == NULL) {
trx_sys_mutex_enter();
ut_ad(!trx->in_rw_trx_list);
} else {
trx_sys_mutex_enter();
UT_LIST_REMOVE(trx_sys->rw_trx_list, trx);
ut_d(trx->in_rw_trx_list = false);
if (trx->read_view != NULL) {
trx_sys->mvcc->view_close(trx->read_view, true);
}
@ -1652,7 +1597,6 @@ trx_commit_in_memory(
ut_ad(trx->read_only);
ut_a(!trx->is_recovered);
ut_ad(trx->rsegs.m_redo.rseg == NULL);
ut_ad(!trx->in_rw_trx_list);
/* Note: We are asserting without holding the lock mutex. But
that is OK because this transaction is not waiting and cannot
@ -2563,8 +2507,6 @@ static my_bool trx_recover_for_mysql_callback(rw_trx_hash_element_t *element,
mutex_enter(&element->mutex);
if (trx_t *trx= element->trx)
{
assert_trx_in_rw_list(element->trx);
/*
The state of a read-write transaction can only change from ACTIVE to
PREPARED while we are holding the element->mutex. But since it is
@ -2627,7 +2569,6 @@ static my_bool trx_get_trx_by_xid_callback(rw_trx_hash_element_t *element,
mutex_enter(&element->mutex);
if (trx_t *trx= element->trx)
{
assert_trx_in_rw_list(element->trx);
if (trx->is_recovered && trx_state_eq(trx, TRX_STATE_PREPARED) &&
arg->xid->eq(reinterpret_cast<XID*>(trx->xid)))
{
@ -2682,7 +2623,7 @@ trx_start_if_not_started_xa_low(
/* If the transaction is tagged as read-only then
it can only write to temp tables and for such
transactions we don't want to move them to the
trx_sys_t::rw_trx_list. */
trx_sys_t::rw_trx_hash. */
if (!trx->read_only) {
trx_set_rw_mode(trx);
}
@ -2807,7 +2748,6 @@ trx_set_rw_mode(
trx_t* trx) /*!< in/out: transaction that is RW */
{
ut_ad(trx->rsegs.m_redo.rseg == 0);
ut_ad(!trx->in_rw_trx_list);
ut_ad(!trx_is_autocommit_non_locking(trx));
ut_ad(!trx->read_only);
ut_ad(trx->id == 0);
@ -2842,11 +2782,6 @@ trx_set_rw_mode(
trx_sys->rw_max_trx_id = trx->id;
}
#endif /* UNIV_DEBUG */
UT_LIST_ADD_FIRST(trx_sys->rw_trx_list, trx);
ut_d(trx->in_rw_trx_list = true);
mutex_exit(&trx_sys->mutex);
trx_sys->rw_trx_hash.insert(trx);
}