diff options
Diffstat (limited to 'storage/xtradb/buf/buf0dump.cc')
-rw-r--r-- | storage/xtradb/buf/buf0dump.cc | 732 |
1 files changed, 0 insertions, 732 deletions
diff --git a/storage/xtradb/buf/buf0dump.cc b/storage/xtradb/buf/buf0dump.cc deleted file mode 100644 index 71b97b770e1..00000000000 --- a/storage/xtradb/buf/buf0dump.cc +++ /dev/null @@ -1,732 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file buf/buf0dump.cc -Implements a buffer pool dump/load. - -Created April 08, 2011 Vasil Dimov -*******************************************************/ - -#include "univ.i" - -#include <stdarg.h> /* va_* */ -#include <string.h> /* strerror() */ - -#include "buf0buf.h" /* srv_buf_pool_instances */ -#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 */ - -enum status_severity { - STATUS_INFO, - STATUS_NOTICE, - STATUS_ERR -}; - -#define SHUTTING_DOWN() (UNIV_UNLIKELY(srv_shutdown_state \ - != SRV_SHUTDOWN_NONE)) - -/* Flags that tell the buffer pool dump/load thread which action should it -take after being waked up. */ -static volatile bool buf_dump_should_start; -static volatile bool buf_load_should_start; - -static ibool buf_load_abort_flag = FALSE; - -/* Used to temporary store dump info in order to avoid IO while holding -buffer pool LRU list mutex during dump and also to sort the contents of the -dump before reading the pages from disk during load. -We store the space id in the high 32 bits and page no in low 32 bits. */ -typedef ib_uint64_t buf_dump_t; - -/* Aux macros to create buf_dump_t and to extract space and page from it */ -#define BUF_DUMP_CREATE(space, page) ut_ull_create(space, page) -#define BUF_DUMP_SPACE(a) ((ulint) ((a) >> 32)) -#define BUF_DUMP_PAGE(a) ((ulint) ((a) & 0xFFFFFFFFUL)) - -/*****************************************************************//** -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() -/*============*/ -{ - buf_dump_should_start = true; - os_event_set(srv_buf_dump_event); -} - -/*****************************************************************//** -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() -/*============*/ -{ - buf_load_should_start = true; - os_event_set(srv_buf_dump_event); -} - -/*****************************************************************//** -Sets the global variable that feeds MySQL's innodb_buffer_pool_dump_status -to the specified string. The format and the following parameters are the -same as the ones used for printf(3). The value of this variable can be -retrieved by: -SELECT variable_value FROM information_schema.global_status WHERE -variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS'; -or by: -SHOW STATUS LIKE 'innodb_buffer_pool_dump_status'; */ -static MY_ATTRIBUTE((nonnull, format(printf, 2, 3))) -void -buf_dump_status( -/*============*/ - enum status_severity severity,/*!< in: status severity */ - const char* fmt, /*!< in: format */ - ...) /*!< in: extra parameters according - to fmt */ -{ - va_list ap; - - va_start(ap, fmt); - - ut_vsnprintf( - export_vars.innodb_buffer_pool_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); - - va_end(ap); -} - -/*****************************************************************//** -Sets the global variable that feeds MySQL's innodb_buffer_pool_load_status -to the specified string. The format and the following parameters are the -same as the ones used for printf(3). The value of this variable can be -retrieved by: -SELECT variable_value FROM information_schema.global_status WHERE -variable_name = 'INNODB_BUFFER_POOL_LOAD_STATUS'; -or by: -SHOW STATUS LIKE 'innodb_buffer_pool_load_status'; */ -static MY_ATTRIBUTE((nonnull, format(printf, 2, 3))) -void -buf_load_status( -/*============*/ - enum status_severity severity,/*!< in: status severity */ - const char* fmt, /*!< in: format */ - ...) /*!< in: extra parameters according to fmt */ -{ - va_list ap; - - va_start(ap, fmt); - - ut_vsnprintf( - export_vars.innodb_buffer_pool_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); - } - - va_end(ap); -} - -/** Returns the directory path where the buffer pool dump file will be created. -@return directory path */ -static -const char* -get_buf_dump_dir() -{ - const char* dump_dir; - - /* The dump file should be created in the default data directory if - innodb_data_home_dir is set as an empty string. */ - if (strcmp(srv_data_home, "") == 0) { - dump_dir = fil_path_to_mysql_datadir; - } else { - dump_dir = srv_data_home; - } - - return(dump_dir); -} - -/*****************************************************************//** -Perform a buffer pool dump into the file specified by -innodb_buffer_pool_filename. If any errors occur then the value of -innodb_buffer_pool_dump_status will be set accordingly, see buf_dump_status(). -The dump filename can be specified by (relative to srv_data_home): -SET GLOBAL innodb_buffer_pool_filename='filename'; */ -static -void -buf_dump( -/*=====*/ - ibool obey_shutdown) /*!< in: quit if we are in a shutting down - state */ -{ -#define SHOULD_QUIT() (SHUTTING_DOWN() && obey_shutdown) - - char full_filename[OS_FILE_MAX_PATH]; - char tmp_filename[OS_FILE_MAX_PATH]; - char now[32]; - FILE* f; - 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); - - ut_snprintf(tmp_filename, sizeof(tmp_filename), - "%s.incomplete", full_filename); - - buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s", - full_filename); - - f = fopen(tmp_filename, "w"); - if (f == NULL) { - buf_dump_status(STATUS_ERR, - "Cannot open '%s' for writing: %s", - tmp_filename, strerror(errno)); - return; - } - /* else */ - - /* walk through each buffer pool */ - for (i = 0; i < srv_buf_pool_instances && !SHOULD_QUIT(); i++) { - buf_pool_t* buf_pool; - const buf_page_t* bpage; - buf_dump_t* dump; - ulint n_pages; - ulint j; - ulint limit; - ulint counter; - - buf_pool = buf_pool_from_array(i); - - /* obtain buf_pool LRU list mutex before allocate, since - UT_LIST_GET_LEN(buf_pool->LRU) could change */ - mutex_enter(&buf_pool->LRU_list_mutex); - - n_pages = UT_LIST_GET_LEN(buf_pool->LRU); - - /* skip empty buffer pools */ - if (n_pages == 0) { - mutex_exit(&buf_pool->LRU_list_mutex); - 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))) ; - - if (dump == NULL) { - mutex_exit(&buf_pool->LRU_list_mutex); - fclose(f); - buf_dump_status(STATUS_ERR, - "Cannot allocate " ULINTPF " bytes: %s", - (ulint) (n_pages * sizeof(*dump)), - strerror(errno)); - /* leave tmp_filename to exist */ - return; - } - - 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)); - - dump[j] = BUF_DUMP_CREATE(buf_page_get_space(bpage), - buf_page_get_page_no(bpage)); - } - - ut_a(j == n_pages); - - mutex_exit(&buf_pool->LRU_list_mutex); - - limit = (ulint)((double)n_pages * ((double)srv_buf_dump_status_frequency / (double)100)); - counter = 0; - - for (j = 0; j < n_pages && !SHOULD_QUIT(); j++) { - ret = fprintf(f, ULINTPF "," ULINTPF "\n", - BUF_DUMP_SPACE(dump[j]), - BUF_DUMP_PAGE(dump[j])); - if (ret < 0) { - ut_free(dump); - fclose(f); - buf_dump_status(STATUS_ERR, - "Cannot write to '%s': %s", - tmp_filename, strerror(errno)); - /* leave tmp_filename to exist */ - return; - } - - counter++; - - /* Print buffer pool dump status only if - srv_buf_dump_status_frequency is > 0 and - we have processed that amount of pages. */ - if (srv_buf_dump_status_frequency && - counter == limit) { - counter = 0; - buf_dump_status( - STATUS_INFO, - "Dumping buffer pool " - ULINTPF "/" ULINTPF ", " - "page " ULINTPF "/" ULINTPF, - i + 1, srv_buf_pool_instances, - j + 1, n_pages); - } - } - - ut_free(dump); - } - - ret = fclose(f); - if (ret != 0) { - buf_dump_status(STATUS_ERR, - "Cannot close '%s': %s", - tmp_filename, strerror(errno)); - return; - } - /* else */ - - ret = unlink(full_filename); - if (ret != 0 && errno != ENOENT) { - buf_dump_status(STATUS_ERR, - "Cannot delete '%s': %s", - full_filename, strerror(errno)); - /* leave tmp_filename to exist */ - return; - } - /* else */ - - ret = rename(tmp_filename, full_filename); - if (ret != 0) { - buf_dump_status(STATUS_ERR, - "Cannot rename '%s' to '%s': %s", - tmp_filename, full_filename, - strerror(errno)); - /* leave tmp_filename to exist */ - return; - } - /* else */ - - /* success */ - - ut_sprintf_timestamp(now); - - buf_dump_status(STATUS_NOTICE, - "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. */ -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(). -The dump filename can be specified by (relative to srv_data_home): -SET GLOBAL innodb_buffer_pool_filename='filename'; */ -static -void -buf_load() -/*======*/ -{ - char full_filename[OS_FILE_MAX_PATH]; - char now[32]; - FILE* f; - buf_dump_t* dump; - buf_dump_t* dump_tmp; - ulint dump_n; - ulint total_buffer_pools_pages; - ulint i; - ulint space_id; - ulint page_no; - int fscanf_ret; - - /* 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_load_status(STATUS_NOTICE, - "Loading buffer pool(s) from %s", full_filename); - - f = fopen(full_filename, "r"); - if (f == NULL) { - buf_load_status(STATUS_ERR, - "Cannot open '%s' for reading: %s", - full_filename, strerror(errno)); - return; - } - /* else */ - - /* First scan the file to estimate how many entries are in it. - This file is tiny (approx 500KB per 1GB buffer pool), reading it - two times is fine. */ - dump_n = 0; - while (fscanf(f, ULINTPF "," ULINTPF, &space_id, &page_no) == 2 - && !SHUTTING_DOWN()) { - dump_n++; - } - - if (!SHUTTING_DOWN() && !feof(f)) { - /* fscanf() returned != 2 */ - const char* what; - if (ferror(f)) { - what = "reading"; - } else { - what = "parsing"; - } - fclose(f); - 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. */ - 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) { - fclose(f); - buf_load_status(STATUS_ERR, - "Cannot allocate " ULINTPF " bytes: %s", - (ulint) (dump_n * sizeof(*dump)), - strerror(errno)); - return; - } - - dump_tmp = static_cast<buf_dump_t*>( - ut_malloc(dump_n * sizeof(*dump_tmp))); - - if (dump_tmp == NULL) { - ut_free(dump); - fclose(f); - buf_load_status(STATUS_ERR, - "Cannot allocate " ULINTPF " bytes: %s", - (ulint) (dump_n * sizeof(*dump_tmp)), - strerror(errno)); - return; - } - - rewind(f); - - for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) { - fscanf_ret = fscanf(f, ULINTPF "," ULINTPF, - &space_id, &page_no); - - if (fscanf_ret != 2) { - if (feof(f)) { - break; - } - /* 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)", - 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", - full_filename, - space_id, page_no, - i); - return; - } - - dump[i] = BUF_DUMP_CREATE(space_id, page_no); - } - - /* Set dump_n to the actual number of initialized elements, - i could be smaller than dump_n here if the file got truncated after - we read it the first time. */ - dump_n = i; - - fclose(f); - - if (dump_n == 0) { - ut_free(dump); - ut_free(dump_tmp); - ut_sprintf_timestamp(now); - buf_load_status(STATUS_NOTICE, - "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); - } - - 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]), - BUF_DUMP_PAGE(dump[i])); - - if (i % 64 == 63) { - os_aio_simulated_wake_handler_threads(); - } - - if (i % 128 == 0) { - buf_load_status(STATUS_INFO, - "Loaded " ULINTPF "/" ULINTPF " pages", - i + 1, dump_n); - } - - if (buf_load_abort_flag) { - buf_load_abort_flag = FALSE; - ut_free(dump); - buf_load_status( - STATUS_NOTICE, - "Buffer pool(s) load aborted on request"); - return; - } - - buf_load_throttle_if_needed( - &last_check_time, &last_activity_cnt, i); - } - - ut_free(dump); - - ut_sprintf_timestamp(now); - - buf_load_status(STATUS_NOTICE, - "Buffer pool(s) load completed at %s", now); -} - -/*****************************************************************//** -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() -/*============*/ -{ - buf_load_abort_flag = TRUE; -} - -/*****************************************************************//** -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 -os_thread_ret_t -DECLARE_THREAD(buf_dump_thread)(void*) -{ - my_thread_init(); - ut_ad(!srv_read_only_mode); - - buf_dump_status(STATUS_INFO, "Dumping buffer pool(s) not yet started"); - buf_load_status(STATUS_INFO, "Loading buffer pool(s) not yet started"); - - if (srv_buffer_pool_load_at_startup) { - buf_load(); - } - - while (!SHUTTING_DOWN()) { - - os_event_wait(srv_buf_dump_event); - - if (buf_dump_should_start) { - buf_dump_should_start = false; - buf_dump(TRUE /* quit on shutdown */); - } - - if (buf_load_should_start) { - buf_load_should_start = false; - buf_load(); - } - - if (buf_dump_should_start || buf_load_should_start) { - continue; - } - os_event_reset(srv_buf_dump_event); - } - - if (srv_buffer_pool_dump_at_shutdown && srv_fast_shutdown != 2) { - buf_dump(FALSE /* ignore shutdown down flag, - keep going even if we are in a shutdown state */); - } - - srv_buf_dump_thread_active = false; - - my_thread_end(); - /* 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_DUMMY_RETURN; -} |