MDEV-27927 row_sel_try_search_shortcut_for_mysql() does not latch a page, violating read view isolation

btr_search_guess_on_hash() would only acquire an index page latch if it
is invoked with ahi_latch=NULL. If it's invoked from
row_sel_try_search_shortcut_for_mysql() with ahi_latch!=NULL, a page
will not be latched, and row_search_mvcc() will get a pointer to the
record, which can be changed by some other transaction before the record
was stored in result buffer with row_sel_store_mysql_rec() call.

ahi_latch argument of btr_cur_search_to_nth_level_func() and
btr_pcur_open_with_no_init_func() is used only for
row_sel_try_search_shortcut_for_mysql().
btr_cur_search_to_nth_level_func(..., ahi_latch !=0, ...) is invoked
only from btr_pcur_open_with_no_init_func(..., ahi_latch !=0, ...),
which, in turns, is invoked only from
row_sel_try_search_shortcut_for_mysql().

I suppose that separate case with ahi_latch!=0 was intentionally
implemented to protect row_sel_store_mysql_rec() call in
row_search_mvcc() just after row_sel_try_search_shortcut_for_mysql()
call. After the ahi_latch was moved from row_seach_mvcc() to
row_sel_try_search_shortcut_for_mysql(), there is no need in it at all
if btr_search_guess_on_hash() latches a page unconditionally. And if
btr_search_guess_on_hash() latched the page, any access to the record in
row_sel_try_search_shortcut_for_mysql() after btr_pcur_open_with_no_init()
call will be protected with the page latch.

The fix is to remove ahi_latch argument from
btr_pcur_open_with_no_init_func(), btr_cur_search_to_nth_level_func()
and btr_search_guess_on_hash().

There will not be test, as to test it we need to freeze some SELECT
execution in the point between row_sel_try_search_shortcut_for_mysql()
and row_sel_store_mysql_rec() calls in row_search_mvcc(), and to change
the record in some other transaction to let row_sel_store_mysql_rec() to
store changed record in result buffer. Buf we can't do this with the
fix, as the page will be latched in btr_search_guess_on_hash() call.
This commit is contained in:
Vlad Lesin 2022-08-31 17:49:38 +03:00
parent 111cbdf3da
commit c0eda62aec
16 changed files with 160 additions and 267 deletions

View File

