summaryrefslogtreecommitdiff
path: root/storage/innobase/buf/buf0dump.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/buf/buf0dump.cc')
-rw-r--r--storage/innobase/buf/buf0dump.cc348
1 files changed, 224 insertions, 124 deletions
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index 0abf7118b4f..682be386f2b 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -23,32 +23,33 @@ Implements a buffer pool dump/load.
Created April 08, 2011 Vasil Dimov
*******************************************************/
-#include "univ.i"
+#include "my_global.h"
+#include "my_sys.h"
+
+#include "mysql/psi/mysql_stage.h"
+#include "mysql/psi/psi.h"
-#include <stdarg.h> /* va_* */
-#include <string.h> /* strerror() */
+#include "univ.i"
-#include "buf0buf.h" /* buf_pool_mutex_enter(), srv_buf_pool_instances */
+#include "buf0buf.h"
#include "buf0dump.h"
-#include "db0err.h"
-#include "dict0dict.h" /* dict_operation_lock */
-#include "os0file.h" /* OS_FILE_MAX_PATH */
-#include "os0sync.h" /* os_event* */
-#include "os0thread.h" /* os_thread_* */
-#include "srv0srv.h" /* srv_fast_shutdown, srv_buf_dump* */
-#include "srv0start.h" /* srv_shutdown_state */
-#include "sync0rw.h" /* rw_lock_s_lock() */
-#include "ut0byte.h" /* ut_ull_create() */
-#include "ut0sort.h" /* UT_SORT_FUNCTION_BODY */
+#include "dict0dict.h"
+#include "os0file.h"
+#include "os0thread.h"
+#include "srv0srv.h"
+#include "srv0start.h"
+#include "sync0rw.h"
+#include "ut0byte.h"
+
+#include <algorithm>
enum status_severity {
+ STATUS_VERBOSE,
STATUS_INFO,
- STATUS_NOTICE,
STATUS_ERR
};
-#define SHUTTING_DOWN() (UNIV_UNLIKELY(srv_shutdown_state \
- != SRV_SHUTDOWN_NONE))
+#define SHUTTING_DOWN() (srv_shutdown_state != SRV_SHUTDOWN_NONE)
/* Flags that tell the buffer pool dump/load thread which action should it
take after being waked up. */
@@ -73,7 +74,6 @@ Wakes up the buffer pool dump/load thread and instructs it to start
a dump. This function is called by MySQL code via buffer_pool_dump_now()
and it should return immediately because the whole MySQL is frozen during
its execution. */
-UNIV_INTERN
void
buf_dump_start()
/*============*/
@@ -87,7 +87,6 @@ Wakes up the buffer pool dump/load thread and instructs it to start
a load. This function is called by MySQL code via buffer_pool_load_now()
and it should return immediately because the whole MySQL is frozen during
its execution. */
-UNIV_INTERN
void
buf_load_start()
/*============*/
@@ -123,7 +122,18 @@ buf_dump_status(
sizeof(export_vars.innodb_buffer_pool_dump_status),
fmt, ap);
- ib_logf((ib_log_level_t) severity, "%s", export_vars.innodb_buffer_pool_dump_status);
+ switch (severity) {
+ case STATUS_INFO:
+ ib::info() << export_vars.innodb_buffer_pool_dump_status;
+ break;
+
+ case STATUS_ERR:
+ ib::error() << export_vars.innodb_buffer_pool_dump_status;
+ break;
+
+ case STATUS_VERBOSE:
+ break;
+ }
va_end(ap);
}
@@ -154,10 +164,17 @@ buf_load_status(
sizeof(export_vars.innodb_buffer_pool_load_status),
fmt, ap);
- if (severity == STATUS_NOTICE || severity == STATUS_ERR) {
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: %s\n",
- export_vars.innodb_buffer_pool_load_status);
+ switch (severity) {
+ case STATUS_INFO:
+ ib::info() << export_vars.innodb_buffer_pool_load_status;
+ break;
+
+ case STATUS_ERR:
+ ib::error() << export_vars.innodb_buffer_pool_load_status;
+ break;
+
+ case STATUS_VERBOSE:
+ break;
}
va_end(ap);
@@ -182,6 +199,56 @@ get_buf_dump_dir()
return(dump_dir);
}
+/** Generate the path to the buffer pool dump/load file.
+@param[out] path generated path
+@param[in] path_size size of 'path', used as in snprintf(3). */
+static
+void
+buf_dump_generate_path(
+ char* path,
+ size_t path_size)
+{
+ char buf[FN_REFLEN];
+
+ ut_snprintf(buf, sizeof(buf), "%s%c%s", get_buf_dump_dir(),
+ OS_PATH_SEPARATOR, srv_buf_dump_filename);
+
+ os_file_type_t type;
+ bool exists = false;
+ bool ret;
+
+ ret = os_file_status(buf, &exists, &type);
+
+ /* For realpath() to succeed the file must exist. */
+
+ if (ret && exists) {
+ /* my_realpath() assumes the destination buffer is big enough
+ to hold FN_REFLEN bytes. */
+ ut_a(path_size >= FN_REFLEN);
+
+ my_realpath(path, buf, 0);
+ } else {
+ /* If it does not exist, then resolve only srv_data_home
+ and append srv_buf_dump_filename to it. */
+ char srv_data_home_full[FN_REFLEN];
+
+ my_realpath(srv_data_home_full, get_buf_dump_dir(), 0);
+
+ if (srv_data_home_full[strlen(srv_data_home_full) - 1]
+ == OS_PATH_SEPARATOR) {
+
+ ut_snprintf(path, path_size, "%s%s",
+ srv_data_home_full,
+ srv_buf_dump_filename);
+ } else {
+ ut_snprintf(path, path_size, "%s%c%s",
+ srv_data_home_full,
+ OS_PATH_SEPARATOR,
+ srv_buf_dump_filename);
+ }
+ }
+}
+
/*****************************************************************//**
Perform a buffer pool dump into the file specified by
innodb_buffer_pool_filename. If any errors occur then the value of
@@ -204,14 +271,12 @@ buf_dump(
ulint i;
int ret;
- ut_snprintf(full_filename, sizeof(full_filename),
- "%s%c%s", get_buf_dump_dir(), SRV_PATH_SEPARATOR,
- srv_buf_dump_filename);
+ buf_dump_generate_path(full_filename, sizeof(full_filename));
ut_snprintf(tmp_filename, sizeof(tmp_filename),
"%s.incomplete", full_filename);
- buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s",
+ buf_dump_status(STATUS_INFO, "Dumping buffer pool(s) to %s",
full_filename);
f = fopen(tmp_filename, "w");
@@ -257,8 +322,8 @@ buf_dump(
}
}
- dump = static_cast<buf_dump_t*>(
- ut_malloc(n_pages * sizeof(*dump))) ;
+ dump = static_cast<buf_dump_t*>(ut_malloc_nokey(
+ n_pages * sizeof(*dump)));
if (dump == NULL) {
buf_pool_mutex_exit(buf_pool);
@@ -277,8 +342,8 @@ buf_dump(
ut_a(buf_page_in_file(bpage));
- dump[j] = BUF_DUMP_CREATE(buf_page_get_space(bpage),
- buf_page_get_page_no(bpage));
+ dump[j] = BUF_DUMP_CREATE(bpage->id.space(),
+ bpage->id.page_no());
}
ut_a(j == n_pages);
@@ -311,10 +376,10 @@ buf_dump(
counter == limit) {
counter = 0;
buf_dump_status(
- STATUS_INFO,
- "Dumping buffer pool "
- ULINTPF "/" ULINTPF ", "
- "page " ULINTPF "/" ULINTPF,
+ STATUS_VERBOSE,
+ "Dumping buffer pool"
+ " " ULINTPF "/" ULINTPF ","
+ " page " ULINTPF "/" ULINTPF,
i + 1, srv_buf_pool_instances,
j + 1, n_pages);
}
@@ -357,47 +422,11 @@ buf_dump(
ut_sprintf_timestamp(now);
- buf_dump_status(STATUS_NOTICE,
+ buf_dump_status(STATUS_INFO,
"Buffer pool(s) dump completed at %s", now);
}
/*****************************************************************//**
-Compare two buffer pool dump entries, used to sort the dump on
-space_no,page_no before loading in order to increase the chance for
-sequential IO.
-@return -1/0/1 if entry 1 is smaller/equal/bigger than entry 2 */
-static
-lint
-buf_dump_cmp(
-/*=========*/
- const buf_dump_t d1, /*!< in: buffer pool dump entry 1 */
- const buf_dump_t d2) /*!< in: buffer pool dump entry 2 */
-{
- if (d1 < d2) {
- return(-1);
- } else if (d1 == d2) {
- return(0);
- } else {
- return(1);
- }
-}
-
-/*****************************************************************//**
-Sort a buffer pool dump on space_no, page_no. */
-static
-void
-buf_dump_sort(
-/*==========*/
- buf_dump_t* dump, /*!< in/out: buffer pool dump to sort */
- buf_dump_t* tmp, /*!< in/out: temp storage */
- ulint low, /*!< in: lowest index (inclusive) */
- ulint high) /*!< in: highest index (non-inclusive) */
-{
- UT_SORT_FUNCTION_BODY(buf_dump_sort, dump, tmp, low, high,
- 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. */
@@ -405,7 +434,7 @@ UNIV_INLINE
void
buf_load_throttle_if_needed(
/*========================*/
- ulint* last_check_time, /*!< in/out: miliseconds since epoch
+ ulint* last_check_time, /*!< in/out: milliseconds since epoch
of the last time we did check if
throttling is needed, we do the check
every srv_io_capacity IO ops. */
@@ -455,7 +484,7 @@ buf_load_throttle_if_needed(
"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) */) {
+ if (elapsed_time < 1000 /* 1 sec (1000 milli secs) */) {
os_thread_sleep((1000 - elapsed_time) * 1000 /* micro secs */);
}
@@ -478,7 +507,6 @@ buf_load()
char now[32];
FILE* f;
buf_dump_t* dump;
- buf_dump_t* dump_tmp;
ulint dump_n;
ulint total_buffer_pools_pages;
ulint i;
@@ -489,11 +517,9 @@ buf_load()
/* Ignore any leftovers from before */
buf_load_abort_flag = FALSE;
- ut_snprintf(full_filename, sizeof(full_filename),
- "%s%c%s", get_buf_dump_dir(), SRV_PATH_SEPARATOR,
- srv_buf_dump_filename);
+ buf_dump_generate_path(full_filename, sizeof(full_filename));
- buf_load_status(STATUS_NOTICE,
+ buf_load_status(STATUS_INFO,
"Loading buffer pool(s) from %s", full_filename);
f = fopen(full_filename, "r");
@@ -523,41 +549,38 @@ buf_load()
what = "parsing";
}
fclose(f);
- buf_load_status(STATUS_ERR, "Error %s '%s', "
- "unable to load buffer pool (stage 1)",
+ buf_load_status(STATUS_ERR, "Error %s '%s',"
+ " unable to load buffer pool (stage 1)",
what, full_filename);
return;
}
/* If dump is larger than the buffer pool(s), then we ignore the
extra trailing. This could happen if a dump is made, then buffer
- pool is shrunk and then load it attempted. */
+ pool is shrunk and then load is attempted. */
total_buffer_pools_pages = buf_pool_get_n_pages()
* srv_buf_pool_instances;
if (dump_n > total_buffer_pools_pages) {
dump_n = total_buffer_pools_pages;
}
- dump = static_cast<buf_dump_t*>(ut_malloc(dump_n * sizeof(*dump)));
-
- if (dump == NULL) {
+ if(dump_n != 0) {
+ dump = static_cast<buf_dump_t*>(ut_malloc_nokey(
+ dump_n * sizeof(*dump)));
+ } else {
fclose(f);
- buf_load_status(STATUS_ERR,
- "Cannot allocate " ULINTPF " bytes: %s",
- (ulint) (dump_n * sizeof(*dump)),
- strerror(errno));
+ ut_sprintf_timestamp(now);
+ buf_load_status(STATUS_INFO,
+ "Buffer pool(s) load completed at %s"
+ " (%s was empty)", now, full_filename);
return;
}
- dump_tmp = static_cast<buf_dump_t*>(
- ut_malloc(dump_n * sizeof(*dump_tmp)));
-
- if (dump_tmp == NULL) {
- ut_free(dump);
+ if (dump == NULL) {
fclose(f);
buf_load_status(STATUS_ERR,
- "Cannot allocate " ULINTPF " bytes: %s",
- (ulint) (dump_n * sizeof(*dump_tmp)),
+ "Cannot allocate %lu bytes: %s",
+ (ulint) (dump_n * sizeof(*dump)),
strerror(errno));
return;
}
@@ -575,24 +598,22 @@ buf_load()
/* else */
ut_free(dump);
- ut_free(dump_tmp);
fclose(f);
buf_load_status(STATUS_ERR,
- "Error parsing '%s', unable "
- "to load buffer pool (stage 2)",
+ "Error parsing '%s', unable"
+ " to load buffer pool (stage 2)",
full_filename);
return;
}
if (space_id > ULINT32_MASK || page_no > ULINT32_MASK) {
ut_free(dump);
- ut_free(dump_tmp);
fclose(f);
buf_load_status(STATUS_ERR,
- "Error parsing '%s': bogus "
- "space,page " ULINTPF "," ULINTPF
- " at line " ULINTPF ", "
- "unable to load buffer pool",
+ "Error parsing '%s': bogus"
+ " space,page " ULINTPF "," ULINTPF
+ " at line " ULINTPF ","
+ " unable to load buffer pool",
full_filename,
space_id, page_no,
i);
@@ -612,42 +633,107 @@ buf_load()
if (dump_n == 0) {
ut_free(dump);
ut_sprintf_timestamp(now);
- buf_load_status(STATUS_NOTICE,
- "Buffer pool(s) load completed at %s "
- "(%s was empty)", now, full_filename);
+ buf_load_status(STATUS_INFO,
+ "Buffer pool(s) load completed at %s"
+ " (%s was empty)", now, full_filename);
return;
}
if (!SHUTTING_DOWN()) {
- buf_dump_sort(dump, dump_tmp, 0, dump_n);
+ std::sort(dump, dump + dump_n);
}
- ut_free(dump_tmp);
-
- ulint last_check_time = 0;
- ulint last_activity_cnt = 0;
+ ulint last_check_time = 0;
+ ulint last_activity_cnt = 0;
+
+ /* Avoid calling the expensive fil_space_acquire_silent() for each
+ page within the same tablespace. dump[] is sorted by (space, page),
+ so all pages from a given tablespace are consecutive. */
+ ulint cur_space_id = BUF_DUMP_SPACE(dump[0]);
+ fil_space_t* space = fil_space_acquire_silent(cur_space_id);
+ page_size_t page_size(space ? space->flags : 0);
+
+ /* JAN: TODO: MySQL 5.7 PSI
+#ifdef HAVE_PSI_STAGE_INTERFACE
+ PSI_stage_progress* pfs_stage_progress
+ = mysql_set_stage(srv_stage_buffer_pool_load.m_key);
+ #endif*/ /* HAVE_PSI_STAGE_INTERFACE */
+ /*
+ mysql_stage_set_work_estimated(pfs_stage_progress, dump_n);
+ mysql_stage_set_work_completed(pfs_stage_progress, 0);
+ */
for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
- buf_read_page_async(BUF_DUMP_SPACE(dump[i]),
- BUF_DUMP_PAGE(dump[i]));
+ /* space_id for this iteration of the loop */
+ const ulint this_space_id = BUF_DUMP_SPACE(dump[i]);
+
+ if (this_space_id != cur_space_id) {
+ if (space != NULL) {
+ fil_space_release(space);
+ }
+
+ cur_space_id = this_space_id;
+ space = fil_space_acquire_silent(cur_space_id);
+
+ if (space != NULL) {
+ const page_size_t cur_page_size(
+ space->flags);
+ page_size.copy_from(cur_page_size);
+ }
+ }
+
+ /* JAN: TODO: As we use background page read below,
+ if tablespace is encrypted we cant use it. */
+ if (space == NULL ||
+ (space && space->crypt_data &&
+ space->crypt_data->encryption != FIL_SPACE_ENCRYPTION_OFF &&
+ space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED)) {
+ continue;
+ }
+
+ buf_read_page_background(
+ page_id_t(this_space_id, BUF_DUMP_PAGE(dump[i])),
+ page_size, true);
if (i % 64 == 63) {
os_aio_simulated_wake_handler_threads();
}
- if (i % 128 == 0) {
- buf_load_status(STATUS_INFO,
+ /* Update the progress every 32 MiB, which is every Nth page,
+ where N = 32*1024^2 / page_size. */
+ static const ulint update_status_every_n_mb = 32;
+ static const ulint update_status_every_n_pages
+ = update_status_every_n_mb * 1024 * 1024
+ / page_size.physical();
+
+ if (i % update_status_every_n_pages == 0) {
+ buf_load_status(STATUS_VERBOSE,
"Loaded " ULINTPF "/" ULINTPF " pages",
i + 1, dump_n);
+ /* mysql_stage_set_work_completed(pfs_stage_progress,
+ i); */
}
if (buf_load_abort_flag) {
+ if (space != NULL) {
+ fil_space_release(space);
+ }
buf_load_abort_flag = FALSE;
ut_free(dump);
buf_load_status(
- STATUS_NOTICE,
+ STATUS_INFO,
"Buffer pool(s) load aborted on request");
+ /* Premature end, set estimated = completed = i and
+ end the current stage event. */
+ /*
+ mysql_stage_set_work_estimated(pfs_stage_progress, i);
+ mysql_stage_set_work_completed(pfs_stage_progress,
+ i);
+ */
+#ifdef HAVE_PSI_STAGE_INTERFACE
+ /* mysql_end_stage(); */
+#endif /* HAVE_PSI_STAGE_INTERFACE */
return;
}
@@ -655,19 +741,29 @@ buf_load()
&last_check_time, &last_activity_cnt, i);
}
+ if (space != NULL) {
+ fil_space_release(space);
+ }
+
ut_free(dump);
ut_sprintf_timestamp(now);
- buf_load_status(STATUS_NOTICE,
+ buf_load_status(STATUS_INFO,
"Buffer pool(s) load completed at %s", now);
+
+ /* Make sure that estimated = completed when we end. */
+ /* mysql_stage_set_work_completed(pfs_stage_progress, dump_n); */
+ /* End the stage progress event. */
+#ifdef HAVE_PSI_STAGE_INTERFACE
+ /* mysql_end_stage(); */
+#endif /* HAVE_PSI_STAGE_INTERFACE */
}
/*****************************************************************//**
Aborts a currently running buffer pool load. This function is called by
MySQL code via buffer_pool_load_abort() and it should return immediately
because the whole MySQL is frozen during its execution. */
-UNIV_INTERN
void
buf_load_abort()
/*============*/
@@ -680,7 +776,7 @@ This is the main thread for buffer pool dump/load. It waits for an
event and when waked up either performs a dump or load and sleeps
again.
@return this function does not return, it calls os_thread_exit() */
-extern "C" UNIV_INTERN
+extern "C"
os_thread_ret_t
DECLARE_THREAD(buf_dump_thread)(
/*============================*/
@@ -688,11 +784,15 @@ DECLARE_THREAD(buf_dump_thread)(
required by os_thread_create */
{
ut_ad(!srv_read_only_mode);
+ /* JAN: TODO: MySQL 5.7 PSI
+#ifdef UNIV_PFS_THREAD
+ pfs_register_thread(buf_dump_thread_key);
+ #endif */ /* UNIV_PFS_THREAD */
srv_buf_dump_thread_active = TRUE;
- buf_dump_status(STATUS_INFO, "Dumping buffer pool(s) not yet started");
- buf_load_status(STATUS_INFO, "Loading buffer pool(s) not yet started");
+ buf_dump_status(STATUS_VERBOSE, "Dumping of buffer pool not started");
+ buf_load_status(STATUS_VERBOSE, "Loading of buffer pool not started");
if (srv_buffer_pool_load_at_startup) {
buf_load();
@@ -724,7 +824,7 @@ DECLARE_THREAD(buf_dump_thread)(
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}