📄 log0recv.c
字号:
/******************************************************Recovery(c) 1997 Innobase OyCreated 9/20/1997 Heikki Tuuri*******************************************************/#include "log0recv.h"#ifdef UNIV_NONINL#include "log0recv.ic"#endif#include "mem0mem.h"#include "buf0buf.h"#include "buf0flu.h"#include "buf0rea.h"#include "srv0srv.h"#include "srv0start.h"#include "mtr0mtr.h"#include "mtr0log.h"#include "page0page.h"#include "page0cur.h"#include "btr0btr.h"#include "btr0cur.h"#include "ibuf0ibuf.h"#include "trx0undo.h"#include "trx0rec.h"#include "trx0roll.h"#include "btr0cur.h"#include "btr0cur.h"#include "btr0cur.h"#include "dict0boot.h"#include "fil0fil.h"#ifdef UNIV_HOTBACKUP/* This is set to FALSE if the backup was originally taken with theibbackup --include regexp option: then we do not want to create tables indirectories which were not included */ibool recv_replay_file_ops = TRUE;#endif /* UNIV_HOTBACKUP *//* Log records are stored in the hash table in chunks at most of this size;this must be less than UNIV_PAGE_SIZE as it is stored in the buffer pool */#define RECV_DATA_BLOCK_SIZE (MEM_MAX_ALLOC_IN_BUF - sizeof(recv_data_t))/* Read-ahead area in applying log records to file pages */#define RECV_READ_AHEAD_AREA 32recv_sys_t* recv_sys = NULL;ibool recv_recovery_on = FALSE;ibool recv_recovery_from_backup_on = FALSE;ibool recv_needed_recovery = FALSE;ibool recv_lsn_checks_on = FALSE;/* If the following is TRUE, the buffer pool file pages must be invalidatedafter recovery and no ibuf operations are allowed; this becomes TRUE ifthe log record hash table becomes too full, and log records must be mergedto file pages already before the recovery is finished: in this case noibuf operations are allowed, as they could modify the pages read in thebuffer pool before the pages have been recovered to the up-to-date state *//* Recovery is running and no operations on the log files are allowedyet: the variable name is misleading */ibool recv_no_ibuf_operations = FALSE;/* The following counter is used to decide when to print info onlog scan */ulint recv_scan_print_counter = 0;ibool recv_is_from_backup = FALSE;#ifdef UNIV_HOTBACKUPibool recv_is_making_a_backup = FALSE;#else# define recv_is_making_a_backup FALSE#endif /* UNIV_HOTBACKUP */ulint recv_previous_parsed_rec_type = 999999;ulint recv_previous_parsed_rec_offset = 0;ulint recv_previous_parsed_rec_is_multi = 0;ulint recv_max_parsed_page_no = 0;/* This many frames must be left free in the buffer pool when we scanthe log and store the scanned log records in the buffer pool: we willuse these free frames to read in pages when we start applying thelog records to the database. */ulint recv_n_pool_free_frames = 256;/* The maximum lsn we see for a page during the recovery process. If thisis bigger than the lsn we are able to scan up to, that is an indication thatthe recovery failed and the database may be corrupt. */dulint recv_max_page_lsn;/************************************************************Creates the recovery system. */voidrecv_sys_create(void)/*=================*/{ if (recv_sys != NULL) { return; } recv_sys = mem_alloc(sizeof(recv_sys_t)); mutex_create(&(recv_sys->mutex)); mutex_set_level(&(recv_sys->mutex), SYNC_RECV); recv_sys->heap = NULL; recv_sys->addr_hash = NULL;}/************************************************************Inits the recovery system for a recovery operation. */voidrecv_sys_init(/*==========*/ ibool recover_from_backup, /* in: TRUE if this is called to recover from a hot backup */ ulint available_memory) /* in: available memory in bytes */{ if (recv_sys->heap != NULL) { return; } mutex_enter(&(recv_sys->mutex)); if (!recover_from_backup) { recv_sys->heap = mem_heap_create_in_buffer(256); } else { recv_sys->heap = mem_heap_create(256); recv_is_from_backup = TRUE; } recv_sys->buf = ut_malloc(RECV_PARSING_BUF_SIZE); recv_sys->len = 0; recv_sys->recovered_offset = 0; recv_sys->addr_hash = hash_create(available_memory / 64); recv_sys->n_addrs = 0; recv_sys->apply_log_recs = FALSE; recv_sys->apply_batch_on = FALSE; recv_sys->last_block_buf_start = mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE); recv_sys->last_block = ut_align(recv_sys->last_block_buf_start, OS_FILE_LOG_BLOCK_SIZE); recv_sys->found_corrupt_log = FALSE; recv_max_page_lsn = ut_dulint_zero; mutex_exit(&(recv_sys->mutex));}/************************************************************Empties the hash table when it has been fully processed. */staticvoidrecv_sys_empty_hash(void)/*=====================*/{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(recv_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ if (recv_sys->n_addrs != 0) { fprintf(stderr,"InnoDB: Error: %lu pages with log records were left unprocessed!\n""InnoDB: Maximum page number with log records on it %lu\n", (ulong) recv_sys->n_addrs, (ulong) recv_max_parsed_page_no); ut_error; } hash_table_free(recv_sys->addr_hash); mem_heap_empty(recv_sys->heap); recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 256);}/************************************************************Frees the recovery system. */staticvoidrecv_sys_free(void)/*===============*/{ mutex_enter(&(recv_sys->mutex)); hash_table_free(recv_sys->addr_hash); mem_heap_free(recv_sys->heap); ut_free(recv_sys->buf); mem_free(recv_sys->last_block_buf_start); recv_sys->addr_hash = NULL; recv_sys->heap = NULL; mutex_exit(&(recv_sys->mutex));}/************************************************************Truncates possible corrupted or extra records from a log group. */staticvoidrecv_truncate_group(/*================*/ log_group_t* group, /* in: log group */ dulint recovered_lsn, /* in: recovery succeeded up to this lsn */ dulint limit_lsn, /* in: this was the limit for recovery */ dulint checkpoint_lsn, /* in: recovery was started from this checkpoint */ dulint archived_lsn) /* in: the log has been archived up to this lsn */{ dulint start_lsn; dulint end_lsn; dulint finish_lsn1; dulint finish_lsn2; dulint finish_lsn; ulint len; ulint i; if (ut_dulint_cmp(archived_lsn, ut_dulint_max) == 0) { /* Checkpoint was taken in the NOARCHIVELOG mode */ archived_lsn = checkpoint_lsn; } finish_lsn1 = ut_dulint_add(ut_dulint_align_down(archived_lsn, OS_FILE_LOG_BLOCK_SIZE), log_group_get_capacity(group)); finish_lsn2 = ut_dulint_add(ut_dulint_align_up(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE), recv_sys->last_log_buf_size); if (ut_dulint_cmp(limit_lsn, ut_dulint_max) != 0) { /* We do not know how far we should erase log records: erase as much as possible */ finish_lsn = finish_lsn1; } else { /* It is enough to erase the length of the log buffer */ finish_lsn = ut_dulint_get_min(finish_lsn1, finish_lsn2); } ut_a(RECV_SCAN_SIZE <= log_sys->buf_size); /* Write the log buffer full of zeros */ for (i = 0; i < RECV_SCAN_SIZE; i++) { *(log_sys->buf + i) = '\0'; } start_lsn = ut_dulint_align_down(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE); if (ut_dulint_cmp(start_lsn, recovered_lsn) != 0) { /* Copy the last incomplete log block to the log buffer and edit its data length: */ ut_memcpy(log_sys->buf, recv_sys->last_block, OS_FILE_LOG_BLOCK_SIZE); log_block_set_data_len(log_sys->buf, ut_dulint_minus(recovered_lsn, start_lsn)); } if (ut_dulint_cmp(start_lsn, finish_lsn) >= 0) { return; } for (;;) { end_lsn = ut_dulint_add(start_lsn, RECV_SCAN_SIZE); if (ut_dulint_cmp(end_lsn, finish_lsn) > 0) { end_lsn = finish_lsn; } len = ut_dulint_minus(end_lsn, start_lsn); log_group_write_buf(group, log_sys->buf, len, start_lsn, 0); if (ut_dulint_cmp(end_lsn, finish_lsn) >= 0) { return; } /* Write the log buffer full of zeros */ for (i = 0; i < RECV_SCAN_SIZE; i++) { *(log_sys->buf + i) = '\0'; } start_lsn = end_lsn; }}/************************************************************Copies the log segment between group->recovered_lsn and recovered_lsn from themost up-to-date log group to group, so that it contains the latest log data. */staticvoidrecv_copy_group(/*============*/ log_group_t* up_to_date_group, /* in: the most up-to-date log group */ log_group_t* group, /* in: copy to this log group */ dulint recovered_lsn) /* in: recovery succeeded up to this lsn */{ dulint start_lsn; dulint end_lsn; ulint len; if (ut_dulint_cmp(group->scanned_lsn, recovered_lsn) >= 0) { return; } ut_a(RECV_SCAN_SIZE <= log_sys->buf_size); start_lsn = ut_dulint_align_down(group->scanned_lsn, OS_FILE_LOG_BLOCK_SIZE); for (;;) { end_lsn = ut_dulint_add(start_lsn, RECV_SCAN_SIZE); if (ut_dulint_cmp(end_lsn, recovered_lsn) > 0) { end_lsn = ut_dulint_align_up(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE); } log_group_read_log_seg(LOG_RECOVER, log_sys->buf, up_to_date_group, start_lsn, end_lsn); len = ut_dulint_minus(end_lsn, start_lsn); log_group_write_buf(group, log_sys->buf, len, start_lsn, 0); if (ut_dulint_cmp(end_lsn, recovered_lsn) >= 0) { return; } start_lsn = end_lsn; }}/************************************************************Copies a log segment from the most up-to-date log group to the other loggroups, so that they all contain the latest log data. Also writes the infoabout the latest checkpoint to the groups, and inits the fields in the groupmemory structs to up-to-date values. */staticvoidrecv_synchronize_groups(/*====================*/ log_group_t* up_to_date_group) /* in: the most up-to-date log group */{ log_group_t* group; dulint start_lsn; dulint end_lsn; dulint recovered_lsn; dulint limit_lsn; recovered_lsn = recv_sys->recovered_lsn; limit_lsn = recv_sys->limit_lsn; /* Read the last recovered log block to the recovery system buffer: the block is always incomplete */ start_lsn = ut_dulint_align_down(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE); end_lsn = ut_dulint_align_up(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE); ut_a(ut_dulint_cmp(start_lsn, end_lsn) != 0); log_group_read_log_seg(LOG_RECOVER, recv_sys->last_block, up_to_date_group, start_lsn, end_lsn); group = UT_LIST_GET_FIRST(log_sys->log_groups); while (group) { if (group != up_to_date_group) { /* Copy log data if needed */ recv_copy_group(group, up_to_date_group, recovered_lsn); } /* Update the fields in the group struct to correspond to recovered_lsn */ log_group_set_fields(group, recovered_lsn); group = UT_LIST_GET_NEXT(log_groups, group); } /* Copy the checkpoint info to the groups; remember that we have incremented checkpoint_no by one, and the info will not be written over the max checkpoint info, thus making the preservation of max checkpoint info on disk certain */ log_groups_write_checkpoint_info(); mutex_exit(&(log_sys->mutex)); /* Wait for the checkpoint write to complete */ rw_lock_s_lock(&(log_sys->checkpoint_lock)); rw_lock_s_unlock(&(log_sys->checkpoint_lock)); mutex_enter(&(log_sys->mutex));}/***************************************************************************Checks the consistency of the checkpoint info */staticiboolrecv_check_cp_is_consistent(/*========================*/ /* out: TRUE if ok */ byte* buf) /* in: buffer containing checkpoint info */{ ulint fold; fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1); if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(buf + LOG_CHECKPOINT_CHECKSUM_1)) { return(FALSE); } fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN, LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN); if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(buf + LOG_CHECKPOINT_CHECKSUM_2)) { return(FALSE); } return(TRUE);}/************************************************************Looks for the maximum consistent checkpoint from the log groups. */staticulintrecv_find_max_checkpoint(/*=====================*/ /* out: error code or DB_SUCCESS */ log_group_t** max_group, /* out: max group */ ulint* max_field) /* out: LOG_CHECKPOINT_1 or LOG_CHECKPOINT_2 */{ log_group_t* group; dulint max_no; dulint checkpoint_no; ulint field; byte* buf; group = UT_LIST_GET_FIRST(log_sys->log_groups); max_no = ut_dulint_zero; *max_group = NULL; *max_field = 0; buf = log_sys->checkpoint_buf; while (group) { group->state = LOG_GROUP_CORRUPTED; for (field = LOG_CHECKPOINT_1; field <= LOG_CHECKPOINT_2; field += LOG_CHECKPOINT_2 - LOG_CHECKPOINT_1) { log_group_read_checkpoint_info(group, field); if (!recv_check_cp_is_consistent(buf)) {#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "InnoDB: Checkpoint in group %lu at %lu invalid, %lu\n", (ulong) group->id, (ulong) field, (ulong) mach_read_from_4(buf
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -