]>
Commit | Line | Data |
---|---|---|
b4e1fa2c AM |
1 | # name : innodb_lru_dump_restore.patch |
2 | # introduced : 11 or before | |
3 | # maintainer : Yasufumi | |
4 | # | |
5 | #!!! notice !!! | |
6 | # Any small change to this file in the main branch | |
7 | # should be done or reviewed by the maintainer! | |
db82db79 AM |
8 | --- a/storage/innobase/buf/buf0lru.c |
9 | +++ b/storage/innobase/buf/buf0lru.c | |
29ffd636 | 10 | @@ -2197,6 +2197,289 @@ |
b4e1fa2c AM |
11 | memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur); |
12 | } | |
13 | ||
14 | +/********************************************************************//** | |
15 | +Dump the LRU page list to the specific file. */ | |
16 | +#define LRU_DUMP_FILE "ib_lru_dump" | |
17 | + | |
18 | +UNIV_INTERN | |
19 | +ibool | |
20 | +buf_LRU_file_dump(void) | |
21 | +/*===================*/ | |
22 | +{ | |
23 | + os_file_t dump_file = -1; | |
24 | + ibool success; | |
25 | + byte* buffer_base = NULL; | |
26 | + byte* buffer = NULL; | |
27 | + buf_page_t* bpage; | |
28 | + ulint buffers; | |
29 | + ulint offset; | |
30 | + ibool ret = FALSE; | |
31 | + ulint i; | |
32 | + | |
33 | + for (i = 0; i < srv_n_data_files; i++) { | |
34 | + if (strstr(srv_data_file_names[i], LRU_DUMP_FILE) != NULL) { | |
35 | + fprintf(stderr, | |
36 | + " InnoDB: The name '%s' seems to be used for" | |
d8778560 AM |
37 | + " innodb_data_file_path. For safety, dumping of the LRU list" |
38 | + " is not being done.\n", LRU_DUMP_FILE); | |
b4e1fa2c AM |
39 | + goto end; |
40 | + } | |
41 | + } | |
42 | + | |
43 | + buffer_base = ut_malloc(2 * UNIV_PAGE_SIZE); | |
44 | + buffer = ut_align(buffer_base, UNIV_PAGE_SIZE); | |
45 | + if (!buffer) { | |
46 | + fprintf(stderr, | |
47 | + " InnoDB: cannot allocate buffer.\n"); | |
48 | + goto end; | |
49 | + } | |
50 | + | |
51 | + dump_file = os_file_create(innodb_file_temp_key, LRU_DUMP_FILE, OS_FILE_OVERWRITE, | |
52 | + OS_FILE_NORMAL, OS_DATA_FILE, &success); | |
53 | + if (!success) { | |
54 | + os_file_get_last_error(TRUE); | |
55 | + fprintf(stderr, | |
56 | + " InnoDB: cannot open %s\n", LRU_DUMP_FILE); | |
57 | + goto end; | |
58 | + } | |
59 | + | |
60 | + buffers = offset = 0; | |
61 | + | |
62 | + for (i = 0; i < srv_buf_pool_instances; i++) { | |
63 | + buf_pool_t* buf_pool; | |
64 | + | |
65 | + buf_pool = buf_pool_from_array(i); | |
66 | + | |
67 | + mutex_enter(&buf_pool->LRU_list_mutex); | |
68 | + bpage = UT_LIST_GET_LAST(buf_pool->LRU); | |
69 | + | |
70 | + while (bpage != NULL) { | |
71 | + if (offset == 0) { | |
72 | + memset(buffer, 0, UNIV_PAGE_SIZE); | |
73 | + } | |
74 | + | |
75 | + mach_write_to_4(buffer + offset * 4, bpage->space); | |
76 | + offset++; | |
77 | + mach_write_to_4(buffer + offset * 4, bpage->offset); | |
78 | + offset++; | |
79 | + | |
80 | + if (offset == UNIV_PAGE_SIZE/4) { | |
81 | + success = os_file_write(LRU_DUMP_FILE, dump_file, buffer, | |
82 | + (buffers << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL, | |
83 | + (buffers >> (32 - UNIV_PAGE_SIZE_SHIFT)), | |
84 | + UNIV_PAGE_SIZE); | |
85 | + if (!success) { | |
86 | + mutex_exit(&buf_pool->LRU_list_mutex); | |
87 | + fprintf(stderr, | |
88 | + " InnoDB: cannot write page %lu of %s\n", | |
89 | + buffers, LRU_DUMP_FILE); | |
90 | + goto end; | |
91 | + } | |
92 | + buffers++; | |
93 | + offset = 0; | |
94 | + } | |
95 | + | |
96 | + bpage = UT_LIST_GET_PREV(LRU, bpage); | |
97 | + } | |
98 | + mutex_exit(&buf_pool->LRU_list_mutex); | |
99 | + } | |
100 | + | |
101 | + if (offset == 0) { | |
102 | + memset(buffer, 0, UNIV_PAGE_SIZE); | |
103 | + } | |
104 | + | |
105 | + mach_write_to_4(buffer + offset * 4, 0xFFFFFFFFUL); | |
106 | + offset++; | |
107 | + mach_write_to_4(buffer + offset * 4, 0xFFFFFFFFUL); | |
108 | + offset++; | |
109 | + | |
110 | + success = os_file_write(LRU_DUMP_FILE, dump_file, buffer, | |
111 | + (buffers << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL, | |
112 | + (buffers >> (32 - UNIV_PAGE_SIZE_SHIFT)), | |
113 | + UNIV_PAGE_SIZE); | |
114 | + if (!success) { | |
115 | + goto end; | |
116 | + } | |
117 | + | |
118 | + ret = TRUE; | |
119 | +end: | |
120 | + if (dump_file != -1) | |
121 | + os_file_close(dump_file); | |
122 | + if (buffer_base) | |
123 | + ut_free(buffer_base); | |
124 | + | |
125 | + return(ret); | |
126 | +} | |
127 | + | |
128 | +typedef struct { | |
129 | + ib_uint32_t space_id; | |
130 | + ib_uint32_t page_no; | |
131 | +} dump_record_t; | |
132 | + | |
133 | +static int dump_record_cmp(const void *a, const void *b) | |
134 | +{ | |
135 | + const dump_record_t *rec1 = (dump_record_t *) a; | |
136 | + const dump_record_t *rec2 = (dump_record_t *) b; | |
137 | + | |
138 | + if (rec1->space_id < rec2->space_id) | |
139 | + return -1; | |
140 | + if (rec1->space_id > rec2->space_id) | |
141 | + return 1; | |
142 | + if (rec1->page_no < rec2->page_no) | |
143 | + return -1; | |
144 | + return rec1->page_no > rec2->page_no; | |
145 | +} | |
146 | + | |
147 | +/********************************************************************//** | |
148 | +Read the pages based on the specific file.*/ | |
149 | +UNIV_INTERN | |
150 | +ibool | |
151 | +buf_LRU_file_restore(void) | |
152 | +/*======================*/ | |
153 | +{ | |
154 | + os_file_t dump_file = -1; | |
155 | + ibool success; | |
156 | + byte* buffer_base = NULL; | |
157 | + byte* buffer = NULL; | |
158 | + ulint buffers; | |
159 | + ulint offset; | |
160 | + ulint reads = 0; | |
161 | + ulint req = 0; | |
162 | + ibool terminated = FALSE; | |
163 | + ibool ret = FALSE; | |
164 | + dump_record_t* records = NULL; | |
165 | + ulint size; | |
166 | + ulint size_high; | |
167 | + ulint length; | |
168 | + | |
169 | + dump_file = os_file_create_simple_no_error_handling(innodb_file_temp_key, | |
170 | + LRU_DUMP_FILE, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success); | |
171 | + if (!success || !os_file_get_size(dump_file, &size, &size_high)) { | |
172 | + os_file_get_last_error(TRUE); | |
173 | + fprintf(stderr, | |
174 | + " InnoDB: cannot open %s\n", LRU_DUMP_FILE); | |
175 | + goto end; | |
176 | + } | |
734d6226 AM |
177 | + |
178 | + ut_print_timestamp(stderr); | |
179 | + fprintf(stderr, " InnoDB: Restoring buffer pool pages from %s\n", | |
180 | + LRU_DUMP_FILE); | |
181 | + | |
b4e1fa2c AM |
182 | + if (size == 0 || size_high > 0 || size % 8) { |
183 | + fprintf(stderr, " InnoDB: broken LRU dump file\n"); | |
184 | + goto end; | |
185 | + } | |
186 | + buffer_base = ut_malloc(2 * UNIV_PAGE_SIZE); | |
187 | + buffer = ut_align(buffer_base, UNIV_PAGE_SIZE); | |
188 | + records = ut_malloc(size); | |
189 | + if (!buffer || !records) { | |
190 | + fprintf(stderr, | |
191 | + " InnoDB: cannot allocate buffer.\n"); | |
192 | + goto end; | |
193 | + } | |
194 | + | |
195 | + buffers = 0; | |
196 | + length = 0; | |
197 | + while (!terminated) { | |
198 | + success = os_file_read(dump_file, buffer, | |
199 | + (buffers << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL, | |
200 | + (buffers >> (32 - UNIV_PAGE_SIZE_SHIFT)), | |
201 | + UNIV_PAGE_SIZE); | |
202 | + if (!success) { | |
203 | + fprintf(stderr, | |
d8778560 AM |
204 | + " InnoDB: either could not read page %lu of %s," |
205 | + " or terminated unexpectedly.\n", | |
b4e1fa2c AM |
206 | + buffers, LRU_DUMP_FILE); |
207 | + goto end; | |
208 | + } | |
209 | + | |
210 | + for (offset = 0; offset < UNIV_PAGE_SIZE/4; offset += 2) { | |
211 | + ulint space_id; | |
212 | + ulint page_no; | |
213 | + | |
214 | + space_id = mach_read_from_4(buffer + offset * 4); | |
215 | + page_no = mach_read_from_4(buffer + (offset + 1) * 4); | |
216 | + if (space_id == 0xFFFFFFFFUL | |
217 | + || page_no == 0xFFFFFFFFUL) { | |
218 | + terminated = TRUE; | |
219 | + break; | |
220 | + } | |
221 | + | |
222 | + records[length].space_id = space_id; | |
223 | + records[length].page_no = page_no; | |
224 | + length++; | |
225 | + if (length * 8 >= size) { | |
226 | + fprintf(stderr, | |
227 | + " InnoDB: could not find the " | |
228 | + "end-of-file marker after reading " | |
229 | + "the expected %lu bytes from the " | |
230 | + "LRU dump file.\n" | |
231 | + " InnoDB: this could be caused by a " | |
232 | + "broken or incomplete file.\n" | |
233 | + " InnoDB: trying to process what has " | |
234 | + "been read so far.\n", | |
235 | + size); | |
236 | + terminated= TRUE; | |
237 | + break; | |
238 | + } | |
239 | + } | |
240 | + buffers++; | |
241 | + } | |
242 | + | |
243 | + qsort(records, length, sizeof(dump_record_t), dump_record_cmp); | |
244 | + | |
245 | + for (offset = 0; offset < length; offset++) { | |
246 | + ulint space_id; | |
247 | + ulint page_no; | |
248 | + ulint zip_size; | |
249 | + ulint err; | |
250 | + ib_int64_t tablespace_version; | |
251 | + | |
252 | + space_id = records[offset].space_id; | |
253 | + page_no = records[offset].page_no; | |
254 | + | |
255 | + if (offset % 16 == 15) { | |
256 | + os_aio_simulated_wake_handler_threads(); | |
257 | + buf_flush_free_margins(FALSE); | |
258 | + } | |
259 | + | |
260 | + zip_size = fil_space_get_zip_size(space_id); | |
261 | + if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) { | |
262 | + continue; | |
263 | + } | |
264 | + | |
d8778560 | 265 | + if (fil_is_exist(space_id, page_no)) { |
b4e1fa2c AM |
266 | + |
267 | + tablespace_version = fil_space_get_version(space_id); | |
268 | + | |
269 | + req++; | |
270 | + reads += buf_read_page_low(&err, FALSE, BUF_READ_ANY_PAGE | |
271 | + | OS_AIO_SIMULATED_WAKE_LATER, | |
272 | + space_id, zip_size, TRUE, | |
273 | + tablespace_version, page_no, NULL); | |
274 | + buf_LRU_stat_inc_io(); | |
275 | + } | |
276 | + } | |
277 | + | |
278 | + os_aio_simulated_wake_handler_threads(); | |
279 | + buf_flush_free_margins(FALSE); | |
280 | + | |
281 | + ut_print_timestamp(stderr); | |
282 | + fprintf(stderr, | |
734d6226 | 283 | + " InnoDB: Completed reading buffer pool pages" |
b4e1fa2c AM |
284 | + " (requested: %lu, read: %lu)\n", req, reads); |
285 | + ret = TRUE; | |
286 | +end: | |
287 | + if (dump_file != -1) | |
288 | + os_file_close(dump_file); | |
289 | + if (buffer_base) | |
290 | + ut_free(buffer_base); | |
291 | + if (records) | |
292 | + ut_free(records); | |
293 | + | |
294 | + return(ret); | |
295 | +} | |
296 | + | |
297 | #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG | |
298 | /**********************************************************************//** | |
299 | Validates the LRU list for one buffer pool instance. */ | |
db82db79 AM |
300 | --- a/storage/innobase/buf/buf0rea.c |
301 | +++ b/storage/innobase/buf/buf0rea.c | |
734d6226 | 302 | @@ -60,7 +60,7 @@ |
b4e1fa2c AM |
303 | which case it is never read into the pool, or if the tablespace does |
304 | not exist or is being dropped | |
305 | @return 1 if read request is issued. 0 if it is not */ | |
306 | -static | |
307 | +UNIV_INTERN | |
308 | ulint | |
309 | buf_read_page_low( | |
310 | /*==============*/ | |
db82db79 AM |
311 | --- a/storage/innobase/fil/fil0fil.c |
312 | +++ b/storage/innobase/fil/fil0fil.c | |
29ffd636 | 313 | @@ -5307,6 +5307,70 @@ |
b4e1fa2c AM |
314 | return(DB_SUCCESS); |
315 | } | |
316 | ||
317 | +/********************************************************************//** | |
318 | +Confirm whether the parameters are valid or not */ | |
319 | +UNIV_INTERN | |
320 | +ibool | |
d8778560 | 321 | +fil_is_exist( |
b4e1fa2c AM |
322 | +/*==============*/ |
323 | + ulint space_id, /*!< in: space id */ | |
d8778560 | 324 | + ulint block_offset) /*!< in: offset in number of blocks */ |
b4e1fa2c AM |
325 | +{ |
326 | + fil_space_t* space; | |
327 | + fil_node_t* node; | |
328 | + | |
329 | + /* Reserve the fil_system mutex and make sure that we can open at | |
330 | + least one file while holding it, if the file is not already open */ | |
331 | + | |
332 | + fil_mutex_enter_and_prepare_for_io(space_id); | |
333 | + | |
334 | + space = fil_space_get_by_id(space_id); | |
335 | + | |
336 | + if (!space) { | |
337 | + mutex_exit(&fil_system->mutex); | |
338 | + return(FALSE); | |
339 | + } | |
340 | + | |
341 | + node = UT_LIST_GET_FIRST(space->chain); | |
342 | + | |
343 | + for (;;) { | |
344 | + if (UNIV_UNLIKELY(node == NULL)) { | |
345 | + mutex_exit(&fil_system->mutex); | |
346 | + return(FALSE); | |
347 | + } | |
348 | + | |
349 | + if (space->id != 0 && node->size == 0) { | |
350 | + /* We do not know the size of a single-table tablespace | |
351 | + before we open the file */ | |
352 | + | |
353 | + break; | |
354 | + } | |
355 | + | |
356 | + if (node->size > block_offset) { | |
357 | + /* Found! */ | |
358 | + break; | |
359 | + } else { | |
360 | + block_offset -= node->size; | |
361 | + node = UT_LIST_GET_NEXT(chain, node); | |
362 | + } | |
363 | + } | |
364 | + | |
365 | + /* Open file if closed */ | |
366 | + fil_node_prepare_for_io(node, fil_system, space); | |
367 | + fil_node_complete_io(node, fil_system, OS_FILE_READ); | |
368 | + | |
369 | + /* Check that at least the start offset is within the bounds of a | |
370 | + single-table tablespace */ | |
371 | + if (UNIV_UNLIKELY(node->size <= block_offset) | |
372 | + && space->id != 0 && space->purpose == FIL_TABLESPACE) { | |
373 | + mutex_exit(&fil_system->mutex); | |
374 | + return(FALSE); | |
375 | + } | |
376 | + | |
377 | + mutex_exit(&fil_system->mutex); | |
378 | + return(TRUE); | |
379 | +} | |
380 | + | |
381 | #ifndef UNIV_HOTBACKUP | |
382 | /**********************************************************************//** | |
383 | Waits for an aio operation to complete. This function is used to write the | |
db82db79 AM |
384 | --- a/storage/innobase/handler/ha_innodb.cc |
385 | +++ b/storage/innobase/handler/ha_innodb.cc | |
734d6226 AM |
386 | @@ -196,6 +196,8 @@ |
387 | ||
388 | static char* innodb_version_str = (char*) INNODB_VERSION_STR; | |
389 | ||
390 | +static my_bool innobase_blocking_lru_restore = FALSE; | |
391 | + | |
392 | /** Possible values for system variable "innodb_stats_method". The values | |
393 | are defined the same as its corresponding MyISAM system variable | |
394 | "myisam_stats_method"(see "myisam_stats_method_names"), for better usability */ | |
395 | @@ -2652,6 +2654,8 @@ | |
396 | srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite; | |
397 | srv_use_checksums = (ibool) innobase_use_checksums; | |
398 | ||
399 | + srv_blocking_lru_restore = (ibool) innobase_blocking_lru_restore; | |
400 | + | |
401 | #ifdef HAVE_LARGE_PAGES | |
402 | if ((os_use_large_pages = (ibool) my_use_large_pages)) | |
403 | os_large_page_size = (ulint) opt_large_page_size; | |
29ffd636 | 404 | @@ -11964,6 +11968,19 @@ |
b4e1fa2c AM |
405 | "Limit the allocated memory for dictionary cache. (0: unlimited)", |
406 | NULL, NULL, 0, 0, LONG_MAX, 0); | |
407 | ||
a9ee80b9 | 408 | +static MYSQL_SYSVAR_UINT(buffer_pool_restore_at_startup, srv_auto_lru_dump, |
b4e1fa2c AM |
409 | + PLUGIN_VAR_RQCMDARG, |
410 | + "Time in seconds between automatic buffer pool dumps. " | |
411 | + "0 (the default) disables automatic dumps.", | |
412 | + NULL, NULL, 0, 0, UINT_MAX32, 0); | |
734d6226 AM |
413 | + |
414 | +static MYSQL_SYSVAR_BOOL(blocking_buffer_pool_restore, | |
415 | + innobase_blocking_lru_restore, | |
416 | + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, | |
417 | + "Block XtraDB startup process until buffer pool is full restored from a " | |
418 | + "dump file (if present). Disabled by default.", | |
419 | + NULL, NULL, FALSE); | |
b4e1fa2c AM |
420 | + |
421 | static struct st_mysql_sys_var* innobase_system_variables[]= { | |
422 | MYSQL_SYSVAR(additional_mem_pool_size), | |
423 | MYSQL_SYSVAR(autoextend_increment), | |
29ffd636 | 424 | @@ -12048,6 +12065,8 @@ |
734d6226 | 425 | MYSQL_SYSVAR(random_read_ahead), |
b4e1fa2c AM |
426 | MYSQL_SYSVAR(read_ahead_threshold), |
427 | MYSQL_SYSVAR(io_capacity), | |
a9ee80b9 | 428 | + MYSQL_SYSVAR(buffer_pool_restore_at_startup), |
734d6226 | 429 | + MYSQL_SYSVAR(blocking_buffer_pool_restore), |
b4e1fa2c AM |
430 | MYSQL_SYSVAR(purge_threads), |
431 | MYSQL_SYSVAR(purge_batch_size), | |
11822e22 | 432 | MYSQL_SYSVAR(rollback_segments), |
db82db79 AM |
433 | --- a/storage/innobase/handler/i_s.cc |
434 | +++ b/storage/innobase/handler/i_s.cc | |
b4e1fa2c AM |
435 | @@ -50,6 +50,7 @@ |
436 | #include "trx0rseg.h" /* for trx_rseg_struct */ | |
437 | #include "trx0sys.h" /* for trx_sys */ | |
438 | #include "dict0dict.h" /* for dict_sys */ | |
439 | +#include "buf0lru.h" /* for XTRA_LRU_[DUMP/RESTORE] */ | |
440 | } | |
441 | ||
adf0fb13 | 442 | #define OK(expr) \ |
1bfc1981 | 443 | @@ -4336,6 +4337,36 @@ |
b4e1fa2c AM |
444 | "Hello!"); |
445 | goto end_func; | |
446 | } | |
447 | + else if (!strncasecmp("XTRA_LRU_DUMP", ptr, 13)) { | |
448 | + ut_print_timestamp(stderr); | |
d8778560 | 449 | + fprintf(stderr, " InnoDB: Administrative command 'XTRA_LRU_DUMP'" |
b4e1fa2c AM |
450 | + " was detected.\n"); |
451 | + | |
452 | + if (buf_LRU_file_dump()) { | |
453 | + field_store_string(i_s_table->field[0], | |
454 | + "XTRA_LRU_DUMP was succeeded."); | |
455 | + } else { | |
456 | + field_store_string(i_s_table->field[0], | |
457 | + "XTRA_LRU_DUMP was failed."); | |
458 | + } | |
459 | + | |
460 | + goto end_func; | |
461 | + } | |
462 | + else if (!strncasecmp("XTRA_LRU_RESTORE", ptr, 16)) { | |
463 | + ut_print_timestamp(stderr); | |
d8778560 | 464 | + fprintf(stderr, " InnoDB: Administrative command 'XTRA_LRU_RESTORE'" |
b4e1fa2c AM |
465 | + " was detected.\n"); |
466 | + | |
467 | + if (buf_LRU_file_restore()) { | |
468 | + field_store_string(i_s_table->field[0], | |
469 | + "XTRA_LRU_RESTORE was succeeded."); | |
470 | + } else { | |
471 | + field_store_string(i_s_table->field[0], | |
472 | + "XTRA_LRU_RESTORE was failed."); | |
473 | + } | |
474 | + | |
475 | + goto end_func; | |
476 | + } | |
477 | ||
478 | field_store_string(i_s_table->field[0], | |
479 | "Undefined XTRA_* command."); | |
db82db79 AM |
480 | --- a/storage/innobase/include/buf0lru.h |
481 | +++ b/storage/innobase/include/buf0lru.h | |
482 | @@ -204,6 +204,18 @@ | |
b4e1fa2c AM |
483 | void |
484 | buf_LRU_stat_update(void); | |
485 | /*=====================*/ | |
486 | +/********************************************************************//** | |
487 | +Dump the LRU page list to the specific file. */ | |
488 | +UNIV_INTERN | |
489 | +ibool | |
490 | +buf_LRU_file_dump(void); | |
491 | +/*===================*/ | |
492 | +/********************************************************************//** | |
493 | +Read the pages based on the specific file.*/ | |
494 | +UNIV_INTERN | |
495 | +ibool | |
496 | +buf_LRU_file_restore(void); | |
497 | +/*======================*/ | |
498 | ||
734d6226 AM |
499 | /******************************************************************//** |
500 | Remove one page from LRU list and put it to free list */ | |
db82db79 AM |
501 | --- a/storage/innobase/include/buf0rea.h |
502 | +++ b/storage/innobase/include/buf0rea.h | |
b4e1fa2c AM |
503 | @@ -31,6 +31,37 @@ |
504 | #include "buf0types.h" | |
505 | ||
506 | /********************************************************************//** | |
507 | +Low-level function which reads a page asynchronously from a file to the | |
508 | +buffer buf_pool if it is not already there, in which case does nothing. | |
509 | +Sets the io_fix flag and sets an exclusive lock on the buffer frame. The | |
510 | +flag is cleared and the x-lock released by an i/o-handler thread. | |
511 | +@return 1 if a read request was queued, 0 if the page already resided | |
512 | +in buf_pool, or if the page is in the doublewrite buffer blocks in | |
513 | +which case it is never read into the pool, or if the tablespace does | |
514 | +not exist or is being dropped | |
515 | +@return 1 if read request is issued. 0 if it is not */ | |
516 | +UNIV_INTERN | |
517 | +ulint | |
518 | +buf_read_page_low( | |
519 | +/*==============*/ | |
520 | + ulint* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are | |
521 | + trying to read from a non-existent tablespace, or a | |
522 | + tablespace which is just now being dropped */ | |
523 | + ibool sync, /*!< in: TRUE if synchronous aio is desired */ | |
524 | + ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ..., | |
525 | + ORed to OS_AIO_SIMULATED_WAKE_LATER (see below | |
526 | + at read-ahead functions) */ | |
527 | + ulint space, /*!< in: space id */ | |
528 | + ulint zip_size,/*!< in: compressed page size, or 0 */ | |
529 | + ibool unzip, /*!< in: TRUE=request uncompressed page */ | |
530 | + ib_int64_t tablespace_version, /*!< in: if the space memory object has | |
531 | + this timestamp different from what we are giving here, | |
532 | + treat the tablespace as dropped; this is a timestamp we | |
533 | + use to stop dangling page reads from a tablespace | |
534 | + which we have DISCARDed + IMPORTed back */ | |
535 | + ulint offset, /*!< in: page number */ | |
536 | + trx_t* trx); | |
537 | +/********************************************************************//** | |
538 | High-level function which reads a page asynchronously from a file to the | |
539 | buffer buf_pool if it is not already there. Sets the io_fix flag and sets | |
540 | an exclusive lock on the buffer frame. The flag is cleared and the x-lock | |
db82db79 AM |
541 | --- a/storage/innobase/include/fil0fil.h |
542 | +++ b/storage/innobase/include/fil0fil.h | |
29ffd636 | 543 | @@ -653,6 +653,14 @@ |
b4e1fa2c AM |
544 | void* message, /*!< in: message for aio handler if non-sync |
545 | aio used, else ignored */ | |
546 | trx_t* trx); | |
547 | +/********************************************************************//** | |
548 | +Confirm whether the parameters are valid or not */ | |
549 | +UNIV_INTERN | |
550 | +ibool | |
d8778560 | 551 | +fil_is_exist( |
b4e1fa2c AM |
552 | +/*==============*/ |
553 | + ulint space_id, /*!< in: space id */ | |
d8778560 | 554 | + ulint block_offset); /*!< in: offset in number of blocks */ |
b4e1fa2c AM |
555 | /**********************************************************************//** |
556 | Waits for an aio operation to complete. This function is used to write the | |
557 | handler for completed requests. The aio array of pending requests is divided | |
db82db79 AM |
558 | --- a/storage/innobase/include/srv0srv.h |
559 | +++ b/storage/innobase/include/srv0srv.h | |
29ffd636 | 560 | @@ -364,6 +364,12 @@ |
b4e1fa2c AM |
561 | reading of a disk page */ |
562 | extern ulint srv_buf_pool_reads; | |
563 | ||
564 | +/** Time in seconds between automatic buffer pool dumps */ | |
565 | +extern uint srv_auto_lru_dump; | |
734d6226 AM |
566 | + |
567 | +/** Whether startup should be blocked until buffer pool is fully restored */ | |
568 | +extern ibool srv_blocking_lru_restore; | |
b4e1fa2c AM |
569 | + |
570 | /** Status variables to be passed to MySQL */ | |
571 | typedef struct export_var_struct export_struc; | |
572 | ||
29ffd636 | 573 | @@ -669,6 +675,16 @@ |
b4e1fa2c AM |
574 | /*=====================*/ |
575 | void* arg); /*!< in: a dummy parameter required by | |
576 | os_thread_create */ | |
577 | +/*********************************************************************//** | |
578 | +A thread which restores the buffer pool from a dump file on startup and does | |
579 | +periodic buffer pool dumps. | |
580 | +@return a dummy parameter */ | |
581 | +UNIV_INTERN | |
582 | +os_thread_ret_t | |
583 | +srv_LRU_dump_restore_thread( | |
584 | +/*====================*/ | |
585 | + void* arg); /*!< in: a dummy parameter required by | |
586 | + os_thread_create */ | |
587 | /******************************************************************//** | |
588 | Outputs to a file the output of the InnoDB Monitor. | |
589 | @return FALSE if not all information printed | |
db82db79 AM |
590 | --- a/storage/innobase/srv/srv0srv.c |
591 | +++ b/storage/innobase/srv/srv0srv.c | |
734d6226 | 592 | @@ -332,6 +332,12 @@ |
b4e1fa2c AM |
593 | reading of a disk page */ |
594 | UNIV_INTERN ulint srv_buf_pool_reads = 0; | |
595 | ||
596 | +/** Time in seconds between automatic buffer pool dumps */ | |
597 | +UNIV_INTERN uint srv_auto_lru_dump = 0; | |
734d6226 AM |
598 | + |
599 | +/** Whether startup should be blocked until buffer pool is fully restored */ | |
600 | +UNIV_INTERN ibool srv_blocking_lru_restore; | |
b4e1fa2c AM |
601 | + |
602 | /* structure to pass status variables to MySQL */ | |
603 | UNIV_INTERN export_struc export_vars; | |
604 | ||
29ffd636 AM |
605 | @@ -2708,6 +2714,58 @@ |
606 | /* We count the number of threads in os_thread_exit(). A created | |
607 | thread should always use that to exit and not use return() to exit. */ | |
b4e1fa2c | 608 | |
29ffd636 AM |
609 | + os_thread_exit(NULL); |
610 | + | |
611 | + OS_THREAD_DUMMY_RETURN; | |
612 | +} | |
613 | + | |
b4e1fa2c AM |
614 | +/*********************************************************************//** |
615 | +A thread which restores the buffer pool from a dump file on startup and does | |
616 | +periodic buffer pool dumps. | |
617 | +@return a dummy parameter */ | |
618 | +UNIV_INTERN | |
619 | +os_thread_ret_t | |
620 | +srv_LRU_dump_restore_thread( | |
621 | +/*====================*/ | |
622 | + void* arg __attribute__((unused))) | |
623 | + /*!< in: a dummy parameter required by | |
624 | + os_thread_create */ | |
625 | +{ | |
626 | + uint auto_lru_dump; | |
627 | + time_t last_dump_time; | |
628 | + time_t time_elapsed; | |
629 | + | |
630 | +#ifdef UNIV_DEBUG_THREAD_CREATION | |
d8778560 | 631 | + fprintf(stderr, "The LRU dump/restore thread has started, id %lu\n", |
b4e1fa2c AM |
632 | + os_thread_pf(os_thread_get_curr_id())); |
633 | +#endif | |
634 | + | |
734d6226 AM |
635 | + /* If srv_blocking_lru_restore is TRUE, restore will be done |
636 | + synchronously on startup. */ | |
637 | + if (srv_auto_lru_dump && !srv_blocking_lru_restore) | |
b4e1fa2c AM |
638 | + buf_LRU_file_restore(); |
639 | + | |
640 | + last_dump_time = time(NULL); | |
641 | + | |
642 | +loop: | |
643 | + os_thread_sleep(5000000); | |
644 | + | |
645 | + if (srv_shutdown_state >= SRV_SHUTDOWN_CLEANUP) { | |
646 | + goto exit_func; | |
647 | + } | |
648 | + | |
649 | + time_elapsed = time(NULL) - last_dump_time; | |
650 | + auto_lru_dump = srv_auto_lru_dump; | |
651 | + if (auto_lru_dump > 0 && (time_t) auto_lru_dump < time_elapsed) { | |
652 | + last_dump_time = time(NULL); | |
653 | + buf_LRU_file_dump(); | |
654 | + } | |
655 | + | |
656 | + goto loop; | |
657 | +exit_func: | |
658 | + /* We count the number of threads in os_thread_exit(). A created | |
659 | + thread should always use that to exit and not use return() to exit. */ | |
660 | + | |
29ffd636 AM |
661 | os_thread_exit(NULL); |
662 | ||
663 | OS_THREAD_DUMMY_RETURN; | |
db82db79 AM |
664 | --- a/storage/innobase/srv/srv0start.c |
665 | +++ b/storage/innobase/srv/srv0start.c | |
734d6226 AM |
666 | @@ -87,6 +87,7 @@ |
667 | # include "btr0pcur.h" | |
668 | # include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ | |
669 | # include "zlib.h" /* for ZLIB_VERSION */ | |
670 | +# include "buf0lru.h" /* for buf_LRU_file_restore() */ | |
671 | ||
672 | /** Log sequence number immediately after startup */ | |
673 | UNIV_INTERN ib_uint64_t srv_start_lsn; | |
674 | @@ -120,9 +121,9 @@ | |
b4e1fa2c AM |
675 | static os_file_t files[1000]; |
676 | ||
677 | /** io_handler_thread parameters for thread identification */ | |
678 | -static ulint n[SRV_MAX_N_IO_THREADS + 6]; | |
679 | +static ulint n[SRV_MAX_N_IO_THREADS + 7]; | |
680 | /** io_handler_thread identifiers */ | |
681 | -static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 6]; | |
682 | +static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 7]; | |
683 | ||
684 | /** We use this mutex to test the return value of pthread_mutex_trylock | |
685 | on successful locking. HP-UX does NOT return 0, though Linux et al do. */ | |
29ffd636 | 686 | @@ -1841,6 +1842,15 @@ |
b4e1fa2c AM |
687 | os_thread_create(&srv_monitor_thread, NULL, |
688 | thread_ids + 4 + SRV_MAX_N_IO_THREADS); | |
689 | ||
690 | + /* Create the thread which automaticaly dumps/restore buffer pool */ | |
691 | + os_thread_create(&srv_LRU_dump_restore_thread, NULL, | |
692 | + thread_ids + 5 + SRV_MAX_N_IO_THREADS); | |
734d6226 AM |
693 | + |
694 | + /* If srv_blocking_lru_restore is TRUE, load buffer pool contents | |
695 | + synchronously */ | |
696 | + if (srv_auto_lru_dump && srv_blocking_lru_restore) | |
697 | + buf_LRU_file_restore(); | |
b4e1fa2c AM |
698 | + |
699 | srv_is_being_started = FALSE; | |
700 | ||
701 | err = dict_create_or_check_foreign_constraint_tables(); | |
734d6226 AM |
702 | --- /dev/null |
703 | +++ b/mysql-test/suite/sys_vars/r/innodb_blocking_buffer_pool_restore_basic.result | |
704 | @@ -0,0 +1,3 @@ | |
705 | +SELECT @@global.innodb_blocking_buffer_pool_restore; | |
706 | +@@global.innodb_blocking_buffer_pool_restore | |
707 | +0 | |
708 | --- /dev/null | |
709 | +++ b/mysql-test/suite/sys_vars/t/innodb_blocking_buffer_pool_restore_basic.test | |
710 | @@ -0,0 +1 @@ | |
711 | +SELECT @@global.innodb_blocking_buffer_pool_restore; |