1/*****************************************************************************
2
3Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/**************************************************//**
21@file buf/buf0dump.cc
22Implements a buffer pool dump/load.
23
24Created April 08, 2011 Vasil Dimov
25*******************************************************/
26
27#include "my_global.h"
28#include "my_sys.h"
29
30#include "mysql/psi/mysql_stage.h"
31#include "mysql/psi/psi.h"
32
33#include "univ.i"
34
35#include "buf0buf.h"
36#include "buf0dump.h"
37#include "dict0dict.h"
38#include "os0file.h"
39#include "os0thread.h"
40#include "srv0srv.h"
41#include "srv0start.h"
42#include "sync0rw.h"
43#include "ut0byte.h"
44
45#include <algorithm>
46
47#include "mysql/service_wsrep.h" /* wsrep_recovery */
48#include <my_service_manager.h>
49
50enum status_severity {
51 STATUS_INFO,
52 STATUS_ERR
53};
54
55#define SHUTTING_DOWN() (srv_shutdown_state != SRV_SHUTDOWN_NONE)
56
57/* Flags that tell the buffer pool dump/load thread which action should it
58take after being waked up. */
59static volatile bool buf_dump_should_start;
60static volatile bool buf_load_should_start;
61
62static ibool buf_load_abort_flag = FALSE;
63
64/* Used to temporary store dump info in order to avoid IO while holding
65buffer pool mutex during dump and also to sort the contents of the dump
66before reading the pages from disk during load.
67We store the space id in the high 32 bits and page no in low 32 bits. */
68typedef ib_uint64_t buf_dump_t;
69
70/* Aux macros to create buf_dump_t and to extract space and page from it */
71#define BUF_DUMP_CREATE(space, page) ut_ull_create(space, page)
72#define BUF_DUMP_SPACE(a) ((ulint) ((a) >> 32))
73#define BUF_DUMP_PAGE(a) ((ulint) ((a) & 0xFFFFFFFFUL))
74
75/*****************************************************************//**
76Wakes up the buffer pool dump/load thread and instructs it to start
77a dump. This function is called by MySQL code via buffer_pool_dump_now()
78and it should return immediately because the whole MySQL is frozen during
79its execution. */
80void
81buf_dump_start()
82/*============*/
83{
84 buf_dump_should_start = true;
85 os_event_set(srv_buf_dump_event);
86}
87
88/*****************************************************************//**
89Wakes up the buffer pool dump/load thread and instructs it to start
90a load. This function is called by MySQL code via buffer_pool_load_now()
91and it should return immediately because the whole MySQL is frozen during
92its execution. */
93void
94buf_load_start()
95/*============*/
96{
97 buf_load_should_start = true;
98 os_event_set(srv_buf_dump_event);
99}
100
101/*****************************************************************//**
102Sets the global variable that feeds MySQL's innodb_buffer_pool_dump_status
103to the specified string. The format and the following parameters are the
104same as the ones used for printf(3). The value of this variable can be
105retrieved by:
106SELECT variable_value FROM information_schema.global_status WHERE
107variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS';
108or by:
109SHOW STATUS LIKE 'innodb_buffer_pool_dump_status'; */
110static MY_ATTRIBUTE((nonnull, format(printf, 2, 3)))
111void
112buf_dump_status(
113/*============*/
114 enum status_severity severity,/*!< in: status severity */
115 const char* fmt, /*!< in: format */
116 ...) /*!< in: extra parameters according
117 to fmt */
118{
119 va_list ap;
120
121 va_start(ap, fmt);
122
123 vsnprintf(
124 export_vars.innodb_buffer_pool_dump_status,
125 sizeof(export_vars.innodb_buffer_pool_dump_status),
126 fmt, ap);
127
128 switch (severity) {
129 case STATUS_INFO:
130 ib::info() << export_vars.innodb_buffer_pool_dump_status;
131 break;
132
133 case STATUS_ERR:
134 ib::error() << export_vars.innodb_buffer_pool_dump_status;
135 break;
136 }
137
138 va_end(ap);
139}
140
141/*****************************************************************//**
142Sets the global variable that feeds MySQL's innodb_buffer_pool_load_status
143to the specified string. The format and the following parameters are the
144same as the ones used for printf(3). The value of this variable can be
145retrieved by:
146SELECT variable_value FROM information_schema.global_status WHERE
147variable_name = 'INNODB_BUFFER_POOL_LOAD_STATUS';
148or by:
149SHOW STATUS LIKE 'innodb_buffer_pool_load_status'; */
150static MY_ATTRIBUTE((nonnull, format(printf, 2, 3)))
151void
152buf_load_status(
153/*============*/
154 enum status_severity severity,/*!< in: status severity */
155 const char* fmt, /*!< in: format */
156 ...) /*!< in: extra parameters according to fmt */
157{
158 va_list ap;
159
160 va_start(ap, fmt);
161
162 vsnprintf(
163 export_vars.innodb_buffer_pool_load_status,
164 sizeof(export_vars.innodb_buffer_pool_load_status),
165 fmt, ap);
166
167 switch (severity) {
168 case STATUS_INFO:
169 ib::info() << export_vars.innodb_buffer_pool_load_status;
170 break;
171
172 case STATUS_ERR:
173 ib::error() << export_vars.innodb_buffer_pool_load_status;
174 break;
175 }
176
177 va_end(ap);
178}
179
180/** Returns the directory path where the buffer pool dump file will be created.
181@return directory path */
182static
183const char*
184get_buf_dump_dir()
185{
186 const char* dump_dir;
187
188 /* The dump file should be created in the default data directory if
189 innodb_data_home_dir is set as an empty string. */
190 if (strcmp(srv_data_home, "") == 0) {
191 dump_dir = fil_path_to_mysql_datadir;
192 } else {
193 dump_dir = srv_data_home;
194 }
195
196 return(dump_dir);
197}
198
199/** Generate the path to the buffer pool dump/load file.
200@param[out] path generated path
201@param[in] path_size size of 'path', used as in snprintf(3). */
202static
203void
204buf_dump_generate_path(
205 char* path,
206 size_t path_size)
207{
208 char buf[FN_REFLEN];
209
210 snprintf(buf, sizeof(buf), "%s%c%s", get_buf_dump_dir(),
211 OS_PATH_SEPARATOR, srv_buf_dump_filename);
212
213 os_file_type_t type;
214 bool exists = false;
215 bool ret;
216
217 ret = os_file_status(buf, &exists, &type);
218
219 /* For realpath() to succeed the file must exist. */
220
221 if (ret && exists) {
222 /* my_realpath() assumes the destination buffer is big enough
223 to hold FN_REFLEN bytes. */
224 ut_a(path_size >= FN_REFLEN);
225
226 my_realpath(path, buf, 0);
227 } else {
228 /* If it does not exist, then resolve only srv_data_home
229 and append srv_buf_dump_filename to it. */
230 char srv_data_home_full[FN_REFLEN];
231
232 my_realpath(srv_data_home_full, get_buf_dump_dir(), 0);
233
234 if (srv_data_home_full[strlen(srv_data_home_full) - 1]
235 == OS_PATH_SEPARATOR) {
236
237 snprintf(path, path_size, "%s%s",
238 srv_data_home_full,
239 srv_buf_dump_filename);
240 } else {
241 snprintf(path, path_size, "%s%c%s",
242 srv_data_home_full,
243 OS_PATH_SEPARATOR,
244 srv_buf_dump_filename);
245 }
246 }
247}
248
249/*****************************************************************//**
250Perform a buffer pool dump into the file specified by
251innodb_buffer_pool_filename. If any errors occur then the value of
252innodb_buffer_pool_dump_status will be set accordingly, see buf_dump_status().
253The dump filename can be specified by (relative to srv_data_home):
254SET GLOBAL innodb_buffer_pool_filename='filename'; */
255static
256void
257buf_dump(
258/*=====*/
259 ibool obey_shutdown) /*!< in: quit if we are in a shutting down
260 state */
261{
262#define SHOULD_QUIT() (SHUTTING_DOWN() && obey_shutdown)
263
264 char full_filename[OS_FILE_MAX_PATH];
265 char tmp_filename[OS_FILE_MAX_PATH];
266 char now[32];
267 FILE* f;
268 ulint i;
269 int ret;
270
271 buf_dump_generate_path(full_filename, sizeof(full_filename));
272
273 snprintf(tmp_filename, sizeof(tmp_filename),
274 "%s.incomplete", full_filename);
275
276 buf_dump_status(STATUS_INFO, "Dumping buffer pool(s) to %s",
277 full_filename);
278
279#if defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
280 f = fopen(tmp_filename, "w" STR_O_CLOEXEC);
281#else
282 {
283 int fd;
284 fd = open(tmp_filename, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, 0640);
285 if (fd >= 0) {
286 f = fdopen(fd, "w");
287 }
288 else {
289 f = NULL;
290 }
291 }
292#endif
293 if (f == NULL) {
294 buf_dump_status(STATUS_ERR,
295 "Cannot open '%s' for writing: %s",
296 tmp_filename, strerror(errno));
297 return;
298 }
299 /* else */
300
301 /* walk through each buffer pool */
302 for (i = 0; i < srv_buf_pool_instances && !SHOULD_QUIT(); i++) {
303 buf_pool_t* buf_pool;
304 const buf_page_t* bpage;
305 buf_dump_t* dump;
306 ulint n_pages;
307 ulint j;
308
309 buf_pool = buf_pool_from_array(i);
310
311 /* obtain buf_pool mutex before allocate, since
312 UT_LIST_GET_LEN(buf_pool->LRU) could change */
313 buf_pool_mutex_enter(buf_pool);
314
315 n_pages = UT_LIST_GET_LEN(buf_pool->LRU);
316
317 /* skip empty buffer pools */
318 if (n_pages == 0) {
319 buf_pool_mutex_exit(buf_pool);
320 continue;
321 }
322
323 if (srv_buf_pool_dump_pct != 100) {
324 ulint t_pages;
325
326 ut_ad(srv_buf_pool_dump_pct < 100);
327
328 /* limit the number of total pages dumped to X% of the
329 * total number of pages */
330 t_pages = buf_pool->curr_size
331 * srv_buf_pool_dump_pct / 100;
332 if (n_pages > t_pages) {
333 buf_dump_status(STATUS_INFO,
334 "Instance " ULINTPF
335 ", restricted to " ULINTPF
336 " pages due to "
337 "innodb_buf_pool_dump_pct=%lu",
338 i, t_pages,
339 srv_buf_pool_dump_pct);
340 n_pages = t_pages;
341 }
342
343 if (n_pages == 0) {
344 n_pages = 1;
345 }
346 }
347
348 dump = static_cast<buf_dump_t*>(ut_malloc_nokey(
349 n_pages * sizeof(*dump)));
350
351 if (dump == NULL) {
352 buf_pool_mutex_exit(buf_pool);
353 fclose(f);
354 buf_dump_status(STATUS_ERR,
355 "Cannot allocate " ULINTPF " bytes: %s",
356 (ulint) (n_pages * sizeof(*dump)),
357 strerror(errno));
358 /* leave tmp_filename to exist */
359 return;
360 }
361
362 for (bpage = UT_LIST_GET_FIRST(buf_pool->LRU), j = 0;
363 bpage != NULL && j < n_pages;
364 bpage = UT_LIST_GET_NEXT(LRU, bpage)) {
365
366 ut_a(buf_page_in_file(bpage));
367 if (bpage->id.space() >= SRV_LOG_SPACE_FIRST_ID) {
368 /* Ignore the innodb_temporary tablespace. */
369 continue;
370 }
371
372 dump[j++] = BUF_DUMP_CREATE(bpage->id.space(),
373 bpage->id.page_no());
374 }
375
376 buf_pool_mutex_exit(buf_pool);
377
378 ut_a(j <= n_pages);
379 n_pages = j;
380
381 for (j = 0; j < n_pages && !SHOULD_QUIT(); j++) {
382 ret = fprintf(f, ULINTPF "," ULINTPF "\n",
383 BUF_DUMP_SPACE(dump[j]),
384 BUF_DUMP_PAGE(dump[j]));
385 if (ret < 0) {
386 ut_free(dump);
387 fclose(f);
388 buf_dump_status(STATUS_ERR,
389 "Cannot write to '%s': %s",
390 tmp_filename, strerror(errno));
391 /* leave tmp_filename to exist */
392 return;
393 }
394 if ( (j % 1024) == 0) {
395 service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL,
396 "Dumping buffer pool "
397 ULINTPF "/" ULINTPF ", "
398 "page " ULINTPF "/" ULINTPF,
399 i + 1, srv_buf_pool_instances,
400 j + 1, n_pages);
401 }
402 }
403
404 ut_free(dump);
405 }
406
407 ret = fclose(f);
408 if (ret != 0) {
409 buf_dump_status(STATUS_ERR,
410 "Cannot close '%s': %s",
411 tmp_filename, strerror(errno));
412 return;
413 }
414 /* else */
415
416 ret = unlink(full_filename);
417 if (ret != 0 && errno != ENOENT) {
418 buf_dump_status(STATUS_ERR,
419 "Cannot delete '%s': %s",
420 full_filename, strerror(errno));
421 /* leave tmp_filename to exist */
422 return;
423 }
424 /* else */
425
426 ret = rename(tmp_filename, full_filename);
427 if (ret != 0) {
428 buf_dump_status(STATUS_ERR,
429 "Cannot rename '%s' to '%s': %s",
430 tmp_filename, full_filename,
431 strerror(errno));
432 /* leave tmp_filename to exist */
433 return;
434 }
435 /* else */
436
437 /* success */
438
439 ut_sprintf_timestamp(now);
440
441 buf_dump_status(STATUS_INFO,
442 "Buffer pool(s) dump completed at %s", now);
443
444 /* Though dumping doesn't related to an incomplete load,
445 we reset this to 0 here to indicate that a shutdown can also perform
446 a dump */
447 export_vars.innodb_buffer_pool_load_incomplete = 0;
448}
449
450/*****************************************************************//**
451Artificially delay the buffer pool loading if necessary. The idea of
452this function is to prevent hogging the server with IO and slowing down
453too much normal client queries. */
454UNIV_INLINE
455void
456buf_load_throttle_if_needed(
457/*========================*/
458 ulint* last_check_time, /*!< in/out: milliseconds since epoch
459 of the last time we did check if
460 throttling is needed, we do the check
461 every srv_io_capacity IO ops. */
462 ulint* last_activity_count,
463 ulint n_io) /*!< in: number of IO ops done since
464 buffer pool load has started */
465{
466 if (n_io % srv_io_capacity < srv_io_capacity - 1) {
467 return;
468 }
469
470 if (*last_check_time == 0 || *last_activity_count == 0) {
471 *last_check_time = ut_time_ms();
472 *last_activity_count = srv_get_activity_count();
473 return;
474 }
475
476 /* srv_io_capacity IO operations have been performed by buffer pool
477 load since the last time we were here. */
478
479 /* If no other activity, then keep going without any delay. */
480 if (srv_get_activity_count() == *last_activity_count) {
481 return;
482 }
483
484 /* There has been other activity, throttle. */
485
486 ulint now = ut_time_ms();
487 ulint elapsed_time = now - *last_check_time;
488
489 /* Notice that elapsed_time is not the time for the last
490 srv_io_capacity IO operations performed by BP load. It is the
491 time elapsed since the last time we detected that there has been
492 other activity. This has a small and acceptable deficiency, e.g.:
493 1. BP load runs and there is no other activity.
494 2. Other activity occurs, we run N IO operations after that and
495 enter here (where 0 <= N < srv_io_capacity).
496 3. last_check_time is very old and we do not sleep at this time, but
497 only update last_check_time and last_activity_count.
498 4. We run srv_io_capacity more IO operations and call this function
499 again.
500 5. There has been more other activity and thus we enter here.
501 6. Now last_check_time is recent and we sleep if necessary to prevent
502 more than srv_io_capacity IO operations per second.
503 The deficiency is that we could have slept at 3., but for this we
504 would have to update last_check_time before the
505 "cur_activity_count == *last_activity_count" check and calling
506 ut_time_ms() that often may turn out to be too expensive. */
507
508 if (elapsed_time < 1000 /* 1 sec (1000 milli secs) */) {
509 os_thread_sleep((1000 - elapsed_time) * 1000 /* micro secs */);
510 }
511
512 *last_check_time = ut_time_ms();
513 *last_activity_count = srv_get_activity_count();
514}
515
516/*****************************************************************//**
517Perform a buffer pool load from the file specified by
518innodb_buffer_pool_filename. If any errors occur then the value of
519innodb_buffer_pool_load_status will be set accordingly, see buf_load_status().
520The dump filename can be specified by (relative to srv_data_home):
521SET GLOBAL innodb_buffer_pool_filename='filename'; */
522static
523void
524buf_load()
525/*======*/
526{
527 char full_filename[OS_FILE_MAX_PATH];
528 char now[32];
529 FILE* f;
530 buf_dump_t* dump;
531 ulint dump_n;
532 ulint total_buffer_pools_pages;
533 ulint i;
534 ulint space_id;
535 ulint page_no;
536 int fscanf_ret;
537
538 /* Ignore any leftovers from before */
539 buf_load_abort_flag = FALSE;
540
541 buf_dump_generate_path(full_filename, sizeof(full_filename));
542
543 buf_load_status(STATUS_INFO,
544 "Loading buffer pool(s) from %s", full_filename);
545
546 f = fopen(full_filename, "r" STR_O_CLOEXEC);
547 if (f == NULL) {
548 buf_load_status(STATUS_INFO,
549 "Cannot open '%s' for reading: %s",
550 full_filename, strerror(errno));
551 return;
552 }
553 /* else */
554
555 /* First scan the file to estimate how many entries are in it.
556 This file is tiny (approx 500KB per 1GB buffer pool), reading it
557 two times is fine. */
558 dump_n = 0;
559 while (fscanf(f, ULINTPF "," ULINTPF, &space_id, &page_no) == 2
560 && !SHUTTING_DOWN()) {
561 dump_n++;
562 }
563
564 if (!SHUTTING_DOWN() && !feof(f)) {
565 /* fscanf() returned != 2 */
566 const char* what;
567 if (ferror(f)) {
568 what = "reading";
569 } else {
570 what = "parsing";
571 }
572 fclose(f);
573 buf_load_status(STATUS_ERR, "Error %s '%s',"
574 " unable to load buffer pool (stage 1)",
575 what, full_filename);
576 return;
577 }
578
579 /* If dump is larger than the buffer pool(s), then we ignore the
580 extra trailing. This could happen if a dump is made, then buffer
581 pool is shrunk and then load is attempted. */
582 total_buffer_pools_pages = buf_pool_get_n_pages()
583 * srv_buf_pool_instances;
584 if (dump_n > total_buffer_pools_pages) {
585 dump_n = total_buffer_pools_pages;
586 }
587
588 if(dump_n != 0) {
589 dump = static_cast<buf_dump_t*>(ut_malloc_nokey(
590 dump_n * sizeof(*dump)));
591 } else {
592 fclose(f);
593 ut_sprintf_timestamp(now);
594 buf_load_status(STATUS_INFO,
595 "Buffer pool(s) load completed at %s"
596 " (%s was empty)", now, full_filename);
597 return;
598 }
599
600 if (dump == NULL) {
601 fclose(f);
602 buf_load_status(STATUS_ERR,
603 "Cannot allocate " ULINTPF " bytes: %s",
604 dump_n * sizeof(*dump),
605 strerror(errno));
606 return;
607 }
608
609 rewind(f);
610
611 export_vars.innodb_buffer_pool_load_incomplete = 1;
612
613 for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
614 fscanf_ret = fscanf(f, ULINTPF "," ULINTPF,
615 &space_id, &page_no);
616
617 if (fscanf_ret != 2) {
618 if (feof(f)) {
619 break;
620 }
621 /* else */
622
623 ut_free(dump);
624 fclose(f);
625 buf_load_status(STATUS_ERR,
626 "Error parsing '%s', unable"
627 " to load buffer pool (stage 2)",
628 full_filename);
629 return;
630 }
631
632 if (space_id > ULINT32_MASK || page_no > ULINT32_MASK) {
633 ut_free(dump);
634 fclose(f);
635 buf_load_status(STATUS_ERR,
636 "Error parsing '%s': bogus"
637 " space,page " ULINTPF "," ULINTPF
638 " at line " ULINTPF ","
639 " unable to load buffer pool",
640 full_filename,
641 space_id, page_no,
642 i);
643 return;
644 }
645
646 dump[i] = BUF_DUMP_CREATE(space_id, page_no);
647 }
648
649 /* Set dump_n to the actual number of initialized elements,
650 i could be smaller than dump_n here if the file got truncated after
651 we read it the first time. */
652 dump_n = i;
653
654 fclose(f);
655
656 if (dump_n == 0) {
657 ut_free(dump);
658 ut_sprintf_timestamp(now);
659 buf_load_status(STATUS_INFO,
660 "Buffer pool(s) load completed at %s"
661 " (%s was empty or had errors)", now, full_filename);
662 return;
663 }
664
665 if (!SHUTTING_DOWN()) {
666 std::sort(dump, dump + dump_n);
667 }
668
669 ulint last_check_time = 0;
670 ulint last_activity_cnt = 0;
671
672 /* Avoid calling the expensive fil_space_acquire_silent() for each
673 page within the same tablespace. dump[] is sorted by (space, page),
674 so all pages from a given tablespace are consecutive. */
675 ulint cur_space_id = BUF_DUMP_SPACE(dump[0]);
676 fil_space_t* space = fil_space_acquire_silent(cur_space_id);
677 page_size_t page_size(space ? space->flags : 0);
678
679 /* JAN: TODO: MySQL 5.7 PSI
680#ifdef HAVE_PSI_STAGE_INTERFACE
681 PSI_stage_progress* pfs_stage_progress
682 = mysql_set_stage(srv_stage_buffer_pool_load.m_key);
683 #endif*/ /* HAVE_PSI_STAGE_INTERFACE */
684 /*
685 mysql_stage_set_work_estimated(pfs_stage_progress, dump_n);
686 mysql_stage_set_work_completed(pfs_stage_progress, 0);
687 */
688
689 for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
690
691 /* space_id for this iteration of the loop */
692 const ulint this_space_id = BUF_DUMP_SPACE(dump[i]);
693
694 if (this_space_id >= SRV_LOG_SPACE_FIRST_ID) {
695 /* Ignore the innodb_temporary tablespace. */
696 continue;
697 }
698
699 if (this_space_id != cur_space_id) {
700 if (space != NULL) {
701 space->release();
702 }
703
704 cur_space_id = this_space_id;
705 space = fil_space_acquire_silent(cur_space_id);
706
707 if (space != NULL) {
708 const page_size_t cur_page_size(
709 space->flags);
710 page_size.copy_from(cur_page_size);
711 }
712 }
713
714 /* JAN: TODO: As we use background page read below,
715 if tablespace is encrypted we cant use it. */
716 if (space == NULL ||
717 (space && space->crypt_data &&
718 space->crypt_data->encryption != FIL_ENCRYPTION_OFF &&
719 space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED)) {
720 continue;
721 }
722
723 buf_read_page_background(
724 page_id_t(this_space_id, BUF_DUMP_PAGE(dump[i])),
725 page_size, true);
726
727 if (i % 64 == 63) {
728 os_aio_simulated_wake_handler_threads();
729 }
730
731 if (buf_load_abort_flag) {
732 if (space != NULL) {
733 space->release();
734 }
735 buf_load_abort_flag = FALSE;
736 ut_free(dump);
737 buf_load_status(
738 STATUS_INFO,
739 "Buffer pool(s) load aborted on request");
740 /* Premature end, set estimated = completed = i and
741 end the current stage event. */
742 /*
743 mysql_stage_set_work_estimated(pfs_stage_progress, i);
744 mysql_stage_set_work_completed(pfs_stage_progress,
745 i);
746 */
747#ifdef HAVE_PSI_STAGE_INTERFACE
748 /* mysql_end_stage(); */
749#endif /* HAVE_PSI_STAGE_INTERFACE */
750 return;
751 }
752
753 buf_load_throttle_if_needed(
754 &last_check_time, &last_activity_cnt, i);
755
756#ifdef UNIV_DEBUG
757 if ((i+1) >= srv_buf_pool_load_pages_abort) {
758 buf_load_abort_flag = 1;
759 }
760#endif
761 }
762
763 if (space != NULL) {
764 space->release();
765 }
766
767 ut_free(dump);
768
769 ut_sprintf_timestamp(now);
770
771 if (i == dump_n) {
772 buf_load_status(STATUS_INFO,
773 "Buffer pool(s) load completed at %s", now);
774 export_vars.innodb_buffer_pool_load_incomplete = 0;
775 } else if (!buf_load_abort_flag) {
776 buf_load_status(STATUS_INFO,
777 "Buffer pool(s) load aborted due to user instigated abort at %s",
778 now);
779 /* intentionally don't reset innodb_buffer_pool_load_incomplete
780 as we don't want a shutdown to save the buffer pool */
781 } else {
782 buf_load_status(STATUS_INFO,
783 "Buffer pool(s) load aborted due to shutdown at %s",
784 now);
785 /* intentionally don't reset innodb_buffer_pool_load_incomplete
786 as we want to abort without saving the buffer pool */
787 }
788
789 /* Make sure that estimated = completed when we end. */
790 /* mysql_stage_set_work_completed(pfs_stage_progress, dump_n); */
791 /* End the stage progress event. */
792#ifdef HAVE_PSI_STAGE_INTERFACE
793 /* mysql_end_stage(); */
794#endif /* HAVE_PSI_STAGE_INTERFACE */
795}
796
797/*****************************************************************//**
798Aborts a currently running buffer pool load. This function is called by
799MySQL code via buffer_pool_load_abort() and it should return immediately
800because the whole MySQL is frozen during its execution. */
801void
802buf_load_abort()
803/*============*/
804{
805 buf_load_abort_flag = TRUE;
806}
807
808/*****************************************************************//**
809This is the main thread for buffer pool dump/load. It waits for an
810event and when waked up either performs a dump or load and sleeps
811again.
812@return this function does not return, it calls os_thread_exit() */
813extern "C"
814os_thread_ret_t
815DECLARE_THREAD(buf_dump_thread)(void*)
816{
817 my_thread_init();
818 ut_ad(!srv_read_only_mode);
819 /* JAN: TODO: MySQL 5.7 PSI
820#ifdef UNIV_PFS_THREAD
821 pfs_register_thread(buf_dump_thread_key);
822 #endif */ /* UNIV_PFS_THREAD */
823
824 if (srv_buffer_pool_load_at_startup) {
825
826#ifdef WITH_WSREP
827 if (!wsrep_recovery) {
828#endif /* WITH_WSREP */
829 buf_load();
830#ifdef WITH_WSREP
831 }
832#endif /* WITH_WSREP */
833 }
834
835 while (!SHUTTING_DOWN()) {
836
837 os_event_wait(srv_buf_dump_event);
838
839 if (buf_dump_should_start) {
840 buf_dump_should_start = false;
841 buf_dump(TRUE /* quit on shutdown */);
842 }
843
844 if (buf_load_should_start) {
845 buf_load_should_start = false;
846 buf_load();
847 }
848
849 if (buf_dump_should_start || buf_load_should_start) {
850 continue;
851 }
852 os_event_reset(srv_buf_dump_event);
853 }
854
855 if (srv_buffer_pool_dump_at_shutdown && srv_fast_shutdown != 2) {
856 if (export_vars.innodb_buffer_pool_load_incomplete) {
857 buf_dump_status(STATUS_INFO,
858 "Dumping of buffer pool not started"
859 " as load was incomplete");
860#ifdef WITH_WSREP
861 } else if (wsrep_recovery) {
862#endif /* WITH_WSREP */
863 } else {
864 buf_dump(FALSE/* do complete dump at shutdown */);
865 }
866 }
867
868 srv_buf_dump_thread_active = false;
869
870 my_thread_end();
871 /* We count the number of threads in os_thread_exit(). A created
872 thread should always use that to exit and not use return() to exit. */
873 os_thread_exit();
874
875 OS_THREAD_DUMMY_RETURN;
876}
877