diff options
-rw-r--r-- | storage/maria/ma_loghandler.c | 21 | ||||
-rw-r--r-- | storage/maria/ma_loghandler_lsn.h | 4 | ||||
-rwxr-xr-x | storage/maria/ma_pagecache.c | 12 | ||||
-rw-r--r-- | storage/maria/ma_recovery.c | 55 | ||||
-rw-r--r-- | storage/maria/ma_recovery.h | 5 | ||||
-rw-r--r-- | storage/maria/maria_read_log.c | 11 |
6 files changed, 89 insertions, 19 deletions
diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index b0654cb70a0..88149fac81b 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -5274,7 +5274,6 @@ my_bool translog_init_scanner(LSN lsn, DBUG_ENTER("translog_init_scanner"); DBUG_PRINT("enter", ("Scanner: 0x%lx LSN: (0x%lu,0x%lx)", (ulong) scanner, LSN_IN_PARTS(lsn))); - DBUG_ASSERT(LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE != 0); DBUG_ASSERT(translog_inited == 1); data.addr= &scanner->page_addr; @@ -6632,6 +6631,26 @@ LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon) DBUG_RETURN(LSN_IMPOSSIBLE); translog_init_scanner(addr, 0, &scanner, 1); + /* + addr can point not to a chunk beginning but page end so next + page beginning. + */ + if (addr % TRANSLOG_PAGE_SIZE == 0) + { + /* + We are emulating the page end which cased such horizon value to + trigger translog_scanner_eop(). + + We can't just increase addr on page header overhead because it + can be file end so we allow translog_get_next_chunk() to skip + to the next page in correct way + */ + scanner.page_addr-= TRANSLOG_PAGE_SIZE; + scanner.page_offset= TRANSLOG_PAGE_SIZE; +#ifndef DBUG_OFF + scanner.page= NULL; /* prevent using incorrect page content */ +#endif + } /* addr can point not to a chunk beginning but to a page end */ if (translog_scanner_eop(&scanner)) { diff --git a/storage/maria/ma_loghandler_lsn.h b/storage/maria/ma_loghandler_lsn.h index af4c6a42da1..34edb1e294f 100644 --- a/storage/maria/ma_loghandler_lsn.h +++ b/storage/maria/ma_loghandler_lsn.h @@ -83,9 +83,9 @@ typedef LSN LSN_WITH_FLAGS; #define FILENO_IMPOSSIBLE 0 /**< log file's numbering starts at 1 */ #define LOG_OFFSET_IMPOSSIBLE 0 /**< log always has a header */ -#define LSN_IMPOSSIBLE 0L +#define LSN_IMPOSSIBLE ((LSN)0) /* following LSN also is impossible */ -#define LSN_ERROR 1 +#define LSN_ERROR ((LSN)1) /** @brief some impossible LSN serve as markers */ #define LSN_REPAIRED_BY_MARIA_CHK ((LSN)2) diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c index 079f3ce3614..259a9886a78 100755 --- a/storage/maria/ma_pagecache.c +++ b/storage/maria/ma_pagecache.c @@ -3941,8 +3941,18 @@ my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache, */ DBUG_ASSERT(block->hash_link != NULL); DBUG_ASSERT(block->status & PCBLOCK_CHANGED); + /** + @todo RECOVERY BUG + REDO phase uses PAGECACHE_PLAIN_PAGE, so the lines below would + confuse the indirect Checkpoint taken at the end of the REDO phase. + So we below collect even dirty pages of temporary tables as a result + :( Soon we should have the MARIA_SHARE accessible from the + pagecache's block and then we can test born_transactional. + */ +#ifdef TRANS_TABLES_ALWAYS_USE_LSN_PAGE if (block->type != PAGECACHE_LSN_PAGE) continue; /* no need to store it */ +#endif stored_list_size++; } } @@ -3967,8 +3977,10 @@ my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache, block; block= block->next_changed) { +#ifdef TRANS_TABLES_ALWAYS_USE_LSN_PAGE if (block->type != PAGECACHE_LSN_PAGE) continue; /* no need to store it in the checkpoint record */ +#endif compile_time_assert(sizeof(block->hash_link->file.file) <= 4); compile_time_assert(sizeof(block->hash_link->pageno) <= 4); int4store(ptr, block->hash_link->file.file); diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index f9bdc59c74a..cf3d2a1db04 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -88,7 +88,7 @@ prototype_undo_exec_hook(UNDO_ROW_INSERT); prototype_undo_exec_hook(UNDO_ROW_DELETE); prototype_undo_exec_hook(UNDO_ROW_UPDATE); -static int run_redo_phase(LSN lsn, my_bool apply); +static int run_redo_phase(LSN lsn, enum maria_apply_log_way apply); static uint end_of_redo_phase(my_bool prepare_for_undo_phase); static int run_undo_phase(uint unfinished); static void display_record_position(const LOG_DESC *log_desc, @@ -136,13 +136,11 @@ void tprint(FILE *trace_file, const char *format, ...) void tprint(FILE *trace_file __attribute__ ((unused)), const char *format __attribute__ ((unused)), ...) { -#ifdef EXTRA_DEBUG va_list args; va_start(args, format); if (trace_file != NULL) vfprintf(trace_file, format, args); va_end(args); -#endif } #define ALERT_USER() DBUG_ASSERT(0) @@ -177,7 +175,8 @@ int maria_recover(void) #endif tprint(trace_file, "TRACE of the last MARIA recovery from mysqld\n"); DBUG_ASSERT(maria_pagecache->inited); - res= maria_apply_log(LSN_IMPOSSIBLE, TRUE, trace_file, TRUE, TRUE, TRUE); + res= maria_apply_log(LSN_IMPOSSIBLE, MARIA_LOG_APPLY, trace_file, + TRUE, TRUE, TRUE); if (!res) tprint(trace_file, "SUCCESS\n"); if (trace_file) @@ -192,7 +191,7 @@ int maria_recover(void) @param from_lsn LSN from which log reading/applying should start; LSN_IMPOSSIBLE means "use last checkpoint" - @param apply if log records should be applied or not + @param apply how log records should be applied or not @param trace_file trace file where progress/debug messages will go @param skip_DDLs_arg Should DDL records (CREATE/RENAME/DROP/REPAIR) be skipped by the REDO phase or not @@ -207,7 +206,8 @@ int maria_recover(void) @retval !=0 Error */ -int maria_apply_log(LSN from_lsn, my_bool apply, FILE *trace_file, +int maria_apply_log(LSN from_lsn, enum maria_apply_log_way apply, + FILE *trace_file, my_bool should_run_undo_phase, my_bool skip_DDLs_arg, my_bool take_checkpoints) { @@ -216,7 +216,7 @@ int maria_apply_log(LSN from_lsn, my_bool apply, FILE *trace_file, ulonglong old_now; DBUG_ENTER("maria_apply_log"); - DBUG_ASSERT(apply || !should_run_undo_phase); + DBUG_ASSERT(apply == MARIA_LOG_APPLY || !should_run_undo_phase); DBUG_ASSERT(!maria_multi_threaded); /* checkpoints can happen only if TRNs have been built */ DBUG_ASSERT(should_run_undo_phase || !take_checkpoints); @@ -370,7 +370,7 @@ end: if (recovery_message_printed != REC_MSG_NONE) { /** @todo RECOVERY BUG all prints to stderr should go to error log */ - fprintf(stderr, "done.\n"); + fprintf(stderr, "%s.\n", error ? " failed" : "done"); } /* we don't cleanly close tables if we hit some error (may corrupt them) */ DBUG_RETURN(error); @@ -981,10 +981,21 @@ static int new_table(uint16 sid, const char *name, 0 (success): leave table open and return 0. */ int error= 1; + MARIA_HA *info; checkpoint_useful= TRUE; + if ((name == NULL) || (name[0] == 0)) + { + /* + we didn't use DBUG_ASSERT() because such record corruption could + silently pass in the "info == NULL" test below. + */ + tprint(tracef, ", record is corrupted"); + info= NULL; + goto end; + } tprint(tracef, "Table '%s', id %u", name, sid); - MARIA_HA *info= maria_open(name, O_RDWR, HA_OPEN_FOR_REPAIR); + info= maria_open(name, O_RDWR, HA_OPEN_FOR_REPAIR); if (info == NULL) { tprint(tracef, ", is absent (must have been dropped later?)" @@ -1563,7 +1574,7 @@ prototype_undo_exec_hook(UNDO_ROW_UPDATE) } -static int run_redo_phase(LSN lsn, my_bool apply) +static int run_redo_phase(LSN lsn, enum maria_apply_log_way apply) { TRANSLOG_HEADER_BUFFER rec; struct st_translog_scanner_data scanner; @@ -1676,7 +1687,21 @@ static int run_redo_phase(LSN lsn, my_bool apply) { const LOG_DESC *log_desc2= &log_record_type_descriptor[rec2.type]; display_record_position(log_desc2, &rec2, 0); - if (apply && display_and_apply_record(log_desc2, &rec2)) + if (apply == MARIA_LOG_CHECK) + { + enlarge_buffer(&rec2); + translog_size_t read_len= + translog_read_record(rec2.lsn, 0, rec2.record_length, + log_record_buffer.str, NULL); + if (read_len != rec2.record_length) + { + tprint(tracef, "Cannot read record's body: read %u of" + " %u bytes\n", read_len, rec2.record_length); + goto err; + } + } + if (apply == MARIA_LOG_APPLY && + display_and_apply_record(log_desc2, &rec2)) { translog_destroy_scanner(&scanner2); goto err; @@ -1698,7 +1723,8 @@ static int run_redo_phase(LSN lsn, my_bool apply) translog_destroy_scanner(&scanner2); } } - if (apply && display_and_apply_record(log_desc, &rec)) + if (apply == MARIA_LOG_APPLY && + display_and_apply_record(log_desc, &rec)) goto err; } else /* record does not end group */ @@ -1904,7 +1930,10 @@ static void prepare_table_for_close(MARIA_HA *info, TRANSLOG_ADDRESS horizon) */ if (cmp_translog_addr(share->state.is_of_horizon, horizon) < 0 && cmp_translog_addr(share->lsn_of_file_id, horizon) < 0) + { share->state.is_of_horizon= horizon; + _ma_state_info_write_sub(share->kfile.file, &share->state, 1); + } _ma_reenable_logging_for_table(share); } @@ -2103,8 +2132,8 @@ static LSN parse_checkpoint_record(LSN lsn) LSN first_log_write_lsn= lsn_korr(ptr); ptr+= LSN_STORE_SIZE; uint name_len= strlen(ptr) + 1; + strmake(name, ptr, sizeof(name)-1); ptr+= name_len; - strnmov(name, ptr, sizeof(name)); if (new_table(sid, name, kfile, dfile, first_log_write_lsn)) return LSN_ERROR; } diff --git a/storage/maria/ma_recovery.h b/storage/maria/ma_recovery.h index da4e8895e2f..ea39fa3e98c 100644 --- a/storage/maria/ma_recovery.h +++ b/storage/maria/ma_recovery.h @@ -24,8 +24,11 @@ /* Performs recovery of the engine at start */ C_MODE_START +enum maria_apply_log_way +{ MARIA_LOG_APPLY, MARIA_LOG_DISPLAY_HEADER, MARIA_LOG_CHECK }; int maria_recover(void); -int maria_apply_log(LSN lsn, my_bool apply, FILE *trace_file, +int maria_apply_log(LSN lsn, enum maria_apply_log_way apply, + FILE *trace_file, my_bool execute_undo_phase, my_bool skip_DDLs, my_bool take_checkpoints); C_MODE_END diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c index 6a565e8f20a..b8449c4d769 100644 --- a/storage/maria/maria_read_log.c +++ b/storage/maria/maria_read_log.c @@ -29,7 +29,8 @@ const char *default_dbug_option= "d:t:i:O,\\maria_read_log.trace"; const char *default_dbug_option= "d:t:i:o,/tmp/maria_read_log.trace"; #endif #endif /* DBUG_OFF */ -static my_bool opt_only_display, opt_apply, opt_apply_undo, opt_silent; +static my_bool opt_only_display, opt_apply, opt_apply_undo, opt_silent, + opt_check; static ulong opt_page_buffer_size; static const char *my_progname_short; @@ -102,7 +103,9 @@ int main(int argc, char **argv) LSN_IN_PARTS(lsn)); fprintf(stdout, "TRACE of the last maria_read_log\n"); - if (maria_apply_log(lsn, opt_apply, opt_silent ? NULL : stdout, + if (maria_apply_log(lsn, opt_apply ? MARIA_LOG_APPLY : + (opt_check ? MARIA_LOG_CHECK : + MARIA_LOG_DISPLAY_HEADER), opt_silent ? NULL : stdout, opt_apply_undo, FALSE, FALSE)) goto err; fprintf(stdout, "%s: SUCCESS\n", my_progname_short); @@ -130,6 +133,10 @@ static struct my_option my_long_options[] = "Apply log to tables. Will display a lot of information if not run with --silent", (uchar **) &opt_apply, (uchar **) &opt_apply, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"check", 'c', + "if --only-display, check if record is fully readable (for debugging)", + (uchar **) &opt_check, (uchar **) &opt_check, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DBUG_OFF {"debug", '#', "Output debug log. Often the argument is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, |