Skip to content

Commit dcb2968

Browse files
committed
MDEV-27557 InnoDB unnecessarily commits mtr during secondary index search to preserve clustered index latching order
New function to release latches till savepoint was added in mtr_t. As there is no longer need to limit MDEV-20605 fix usage for locking reads only, the limitation is removed.
1 parent 157a838 commit dcb2968

File tree

3 files changed

+82
-29
lines changed

3 files changed

+82
-29
lines changed

storage/innobase/include/mtr0mtr.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ struct mtr_t {
9797
/** Commit the mini-transaction. */
9898
void commit();
9999

100+
/** Release latches till savepoint. To simplify the code only
101+
MTR_MEMO_S_LOCK and MTR_MEMO_PAGE_S_FIX slot types are allowed to be
102+
released, otherwise it would be neccesary to add one more argument in the
103+
function to point out what slot types are allowed for rollback, and this
104+
would be overengineering as currently the function is used only in one place
105+
in the code.
106+
@param savepoint savepoint, can be obtained with get_savepoint */
107+
void rollback_to_savepoint(ulint savepoint);
108+
100109
/** Commit a mini-transaction that is shrinking a tablespace.
101110
@param space tablespace that is being shrunk */
102111
ATTRIBUTE_COLD void commit_shrink(fil_space_t &space);

storage/innobase/mtr/mtr0mtr.cc

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,50 @@ struct ReleaseAll {
300300
}
301301
};
302302

303+
/** Stops iteration is savepoint is reached */
304+
template <typename Functor> struct TillSavepoint
305+
{
306+
307+
/** Constructor
308+
@param[in] functor functor which is called if savepoint is not reached
309+
@param[in] savepoint savepoint value to rollback
310+
@param[in] used current position in slots container */
311+
TillSavepoint(const Functor &functor, ulint savepoint, ulint used)
312+
: functor(functor),
313+
m_slots_count((used - savepoint) / sizeof(mtr_memo_slot_t))
314+
{
315+
ut_ad(savepoint);
316+
ut_ad(used >= savepoint);
317+
}
318+
319+
/** @return true if savepoint is not reached, false otherwise */
320+
bool operator()(mtr_memo_slot_t *slot)
321+
{
322+
#ifdef UNIV_DEBUG
323+
/** This check is added because the code is invoked only from
324+
row_search_mvcc() to release latches acquired during clustered index search
325+
for secondary index record. To make it more universal we could add one more
326+
member in this functor for debug build to pass only certain slot types,
327+
but this is currently not necessary. */
328+
switch (slot->type)
329+
{
330+
case MTR_MEMO_S_LOCK:
331+
case MTR_MEMO_PAGE_S_FIX:
332+
break;
333+
default:
334+
ut_a(false);
335+
}
336+
#endif
337+
return m_slots_count-- && functor(slot);
338+
}
339+
340+
private:
341+
/** functor to invoke */
342+
const Functor &functor;
343+
/** slots count left till savepoint */
344+
ulint m_slots_count;
345+
};
346+
303347
#ifdef UNIV_DEBUG
304348
/** Check that all slots have been handled. */
305349
struct DebugCheck {
@@ -468,6 +512,21 @@ void mtr_t::commit()
468512
release_resources();
469513
}
470514