@ -876,7 +876,7 @@ btr_page_get_father_node_ptr_func(
err = btr_cur_search_to_nth_level( err = btr_cur_search_to_nth_level(
index, level + 1, tuple, index, level + 1, tuple,
PAGE_CUR_LE, latch_mode, cursor, 0, PAGE_CUR_LE, latch_mode, cursor,
file, line, mtr); file, line, mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -2380,7 +2380,7 @@ btr_insert_on_non_leaf_level_func(
dberr_t err = btr_cur_search_to_nth_level( dberr_t err = btr_cur_search_to_nth_level(
index, level, tuple, PAGE_CUR_LE, index, level, tuple, PAGE_CUR_LE,
BTR_CONT_MODIFY_TREE, BTR_CONT_MODIFY_TREE,
&cursor, 0, file, line, mtr); &cursor, file, line, mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
ib::warn() << " Error code: " << err ib::warn() << " Error code: " << err
@ -2401,7 +2401,7 @@ btr_insert_on_non_leaf_level_func(
btr_cur_search_to_nth_level(index, level, tuple, btr_cur_search_to_nth_level(index, level, tuple,
PAGE_CUR_RTREE_INSERT, PAGE_CUR_RTREE_INSERT,
BTR_CONT_MODIFY_TREE, BTR_CONT_MODIFY_TREE,
&cursor, 0, file, line, mtr); &cursor, file, line, mtr);
} }
ut_ad(cursor.flag == BTR_CUR_BINARY); ut_ad(cursor.flag == BTR_CUR_BINARY);

View File

@ -1102,38 +1102,36 @@ If mode is PAGE_CUR_GE, then up_match will a have a sensible value.
If mode is PAGE_CUR_LE , cursor is left at the place where an insert of the If mode is PAGE_CUR_LE , cursor is left at the place where an insert of the
search tuple should be performed in the B-tree. InnoDB does an insert search tuple should be performed in the B-tree. InnoDB does an insert
immediately after the cursor. Thus, the cursor may end up on a user record, immediately after the cursor. Thus, the cursor may end up on a user record,
or on a page infimum record. */ or on a page infimum record.
dberr_t @param index index
btr_cur_search_to_nth_level_func( @param level the tree level of search
dict_index_t* index, /*!< in: index */ @param tuple data tuple; NOTE: n_fields_cmp in tuple must be set so that
ulint level, /*!< in: the tree level of search */ it cannot get compared to the node ptr page number field!
const dtuple_t* tuple, /*!< in: data tuple; NOTE: n_fields_cmp in @param mode PAGE_CUR_L, NOTE that if the search is made using a unique
tuple must be set so that it cannot get prefix of a record, mode should be PAGE_CUR_LE, not
compared to the node ptr page number field! */ PAGE_CUR_GE, as the latter may end up on the previous page of
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...; the record! Inserts should always be made using PAGE_CUR_LE
Inserts should always be made using to search the position!
PAGE_CUR_LE to search the position! */ @param latch_mode BTR_SEARCH_LEAF, ..., ORed with at most one of BTR_INSERT,
ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ..., ORed with BTR_DELETE_MARK, BTR_DELETE, or BTR_ESTIMATE;
at most one of BTR_INSERT, BTR_DELETE_MARK, cursor->left_block is used to store a pointer to the left
BTR_DELETE, or BTR_ESTIMATE; neighbor page, in the cases BTR_SEARCH_PREV and
cursor->left_block is used to store a pointer BTR_MODIFY_PREV; NOTE that if ahi_latch, we might not have a
to the left neighbor page, in the cases cursor page latch, we assume that ahi_latch protects the
BTR_SEARCH_PREV and BTR_MODIFY_PREV; record!
NOTE that if ahi_latch, we might not have a @param cursor tree cursor; the cursor page is s- or x-latched, but see also
cursor page latch, we assume that ahi_latch above!
protects the record! */ @param file file name
btr_cur_t* cursor, /*!< in/out: tree cursor; the cursor page is @param line line where called
s- or x-latched, but see also above! */ @param mtr mini-transaction
#ifdef BTR_CUR_HASH_ADAPT @param autoinc PAGE_ROOT_AUTO_INC to be written (0 if none)
rw_lock_t* ahi_latch, @return DB_SUCCESS on success or error code otherwise */
/*!< in: currently held btr_search_latch dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
(in RW_S_LATCH mode), or NULL */ const dtuple_t *tuple,
#endif /* BTR_CUR_HASH_ADAPT */ page_cur_mode_t mode, ulint latch_mode,
const char* file, /*!< in: file name */ btr_cur_t *cursor, const char *file,
unsigned line, /*!< in: line where called */ unsigned line, mtr_t *mtr,
mtr_t* mtr, /*!< in: mtr */ ib_uint64_t autoinc)
ib_uint64_t autoinc)/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
{ {
page_t* page = NULL; /* remove warning */ page_t* page = NULL; /* remove warning */
buf_block_t* block; buf_block_t* block;
@ -1301,15 +1299,14 @@ btr_cur_search_to_nth_level_func(
&& mode != PAGE_CUR_LE_OR_EXTENDS && mode != PAGE_CUR_LE_OR_EXTENDS
# endif /* PAGE_CUR_LE_OR_EXTENDS */ # endif /* PAGE_CUR_LE_OR_EXTENDS */
&& !dict_index_is_spatial(index) && !dict_index_is_spatial(index)
/* If !ahi_latch, we do a dirty read of /* We do a dirty read of
btr_search_enabled below, and btr_search_guess_on_hash() btr_search_enabled below, and btr_search_guess_on_hash()
will have to check it again. */ will have to check it again. */
&& btr_search_enabled && btr_search_enabled
&& !modify_external && !modify_external
&& !(tuple->info_bits & REC_INFO_MIN_REC_FLAG) && !(tuple->info_bits & REC_INFO_MIN_REC_FLAG)
&& btr_search_guess_on_hash(index, info, tuple, mode, && btr_search_guess_on_hash(index, info, tuple, mode,
latch_mode, cursor, latch_mode, cursor, mtr)) {
ahi_latch, mtr)) {
/* Search using the hash index succeeded */ /* Search using the hash index succeeded */
@ -1330,13 +1327,6 @@ btr_cur_search_to_nth_level_func(
/* If the hash search did not succeed, do binary search down the /* If the hash search did not succeed, do binary search down the
tree */ tree */
#ifdef BTR_CUR_HASH_ADAPT
if (ahi_latch) {
/* Release possible search latch to obey latching order */
rw_lock_s_unlock(ahi_latch);
}
#endif /* BTR_CUR_HASH_ADAPT */
/* Store the position of the tree latch we push to mtr so that we /* Store the position of the tree latch we push to mtr so that we
know how to release it when we have latched leaf node(s) */ know how to release it when we have latched leaf node(s) */
@ -2397,12 +2387,6 @@ func_exit:
cursor->rtr_info->mbr_adj = true; cursor->rtr_info->mbr_adj = true;
} }
#ifdef BTR_CUR_HASH_ADAPT
if (ahi_latch) {
rw_lock_s_lock(ahi_latch);
}
#endif /* BTR_CUR_HASH_ADAPT */
DBUG_RETURN(err); DBUG_RETURN(err);
} }
@ -6232,8 +6216,7 @@ btr_estimate_n_rows_in_range_low(
btr_cur_search_to_nth_level(index, 0, tuple1, mode1, btr_cur_search_to_nth_level(index, 0, tuple1, mode1,
BTR_SEARCH_LEAF | BTR_ESTIMATE, BTR_SEARCH_LEAF | BTR_ESTIMATE,
&cursor, 0, &cursor, __FILE__, __LINE__, &mtr);
__FILE__, __LINE__, &mtr);
ut_ad(!page_rec_is_infimum(btr_cur_get_rec(&cursor))); ut_ad(!page_rec_is_infimum(btr_cur_get_rec(&cursor)));
@ -6286,8 +6269,7 @@ btr_estimate_n_rows_in_range_low(
btr_cur_search_to_nth_level(index, 0, tuple2, mode2, btr_cur_search_to_nth_level(index, 0, tuple2, mode2,
BTR_SEARCH_LEAF | BTR_ESTIMATE, BTR_SEARCH_LEAF | BTR_ESTIMATE,
&cursor, 0, &cursor, __FILE__, __LINE__, &mtr);
__FILE__, __LINE__, &mtr);
const rec_t* rec = btr_cur_get_rec(&cursor); const rec_t* rec = btr_cur_get_rec(&cursor);

View File

@ -424,11 +424,7 @@ btr_pcur_t::restore_position(ulint restore_latch_mode, const char *file,
} }
btr_pcur_open_with_no_init_func(index, tuple, mode, restore_latch_mode, btr_pcur_open_with_no_init_func(index, tuple, mode, restore_latch_mode,
this, this, file, line, mtr);
#ifdef BTR_CUR_HASH_ADAPT
NULL,
#endif /* BTR_CUR_HASH_ADAPT */
file, line, mtr);
/* Restore the old search mode */ /* Restore the old search mode */
search_mode = old_mode; search_mode = old_mode;

View File

@ -895,8 +895,6 @@ both have sensible values.
we assume the caller uses his search latch we assume the caller uses his search latch
to protect the record! to protect the record!
@param[out] cursor tree cursor @param[out] cursor tree cursor
@param[in] ahi_latch the adaptive hash index latch being held,
or NULL
@param[in] mtr mini transaction @param[in] mtr mini transaction
@return whether the search succeeded */ @return whether the search succeeded */
bool bool
@ -907,7 +905,6 @@ btr_search_guess_on_hash(
ulint mode, ulint mode,
ulint latch_mode, ulint latch_mode,
btr_cur_t* cursor, btr_cur_t* cursor,
rw_lock_t* ahi_latch,
mtr_t* mtr) mtr_t* mtr)
{ {
ulint fold; ulint fold;
@ -916,8 +913,6 @@ btr_search_guess_on_hash(
btr_cur_t cursor2; btr_cur_t cursor2;
btr_pcur_t pcur; btr_pcur_t pcur;
#endif #endif
ut_ad(!ahi_latch || rw_lock_own_flagged(
ahi_latch, RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
if (!btr_search_enabled) { if (!btr_search_enabled) {
return false; return false;
@ -925,7 +920,6 @@ btr_search_guess_on_hash(
ut_ad(index && info && tuple && cursor && mtr); ut_ad(index && info && tuple && cursor && mtr);
ut_ad(!dict_index_is_ibuf(index)); ut_ad(!dict_index_is_ibuf(index));
ut_ad(!ahi_latch || ahi_latch == btr_get_search_latch(index));
ut_ad((latch_mode == BTR_SEARCH_LEAF) ut_ad((latch_mode == BTR_SEARCH_LEAF)
|| (latch_mode == BTR_MODIFY_LEAF)); || (latch_mode == BTR_MODIFY_LEAF));
@ -956,28 +950,21 @@ btr_search_guess_on_hash(
cursor->fold = fold; cursor->fold = fold;
cursor->flag = BTR_CUR_HASH; cursor->flag = BTR_CUR_HASH;
rw_lock_t* use_latch = ahi_latch ? NULL : btr_get_search_latch(index); rw_lock_t* ahi_latch = btr_get_search_latch(index);
const rec_t* rec; const rec_t* rec;
if (use_latch) { rw_lock_s_lock(ahi_latch);
rw_lock_s_lock(use_latch);
if (!btr_search_enabled) { if (!btr_search_enabled) {
goto fail; goto fail;
}
} else {
ut_ad(btr_search_enabled);
ut_ad(rw_lock_own(ahi_latch, RW_LOCK_S));
} }
rec = static_cast<const rec_t*>( rec = static_cast<const rec_t*>(
ha_search_and_get_data(btr_get_search_table(index), fold)); ha_search_and_get_data(btr_get_search_table(index), fold));
if (!rec) { if (!rec) {
if (use_latch) {
fail: fail:
rw_lock_s_unlock(use_latch); rw_lock_s_unlock(ahi_latch);
}
btr_search_failure(info, cursor); btr_search_failure(info, cursor);
return false; return false;
@ -985,25 +972,19 @@ fail:
buf_block_t* block = buf_block_from_ahi(rec); buf_block_t* block = buf_block_from_ahi(rec);
if (use_latch) { if (!buf_page_get_known_nowait(latch_mode, block, BUF_MAKE_YOUNG,
if (!buf_page_get_known_nowait( __FILE__, __LINE__, mtr)) {
latch_mode, block, BUF_MAKE_YOUNG, goto fail;
__FILE__, __LINE__, mtr)) { }
goto fail;
}
const bool fail = index != block->index const bool fail = index != block->index
&& index_id == block->index->id; && index_id == block->index->id;
ut_a(!fail || block->index->freed()); ut_a(!fail || block->index->freed());
rw_lock_s_unlock(use_latch); ut_ad(fail || !block->page.file_page_was_freed);
rw_lock_s_unlock(ahi_latch);
buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH); buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
if (UNIV_UNLIKELY(fail)) { if (UNIV_UNLIKELY(fail)) {
goto fail_and_release_page;
}
} else if (UNIV_UNLIKELY(index != block->index
&& index_id == block->index->id)) {
ut_a(block->index->freed());
goto fail_and_release_page; goto fail_and_release_page;
} }
@ -1012,9 +993,7 @@ fail:
ut_ad(buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH); ut_ad(buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH);
fail_and_release_page: fail_and_release_page:
if (!ahi_latch) { btr_leaf_page_release(block, latch_mode, mtr);
btr_leaf_page_release(block, latch_mode, mtr);
}
btr_search_failure(info, cursor); btr_search_failure(info, cursor);
return false; return false;
@ -1032,7 +1011,7 @@ fail_and_release_page:
record to determine if our guess for the cursor position is record to determine if our guess for the cursor position is
right. */ right. */
if (index_id != btr_page_get_index_id(block->frame) if (index_id != btr_page_get_index_id(block->frame)
|| !btr_search_check_guess(cursor, !!ahi_latch, tuple, mode)) { || !btr_search_check_guess(cursor, 0, tuple, mode)) {
goto fail_and_release_page; goto fail_and_release_page;
} }
@ -1081,7 +1060,7 @@ fail_and_release_page:
#ifdef UNIV_SEARCH_PERF_STAT #ifdef UNIV_SEARCH_PERF_STAT
btr_search_n_succ++; btr_search_n_succ++;
#endif #endif
if (!ahi_latch && buf_page_peek_if_too_old(&block->page)) { if (buf_page_peek_if_too_old(&block->page)) {
buf_page_make_young(&block->page); buf_page_make_young(&block->page);
} }

View File

@ -4815,6 +4815,10 @@ buf_page_get_known_nowait(
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
/* The check for the page was not freed would already have been
performed when the block descriptor was acquired by the thread for the
first time.*/
buf_block_buf_fix_inc(block, file, line); buf_block_buf_fix_inc(block, file, line);
buf_page_set_accessed(&block->page); buf_page_set_accessed(&block->page);
@ -4861,24 +4865,6 @@ buf_page_get_known_nowait(
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
#ifdef UNIV_DEBUG
if (mode != BUF_KEEP_OLD) {
/* If mode == BUF_KEEP_OLD, we are executing an I/O
completion routine. Avoid a bogus assertion failure
when ibuf_merge_or_delete_for_page() is processing a
page that was just freed due to DROP INDEX, or
deleting a record from SYS_INDEXES. This check will be
skipped in recv_recover_page() as well. */
# ifdef BTR_CUR_HASH_ADAPT
ut_ad(!block->page.file_page_was_freed
|| btr_search_check_marked_free_index(block));
# else /* BTR_CUR_HASH_ADAPT */
ut_ad(!block->page.file_page_was_freed);
# endif /* BTR_CUR_HASH_ADAPT */
}
#endif /* UNIV_DEBUG */
buf_pool->stat.n_page_gets++; buf_pool->stat.n_page_gets++;
return(TRUE); return(TRUE);

View File

@ -5435,7 +5435,7 @@ dict_set_corrupted(
btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_LE, btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_LE,
BTR_MODIFY_LEAF, BTR_MODIFY_LEAF,
&cursor, 0, __FILE__, __LINE__, &mtr); &cursor, __FILE__, __LINE__, &mtr);
if (cursor.low_match == dtuple_get_n_fields(tuple)) { if (cursor.low_match == dtuple_get_n_fields(tuple)) {
/* UPDATE SYS_INDEXES SET TYPE=index->type /* UPDATE SYS_INDEXES SET TYPE=index->type
@ -5538,7 +5538,7 @@ dict_index_set_merge_threshold(
btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE, btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE,
BTR_MODIFY_LEAF, BTR_MODIFY_LEAF,
&cursor, 0, __FILE__, __LINE__, &mtr); &cursor, __FILE__, __LINE__, &mtr);
if (cursor.up_match == dtuple_get_n_fields(tuple) if (cursor.up_match == dtuple_get_n_fields(tuple)
&& rec_get_n_fields_old(btr_cur_get_rec(&cursor)) && rec_get_n_fields_old(btr_cur_get_rec(&cursor))

View File

@ -3437,7 +3437,7 @@ fts_add_doc_by_id(
btr_pcur_open_with_no_init( btr_pcur_open_with_no_init(
fts_id_index, tuple, PAGE_CUR_LE, BTR_SEARCH_LEAF, fts_id_index, tuple, PAGE_CUR_LE, BTR_SEARCH_LEAF,
&pcur, 0, &mtr); &pcur, &mtr);
/* If we have a match, add the data to doc structure */ /* If we have a match, add the data to doc structure */
if (btr_pcur_get_low_match(&pcur) == 1) { if (btr_pcur_get_low_match(&pcur) == 1) {
@ -3475,7 +3475,7 @@ fts_add_doc_by_id(
btr_pcur_open_with_no_init( btr_pcur_open_with_no_init(
clust_index, clust_ref, PAGE_CUR_LE, clust_index, clust_ref, PAGE_CUR_LE,
BTR_SEARCH_LEAF, &clust_pcur, 0, &mtr); BTR_SEARCH_LEAF, &clust_pcur, &mtr);
doc_pcur = &clust_pcur; doc_pcur = &clust_pcur;
clust_rec = btr_pcur_get_rec(&clust_pcur); clust_rec = btr_pcur_get_rec(&clust_pcur);

View File

@ -588,7 +588,7 @@ rtr_pcur_open_low(
} }
btr_cur_search_to_nth_level(index, level, tuple, mode, latch_mode, btr_cur_search_to_nth_level(index, level, tuple, mode, latch_mode,
btr_cursor, 0, file, line, mtr); btr_cursor, file, line, mtr);
cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->pos_state = BTR_PCUR_IS_POSITIONED;
cursor->trx_if_known = NULL; cursor->trx_if_known = NULL;
@ -756,8 +756,7 @@ static void rtr_get_father_node(
/* root split, and search the new root */ /* root split, and search the new root */
btr_cur_search_to_nth_level( btr_cur_search_to_nth_level(
index, level, tuple, PAGE_CUR_RTREE_LOCATE, index, level, tuple, PAGE_CUR_RTREE_LOCATE,
BTR_CONT_MODIFY_TREE, btr_cur, 0, BTR_CONT_MODIFY_TREE, btr_cur, __FILE__, __LINE__, mtr);
__FILE__, __LINE__, mtr);
} else { } else {
/* btr_validate */ /* btr_validate */
@ -766,8 +765,7 @@ static void rtr_get_father_node(
btr_cur_search_to_nth_level( btr_cur_search_to_nth_level(
index, level, tuple, PAGE_CUR_RTREE_LOCATE, index, level, tuple, PAGE_CUR_RTREE_LOCATE,
BTR_CONT_MODIFY_TREE, btr_cur, 0, BTR_CONT_MODIFY_TREE, btr_cur, __FILE__, __LINE__, mtr);
__FILE__, __LINE__, mtr);
rec = btr_cur_get_rec(btr_cur); rec = btr_cur_get_rec(btr_cur);
n_fields = dtuple_get_n_fields_cmp(tuple); n_fields = dtuple_get_n_fields_cmp(tuple);

View File

@ -170,56 +170,41 @@ btr_cur_optimistic_latch_leaves(
unsigned line, unsigned line,
mtr_t* mtr); mtr_t* mtr);
/********************************************************************//** /** Searches an index tree and positions a tree cursor on a given level.
Searches an index tree and positions a tree cursor on a given level.
NOTE: n_fields_cmp in tuple must be set so that it cannot be compared NOTE: n_fields_cmp in tuple must be set so that it cannot be compared
to node pointer page number fields on the upper levels of the tree! to node pointer page number fields on the upper levels of the tree!
Note that if mode is PAGE_CUR_LE, which is used in inserts, then Note that if mode is PAGE_CUR_LE, which is used in inserts, then
cursor->up_match and cursor->low_match both will have sensible values. cursor->up_match and cursor->low_match both will have sensible values.
If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */ If mode is PAGE_CUR_GE, then up_match will a have a sensible value.
dberr_t @param index index
btr_cur_search_to_nth_level_func( @param level the tree level of search
dict_index_t* index, /*!< in: index */ @param tuple data tuple; NOTE: n_fields_cmp in tuple must be set so that
ulint level, /*!< in: the tree level of search */ it cannot get compared to the node ptr page number field!
const dtuple_t* tuple, /*!< in: data tuple; NOTE: n_fields_cmp in @param mode PAGE_CUR_L, NOTE that if the search is made using a unique
tuple must be set so that it cannot get prefix of a record, mode should be PAGE_CUR_LE, not
compared to the node ptr page number field! */ PAGE_CUR_GE, as the latter may end up on the previous page of
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...; the record! Inserts should always be made using PAGE_CUR_LE
NOTE that if the search is made using a unique to search the position!
prefix of a record, mode should be PAGE_CUR_LE, @param latch_mode BTR_SEARCH_LEAF, ..., ORed with at most one of BTR_INSERT,
not PAGE_CUR_GE, as the latter may end up on BTR_DELETE_MARK, BTR_DELETE, or BTR_ESTIMATE;
the previous page of the record! Inserts cursor->left_block is used to store a pointer to the left
should always be made using PAGE_CUR_LE to neighbor page, in the cases BTR_SEARCH_PREV and
search the position! */ BTR_MODIFY_PREV; NOTE that if ahi_latch, we might not have a
ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ..., ORed with cursor page latch, we assume that ahi_latch protects the
at most one of BTR_INSERT, BTR_DELETE_MARK, record!
BTR_DELETE, or BTR_ESTIMATE; @param cursor tree cursor; the cursor page is s- or x-latched, but see also
cursor->left_block is used to store a pointer above!
to the left neighbor page, in the cases @param file file name
BTR_SEARCH_PREV and BTR_MODIFY_PREV; @param line line where called
NOTE that if ahi_latch, we might not have a @param mtr mini-transaction
cursor page latch, we assume that ahi_latch @param autoinc PAGE_ROOT_AUTO_INC to be written (0 if none)
protects the record! */ @return DB_SUCCESS on success or error code otherwise */
btr_cur_t* cursor, /*!< in/out: tree cursor; the cursor page is dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
s- or x-latched, but see also above! */ const dtuple_t *tuple,
#ifdef BTR_CUR_HASH_ADAPT page_cur_mode_t mode, ulint latch_mode,
rw_lock_t* ahi_latch, btr_cur_t *cursor, const char *file,
/*!< in: currently held btr_search_latch unsigned line, mtr_t *mtr,
(in RW_S_LATCH mode), or NULL */ ib_uint64_t autoinc= 0);
#endif /* BTR_CUR_HASH_ADAPT */
const char* file, /*!< in: file name */
unsigned line, /*!< in: line where called */
mtr_t* mtr, /*!< in/out: mini-transaction */
ib_uint64_t autoinc = 0);
/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
#ifdef BTR_CUR_HASH_ADAPT
# define btr_cur_search_to_nth_level(i,l,t,m,lm,c,a,fi,li,mtr) \
btr_cur_search_to_nth_level_func(i,l,t,m,lm,c,a,fi,li,mtr)
#else /* BTR_CUR_HASH_ADAPT */
# define btr_cur_search_to_nth_level(i,l,t,m,lm,c,a,fi,li,mtr) \
btr_cur_search_to_nth_level_func(i,l,t,m,lm,c,fi,li,mtr)
#endif /* BTR_CUR_HASH_ADAPT */
/*****************************************************************//** /*****************************************************************//**
Opens a cursor at either end of an index. Opens a cursor at either end of an index.

View File

@ -116,41 +116,30 @@ btr_pcur_open_low(
mtr_t* mtr); /*!< in: mtr */ mtr_t* mtr); /*!< in: mtr */
#define btr_pcur_open(i,t,md,l,c,m) \ #define btr_pcur_open(i,t,md,l,c,m) \
btr_pcur_open_low(i,0,t,md,l,c,__FILE__,__LINE__,0,m) btr_pcur_open_low(i,0,t,md,l,c,__FILE__,__LINE__,0,m)
/**************************************************************//** /** Opens an persistent cursor to an index tree without initializing the
Opens an persistent cursor to an index tree without initializing the cursor.
cursor. */ @param index index
@param tuple tuple on which search done
@param mode PAGE_CUR_L, ...; NOTE that if the search is made using a
unique prefix of a record, mode should be PAGE_CUR_LE, not
PAGE_CUR_GE, as the latter may end up on the previous page of
the record!
@param latch_mode BTR_SEARCH_LEAF, ...; NOTE that if ahi_latch then we might
not acquire a cursor page latch, but assume that the
ahi_latch protects the record!
@param cursor memory buffer for persistent cursor
@param file file name
@param line line where called
@param mtr mtr
@return DB_SUCCESS on success or error code otherwise. */
UNIV_INLINE UNIV_INLINE
dberr_t dberr_t btr_pcur_open_with_no_init_func(dict_index_t *index,
btr_pcur_open_with_no_init_func( const dtuple_t *tuple,
/*============================*/ page_cur_mode_t mode, ulint latch_mode,
dict_index_t* index, /*!< in: index */ btr_pcur_t *cursor, const char *file,
const dtuple_t* tuple, /*!< in: tuple on which search done */ unsigned line, mtr_t *mtr);
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...; # define btr_pcur_open_with_no_init(ix,t,md,l,cur,m) \
NOTE that if the search is made using a unique
prefix of a record, mode should be
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
may end up on the previous page of the
record! */
ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ...;
NOTE that if ahi_latch then we might not
acquire a cursor page latch, but assume
that the ahi_latch protects the record! */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
#ifdef BTR_CUR_HASH_ADAPT
rw_lock_t* ahi_latch,
/*!< in: adaptive hash index latch held
by the caller, or NULL if none */
#endif /* BTR_CUR_HASH_ADAPT */
const char* file, /*!< in: file name */
unsigned line, /*!< in: line where called */
mtr_t* mtr); /*!< in: mtr */
#ifdef BTR_CUR_HASH_ADAPT
# define btr_pcur_open_with_no_init(ix,t,md,l,cur,ahi,m) \
btr_pcur_open_with_no_init_func(ix,t,md,l,cur,ahi,__FILE__,__LINE__,m)
#else /* BTR_CUR_HASH_ADAPT */
# define btr_pcur_open_with_no_init(ix,t,md,l,cur,ahi,m) \
btr_pcur_open_with_no_init_func(ix,t,md,l,cur,__FILE__,__LINE__,m) btr_pcur_open_with_no_init_func(ix,t,md,l,cur,__FILE__,__LINE__,m)
#endif /* BTR_CUR_HASH_ADAPT */
/*****************************************************************//** /*****************************************************************//**
Opens a persistent cursor at either end of an index. */ Opens a persistent cursor at either end of an index. */

View File

@ -438,11 +438,8 @@ btr_pcur_open_low(
ut_ad(!dict_index_is_spatial(index)); ut_ad(!dict_index_is_spatial(index));
err = btr_cur_search_to_nth_level_func( err = btr_cur_search_to_nth_level(
index, level, tuple, mode, latch_mode, btr_cursor, index, level, tuple, mode, latch_mode, btr_cursor,
#ifdef BTR_CUR_HASH_ADAPT
NULL,
#endif /* BTR_CUR_HASH_ADAPT */
file, line, mtr, autoinc); file, line, mtr, autoinc);
if (UNIV_UNLIKELY(err != DB_SUCCESS)) { if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
@ -462,34 +459,28 @@ btr_pcur_open_low(
return(err); return(err);
} }
/**************************************************************//** /** Opens an persistent cursor to an index tree without initializing the
Opens an persistent cursor to an index tree without initializing the cursor.
cursor. */ @param index index
@param tuple tuple on which search done
@param mode PAGE_CUR_L, ...; NOTE that if the search is made using a
unique prefix of a record, mode should be PAGE_CUR_LE, not
PAGE_CUR_GE, as the latter may end up on the previous page of
the record!
@param latch_mode BTR_SEARCH_LEAF, ...; NOTE that if ahi_latch then we might
not acquire a cursor page latch, but assume that the
ahi_latch protects the record!
@param cursor memory buffer for persistent cursor
@param file file name
@param line line where called
@param mtr mtr
@return DB_SUCCESS on success or error code otherwise. */
UNIV_INLINE UNIV_INLINE
dberr_t dberr_t btr_pcur_open_with_no_init_func(dict_index_t *index,
btr_pcur_open_with_no_init_func( const dtuple_t *tuple,
/*============================*/ page_cur_mode_t mode, ulint latch_mode,
dict_index_t* index, /*!< in: index */ btr_pcur_t *cursor, const char *file,
const dtuple_t* tuple, /*!< in: tuple on which search done */ unsigned line, mtr_t *mtr)
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...;
NOTE that if the search is made using a unique
prefix of a record, mode should be
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
may end up on the previous page of the
record! */
ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ...;
NOTE that if ahi_latch then we might not
acquire a cursor page latch, but assume
that the ahi_latch protects the record! */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
#ifdef BTR_CUR_HASH_ADAPT
rw_lock_t* ahi_latch,
/*!< in: adaptive hash index latch held
by the caller, or NULL if none */
#endif /* BTR_CUR_HASH_ADAPT */
const char* file, /*!< in: file name */
unsigned line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mtr */
{ {
btr_cur_t* btr_cursor; btr_cur_t* btr_cursor;
dberr_t err = DB_SUCCESS; dberr_t err = DB_SUCCESS;
@ -501,11 +492,8 @@ btr_pcur_open_with_no_init_func(
btr_cursor = btr_pcur_get_btr_cur(cursor); btr_cursor = btr_pcur_get_btr_cur(cursor);
err = btr_cur_search_to_nth_level_func( err = btr_cur_search_to_nth_level(
index, 0, tuple, mode, latch_mode, btr_cursor, index, 0, tuple, mode, latch_mode, btr_cursor,
#ifdef BTR_CUR_HASH_ADAPT
ahi_latch,
#endif /* BTR_CUR_HASH_ADAPT */
file, line, mtr); file, line, mtr);
cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->pos_state = BTR_PCUR_IS_POSITIONED;

View File

@ -80,7 +80,6 @@ btr_search_guess_on_hash(
ulint mode, ulint mode,
ulint latch_mode, ulint latch_mode,
btr_cur_t* cursor, btr_cur_t* cursor,
rw_lock_t* ahi_latch,
mtr_t* mtr); mtr_t* mtr);
/** Move or delete hash entries for moved records, usually in a page split. /** Move or delete hash entries for moved records, usually in a page split.

View File

@ -1137,7 +1137,7 @@ row_ins_foreign_check_on_constraint(
tmp_heap); tmp_heap);
btr_pcur_open_with_no_init(clust_index, ref, btr_pcur_open_with_no_init(clust_index, ref,
PAGE_CUR_LE, BTR_SEARCH_LEAF, PAGE_CUR_LE, BTR_SEARCH_LEAF,
cascade->pcur, 0, mtr); cascade->pcur, mtr);
clust_rec = btr_pcur_get_rec(cascade->pcur); clust_rec = btr_pcur_get_rec(cascade->pcur);
clust_block = btr_pcur_get_block(cascade->pcur); clust_block = btr_pcur_get_block(cascade->pcur);
@ -2958,7 +2958,7 @@ row_ins_sec_index_entry_low(
err = btr_cur_search_to_nth_level( err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_RTREE_INSERT, index, 0, entry, PAGE_CUR_RTREE_INSERT,
search_mode, search_mode,
&cursor, 0, __FILE__, __LINE__, &mtr); &cursor, __FILE__, __LINE__, &mtr);
if (mode == BTR_MODIFY_LEAF && rtr_info.mbr_adj) { if (mode == BTR_MODIFY_LEAF && rtr_info.mbr_adj) {
mtr_commit(&mtr); mtr_commit(&mtr);
@ -2977,7 +2977,7 @@ row_ins_sec_index_entry_low(
err = btr_cur_search_to_nth_level( err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_RTREE_INSERT, index, 0, entry, PAGE_CUR_RTREE_INSERT,
search_mode, search_mode,
&cursor, 0, __FILE__, __LINE__, &mtr); &cursor, __FILE__, __LINE__, &mtr);
mode = BTR_MODIFY_TREE; mode = BTR_MODIFY_TREE;
} }
@ -2989,7 +2989,7 @@ row_ins_sec_index_entry_low(
err = btr_cur_search_to_nth_level( err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_LE, index, 0, entry, PAGE_CUR_LE,
search_mode, search_mode,
&cursor, 0, __FILE__, __LINE__, &mtr); &cursor, __FILE__, __LINE__, &mtr);
} }
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -3083,7 +3083,7 @@ row_ins_sec_index_entry_low(
index, 0, entry, PAGE_CUR_LE, index, 0, entry, PAGE_CUR_LE,
(search_mode (search_mode
& ~(BTR_INSERT | BTR_IGNORE_SEC_UNIQUE)), & ~(BTR_INSERT | BTR_IGNORE_SEC_UNIQUE)),
&cursor, 0, __FILE__, __LINE__, &mtr); &cursor, __FILE__, __LINE__, &mtr);
} }
if (row_ins_must_modify_rec(&cursor)) { if (row_ins_must_modify_rec(&cursor)) {

View File

@ -3354,7 +3354,7 @@ row_log_apply_op_low(
has_index_lock has_index_lock
? BTR_MODIFY_TREE ? BTR_MODIFY_TREE
: BTR_MODIFY_LEAF, : BTR_MODIFY_LEAF,
&cursor, 0, __FILE__, __LINE__, &cursor, __FILE__, __LINE__,
&mtr); &mtr);
ut_ad(dict_index_get_n_unique(index) > 0); ut_ad(dict_index_get_n_unique(index) > 0);
@ -3403,7 +3403,7 @@ row_log_apply_op_low(
index->set_modified(mtr); index->set_modified(mtr);
btr_cur_search_to_nth_level( btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_LE, index, 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, 0, BTR_MODIFY_TREE, &cursor,
__FILE__, __LINE__, &mtr); __FILE__, __LINE__, &mtr);
/* No other thread than the current one /* No other thread than the current one
@ -3506,7 +3506,7 @@ insert_the_rec:
index->set_modified(mtr); index->set_modified(mtr);
btr_cur_search_to_nth_level( btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_LE, index, 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, 0, BTR_MODIFY_TREE, &cursor,
__FILE__, __LINE__, &mtr); __FILE__, __LINE__, &mtr);
} }

View File

@ -163,7 +163,7 @@ public:
btr_cur_search_to_nth_level(m_index, 0, dtuple, btr_cur_search_to_nth_level(m_index, 0, dtuple,
PAGE_CUR_RTREE_INSERT, PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_LEAF, &ins_cur, BTR_MODIFY_LEAF, &ins_cur,
0, __FILE__, __LINE__, __FILE__, __LINE__,
&mtr); &mtr);
/* It need to update MBR in parent entry, /* It need to update MBR in parent entry,
@ -179,7 +179,7 @@ public:
btr_cur_search_to_nth_level( btr_cur_search_to_nth_level(
m_index, 0, dtuple, m_index, 0, dtuple,
PAGE_CUR_RTREE_INSERT, PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_TREE, &ins_cur, 0, BTR_MODIFY_TREE, &ins_cur,
__FILE__, __LINE__, &mtr); __FILE__, __LINE__, &mtr);
} }
@ -202,8 +202,7 @@ public:
m_index, 0, dtuple, m_index, 0, dtuple,
PAGE_CUR_RTREE_INSERT, PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_TREE, BTR_MODIFY_TREE,
&ins_cur, 0, &ins_cur, __FILE__, __LINE__, &mtr);
__FILE__, __LINE__, &mtr);
error = btr_cur_pessimistic_insert( error = btr_cur_pessimistic_insert(
flag, &ins_cur, &ins_offsets, flag, &ins_cur, &ins_offsets,

View File

@ -985,8 +985,7 @@ row_sel_get_clust_rec(
index = dict_table_get_first_index(plan->table); index = dict_table_get_first_index(plan->table);
btr_pcur_open_with_no_init(index, plan->clust_ref, PAGE_CUR_LE, btr_pcur_open_with_no_init(index, plan->clust_ref, PAGE_CUR_LE,
BTR_SEARCH_LEAF, &plan->clust_pcur, BTR_SEARCH_LEAF, &plan->clust_pcur, mtr);
0, mtr);
clust_rec = btr_pcur_get_rec(&(plan->clust_pcur)); clust_rec = btr_pcur_get_rec(&(plan->clust_pcur));
@ -1394,8 +1393,7 @@ row_sel_open_pcur(
/* Open pcur to the index */ /* Open pcur to the index */
btr_pcur_open_with_no_init(index, plan->tuple, plan->mode, btr_pcur_open_with_no_init(index, plan->tuple, plan->mode,
BTR_SEARCH_LEAF, &plan->pcur, BTR_SEARCH_LEAF, &plan->pcur, mtr);
NULL, mtr);
} else { } else {
/* Open the cursor to the start or the end of the index /* Open the cursor to the start or the end of the index
(FALSE: no init) */ (FALSE: no init) */
@ -3369,7 +3367,7 @@ Row_sel_get_clust_rec_for_mysql::operator()(
btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref, btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref,
PAGE_CUR_LE, BTR_SEARCH_LEAF, PAGE_CUR_LE, BTR_SEARCH_LEAF,
prebuilt->clust_pcur, 0, mtr); prebuilt->clust_pcur, mtr);
clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur); clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur);
@ -3952,15 +3950,12 @@ row_sel_try_search_shortcut_for_mysql(
ut_ad(dict_index_is_clust(index)); ut_ad(dict_index_is_clust(index));
ut_ad(!prebuilt->templ_contains_blob); ut_ad(!prebuilt->templ_contains_blob);
rw_lock_t* ahi_latch = btr_get_search_latch(index);
rw_lock_s_lock(ahi_latch);
btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE, btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, pcur, ahi_latch, mtr); BTR_SEARCH_LEAF, pcur, mtr);
rec = btr_pcur_get_rec(pcur); rec = btr_pcur_get_rec(pcur);
if (!page_rec_is_user_rec(rec) || rec_is_metadata(rec, index)) { if (!page_rec_is_user_rec(rec) || rec_is_metadata(rec, index)) {
retry: retry:
rw_lock_s_unlock(ahi_latch);
return(SEL_RETRY); return(SEL_RETRY);
} }
@ -3970,7 +3965,6 @@ retry:
if (btr_pcur_get_up_match(pcur) < dtuple_get_n_fields(search_tuple)) { if (btr_pcur_get_up_match(pcur) < dtuple_get_n_fields(search_tuple)) {
exhausted: exhausted:
rw_lock_s_unlock(ahi_latch);
return(SEL_EXHAUSTED); return(SEL_EXHAUSTED);
} }
@ -3994,7 +3988,6 @@ exhausted:
*out_rec = rec; *out_rec = rec;
rw_lock_s_unlock(ahi_latch);
return(SEL_FOUND); return(SEL_FOUND);
} }
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
@ -4728,8 +4721,7 @@ wait_table_again:
} }
err = btr_pcur_open_with_no_init(index, search_tuple, mode, err = btr_pcur_open_with_no_init(index, search_tuple, mode,
BTR_SEARCH_LEAF, BTR_SEARCH_LEAF, pcur, &mtr);
pcur, 0, &mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
rec = NULL; rec = NULL;