Commit b6e41e38 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-28445 Secondary index locking invokes costly trx_sys.get_min_trx_id()

lock_sec_rec_read_check_and_lock(): Remove a redundant check
for trx_sys.get_min_trx_id(). This would be checked in
lock_sec_rec_some_has_impl() anyway. Also, test the
cheapest conditions first.

lock_sec_rec_some_has_impl(): Replace trx_sys.get_min_trx_id()
with trx_sys.find_same_or_older() that is much easier to evaluate.

Inspired by mysql/mysql-server@0a0c0db97e9c9705f4dffc629a770fb87a60cb22
parent 0f717d03
...@@ -925,20 +925,16 @@ class trx_sys_t ...@@ -925,20 +925,16 @@ class trx_sys_t
/** /**
Returns the minimum trx id in rw trx list. Determine if the specified transaction or any older one might be active.
This is the smallest id for which the trx can possibly be active. (But, you @param caller_trx used to get/set pins
must look at the trx->state to find out if the minimum trx id transaction @param id transaction identifier
itself is active, or already committed.) @return whether any transaction not newer than id might be active
@return the minimum trx id, or m_max_trx_id if the trx list is empty
*/ */
trx_id_t get_min_trx_id() bool find_same_or_older(trx_t *caller_trx, trx_id_t id)
{ {
trx_id_t id= get_max_trx_id(); return rw_trx_hash.iterate(caller_trx, find_same_or_older_callback, &id);
rw_trx_hash.iterate(get_min_trx_id_callback, &id);
return id;
} }
...@@ -1173,18 +1169,10 @@ class trx_sys_t ...@@ -1173,18 +1169,10 @@ class trx_sys_t
} }
private: private:
static my_bool get_min_trx_id_callback(rw_trx_hash_element_t *element, static my_bool find_same_or_older_callback(rw_trx_hash_element_t *element,
trx_id_t *id) trx_id_t *id)
{ {
if (element->id < *id) return element->id <= *id;
{
element->mutex.wr_lock();
/* We don't care about read-only transactions here. */
if (element->trx && element->trx->rsegs.m_redo.rseg)
*id= element->id;
element->mutex.wr_unlock();
}
return 0;
} }
......
...@@ -1045,39 +1045,22 @@ lock_sec_rec_some_has_impl( ...@@ -1045,39 +1045,22 @@ lock_sec_rec_some_has_impl(
dict_index_t* index, /*!< in: secondary index */ dict_index_t* index, /*!< in: secondary index */
const rec_offs* offsets)/*!< in: rec_get_offsets(rec, index) */ const rec_offs* offsets)/*!< in: rec_get_offsets(rec, index) */
{ {
trx_t* trx;
trx_id_t max_trx_id;
const page_t* page = page_align(rec);
lock_sys.assert_unlocked(); lock_sys.assert_unlocked();
ut_ad(!dict_index_is_clust(index)); ut_ad(!dict_index_is_clust(index));
ut_ad(page_rec_is_user_rec(rec)); ut_ad(page_rec_is_user_rec(rec));
ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(!rec_is_metadata(rec, *index)); ut_ad(!rec_is_metadata(rec, *index));
max_trx_id = page_get_max_trx_id(page); const trx_id_t max_trx_id= page_get_max_trx_id(page_align(rec));
/* Some transaction may have an implicit x-lock on the record only
if the max trx id for the page >= min trx id for the trx list, or
database recovery is running. */
if (max_trx_id < trx_sys.get_min_trx_id()) {
trx = 0; if ((caller_trx->id > max_trx_id &&
!trx_sys.find_same_or_older(caller_trx, max_trx_id)) ||
} else if (!lock_check_trx_id_sanity(max_trx_id, rec, index, offsets)) { !lock_check_trx_id_sanity(max_trx_id, rec, index, offsets))
return nullptr;
/* The page is corrupt: try to avoid a crash by returning 0 */
trx = 0;
/* In this case it is possible that some transaction has an implicit /* In this case it is possible that some transaction has an implicit
x-lock. We have to look in the clustered index. */ x-lock. We have to look in the clustered index. */
return row_vers_impl_x_locked(caller_trx, rec, index, offsets);
} else {
trx = row_vers_impl_x_locked(caller_trx, rec, index, offsets);
}
return(trx);
} }
/*********************************************************************//** /*********************************************************************//**
...@@ -5413,7 +5396,6 @@ lock_sec_rec_read_check_and_lock( ...@@ -5413,7 +5396,6 @@ lock_sec_rec_read_check_and_lock(
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
dberr_t err; dberr_t err;
ulint heap_no;
ut_ad(!dict_index_is_clust(index)); ut_ad(!dict_index_is_clust(index));
ut_ad(!dict_index_is_online_ddl(index)); ut_ad(!dict_index_is_online_ddl(index));
...@@ -5433,17 +5415,10 @@ lock_sec_rec_read_check_and_lock( ...@@ -5433,17 +5415,10 @@ lock_sec_rec_read_check_and_lock(
const page_id_t id{block->page.id()}; const page_id_t id{block->page.id()};
ut_ad(!rec_is_metadata(rec, *index)); ut_ad(!rec_is_metadata(rec, *index));
heap_no = page_rec_get_heap_no(rec);
/* Some transaction may have an implicit x-lock on the record only
if the max trx id for the page >= min trx id for the trx list or a
database recovery is running. */
trx_t *trx = thr_get_trx(thr); trx_t *trx = thr_get_trx(thr);
if (!lock_table_has(trx, index->table, LOCK_X) if (!page_rec_is_supremum(rec)
&& !page_rec_is_supremum(rec) && !lock_table_has(trx, index->table, LOCK_X)
&& page_get_max_trx_id(block->page.frame)
>= trx_sys.get_min_trx_id()
&& lock_rec_convert_impl_to_expl(thr_get_trx(thr), id, rec, && lock_rec_convert_impl_to_expl(thr_get_trx(thr), id, rec,
index, offsets) index, offsets)
&& gap_mode == LOCK_REC_NOT_GAP) { && gap_mode == LOCK_REC_NOT_GAP) {
...@@ -5464,7 +5439,7 @@ lock_sec_rec_read_check_and_lock( ...@@ -5464,7 +5439,7 @@ lock_sec_rec_read_check_and_lock(
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
err = lock_rec_lock(false, gap_mode | mode, err = lock_rec_lock(false, gap_mode | mode,
block, heap_no, index, thr); block, page_rec_get_heap_no(rec), index, thr);
#ifdef WITH_WSREP #ifdef WITH_WSREP
if (trx->wsrep == 3) trx->wsrep = 1; if (trx->wsrep == 3) trx->wsrep = 1;
......
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