Skip to content

Commit

Permalink
MDEV-14756 - Remove trx_sys_t::rw_trx_list
Browse files Browse the repository at this point in the history
Determine minimum transaction id by iterating rw_trx_hash, not rw_trx_list.

It is more expensive than previous implementation since it does linear
search, especially if there're many concurrent transactions running. But in
such case mutex is much bigger evil. And since it doesn't require
trx_sys->mutex protection it scales better.

For low concurrency performance difference is neglible.
  • Loading branch information
Sergey Vojtovich committed Jan 20, 2018
1 parent 868c77d commit a0b385e
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 59 deletions.
76 changes: 66 additions & 10 deletions storage/innobase/include/trx0sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,6 @@ inline bool trx_id_check(const void* db_trx_id, trx_id_t trx_id)
}
#endif

/****************************************************************//**
Returns the minimum trx id in rw trx list. This is the smallest id for which
the trx can possibly be active. (But, you must look at the trx->state to
find out if the minimum trx id transaction itself is active, or already
committed.)
@return the minimum trx id, or trx_sys->max_trx_id if the trx list is empty */
UNIV_INLINE
trx_id_t
trx_rw_min_trx_id(void);
/*===================*/
/*****************************************************************//**
Updates the offset information about the end of the MySQL binlog entry
which corresponds to the transaction just being committed. In a MySQL
Expand Down Expand Up @@ -743,6 +733,38 @@ class rw_trx_hash_t
{
return my_atomic_load32_explicit(&hash.count, MY_MEMORY_ORDER_RELAXED);
}


/**
Iterates the hash.
@param caller_trx used to get/set pins
@param action called for every element in hash
@param argument opque argument passed to action
May return the same element multiple times if hash is under contention.
Elements can be added or removed while this method is being executed.
@return
@retval 0 iteration completed successfully
@retval 1 iteration was interrupted (action returned 1)
*/

int iterate(trx_t *caller_trx, my_hash_walk_action action, void *argument)
{
LF_PINS *pins= caller_trx ? get_pins(caller_trx) : lf_hash_get_pins(&hash);
ut_a(pins);
int res= lf_hash_iterate(&hash, pins, action, argument);
if (!caller_trx)
lf_hash_put_pins(pins);
return res;
}


int iterate(my_hash_walk_action action, void *argument)
{
return iterate(current_trx(), action, argument);
}
};


Expand Down Expand Up @@ -840,6 +862,40 @@ struct trx_sys_t {
while there were XA PREPARED
transactions. We disable query cache
if such transactions exist. */

/**
Returns the minimum trx id in rw trx list.
This is the smallest id for which the trx can possibly be active. (But, you
must look at the trx->state to find out if the minimum trx id transaction
itself is active, or already committed.)
@return the minimum trx id, or trx_sys->max_trx_id if the trx list is empty
*/

trx_id_t get_min_trx_id()
{
trx_id_t id= trx_sys_get_max_trx_id();
rw_trx_hash.iterate(reinterpret_cast<my_hash_walk_action>
(get_min_trx_id_callback), &id);
return id;
}


private:
static my_bool get_min_trx_id_callback(rw_trx_hash_element_t *element,
trx_id_t *id)
{
if (element->id < *id)
{
mutex_enter(&element->mutex);
/* We don't care about read-only transactions here. */
if (element->trx && element->trx->rsegs.m_redo.rseg)
*id= element->id;
mutex_exit(&element->mutex);
}
return 0;
}
};

/** When a trx id which is zero modulo this number (which must be a power of
Expand Down
47 changes: 0 additions & 47 deletions storage/innobase/include/trx0sys.ic
Original file line number Diff line number Diff line change
Expand Up @@ -192,53 +192,6 @@ trx_write_trx_id(
mach_write_to_6(ptr, id);
}

/****************************************************************//**
Returns the minimum trx id in trx list. This is the smallest id for which
the trx can possibly be active. (But, you must look at the trx->state
to find out if the minimum trx id transaction itself is active, or already
committed.). The caller must be holding the trx_sys_t::mutex in shared mode.
@return the minimum trx id, or trx_sys->max_trx_id if the trx list is empty */
UNIV_INLINE
trx_id_t
trx_rw_min_trx_id_low(void)
/*=======================*/
{
trx_id_t id;

ut_ad(trx_sys_mutex_own());

const trx_t* trx = UT_LIST_GET_LAST(trx_sys->rw_trx_list);

if (trx == NULL) {
id = trx_sys->max_trx_id;
} else {
assert_trx_in_rw_list(trx);
id = trx->id;
}

return(id);
}

/****************************************************************//**
Returns the minimum trx id in rw trx list. This is the smallest id for which
the rw trx can possibly be active. (But, you must look at the trx->state
to find out if the minimum trx id transaction itself is active, or already
committed.)
@return the minimum trx id, or trx_sys->max_trx_id if rw trx list is empty */
UNIV_INLINE
trx_id_t
trx_rw_min_trx_id(void)
/*===================*/
{
trx_sys_mutex_enter();

trx_id_t id = trx_rw_min_trx_id_low();

trx_sys_mutex_exit();

return(id);
}

/*****************************************************************//**
Allocates a new transaction id.
@return new, allocated trx id */
Expand Down
5 changes: 3 additions & 2 deletions storage/innobase/lock/lock0lock.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1514,7 +1514,7 @@ lock_sec_rec_some_has_impl(
max trx id to the log, and therefore during recovery, this value
for a page may be incorrect. */

if (max_trx_id < trx_rw_min_trx_id()) {
if (max_trx_id < trx_sys->get_min_trx_id()) {

trx = 0;

Expand Down Expand Up @@ -7094,7 +7094,8 @@ lock_sec_rec_read_check_and_lock(
database recovery is running. */

if (!page_rec_is_supremum(rec)
&& page_get_max_trx_id(block->frame) >= trx_rw_min_trx_id()) {
&& page_get_max_trx_id(block->frame) >=
trx_sys->get_min_trx_id()) {

lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec,
index, offsets);
Expand Down

0 comments on commit a0b385e

Please sign in to comment.