1
# name : innodb_recovery_patches.patch
2
# introduced : 11 or before
3
# maintainer : Yasufumi
6
# Any small change to this file in the main branch
7
# should be done or reviewed by the maintainer!
8
--- a/storage/innodb_plugin/buf/buf0rea.c
9
+++ b/storage/innodb_plugin/buf/buf0rea.c
11
bpage = buf_page_init_for_read(err, mode, space, zip_size, unzip,
12
tablespace_version, offset);
14
+ /* bugfix: http://bugs.mysql.com/bug.php?id=43948 */
15
+ if (recv_recovery_is_on() && *err == DB_TABLESPACE_DELETED) {
16
+ /* hashed log recs must be treated here */
17
+ recv_addr_t* recv_addr;
19
+ mutex_enter(&(recv_sys->mutex));
21
+ if (recv_sys->apply_log_recs == FALSE) {
22
+ mutex_exit(&(recv_sys->mutex));
23
+ goto not_to_recover;
26
+ /* recv_get_fil_addr_struct() */
27
+ recv_addr = HASH_GET_FIRST(recv_sys->addr_hash,
28
+ hash_calc_hash(ut_fold_ulint_pair(space, offset),
29
+ recv_sys->addr_hash));
31
+ if ((recv_addr->space == space)
32
+ && (recv_addr->page_no == offset)) {
35
+ recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
38
+ if ((recv_addr == NULL)
39
+ || (recv_addr->state == RECV_BEING_PROCESSED)
40
+ || (recv_addr->state == RECV_PROCESSED)) {
41
+ mutex_exit(&(recv_sys->mutex));
42
+ goto not_to_recover;
45
+ fprintf(stderr, " (cannot find space: %lu)", space);
46
+ recv_addr->state = RECV_PROCESSED;
48
+ ut_a(recv_sys->n_addrs);
49
+ recv_sys->n_addrs--;
51
+ mutex_exit(&(recv_sys->mutex));
58
/* It is a single table tablespace and the .ibd file is
59
missing: do nothing */
61
+ /* the log records should be treated here same reason
62
+ for http://bugs.mysql.com/bug.php?id=43948 */
64
+ if (recv_recovery_is_on()) {
65
+ recv_addr_t* recv_addr;
67
+ mutex_enter(&(recv_sys->mutex));
69
+ if (recv_sys->apply_log_recs == FALSE) {
70
+ mutex_exit(&(recv_sys->mutex));
71
+ goto not_to_recover;
74
+ for (i = 0; i < n_stored; i++) {
75
+ /* recv_get_fil_addr_struct() */
76
+ recv_addr = HASH_GET_FIRST(recv_sys->addr_hash,
77
+ hash_calc_hash(ut_fold_ulint_pair(space, page_nos[i]),
78
+ recv_sys->addr_hash));
80
+ if ((recv_addr->space == space)
81
+ && (recv_addr->page_no == page_nos[i])) {
84
+ recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
87
+ if ((recv_addr == NULL)
88
+ || (recv_addr->state == RECV_BEING_PROCESSED)
89
+ || (recv_addr->state == RECV_PROCESSED)) {
93
+ recv_addr->state = RECV_PROCESSED;
95
+ ut_a(recv_sys->n_addrs);
96
+ recv_sys->n_addrs--;
99
+ mutex_exit(&(recv_sys->mutex));
101
+ fprintf(stderr, " (cannot find space: %lu)", space);
108
--- a/storage/innodb_plugin/handler/ha_innodb.cc
109
+++ b/storage/innodb_plugin/handler/ha_innodb.cc
111
static my_bool innobase_use_doublewrite = TRUE;
112
static my_bool innobase_use_checksums = TRUE;
113
static my_bool innobase_extra_undoslots = FALSE;
114
+static my_bool innobase_fast_recovery = FALSE;
115
+static my_bool innobase_recovery_stats = TRUE;
116
static my_bool innobase_locks_unsafe_for_binlog = FALSE;
117
static my_bool innobase_overwrite_relay_log_info = FALSE;
118
static my_bool innobase_rollback_on_timeout = FALSE;
119
@@ -2367,6 +2369,8 @@
121
srv_force_recovery = (ulint) innobase_force_recovery;
123
+ srv_recovery_stats = (ibool) innobase_recovery_stats;
125
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
126
srv_use_checksums = (ibool) innobase_use_checksums;
128
@@ -10987,6 +10991,16 @@
129
"don't use the datafile for normal mysqld or ibbackup! ####",
132
+static MYSQL_SYSVAR_BOOL(fast_recovery, innobase_fast_recovery,
133
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
134
+ "obsolete option. affects nothing.",
135
+ NULL, NULL, FALSE);
137
+static MYSQL_SYSVAR_BOOL(recovery_stats, innobase_recovery_stats,
138
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
139
+ "Output statistics of recovery process after it.",
140
+ NULL, NULL, FALSE);
142
static MYSQL_SYSVAR_BOOL(overwrite_relay_log_info, innobase_overwrite_relay_log_info,
143
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
144
"During InnoDB crash recovery on slave overwrite relay-log.info "
145
@@ -11412,6 +11426,8 @@
146
MYSQL_SYSVAR(data_home_dir),
147
MYSQL_SYSVAR(doublewrite),
148
MYSQL_SYSVAR(extra_undoslots),
149
+ MYSQL_SYSVAR(fast_recovery),
150
+ MYSQL_SYSVAR(recovery_stats),
151
MYSQL_SYSVAR(fast_shutdown),
152
MYSQL_SYSVAR(file_io_threads),
153
MYSQL_SYSVAR(read_io_threads),
154
--- a/storage/innodb_plugin/handler/innodb_patch_info.h
155
+++ b/storage/innodb_plugin/handler/innodb_patch_info.h
157
{"innodb_expand_import","convert .ibd file automatically when import tablespace","the files are generated by xtrabackup export mode.","http://www.percona.com/docs/wiki/percona-xtradb"},
158
{"innodb_dict_size_limit","Limit dictionary cache size","Variable innodb_dict_size_limit in bytes","http://www.percona.com/docs/wiki/percona-xtradb"},
159
{"innodb_split_buf_pool_mutex","More fix of buffer_pool mutex","Spliting buf_pool_mutex and optimizing based on innodb_opt_lru_count","http://www.percona.com/docs/wiki/percona-xtradb"},
160
+{"innodb_recovery_patches","Bugfixes and adjustments about recovery process","","http://www.percona.com/docs/wiki/percona-xtradb"},
161
{NULL, NULL, NULL, NULL}
163
--- a/storage/innodb_plugin/include/log0recv.h
164
+++ b/storage/innodb_plugin/include/log0recv.h
166
hash_table_t* addr_hash;/*!< hash table of file addresses of pages */
167
ulint n_addrs;/*!< number of not processed hashed file
168
addresses in the hash table */
170
+/* If you modified the following defines at original file,
171
+ You should also modify them. */
172
+/* defined in os0file.c */
173
+#define OS_AIO_MERGE_N_CONSECUTIVE 64
174
+/* defined in log0recv.c */
175
+#define RECV_READ_AHEAD_AREA 32
176
+ time_t stats_recv_start_time;
177
+ ulint stats_recv_turns;
179
+ ulint stats_read_requested_pages;
180
+ ulint stats_read_in_area[RECV_READ_AHEAD_AREA];
182
+ ulint stats_read_io_pages;
183
+ ulint stats_read_io_consecutive[OS_AIO_MERGE_N_CONSECUTIVE];
184
+ ulint stats_write_io_pages;
185
+ ulint stats_write_io_consecutive[OS_AIO_MERGE_N_CONSECUTIVE];
187
+ ulint stats_doublewrite_check_pages;
188
+ ulint stats_doublewrite_overwrite_pages;
190
+ ulint stats_recover_pages_with_read;
191
+ ulint stats_recover_pages_without_read;
193
+ ulint stats_log_recs;
194
+ ulint stats_log_len_sum;
196
+ ulint stats_applied_log_recs;
197
+ ulint stats_applied_log_len_sum;
198
+ ulint stats_pages_already_new;
200
+ ib_uint64_t stats_oldest_modified_lsn;
201
+ ib_uint64_t stats_newest_modified_lsn;
204
/** The recovery system */
205
--- a/storage/innodb_plugin/include/srv0srv.h
206
+++ b/storage/innodb_plugin/include/srv0srv.h
209
extern ibool srv_extra_undoslots;
211
+extern ibool srv_recovery_stats;
213
extern ibool srv_auto_extend_last_data_file;
214
extern ulint srv_last_file_size_max;
215
extern char** srv_log_group_home_dirs;
216
--- a/storage/innodb_plugin/log/log0recv.c
217
+++ b/storage/innodb_plugin/log/log0recv.c
220
recv_sys->heap = NULL;
221
recv_sys->addr_hash = NULL;
223
+ recv_sys->stats_recv_start_time = time(NULL);
224
+ recv_sys->stats_oldest_modified_lsn = IB_ULONGLONG_MAX;
227
/********************************************************//**
229
recv_n_pool_free_frames = 512;
232
+ if (buf_pool_get_curr_size() >= (32 * 1024 * 1024)) {
233
+ /* Buffer pool of size greater than 32 MB. */
234
+ recv_n_pool_free_frames = 1024;
237
recv_sys->buf = ut_malloc(RECV_PARSING_BUF_SIZE);
239
recv_sys->recovered_offset = 0;
240
@@ -1353,6 +1361,11 @@
242
len = rec_end - body;
244
+ if (srv_recovery_stats) {
245
+ recv_sys->stats_log_recs++;
246
+ recv_sys->stats_log_len_sum += len;
249
recv = mem_heap_alloc(recv_sys->heap, sizeof(recv_t));
251
recv->len = rec_end - body;
252
@@ -1464,6 +1477,7 @@
253
ib_uint64_t start_lsn;
255
ib_uint64_t page_lsn;
256
+ ib_uint64_t page_lsn_orig;
257
ib_uint64_t page_newest_lsn;
258
ibool modification_to_page;
259
#ifndef UNIV_HOTBACKUP
260
@@ -1486,6 +1500,8 @@
261
buf_block_get_page_no(block));
263
if ((recv_addr == NULL)
264
+ /* bugfix: http://bugs.mysql.com/bug.php?id=44140 */
265
+ || (recv_addr->state == RECV_BEING_READ && !just_read_in)
266
|| (recv_addr->state == RECV_BEING_PROCESSED)
267
|| (recv_addr->state == RECV_PROCESSED)) {
269
@@ -1501,6 +1517,14 @@
271
recv_addr->state = RECV_BEING_PROCESSED;
273
+ if (srv_recovery_stats) {
274
+ if (just_read_in) {
275
+ recv_sys->stats_recover_pages_with_read++;
277
+ recv_sys->stats_recover_pages_without_read++;
281
mutex_exit(&(recv_sys->mutex));
284
@@ -1530,6 +1554,7 @@
286
/* Read the newest modification lsn from the page */
287
page_lsn = mach_read_ull(page + FIL_PAGE_LSN);
288
+ page_lsn_orig = page_lsn;
290
#ifndef UNIV_HOTBACKUP
291
/* It may be that the page has been modified in the buffer
292
@@ -1549,6 +1574,21 @@
293
modification_to_page = FALSE;
294
start_lsn = end_lsn = 0;
296
+ if (srv_recovery_stats) {
297
+ mutex_enter(&(recv_sys->mutex));
298
+ if (page_lsn_orig && recv_sys->stats_oldest_modified_lsn > page_lsn_orig) {
299
+ recv_sys->stats_oldest_modified_lsn = page_lsn_orig;
301
+ if (page_lsn_orig && recv_sys->stats_newest_modified_lsn < page_lsn_orig) {
302
+ recv_sys->stats_newest_modified_lsn = page_lsn_orig;
304
+ if (UT_LIST_GET_LAST(recv_addr->rec_list)->start_lsn
306
+ recv_sys->stats_pages_already_new++;
308
+ mutex_exit(&(recv_sys->mutex));
311
recv = UT_LIST_GET_FIRST(recv_addr->rec_list);
314
@@ -1603,6 +1643,13 @@
318
+ if (srv_recovery_stats) {
319
+ mutex_enter(&(recv_sys->mutex));
320
+ recv_sys->stats_applied_log_recs++;
321
+ recv_sys->stats_applied_log_len_sum += recv->len;
322
+ mutex_exit(&(recv_sys->mutex));
325
end_lsn = recv->start_lsn + recv->len;
326
mach_write_ull(FIL_PAGE_LSN + page, end_lsn);
327
mach_write_ull(UNIV_PAGE_SIZE
328
@@ -1703,6 +1750,13 @@
332
+ if (srv_recovery_stats && n) {
333
+ mutex_enter(&(recv_sys->mutex));
334
+ recv_sys->stats_read_requested_pages += n;
335
+ recv_sys->stats_read_in_area[n - 1]++;
336
+ mutex_exit(&(recv_sys->mutex));
339
buf_read_recv_pages(FALSE, space, zip_size, page_nos, n);
341
fprintf(stderr, "Recv pages at %lu n %lu\n", page_nos[0], n);
342
@@ -1856,6 +1910,10 @@
345
fprintf(stderr, "InnoDB: Apply batch completed\n");
347
+ if (srv_recovery_stats) {
348
+ recv_sys->stats_recv_turns++;
352
mutex_exit(&(recv_sys->mutex));
353
@@ -3257,6 +3315,83 @@
355
#endif /* UNIV_DEBUG */
357
+ if (recv_needed_recovery && srv_recovery_stats) {
361
+ "InnoDB: Applying log records was done. Its statistics are followings.\n");
364
+ "============================================================\n"
365
+ "-------------------\n"
366
+ "RECOVERY STATISTICS\n"
367
+ "-------------------\n");
369
+ "Recovery time: %g sec. (%lu turns)\n",
370
+ difftime(time(NULL), recv_sys->stats_recv_start_time),
371
+ recv_sys->stats_recv_turns);
375
+ "Data page IO statistics\n"
376
+ " Requested pages: %lu\n"
377
+ " Read pages: %lu\n"
378
+ " Written pages: %lu\n"
379
+ " (Dirty blocks): %lu\n",
380
+ recv_sys->stats_read_requested_pages,
381
+ recv_sys->stats_read_io_pages,
382
+ recv_sys->stats_write_io_pages,
383
+ UT_LIST_GET_LEN(buf_pool->flush_list));
386
+ " Grouping IO [times]:\n"
387
+ "\tnumber of pages,\n"
388
+ "\t\tread request neighbors (in %d pages chunk),\n"
389
+ "\t\t\tcombined read IO,\n"
390
+ "\t\t\t\tcombined write IO\n",
391
+ RECV_READ_AHEAD_AREA);
392
+ for (i = 0; i < ut_max(RECV_READ_AHEAD_AREA,
393
+ OS_AIO_MERGE_N_CONSECUTIVE); i++) {
395
+ "\t%3lu,\t%lu,\t%lu,\t%lu\n", i + 1,
396
+ (i < RECV_READ_AHEAD_AREA) ?
397
+ recv_sys->stats_read_in_area[i] : 0,
398
+ (i < OS_AIO_MERGE_N_CONSECUTIVE) ?
399
+ recv_sys->stats_read_io_consecutive[i] : 0,
400
+ (i < OS_AIO_MERGE_N_CONSECUTIVE) ?
401
+ recv_sys->stats_write_io_consecutive[i] : 0);
406
+ "Recovery process statistics\n"
407
+ " Checked pages by doublewrite buffer: %lu\n"
408
+ " Overwritten pages from doublewrite: %lu\n"
409
+ " Recovered pages by io_thread: %lu\n"
410
+ " Recovered pages by main thread: %lu\n"
411
+ " Parsed log records to apply: %lu\n"
412
+ " Sum of the length: %lu\n"
413
+ " Applied log records: %lu\n"
414
+ " Sum of the length: %lu\n"
415
+ " Pages which are already new enough: %lu (It may not be accurate, if turns > 1)\n"
416
+ " Oldest page's LSN: %llu\n"
417
+ " Newest page's LSN: %llu\n",
418
+ recv_sys->stats_doublewrite_check_pages,
419
+ recv_sys->stats_doublewrite_overwrite_pages,
420
+ recv_sys->stats_recover_pages_with_read,
421
+ recv_sys->stats_recover_pages_without_read,
422
+ recv_sys->stats_log_recs,
423
+ recv_sys->stats_log_len_sum,
424
+ recv_sys->stats_applied_log_recs,
425
+ recv_sys->stats_applied_log_len_sum,
426
+ recv_sys->stats_pages_already_new,
427
+ recv_sys->stats_oldest_modified_lsn,
428
+ recv_sys->stats_newest_modified_lsn);
431
+ "============================================================\n");
434
if (recv_needed_recovery) {
435
trx_sys_print_mysql_master_log_pos();
436
trx_sys_print_mysql_binlog_offset();
437
--- a/storage/innodb_plugin/os/os0file.c
438
+++ b/storage/innodb_plugin/os/os0file.c
440
#include "srv0start.h"
443
+#include "log0recv.h"
444
#ifndef UNIV_HOTBACKUP
445
# include "os0sync.h"
446
# include "os0thread.h"
447
@@ -4235,6 +4236,18 @@
451
+ if (srv_recovery_stats && recv_recovery_is_on() && n_consecutive) {
452
+ mutex_enter(&(recv_sys->mutex));
453
+ if (slot->type == OS_FILE_READ) {
454
+ recv_sys->stats_read_io_pages += n_consecutive;
455
+ recv_sys->stats_read_io_consecutive[n_consecutive - 1]++;
456
+ } else if (slot->type == OS_FILE_WRITE) {
457
+ recv_sys->stats_write_io_pages += n_consecutive;
458
+ recv_sys->stats_write_io_consecutive[n_consecutive - 1]++;
460
+ mutex_exit(&(recv_sys->mutex));
463
os_mutex_enter(array->mutex);
465
/* Mark the i/os done in slots */
466
--- a/storage/innodb_plugin/srv/srv0srv.c
467
+++ b/storage/innodb_plugin/srv/srv0srv.c
470
UNIV_INTERN ibool srv_extra_undoslots = FALSE;
472
+UNIV_INTERN ibool srv_recovery_stats = FALSE;
474
/* if TRUE, then we auto-extend the last data file */
475
UNIV_INTERN ibool srv_auto_extend_last_data_file = FALSE;
476
/* if != 0, this tells the max size auto-extending may increase the
477
--- a/storage/innodb_plugin/trx/trx0sys.c
478
+++ b/storage/innodb_plugin/trx/trx0sys.c
480
#include "srv0start.h"
481
#include "trx0purge.h"
483
+#include "log0recv.h"
485
#include "read0read.h"
488
zip_size ? zip_size : UNIV_PAGE_SIZE,
491
+ if (srv_recovery_stats && recv_recovery_is_on()) {
492
+ mutex_enter(&(recv_sys->mutex));
493
+ recv_sys->stats_doublewrite_check_pages++;
494
+ mutex_exit(&(recv_sys->mutex));
497
/* Check if the page is corrupt */
501
zip_size, page_no, 0,
502
zip_size ? zip_size : UNIV_PAGE_SIZE,
505
+ if (srv_recovery_stats && recv_recovery_is_on()) {
506
+ mutex_enter(&(recv_sys->mutex));
507
+ recv_sys->stats_doublewrite_overwrite_pages++;
508
+ mutex_exit(&(recv_sys->mutex));
512
"InnoDB: Recovered the page from"
513
" the doublewrite buffer.\n");