515+
/** Release latches till savepoint. To simplify the code only
516+
MTR_MEMO_S_LOCK and MTR_MEMO_PAGE_S_FIX slot types are allowed to be
517+
released, otherwise it would be neccesary to add one more argument in the
518+
function to point out what slot types are allowed for rollback, and this
519+
would be overengineering as corrently the function is used only in one place
520+
in the code.
521+
@param savepoint savepoint, can be obtained with get_savepoint */
522+
void mtr_t::rollback_to_savepoint(ulint savepoint)
523+
{
524+
Iterate<TillSavepoint<ReleaseLatches>> iteration(
525+
TillSavepoint<ReleaseLatches>(ReleaseLatches(), savepoint,
526+
get_savepoint()));
527+
m_memo.for_each_block_in_reverse(iteration);
528+
}
529+
471530
/** Shrink a tablespace. */
472531
struct Shrink
473532
{

storage/innobase/row/row0sel.cc

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3588,14 +3588,12 @@ record with the same ordering prefix in in the B-tree index
35883588
@param[in] latch_mode latch mode wished in restoration
35893589
@param[in] pcur cursor whose position has been stored
35903590
@param[in] moves_up true if the cursor moves up in the index
3591-
@param[in] mtr mtr; CAUTION: may commit mtr temporarily!
3592-
@param[in] select_lock_type select lock type
3591+
@param[in,out] mtr mtr; CAUTION: may commit mtr temporarily!
35933592
@return true if we may need to process the record the cursor is now
35943593
positioned on (i.e. we should not go to the next record yet) */
35953594
static bool sel_restore_position_for_mysql(bool *same_user_rec,
35963595
ulint latch_mode, btr_pcur_t *pcur,
3597-
bool moves_up, mtr_t *mtr,
3598-
lock_mode select_lock_type)
3596+
bool moves_up, mtr_t *mtr)
35993597
{
36003598
auto status = btr_pcur_restore_position(latch_mode, pcur, mtr);
36013599

@@ -3618,8 +3616,7 @@ static bool sel_restore_position_for_mysql(bool *same_user_rec,
36183616
switch (pcur->rel_pos) {
36193617
case BTR_PCUR_ON:
36203618
if (!*same_user_rec && moves_up) {
3621-
if (status == btr_pcur_t::SAME_UNIQ
3622-
&& select_lock_type != LOCK_NONE)
3619+
if (status == btr_pcur_t::SAME_UNIQ)
36233620
return true;
36243621
next:
36253622
if (btr_pcur_move_to_next(pcur, mtr)
@@ -4303,7 +4300,7 @@ row_search_mvcc(
43034300
const rec_t* clust_rec;
43044301
Row_sel_get_clust_rec_for_mysql row_sel_get_clust_rec_for_mysql;
43054302
ibool unique_search = FALSE;
4306-
ibool mtr_has_extra_clust_latch = FALSE;
4303+
ulint mtr_extra_clust_savepoint = 0;
43074304
bool moves_up = false;
43084305
/* if the returned record was locked and we did a semi-consistent
43094306
read (fetch the newest committed version), then this is set to
@@ -4673,7 +4670,7 @@ row_search_mvcc(
46734670

46744671
bool need_to_process = sel_restore_position_for_mysql(
46754672
&same_user_rec, BTR_SEARCH_LEAF,
4676-
pcur, moves_up, &mtr, prebuilt->select_lock_type);
4673+
pcur, moves_up, &mtr);
46774674

46784675
if (UNIV_UNLIKELY(need_to_process)) {
46794676
if (UNIV_UNLIKELY(prebuilt->row_read_type
@@ -5355,7 +5352,7 @@ row_search_mvcc(
53555352
/* It was a non-clustered index and we must fetch also the
53565353
clustered index record */
53575354

5358-
mtr_has_extra_clust_latch = TRUE;
5355+
mtr_extra_clust_savepoint = mtr.get_savepoint();
53595356

53605357
ut_ad(!vrow);
53615358
/* The following call returns 'offsets' associated with
@@ -5643,27 +5640,15 @@ row_search_mvcc(
56435640
/* No need to do store restore for R-tree */
56445641
mtr.commit();
56455642
mtr.start();
5646-
mtr_has_extra_clust_latch = FALSE;
5647-
} else if (mtr_has_extra_clust_latch) {
5648-
/* If we have extra cluster latch, we must commit
5649-
mtr if we are moving to the next non-clustered
5643+
mtr_extra_clust_savepoint = 0;
5644+
} else if (mtr_extra_clust_savepoint) {
5645+
/* We must release any clustered index latches
5646+
if we are moving to the next non-clustered
56505647
index record, because we could break the latching
56515648
order if we would access a different clustered
56525649
index page right away without releasing the previous. */
5653-
5654-
btr_pcur_store_position(pcur, &mtr);
5655-
mtr.commit();
5656-
mtr_has_extra_clust_latch = FALSE;
5657-
5658-
mtr.start();
5659-
5660-
if (sel_restore_position_for_mysql(&same_user_rec,
5661-
BTR_SEARCH_LEAF,
5662-
pcur, moves_up, &mtr,
5663-
prebuilt->select_lock_type)
5664-
) {
5665-
goto rec_loop;
5666-
}
5650+
mtr.rollback_to_savepoint(mtr_extra_clust_savepoint);
5651+
mtr_extra_clust_savepoint = 0;
56675652
}
56685653

56695654
if (moves_up) {
@@ -5723,7 +5708,7 @@ row_search_mvcc(
57235708

57245709
lock_table_wait:
57255710
mtr.commit();
5726-
mtr_has_extra_clust_latch = FALSE;
5711+
mtr_extra_clust_savepoint = 0;
57275712

57285713
trx->error_state = err;
57295714

@@ -5752,7 +5737,7 @@ row_search_mvcc(
57525737
if (!dict_index_is_spatial(index)) {
57535738
sel_restore_position_for_mysql(
57545739
&same_user_rec, BTR_SEARCH_LEAF, pcur,
5755-
moves_up, &mtr, prebuilt->select_lock_type);
5740+
moves_up, &mtr);
57565741
}
57575742

57585743
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED

0 commit comments

Comments
 (0)