Commit 1e9c922f authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-26623 Possible race condition between statistics and bulk insert

When computing statistics, let us play it safe and check whether
an insert into an empty table is in progress, once we have acquired
the root page latch. If yes, let us pretend that the table is empty,
just like MVCC reads would do.

It is unlikely that this race condition could lead into any crashes
before MDEV-24621, because the index tree structure should be protected
by the page latches. But, at least we can avoid some busy work and
return earlier.

As part of this, some code that is only used for statistics calculation
is being moved into static functions in that compilation unit.
parent 1a4a7ddd
......@@ -273,38 +273,6 @@ btr_root_get(
return(root ? buf_block_get_frame(root) : NULL);
}
/**************************************************************//**
Gets the height of the B-tree (the level of the root, when the leaf
level is assumed to be 0). The caller must hold an S or X latch on
the index.
@return tree height (level of the root) */
ulint
btr_height_get(
/*===========*/
const dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint height=0;
buf_block_t* root_block;
ut_ad(srv_read_only_mode
|| mtr->memo_contains_flagged(&index->lock, MTR_MEMO_S_LOCK
| MTR_MEMO_X_LOCK
| MTR_MEMO_SX_LOCK));
/* S latches the page */
root_block = btr_root_block_get(index, RW_S_LATCH, mtr);
if (root_block) {
height = btr_page_get_level(buf_block_get_frame(root_block));
/* Release the S latch on the root page. */
mtr->memo_release(root_block, MTR_MEMO_PAGE_S_FIX);
}
return(height);
}
/**************************************************************//**
Checks a file segment header within a B-tree root page and updates
the segment header space id.
......@@ -562,48 +530,6 @@ btr_page_alloc(
index, hint_page_no, file_direction, level, mtr, init_mtr);
}
/**************************************************************//**
Gets the number of pages in a B-tree.
@return number of pages, or ULINT_UNDEFINED if the index is unavailable */
ulint
btr_get_size(
/*=========*/
const dict_index_t* index, /*!< in: index */
ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
mtr_t* mtr) /*!< in/out: mini-transaction where index
is s-latched */
{
ulint n=0;
ut_ad(srv_read_only_mode
|| mtr->memo_contains(index->lock, MTR_MEMO_S_LOCK));
ut_ad(flag == BTR_N_LEAF_PAGES || flag == BTR_TOTAL_SIZE);
if (dict_index_is_online_ddl(index)
|| !index->is_committed()) {
return(ULINT_UNDEFINED);
}
buf_block_t* root = btr_root_block_get(index, RW_SX_LATCH, mtr);
if (!root) {
return ULINT_UNDEFINED;
}
mtr->x_lock_space(index->table->space);
if (flag == BTR_N_LEAF_PAGES) {
fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF
+ root->frame, &n, mtr);
} else {
ulint dummy;
n = fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_TOP
+ root->frame, &dummy, mtr);
n += fseg_n_reserved_pages(*root,
PAGE_HEADER + PAGE_BTR_SEG_LEAF
+ root->frame, &dummy, mtr);
}
return(n);
}
/**************************************************************//**
Frees a page used in an ibuf tree. Puts the page to the free list of the
ibuf tree. */
......
This diff is collapsed.
This diff is collapsed.
......@@ -196,18 +196,6 @@ btr_root_adjust_on_import(
const dict_index_t* index) /*!< in: index tree */
MY_ATTRIBUTE((warn_unused_result));
/**************************************************************//**
Gets the height of the B-tree (the level of the root, when the leaf
level is assumed to be 0). The caller must hold an S or X latch on
the index.
@return tree height (level of the root) */
ulint
btr_height_get(
/*===========*/
const dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in/out: mini-transaction */
MY_ATTRIBUTE((warn_unused_result));
/** Get an index page and declare its latching order level.
@param[in] index index tree
@param[in] page page number
......@@ -537,17 +525,6 @@ btr_discard_page(
btr_cur_t* cursor, /*!< in: cursor on the page to discard: not on
the root page */
mtr_t* mtr); /*!< in: mtr */
/**************************************************************//**
Gets the number of pages in a B-tree.
@return number of pages, or ULINT_UNDEFINED if the index is unavailable */
ulint
btr_get_size(
/*=========*/
const dict_index_t* index, /*!< in: index */
ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
mtr_t* mtr) /*!< in/out: mini-transaction where index
is s-latched */
MY_ATTRIBUTE((warn_unused_result));
/**************************************************************//**
Allocates a new file page to be used in an index tree. NOTE: we assume
......@@ -614,7 +591,6 @@ btr_root_block_get(
rw_lock_type_t mode, /*!< in: either RW_S_LATCH
or RW_X_LATCH */
mtr_t* mtr); /*!< in: mtr */
/*************************************************************//**
Reorganizes an index page.
......
......@@ -575,37 +575,6 @@ btr_estimate_n_rows_in_range(
btr_pos_t* range_start,
btr_pos_t* range_end);
/** Statistics for one field of an index. */
struct index_field_stats_t
{
ib_uint64_t n_diff_key_vals;
ib_uint64_t n_sample_sizes;
ib_uint64_t n_non_null_key_vals;
index_field_stats_t(ib_uint64_t n_diff_key_vals= 0,
ib_uint64_t n_sample_sizes= 0,
ib_uint64_t n_non_null_key_vals= 0)
: n_diff_key_vals(n_diff_key_vals), n_sample_sizes(n_sample_sizes),
n_non_null_key_vals(n_non_null_key_vals)
{
}
};
/** Estimates the number of different key values in a given index, for
each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index).
The estimates are stored in the array index->stat_n_diff_key_vals[] (indexed
0..n_uniq-1) and the number of pages that were sampled is saved in
index->stat_n_sample_sizes[].
If innodb_stats_method is nulls_ignored, we also record the number of
non-null values for each prefix and stored the estimates in
array index->stat_n_non_null_key_vals.
@param[in] index index
@return stat vector if the index is available and we get the estimated numbers,
empty vector if the index is unavailable. */
std::vector<index_field_stats_t>
btr_estimate_number_of_different_key_vals(dict_index_t* index);
/** Gets the externally stored size of a record, in units of a database page.
@param[in] rec record
@param[in] offsets array returned by rec_get_offsets()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment