1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-35000 preparation: Clean up dict_table_t::stat

innodb_stats_transient_sample_pages, innodb_stats_persistent_sample_pages:
Change the type to UNSIGNED, because the number of pages in a table
is limited to 32 bits by the InnoDB file format.

btr_get_size_and_reserved(), fseg_get_n_frag_pages(),
fseg_n_reserved_pages_low(), fseg_n_reserved_pages(): Return uint32_t.
The file format limits page numbers to 32 bits.

dict_table_t::stat: An Atomic_relaxed<uint32_t> that combines a
number of metadata fields.

innodb_copy_stat_flags(): Copy the statistics flags from
TABLE_SHARE or HA_CREATE_INFO.

dict_table_t::stats_initialized(), dict_table_t::stats_is_persistent():
Accessors to dict_table_t::stat.

Reviewed by: Thirunarayanan Balathandayuthapani
This commit is contained in:
Marko Mäkelä
2025-02-28 08:55:16 +02:00
parent 1965b2be16
commit 1ed09cfdcb
22 changed files with 226 additions and 398 deletions

View File

@@ -1571,10 +1571,10 @@ VARIABLE_NAME INNODB_STATS_PERSISTENT_SAMPLE_PAGES
SESSION_VALUE NULL SESSION_VALUE NULL
DEFAULT_VALUE 20 DEFAULT_VALUE 20
VARIABLE_SCOPE GLOBAL VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of leaf index pages to sample when calculating persistent statistics (by ANALYZE, default 20) VARIABLE_COMMENT The number of leaf index pages to sample when calculating persistent statistics (by ANALYZE, default 20)
NUMERIC_MIN_VALUE 1 NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 18446744073709551615 NUMERIC_MAX_VALUE 4294967295
NUMERIC_BLOCK_SIZE 0 NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL ENUM_VALUE_LIST NULL
READ_ONLY NO READ_ONLY NO
@@ -1595,10 +1595,10 @@ VARIABLE_NAME INNODB_STATS_TRANSIENT_SAMPLE_PAGES
SESSION_VALUE NULL SESSION_VALUE NULL
DEFAULT_VALUE 8 DEFAULT_VALUE 8
VARIABLE_SCOPE GLOBAL VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of leaf index pages to sample when calculating transient statistics (if persistent statistics are not used, default 8) VARIABLE_COMMENT The number of leaf index pages to sample when calculating transient statistics (if persistent statistics are not used, default 8)
NUMERIC_MIN_VALUE 1 NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 18446744073709551615 NUMERIC_MAX_VALUE 4294967295
NUMERIC_BLOCK_SIZE 0 NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL ENUM_VALUE_LIST NULL
READ_ONLY NO READ_ONLY NO

View File

