Commit b63bf736 authored by Jan Lindström's avatar Jan Lindström

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
parent af3c6705
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;
#
# 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;
......
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