summaryrefslogtreecommitdiff
path: root/storage/innobase/dict/dict0stats.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/dict/dict0stats.cc')
-rw-r--r--storage/innobase/dict/dict0stats.cc129
1 files changed, 101 insertions, 28 deletions
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 84fac55a304..c7355f85c2e 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -1560,6 +1560,96 @@ empty_table:
return err;
}
+/** Open a cursor at the first page in a tree level.
+@param page_cur cursor
+@param level level to search for (0=leaf)
+@param mtr mini-transaction */
+static dberr_t page_cur_open_level(page_cur_t *page_cur, ulint level,
+ mtr_t *mtr)
+{
+ mem_heap_t *heap= nullptr;
+ rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_offs *offsets= offsets_;
+ dberr_t err;
+
+ dict_index_t *const index= page_cur->index;
+
+ rec_offs_init(offsets_);
+ ut_ad(level != ULINT_UNDEFINED);
+ ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_SX_LOCK));
+ ut_ad(mtr->get_savepoint() == 1);
+
+ uint32_t page= index->page;
+
+ for (ulint height = ULINT_UNDEFINED;; height--)
+ {
+ buf_block_t* block=
+ btr_block_get(*index, page, RW_S_LATCH,
+ !height && !index->is_clust(), mtr, &err);
+ if (!block)
+ break;
+
+ const uint32_t l= btr_page_get_level(block->page.frame);
+
+ if (height == ULINT_UNDEFINED)
+ {
+ ut_ad(!heap);
+ /* We are in the root node */
+ height= l;
+ if (UNIV_UNLIKELY(height < level))
+ return DB_CORRUPTION;
+ }
+ else if (UNIV_UNLIKELY(height != l) || page_has_prev(block->page.frame))
+ {
+ err= DB_CORRUPTION;
+ break;
+ }
+
+ page_cur_set_before_first(block, page_cur);
+
+ if (height == level)
+ break;
+
+ ut_ad(height);
+
+ if (!page_cur_move_to_next(page_cur))
+ {
+ err= DB_CORRUPTION;
+ break;
+ }
+
+ offsets= rec_get_offsets(page_cur->rec, index, offsets, 0, ULINT_UNDEFINED,
+ &heap);
+ page= btr_node_ptr_get_child_page_no(page_cur->rec, offsets);
+ }
+
+ if (UNIV_LIKELY_NULL(heap))
+ mem_heap_free(heap);
+
+ /* Release all page latches except the one on the desired page. */
+ const auto end= mtr->get_savepoint();
+ if (end > 1)
+ mtr->rollback_to_savepoint(1, end - 1);
+
+ return err;
+}
+
+/** Open a cursor at the first page in a tree level.
+@param page_cur cursor
+@param level level to search for (0=leaf)
+@param mtr mini-transaction
+@param index index tree */
+static dberr_t btr_pcur_open_level(btr_pcur_t *pcur, ulint level, mtr_t *mtr,
+ dict_index_t *index)
+{
+ pcur->latch_mode= BTR_SEARCH_TREE;
+ pcur->search_mode= PAGE_CUR_G;
+ pcur->pos_state= BTR_PCUR_IS_POSITIONED;
+ pcur->btr_cur.page_cur.index= index;
+ return page_cur_open_level(&pcur->btr_cur.page_cur, level, mtr);
+}
+
+
/* @{ Pseudo code about the relation between the following functions
let N = N_SAMPLE_PAGES(index)
@@ -1616,7 +1706,8 @@ dict_stats_analyze_index_level(
DEBUG_PRINTF(" %s(table=%s, index=%s, level=" ULINTPF ")\n",
__func__, index->table->name, index->name, level);
- ut_ad(mtr->memo_contains(index->lock, MTR_MEMO_SX_LOCK));
+ *total_recs = 0;
+ *total_pages = 0;
n_uniq = dict_index_get_n_unique(index);
@@ -1649,9 +1740,7 @@ dict_stats_analyze_index_level(
/* Position pcur on the leftmost record on the leftmost page
on the desired level. */
- if (btr_pcur_open_at_index_side(
- true, index, BTR_SEARCH_TREE_ALREADY_S_LATCHED,
- &pcur, true, level, mtr) != DB_SUCCESS
+ if (btr_pcur_open_level(&pcur, level, mtr, index) != DB_SUCCESS
|| !btr_pcur_move_to_next_on_page(&pcur)) {
goto func_exit;
}
@@ -1661,21 +1750,10 @@ dict_stats_analyze_index_level(
/* The page must not be empty, except when
it is the root page (and the whole index is empty). */
ut_ad(btr_pcur_is_on_user_rec(&pcur) || page_is_leaf(page));
- ut_ad(btr_pcur_get_rec(&pcur)
- == page_rec_get_next_const(page_get_infimum_rec(page)));
prev_rec = NULL;
prev_rec_is_copied = false;
- /* no records by default */
- *total_recs = 0;
-
- *total_pages = 0;
-
- if (page_has_prev(page) || btr_page_get_level(page) != level) {
- goto func_exit;
- }
-
if (REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
btr_pcur_get_rec(&pcur), page_is_comp(page))) {
ut_ad(btr_pcur_is_on_user_rec(&pcur));
@@ -1728,10 +1806,7 @@ dict_stats_analyze_index_level(
if (level == 0
&& !srv_stats_include_delete_marked
- && rec_get_deleted_flag(
- rec,
- page_is_comp(btr_pcur_get_page(&pcur)))) {
-
+ && rec_get_deleted_flag(rec, page_rec_is_comp(rec))) {
if (rec_is_last_on_page
&& !prev_rec_is_copied
&& prev_rec != NULL) {
@@ -1811,7 +1886,7 @@ dict_stats_analyze_index_level(
records on this level at some point we will jump from
one page to the next and then rec and prev_rec will
be on different pages and
- btr_pcur_move_to_next_user_rec() will release the
+ btr_cur_move_to_next_user_rec() will release the
latch on the page that prev_rec is on */
prev_rec = rec_copy_prefix_to_buf(
rec, index, n_uniq,
@@ -1820,7 +1895,7 @@ dict_stats_analyze_index_level(
} else {
/* still on the same page, the next call to
- btr_pcur_move_to_next_user_rec() will not jump
+ btr_cur_move_to_next_user_rec() will not jump
on the next page, we can simply assign pointers
instead of copying the records like above */
@@ -1891,7 +1966,6 @@ dict_stats_analyze_index_level(
}
#endif /* UNIV_STATS_DEBUG */
- btr_leaf_page_release(btr_pcur_get_block(&pcur), BTR_SEARCH_LEAF, mtr);
func_exit:
ut_free(prev_rec_buf);
mem_heap_free(heap);
@@ -2280,7 +2354,6 @@ dict_stats_analyze_index_for_n_prefix(
n_prefix, n_diff_data->n_diff_on_level);
#endif
- ut_ad(mtr->memo_contains(index->lock, MTR_MEMO_SX_LOCK));
ut_ad(n_diff_data->level);
/* Position pcur on the leftmost record on the leftmost page
@@ -2289,9 +2362,7 @@ dict_stats_analyze_index_for_n_prefix(
n_diff_data->n_diff_all_analyzed_pages = 0;
n_diff_data->n_external_pages_sum = 0;
- if (btr_pcur_open_at_index_side(true, index,
- BTR_SEARCH_TREE_ALREADY_S_LATCHED,
- &pcur, true, n_diff_data->level, mtr)
+ if (btr_pcur_open_level(&pcur, n_diff_data->level, mtr, index)
!= DB_SUCCESS
|| !btr_pcur_move_to_next_on_page(&pcur)) {
return;
@@ -2680,6 +2751,7 @@ empty_index:
mtr.commit();
mtr.start();
mtr_sx_lock_index(index, &mtr);
+ ut_ad(mtr.get_savepoint() == 1);
buf_block_t *root = btr_root_block_get(index, RW_S_LATCH,
&mtr, &err);
if (!root || root_level != btr_page_get_level(root->page.frame)
@@ -2695,7 +2767,7 @@ empty_index:
break;
}
- mtr.memo_release(root, MTR_MEMO_PAGE_S_FIX);
+ mtr.rollback_to_savepoint(1);
/* check whether we should pick the current level;
we pick level 1 even if it does not have enough
@@ -2757,6 +2829,7 @@ empty_index:
break;
}
+ mtr.rollback_to_savepoint(1);
dict_stats_analyze_index_level(index,
level,
n_diff_on_level,
@@ -2764,7 +2837,7 @@ empty_index:
&total_pages,
n_diff_boundaries,
&mtr);
-
+ mtr.rollback_to_savepoint(1);
level_is_analyzed = true;
if (level == 1