[Commits] 91a7560: MDEV-8923: port innodb_buffer_pool_dump_pct from MySQL

Jan Lindström jan.lindstrom at mariadb.com
Tue Dec 15 09:33:11 EET 2015


revision-id: 91a756019e3b7e4f9aa61844d43a523cab8b78ff (mariadb-10.0.22-60-g91a7560)
parent(s): 99404c3437b35b5ee51578c2ea74209ccb9ba890
committer: Jan Lindström
timestamp: 2015-12-15 09:30:13 +0200
message:

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

---
 .../r/innodb_buffer_pool_dump_pct_basic.result     | 20 +++++
 .../t/innodb_buffer_pool_dump_pct_basic.test       | 34 +++++++++
 storage/innobase/buf/buf0dump.cc                   | 88 +++++++++++++++++++++-
 storage/innobase/handler/ha_innodb.cc              |  6 ++
 storage/innobase/include/srv0srv.h                 |  2 +
 storage/innobase/srv/srv0srv.cc                    |  2 +
 storage/xtradb/buf/buf0dump.cc                     | 88 +++++++++++++++++++++-
 storage/xtradb/handler/ha_innodb.cc                |  6 ++
 storage/xtradb/include/srv0srv.h                   |  2 +
 storage/xtradb/srv/srv0srv.cc                      |  2 +
 10 files changed, 244 insertions(+), 6 deletions(-)

diff --git a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_pct_basic.result b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_pct_basic.result
new file mode 100644
index 0000000..51c72cf
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_dump_pct_basic.result
@@ -0,0 +1,20 @@
+SET @orig = @@global.innodb_buffer_pool_dump_pct;
+SELECT @orig;
+ at 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;
diff --git a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_pct_basic.test b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_pct_basic.test
new file mode 100644
index 0000000..d2f5cb4
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_dump_pct_basic.test
@@ -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;
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index 467f817..bf757dc 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -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));
 
@@ -361,6 +371,72 @@ buf_dump_sort(
 }
 
 /*****************************************************************//**
+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
 innodb_buffer_pool_load_status will be set accordingly, see buf_load_status().
@@ -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);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index fde5683..ff2fece 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -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 */
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 338ad55..6c5b2c5 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -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;
 
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index b3df528..6eb63fd 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -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;
diff --git a/storage/xtradb/buf/buf0dump.cc b/storage/xtradb/buf/buf0dump.cc
index 090e8ca..2b3b506 100644
--- a/storage/xtradb/buf/buf0dump.cc
+++ b/storage/xtradb/buf/buf0dump.cc
@@ -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));
 
@@ -361,6 +371,72 @@ buf_dump_sort(
 }
 
 /*****************************************************************//**
+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
 innodb_buffer_pool_load_status will be set accordingly, see buf_load_status().
@@ -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);
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 348e710..e30727b 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -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 */
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index 981bcd0..aabc9c7 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -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;
 
diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc
index c92aa0e..ffded97 100644
--- a/storage/xtradb/srv/srv0srv.cc
+++ b/storage/xtradb/srv/srv0srv.cc
@@ -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;


More information about the commits mailing list