MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
buf0dump.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 2011, 2012, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "univ.i"
27 
28 #include <stdarg.h> /* va_* */
29 #include <string.h> /* strerror() */
30 
31 #include "buf0buf.h" /* buf_pool_mutex_enter(), srv_buf_pool_instances */
32 #include "buf0dump.h"
33 #include "db0err.h"
34 #include "dict0dict.h" /* dict_operation_lock */
35 #include "os0file.h" /* OS_FILE_MAX_PATH */
36 #include "os0sync.h" /* os_event* */
37 #include "os0thread.h" /* os_thread_* */
38 #include "srv0srv.h" /* srv_fast_shutdown, srv_buf_dump* */
39 #include "srv0start.h" /* srv_shutdown_state */
40 #include "sync0rw.h" /* rw_lock_s_lock() */
41 #include "ut0byte.h" /* ut_ull_create() */
42 #include "ut0sort.h" /* UT_SORT_FUNCTION_BODY */
43 
44 enum status_severity {
45  STATUS_INFO,
46  STATUS_NOTICE,
47  STATUS_ERR
48 };
49 
50 #define SHUTTING_DOWN() (UNIV_UNLIKELY(srv_shutdown_state \
51  != SRV_SHUTDOWN_NONE))
52 
53 /* Flags that tell the buffer pool dump/load thread which action should it
54 take after being waked up. */
55 static ibool buf_dump_should_start = FALSE;
56 static ibool buf_load_should_start = FALSE;
57 
58 static ibool buf_load_abort_flag = FALSE;
59 
60 /* Used to temporary store dump info in order to avoid IO while holding
61 buffer pool mutex during dump and also to sort the contents of the dump
62 before reading the pages from disk during load.
63 We store the space id in the high 32 bits and page no in low 32 bits. */
64 typedef ib_uint64_t buf_dump_t;
65 
66 /* Aux macros to create buf_dump_t and to extract space and page from it */
67 #define BUF_DUMP_CREATE(space, page) ut_ull_create(space, page)
68 #define BUF_DUMP_SPACE(a) ((ulint) ((a) >> 32))
69 #define BUF_DUMP_PAGE(a) ((ulint) ((a) & 0xFFFFFFFFUL))
70 
71 /*****************************************************************/
76 UNIV_INTERN
77 void
79 /*============*/
80 {
81  buf_dump_should_start = TRUE;
83 }
84 
85 /*****************************************************************/
90 UNIV_INTERN
91 void
93 /*============*/
94 {
95  buf_load_should_start = TRUE;
97 }
98 
99 /*****************************************************************/
108 static __attribute__((nonnull, format(printf, 2, 3)))
109 void
110 buf_dump_status(
111 /*============*/
112  enum status_severity severity,
113  const char* fmt,
114  ...)
116 {
117  va_list ap;
118 
119  va_start(ap, fmt);
120 
121  ut_vsnprintf(
124  fmt, ap);
125 
126  if (severity == STATUS_NOTICE || severity == STATUS_ERR) {
127  ut_print_timestamp(stderr);
128  fprintf(stderr, " InnoDB: %s\n",
130  }
131 
132  va_end(ap);
133 }
134 
135 /*****************************************************************/
144 static __attribute__((nonnull, format(printf, 2, 3)))
145 void
146 buf_load_status(
147 /*============*/
148  enum status_severity severity,
149  const char* fmt,
150  ...)
151 {
152  va_list ap;
153 
154  va_start(ap, fmt);
155 
156  ut_vsnprintf(
159  fmt, ap);
160 
161  if (severity == STATUS_NOTICE || severity == STATUS_ERR) {
162  ut_print_timestamp(stderr);
163  fprintf(stderr, " InnoDB: %s\n",
165  }
166 
167  va_end(ap);
168 }
169 
170 /*****************************************************************/
176 static
177 void
178 buf_dump(
179 /*=====*/
180  ibool obey_shutdown)
182 {
183 #define SHOULD_QUIT() (SHUTTING_DOWN() && obey_shutdown)
184 
185  char full_filename[OS_FILE_MAX_PATH];
186  char tmp_filename[OS_FILE_MAX_PATH];
187  char now[32];
188  FILE* f;
189  ulint i;
190  int ret;
191 
192  ut_snprintf(full_filename, sizeof(full_filename),
193  "%s%c%s", srv_data_home, SRV_PATH_SEPARATOR,
195 
196  ut_snprintf(tmp_filename, sizeof(tmp_filename),
197  "%s.incomplete", full_filename);
198 
199  buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s",
200  full_filename);
201 
202  f = fopen(tmp_filename, "w");
203  if (f == NULL) {
204  buf_dump_status(STATUS_ERR,
205  "Cannot open '%s' for writing: %s",
206  tmp_filename, strerror(errno));
207  return;
208  }
209  /* else */
210 
211  /* walk through each buffer pool */
212  for (i = 0; i < srv_buf_pool_instances && !SHOULD_QUIT(); i++) {
213  buf_pool_t* buf_pool;
214  const buf_page_t* bpage;
215  buf_dump_t* dump;
216  ulint n_pages;
217  ulint j;
218 
219  buf_pool = buf_pool_from_array(i);
220 
221  /* obtain buf_pool mutex before allocate, since
222  UT_LIST_GET_LEN(buf_pool->LRU) could change */
223  buf_pool_mutex_enter(buf_pool);
224 
225  n_pages = UT_LIST_GET_LEN(buf_pool->LRU);
226 
227  /* skip empty buffer pools */
228  if (n_pages == 0) {
229  buf_pool_mutex_exit(buf_pool);
230  continue;
231  }
232 
233  dump = static_cast<buf_dump_t*>(
234  ut_malloc(n_pages * sizeof(*dump))) ;
235 
236  if (dump == NULL) {
237  buf_pool_mutex_exit(buf_pool);
238  fclose(f);
239  buf_dump_status(STATUS_ERR,
240  "Cannot allocate " ULINTPF " bytes: %s",
241  (ulint) (n_pages * sizeof(*dump)),
242  strerror(errno));
243  /* leave tmp_filename to exist */
244  return;
245  }
246 
247  for (bpage = UT_LIST_GET_LAST(buf_pool->LRU), j = 0;
248  bpage != NULL;
249  bpage = UT_LIST_GET_PREV(LRU, bpage), j++) {
250 
251  ut_a(buf_page_in_file(bpage));
252 
253  dump[j] = BUF_DUMP_CREATE(buf_page_get_space(bpage),
254  buf_page_get_page_no(bpage));
255  }
256 
257  ut_a(j == n_pages);
258 
259  buf_pool_mutex_exit(buf_pool);
260 
261  for (j = 0; j < n_pages && !SHOULD_QUIT(); j++) {
262  ret = fprintf(f, ULINTPF "," ULINTPF "\n",
263  BUF_DUMP_SPACE(dump[j]),
264  BUF_DUMP_PAGE(dump[j]));
265  if (ret < 0) {
266  ut_free(dump);
267  fclose(f);
268  buf_dump_status(STATUS_ERR,
269  "Cannot write to '%s': %s",
270  tmp_filename, strerror(errno));
271  /* leave tmp_filename to exist */
272  return;
273  }
274 
275  if (j % 128 == 0) {
276  buf_dump_status(
277  STATUS_INFO,
278  "Dumping buffer pool "
279  ULINTPF "/" ULINTPF ", "
280  "page " ULINTPF "/" ULINTPF,
281  i + 1, srv_buf_pool_instances,
282  j + 1, n_pages);
283  }
284  }
285 
286  ut_free(dump);
287  }
288 
289  ret = fclose(f);
290  if (ret != 0) {
291  buf_dump_status(STATUS_ERR,
292  "Cannot close '%s': %s",
293  tmp_filename, strerror(errno));
294  return;
295  }
296  /* else */
297 
298  ret = unlink(full_filename);
299  if (ret != 0 && errno != ENOENT) {
300  buf_dump_status(STATUS_ERR,
301  "Cannot delete '%s': %s",
302  full_filename, strerror(errno));
303  /* leave tmp_filename to exist */
304  return;
305  }
306  /* else */
307 
308  ret = rename(tmp_filename, full_filename);
309  if (ret != 0) {
310  buf_dump_status(STATUS_ERR,
311  "Cannot rename '%s' to '%s': %s",
312  tmp_filename, full_filename,
313  strerror(errno));
314  /* leave tmp_filename to exist */
315  return;
316  }
317  /* else */
318 
319  /* success */
320 
322 
323  buf_dump_status(STATUS_NOTICE,
324  "Buffer pool(s) dump completed at %s", now);
325 }
326 
327 /*****************************************************************/
332 static
333 lint
334 buf_dump_cmp(
335 /*=========*/
336  const buf_dump_t d1,
337  const buf_dump_t d2)
338 {
339  if (d1 < d2) {
340  return(-1);
341  } else if (d1 == d2) {
342  return(0);
343  } else {
344  return(1);
345  }
346 }
347 
348 /*****************************************************************/
350 static
351 void
352 buf_dump_sort(
353 /*==========*/
354  buf_dump_t* dump,
355  buf_dump_t* tmp,
356  ulint low,
357  ulint high)
358 {
359  UT_SORT_FUNCTION_BODY(buf_dump_sort, dump, tmp, low, high,
360  buf_dump_cmp);
361 }
362 
363 /*****************************************************************/
369 static
370 void
371 buf_load()
372 /*======*/
373 {
374  char full_filename[OS_FILE_MAX_PATH];
375  char now[32];
376  FILE* f;
377  buf_dump_t* dump;
378  buf_dump_t* dump_tmp;
379  ulint dump_n;
380  ulint total_buffer_pools_pages;
381  ulint i;
382  ulint space_id;
383  ulint page_no;
384  int fscanf_ret;
385 
386  /* Ignore any leftovers from before */
387  buf_load_abort_flag = FALSE;
388 
389  ut_snprintf(full_filename, sizeof(full_filename),
390  "%s%c%s", srv_data_home, SRV_PATH_SEPARATOR,
392 
393  buf_load_status(STATUS_NOTICE,
394  "Loading buffer pool(s) from %s", full_filename);
395 
396  f = fopen(full_filename, "r");
397  if (f == NULL) {
398  buf_load_status(STATUS_ERR,
399  "Cannot open '%s' for reading: %s",
400  full_filename, strerror(errno));
401  return;
402  }
403  /* else */
404 
405  /* First scan the file to estimate how many entries are in it.
406  This file is tiny (approx 500KB per 1GB buffer pool), reading it
407  two times is fine. */
408  dump_n = 0;
409  while (fscanf(f, ULINTPF "," ULINTPF, &space_id, &page_no) == 2
410  && !SHUTTING_DOWN()) {
411  dump_n++;
412  }
413 
414  if (!SHUTTING_DOWN() && !feof(f)) {
415  /* fscanf() returned != 2 */
416  const char* what;
417  if (ferror(f)) {
418  what = "reading";
419  } else {
420  what = "parsing";
421  }
422  fclose(f);
423  buf_load_status(STATUS_ERR, "Error %s '%s', "
424  "unable to load buffer pool (stage 1)",
425  what, full_filename);
426  return;
427  }
428 
429  /* If dump is larger than the buffer pool(s), then we ignore the
430  extra trailing. This could happen if a dump is made, then buffer
431  pool is shrunk and then load it attempted. */
432  total_buffer_pools_pages = buf_pool_get_n_pages()
433  * srv_buf_pool_instances;
434  if (dump_n > total_buffer_pools_pages) {
435  dump_n = total_buffer_pools_pages;
436  }
437 
438  dump = static_cast<buf_dump_t*>(ut_malloc(dump_n * sizeof(*dump)));
439 
440  if (dump == NULL) {
441  fclose(f);
442  buf_load_status(STATUS_ERR,
443  "Cannot allocate " ULINTPF " bytes: %s",
444  (ulint) (dump_n * sizeof(*dump)),
445  strerror(errno));
446  return;
447  }
448 
449  dump_tmp = static_cast<buf_dump_t*>(
450  ut_malloc(dump_n * sizeof(*dump_tmp)));
451 
452  if (dump_tmp == NULL) {
453  ut_free(dump);
454  fclose(f);
455  buf_load_status(STATUS_ERR,
456  "Cannot allocate " ULINTPF " bytes: %s",
457  (ulint) (dump_n * sizeof(*dump_tmp)),
458  strerror(errno));
459  return;
460  }
461 
462  rewind(f);
463 
464  for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
465  fscanf_ret = fscanf(f, ULINTPF "," ULINTPF,
466  &space_id, &page_no);
467 
468  if (fscanf_ret != 2) {
469  if (feof(f)) {
470  break;
471  }
472  /* else */
473 
474  ut_free(dump);
475  ut_free(dump_tmp);
476  fclose(f);
477  buf_load_status(STATUS_ERR,
478  "Error parsing '%s', unable "
479  "to load buffer pool (stage 2)",
480  full_filename);
481  return;
482  }
483 
484  if (space_id > ULINT32_MASK || page_no > ULINT32_MASK) {
485  ut_free(dump);
486  ut_free(dump_tmp);
487  fclose(f);
488  buf_load_status(STATUS_ERR,
489  "Error parsing '%s': bogus "
490  "space,page " ULINTPF "," ULINTPF
491  " at line " ULINTPF ", "
492  "unable to load buffer pool",
493  full_filename,
494  space_id, page_no,
495  i);
496  return;
497  }
498 
499  dump[i] = BUF_DUMP_CREATE(space_id, page_no);
500  }
501 
502  /* Set dump_n to the actual number of initialized elements,
503  i could be smaller than dump_n here if the file got truncated after
504  we read it the first time. */
505  dump_n = i;
506 
507  fclose(f);
508 
509  if (dump_n == 0) {
510  ut_free(dump);
512  buf_load_status(STATUS_NOTICE,
513  "Buffer pool(s) load completed at %s "
514  "(%s was empty)", now, full_filename);
515  return;
516  }
517 
518  if (!SHUTTING_DOWN()) {
519  buf_dump_sort(dump, dump_tmp, 0, dump_n);
520  }
521 
522  ut_free(dump_tmp);
523 
524  for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
525 
526  buf_read_page_async(BUF_DUMP_SPACE(dump[i]),
527  BUF_DUMP_PAGE(dump[i]));
528 
529  if (i % 64 == 63) {
531  }
532 
533  if (i % 128 == 0) {
534  buf_load_status(STATUS_INFO,
535  "Loaded " ULINTPF "/" ULINTPF " pages",
536  i + 1, dump_n);
537  }
538 
539  if (buf_load_abort_flag) {
540  buf_load_abort_flag = FALSE;
541  ut_free(dump);
542  buf_load_status(
543  STATUS_NOTICE,
544  "Buffer pool(s) load aborted on request");
545  return;
546  }
547  }
548 
549  ut_free(dump);
550 
552 
553  buf_load_status(STATUS_NOTICE,
554  "Buffer pool(s) load completed at %s", now);
555 }
556 
557 /*****************************************************************/
561 UNIV_INTERN
562 void
563 buf_load_abort()
564 /*============*/
565 {
566  buf_load_abort_flag = TRUE;
567 }
568 
569 /*****************************************************************/
574 extern "C" UNIV_INTERN
575 os_thread_ret_t
576 DECLARE_THREAD(buf_dump_thread)(
577 /*============================*/
578  void* arg __attribute__((unused)))
580 {
582 
583  srv_buf_dump_thread_active = TRUE;
584 
585  buf_dump_status(STATUS_INFO, "not started");
586  buf_load_status(STATUS_INFO, "not started");
587 
588  if (srv_buffer_pool_load_at_startup) {
589  buf_load();
590  }
591 
592  while (!SHUTTING_DOWN()) {
593 
594  os_event_wait(srv_buf_dump_event);
595 
596  if (buf_dump_should_start) {
597  buf_dump_should_start = FALSE;
598  buf_dump(TRUE /* quit on shutdown */);
599  }
600 
601  if (buf_load_should_start) {
602  buf_load_should_start = FALSE;
603  buf_load();
604  }
605 
607  }
608 
610  buf_dump(FALSE /* ignore shutdown down flag,
611  keep going even if we are in a shutdown state */);
612  }
613 
614  srv_buf_dump_thread_active = FALSE;
615 
616  /* We count the number of threads in os_thread_exit(). A created
617  thread should always use that to exit and not use return() to exit. */
618  os_thread_exit(NULL);
619 
620  OS_THREAD_DUMMY_RETURN;
621 }