@@ -284,18 +284,18 @@ release_and_exit:
/**************************************************************//** /**************************************************************//**
Gets the number of reserved and used pages in a B-tree. Gets the number of reserved and used pages in a B-tree.
@return number of pages reserved, or ULINT_UNDEFINED if the index @return number of pages reserved
is unavailable */ @retval 0 if the index is unavailable */
static static
ulint uint32_t
btr_get_size_and_reserved( btr_get_size_and_reserved(
dict_index_t* index, /*!< in: index */ dict_index_t* index, /*!< in: index */
ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
ulint* used, /*!< out: number of pages used (<= reserved) */ uint32_t* used, /*!< out: number of pages used (<= reserved) */
mtr_t* mtr) /*!< in/out: mini-transaction where index mtr_t* mtr) /*!< in/out: mini-transaction where index
is s-latched */ is s-latched */
{ {
ulint dummy; uint32_t dummy;
ut_ad(mtr->memo_contains(index->lock, MTR_MEMO_SX_LOCK)); ut_ad(mtr->memo_contains(index->lock, MTR_MEMO_SX_LOCK));
ut_a(flag == BTR_N_LEAF_PAGES || flag == BTR_TOTAL_SIZE); ut_a(flag == BTR_N_LEAF_PAGES || flag == BTR_TOTAL_SIZE);
@@ -304,19 +304,19 @@ btr_get_size_and_reserved(
|| dict_index_is_online_ddl(index) || dict_index_is_online_ddl(index)
|| !index->is_committed() || !index->is_committed()
|| !index->table->space) { || !index->table->space) {
return(ULINT_UNDEFINED); return 0;
} }
dberr_t err; dberr_t err;
buf_block_t* root = btr_root_block_get(index, RW_SX_LATCH, mtr, &err); buf_block_t* root = btr_root_block_get(index, RW_SX_LATCH, mtr, &err);
*used = 0; *used = 0;
if (!root) { if (!root) {
return ULINT_UNDEFINED; return 0;
} }
mtr->x_lock_space(index->table->space); mtr->x_lock_space(index->table->space);
ulint n = fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF auto n = fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF
+ root->page.frame, used, mtr); + root->page.frame, used, mtr);
if (flag == BTR_TOTAL_SIZE) { if (flag == BTR_TOTAL_SIZE) {
n += fseg_n_reserved_pages(*root, n += fseg_n_reserved_pages(*root,
@@ -343,14 +343,14 @@ dict_stats_save_defrag_stats(
const time_t now= time(nullptr); const time_t now= time(nullptr);
mtr_t mtr; mtr_t mtr;
ulint n_leaf_pages; uint32_t n_leaf_pages;
mtr.start(); mtr.start();
mtr_sx_lock_index(index, &mtr); mtr_sx_lock_index(index, &mtr);
ulint n_leaf_reserved= btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES, uint32_t n_leaf_reserved= btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES,
&n_leaf_pages, &mtr); &n_leaf_pages, &mtr);
mtr.commit(); mtr.commit();
if (n_leaf_reserved == ULINT_UNDEFINED) if (!n_leaf_reserved)
return DB_SUCCESS; return DB_SUCCESS;
THD *thd= current_thd; THD *thd= current_thd;

View File

@@ -198,8 +198,7 @@ dict_tables_have_same_db(
/** Decrement the count of open handles */ /** Decrement the count of open handles */
void dict_table_close(dict_table_t *table) void dict_table_close(dict_table_t *table)
{ {
if (table->get_ref_count() == 1 && if (table->get_ref_count() == 1 && table->stats_is_persistent() &&
dict_stats_is_persistent_enabled(table) &&
strchr(table->name.m_name, '/')) strchr(table->name.m_name, '/'))
{ {
/* It looks like we are closing the last handle. The user could /* It looks like we are closing the last handle. The user could
@@ -238,7 +237,7 @@ dict_table_close(
dict_table_close(table); dict_table_close(table);
else else
{ {
if (table->release() && dict_stats_is_persistent_enabled(table) && if (table->release() && table->stats_is_persistent() &&
strchr(table->name.m_name, '/')) strchr(table->name.m_name, '/'))
{ {
/* Force persistent stats re-read upon next open of the table so /* Force persistent stats re-read upon next open of the table so

View File

@@ -599,7 +599,7 @@ void dict_stats_empty_table(
table->stat_clustered_index_size = 1; table->stat_clustered_index_size = 1;
/* 1 page for each index, not counting the clustered */ /* 1 page for each index, not counting the clustered */
table->stat_sum_of_other_index_sizes table->stat_sum_of_other_index_sizes
= UT_LIST_GET_LEN(table->indexes) - 1; = uint32_t(UT_LIST_GET_LEN(table->indexes) - 1);
table->stat_modified_counter = 0; table->stat_modified_counter = 0;
dict_index_t* index; dict_index_t* index;
@@ -617,7 +617,7 @@ void dict_stats_empty_table(
dict_stats_empty_index(index, empty_defrag_stats); dict_stats_empty_index(index, empty_defrag_stats);
} }
table->stat_initialized = TRUE; table->stat = table->stat | dict_table_t::STATS_INITIALIZED;
table->stats_mutex_unlock(); table->stats_mutex_unlock();
} }
@@ -658,16 +658,10 @@ dict_stats_assert_initialized(
/*==========================*/ /*==========================*/
const dict_table_t* table) /*!< in: table */ const dict_table_t* table) /*!< in: table */
{ {
ut_a(table->stat_initialized);
MEM_CHECK_DEFINED(&table->stats_last_recalc, MEM_CHECK_DEFINED(&table->stats_last_recalc,
sizeof table->stats_last_recalc); sizeof table->stats_last_recalc);
MEM_CHECK_DEFINED(&table->stat_persistent, MEM_CHECK_DEFINED(&table->stat, sizeof table->stat);
sizeof table->stat_persistent);
MEM_CHECK_DEFINED(&table->stats_auto_recalc,
sizeof table->stats_auto_recalc);
MEM_CHECK_DEFINED(&table->stats_sample_pages, MEM_CHECK_DEFINED(&table->stats_sample_pages,
sizeof table->stats_sample_pages); sizeof table->stats_sample_pages);
@@ -844,8 +838,8 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index,
ulint n_cols; ulint n_cols;
ib_uint64_t* n_diff; ib_uint64_t* n_diff;
ib_uint64_t* n_not_null; ib_uint64_t* n_not_null;
ibool stats_null_not_equal; bool stats_null_not_equal;
uintmax_t n_sample_pages=1; /* number of pages to sample */ uint32_t n_sample_pages=1; /* number of pages to sample */
ulint not_empty_flag = 0; ulint not_empty_flag = 0;
ulint total_external_size = 0; ulint total_external_size = 0;
uintmax_t add_on; uintmax_t add_on;
@@ -883,11 +877,11 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index,
case SRV_STATS_NULLS_UNEQUAL: case SRV_STATS_NULLS_UNEQUAL:
/* for both SRV_STATS_NULLS_IGNORED and SRV_STATS_NULLS_UNEQUAL /* for both SRV_STATS_NULLS_IGNORED and SRV_STATS_NULLS_UNEQUAL
case, we will treat NULLs as unequal value */ case, we will treat NULLs as unequal value */
stats_null_not_equal = TRUE; stats_null_not_equal = true;
break; break;
case SRV_STATS_NULLS_EQUAL: case SRV_STATS_NULLS_EQUAL:
stats_null_not_equal = FALSE; stats_null_not_equal = false;
break; break;
default: default:
@@ -938,19 +932,21 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index,
so taking all case2 paths is I, our expression is: so taking all case2 paths is I, our expression is:
n_pages = S < I? min(I,L) : I n_pages = S < I? min(I,L) : I
*/ */
if (index->stat_index_size > 1) { if (uint32_t I = index->stat_index_size) {
n_sample_pages = (srv_stats_transient_sample_pages < index->stat_index_size) const uint32_t S{srv_stats_transient_sample_pages};
? ut_min(index->stat_index_size, n_sample_pages = S < I
static_cast<ulint>( ? std::min(I,
log2(double(index->stat_index_size)) uint32_t(log2(double(I))
* double(srv_stats_transient_sample_pages))) * double(S)))
: index->stat_index_size; : I;
} }
} }
/* Sanity check */ /* Sanity check */
ut_ad(n_sample_pages > 0 && n_sample_pages <= (index->stat_index_size <= 1 ? 1 : index->stat_index_size)); ut_ad(n_sample_pages);
ut_ad(n_sample_pages <= (index->stat_index_size <= 1
? 1 : index->stat_index_size));
/* We sample some pages in the index to get an estimate */ /* We sample some pages in the index to get an estimate */
btr_cur_t cursor; btr_cur_t cursor;
@@ -1169,7 +1165,7 @@ invalid:
mtr.x_lock_space(index->table->space); mtr.x_lock_space(index->table->space);
ulint dummy, size; uint32_t dummy, size;
index->stat_index_size index->stat_index_size
= fseg_n_reserved_pages(*root, PAGE_HEADER = fseg_n_reserved_pages(*root, PAGE_HEADER
+ PAGE_BTR_SEG_LEAF + PAGE_BTR_SEG_LEAF
@@ -1226,7 +1222,7 @@ dict_stats_update_transient(
ut_ad(!table->stats_mutex_is_owner()); ut_ad(!table->stats_mutex_is_owner());
dict_index_t* index; dict_index_t* index;
ulint sum_of_index_sizes = 0; uint32_t sum_of_index_sizes = 0;
dberr_t err = DB_SUCCESS; dberr_t err = DB_SUCCESS;
/* Find out the sizes of the indexes and how many different values /* Find out the sizes of the indexes and how many different values
@@ -1285,7 +1281,7 @@ empty_table:
table->stat_modified_counter = 0; table->stat_modified_counter = 0;
table->stat_initialized = TRUE; table->stat = table->stat | dict_table_t::STATS_INITIALIZED;
table->stats_mutex_unlock(); table->stats_mutex_unlock();
@@ -2225,8 +2221,8 @@ dict_stats_analyze_index_for_n_prefix(
struct index_stats_t struct index_stats_t
{ {
std::vector<index_field_stats_t> stats; std::vector<index_field_stats_t> stats;
ulint index_size; uint32_t index_size;
ulint n_leaf_pages; uint32_t n_leaf_pages;
index_stats_t(ulint n_uniq) : index_size(1), n_leaf_pages(1) index_stats_t(ulint n_uniq) : index_size(1), n_leaf_pages(1)
{ {
@@ -2365,7 +2361,7 @@ empty_index:
uint16_t root_level = btr_page_get_level(root->page.frame); uint16_t root_level = btr_page_get_level(root->page.frame);
mtr.x_lock_space(index->table->space); mtr.x_lock_space(index->table->space);
ulint dummy, size; uint32_t dummy, size;
result.index_size result.index_size
= fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF = fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF
+ root->page.frame, &size, &mtr) + root->page.frame, &size, &mtr)
@@ -2742,7 +2738,7 @@ dict_stats_update_persistent(
table->stat_modified_counter = 0; table->stat_modified_counter = 0;
table->stat_initialized = TRUE; table->stat = table->stat | dict_table_t::STATS_INITIALIZED;
dict_stats_assert_initialized(table); dict_stats_assert_initialized(table);
@@ -3164,8 +3160,7 @@ dict_stats_fetch_table_stats_step(
ut_a(len == 8); ut_a(len == 8);
table->stat_clustered_index_size table->stat_clustered_index_size
= std::max<ulint>( = std::max(mach_read_from_4(data + 4), 1U);
(ulint) mach_read_from_8(data), 1);
break; break;
} }
@@ -3174,18 +3169,9 @@ dict_stats_fetch_table_stats_step(
ut_a(dtype_get_mtype(type) == DATA_INT); ut_a(dtype_get_mtype(type) == DATA_INT);
ut_a(len == 8); ut_a(len == 8);
ulint stat_other_idx_size table->stat_sum_of_other_index_sizes = std::max(
= (ulint) mach_read_from_8(data); mach_read_from_4(data + 4),
if (!stat_other_idx_size uint32_t(UT_LIST_GET_LEN(table->indexes) - 1));
&& UT_LIST_GET_LEN(table->indexes) > 1) {
stat_other_idx_size
= UT_LIST_GET_LEN(table->indexes) - 1;
}
table->stat_sum_of_other_index_sizes
= std::max<ulint>(
(ulint) mach_read_from_8(data),
UT_LIST_GET_LEN(table->indexes) - 1);
break; break;
} }
default: default:
@@ -3370,14 +3356,12 @@ dict_stats_fetch_index_stats_step(
if (stat_name_len == 4 /* strlen("size") */ if (stat_name_len == 4 /* strlen("size") */
&& strncasecmp("size", stat_name, stat_name_len) == 0) { && strncasecmp("size", stat_name, stat_name_len) == 0) {
index->stat_index_size index->stat_index_size = std::max(uint32_t(stat_value), 1U);
= std::max<ulint>((ulint) stat_value, 1);
arg->stats_were_modified = true; arg->stats_were_modified = true;
} else if (stat_name_len == 12 /* strlen("n_leaf_pages") */ } else if (stat_name_len == 12 /* strlen("n_leaf_pages") */
&& strncasecmp("n_leaf_pages", stat_name, stat_name_len) && strncasecmp("n_leaf_pages", stat_name, stat_name_len)
== 0) { == 0) {
index->stat_n_leaf_pages index->stat_n_leaf_pages = std::max(uint32_t(stat_value), 1U);
= std::max<ulint>((ulint) stat_value, 1);
arg->stats_were_modified = true; arg->stats_were_modified = true;
} else if (stat_name_len == 12 /* strlen("n_page_split") */ } else if (stat_name_len == 12 /* strlen("n_page_split") */
&& strncasecmp("n_page_split", stat_name, stat_name_len) && strncasecmp("n_page_split", stat_name, stat_name_len)
@@ -3648,7 +3632,9 @@ dict_stats_update_for_index(
{ {
DBUG_ENTER("dict_stats_update_for_index"); DBUG_ENTER("dict_stats_update_for_index");
if (dict_stats_is_persistent_enabled(index->table)) { ut_ad(index->table->stat_initialized());
if (index->table->stats_is_persistent()) {
if (dict_stats_persistent_storage_check(false)) { if (dict_stats_persistent_storage_check(false)) {
index_stats_t stats = dict_stats_analyze_index(index); index_stats_t stats = dict_stats_analyze_index(index);
@@ -3789,7 +3775,7 @@ dict_stats_update(
/* If table is using persistent stats, /* If table is using persistent stats,
then save the stats on disk */ then save the stats on disk */
if (dict_stats_is_persistent_enabled(table)) { if (table->stats_is_persistent()) {
if (dict_stats_persistent_storage_check(false)) { if (dict_stats_persistent_storage_check(false)) {
@@ -3806,7 +3792,7 @@ dict_stats_update(
/* fetch requested, either fetch from persistent statistics /* fetch requested, either fetch from persistent statistics
storage or use the old method */ storage or use the old method */
if (table->stat_initialized) { if (table->stat_initialized()) {
return(DB_SUCCESS); return(DB_SUCCESS);
} }
@@ -3850,7 +3836,7 @@ dict_stats_update(
goto transient; goto transient;
} }
#endif #endif
if (dict_stats_auto_recalc_is_enabled(table)) { if (table->stats_is_auto_recalc()) {
return(dict_stats_update( return(dict_stats_update(
table, table,
DICT_STATS_RECALC_PERSISTENT)); DICT_STATS_RECALC_PERSISTENT));

View File

@@ -135,7 +135,9 @@ schedule new estimates for table and index statistics to be calculated.
void dict_stats_update_if_needed_func(dict_table_t *table) void dict_stats_update_if_needed_func(dict_table_t *table)
#endif #endif
{ {
if (UNIV_UNLIKELY(!table->stat_initialized)) { uint32_t stat{table->stat};
if (UNIV_UNLIKELY(!table->stat_initialized(stat))) {
/* The table may have been evicted from dict_sys /* The table may have been evicted from dict_sys
and reloaded internally by InnoDB for FOREIGN KEY and reloaded internally by InnoDB for FOREIGN KEY
processing, but not reloaded by the SQL layer. processing, but not reloaded by the SQL layer.
@@ -154,13 +156,9 @@ void dict_stats_update_if_needed_func(dict_table_t *table)
ulonglong counter = table->stat_modified_counter++; ulonglong counter = table->stat_modified_counter++;
ulonglong n_rows = dict_table_get_n_rows(table); ulonglong n_rows = dict_table_get_n_rows(table);
if (dict_stats_is_persistent_enabled(table)) { if (table->stats_is_persistent(stat)) {
if (table->name.is_temporary()) { if (table->stats_is_auto_recalc(stat)
return; && counter > n_rows / 10 && !table->name.is_temporary()) {
}
if (counter > n_rows / 10 /* 10% */
&& dict_stats_auto_recalc_is_enabled(table)) {
#ifdef WITH_WSREP #ifdef WITH_WSREP
/* Do not add table to background /* Do not add table to background
statistic calculation if this thread is not a statistic calculation if this thread is not a

View File

@@ -1644,12 +1644,11 @@ fseg_find_last_used_frag_page_slot(
/** Calculate reserved fragment page slots. /** Calculate reserved fragment page slots.
@param inode file segment index @param inode file segment index
@return number of fragment pages */ @return number of fragment pages */
static ulint fseg_get_n_frag_pages(const fseg_inode_t *inode) static uint32_t fseg_get_n_frag_pages(const fseg_inode_t *inode) noexcept
{ {
ulint i; uint32_t count = 0;
ulint count = 0;
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) { for (ulint i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i)) { if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i)) {
count++; count++;
} }
@@ -1794,21 +1793,24 @@ Calculates the number of pages reserved by a segment, and how many pages are
currently used. currently used.
@return number of reserved pages */ @return number of reserved pages */
static static
ulint uint32_t
fseg_n_reserved_pages_low( fseg_n_reserved_pages_low(
/*======================*/ /*======================*/
const fseg_inode_t* inode, /*!< in: segment inode */ const fseg_inode_t* inode, /*!< in: segment inode */
ulint* used) /*!< out: number of pages used (not uint32_t* used) /*!< out: number of pages used (not
more than reserved) */ more than reserved) */
noexcept
{ {
const uint32_t extent_size = FSP_EXTENT_SIZE;
*used = mach_read_from_4(inode + FSEG_NOT_FULL_N_USED) *used = mach_read_from_4(inode + FSEG_NOT_FULL_N_USED)
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL) + extent_size * flst_get_len(inode + FSEG_FULL)
+ fseg_get_n_frag_pages(inode); + fseg_get_n_frag_pages(inode);
return fseg_get_n_frag_pages(inode) return fseg_get_n_frag_pages(inode)
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE) + extent_size * flst_get_len(inode + FSEG_FREE)
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL) + extent_size * flst_get_len(inode + FSEG_NOT_FULL)
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL); + extent_size * flst_get_len(inode + FSEG_FULL);
} }
/** Calculate the number of pages reserved by a segment, /** Calculate the number of pages reserved by a segment,
@@ -1818,9 +1820,9 @@ and how many pages are currently used.
@param[out] used number of pages that are used (not more than reserved) @param[out] used number of pages that are used (not more than reserved)
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@return number of reserved pages */ @return number of reserved pages */
ulint fseg_n_reserved_pages(const buf_block_t &block, uint32_t fseg_n_reserved_pages(const buf_block_t &block,
const fseg_header_t *header, ulint *used, const fseg_header_t *header, uint32_t *used,
mtr_t *mtr) mtr_t *mtr) noexcept
{ {
ut_ad(page_align(header) == block.page.frame); ut_ad(page_align(header) == block.page.frame);
buf_block_t *iblock; buf_block_t *iblock;
@@ -1845,7 +1847,7 @@ static dberr_t fseg_fill_free_list(const fseg_inode_t *inode,
buf_block_t *iblock, fil_space_t *space, buf_block_t *iblock, fil_space_t *space,
uint32_t hint, mtr_t *mtr) uint32_t hint, mtr_t *mtr)
{ {
ulint used; uint32_t used;
ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
ut_d(space->modify_check(*mtr)); ut_d(space->modify_check(*mtr));
@@ -1996,8 +1998,7 @@ fseg_alloc_free_page_low(
dberr_t* err) dberr_t* err)
{ {
ib_id_t seg_id; ib_id_t seg_id;
ulint used; uint32_t used, reserved;
ulint reserved;
xdes_t* descr; /*!< extent of the hinted page */ xdes_t* descr; /*!< extent of the hinted page */
uint32_t ret_page; /*!< the allocated page offset, FIL_NULL uint32_t ret_page; /*!< the allocated page offset, FIL_NULL
if could not be allocated */ if could not be allocated */

View File

@@ -1622,7 +1622,7 @@ inline void ha_innobase::reload_statistics()
if (table->is_readable()) if (table->is_readable())
dict_stats_init(table); dict_stats_init(table);
else else
table->stat_initialized= 1; table->stat.fetch_or(dict_table_t::STATS_INITIALIZED);
} }
} }
@@ -2978,6 +2978,44 @@ static int innobase_rollback_by_xid(handlerton*, XID *xid) noexcept
return XAER_NOTA; return XAER_NOTA;
} }
/** Initialize the InnoDB persistent statistics attributes.
@param table InnoDB table
@param table_options MariaDB table options
@param sar the value of STATS_AUTO_RECALC
@param initialized whether the InnoDB statistics were already initialized
@return whether table->stats_sample_pages needs to be initialized */
static bool innodb_copy_stat_flags(dict_table_t *table,
ulong table_options,
enum_stats_auto_recalc sar,
bool initialized) noexcept
{
if (table->is_temporary() || table->no_rollback())
{
table->stat= dict_table_t::STATS_INITIALIZED |
dict_table_t::STATS_PERSISTENT_OFF | dict_table_t::STATS_AUTO_RECALC_OFF;
table->stats_sample_pages= 1;
return false;
}
static_assert(HA_OPTION_STATS_PERSISTENT ==
dict_table_t::STATS_PERSISTENT_ON << 11, "");
static_assert(HA_OPTION_NO_STATS_PERSISTENT ==
dict_table_t::STATS_PERSISTENT_OFF << 11, "");
uint32_t stat=
(table_options &
(HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT)) >> 11;
static_assert(uint32_t{HA_STATS_AUTO_RECALC_ON} << 3 ==
dict_table_t::STATS_AUTO_RECALC_ON, "");
static_assert(uint32_t{HA_STATS_AUTO_RECALC_OFF} << 3 ==
dict_table_t::STATS_AUTO_RECALC_OFF, "");
static_assert(true == dict_table_t::STATS_INITIALIZED, "");
stat|= (sar & (HA_STATS_AUTO_RECALC_ON | HA_STATS_AUTO_RECALC_OFF)) << 3 |
initialized;
table->stat= stat;
return true;
}
/*********************************************************************//** /*********************************************************************//**
Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object. Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object.
Those flags are stored in .frm file and end up in the MySQL table object, Those flags are stored in .frm file and end up in the MySQL table object,
@@ -2990,29 +3028,9 @@ innobase_copy_frm_flags_from_create_info(
dict_table_t* innodb_table, /*!< in/out: InnoDB table */ dict_table_t* innodb_table, /*!< in/out: InnoDB table */
const HA_CREATE_INFO* create_info) /*!< in: create info */ const HA_CREATE_INFO* create_info) /*!< in: create info */
{ {
ibool ps_on; if (innodb_copy_stat_flags(innodb_table, create_info->table_options,
ibool ps_off; create_info->stats_auto_recalc, false))
innodb_table->stats_sample_pages= create_info->stats_sample_pages;
if (innodb_table->is_temporary()
|| innodb_table->no_rollback()) {
/* Temp tables do not use persistent stats. */
ps_on = FALSE;
ps_off = TRUE;
} else {
ps_on = create_info->table_options
& HA_OPTION_STATS_PERSISTENT;
ps_off = create_info->table_options
& HA_OPTION_NO_STATS_PERSISTENT;
}
dict_stats_set_persistent(innodb_table, ps_on, ps_off);
dict_stats_auto_recalc_set(
innodb_table,
create_info->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON,
create_info->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF);
innodb_table->stats_sample_pages = create_info->stats_sample_pages;
} }
/*********************************************************************//** /*********************************************************************//**
@@ -3026,28 +3044,10 @@ innobase_copy_frm_flags_from_table_share(
dict_table_t* innodb_table, /*!< in/out: InnoDB table */ dict_table_t* innodb_table, /*!< in/out: InnoDB table */
const TABLE_SHARE* table_share) /*!< in: table share */ const TABLE_SHARE* table_share) /*!< in: table share */
{ {
ibool ps_on; if (innodb_copy_stat_flags(innodb_table, table_share->db_create_options,
ibool ps_off; table_share->stats_auto_recalc,
innodb_table->stat_initialized()))
if (innodb_table->is_temporary()) { innodb_table->stats_sample_pages= table_share->stats_sample_pages;
/* Temp tables do not use persistent stats */
ps_on = FALSE;
ps_off = TRUE;
} else {
ps_on = table_share->db_create_options
& HA_OPTION_STATS_PERSISTENT;
ps_off = table_share->db_create_options
& HA_OPTION_NO_STATS_PERSISTENT;
}
dict_stats_set_persistent(innodb_table, ps_on, ps_off);
dict_stats_auto_recalc_set(
innodb_table,
table_share->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON,
table_share->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF);
innodb_table->stats_sample_pages = table_share->stats_sample_pages;
} }
/*********************************************************************//** /*********************************************************************//**
@@ -13387,6 +13387,8 @@ ha_innobase::discard_or_import_tablespace(
DBUG_RETURN(HA_ERR_TABLE_NEEDS_UPGRADE); DBUG_RETURN(HA_ERR_TABLE_NEEDS_UPGRADE);
} }
ut_ad(m_prebuilt->table->stat_initialized());
if (m_prebuilt->table->space == fil_system.sys_space) { if (m_prebuilt->table->space == fil_system.sys_space) {
ib_senderrf( ib_senderrf(
m_prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR, m_prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
@@ -13460,7 +13462,7 @@ ha_innobase::discard_or_import_tablespace(
err, m_prebuilt->table->flags, NULL)); err, m_prebuilt->table->flags, NULL));
} }
if (dict_stats_is_persistent_enabled(m_prebuilt->table)) { if (m_prebuilt->table->stats_is_persistent()) {
dberr_t ret; dberr_t ret;
/* Adjust the persistent statistics. */ /* Adjust the persistent statistics. */
@@ -13645,7 +13647,7 @@ int ha_innobase::delete_table(const char *name)
/* This looks like the rollback of ALTER TABLE...ADD PARTITION /* This looks like the rollback of ALTER TABLE...ADD PARTITION
that was caused by MDL timeout. We could have written undo log that was caused by MDL timeout. We could have written undo log
for inserting the data into the new partitions. */ for inserting the data into the new partitions. */
if (table->stat_persistent != DICT_STATS_PERSISTENT_OFF) if (!(table->stat & dict_table_t::STATS_PERSISTENT_OFF))
{ {
/* We do not really know if we are holding MDL_EXCLUSIVE. Even /* We do not really know if we are holding MDL_EXCLUSIVE. Even
though this code is handling the case that we are not holding though this code is handling the case that we are not holding
@@ -13660,7 +13662,7 @@ int ha_innobase::delete_table(const char *name)
DEBUG_SYNC(thd, "before_delete_table_stats"); DEBUG_SYNC(thd, "before_delete_table_stats");
if (err == DB_SUCCESS && dict_stats_is_persistent_enabled(table) && if (err == DB_SUCCESS && table->stats_is_persistent() &&
!table->is_stats_table()) !table->is_stats_table())
{ {
table_stats= dict_table_open_on_name(TABLE_STATS_NAME, false, table_stats= dict_table_open_on_name(TABLE_STATS_NAME, false,
@@ -14033,7 +14035,7 @@ int ha_innobase::truncate()
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }
if (error == DB_SUCCESS && dict_stats_is_persistent_enabled(ib_table) && if (error == DB_SUCCESS && ib_table->stats_is_persistent() &&
!ib_table->is_stats_table()) !ib_table->is_stats_table())
{ {
table_stats= dict_table_open_on_name(TABLE_STATS_NAME, false, table_stats= dict_table_open_on_name(TABLE_STATS_NAME, false,
@@ -14529,7 +14531,7 @@ ha_innobase::scan_time()
ulint stat_clustered_index_size; ulint stat_clustered_index_size;
ut_a(m_prebuilt->table->stat_initialized); ut_ad(m_prebuilt->table->stat_initialized());
stat_clustered_index_size = stat_clustered_index_size =
m_prebuilt->table->stat_clustered_index_size; m_prebuilt->table->stat_clustered_index_size;
@@ -14656,7 +14658,7 @@ innodb_rec_per_key(
rec_per_key_t rec_per_key; rec_per_key_t rec_per_key;
ib_uint64_t n_diff; ib_uint64_t n_diff;
ut_a(index->table->stat_initialized); ut_ad(index->table->stat_initialized());
ut_ad(i < dict_index_get_n_unique(index)); ut_ad(i < dict_index_get_n_unique(index));
ut_ad(!dict_index_is_spatial(index)); ut_ad(!dict_index_is_spatial(index));
@@ -14806,7 +14808,7 @@ ha_innobase::info_low(
m_prebuilt->trx->op_info = "updating table statistics"; m_prebuilt->trx->op_info = "updating table statistics";
if (dict_stats_is_persistent_enabled(ib_table)) { if (ib_table->stats_is_persistent()) {
if (is_analyze) { if (is_analyze) {
if (!srv_read_only_mode) { if (!srv_read_only_mode) {
dict_stats_recalc_pool_del( dict_stats_recalc_pool_del(
@@ -14844,7 +14846,7 @@ ha_innobase::info_low(
ulint stat_clustered_index_size; ulint stat_clustered_index_size;
ulint stat_sum_of_other_index_sizes; ulint stat_sum_of_other_index_sizes;
ut_a(ib_table->stat_initialized); ut_ad(ib_table->stat_initialized());
#if !defined NO_ELISION && !defined SUX_LOCK_GENERIC #if !defined NO_ELISION && !defined SUX_LOCK_GENERIC
if (xbegin()) { if (xbegin()) {
@@ -14998,7 +15000,7 @@ ha_innobase::info_low(
auto _ = make_scope_exit([ib_table]() { auto _ = make_scope_exit([ib_table]() {
ib_table->stats_shared_unlock(); }); ib_table->stats_shared_unlock(); });
ut_a(ib_table->stat_initialized); ut_ad(ib_table->stat_initialized());
for (uint i = 0; i < table->s->keys; i++) { for (uint i = 0; i < table->s->keys; i++) {
ulong j; ulong j;
@@ -15925,8 +15927,7 @@ ha_innobase::extra(
/* During copy alter operation, InnoDB /* During copy alter operation, InnoDB
updates the stats only for non-persistent updates the stats only for non-persistent
tables. */ tables. */
if (!dict_stats_is_persistent_enabled( if (!m_prebuilt->table->stats_is_persistent()) {
m_prebuilt->table)) {
dict_stats_update_if_needed( dict_stats_update_if_needed(
m_prebuilt->table, *trx); m_prebuilt->table, *trx);
} }
@@ -19156,12 +19157,12 @@ static MYSQL_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
" SHOW TABLE STATUS for tables that use transient statistics (off by default)", " SHOW TABLE STATUS for tables that use transient statistics (off by default)",
NULL, NULL, FALSE); NULL, NULL, FALSE);
static MYSQL_SYSVAR_ULONGLONG(stats_transient_sample_pages, static MYSQL_SYSVAR_UINT(stats_transient_sample_pages,
srv_stats_transient_sample_pages, srv_stats_transient_sample_pages,
PLUGIN_VAR_RQCMDARG, PLUGIN_VAR_RQCMDARG,
"The number of leaf index pages to sample when calculating transient" "The number of leaf index pages to sample when calculating transient"
" statistics (if persistent statistics are not used, default 8)", " statistics (if persistent statistics are not used, default 8)",
NULL, NULL, 8, 1, ~0ULL, 0); NULL, NULL, 8, 1, ~0U, 0);
static MYSQL_SYSVAR_BOOL(stats_persistent, srv_stats_persistent, static MYSQL_SYSVAR_BOOL(stats_persistent, srv_stats_persistent,
PLUGIN_VAR_OPCMDARG, PLUGIN_VAR_OPCMDARG,
@@ -19177,12 +19178,12 @@ static MYSQL_SYSVAR_BOOL(stats_auto_recalc, srv_stats_auto_recalc,
" new statistics)", " new statistics)",
NULL, NULL, TRUE); NULL, NULL, TRUE);
static MYSQL_SYSVAR_ULONGLONG(stats_persistent_sample_pages, static MYSQL_SYSVAR_UINT(stats_persistent_sample_pages,
srv_stats_persistent_sample_pages, srv_stats_persistent_sample_pages,
PLUGIN_VAR_RQCMDARG, PLUGIN_VAR_RQCMDARG,
"The number of leaf index pages to sample when calculating persistent" "The number of leaf index pages to sample when calculating persistent"
" statistics (by ANALYZE, default 20)", " statistics (by ANALYZE, default 20)",
NULL, NULL, 20, 1, ~0ULL, 0); NULL, NULL, 20, 1, ~0U, 0);
static MYSQL_SYSVAR_ULONGLONG(stats_modified_counter, srv_stats_modified_counter, static MYSQL_SYSVAR_ULONGLONG(stats_modified_counter, srv_stats_modified_counter,
PLUGIN_VAR_RQCMDARG, PLUGIN_VAR_RQCMDARG,

View File

@@ -11180,7 +11180,7 @@ alter_stats_norebuild(
DBUG_ENTER("alter_stats_norebuild"); DBUG_ENTER("alter_stats_norebuild");
DBUG_ASSERT(!ctx->need_rebuild()); DBUG_ASSERT(!ctx->need_rebuild());
if (!dict_stats_is_persistent_enabled(ctx->new_table)) { if (!ctx->new_table->stats_is_persistent()) {
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@@ -11214,8 +11214,7 @@ alter_stats_rebuild(
{ {
DBUG_ENTER("alter_stats_rebuild"); DBUG_ENTER("alter_stats_rebuild");
if (!table->space if (!table->space || !table->stats_is_persistent()) {
|| !dict_stats_is_persistent_enabled(table)) {
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }

View File

@@ -4777,9 +4777,9 @@ i_s_dict_fill_sys_tablestats(THD* thd, dict_table_t *table,
OK(field_store_string(fields[SYS_TABLESTATS_NAME], OK(field_store_string(fields[SYS_TABLESTATS_NAME],
table->name.m_name)); table->name.m_name));
OK(fields[SYS_TABLESTATS_INIT]->store(table->stat_initialized, true)); OK(fields[SYS_TABLESTATS_INIT]->store(table->stat_initialized(), true));
if (table->stat_initialized) if (table->stat_initialized())
{ {
OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows, true)); OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows, true));

View File

@@ -375,7 +375,7 @@ ibuf_size_update(
ibuf.free_list_len = flst_get_len(root + PAGE_HEADER ibuf.free_list_len = flst_get_len(root + PAGE_HEADER
+ PAGE_BTR_IBUF_FREE_LIST); + PAGE_BTR_IBUF_FREE_LIST);
ibuf.height = 1 + btr_page_get_level(root); ibuf.height = uint8_t(1 + btr_page_get_level(root));
/* the '1 +' is the ibuf header page */ /* the '1 +' is the ibuf header page */
ibuf.size = ibuf.seg_size - (1 + ibuf.free_list_len); ibuf.size = ibuf.seg_size - (1 + ibuf.free_list_len);
@@ -443,18 +443,11 @@ err_exit:
goto err_exit; goto err_exit;
} }
/* At startup we intialize ibuf to have a maximum of
CHANGE_BUFFER_DEFAULT_SIZE in terms of percentage of the
buffer pool size. Once ibuf struct is initialized this
value is updated with the user supplied size by calling
ibuf_max_size_update(). */
ibuf.max_size = ((buf_pool_get_curr_size() >> srv_page_size_shift)
* CHANGE_BUFFER_DEFAULT_SIZE) / 100;
mysql_mutex_init(ibuf_mutex_key, &ibuf_mutex, nullptr); mysql_mutex_init(ibuf_mutex_key, &ibuf_mutex, nullptr);
mysql_mutex_init(ibuf_pessimistic_insert_mutex_key, mysql_mutex_init(ibuf_pessimistic_insert_mutex_key,
&ibuf_pessimistic_insert_mutex, nullptr); &ibuf_pessimistic_insert_mutex, nullptr);
ibuf_max_size_update(CHANGE_BUFFER_DEFAULT_SIZE);
mysql_mutex_lock(&ibuf_mutex); mysql_mutex_lock(&ibuf_mutex);
ibuf_size_update(root); ibuf_size_update(root);
mysql_mutex_unlock(&ibuf_mutex); mysql_mutex_unlock(&ibuf_mutex);
@@ -506,10 +499,12 @@ ibuf_max_size_update(
percentage of the buffer pool size */ percentage of the buffer pool size */
{ {
if (UNIV_UNLIKELY(!ibuf.index)) return; if (UNIV_UNLIKELY(!ibuf.index)) return;
ulint new_size = ((buf_pool_get_curr_size() >> srv_page_size_shift) ulint new_size = std::min<ulint>(
* new_val) / 100; (buf_pool_get_curr_size() >> srv_page_size_shift) * new_val
/ 100, uint32_t(~0U));
mysql_mutex_lock(&ibuf_mutex); mysql_mutex_lock(&ibuf_mutex);
ibuf.max_size = new_size; ibuf.max_size = uint32_t(new_size);
mysql_mutex_unlock(&ibuf_mutex); mysql_mutex_unlock(&ibuf_mutex);
} }
@@ -4483,17 +4478,17 @@ ibuf_print(
return; return;
} }
const ulint size= ibuf.size; const uint32_t size= ibuf.size;
const ulint free_list_len= ibuf.free_list_len; const uint32_t free_list_len= ibuf.free_list_len;
const ulint seg_size= ibuf.seg_size; const uint32_t seg_size= ibuf.seg_size;
mysql_mutex_unlock(&ibuf_mutex); mysql_mutex_unlock(&ibuf_mutex);
fprintf(file, fprintf(file,
"-------------\n" "-------------\n"
"INSERT BUFFER\n" "INSERT BUFFER\n"
"-------------\n" "-------------\n"
"size " ULINTPF ", free list len " ULINTPF "," "size %" PRIu32 ", free list len %" PRIu32 ","
" seg size " ULINTPF ", " ULINTPF " merges\n", " seg size %" PRIu32 ", " ULINTPF " merges\n",
size, free_list_len, seg_size, ulint{ibuf.n_merges}); size, free_list_len, seg_size, ulint{ibuf.n_merges});
ibuf_print_ops("merged operations:\n", ibuf.n_merged_ops, file); ibuf_print_ops("merged operations:\n", ibuf.n_merged_ops, file);
ibuf_print_ops("discarded operations:\n", ibuf.n_discarded_ops, file); ibuf_print_ops("discarded operations:\n", ibuf.n_discarded_ops, file);

View File

@@ -674,7 +674,7 @@ TPOOL_SUPPRESS_TSAN
@return estimated number of rows */ @return estimated number of rows */
inline uint64_t dict_table_get_n_rows(const dict_table_t *table) inline uint64_t dict_table_get_n_rows(const dict_table_t *table)
{ {
ut_ad(table->stat_initialized); ut_ad(table->stat_initialized());
return table->stat_n_rows; return table->stat_n_rows;
} }

View File

@@ -1106,10 +1106,10 @@ struct dict_index_t {
is indexed from 0 to n_uniq-1); This is indexed from 0 to n_uniq-1); This
is used when innodb_stats_method is is used when innodb_stats_method is
"nulls_ignored". */ "nulls_ignored". */
ulint stat_index_size; uint32_t stat_index_size;
/*!< approximate index size in /*!< approximate index size in
database pages */ database pages */
ulint stat_n_leaf_pages; uint32_t stat_n_leaf_pages;
/*!< approximate number of leaf pages in the /*!< approximate number of leaf pages in the
index tree */ index tree */
bool stats_error_printed; bool stats_error_printed;
@@ -2358,63 +2358,32 @@ public:
/** Statistics for query optimization. Mostly protected by /** Statistics for query optimization. Mostly protected by
dict_sys.latch and stats_mutex_lock(). @{ */ dict_sys.latch and stats_mutex_lock(). @{ */
/** TRUE if statistics have been calculated the first time after
database startup or table creation. */
unsigned stat_initialized:1;
/** Timestamp of last recalc of the stats. */ /** Timestamp of last recalc of the stats. */
time_t stats_last_recalc; time_t stats_last_recalc;
/** The two bits below are set in the 'stat_persistent' member. They static constexpr uint32_t STATS_INITIALIZED= 1U;
have the following meaning: static constexpr uint32_t STATS_PERSISTENT_ON= 1U << 1;
1. _ON=0, _OFF=0, no explicit persistent stats setting for this table, static constexpr uint32_t STATS_PERSISTENT_OFF= 1U << 2;
the value of the global srv_stats_persistent is used to determine static constexpr uint32_t STATS_AUTO_RECALC_ON= 1U << 3;
whether the table has persistent stats enabled or not static constexpr uint32_t STATS_AUTO_RECALC_OFF= 1U << 4;
2. _ON=0, _OFF=1, persistent stats are explicitly disabled for this
table, regardless of the value of the global srv_stats_persistent
3. _ON=1, _OFF=0, persistent stats are explicitly enabled for this
table, regardless of the value of the global srv_stats_persistent
4. _ON=1, _OFF=1, not allowed, we assert if this ever happens. */
#define DICT_STATS_PERSISTENT_ON (1 << 1)
#define DICT_STATS_PERSISTENT_OFF (1 << 2)
/** Indicates whether the table uses persistent stats or not. See /** flags for index cardinality statistics */
DICT_STATS_PERSISTENT_ON and DICT_STATS_PERSISTENT_OFF. */ Atomic_relaxed<uint32_t> stat;
ib_uint32_t stat_persistent; /** Approximate clustered index size in database pages. */
uint32_t stat_clustered_index_size;
/** Approximate size of other indexes in database pages. */
uint32_t stat_sum_of_other_index_sizes;
/** The two bits below are set in the 'stats_auto_recalc' member. They
have the following meaning:
1. _ON=0, _OFF=0, no explicit auto recalc setting for this table, the
value of the global srv_stats_persistent_auto_recalc is used to
determine whether the table has auto recalc enabled or not
2. _ON=0, _OFF=1, auto recalc is explicitly disabled for this table,
regardless of the value of the global srv_stats_persistent_auto_recalc
3. _ON=1, _OFF=0, auto recalc is explicitly enabled for this table,
regardless of the value of the global srv_stats_persistent_auto_recalc
4. _ON=1, _OFF=1, not allowed, we assert if this ever happens. */
#define DICT_STATS_AUTO_RECALC_ON (1 << 1)
#define DICT_STATS_AUTO_RECALC_OFF (1 << 2)
/** Indicates whether the table uses automatic recalc for persistent /** The number of pages to sample for this table during persistent
stats or not. See DICT_STATS_AUTO_RECALC_ON and stats estimation. If this is 0, then the value of the global
DICT_STATS_AUTO_RECALC_OFF. */ srv_stats_persistent_sample_pages will be used instead. */
ib_uint32_t stats_auto_recalc; uint32_t stats_sample_pages;
/** The number of pages to sample for this table during persistent
stats estimation. If this is 0, then the value of the global
srv_stats_persistent_sample_pages will be used instead. */
ulint stats_sample_pages;
/** Approximate number of rows in the table. We periodically calculate /** Approximate number of rows in the table. We periodically calculate
new estimates. */ new estimates. */
ib_uint64_t stat_n_rows; ib_uint64_t stat_n_rows;
/** Approximate clustered index size in database pages. */
ulint stat_clustered_index_size;
/** Approximate size of other indexes in database pages. */
ulint stat_sum_of_other_index_sizes;
/** How many rows are modified since last stats recalc. When a row is /** How many rows are modified since last stats recalc. When a row is
inserted, updated, or deleted, we add 1 to this number; we calculate inserted, updated, or deleted, we add 1 to this number; we calculate
new estimates for the table and the indexes if the table has changed new estimates for the table and the indexes if the table has changed
@@ -2551,6 +2520,35 @@ public:
/** @return the index for that starts with a specific column */ /** @return the index for that starts with a specific column */
dict_index_t *get_index(const dict_col_t &col) const; dict_index_t *get_index(const dict_col_t &col) const;
/** @return whether the statistics are initialized */
static bool stat_initialized(uint32_t stat) noexcept
{ return stat & STATS_INITIALIZED; }
/** @return whether STATS_PERSISTENT is enabled */
static bool stats_is_persistent(uint32_t stat) noexcept
{
ut_ad(~(stat & (STATS_PERSISTENT_ON | STATS_PERSISTENT_OFF)));
if (stat & STATS_PERSISTENT_ON) return true;
return !(stat & STATS_PERSISTENT_OFF) && srv_stats_persistent;
}
/** @return whether STATS_AUTO_RECALC is enabled */
static bool stats_is_auto_recalc(uint32_t stat) noexcept
{
ut_ad(stat_initialized(stat));
ut_ad(~(stat & (STATS_AUTO_RECALC_ON | STATS_AUTO_RECALC_OFF)));
if (stat & STATS_AUTO_RECALC_ON) return true;
return !(stat & STATS_AUTO_RECALC_OFF) && srv_stats_auto_recalc;
}
/** @return whether the statistics are initialized */
bool stat_initialized() const noexcept { return stat_initialized(stat); }
/** @return whether STATS_PERSISTENT is enabled */
bool stats_is_persistent() const noexcept
{ return stats_is_persistent(stat); }
/** @return whether STATS_AUTO_RECALC is enabled */
bool stats_is_auto_recalc() const noexcept
{ return stats_is_auto_recalc(stat); }
/** Create metadata. /** Create metadata.
@param name table name @param name table name
@param space tablespace @param space tablespace

View File

@@ -52,44 +52,6 @@ enum dict_stats_upd_option_t {
otherwise do nothing */ otherwise do nothing */
}; };
/*********************************************************************//**
Set the persistent statistics flag for a given table. This is set only
in the in-memory table object and is not saved on disk. It will be read
from the .frm file upon first open from MySQL after a server restart. */
UNIV_INLINE
void
dict_stats_set_persistent(
/*======================*/
dict_table_t* table, /*!< in/out: table */
ibool ps_on, /*!< in: persistent stats explicitly enabled */
ibool ps_off) /*!< in: persistent stats explicitly disabled */
MY_ATTRIBUTE((nonnull));
/** @return whether persistent statistics is enabled for a given table */
UNIV_INLINE
bool
dict_stats_is_persistent_enabled(const dict_table_t* table)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/*********************************************************************//**
Set the auto recalc flag for a given table (only honored for a persistent
stats enabled table). The flag is set only in the in-memory table object
and is not saved in InnoDB files. It will be read from the .frm file upon
first open from MySQL after a server restart. */
UNIV_INLINE
void
dict_stats_auto_recalc_set(
/*=======================*/
dict_table_t* table, /*!< in/out: table */
ibool auto_recalc_on, /*!< in: explicitly enabled */
ibool auto_recalc_off); /*!< in: explicitly disabled */
/** @return whether auto recalc is enabled for a given table*/
UNIV_INLINE
bool
dict_stats_auto_recalc_is_enabled(const dict_table_t* table)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/*********************************************************************//** /*********************************************************************//**
Initialize table's stats for the first time when opening a table. */ Initialize table's stats for the first time when opening a table. */
UNIV_INLINE UNIV_INLINE

View File

@@ -25,120 +25,6 @@ Created Jan 23, 2012 Vasil Dimov
*******************************************************/ *******************************************************/
#include "dict0dict.h" #include "dict0dict.h"
#include "srv0srv.h"
/*********************************************************************//**
Set the persistent statistics flag for a given table. This is set only
in the in-memory table object and is not saved on disk. It will be read
from the .frm file upon first open from MySQL after a server restart. */
UNIV_INLINE
void
dict_stats_set_persistent(
/*======================*/
dict_table_t* table, /*!< in/out: table */
ibool ps_on, /*!< in: persistent stats explicitly enabled */
ibool ps_off) /*!< in: persistent stats explicitly disabled */
{
/* Not allowed to have both flags set, but a CREATE or ALTER
statement that contains "STATS_PERSISTENT=0 STATS_PERSISTENT=1" would
end up having both set. In this case we clear the OFF flag. */
if (ps_on && ps_off) {
ps_off = FALSE;
}
ib_uint32_t stat_persistent = 0;
if (ps_on) {
stat_persistent |= DICT_STATS_PERSISTENT_ON;
}
if (ps_off) {
stat_persistent |= DICT_STATS_PERSISTENT_OFF;
}
/* we rely on this assignment to be atomic */
table->stat_persistent = stat_persistent;
}
/** @return whether persistent statistics is enabled for a given table */
UNIV_INLINE
bool
dict_stats_is_persistent_enabled(const dict_table_t* table)
{
/* Because of the nature of this check (non-locking) it is possible
that a table becomes:
* PS-disabled immediately after this function has returned TRUE or
* PS-enabled immediately after this function has returned FALSE.
This means that it is possible that we do:
+ dict_stats_update(DICT_STATS_RECALC_PERSISTENT) on a table that has
just been PS-disabled or
+ dict_stats_update(DICT_STATS_RECALC_TRANSIENT) on a table that has
just been PS-enabled.
This is acceptable. Avoiding this would mean that we would have to
hold dict_sys.latch or stats_mutex_lock() like for accessing the
other ::stat_ members which would be too big performance penalty,
especially when this function is called from
dict_stats_update_if_needed(). */
/* we rely on this read to be atomic */
ib_uint32_t stat_persistent = table->stat_persistent;
if (stat_persistent & DICT_STATS_PERSISTENT_ON) {
ut_ad(!(stat_persistent & DICT_STATS_PERSISTENT_OFF));
return(true);
} else if (stat_persistent & DICT_STATS_PERSISTENT_OFF) {
return(false);
} else {
return(srv_stats_persistent);
}
}
/*********************************************************************//**
Set the auto recalc flag for a given table (only honored for a persistent
stats enabled table). The flag is set only in the in-memory table object
and is not saved in InnoDB files. It will be read from the .frm file upon
first open from MySQL after a server restart. */
UNIV_INLINE
void
dict_stats_auto_recalc_set(
/*=======================*/
dict_table_t* table, /*!< in/out: table */
ibool auto_recalc_on, /*!< in: explicitly enabled */
ibool auto_recalc_off) /*!< in: explicitly disabled */
{
ut_ad(!auto_recalc_on || !auto_recalc_off);
ib_uint32_t stats_auto_recalc = 0;
if (auto_recalc_on) {
stats_auto_recalc |= DICT_STATS_AUTO_RECALC_ON;
}
if (auto_recalc_off) {
stats_auto_recalc |= DICT_STATS_AUTO_RECALC_OFF;
}
/* we rely on this assignment to be atomic */
table->stats_auto_recalc = stats_auto_recalc;
}
/** @return whether auto recalc is enabled for a given table*/
UNIV_INLINE
bool
dict_stats_auto_recalc_is_enabled(const dict_table_t* table)
{
/* we rely on this read to be atomic */
ib_uint32_t stats_auto_recalc = table->stats_auto_recalc;
if (stats_auto_recalc & DICT_STATS_AUTO_RECALC_ON) {
ut_ad(!(stats_auto_recalc & DICT_STATS_AUTO_RECALC_OFF));
return(true);
} else if (stats_auto_recalc & DICT_STATS_AUTO_RECALC_OFF) {
return(false);
} else {
return(srv_stats_auto_recalc);
}
}
/*********************************************************************//** /*********************************************************************//**
Initialize table's stats for the first time when opening a table. */ Initialize table's stats for the first time when opening a table. */
@@ -150,13 +36,15 @@ dict_stats_init(
{ {
ut_ad(!table->stats_mutex_is_owner()); ut_ad(!table->stats_mutex_is_owner());
if (table->stat_initialized) { uint32_t stat = table->stat;
if (stat & dict_table_t::STATS_INITIALIZED) {
return; return;
} }
dict_stats_upd_option_t opt; dict_stats_upd_option_t opt;
if (dict_stats_is_persistent_enabled(table)) { if (table->stats_is_persistent(stat)) {
opt = DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY; opt = DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY;
} else { } else {
opt = DICT_STATS_RECALC_TRANSIENT; opt = DICT_STATS_RECALC_TRANSIENT;
@@ -178,7 +66,7 @@ dict_stats_deinit(
ut_ad(table->get_ref_count() == 0); ut_ad(table->get_ref_count() == 0);
#ifdef HAVE_valgrind #ifdef HAVE_valgrind
if (!table->stat_initialized) { if (!table->stat_initialized()) {
return; return;
} }
@@ -215,5 +103,6 @@ dict_stats_deinit(
sizeof(index->stat_n_leaf_pages)); sizeof(index->stat_n_leaf_pages));
} }
#endif /* HAVE_valgrind */ #endif /* HAVE_valgrind */
table->stat_initialized = FALSE;
table->stat = table->stat & ~dict_table_t::STATS_INITIALIZED;
} }

View File

@@ -355,9 +355,9 @@ and how many pages are currently used.
@param[out] used number of pages that are used (not more than reserved) @param[out] used number of pages that are used (not more than reserved)
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@return number of reserved pages */ @return number of reserved pages */
ulint fseg_n_reserved_pages(const buf_block_t &block, uint32_t fseg_n_reserved_pages(const buf_block_t &block,
const fseg_header_t *header, ulint *used, const fseg_header_t *header, uint32_t *used,
mtr_t *mtr) mtr_t *mtr) noexcept
MY_ATTRIBUTE((nonnull)); MY_ATTRIBUTE((nonnull));
/**********************************************************************//** /**********************************************************************//**
Allocates a single free page from a segment. This function implements Allocates a single free page from a segment. This function implements

View File

@@ -62,11 +62,11 @@ extern ulong innodb_change_buffering;
/** Insert buffer struct */ /** Insert buffer struct */
struct ibuf_t{ struct ibuf_t{
Atomic_relaxed<ulint> size; /*!< current size of the ibuf index Atomic_relaxed<uint32_t> size; /*!< current size of the ibuf index
tree, in pages */ tree, in pages */
Atomic_relaxed<ulint> max_size; /*!< recommended maximum size of the Atomic_relaxed<uint32_t> max_size;/*!< recommended maximum size of the
ibuf index tree, in pages */ ibuf index tree, in pages */
ulint seg_size; /*!< allocated pages of the file uint32_t seg_size; /*!< allocated pages of the file
segment containing ibuf header and segment containing ibuf header and
tree */ tree */
bool empty; /*!< Protected by the page bool empty; /*!< Protected by the page
@@ -75,8 +75,8 @@ struct ibuf_t{
(FSP_IBUF_TREE_ROOT_PAGE_NO). true (FSP_IBUF_TREE_ROOT_PAGE_NO). true
if and only if the insert if and only if the insert
buffer tree is empty. */ buffer tree is empty. */
ulint free_list_len; /*!< length of the free list */ uint8_t height; /*!< tree height */
ulint height; /*!< tree height */ uint32_t free_list_len; /*!< length of the free list */
dict_index_t* index; /*!< insert buffer index */ dict_index_t* index; /*!< insert buffer index */
/** number of pages merged */ /** number of pages merged */

View File

@@ -294,9 +294,9 @@ extern uint srv_fast_shutdown;
extern ibool srv_innodb_status; extern ibool srv_innodb_status;
extern unsigned long long srv_stats_transient_sample_pages; extern uint32_t srv_stats_transient_sample_pages;
extern my_bool srv_stats_persistent; extern my_bool srv_stats_persistent;
extern unsigned long long srv_stats_persistent_sample_pages; extern uint32_t srv_stats_persistent_sample_pages;
extern my_bool srv_stats_auto_recalc; extern my_bool srv_stats_auto_recalc;
extern my_bool srv_stats_include_delete_marked; extern my_bool srv_stats_include_delete_marked;
extern unsigned long long srv_stats_modified_counter; extern unsigned long long srv_stats_modified_counter;

View File

@@ -1599,7 +1599,7 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
ut_a(prebuilt->magic_n == ROW_PREBUILT_ALLOCATED); ut_a(prebuilt->magic_n == ROW_PREBUILT_ALLOCATED);
ut_a(prebuilt->magic_n2 == ROW_PREBUILT_ALLOCATED); ut_a(prebuilt->magic_n2 == ROW_PREBUILT_ALLOCATED);
ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW); ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
ut_ad(table->stat_initialized); ut_ad(table->stat_initialized());
if (!table->is_readable()) { if (!table->is_readable()) {
return row_mysql_get_table_error(trx, table); return row_mysql_get_table_error(trx, table);

View File

@@ -1564,7 +1564,7 @@ row_purge_record_func(
case TRX_UNDO_DEL_MARK_REC: case TRX_UNDO_DEL_MARK_REC:
purged = row_purge_del_mark(node); purged = row_purge_del_mark(node);
if (purged) { if (purged) {
if (node->table->stat_initialized if (node->table->stat_initialized()
&& srv_stats_include_delete_marked) { && srv_stats_include_delete_marked) {
dict_stats_update_if_needed( dict_stats_update_if_needed(
node->table, *thr->graph->trx); node->table, *thr->graph->trx);

View File

@@ -614,7 +614,7 @@ row_undo_ins(
err = row_undo_ins_remove_clust_rec(node); err = row_undo_ins_remove_clust_rec(node);
} }
if (err == DB_SUCCESS && node->table->stat_initialized) { if (err == DB_SUCCESS && node->table->stat_initialized()) {
/* Not protected by dict_sys.latch /* Not protected by dict_sys.latch
or table->stats_mutex_lock() for or table->stats_mutex_lock() for
performance reasons, we would rather get garbage performance reasons, we would rather get garbage

View File

@@ -1388,7 +1388,7 @@ rollback_clust:
bool update_statistics bool update_statistics
= !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE); = !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE);
if (err == DB_SUCCESS && node->table->stat_initialized) { if (err == DB_SUCCESS && node->table->stat_initialized()) {
switch (node->rec_type) { switch (node->rec_type) {
case TRX_UNDO_UPD_EXIST_REC: case TRX_UNDO_UPD_EXIST_REC:
break; break;

View File

@@ -291,13 +291,13 @@ this many index pages, there are 2 ways to calculate statistics:
in the innodb database. in the innodb database.
* quick transient stats, that are used if persistent stats for the given * quick transient stats, that are used if persistent stats for the given
table/index are not found in the innodb database */ table/index are not found in the innodb database */
unsigned long long srv_stats_transient_sample_pages; uint32_t srv_stats_transient_sample_pages;
/** innodb_stats_persistent */ /** innodb_stats_persistent */
my_bool srv_stats_persistent; my_bool srv_stats_persistent;
/** innodb_stats_include_delete_marked */ /** innodb_stats_include_delete_marked */
my_bool srv_stats_include_delete_marked; my_bool srv_stats_include_delete_marked;
/** innodb_stats_persistent_sample_pages */ /** innodb_stats_persistent_sample_pages */
unsigned long long srv_stats_persistent_sample_pages; uint32_t srv_stats_persistent_sample_pages;
/** innodb_stats_auto_recalc */ /** innodb_stats_auto_recalc */
my_bool srv_stats_auto_recalc; my_bool srv_stats_auto_recalc;