summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase')
-rw-r--r--storage/innobase/btr/btr0btr.cc22
-rw-r--r--storage/innobase/btr/btr0cur.cc21
-rw-r--r--storage/innobase/btr/btr0pcur.cc9
-rw-r--r--storage/innobase/btr/btr0sea.cc364
-rw-r--r--storage/innobase/buf/buf0buf.cc89
-rw-r--r--storage/innobase/buf/buf0lru.cc160
-rw-r--r--storage/innobase/dict/dict0crea.cc9
-rw-r--r--storage/innobase/dict/dict0dict.cc141
-rw-r--r--storage/innobase/dict/dict0mem.cc7
-rw-r--r--storage/innobase/dict/dict0stats.cc9
-rw-r--r--storage/innobase/fsp/fsp0fsp.cc102
-rw-r--r--storage/innobase/gis/gis0sea.cc6
-rw-r--r--storage/innobase/handler/handler0alter.cc16
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc2
-rw-r--r--storage/innobase/include/btr0cur.h13
-rw-r--r--storage/innobase/include/btr0pcur.h11
-rw-r--r--storage/innobase/include/btr0pcur.ic6
-rw-r--r--storage/innobase/include/btr0sea.h51
-rw-r--r--storage/innobase/include/btr0sea.ic41
-rw-r--r--storage/innobase/include/buf0buf.h10
-rw-r--r--storage/innobase/include/buf0lru.h11
-rw-r--r--storage/innobase/include/dict0mem.h24
-rw-r--r--storage/innobase/include/fsp0fsp.h47
-rw-r--r--storage/innobase/row/row0import.cc14
-rw-r--r--storage/innobase/row/row0ins.cc8
-rw-r--r--storage/innobase/row/row0log.cc6
-rw-r--r--storage/innobase/row/row0merge.cc13
-rw-r--r--storage/innobase/row/row0mysql.cc32
-rw-r--r--storage/innobase/row/row0sel.cc92
-rw-r--r--storage/innobase/row/row0trunc.cc13
-rw-r--r--storage/innobase/trx/trx0purge.cc6
-rw-r--r--storage/innobase/trx/trx0undo.cc4
32 files changed, 552 insertions, 807 deletions
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 2049bbd26fa..5f38e623985 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -2,7 +2,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2014, 2019, MariaDB Corporation.
+Copyright (c) 2014, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -723,8 +723,10 @@ void btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
{
ut_ad(mtr_is_block_fix(mtr, block, MTR_MEMO_PAGE_X_FIX, index->table));
#ifdef BTR_CUR_HASH_ADAPT
- ut_ad(!block->index || !blob);
- ut_ad(!block->index || page_is_leaf(block->frame));
+ if (block->index && !block->index->freed()) {
+ ut_ad(!blob);
+ ut_ad(page_is_leaf(block->frame));
+ }
#endif
ut_ad(index->space == block->page.id.space());
/* The root page is freed by btr_free_root(). */
@@ -751,7 +753,7 @@ void btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
fseg_free_page(seg_header,
block->page.id.space(),
block->page.id.page_no(),
- block->index != NULL, mtr);
+ mtr);
/* The page was marked free in the allocation bitmap, but it
should remain exclusively latched until mtr_t::commit() or until it
@@ -876,7 +878,7 @@ btr_page_get_father_node_ptr_func(
err = btr_cur_search_to_nth_level(
index, level + 1, tuple,
PAGE_CUR_LE, latch_mode, cursor, 0,
- file, line, mtr);
+ file, line, mtr, 0);
if (err != DB_SUCCESS) {
ib::warn() << " Error code: " << err
@@ -1005,7 +1007,7 @@ static void btr_free_root(buf_block_t* block, mtr_t* mtr, bool invalidate)
BTR_FREED_INDEX_ID, mtr);
}
- while (!fseg_free_step(header, true, mtr)) {
+ while (!fseg_free_step(header, mtr)) {
/* Free the entire segment in small steps. */
}
}
@@ -1254,7 +1256,7 @@ leaf_loop:
fsp0fsp. */
finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_LEAF,
- true, &mtr);
+ &mtr);
mtr_commit(&mtr);
if (!finished) {
@@ -1274,7 +1276,7 @@ top_loop:
#endif /* UNIV_BTR_DEBUG */
finished = fseg_free_step_not_header(
- root + PAGE_HEADER + PAGE_BTR_SEG_TOP, true, &mtr);
+ root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
mtr_commit(&mtr);
if (!finished) {
@@ -2342,7 +2344,7 @@ btr_insert_on_non_leaf_level_func(
dberr_t err = btr_cur_search_to_nth_level(
index, level, tuple, PAGE_CUR_LE,
BTR_CONT_MODIFY_TREE,
- &cursor, 0, file, line, mtr);
+ &cursor, 0, file, line, mtr, 0);
if (err != DB_SUCCESS) {
ib::warn() << " Error code: " << err
@@ -2363,7 +2365,7 @@ btr_insert_on_non_leaf_level_func(
btr_cur_search_to_nth_level(index, level, tuple,
PAGE_CUR_RTREE_INSERT,
BTR_CONT_MODIFY_TREE,
- &cursor, 0, file, line, mtr);
+ &cursor, 0, file, line, mtr, 0);
}
ut_ad(cursor.flag == BTR_CUR_BINARY);
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index 2bf657f037f..37ba133cb0f 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -864,8 +864,7 @@ 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,
or on a page infimum record. */
dberr_t
-btr_cur_search_to_nth_level(
-/*========================*/
+btr_cur_search_to_nth_level_func(
dict_index_t* index, /*!< in: index */
ulint level, /*!< in: the tree level of search */
const dtuple_t* tuple, /*!< in: data tuple; NOTE: n_fields_cmp in
@@ -887,10 +886,12 @@ btr_cur_search_to_nth_level(
to protect the record! */
btr_cur_t* cursor, /*!< in/out: tree cursor; the cursor page is
s- or x-latched, but see also above! */
+#ifdef BTR_CUR_HASH_ADAPT
ulint has_search_latch,
/*!< in: info on the latch mode the
caller currently has on search system:
RW_S_LATCH, or 0 */
+#endif /* BTR_CUR_HASH_ADAPT */
const char* file, /*!< in: file name */
unsigned line, /*!< in: line where called */
mtr_t* mtr, /*!< in: mtr */
@@ -1053,6 +1054,7 @@ btr_cur_search_to_nth_level(
}
#ifdef BTR_CUR_HASH_ADAPT
+ rw_lock_t* const search_latch = btr_get_search_latch(index);
# ifdef UNIV_SEARCH_PERF_STAT
info->n_searches++;
@@ -1073,8 +1075,7 @@ btr_cur_search_to_nth_level(
will have to check it again. */
&& btr_search_enabled
&& !modify_external
- && rw_lock_get_writer(btr_get_search_latch(index))
- == RW_LOCK_NOT_LOCKED
+ && rw_lock_get_writer(search_latch) == RW_LOCK_NOT_LOCKED
&& btr_search_guess_on_hash(index, info, tuple, mode,
latch_mode, cursor,
has_search_latch, mtr)) {
@@ -1098,10 +1099,12 @@ btr_cur_search_to_nth_level(
/* If the hash search did not succeed, do binary search down the
tree */
+#ifdef BTR_CUR_HASH_ADAPT
if (has_search_latch) {
/* Release possible search latch to obey latching order */
- btr_search_s_unlock(index);
+ rw_lock_s_unlock(search_latch);
}
+#endif /* BTR_CUR_HASH_ADAPT */
/* 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) */
@@ -2155,9 +2158,11 @@ func_exit:
ut_free(prev_tree_savepoints);
}
+#ifdef BTR_CUR_HASH_ADAPT
if (has_search_latch) {
- btr_search_s_lock(index);
+ rw_lock_s_lock(search_latch);
}
+#endif /* BTR_CUR_HASH_ADAPT */
if (mbr_adj) {
/* remember that we will need to adjust parent MBR */
@@ -5746,7 +5751,7 @@ btr_estimate_n_rows_in_range_low(
btr_cur_search_to_nth_level(index, 0, tuple1, mode1,
BTR_SEARCH_LEAF | BTR_ESTIMATE,
&cursor, 0,
- __FILE__, __LINE__, &mtr);
+ __FILE__, __LINE__, &mtr, 0);
ut_ad(!page_rec_is_infimum(btr_cur_get_rec(&cursor)));
@@ -5800,7 +5805,7 @@ btr_estimate_n_rows_in_range_low(
btr_cur_search_to_nth_level(index, 0, tuple2, mode2,
BTR_SEARCH_LEAF | BTR_ESTIMATE,
&cursor, 0,
- __FILE__, __LINE__, &mtr);
+ __FILE__, __LINE__, &mtr, 0);
const rec_t* rec = btr_cur_get_rec(&cursor);
diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc
index 7a62e4c128a..4340c2f32b0 100644
--- a/storage/innobase/btr/btr0pcur.cc
+++ b/storage/innobase/btr/btr0pcur.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, 2019, MariaDB Corporation.
+Copyright (c) 2016, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -353,8 +353,11 @@ btr_pcur_restore_position_func(
mode = PAGE_CUR_UNSUPP;
}
- btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode,
- cursor, 0, file, line, mtr);
+ btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode, cursor,
+#ifdef BTR_CUR_HASH_ADAPT
+ 0,
+#endif /* BTR_CUR_HASH_ADAPT */
+ file, line, mtr);
/* Restore the old search mode */
cursor->search_mode = old_mode;
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 7671895953e..f1075358ad2 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -141,15 +141,8 @@ static
void
btr_search_check_free_space_in_heap(dict_index_t* index)
{
- hash_table_t* table;
- mem_heap_t* heap;
-
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_S));
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_X));
-
- table = btr_get_search_table(index);
-
- heap = table->heap;
+ hash_table_t* table = btr_get_search_table(index);
+ mem_heap_t* heap = table->heap;
/* Note that we peek the value of heap->free_block without reserving
the latch: this is ok, because we will not guarantee that there will
@@ -157,8 +150,9 @@ btr_search_check_free_space_in_heap(dict_index_t* index)
if (heap->free_block == NULL) {
buf_block_t* block = buf_block_alloc(NULL);
+ rw_lock_t* latch = btr_get_search_latch(index);
- btr_search_x_lock(index);
+ rw_lock_x_lock(latch);
if (btr_search_enabled
&& heap->free_block == NULL) {
@@ -167,7 +161,7 @@ btr_search_check_free_space_in_heap(dict_index_t* index)
buf_block_free(block);
}
- btr_search_x_unlock(index);
+ rw_lock_x_unlock(latch);
}
}
@@ -289,18 +283,88 @@ btr_search_disable_ref_count(
{
dict_index_t* index;
- ut_ad(mutex_own(&dict_sys->mutex));
-
for (index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
-
- ut_ad(rw_lock_own(btr_get_search_latch(index), RW_LOCK_X));
-
index->search_info->ref_count = 0;
}
}
+/** Lazily free detached metadata when removing the last reference. */
+ATTRIBUTE_COLD static void btr_search_lazy_free(dict_index_t *index)
+{
+ ut_ad(index->freed());
+ dict_table_t *table= index->table;
+ /* Perform the skipped steps of dict_index_remove_from_cache_low(). */
+ UT_LIST_REMOVE(table->freed_indexes, index);
+ rw_lock_free(&index->lock);
+ dict_mem_index_free(index);
+
+ if (!UT_LIST_GET_LEN(table->freed_indexes) &&
+ !UT_LIST_GET_LEN(table->indexes))
+ {
+ ut_ad(table->id == 0);
+ dict_mem_table_free(table);
+ }
+}
+
+/** Clear the adaptive hash index on all pages in the buffer pool. */
+static void buf_pool_clear_hash_index()
+{
+ ut_ad(btr_search_own_all(RW_LOCK_X));
+ ut_ad(!btr_search_enabled);
+
+ std::set<dict_index_t*> garbage;
+
+ for (ulong p = 0; p < srv_buf_pool_instances; p++)
+ {
+ buf_pool_t *buf_pool= buf_pool_from_array(p);
+ buf_chunk_t *chunks= buf_pool->chunks;
+ buf_chunk_t *chunk= chunks + buf_pool->n_chunks;
+
+ while (--chunk >= chunks)
+ {
+ buf_block_t *block= chunk->blocks;
+ for (ulint i= chunk->size; i--; block++)
+ {
+ dict_index_t *index= block->index;
+ assert_block_ahi_valid(block);
+
+ /* We can clear block->index and block->n_pointers when
+ btr_search_own_all(RW_LOCK_X); see the comments in buf0buf.h */
+
+ if (!index)
+ {
+# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ ut_a(!block->n_pointers);
+# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ continue;
+ }
+
+ ut_d(buf_page_state state= buf_block_get_state(block));
+ /* Another thread may have set the state to
+ BUF_BLOCK_REMOVE_HASH in buf_LRU_block_remove_hashed().
+
+ The state change in buf_page_realloc() is not observable here,
+ because in that case we would have !block->index.
+
+ In the end, the entire adaptive hash index will be removed. */
+ ut_ad(state == BUF_BLOCK_FILE_PAGE || state == BUF_BLOCK_REMOVE_HASH);
+# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ block->n_pointers= 0;
+# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ if (index->freed())
+ garbage.insert(index);
+ block->index= NULL;
+ }
+ }
+ }
+
+ for (std::set<dict_index_t*>::iterator i= garbage.begin();
+ i != garbage.end(); i++)
+ btr_search_lazy_free(*i);
+}
+
/** Disable the adaptive hash search system and empty the index.
@param[in] need_mutex need to acquire dict_sys->mutex */
void
@@ -373,33 +437,6 @@ btr_search_enable()
btr_search_x_unlock_all();
}
-/** Returns the value of ref_count. The value is protected by latch.
-@param[in] info search info
-@param[in] index index identifier
-@return ref_count value. */
-ulint
-btr_search_info_get_ref_count(
- btr_search_t* info,
- dict_index_t* index)
-{
- ulint ret = 0;
-
- if (!btr_search_enabled) {
- return(ret);
- }
-
- ut_ad(info);
-
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_S));
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_X));
-
- btr_search_s_lock(index);
- ret = info->ref_count;
- btr_search_s_unlock(index);
-
- return(ret);
-}
-
/** Updates the search info of an index about hash successes. NOTE that info
is NOT protected by any semaphore, to save CPU time! Do not assume its fields
are consistent.
@@ -415,8 +452,8 @@ btr_search_info_update_hash(
ulint n_unique;
int cmp;
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_S));
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_X));
+ ut_ad(!rw_lock_own_flagged(btr_get_search_latch(index),
+ RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
if (dict_index_is_ibuf(index)) {
/* So many deletes are performed on an insert buffer tree
@@ -601,28 +638,25 @@ btr_search_update_hash_ref(
buf_block_t* block,
const btr_cur_t* cursor)
{
- dict_index_t* index;
- ulint fold;
- rec_t* rec;
-
ut_ad(cursor->flag == BTR_CUR_HASH_FAIL);
- ut_ad(rw_lock_own(btr_get_search_latch(cursor->index), RW_LOCK_X));
+
ut_ad(rw_lock_own_flagged(&block->lock,
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
ut_ad(page_align(btr_cur_get_rec(cursor)) == block->frame);
ut_ad(page_is_leaf(block->frame));
assert_block_ahi_valid(block);
- index = block->index;
+ dict_index_t* index = block->index;
if (!index) {
-
return;
}
ut_ad(block->page.id.space() == index->space);
ut_a(index == cursor->index);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
+ rw_lock_t* const latch = btr_get_search_latch(index);
+ rw_lock_x_lock(latch);
if ((info->n_hash_potential > 0)
&& (block->curr_n_fields == info->n_fields)
@@ -632,28 +666,30 @@ btr_search_update_hash_ref(
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
rec_offs_init(offsets_);
- rec = btr_cur_get_rec(cursor);
+ const rec_t* rec = btr_cur_get_rec(cursor);
if (!page_rec_is_user_rec(rec)) {
-
- return;
+ goto func_exit;
}
- fold = rec_fold(rec,
- rec_get_offsets(rec, index, offsets_, true,
- ULINT_UNDEFINED, &heap),
- block->curr_n_fields,
- block->curr_n_bytes, index->id);
+ ulint fold = rec_fold(
+ rec,
+ rec_get_offsets(rec, index, offsets_, true,
+ ULINT_UNDEFINED, &heap),
+ block->curr_n_fields,
+ block->curr_n_bytes, index->id);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
- ut_ad(rw_lock_own(btr_get_search_latch(index), RW_LOCK_X));
ha_insert_for_fold(btr_get_search_table(index), fold,
block, rec);
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_ADDED);
}
+
+func_exit:
+ rw_lock_x_unlock(latch);
}
/** Updates the search info.
@@ -692,12 +728,7 @@ btr_search_info_update_slow(
#ifdef UNIV_SEARCH_PERF_STAT
btr_search_n_hash_fail++;
#endif /* UNIV_SEARCH_PERF_STAT */
-
- btr_search_x_lock(cursor->index);
-
btr_search_update_hash_ref(info, block, cursor);
-
- btr_search_x_unlock(cursor->index);
}
if (build_index) {
@@ -898,7 +929,6 @@ btr_search_guess_on_hash(
ulint has_search_latch,
mtr_t* mtr)
{
- const rec_t* rec;
ulint fold;
index_id_t index_id;
#ifdef notdefined
@@ -944,33 +974,28 @@ btr_search_guess_on_hash(
cursor->fold = fold;
cursor->flag = BTR_CUR_HASH;
+ rw_lock_t* const latch = btr_get_search_latch(index);
+
if (!has_search_latch) {
- btr_search_s_lock(index);
+ rw_lock_s_lock(latch);
if (!btr_search_enabled) {
- btr_search_s_unlock(index);
-
+fail:
+ if (!has_search_latch) {
+ rw_lock_s_unlock(latch);
+ }
btr_search_failure(info, cursor);
-
return(FALSE);
}
}
- ut_ad(rw_lock_get_writer(btr_get_search_latch(index)) != RW_LOCK_X);
- ut_ad(rw_lock_get_reader_count(btr_get_search_latch(index)) > 0);
-
- rec = (rec_t*) ha_search_and_get_data(
- btr_get_search_table(index), fold);
+ ut_ad(rw_lock_own(latch, RW_LOCK_S));
- if (rec == NULL) {
+ const rec_t* rec = static_cast<const rec_t*>(
+ ha_search_and_get_data(btr_get_search_table(index), fold));
- if (!has_search_latch) {
- btr_search_s_unlock(index);
- }
-
- btr_search_failure(info, cursor);
-
- return(FALSE);
+ if (!rec) {
+ goto fail;
}
buf_block_t* block = buf_block_from_ahi(rec);
@@ -980,32 +1005,34 @@ btr_search_guess_on_hash(
if (!buf_page_get_known_nowait(
latch_mode, block, BUF_MAKE_YOUNG,
__FILE__, __LINE__, mtr)) {
-
- if (!has_search_latch) {
- btr_search_s_unlock(index);
- }
-
- btr_search_failure(info, cursor);
-
- return(FALSE);
+ goto fail;
}
- btr_search_s_unlock(index);
+ const bool fail = index != block->index
+ && index_id == block->index->id;
+ ut_a(!fail || block->index->freed());
+ rw_lock_s_unlock(latch);
buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
+ if (UNIV_UNLIKELY(fail)) {
+ btr_search_drop_page_hash_index(block);
+ 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;
}
if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
ut_ad(buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH);
-
+fail_and_release_page:
if (!has_search_latch) {
-
btr_leaf_page_release(block, latch_mode, mtr);
}
btr_search_failure(info, cursor);
-
return(FALSE);
}
@@ -1024,14 +1051,7 @@ btr_search_guess_on_hash(
|| !btr_search_check_guess(cursor,
has_search_latch,
tuple, mode, mtr)) {
-
- if (!has_search_latch) {
- btr_leaf_page_release(block, latch_mode, mtr);
- }
-
- btr_search_failure(info, cursor);
-
- return(FALSE);
+ goto fail_and_release_page;
}
if (info->n_hash_potential < BTR_SEARCH_BUILD_LIMIT + 5) {
@@ -1115,30 +1135,26 @@ btr_search_drop_page_hash_index(buf_block_t* block)
ulint* folds;
ulint i;
mem_heap_t* heap;
- const dict_index_t* index;
rec_offs* offsets;
rw_lock_t* latch;
- btr_search_t* info;
retry:
- /* Do a dirty check on block->index, return if the block is
- not in the adaptive hash index. */
- index = block->index;
/* This debug check uses a dirty read that could theoretically cause
false positives while buf_pool_clear_hash_index() is executing. */
assert_block_ahi_valid(block);
- if (index == NULL) {
+ if (!block->index) {
return;
}
ut_ad(block->page.buf_fix_count == 0
|| buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH
|| rw_lock_own_flagged(&block->lock,
- RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
+ RW_LOCK_FLAG_X | RW_LOCK_FLAG_S
+ | RW_LOCK_FLAG_SX));
ut_ad(page_is_leaf(block->frame));
- /* We must not dereference index here, because it could be freed
+ /* We must not dereference block->index here, because it could be freed
if (index->table->n_ref_count == 0 && !mutex_own(&dict_sys->mutex)).
Determine the ahi_slot based on the block contents. */
@@ -1156,18 +1172,12 @@ retry:
rw_lock_s_lock(latch);
assert_block_ahi_valid(block);
- if (block->index == NULL) {
+ if (!block->index) {
rw_lock_s_unlock(latch);
return;
}
- /* The index associated with a block must remain the
- same, because we are holding block->lock or the block is
- not accessible by other threads (BUF_BLOCK_REMOVE_HASH),
- or the index is not accessible to other threads
- (buf_fix_count == 0 when DROP TABLE or similar is executing
- buf_LRU_drop_page_hash_for_tablespace()). */
- ut_a(index == block->index);
+ dict_index_t* index = block->index;
#ifdef MYSQL_INDEX_DISABLE_AHI
ut_ad(!index->disable_ahi);
#endif
@@ -1176,7 +1186,7 @@ retry:
ut_ad(index->space == FIL_NULL
|| block->page.id.space() == index->space);
ut_a(index_id == index->id);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
#ifdef UNIV_DEBUG
switch (dict_index_get_online_status(index)) {
case ONLINE_INDEX_CREATION:
@@ -1281,9 +1291,14 @@ next_rec:
folds[i], page);
}
- info = btr_search_get_info(block->index);
- ut_a(info->ref_count > 0);
- info->ref_count--;
+ switch (index->search_info->ref_count--) {
+ case 0:
+ ut_error;
+ case 1:
+ if (index->freed()) {
+ btr_search_lazy_free(index);
+ }
+ }
block->index = NULL;
@@ -1383,27 +1398,27 @@ btr_search_build_page_hash_index(
rec_offs_init(offsets_);
ut_ad(index);
ut_ad(block->page.id.space() == index->space);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
ut_ad(page_is_leaf(block->frame));
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_X));
ut_ad(rw_lock_own_flagged(&block->lock,
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
+ ut_ad(block->page.id.page_no() >= 3);
- btr_search_s_lock(index);
+ rw_lock_t* const latch = btr_get_search_latch(index);
+ rw_lock_s_lock(latch);
table = btr_get_search_table(index);
page = buf_block_get_frame(block);
- if (block->index && ((block->curr_n_fields != n_fields)
- || (block->curr_n_bytes != n_bytes)
- || (block->curr_left_side != left_side))) {
-
- btr_search_s_unlock(index);
+ const bool must_drop = block->index
+ && ((block->curr_n_fields != n_fields)
+ || (block->curr_n_bytes != n_bytes)
+ || (block->curr_left_side != left_side));
+ rw_lock_s_unlock(latch);
+ if (must_drop) {
btr_search_drop_page_hash_index(block);
- } else {
- btr_search_s_unlock(index);
}
/* Check that the values for hash index build are sensible */
@@ -1495,7 +1510,7 @@ btr_search_build_page_hash_index(
btr_search_check_free_space_in_heap(index);
- btr_search_x_lock(index);
+ rw_lock_x_lock(latch);
if (!btr_search_enabled) {
goto exit_func;
@@ -1533,7 +1548,7 @@ btr_search_build_page_hash_index(
MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_ADDED, n_cached);
exit_func:
assert_block_ahi_valid(block);
- btr_search_x_unlock(index);
+ rw_lock_x_unlock(latch);
ut_free(folds);
ut_free(recs);
@@ -1566,21 +1581,19 @@ btr_search_move_or_delete_hash_entries(
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_X));
ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_X));
- btr_search_s_lock(index);
+ rw_lock_t* const latch = btr_get_search_latch(index);
+ rw_lock_s_lock(latch);
ut_a(!new_block->index || new_block->index == index);
ut_a(!block->index || block->index == index);
- ut_a(!(new_block->index || block->index)
- || !dict_index_is_ibuf(index));
+ ut_ad(!(new_block->index || block->index)
+ || !dict_index_is_ibuf(index));
assert_block_ahi_valid(block);
assert_block_ahi_valid(new_block);
if (new_block->index) {
-
- btr_search_s_unlock(index);
-
+ rw_lock_s_unlock(latch);
btr_search_drop_page_hash_index(block);
-
return;
}
@@ -1593,7 +1606,7 @@ btr_search_move_or_delete_hash_entries(
new_block->n_bytes = block->curr_n_bytes;
new_block->left_side = left_side;
- btr_search_s_unlock(index);
+ rw_lock_s_unlock(latch);
ut_a(n_fields > 0 || n_bytes > 0);
@@ -1605,7 +1618,7 @@ btr_search_move_or_delete_hash_entries(
return;
}
- btr_search_s_unlock(index);
+ rw_lock_s_unlock(latch);
}
/** Updates the page hash index when a single record is deleted from a page.
@@ -1647,7 +1660,7 @@ btr_search_update_hash_on_delete(btr_cur_t* cursor)
ut_ad(block->page.id.space() == index->space);
ut_a(index == cursor->index);
ut_a(block->curr_n_fields > 0 || block->curr_n_bytes > 0);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
table = btr_get_search_table(index);
@@ -1660,7 +1673,8 @@ btr_search_update_hash_on_delete(btr_cur_t* cursor)
mem_heap_free(heap);
}
- btr_search_x_lock(index);
+ rw_lock_t* const latch = btr_get_search_latch(index);
+ rw_lock_x_lock(latch);
assert_block_ahi_valid(block);
if (block->index) {
@@ -1676,7 +1690,7 @@ btr_search_update_hash_on_delete(btr_cur_t* cursor)
assert_block_ahi_valid(block);
}
- btr_search_x_unlock(index);
+ rw_lock_x_unlock(latch);
}
/** Updates the page hash index when a single record is inserted on a page.
@@ -1712,9 +1726,10 @@ btr_search_update_hash_node_on_insert(btr_cur_t* cursor)
}
ut_a(cursor->index == index);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
- btr_search_x_lock(index);
+ rw_lock_t* const latch = btr_get_search_latch(index);
+ rw_lock_x_lock(latch);
if (!block->index) {
@@ -1738,10 +1753,9 @@ btr_search_update_hash_node_on_insert(btr_cur_t* cursor)
func_exit:
assert_block_ahi_valid(block);
- btr_search_x_unlock(index);
+ rw_lock_x_unlock(latch);
} else {
- btr_search_x_unlock(index);
-
+ rw_lock_x_unlock(latch);
btr_search_update_hash_on_insert(cursor);
}
}
@@ -1765,8 +1779,6 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor)
ulint next_fold = 0; /* remove warning (??? bug ???) */
ulint n_fields;
ulint n_bytes;
- ibool left_side;
- ibool locked = FALSE;
mem_heap_t* heap = NULL;
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
rec_offs* offsets = offsets_;
@@ -1803,11 +1815,11 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor)
ut_a(!index->disable_ahi);
#endif
ut_a(index == cursor->index);
- ut_a(!dict_index_is_ibuf(index));
+ ut_ad(!dict_index_is_ibuf(index));
n_fields = block->curr_n_fields;
n_bytes = block->curr_n_bytes;
- left_side = block->curr_left_side;
+ const bool left_side = block->curr_left_side;
ins_rec = page_rec_get_next_const(rec);
next_rec = page_rec_get_next_const(ins_rec);
@@ -1824,17 +1836,18 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor)
n_bytes, index->id);
}
+ rw_lock_t* const latch = btr_get_search_latch(index);
+ bool locked = false;
+
if (!page_rec_is_infimum(rec)) {
offsets = rec_get_offsets(
rec, index, offsets, true,
btr_search_get_n_fields(n_fields, n_bytes), &heap);
fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id);
} else {
- if (left_side) {
-
- btr_search_x_lock(index);
-
- locked = TRUE;
+ locked = left_side;
+ if (locked) {
+ rw_lock_x_lock(latch);
if (!btr_search_enabled) {
goto function_exit;
@@ -1849,10 +1862,8 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor)
if (fold != ins_fold) {
if (!locked) {
-
- btr_search_x_lock(index);
-
- locked = TRUE;
+ locked = true;
+ rw_lock_x_lock(latch);
if (!btr_search_enabled) {
goto function_exit;
@@ -1870,11 +1881,9 @@ check_next_rec:
if (page_rec_is_supremum(next_rec)) {
if (!left_side) {
-
if (!locked) {
- btr_search_x_lock(index);
-
- locked = TRUE;
+ locked = true;
+ rw_lock_x_lock(latch);
if (!btr_search_enabled) {
goto function_exit;
@@ -1888,12 +1897,9 @@ check_next_rec:
}
if (ins_fold != next_fold) {
-
if (!locked) {
-
- btr_search_x_lock(index);
-
- locked = TRUE;
+ locked = true;
+ rw_lock_x_lock(latch);
if (!btr_search_enabled) {
goto function_exit;
@@ -1912,7 +1918,7 @@ function_exit:
mem_heap_free(heap);
}
if (locked) {
- btr_search_x_unlock(index);
+ rw_lock_x_unlock(latch);
}
}
@@ -2019,7 +2025,7 @@ btr_search_hash_table_validate(ulint hash_table_id)
== BUF_BLOCK_REMOVE_HASH);
}
- ut_a(!dict_index_is_ibuf(block->index));
+ ut_ad(!dict_index_is_ibuf(block->index));
ut_ad(block->page.id.space() == block->index->space);
page_index_id = btr_page_get_index_id(block->frame);
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 11c2e0e5ad5..3beae8982b6 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -3165,66 +3165,6 @@ DECLARE_THREAD(buf_resize_thread)(void*)
OS_THREAD_DUMMY_RETURN;
}
-#ifdef BTR_CUR_HASH_ADAPT
-/** Clear the adaptive hash index on all pages in the buffer pool. */
-void
-buf_pool_clear_hash_index()
-{
- ulint p;
-
- ut_ad(btr_search_own_all(RW_LOCK_X));
- ut_ad(!buf_pool_resizing);
- ut_ad(!btr_search_enabled);
-
- for (p = 0; p < srv_buf_pool_instances; p++) {
- buf_pool_t* buf_pool = buf_pool_from_array(p);
- buf_chunk_t* chunks = buf_pool->chunks;
- buf_chunk_t* chunk = chunks + buf_pool->n_chunks;
-
- while (--chunk >= chunks) {
- buf_block_t* block = chunk->blocks;
- ulint i = chunk->size;
-
- for (; i--; block++) {
- dict_index_t* index = block->index;
- assert_block_ahi_valid(block);
-
- /* We can set block->index = NULL
- and block->n_pointers = 0
- when btr_search_own_all(RW_LOCK_X);
- see the comments in buf0buf.h */
-
- if (!index) {
-# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
- ut_a(!block->n_pointers);
-# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- continue;
- }
-
- ut_d(buf_page_state state
- = buf_block_get_state(block));
- /* Another thread may have set the
- state to BUF_BLOCK_REMOVE_HASH in
- buf_LRU_block_remove_hashed().
-
- The state change in buf_page_realloc()
- is not observable here, because in
- that case we would have !block->index.
-
- In the end, the entire adaptive hash
- index will be removed. */
- ut_ad(state == BUF_BLOCK_FILE_PAGE
- || state == BUF_BLOCK_REMOVE_HASH);
-# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
- block->n_pointers = 0;
-# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- block->index = NULL;
- }
- }
- }
-}
-#endif /* BTR_CUR_HASH_ADAPT */
-
/********************************************************************//**
Relocate a buffer control block. Relocates the block on the LRU list
and in buf_pool->page_hash. Does not relocate bpage->list.
@@ -4207,7 +4147,7 @@ static buf_block_t* buf_page_mtr_lock(buf_block_t *block,
{
case RW_NO_LATCH:
fix_type= MTR_MEMO_BUF_FIX;
- break;
+ goto done;
case RW_S_LATCH:
rw_lock_s_lock_inline(&block->lock, 0, file, line);
fix_type= MTR_MEMO_PAGE_S_FIX;
@@ -4223,6 +4163,15 @@ static buf_block_t* buf_page_mtr_lock(buf_block_t *block,
break;
}
+#ifdef BTR_CUR_HASH_ADAPT
+ {
+ dict_index_t *index= block->index;
+ if (index && index->freed())
+ btr_search_drop_page_hash_index(block);
+ }
+#endif /* BTR_CUR_HASH_ADAPT */
+
+done:
mtr_memo_push(mtr, block, fix_type);
return block;
}
@@ -4540,6 +4489,7 @@ evict_from_pool:
buf_pool_mutex_exit(buf_pool);
return(NULL);
}
+
break;
case BUF_BLOCK_ZIP_PAGE:
@@ -5087,9 +5037,11 @@ buf_page_get_known_nowait(
buf_pool = buf_pool_from_block(block);
+#ifdef BTR_CUR_HASH_ADAPT
if (mode == BUF_MAKE_YOUNG) {
buf_page_make_young_if_needed(&block->page);
}
+#endif /* BTR_CUR_HASH_ADAPT */
ut_ad(!ibuf_inside(mtr) || mode == BUF_KEEP_OLD);
@@ -5132,9 +5084,12 @@ buf_page_get_known_nowait(
deleting a record from SYS_INDEXES. This check will be
skipped in recv_recover_page() as well. */
- buf_page_mutex_enter(block);
- ut_a(!block->page.file_page_was_freed);
- buf_page_mutex_exit(block);
+# ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!block->page.file_page_was_freed
+ || (block->index && block->index->freed()));
+# else /* BTR_CUR_HASH_ADAPT */
+ ut_ad(!block->page.file_page_was_freed);
+# endif /* BTR_CUR_HASH_ADAPT */
}
#endif /* UNIV_DEBUG */
@@ -5627,6 +5582,12 @@ buf_page_create(
rw_lock_x_unlock(hash_lock);
buf_block_free(free_block);
+#ifdef BTR_CUR_HASH_ADAPT
+ if (block->page.state == BUF_BLOCK_FILE_PAGE
+ && UNIV_LIKELY_NULL(block->index)) {
+ btr_search_drop_page_hash_index(block);
+ }
+#endif /* BTR_CUR_HASH_ADAPT */
if (!recv_recovery_is_on()) {
return buf_page_get_with_no_latch(page_id, page_size,
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 9feebd9a08e..6e2dba77513 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -222,166 +222,6 @@ buf_LRU_evict_from_unzip_LRU(
}
#ifdef BTR_CUR_HASH_ADAPT
-/** Attempts to drop page hash index on a batch of pages belonging to a
-particular space id.
-@param[in] space_id space id
-@param[in] arr array of page_no
-@param[in] count number of entries in array */
-static
-void
-buf_LRU_drop_page_hash_batch(ulint space_id, const ulint* arr, ulint count)
-{
- ut_ad(count <= BUF_LRU_DROP_SEARCH_SIZE);
-
- for (const ulint* const end = arr + count; arr != end; ) {
- /* While our only caller
- buf_LRU_drop_page_hash_for_tablespace()
- is being executed for DROP TABLE or similar,
- the table cannot be evicted from the buffer pool. */
- btr_search_drop_page_hash_when_freed(
- page_id_t(space_id, *arr++));
- }
-}
-
-/******************************************************************//**
-When doing a DROP TABLE/DISCARD TABLESPACE we have to drop all page
-hash index entries belonging to that table. This function tries to
-do that in batch. Note that this is a 'best effort' attempt and does
-not guarantee that ALL hash entries will be removed. */
-static
-void
-buf_LRU_drop_page_hash_for_tablespace(
-/*==================================*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- ulint id) /*!< in: space id */
-{
- ulint* page_arr = static_cast<ulint*>(ut_malloc_nokey(
- sizeof(ulint) * BUF_LRU_DROP_SEARCH_SIZE));
-
- ulint num_entries = 0;
-
- buf_pool_mutex_enter(buf_pool);
-
-scan_again:
- for (buf_page_t* bpage = UT_LIST_GET_LAST(buf_pool->LRU);
- bpage != NULL;
- /* No op */) {
-
- buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
-
- ut_a(buf_page_in_file(bpage));
-
- if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE
- || bpage->id.space() != id
- || bpage->io_fix != BUF_IO_NONE) {
- /* Compressed pages are never hashed.
- Skip blocks of other tablespaces.
- Skip I/O-fixed blocks (to be dealt with later). */
-next_page:
- bpage = prev_bpage;
- continue;
- }
-
- buf_block_t* block = reinterpret_cast<buf_block_t*>(bpage);
-
- mutex_enter(&block->mutex);
-
- /* This debug check uses a dirty read that could
- theoretically cause false positives while
- buf_pool_clear_hash_index() is executing.
- (Other conflicting access paths to the adaptive hash
- index should not be possible, because when a
- tablespace is being discarded or dropped, there must
- be no concurrect access to the contained tables.) */
- assert_block_ahi_valid(block);
-
- bool skip = bpage->buf_fix_count > 0 || !block->index;
-
- mutex_exit(&block->mutex);
-
- if (skip) {
- /* Skip this block, because there are
- no adaptive hash index entries
- pointing to it, or because we cannot
- drop them due to the buffer-fix. */
- goto next_page;
- }
-
- /* Store the page number so that we can drop the hash
- index in a batch later. */
- page_arr[num_entries] = bpage->id.page_no();
- ut_a(num_entries < BUF_LRU_DROP_SEARCH_SIZE);
- ++num_entries;
-
- if (num_entries < BUF_LRU_DROP_SEARCH_SIZE) {
- goto next_page;
- }
-
- /* Array full. We release the buf_pool->mutex to obey
- the latching order. */
- buf_pool_mutex_exit(buf_pool);
-
- buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
-
- num_entries = 0;
-
- buf_pool_mutex_enter(buf_pool);
-
- /* Note that we released the buf_pool mutex above
- after reading the prev_bpage during processing of a
- page_hash_batch (i.e.: when the array was full).
- Because prev_bpage could belong to a compressed-only
- block, it may have been relocated, and thus the
- pointer cannot be trusted. Because bpage is of type
- buf_block_t, it is safe to dereference.
-
- bpage can change in the LRU list. This is OK because
- this function is a 'best effort' to drop as many
- search hash entries as possible and it does not
- guarantee that ALL such entries will be dropped. */
-
- /* If, however, bpage has been removed from LRU list
- to the free list then we should restart the scan.
- bpage->state is protected by buf_pool mutex. */
- if (bpage != NULL
- && buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
-
- goto scan_again;
- }
- }
-
- buf_pool_mutex_exit(buf_pool);
-
- /* Drop any remaining batch of search hashed pages. */
- buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
- ut_free(page_arr);
-}
-
-/** Try to drop the adaptive hash index for a tablespace.
-@param[in,out] table table
-@return whether anything was dropped */
-bool buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table)
-{
- for (dict_index_t* index = dict_table_get_first_index(table);
- index != NULL;
- index = dict_table_get_next_index(index)) {
- if (btr_search_info_get_ref_count(btr_search_get_info(index),
- index)) {
- goto drop_ahi;
- }
- }
-
- return false;
-drop_ahi:
- ulint id = table->space;
- for (ulint i = 0; i < srv_buf_pool_instances; i++) {
- buf_LRU_drop_page_hash_for_tablespace(buf_pool_from_array(i),
- id);
- }
-
- return true;
-}
-
/******************************************************************//**
While flushing (or removing dirty) pages from a tablespace we don't
want to hog the CPU and resources. Release the buffer pool and block
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index 54d2eca245f..1a3d6c51d98 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -26,7 +26,9 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0crea.h"
#include "btr0pcur.h"
-#include "btr0btr.h"
+#ifdef BTR_CUR_HASH_ADAPT
+# include "btr0sea.h"
+#endif /* BTR_CUR_HASH_ADAPT */
#include "page0page.h"
#include "mach0data.h"
#include "dict0boot.h"
@@ -1528,6 +1530,9 @@ dict_create_index_step(
&node->table->fts->cache->init_lock);
}
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!node->index->search_info->ref_count);
+#endif /* BTR_CUR_HASH_ADAPT */
dict_index_remove_from_cache(node->table, node->index);
node->index = NULL;
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 8f94ccb4c63..cff213dea3d 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1361,25 +1361,12 @@ dict_table_can_be_evicted(
}
#ifdef BTR_CUR_HASH_ADAPT
+ /* We cannot really evict the table if adaptive hash
+ index entries are pointing to any of its indexes. */
for (dict_index_t* index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
-
- btr_search_t* info = btr_search_get_info(index);
-
- /* We are not allowed to free the in-memory index
- struct dict_index_t until all entries in the adaptive
- hash index that point to any of the page belonging to
- his b-tree index are dropped. This is so because
- dropping of these entries require access to
- dict_index_t struct. To avoid such scenario we keep
- a count of number of such pages in the search_info and
- only free the dict_index_t struct when this count
- drops to zero.
-
- See also: dict_index_remove_from_cache_low() */
-
- if (btr_search_info_get_ref_count(info, index) > 0) {
+ if (index->n_ahi_pages()) {
return(FALSE);
}
}
@@ -1391,6 +1378,71 @@ dict_table_can_be_evicted(
return(FALSE);
}
+#ifdef BTR_CUR_HASH_ADAPT
+/** @return a clone of this */
+dict_index_t *dict_index_t::clone() const
+{
+ ut_ad(n_fields);
+ ut_ad(!(type & (DICT_IBUF | DICT_SPATIAL | DICT_FTS)));
+ ut_ad(online_status == ONLINE_INDEX_COMPLETE);
+ ut_ad(is_committed());
+ ut_ad(!is_dummy);
+ ut_ad(!parser);
+ ut_ad(!index_fts_syncing);
+ ut_ad(!online_log);
+ ut_ad(!rtr_track);
+
+ const size_t size= sizeof *this + n_fields * sizeof(*fields) +
+#ifdef BTR_CUR_ADAPT
+ sizeof *search_info +
+#endif
+ 1 + strlen(name) +
+ n_uniq * (sizeof *stat_n_diff_key_vals +
+ sizeof *stat_n_sample_sizes +
+ sizeof *stat_n_non_null_key_vals);
+
+ mem_heap_t* heap= mem_heap_create(size);
+ dict_index_t *index= static_cast<dict_index_t*>(mem_heap_dup(heap, this,
+ sizeof *this));
+ *index= *this;
+ rw_lock_create(index_tree_rw_lock_key, &index->lock, SYNC_INDEX_TREE);
+ index->heap= heap;
+ index->name= mem_heap_strdup(heap, name);
+ index->fields= static_cast<dict_field_t*>
+ (mem_heap_dup(heap, fields, n_fields * sizeof *fields));
+#ifdef BTR_CUR_ADAPT
+ index->search_info= btr_search_info_create(index->heap);
+#endif /* BTR_CUR_ADAPT */
+ index->stat_n_diff_key_vals= static_cast<ib_uint64_t*>
+ (mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_diff_key_vals));
+ index->stat_n_sample_sizes= static_cast<ib_uint64_t*>
+ (mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_sample_sizes));
+ index->stat_n_non_null_key_vals= static_cast<ib_uint64_t*>
+ (mem_heap_zalloc(heap, n_uniq * sizeof *stat_n_non_null_key_vals));
+ memset(&index->zip_pad, 0, sizeof index->zip_pad);
+ return index;
+}
+
+/** Clone this index for lazy dropping of the adaptive hash.
+@return this or a clone */
+dict_index_t *dict_index_t::clone_if_needed()
+{
+ if (!search_info->ref_count)
+ return this;
+ dict_index_t *prev= UT_LIST_GET_PREV(indexes, this);
+
+ UT_LIST_REMOVE(table->indexes, this);
+ UT_LIST_ADD_LAST(table->freed_indexes, this);
+ dict_index_t *index= clone();
+ set_freed();
+ if (prev)
+ UT_LIST_INSERT_AFTER(table->indexes, prev, index);
+ else
+ UT_LIST_ADD_FIRST(table->indexes, index);
+ return index;
+}
+#endif /* BTR_CUR_HASH_ADAPT */
+
/**********************************************************************//**
Make room in the table cache by evicting an unused table. The unused table
should not be part of FK relationship and currently not used in any user
@@ -2081,6 +2133,14 @@ dict_table_remove_from_cache_low(
UT_DELETE(table->vc_templ);
}
+#ifdef BTR_CUR_HASH_ADAPT
+ if (UNIV_UNLIKELY(UT_LIST_GET_LEN(table->freed_indexes) != 0)) {
+ table->vc_templ = NULL;
+ table->id = 0;
+ return;
+ }
+#endif /* BTR_CUR_HASH_ADAPT */
+
dict_mem_table_free(table);
}
@@ -2310,6 +2370,8 @@ dict_index_remove_from_cache_low(
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(mutex_own(&dict_sys->mutex));
+ ut_ad(table->id);
+ ut_ad(!index->freed());
/* No need to acquire the dict_index_t::lock here because
there can't be any active operations on this index (or table). */
@@ -2319,13 +2381,22 @@ dict_index_remove_from_cache_low(
row_log_free(index->online_log);
}
+ /* Remove the index from the list of indexes of the table */
+ UT_LIST_REMOVE(table->indexes, index);
+
+ /* The index is being dropped, remove any compression stats for it. */
+ if (!lru_evict && DICT_TF_GET_ZIP_SSIZE(index->table->flags)) {
+ mutex_enter(&page_zip_stat_per_index_mutex);
+ page_zip_stat_per_index.erase(index->id);
+ mutex_exit(&page_zip_stat_per_index_mutex);
+ }
+
+ /* Remove the index from affected virtual column index list */
+ index->detach_columns();
+
#ifdef BTR_CUR_HASH_ADAPT
/* We always create search info whether or not adaptive
hash index is enabled or not. */
- btr_search_t* info = btr_search_get_info(index);
- ulint retries = 0;
- ut_ad(info);
-
/* We are not allowed to free the in-memory index struct
dict_index_t until all entries in the adaptive hash index
that point to any of the page belonging to his b-tree index
@@ -2335,31 +2406,15 @@ dict_index_remove_from_cache_low(
only free the dict_index_t struct when this count drops to
zero. See also: dict_table_can_be_evicted() */
- do {
- if (!btr_search_info_get_ref_count(info, index)
- || !buf_LRU_drop_page_hash_for_tablespace(table)) {
- break;
- }
-
- ut_a(++retries < 10000);
- } while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
+ if (index->n_ahi_pages()) {
+ index->set_freed();
+ UT_LIST_ADD_LAST(table->freed_indexes, index);
+ return;
+ }
#endif /* BTR_CUR_HASH_ADAPT */
rw_lock_free(&index->lock);
- /* The index is being dropped, remove any compression stats for it. */
- if (!lru_evict && DICT_TF_GET_ZIP_SSIZE(index->table->flags)) {
- mutex_enter(&page_zip_stat_per_index_mutex);
- page_zip_stat_per_index.erase(index->id);
- mutex_exit(&page_zip_stat_per_index_mutex);
- }
-
- /* Remove the index from the list of indexes of the table */
- UT_LIST_REMOVE(table->indexes, index);
-
- /* Remove the index from affected virtual column index list */
- index->detach_columns();
-
dict_mem_index_free(index);
}
@@ -5698,7 +5753,7 @@ dict_set_corrupted(
btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_LE,
BTR_MODIFY_LEAF,
- &cursor, 0, __FILE__, __LINE__, &mtr);
+ &cursor, 0, __FILE__, __LINE__, &mtr, 0);
if (cursor.low_match == dtuple_get_n_fields(tuple)) {
/* UPDATE SYS_INDEXES SET TYPE=index->type
@@ -5800,7 +5855,7 @@ dict_index_set_merge_threshold(
btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE,
BTR_MODIFY_LEAF,
- &cursor, 0, __FILE__, __LINE__, &mtr);
+ &cursor, 0, __FILE__, __LINE__, &mtr, 0);
if (cursor.up_match == dtuple_get_n_fields(tuple)
&& rec_get_n_fields_old(btr_cur_get_rec(&cursor))
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index 21a3c743f52..8327318e46c 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -126,6 +126,9 @@ dict_mem_table_create(
lock_table_lock_list_init(&table->locks);
UT_LIST_INIT(table->indexes, &dict_index_t::indexes);
+#ifdef BTR_CUR_HASH_ADAPT
+ UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes);
+#endif /* BTR_CUR_HASH_ADAPT */
table->heap = heap;
@@ -181,6 +184,10 @@ dict_mem_table_free(
{
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
+ ut_ad(UT_LIST_GET_LEN(table->indexes) == 0);
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(UT_LIST_GET_LEN(table->freed_indexes) == 0);
+#endif /* BTR_CUR_HASH_ADAPT */
ut_d(table->cached = FALSE);
if (dict_table_has_fts_index(table)
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index dab30a218e6..0da77dfdff7 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -424,6 +424,9 @@ dict_stats_table_clone_create(
dict_table_stats_latch_create(t, false);
UT_LIST_INIT(t->indexes, &dict_index_t::indexes);
+#ifdef BTR_CUR_HASH_ADAPT
+ UT_LIST_INIT(t->freed_indexes, &dict_index_t::indexes);
+#endif /* BTR_CUR_HASH_ADAPT */
for (index = dict_table_get_first_index(table);
index != NULL;
@@ -4005,6 +4008,9 @@ test_dict_stats_save()
table.stat_clustered_index_size = TEST_CLUSTERED_INDEX_SIZE;
table.stat_sum_of_other_index_sizes = TEST_SUM_OF_OTHER_INDEX_SIZES;
UT_LIST_INIT(table.indexes, &dict_index_t::indexes);
+#ifdef BTR_CUR_HASH_ADAPT
+ UT_LIST_INIT(table.freed_indexes, &dict_index_t::indexes);
+#endif /* BTR_CUR_HASH_ADAPT */
UT_LIST_ADD_LAST(table.indexes, &index1);
UT_LIST_ADD_LAST(table.indexes, &index2);
ut_d(table.magic_n = DICT_TABLE_MAGIC_N);
@@ -4154,6 +4160,9 @@ test_dict_stats_fetch_from_ps()
/* craft a dummy dict_table_t */
table.name.m_name = (char*) (TEST_DATABASE_NAME "/" TEST_TABLE_NAME);
UT_LIST_INIT(table.indexes, &dict_index_t::indexes);
+#ifdef BTR_CUR_HASH_ADAPT
+ UT_LIST_INIT(table.freed_indexes, &dict_index_t::indexes);
+#endif /* BTR_CUR_HASH_ADAPT */
UT_LIST_ADD_LAST(table.indexes, &index1);
UT_LIST_ADD_LAST(table.indexes, &index2);
ut_d(table.magic_n = DICT_TABLE_MAGIC_N);
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index d308ff9de71..974a514e637 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -2976,8 +2976,6 @@ fseg_mark_page_used(
@param[in,out] space tablespace
@param[in] offset page number
@param[in] page_size page size
-@param[in] ahi whether we may need to drop the adaptive
-hash index
@param[in,out] mtr mini-transaction */
static
void
@@ -2986,9 +2984,6 @@ fseg_free_page_low(
fil_space_t* space,
page_no_t offset,
const page_size_t& page_size,
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi,
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr)
{
xdes_t* descr;
@@ -3003,15 +2998,6 @@ fseg_free_page_low(
== FSEG_MAGIC_N_VALUE);
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
ut_d(space->modify_check(*mtr));
-#ifdef BTR_CUR_HASH_ADAPT
- /* Drop search system page hash index if the page is found in
- the pool and is hashed */
-
- if (ahi) {
- btr_search_drop_page_hash_when_freed(
- page_id_t(space->id, offset));
- }
-#endif /* BTR_CUR_HASH_ADAPT */
descr = xdes_get_descriptor(space, offset, page_size, mtr);
@@ -3097,22 +3083,13 @@ fseg_free_page_low(
}
}
-#ifndef BTR_CUR_HASH_ADAPT
-# define fseg_free_page_low(inode, space, offset, page_size, ahi, mtr) \
- fseg_free_page_low(inode, space, offset, page_size, mtr)
-#endif /* !BTR_CUR_HASH_ADAPT */
-
/**********************************************************************//**
Frees a single page of a segment. */
void
-fseg_free_page_func(
+fseg_free_page(
fseg_header_t* seg_header, /*!< in: segment header */
ulint space_id,/*!< in: space id */
ulint page, /*!< in: page offset */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
DBUG_ENTER("fseg_free_page");
@@ -3128,7 +3105,7 @@ fseg_free_page_func(
&iblock);
fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr);
- fseg_free_page_low(seg_inode, space, page, page_size, ahi, mtr);
+ fseg_free_page_low(seg_inode, space, page, page_size, mtr);
ut_d(buf_page_set_file_page_was_freed(page_id_t(space_id, page)));
@@ -3169,8 +3146,6 @@ fseg_page_is_free(fil_space_t* space, unsigned page)
@param[in,out] space tablespace
@param[in] page_size page size
@param[in] page page number in the extent
-@param[in] ahi whether we may need to drop
- the adaptive hash index
@param[in,out] mtr mini-transaction */
MY_ATTRIBUTE((nonnull))
static
@@ -3180,9 +3155,6 @@ fseg_free_extent(
fil_space_t* space,
const page_size_t& page_size,
ulint page,
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi,
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr)
{
xdes_t* descr;
@@ -3203,23 +3175,6 @@ fseg_free_extent(
const ulint first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
#endif /* BTR_CUR_HASH_ADAPT || UNIV_DEBUG */
-#ifdef BTR_CUR_HASH_ADAPT
- if (ahi) {
- for (ulint i = 0; i < FSP_EXTENT_SIZE; i++) {
- if (!xdes_mtr_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
-
- /* Drop search system page hash index
- if the page is found in the pool and
- is hashed */
-
- btr_search_drop_page_hash_when_freed(
- page_id_t(space->id,
- first_page_in_extent + i));
- }
- }
- }
-#endif /* BTR_CUR_HASH_ADAPT */
-
if (xdes_is_full(descr, mtr)) {
flst_remove(seg_inode + FSEG_FULL,
descr + XDES_FLST_NODE, mtr);
@@ -3251,27 +3206,18 @@ fseg_free_extent(
#endif /* UNIV_DEBUG */
}
-#ifndef BTR_CUR_HASH_ADAPT
-# define fseg_free_extent(inode, space, page_size, page, ahi, mtr) \
- fseg_free_extent(inode, space, page_size, page, mtr)
-#endif /* !BTR_CUR_HASH_ADAPT */
-
/**********************************************************************//**
Frees part of a segment. This function can be used to free a segment by
repeatedly calling this function in different mini-transactions. Doing
the freeing in a single mini-transaction might result in too big a
mini-transaction.
-@return TRUE if freeing completed */
-ibool
-fseg_free_step_func(
+@return whether the freeing was completed */
+bool
+fseg_free_step(
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
resides on the first page of the frag list
of the segment, this pointer becomes obsolete
after the last freeing step */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint n;
@@ -3303,7 +3249,7 @@ fseg_free_step_func(
if (inode == NULL) {
ib::info() << "Double free of inode from "
<< page_id_t(space_id, header_page);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(true);
}
fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr);
@@ -3313,9 +3259,9 @@ fseg_free_step_func(
/* Free the extent held by the segment */
page = xdes_get_offset(descr);
- fseg_free_extent(inode, space, page_size, page, ahi, mtr);
+ fseg_free_extent(inode, space, page_size, page, mtr);
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
}
/* Free a frag page */
@@ -3325,13 +3271,13 @@ fseg_free_step_func(
/* Freeing completed: free the segment inode */
fsp_free_seg_inode(space, page_size, inode, mtr);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(true);
}
fseg_free_page_low(
inode, space,
fseg_get_nth_frag_page_no(inode, n, mtr),
- page_size, ahi, mtr);
+ page_size, mtr);
n = fseg_find_last_used_frag_page_slot(inode, mtr);
@@ -3339,24 +3285,20 @@ fseg_free_step_func(
/* Freeing completed: free the segment inode */
fsp_free_seg_inode(space, page_size, inode, mtr);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(true);
}
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
}
/**********************************************************************//**
Frees part of a segment. Differs from fseg_free_step because this function
leaves the header page unfreed.
-@return TRUE if freeing completed, except the header page */
-ibool
-fseg_free_step_not_header_func(
+@return whether the freeing was completed, except for the header page */
+bool
+fseg_free_step_not_header(
fseg_header_t* header, /*!< in: segment header which must reside on
the first fragment page of the segment */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint n;
@@ -3382,29 +3324,27 @@ fseg_free_step_not_header_func(
/* Free the extent held by the segment */
page = xdes_get_offset(descr);
- fseg_free_extent(inode, space, page_size, page, ahi, mtr);
+ fseg_free_extent(inode, space, page_size, page, mtr);
- return(FALSE);
+ return false;
}
/* Free a frag page */
n = fseg_find_last_used_frag_page_slot(inode, mtr);
- if (n == ULINT_UNDEFINED) {
- ut_error;
- }
+ ut_a(n != ULINT_UNDEFINED);
page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
if (page_no == page_get_page_no(page_align(header))) {
- return(TRUE);
+ return true;
}
- fseg_free_page_low(inode, space, page_no, page_size, ahi, mtr);
+ fseg_free_page_low(inode, space, page_no, page_size, mtr);
- return(FALSE);
+ return false;
}
/** Returns the first extent descriptor for a segment.
diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc
index 3631ff35874..c372a3f1cd4 100644
--- a/storage/innobase/gis/gis0sea.cc
+++ b/storage/innobase/gis/gis0sea.cc
@@ -590,7 +590,7 @@ rtr_pcur_open_low(
}
btr_cur_search_to_nth_level(index, level, tuple, mode, latch_mode,
- btr_cursor, 0, file, line, mtr);
+ btr_cursor, 0, file, line, mtr, 0);
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
cursor->trx_if_known = NULL;
@@ -759,7 +759,7 @@ static void rtr_get_father_node(
btr_cur_search_to_nth_level(
index, level, tuple, PAGE_CUR_RTREE_LOCATE,
BTR_CONT_MODIFY_TREE, btr_cur, 0,
- __FILE__, __LINE__, mtr);
+ __FILE__, __LINE__, mtr, 0);
} else {
/* btr_validate */
@@ -769,7 +769,7 @@ static void rtr_get_father_node(
btr_cur_search_to_nth_level(
index, level, tuple, PAGE_CUR_RTREE_LOCATE,
BTR_CONT_MODIFY_TREE, btr_cur, 0,
- __FILE__, __LINE__, mtr);
+ __FILE__, __LINE__, mtr, 0);
rec = btr_cur_get_rec(btr_cur);
n_fields = dtuple_get_n_fields_cmp(tuple);
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index edc7478f7de..9b1d99d3730 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -254,6 +254,7 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
for (ulint i = 0; i < num_to_add_index; i++) {
if (!add_index[i]->is_committed()) {
add_index[i]->detach_columns();
+ add_index[i]->n_fields = 0;
}
}
}
@@ -8689,21 +8690,14 @@ foreign_fail:
}
if (ctx0->num_to_drop_vcol || ctx0->num_to_add_vcol) {
+ /* FIXME: this workaround does not seem to work with
+ partitioned tables */
DBUG_ASSERT(ctx0->old_table->get_ref_count() == 1);
trx_commit_for_mysql(m_prebuilt->trx);
-#ifdef BTR_CUR_HASH_ADAPT
- if (btr_search_enabled) {
- btr_search_disable(false);
- btr_search_enable();
- }
-#endif /* BTR_CUR_HASH_ADAPT */
-
- char tb_name[FN_REFLEN];
- ut_strcpy(tb_name, m_prebuilt->table->name.m_name);
-
- tb_name[strlen(m_prebuilt->table->name.m_name)] = 0;
+ char tb_name[NAME_LEN * 2 + 1 + 1];
+ strcpy(tb_name, m_prebuilt->table->name.m_name);
dict_table_close(m_prebuilt->table, true, false);
dict_table_remove_from_cache(m_prebuilt->table);
m_prebuilt->table = dict_table_open_on_name(
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index e02958b4ac3..1ee1624ca8b 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -2109,7 +2109,7 @@ ibuf_remove_free_page(void)
page from it. */
fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
- IBUF_SPACE_ID, page_no, false, &mtr);
+ IBUF_SPACE_ID, page_no, &mtr);
const page_id_t page_id(IBUF_SPACE_ID, page_no);
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index 19d0fb397be..f70fe687182 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -154,8 +154,7 @@ 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.
If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */
dberr_t
-btr_cur_search_to_nth_level(
-/*========================*/
+btr_cur_search_to_nth_level_func(
dict_index_t* index, /*!< in: index */
ulint level, /*!< in: the tree level of search */
const dtuple_t* tuple, /*!< in: data tuple; NOTE: n_fields_cmp in
@@ -181,16 +180,24 @@ btr_cur_search_to_nth_level(
to protect the record! */
btr_cur_t* cursor, /*!< in/out: tree cursor; the cursor page is
s- or x-latched, but see also above! */
+#ifdef BTR_CUR_HASH_ADAPT
ulint has_search_latch,
/*!< in: latch mode the caller
currently has on search system:
RW_S_LATCH, or 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);
+ ib_uint64_t autoinc);
/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
+#ifdef BTR_CUR_HASH_ADAPT
+# define btr_cur_search_to_nth_level btr_cur_search_to_nth_level_func
+#else /* BTR_CUR_HASH_ADAPT */
+# define btr_cur_search_to_nth_level(ix,lv,t,md,l,cur,has,file,line,m,ai) \
+ btr_cur_search_to_nth_level_func(ix,lv,t,md,l,cur,file,line,m,ai)
+#endif /* BTR_CUR_HASH_ADAPT */
/*****************************************************************//**
Opens a cursor at either end of an index.
diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h
index b79260e5ab6..26c7ebcee6d 100644
--- a/storage/innobase/include/btr0pcur.h
+++ b/storage/innobase/include/btr0pcur.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -136,15 +136,22 @@ btr_pcur_open_with_no_init_func(
page, but assume that the caller uses his
btr search latch to protect the record! */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
+#ifdef BTR_CUR_HASH_ADAPT
ulint has_search_latch,
/*!< in: latch mode the caller
currently has on search system:
RW_S_LATCH, or 0 */
+#endif /* BTR_CUR_HASH_ADAPT */
const char* file, /*!< in: file name */
unsigned line, /*!< in: line where called */
mtr_t* mtr); /*!< in: mtr */
-#define btr_pcur_open_with_no_init(ix,t,md,l,cur,has,m) \
+#ifdef BTR_CUR_HASH_ADAPT
+# define btr_pcur_open_with_no_init(ix,t,md,l,cur,has,m) \
btr_pcur_open_with_no_init_func(ix,t,md,l,cur,has,__FILE__,__LINE__,m)
+#else /* BTR_CUR_HASH_ADAPT */
+# define btr_pcur_open_with_no_init(ix,t,md,l,cur,has,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. */
diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic
index 8b0da666250..b5b57050832 100644
--- a/storage/innobase/include/btr0pcur.ic
+++ b/storage/innobase/include/btr0pcur.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2019, MariaDB Corporation.
+Copyright (c) 2015, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -496,10 +496,12 @@ btr_pcur_open_with_no_init_func(
page, but assume that the caller uses his
btr search latch to protect the record! */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
+#ifdef BTR_CUR_HASH_ADAPT
ulint has_search_latch,
/*!< in: latch mode the caller
currently has on search system:
RW_S_LATCH, or 0 */
+#endif /* BTR_CUR_HASH_ADAPT */
const char* file, /*!< in: file name */
unsigned line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mtr */
@@ -516,7 +518,7 @@ btr_pcur_open_with_no_init_func(
err = btr_cur_search_to_nth_level(
index, 0, tuple, mode, latch_mode, btr_cursor,
- has_search_latch, file, line, mtr);
+ has_search_latch, file, line, mtr, 0);
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
index 645b3689ff6..b808ba036db 100644
--- a/storage/innobase/include/btr0sea.h
+++ b/storage/innobase/include/btr0sea.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2018, MariaDB Corporation.
+Copyright (c) 2018, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -54,15 +54,6 @@ btr_search_disable(
void
btr_search_enable();
-/** Returns the value of ref_count. The value is protected by latch.
-@param[in] info search info
-@param[in] index index identifier
-@return ref_count value. */
-ulint
-btr_search_info_get_ref_count(
- btr_search_t* info,
- dict_index_t* index);
-
/*********************************************************************//**
Updates the search info. */
UNIV_INLINE
@@ -156,18 +147,6 @@ btr_search_update_hash_on_delete(btr_cur_t* cursor);
bool
btr_search_validate();
-/** X-Lock the search latch (corresponding to given index)
-@param[in] index index handler */
-UNIV_INLINE
-void
-btr_search_x_lock(const dict_index_t* index);
-
-/** X-Unlock the search latch (corresponding to given index)
-@param[in] index index handler */
-UNIV_INLINE
-void
-btr_search_x_unlock(const dict_index_t* index);
-
/** Lock all search latches in exclusive mode. */
UNIV_INLINE
void
@@ -178,18 +157,6 @@ UNIV_INLINE
void
btr_search_x_unlock_all();
-/** S-Lock the search latch (corresponding to given index)
-@param[in] index index handler */
-UNIV_INLINE
-void
-btr_search_s_lock(const dict_index_t* index);
-
-/** S-Unlock the search latch (corresponding to given index)
-@param[in] index index handler */
-UNIV_INLINE
-void
-btr_search_s_unlock(const dict_index_t* index);
-
/** Lock all search latches in shared mode. */
UNIV_INLINE
void
@@ -236,12 +203,8 @@ btr_get_search_table(const dict_index_t* index);
#else /* BTR_CUR_HASH_ADAPT */
# define btr_search_sys_create(size)
# define btr_search_drop_page_hash_index(block)
-# define btr_search_s_lock(index)
-# define btr_search_s_unlock(index)
# define btr_search_s_lock_all(index)
# define btr_search_s_unlock_all(index)
-# define btr_search_x_lock(index)
-# define btr_search_x_unlock(index)
# define btr_search_info_update(index, cursor)
# define btr_search_move_or_delete_hash_entries(new_block, block, index)
# define btr_search_update_hash_on_insert(cursor)
@@ -327,6 +290,18 @@ struct btr_search_t{
};
#ifdef BTR_CUR_HASH_ADAPT
+/** @return number of leaf pages pointed to by the adaptive hash index */
+inline ulint dict_index_t::n_ahi_pages() const
+{
+ if (!btr_search_enabled)
+ return 0;
+ rw_lock_t *latch = btr_get_search_latch(this);
+ rw_lock_s_lock(latch);
+ ulint ref_count= search_info->ref_count;
+ rw_lock_s_unlock(latch);
+ return ref_count;
+}
+
/** The hash index system */
struct btr_search_sys_t{
hash_table_t** hash_tables; /*!< the adaptive hash tables,
diff --git a/storage/innobase/include/btr0sea.ic b/storage/innobase/include/btr0sea.ic
index 4972de16064..90877d23192 100644
--- a/storage/innobase/include/btr0sea.ic
+++ b/storage/innobase/include/btr0sea.ic
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -62,8 +63,8 @@ btr_search_info_update(
dict_index_t* index, /*!< in: index of the cursor */
btr_cur_t* cursor) /*!< in: cursor which was just positioned */
{
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_S));
- ut_ad(!rw_lock_own(btr_get_search_latch(index), RW_LOCK_X));
+ ut_ad(!rw_lock_own_flagged(btr_get_search_latch(index),
+ RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
if (dict_index_is_spatial(index) || !btr_search_enabled) {
return;
@@ -87,24 +88,6 @@ btr_search_info_update(
btr_search_info_update_slow(info, cursor);
}
-/** X-Lock the search latch (corresponding to given index)
-@param[in] index index handler */
-UNIV_INLINE
-void
-btr_search_x_lock(const dict_index_t* index)
-{
- rw_lock_x_lock(btr_get_search_latch(index));
-}
-
-/** X-Unlock the search latch (corresponding to given index)
-@param[in] index index handler */
-UNIV_INLINE
-void
-btr_search_x_unlock(const dict_index_t* index)
-{
- rw_lock_x_unlock(btr_get_search_latch(index));
-}
-
/** Lock all search latches in exclusive mode. */
UNIV_INLINE
void
@@ -125,24 +108,6 @@ btr_search_x_unlock_all()
}
}
-/** S-Lock the search latch (corresponding to given index)
-@param[in] index index handler */
-UNIV_INLINE
-void
-btr_search_s_lock(const dict_index_t* index)
-{
- rw_lock_s_lock(btr_get_search_latch(index));
-}
-
-/** S-Unlock the search latch (corresponding to given index)
-@param[in] index index handler */
-UNIV_INLINE
-void
-btr_search_s_unlock(const dict_index_t* index)
-{
- rw_lock_s_unlock(btr_get_search_latch(index));
-}
-
/** Lock all search latches in shared mode. */
UNIV_INLINE
void
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 0536e2f8ac6..a9b8ef94bab 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -71,11 +71,13 @@ struct fil_addr_t;
/* @} */
/** @name Modes for buf_page_get_known_nowait */
/* @{ */
-#define BUF_MAKE_YOUNG 51 /*!< Move the block to the
+#ifdef BTR_CUR_HASH_ADAPT
+# define BUF_MAKE_YOUNG 51 /*!< Move the block to the
start of the LRU list if there
is a danger that the block
would drift out of the buffer
pool*/
+#endif /* BTR_CUR_HASH_ADAPT */
#define BUF_KEEP_OLD 52 /*!< Preserve the current LRU
position of the block. */
/* @} */
@@ -282,12 +284,6 @@ extern "C"
os_thread_ret_t
DECLARE_THREAD(buf_resize_thread)(void*);
-#ifdef BTR_CUR_HASH_ADAPT
-/** Clear the adaptive hash index on all pages in the buffer pool. */
-void
-buf_pool_clear_hash_index();
-#endif /* BTR_CUR_HASH_ADAPT */
-
/*********************************************************************//**
Gets the current size of buffer buf_pool in bytes.
@return size in bytes */
diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h
index 1efbb1f03ef..a72d98395af 100644
--- a/storage/innobase/include/buf0lru.h
+++ b/storage/innobase/include/buf0lru.h
@@ -49,17 +49,6 @@ These are low-level functions
/** Minimum LRU list length for which the LRU_old pointer is defined */
#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */
-#ifdef BTR_CUR_HASH_ADAPT
-struct dict_table_t;
-/** Try to drop the adaptive hash index for a tablespace.
-@param[in,out] table table
-@return whether anything was dropped */
-bool buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table)
- MY_ATTRIBUTE((warn_unused_result,nonnull));
-#else
-# define buf_LRU_drop_page_hash_for_tablespace(table)
-#endif /* BTR_CUR_HASH_ADAPT */
-
/** Empty the flush list for all pages belonging to a tablespace.
@param[in] id tablespace identifier
@param[in,out] observer flush observer,
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index b259d2fb2ad..80d18dcbb2a 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -831,6 +831,9 @@ struct dict_index_t{
dict_table_t* table; /*!< back pointer to table */
unsigned space:32;
/*!< space where the index tree is placed */
+ /** root page number, or FIL_NULL if the index has been detached
+ from storage (DISCARD TABLESPACE or similar),
+ or 1 if the index is in table->freed_indexes */
unsigned page:32;/*!< index tree root page number */
unsigned merge_threshold:6;
/*!< In the pessimistic delete, if the page
@@ -1021,11 +1024,23 @@ struct dict_index_t{
for (unsigned i = 0; i < n_fields; i++) {
fields[i].col->detach(*this);
}
-
- n_fields = 0;
}
}
+#ifdef BTR_CUR_HASH_ADAPT
+ /** @return a clone of this */
+ dict_index_t* clone() const;
+ /** Clone this index for lazy dropping of the adaptive hash index.
+ @return this or a clone */
+ dict_index_t* clone_if_needed();
+ /** @return number of leaf pages pointed to by the adaptive hash index */
+ inline ulint n_ahi_pages() const;
+ /** @return whether mark_freed() had been invoked */
+ bool freed() const { return UNIV_UNLIKELY(page == 1); }
+ /** Note that the index is waiting for btr_search_lazy_free() */
+ void set_freed() { ut_ad(!freed()); page= 1; }
+#endif /* BTR_CUR_HASH_ADAPT */
+
/** This ad-hoc class is used by record_size_info only. */
class record_size_info_t {
public:
@@ -1605,6 +1620,11 @@ struct dict_table_t {
/** List of indexes of the table. */
UT_LIST_BASE_NODE_T(dict_index_t) indexes;
+#ifdef BTR_CUR_HASH_ADAPT
+ /** List of detached indexes that are waiting to be freed along with
+ the last adaptive hash index entry */
+ UT_LIST_BASE_NODE_T(dict_index_t) freed_indexes;
+#endif /* BTR_CUR_HASH_ADAPT */
/** List of foreign key constraints in the table. These refer to
columns in other tables. */
diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h
index a4e3b84b55e..8debdb00013 100644
--- a/storage/innobase/include/fsp0fsp.h
+++ b/storage/innobase/include/fsp0fsp.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2019, MariaDB Corporation.
+Copyright (c) 2013, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -568,22 +568,11 @@ fsp_get_available_space_in_free_extents(
/**********************************************************************//**
Frees a single page of a segment. */
void
-fseg_free_page_func(
+fseg_free_page(
fseg_header_t* seg_header, /*!< in: segment header */
ulint space_id, /*!< in: space id */
ulint page, /*!< in: page offset */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr); /*!< in/out: mini-transaction */
-#ifdef BTR_CUR_HASH_ADAPT
-# define fseg_free_page(header, space_id, page, ahi, mtr) \
- fseg_free_page_func(header, space_id, page, ahi, mtr)
-#else /* BTR_CUR_HASH_ADAPT */
-# define fseg_free_page(header, space_id, page, ahi, mtr) \
- fseg_free_page_func(header, space_id, page, mtr)
-#endif /* BTR_CUR_HASH_ADAPT */
/** Determine whether a page is free.
@param[in,out] space tablespace
@param[in] page page number
@@ -596,45 +585,25 @@ Frees part of a segment. This function can be used to free a segment
by repeatedly calling this function in different mini-transactions.
Doing the freeing in a single mini-transaction might result in
too big a mini-transaction.
-@return TRUE if freeing completed */
-ibool
-fseg_free_step_func(
+@return whether the freeing was completed */
+bool
+fseg_free_step(
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
resides on the first page of the frag list
of the segment, this pointer becomes obsolete
after the last freeing step */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
MY_ATTRIBUTE((warn_unused_result));
-#ifdef BTR_CUR_HASH_ADAPT
-# define fseg_free_step(header, ahi, mtr) fseg_free_step_func(header, ahi, mtr)
-#else /* BTR_CUR_HASH_ADAPT */
-# define fseg_free_step(header, ahi, mtr) fseg_free_step_func(header, mtr)
-#endif /* BTR_CUR_HASH_ADAPT */
/**********************************************************************//**
Frees part of a segment. Differs from fseg_free_step because this function
leaves the header page unfreed.
-@return TRUE if freeing completed, except the header page */
-ibool
-fseg_free_step_not_header_func(
+@return whether the freeing was completed, except for the header page */
+bool
+fseg_free_step_not_header(
fseg_header_t* header, /*!< in: segment header which must reside on
the first fragment page of the segment */
-#ifdef BTR_CUR_HASH_ADAPT
- bool ahi, /*!< in: whether we may need to drop
- the adaptive hash index */
-#endif /* BTR_CUR_HASH_ADAPT */
mtr_t* mtr) /*!< in/out: mini-transaction */
MY_ATTRIBUTE((warn_unused_result));
-#ifdef BTR_CUR_HASH_ADAPT
-# define fseg_free_step_not_header(header, ahi, mtr) \
- fseg_free_step_not_header_func(header, ahi, mtr)
-#else /* BTR_CUR_HASH_ADAPT */
-# define fseg_free_step_not_header(header, ahi, mtr) \
- fseg_free_step_not_header_func(header, mtr)
-#endif /* BTR_CUR_HASH_ADAPT */
/** Reset the page type.
Data files created before MySQL 5.1.48 may contain garbage in FIL_PAGE_TYPE.
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index b0fcecf0e39..d92bcb761e4 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -26,6 +26,9 @@ Created 2012-02-08 by Sunny Bains.
#include "row0import.h"
#include "btr0pcur.h"
+#ifdef BTR_CUR_HASH_ADAPT
+# include "btr0sea.h"
+#endif
#include "que0que.h"
#include "dict0boot.h"
#include "dict0load.h"
@@ -4017,15 +4020,12 @@ row_import_for_mysql(
index entries that point to cached garbage pages in the buffer
pool, because PageConverter::operator() only evicted those
pages that were replaced by the imported pages. We must
- discard all remaining adaptive hash index entries, because the
+ detach any remaining adaptive hash index entries, because the
adaptive hash index must be a subset of the table contents;
false positives are not tolerated. */
- while (buf_LRU_drop_page_hash_for_tablespace(table)) {
- if (trx_is_interrupted(trx)
- || srv_shutdown_state != SRV_SHUTDOWN_NONE) {
- err = DB_INTERRUPTED;
- break;
- }
+ for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); index;
+ index = UT_LIST_GET_NEXT(indexes, index)) {
+ index = index->clone_if_needed();
}
#endif /* BTR_CUR_HASH_ADAPT */
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 4c11c241cd6..123566132f4 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -2907,7 +2907,7 @@ row_ins_sec_index_entry_low(
err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_RTREE_INSERT,
search_mode,
- &cursor, 0, __FILE__, __LINE__, &mtr);
+ &cursor, 0, __FILE__, __LINE__, &mtr, 0);
if (mode == BTR_MODIFY_LEAF && rtr_info.mbr_adj) {
mtr_commit(&mtr);
@@ -2922,7 +2922,7 @@ row_ins_sec_index_entry_low(
err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_RTREE_INSERT,
search_mode,
- &cursor, 0, __FILE__, __LINE__, &mtr);
+ &cursor, 0, __FILE__, __LINE__, &mtr, 0);
mode = BTR_MODIFY_TREE;
}
@@ -2934,7 +2934,7 @@ row_ins_sec_index_entry_low(
err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_LE,
search_mode,
- &cursor, 0, __FILE__, __LINE__, &mtr);
+ &cursor, 0, __FILE__, __LINE__, &mtr, 0);
}
if (err != DB_SUCCESS) {
@@ -3028,7 +3028,7 @@ row_ins_sec_index_entry_low(
index, 0, entry, PAGE_CUR_LE,
(search_mode
& ~(BTR_INSERT | BTR_IGNORE_SEC_UNIQUE)),
- &cursor, 0, __FILE__, __LINE__, &mtr);
+ &cursor, 0, __FILE__, __LINE__, &mtr, 0);
}
if (row_ins_must_modify_rec(&cursor)) {
diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc
index e7b06e5a5b2..e46ee2c4f18 100644
--- a/storage/innobase/row/row0log.cc
+++ b/storage/innobase/row/row0log.cc
@@ -3102,7 +3102,7 @@ row_log_apply_op_low(
? BTR_MODIFY_TREE
: BTR_MODIFY_LEAF,
&cursor, 0, __FILE__, __LINE__,
- &mtr);
+ &mtr, 0);
ut_ad(dict_index_get_n_unique(index) > 0);
/* This test is somewhat similar to row_ins_must_modify_rec(),
@@ -3151,7 +3151,7 @@ row_log_apply_op_low(
btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, 0,
- __FILE__, __LINE__, &mtr);
+ __FILE__, __LINE__, &mtr, 0);
/* No other thread than the current one
is allowed to modify the index tree.
@@ -3254,7 +3254,7 @@ insert_the_rec:
btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, 0,
- __FILE__, __LINE__, &mtr);
+ __FILE__, __LINE__, &mtr, 0);
}
/* We already determined that the
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 1677a47fa45..8c8f1674374 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -46,6 +46,9 @@ Completed by Sunny Bains and Marko Makela
#include "row0vers.h"
#include "handler0alter.h"
#include "btr0bulk.h"
+#ifdef BTR_CUR_ADAPT
+# include "btr0sea.h"
+#endif /* BTR_CUR_ADAPT */
#include "ut0stage.h"
#include "fil0crypt.h"
@@ -162,7 +165,7 @@ public:
PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_LEAF, &ins_cur,
0, __FILE__, __LINE__,
- &mtr);
+ &mtr, 0);
/* It need to update MBR in parent entry,
so change search mode to BTR_MODIFY_TREE */
@@ -178,7 +181,7 @@ public:
m_index, 0, dtuple,
PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_TREE, &ins_cur, 0,
- __FILE__, __LINE__, &mtr);
+ __FILE__, __LINE__, &mtr, 0);
}
error = btr_cur_optimistic_insert(
@@ -201,8 +204,7 @@ public:
PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_TREE,
&ins_cur, 0,
- __FILE__, __LINE__, &mtr);
-
+ __FILE__, __LINE__, &mtr, 0);
error = btr_cur_pessimistic_insert(
flag, &ins_cur, &ins_offsets,
@@ -3770,6 +3772,9 @@ row_merge_drop_indexes(
we should exclude FTS entries from
prebuilt->ins_node->entry_list
in ins_node_create_entry_list(). */
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!index->search_info->ref_count);
+#endif /* BTR_CUR_HASH_ADAPT */
dict_index_remove_from_cache(
table, index);
index = prev;
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 45586a1e977..9bbd531cb9a 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -2459,6 +2459,9 @@ row_create_index_for_mysql(
index->table = table;
err = dict_create_index_tree_in_mem(index, trx);
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!index->search_info->ref_count);
+#endif /* BTR_CUR_HASH_ADAPT */
if (err != DB_SUCCESS) {
dict_index_remove_from_cache(table, index);
@@ -3372,35 +3375,6 @@ row_drop_table_for_mysql(
if (!dict_table_is_temporary(table)) {
if (table->space != TRX_SYS_SPACE) {
-#ifdef BTR_CUR_HASH_ADAPT
- /* On DISCARD TABLESPACE, we would not drop the
- adaptive hash index entries. If the tablespace is
- missing here, delete-marking the record in SYS_INDEXES
- would not free any pages in the buffer pool. Thus,
- dict_index_remove_from_cache() would hang due to
- adaptive hash index entries existing in the buffer
- pool. To prevent this hang, and also to guarantee
- that btr_search_drop_page_hash_when_freed() will avoid
- calling btr_search_drop_page_hash_index() while we
- hold the InnoDB dictionary lock, we will drop any
- adaptive hash index entries upfront. */
- const bool immune = is_temp_name
- || create_failed
- || sqlcom == SQLCOM_CREATE_TABLE
- || strstr(table->name.m_name, "/FTS");
-
- while (buf_LRU_drop_page_hash_for_tablespace(table)) {
- if ((!immune && trx_is_interrupted(trx))
- || srv_shutdown_state
- != SRV_SHUTDOWN_NONE) {
- err = DB_INTERRUPTED;
- table->to_be_dropped = false;
- dict_table_close(table, true, false);
- goto funct_exit;
- }
- }
-#endif /* BTR_CUR_HASH_ADAPT */
-
/* Delete the link file if used. */
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
RemoteDatafile::delete_link_file(name);
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 6420bf8a707..15486500b37 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -2,7 +2,7 @@
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2015, 2019, MariaDB Corporation.
+Copyright (c) 2015, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -1289,23 +1289,17 @@ void
row_sel_open_pcur(
/*==============*/
plan_t* plan, /*!< in: table plan */
- ibool search_latch_locked,
- /*!< in: TRUE if the thread currently
- has the search latch locked in
- s-mode */
+#ifdef BTR_CUR_HASH_ADAPT
+ ulint has_search_latch,
+#endif
mtr_t* mtr) /*!< in: mtr */
{
dict_index_t* index;
func_node_t* cond;
que_node_t* exp;
ulint n_fields;
- ulint has_search_latch = 0; /* RW_S_LATCH or 0 */
ulint i;
- if (search_latch_locked) {
- has_search_latch = RW_S_LATCH;
- }
-
index = plan->index;
/* Calculate the value of the search tuple: the exact match columns
@@ -1357,6 +1351,11 @@ row_sel_open_pcur(
plan->pcur_is_open = TRUE;
}
+#ifndef BTR_CUR_HASH_ADAPT
+# define row_sel_open_pcur(plan, has_search_latch, mtr) \
+ row_sel_open_pcur(plan, mtr)
+#endif /* !BTR_CUR_HASH_ADAPT */
+
/*********************************************************************//**
Restores a stored pcur position to a table index.
@return TRUE if the cursor should be moved to the next record after we
@@ -1618,12 +1617,6 @@ row_sel(
ut_ad(thr->run_node == node);
-#ifdef BTR_CUR_HASH_ADAPT
- ibool search_latch_locked = FALSE;
-#else /* BTR_CUR_HASH_ADAPT */
-# define search_latch_locked false
-#endif /* BTR_CUR_HASH_ADAPT */
-
if (node->read_view) {
/* In consistent reads, we try to do with the hash index and
not to use the buffer page get. This is to reduce memory bus
@@ -1648,6 +1641,10 @@ table_loop:
plan = sel_node_get_nth_plan(node, node->fetch_table);
index = plan->index;
+#ifdef BTR_CUR_HASH_ADAPT
+ ulint has_search_latch = 0;
+ rw_lock_t* const latch = btr_get_search_latch(index);
+#endif /* BTR_CUR_HASH_ADAPT */
if (plan->n_rows_prefetched > 0) {
sel_dequeue_prefetched_row(plan);
@@ -1672,26 +1669,22 @@ table_loop:
#ifdef BTR_CUR_HASH_ADAPT
if (consistent_read && plan->unique_search && !plan->pcur_is_open
&& !plan->must_get_clust) {
- if (!search_latch_locked) {
- btr_search_s_lock(index);
-
- search_latch_locked = TRUE;
- } else if (rw_lock_get_writer(btr_get_search_latch(index))
- == RW_LOCK_X_WAIT) {
-
+ if (!has_search_latch) {
+ has_search_latch = RW_S_LATCH;
+ rw_lock_s_lock(latch);
+ } else if (rw_lock_get_writer(latch) == RW_LOCK_X_WAIT) {
/* There is an x-latch request waiting: release the
s-latch for a moment; as an s-latch here is often
kept for some 10 searches before being released,
a waiting x-latch request would block other threads
from acquiring an s-latch for a long time, lowering
performance significantly in multiprocessors. */
-
- btr_search_s_unlock(index);
- btr_search_s_lock(index);
+ rw_lock_s_unlock(latch);
+ rw_lock_s_lock(latch);
}
switch (row_sel_try_search_shortcut(node, plan,
- search_latch_locked,
+ has_search_latch,
&mtr)) {
case SEL_FOUND:
goto next_table;
@@ -1709,10 +1702,9 @@ table_loop:
mtr.start();
}
- if (search_latch_locked) {
- btr_search_s_unlock(index);
-
- search_latch_locked = FALSE;
+ if (has_search_latch) {
+ has_search_latch = 0;
+ rw_lock_s_unlock(latch);
}
#endif /* BTR_CUR_HASH_ADAPT */
@@ -1720,7 +1712,7 @@ table_loop:
/* Evaluate the expressions to build the search tuple and
open the cursor */
- row_sel_open_pcur(plan, search_latch_locked, &mtr);
+ row_sel_open_pcur(plan, has_search_latch, &mtr);
cursor_just_opened = TRUE;
@@ -2117,7 +2109,9 @@ skip_lock:
}
next_rec:
- ut_ad(!search_latch_locked);
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!has_search_latch);
+#endif /* BTR_CUR_HASH_ADAPT */
if (mtr_has_extra_clust_latch) {
@@ -2156,8 +2150,9 @@ next_table:
plan->cursor_at_end = TRUE;
} else {
- ut_ad(!search_latch_locked);
-
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!has_search_latch);
+#endif /* BTR_CUR_HASH_ADAPT */
plan->stored_cursor_rec_processed = TRUE;
btr_pcur_store_position(&(plan->pcur), &mtr);
@@ -2248,8 +2243,9 @@ stop_for_a_while:
inserted new records which should have appeared in the result set,
which would result in the phantom problem. */
- ut_ad(!search_latch_locked);
-
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!has_search_latch);
+#endif /* BTR_CUR_HASH_ADAPT */
plan->stored_cursor_rec_processed = FALSE;
btr_pcur_store_position(&(plan->pcur), &mtr);
@@ -2266,7 +2262,9 @@ commit_mtr_for_a_while:
plan->stored_cursor_rec_processed = TRUE;
- ut_ad(!search_latch_locked);
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!has_search_latch);
+#endif /* BTR_CUR_HASH_ADAPT */
btr_pcur_store_position(&(plan->pcur), &mtr);
mtr.commit();
@@ -2280,7 +2278,9 @@ lock_wait_or_error:
/* See the note at stop_for_a_while: the same holds for this case */
ut_ad(!btr_pcur_is_before_first_on_page(&plan->pcur) || !node->asc);
- ut_ad(!search_latch_locked);
+#ifdef BTR_CUR_HASH_ADAPT
+ ut_ad(!has_search_latch);
+#endif /* BTR_CUR_HASH_ADAPT */
plan->stored_cursor_rec_processed = FALSE;
btr_pcur_store_position(&(plan->pcur), &mtr);
@@ -2289,8 +2289,8 @@ lock_wait_or_error:
func_exit:
#ifdef BTR_CUR_HASH_ADAPT
- if (search_latch_locked) {
- btr_search_s_unlock(index);
+ if (has_search_latch) {
+ rw_lock_s_unlock(latch);
}
#endif /* BTR_CUR_HASH_ADAPT */
ut_ad(!sync_check_iterate(dict_sync_check()));
@@ -4460,7 +4460,6 @@ row_search_mvcc(
&& !prebuilt->templ_contains_blob
&& !prebuilt->used_in_HANDLER
&& (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) {
-
mode = PAGE_CUR_GE;
if (trx->mysql_n_tables_locked == 0
@@ -4480,7 +4479,8 @@ row_search_mvcc(
and if we try that, we can deadlock on the adaptive
hash index semaphore! */
- rw_lock_s_lock(btr_get_search_latch(index));
+ rw_lock_t* const latch = btr_get_search_latch(index);
+ rw_lock_s_lock(latch);
switch (row_sel_try_search_shortcut_for_mysql(
&rec, prebuilt, &offsets, &heap,
@@ -4534,7 +4534,7 @@ row_search_mvcc(
err = DB_SUCCESS;
- rw_lock_s_unlock(btr_get_search_latch(index));
+ rw_lock_s_unlock(latch);
goto func_exit;
@@ -4544,7 +4544,7 @@ row_search_mvcc(
err = DB_RECORD_NOT_FOUND;
- rw_lock_s_unlock(btr_get_search_latch(index));
+ rw_lock_s_unlock(latch);
/* NOTE that we do NOT store the cursor
position */
@@ -4561,7 +4561,7 @@ row_search_mvcc(
mtr.commit();
mtr.start();
- rw_lock_s_unlock(btr_get_search_latch(index));
+ rw_lock_s_unlock(latch);
}
}
#endif /* BTR_CUR_HASH_ADAPT */
diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc
index 5e512c602e6..618e161bee4 100644
--- a/storage/innobase/row/row0trunc.cc
+++ b/storage/innobase/row/row0trunc.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2013, 2018, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -39,6 +39,7 @@ Created 2013-04-12 Sunny Bains
#include "os0file.h"
#include "que0que.h"
#include "trx0undo.h"
+#include "btr0sea.h"
/* FIXME: For temporary tables, use a simple approach of btr_free()
and btr_create() of each index tree. */
@@ -1953,7 +1954,6 @@ dberr_t row_truncate_table_for_mysql(dict_table_t* table, trx_t* trx)
for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
index != NULL;
index = UT_LIST_GET_NEXT(indexes, index)) {
-
err = dict_truncate_index_tree_in_mem(index);
if (err != DB_SUCCESS) {
@@ -2003,6 +2003,15 @@ dberr_t row_truncate_table_for_mysql(dict_table_t* table, trx_t* trx)
os_thread_sleep(2000000);
DBUG_SUICIDE(););
+#ifdef BTR_CUR_HASH_ADAPT
+ dict_table_x_unlock_indexes(table);
+ for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); index;
+ index = UT_LIST_GET_NEXT(indexes, index)) {
+ index = index->clone_if_needed();
+ }
+ dict_table_x_lock_indexes(table);
+#endif /* BTR_CUR_HASH_ADAPT */
+
/* Step-10: Re-create new indexes. */
if (!dict_table_is_temporary(table)) {
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index 732435ccefb..81ba1b731bf 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -383,7 +383,7 @@ trx_purge_free_segment(trx_rseg_t* rseg, fil_addr_t hdr_addr)
}
if (fseg_free_step_not_header(
- seg_hdr + TRX_UNDO_FSEG_HEADER, false, &mtr)) {
+ seg_hdr + TRX_UNDO_FSEG_HEADER, &mtr)) {
break;
}
@@ -413,7 +413,7 @@ trx_purge_free_segment(trx_rseg_t* rseg, fil_addr_t hdr_addr)
is not flooded with bufferfixed pages: see the note in
fsp0fsp.cc. */
- } while (!fseg_free_step(seg_hdr + TRX_UNDO_FSEG_HEADER, false, &mtr));
+ } while (!fseg_free_step(seg_hdr + TRX_UNDO_FSEG_HEADER, &mtr));
hist_size = mtr_read_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE,
MLOG_4BYTES, &mtr);
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index 336506c7b65..f9e76e5d772 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -869,7 +869,7 @@ trx_undo_free_page(
undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
fseg_free_page(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER,
- space, page_no, false, mtr);
+ space, page_no, mtr);
last_addr = flst_get_last(header_page + TRX_UNDO_SEG_HDR
+ TRX_UNDO_PAGE_LIST, mtr);
@@ -1092,7 +1092,7 @@ trx_undo_seg_free(
file_seg = seg_header + TRX_UNDO_FSEG_HEADER;
- finished = fseg_free_step(file_seg, false, &mtr);
+ finished = fseg_free_step(file_seg, &mtr);
if (finished) {
/* Update the rseg header */