mirror of
https://github.com/MariaDB/server.git
synced 2026-05-15 03:17:20 +02:00
MDEV-8923: port innodb_buffer_pool_dump_pct from MySQL
Backport pull request #125 from grooverdan/MDEV-8923_innodb_buffer_pool_dump_pct to 10.0 WL#6504 InnoDB buffer pool dump/load enchantments This patch consists of two parts: 1. Dump only the hottest N% of the buffer pool(s) 2. Prevent hogging the server duing BP load From MySQL - commit b409342c43ce2edb68807100a77001367c7e6b8e Add testcases for innodb_buffer_pool_dump_pct_basic. Part of the code authored by Daniel Black
This commit is contained in:
parent
af3c67056d
commit
b63bf7368b
10 changed files with 244 additions and 6 deletions
|
|
@ -0,0 +1,20 @@
|
|||
SET @orig = @@global.innodb_buffer_pool_dump_pct;
|
||||
SELECT @orig;
|
||||
@orig
|
||||
100
|
||||
SET GLOBAL innodb_buffer_pool_dump_pct=3, GLOBAL innodb_buffer_pool_dump_now = ON;
|
||||
SET GLOBAL innodb_buffer_pool_dump_pct=0;
|
||||
SELECT @@global.innodb_buffer_pool_dump_pct;
|
||||
@@global.innodb_buffer_pool_dump_pct
|
||||
1
|
||||
SHOW WARNINGS;
|
||||
Level Code Message
|
||||
Warning 1292 Truncated incorrect innodb_buffer_pool_dump_pct value: '0'
|
||||
SET GLOBAL innodb_buffer_pool_dump_pct=101;
|
||||
SELECT @@global.innodb_buffer_pool_dump_pct;
|
||||
@@global.innodb_buffer_pool_dump_pct
|
||||
100
|
||||
SHOW WARNINGS;
|
||||
Level Code Message
|
||||
Warning 1292 Truncated incorrect innodb_buffer_pool_dump_pct value: '101'
|
||||
SET GLOBAL innodb_buffer_pool_dump_pct=@orig;
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# Basic test for innodb_buffer_pool_dump_pct
|
||||
#
|
||||
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
# Check the default value
|
||||
SET @orig = @@global.innodb_buffer_pool_dump_pct;
|
||||
SELECT @orig;
|
||||
|
||||
# Do the dump
|
||||
SET GLOBAL innodb_buffer_pool_dump_pct=3, GLOBAL innodb_buffer_pool_dump_now = ON;
|
||||
|
||||
# Wait for the dump to complete
|
||||
let $wait_condition =
|
||||
SELECT SUBSTR(variable_value, 1, 33) = 'Buffer pool(s) dump completed at '
|
||||
FROM information_schema.global_status
|
||||
WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status';
|
||||
-- source include/wait_condition.inc
|
||||
|
||||
# Confirm that the dump file has been created
|
||||
-- let $file = `SELECT CONCAT(@@datadir, @@global.innodb_buffer_pool_filename)`
|
||||
-- file_exists $file
|
||||
|
||||
--disable_warnings
|
||||
SET GLOBAL innodb_buffer_pool_dump_pct=0;
|
||||
SELECT @@global.innodb_buffer_pool_dump_pct;
|
||||
SHOW WARNINGS;
|
||||
SET GLOBAL innodb_buffer_pool_dump_pct=101;
|
||||
SELECT @@global.innodb_buffer_pool_dump_pct;
|
||||
SHOW WARNINGS;
|
||||
--enable_warnings
|
||||
|
||||
SET GLOBAL innodb_buffer_pool_dump_pct=@orig;
|
||||
|
|
@ -230,6 +230,16 @@ buf_dump(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (srv_buf_pool_dump_pct != 100) {
|
||||
ut_ad(srv_buf_pool_dump_pct < 100);
|
||||
|
||||
n_pages = n_pages * srv_buf_pool_dump_pct / 100;
|
||||
|
||||
if (n_pages == 0) {
|
||||
n_pages = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dump = static_cast<buf_dump_t*>(
|
||||
ut_malloc(n_pages * sizeof(*dump))) ;
|
||||
|
||||
|
|
@ -244,9 +254,9 @@ buf_dump(
|
|||
return;
|
||||
}
|
||||
|
||||
for (bpage = UT_LIST_GET_LAST(buf_pool->LRU), j = 0;
|
||||
bpage != NULL;
|
||||
bpage = UT_LIST_GET_PREV(LRU, bpage), j++) {
|
||||
for (bpage = UT_LIST_GET_FIRST(buf_pool->LRU), j = 0;
|
||||
bpage != NULL && j < n_pages;
|
||||
bpage = UT_LIST_GET_NEXT(LRU, bpage), j++) {
|
||||
|
||||
ut_a(buf_page_in_file(bpage));
|
||||
|
||||
|
|
@ -360,6 +370,72 @@ buf_dump_sort(
|
|||
buf_dump_cmp);
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
Artificially delay the buffer pool loading if necessary. The idea of
|
||||
this function is to prevent hogging the server with IO and slowing down
|
||||
too much normal client queries. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_load_throttle_if_needed(
|
||||
/*========================*/
|
||||
ulint* last_check_time, /*!< in/out: miliseconds since epoch
|
||||
of the last time we did check if
|
||||
throttling is needed, we do the check
|
||||
every srv_io_capacity IO ops. */
|
||||
ulint* last_activity_count,
|
||||
ulint n_io) /*!< in: number of IO ops done since
|
||||
buffer pool load has started */
|
||||
{
|
||||
if (n_io % srv_io_capacity < srv_io_capacity - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*last_check_time == 0 || *last_activity_count == 0) {
|
||||
*last_check_time = ut_time_ms();
|
||||
*last_activity_count = srv_get_activity_count();
|
||||
return;
|
||||
}
|
||||
|
||||
/* srv_io_capacity IO operations have been performed by buffer pool
|
||||
load since the last time we were here. */
|
||||
|
||||
/* If no other activity, then keep going without any delay. */
|
||||
if (srv_get_activity_count() == *last_activity_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* There has been other activity, throttle. */
|
||||
|
||||
ulint now = ut_time_ms();
|
||||
ulint elapsed_time = now - *last_check_time;
|
||||
|
||||
/* Notice that elapsed_time is not the time for the last
|
||||
srv_io_capacity IO operations performed by BP load. It is the
|
||||
time elapsed since the last time we detected that there has been
|
||||
other activity. This has a small and acceptable deficiency, e.g.:
|
||||
1. BP load runs and there is no other activity.
|
||||
2. Other activity occurs, we run N IO operations after that and
|
||||
enter here (where 0 <= N < srv_io_capacity).
|
||||
3. last_check_time is very old and we do not sleep at this time, but
|
||||
only update last_check_time and last_activity_count.
|
||||
4. We run srv_io_capacity more IO operations and call this function
|
||||
again.
|
||||
5. There has been more other activity and thus we enter here.
|
||||
6. Now last_check_time is recent and we sleep if necessary to prevent
|
||||
more than srv_io_capacity IO operations per second.
|
||||
The deficiency is that we could have slept at 3., but for this we
|
||||
would have to update last_check_time before the
|
||||
"cur_activity_count == *last_activity_count" check and calling
|
||||
ut_time_ms() that often may turn out to be too expensive. */
|
||||
|
||||
if (elapsed_time < 1000 /* 1 sec (1000 mili secs) */) {
|
||||
os_thread_sleep((1000 - elapsed_time) * 1000 /* micro secs */);
|
||||
}
|
||||
|
||||
*last_check_time = ut_time_ms();
|
||||
*last_activity_count = srv_get_activity_count();
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
Perform a buffer pool load from the file specified by
|
||||
innodb_buffer_pool_filename. If any errors occur then the value of
|
||||
|
|
@ -521,6 +597,9 @@ buf_load()
|
|||
|
||||
ut_free(dump_tmp);
|
||||
|
||||
ulint last_check_time = 0;
|
||||
ulint last_activity_cnt = 0;
|
||||
|
||||
for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
|
||||
|
||||
buf_read_page_async(BUF_DUMP_SPACE(dump[i]),
|
||||
|
|
@ -544,6 +623,9 @@ buf_load()
|
|||
"Buffer pool(s) load aborted on request");
|
||||
return;
|
||||
}
|
||||
|
||||
buf_load_throttle_if_needed(
|
||||
&last_check_time, &last_activity_cnt, i);
|
||||
}
|
||||
|
||||
ut_free(dump);
|
||||
|
|
|
|||
|
|
@ -16487,6 +16487,11 @@ static MYSQL_SYSVAR_BOOL(buffer_pool_dump_at_shutdown, srv_buffer_pool_dump_at_s
|
|||
"Dump the buffer pool into a file named @@innodb_buffer_pool_filename",
|
||||
NULL, NULL, FALSE);
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(buffer_pool_dump_pct, srv_buf_pool_dump_pct,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"Dump only the hottest N% of each buffer pool, defaults to 100",
|
||||
NULL, NULL, 100, 1, 100, 0);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
static MYSQL_SYSVAR_STR(buffer_pool_evict, srv_buffer_pool_evict,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
|
|
@ -16960,6 +16965,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
|
|||
MYSQL_SYSVAR(buffer_pool_filename),
|
||||
MYSQL_SYSVAR(buffer_pool_dump_now),
|
||||
MYSQL_SYSVAR(buffer_pool_dump_at_shutdown),
|
||||
MYSQL_SYSVAR(buffer_pool_dump_pct),
|
||||
#ifdef UNIV_DEBUG
|
||||
MYSQL_SYSVAR(buffer_pool_evict),
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
|
|
|||
|
|
@ -306,6 +306,8 @@ extern ulong srv_flush_neighbors; /*!< whether or not to flush
|
|||
neighbors of a block */
|
||||
extern ulint srv_buf_pool_old_size; /*!< previously requested size */
|
||||
extern ulint srv_buf_pool_curr_size; /*!< current size in bytes */
|
||||
extern ulong srv_buf_pool_dump_pct; /*!< dump that may % of each buffer
|
||||
pool during BP dump */
|
||||
extern ulint srv_mem_pool_size;
|
||||
extern ulint srv_lock_table_size;
|
||||
|
||||
|
|
|
|||
|
|
@ -232,6 +232,8 @@ UNIV_INTERN ulong srv_flush_neighbors = 1;
|
|||
UNIV_INTERN ulint srv_buf_pool_old_size;
|
||||
/* current size in kilobytes */
|
||||
UNIV_INTERN ulint srv_buf_pool_curr_size = 0;
|
||||
/* dump that may % of each buffer pool during BP dump */
|
||||
UNIV_INTERN ulong srv_buf_pool_dump_pct;
|
||||
/* size in bytes */
|
||||
UNIV_INTERN ulint srv_mem_pool_size = ULINT_MAX;
|
||||
UNIV_INTERN ulint srv_lock_table_size = ULINT_MAX;
|
||||
|
|
|
|||
|
|
@ -230,6 +230,16 @@ buf_dump(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (srv_buf_pool_dump_pct != 100) {
|
||||
ut_ad(srv_buf_pool_dump_pct < 100);
|
||||
|
||||
n_pages = n_pages * srv_buf_pool_dump_pct / 100;
|
||||
|
||||
if (n_pages == 0) {
|
||||
n_pages = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dump = static_cast<buf_dump_t*>(
|
||||
ut_malloc(n_pages * sizeof(*dump))) ;
|
||||
|
||||
|
|
@ -244,9 +254,9 @@ buf_dump(
|
|||
return;
|
||||
}
|
||||
|
||||
for (bpage = UT_LIST_GET_LAST(buf_pool->LRU), j = 0;
|
||||
bpage != NULL;
|
||||
bpage = UT_LIST_GET_PREV(LRU, bpage), j++) {
|
||||
for (bpage = UT_LIST_GET_FIRST(buf_pool->LRU), j = 0;
|
||||
bpage != NULL && j < n_pages;
|
||||
bpage = UT_LIST_GET_NEXT(LRU, bpage), j++) {
|
||||
|
||||
ut_a(buf_page_in_file(bpage));
|
||||
|
||||
|
|
@ -360,6 +370,72 @@ buf_dump_sort(
|
|||
buf_dump_cmp);
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
Artificially delay the buffer pool loading if necessary. The idea of
|
||||
this function is to prevent hogging the server with IO and slowing down
|
||||
too much normal client queries. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_load_throttle_if_needed(
|
||||
/*========================*/
|
||||
ulint* last_check_time, /*!< in/out: miliseconds since epoch
|
||||
of the last time we did check if
|
||||
throttling is needed, we do the check
|
||||
every srv_io_capacity IO ops. */
|
||||
ulint* last_activity_count,
|
||||
ulint n_io) /*!< in: number of IO ops done since
|
||||
buffer pool load has started */
|
||||
{
|
||||
if (n_io % srv_io_capacity < srv_io_capacity - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*last_check_time == 0 || *last_activity_count == 0) {
|
||||
*last_check_time = ut_time_ms();
|
||||
*last_activity_count = srv_get_activity_count();
|
||||
return;
|
||||
}
|
||||
|
||||
/* srv_io_capacity IO operations have been performed by buffer pool
|
||||
load since the last time we were here. */
|
||||
|
||||
/* If no other activity, then keep going without any delay. */
|
||||
if (srv_get_activity_count() == *last_activity_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* There has been other activity, throttle. */
|
||||
|
||||
ulint now = ut_time_ms();
|
||||
ulint elapsed_time = now - *last_check_time;
|
||||
|
||||
/* Notice that elapsed_time is not the time for the last
|
||||
srv_io_capacity IO operations performed by BP load. It is the
|
||||
time elapsed since the last time we detected that there has been
|
||||
other activity. This has a small and acceptable deficiency, e.g.:
|
||||
1. BP load runs and there is no other activity.
|
||||
2. Other activity occurs, we run N IO operations after that and
|
||||
enter here (where 0 <= N < srv_io_capacity).
|
||||
3. last_check_time is very old and we do not sleep at this time, but
|
||||
only update last_check_time and last_activity_count.
|
||||
4. We run srv_io_capacity more IO operations and call this function
|
||||
again.
|
||||
5. There has been more other activity and thus we enter here.
|
||||
6. Now last_check_time is recent and we sleep if necessary to prevent
|
||||
more than srv_io_capacity IO operations per second.
|
||||
The deficiency is that we could have slept at 3., but for this we
|
||||
would have to update last_check_time before the
|
||||
"cur_activity_count == *last_activity_count" check and calling
|
||||
ut_time_ms() that often may turn out to be too expensive. */
|
||||
|
||||
if (elapsed_time < 1000 /* 1 sec (1000 mili secs) */) {
|
||||
os_thread_sleep((1000 - elapsed_time) * 1000 /* micro secs */);
|
||||
}
|
||||
|
||||
*last_check_time = ut_time_ms();
|
||||
*last_activity_count = srv_get_activity_count();
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
Perform a buffer pool load from the file specified by
|
||||
innodb_buffer_pool_filename. If any errors occur then the value of
|
||||
|
|
@ -521,6 +597,9 @@ buf_load()
|
|||
|
||||
ut_free(dump_tmp);
|
||||
|
||||
ulint last_check_time = 0;
|
||||
ulint last_activity_cnt = 0;
|
||||
|
||||
for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
|
||||
|
||||
buf_read_page_async(BUF_DUMP_SPACE(dump[i]),
|
||||
|
|
@ -544,6 +623,9 @@ buf_load()
|
|||
"Buffer pool(s) load aborted on request");
|
||||
return;
|
||||
}
|
||||
|
||||
buf_load_throttle_if_needed(
|
||||
&last_check_time, &last_activity_cnt, i);
|
||||
}
|
||||
|
||||
ut_free(dump);
|
||||
|
|
|
|||
|
|
@ -17840,6 +17840,11 @@ static MYSQL_SYSVAR_BOOL(buffer_pool_dump_at_shutdown, srv_buffer_pool_dump_at_s
|
|||
"Dump the buffer pool into a file named @@innodb_buffer_pool_filename",
|
||||
NULL, NULL, FALSE);
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(buffer_pool_dump_pct, srv_buf_pool_dump_pct,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"Dump only the hottest N% of each buffer pool, defaults to 100",
|
||||
NULL, NULL, 100, 1, 100, 0);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
static MYSQL_SYSVAR_STR(buffer_pool_evict, srv_buffer_pool_evict,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
|
|
@ -18382,6 +18387,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
|
|||
MYSQL_SYSVAR(buffer_pool_filename),
|
||||
MYSQL_SYSVAR(buffer_pool_dump_now),
|
||||
MYSQL_SYSVAR(buffer_pool_dump_at_shutdown),
|
||||
MYSQL_SYSVAR(buffer_pool_dump_pct),
|
||||
#ifdef UNIV_DEBUG
|
||||
MYSQL_SYSVAR(buffer_pool_evict),
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
|
|
|||
|
|
@ -335,6 +335,8 @@ extern ulong srv_flush_neighbors; /*!< whether or not to flush
|
|||
neighbors of a block */
|
||||
extern ulint srv_buf_pool_old_size; /*!< previously requested size */
|
||||
extern ulint srv_buf_pool_curr_size; /*!< current size in bytes */
|
||||
extern ulong srv_buf_pool_dump_pct; /*!< dump that may % of each buffer
|
||||
pool during BP dump */
|
||||
extern ulint srv_mem_pool_size;
|
||||
extern ulint srv_lock_table_size;
|
||||
|
||||
|
|
|
|||
|
|
@ -260,6 +260,8 @@ UNIV_INTERN ulong srv_flush_neighbors = 1;
|
|||
UNIV_INTERN ulint srv_buf_pool_old_size;
|
||||
/* current size in kilobytes */
|
||||
UNIV_INTERN ulint srv_buf_pool_curr_size = 0;
|
||||
/* dump that may % of each buffer pool during BP dump */
|
||||
UNIV_INTERN ulong srv_buf_pool_dump_pct;
|
||||
/* size in bytes */
|
||||
UNIV_INTERN ulint srv_mem_pool_size = ULINT_MAX;
|
||||
UNIV_INTERN ulint srv_lock_table_size = ULINT_MAX;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue