Commit a816df70 authored by Vasil Dimov's avatar Vasil Dimov Committed by Daniel Black

MDEV-8923 Port innodb_buffer_pool_dump_pct

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
parent 3c0e9d31
......@@ -228,6 +228,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))) ;
......@@ -242,9 +252,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));
......@@ -368,6 +378,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
......@@ -529,6 +605,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]),
......@@ -552,6 +631,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);
......
......@@ -18787,6 +18787,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,
......@@ -19524,6 +19529,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 */
......
......@@ -380,6 +380,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;
......
......@@ -263,6 +263,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;
......
......@@ -228,6 +228,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))) ;
......@@ -242,9 +252,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));
......@@ -368,6 +378,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
......@@ -529,6 +605,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]),
......@@ -552,6 +631,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);
......
......@@ -19934,6 +19934,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,
......@@ -20736,6 +20741,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 */
......
......@@ -403,6 +403,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;
......
......@@ -296,6 +296,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