📄 log0recv.c
字号:
/* The address hash table is externally chained */ recv_addr = hash_get_nth_cell(recv_sys->addr_hash, i)->node; while (recv_addr != NULL) { if (!fil_tablespace_exists_in_mem(recv_addr->space)) {/* fprintf(stderr,"InnoDB: Warning: cannot apply log record to tablespace %lu page %lu,\n""InnoDB: because tablespace with that id does not exist.\n", recv_addr->space, recv_addr->page_no);*/ recv_addr->state = RECV_PROCESSED; ut_a(recv_sys->n_addrs); recv_sys->n_addrs--; goto skip_this_recv_addr; } /* We simulate a page read made by the buffer pool, to make sure the recovery apparatus works ok, for example, the buf_frame_align() function. We must init the block corresponding to buf_pool->frame_zero (== page). */ buf_page_init_for_backup_restore(recv_addr->space, recv_addr->page_no, buf_block_align(page)); /* Extend the tablespace's last file if the page_no does not fall inside its bounds; we assume the last file is auto-extending, and ibbackup copied the file when it still was smaller */ success = fil_extend_space_to_desired_size( &actual_size, recv_addr->space, recv_addr->page_no + 1); if (!success) { fprintf(stderr,"InnoDB: Fatal error: cannot extend tablespace %lu to hold %lu pages\n", recv_addr->space, recv_addr->page_no); exit(1); } /* Read the page from the tablespace file using the fil0fil.c routines */ error = fil_io(OS_FILE_READ, TRUE, recv_addr->space, recv_addr->page_no, 0, UNIV_PAGE_SIZE, page, NULL); if (error != DB_SUCCESS) { fprintf(stderr,"InnoDB: Fatal error: cannot read from tablespace %lu page number %lu\n", (ulong) recv_addr->space, (ulong) recv_addr->page_no); exit(1); } /* Apply the log records to this page */ recv_recover_page(TRUE, FALSE, page, recv_addr->space, recv_addr->page_no); /* Write the page back to the tablespace file using the fil0fil.c routines */ buf_flush_init_for_writing(page, mach_read_from_8(page + FIL_PAGE_LSN), recv_addr->space, recv_addr->page_no); error = fil_io(OS_FILE_WRITE, TRUE, recv_addr->space, recv_addr->page_no, 0, UNIV_PAGE_SIZE, page, NULL);skip_this_recv_addr: recv_addr = HASH_GET_NEXT(addr_hash, recv_addr); } if ((100 * i) / n_hash_cells != (100 * (i + 1)) / n_hash_cells) { fprintf(stderr, "%lu ", (ulong) ((100 * i) / n_hash_cells)); fflush(stderr); } } recv_sys_empty_hash();}#ifdef notdefined/***********************************************************************In the debug version, updates the replica of a file page, based on a logrecord. */staticvoidrecv_update_replicate(/*==================*/ byte type, /* in: log record type */ ulint space, /* in: space id */ ulint page_no,/* in: page number */ byte* body, /* in: log record body */ byte* end_ptr)/* in: log record end */{ page_t* replica; mtr_t mtr; byte* ptr; mtr_start(&mtr); mtr_set_log_mode(&mtr, MTR_LOG_NONE); replica = buf_page_get(space + RECV_REPLICA_SPACE_ADD, page_no, RW_X_LATCH, &mtr);#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(replica, SYNC_NO_ORDER_CHECK);#endif /* UNIV_SYNC_DEBUG */ ptr = recv_parse_or_apply_log_rec_body(type, body, end_ptr, replica, &mtr); ut_a(ptr == end_ptr); /* Notify the buffer manager that the page has been updated */ buf_flush_recv_note_modification(buf_block_align(replica), log_sys->old_lsn, log_sys->old_lsn); /* Make sure that committing mtr does not call log routines, as we currently own the log mutex */ mtr.modifications = FALSE; mtr_commit(&mtr);}/***********************************************************************Checks that two strings are identical. */staticvoidrecv_check_identical(/*=================*/ byte* str1, /* in: first string */ byte* str2, /* in: second string */ ulint len) /* in: length of strings */{ ulint i; for (i = 0; i < len; i++) { if (str1[i] != str2[i]) { fprintf(stderr, "Strings do not match at offset %lu\n", i); ut_print_buf(str1 + i, 16); fprintf(stderr, "\n"); ut_print_buf(str2 + i, 16); ut_error; } }} /***********************************************************************In the debug version, checks that the replica of a file page is identicalto the original page. */staticvoidrecv_compare_replicate(/*===================*/ ulint space, /* in: space id */ ulint page_no)/* in: page number */{ page_t* replica; page_t* page; mtr_t mtr; mtr_start(&mtr); mutex_enter(&(buf_pool->mutex)); page = buf_page_hash_get(space, page_no)->frame; mutex_exit(&(buf_pool->mutex)); replica = buf_page_get(space + RECV_REPLICA_SPACE_ADD, page_no, RW_X_LATCH, &mtr);#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(replica, SYNC_NO_ORDER_CHECK);#endif /* UNIV_SYNC_DEBUG */ recv_check_identical(page + FIL_PAGE_DATA, replica + FIL_PAGE_DATA, PAGE_HEADER + PAGE_MAX_TRX_ID - FIL_PAGE_DATA); recv_check_identical(page + PAGE_HEADER + PAGE_MAX_TRX_ID + 8, replica + PAGE_HEADER + PAGE_MAX_TRX_ID + 8, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END - PAGE_HEADER - PAGE_MAX_TRX_ID - 8); mtr_commit(&mtr);}/***********************************************************************Checks that a replica of a space is identical to the original space. */voidrecv_compare_spaces(/*================*/ ulint space1, /* in: space id */ ulint space2, /* in: space id */ ulint n_pages)/* in: number of pages */{ page_t* replica; page_t* page; mtr_t mtr; page_t* frame; ulint page_no; replica = buf_frame_alloc(); page = buf_frame_alloc(); for (page_no = 0; page_no < n_pages; page_no++) { mtr_start(&mtr); frame = buf_page_get_gen(space1, page_no, RW_S_LATCH, NULL, BUF_GET_IF_IN_POOL, __FILE__, __LINE__, &mtr); if (frame) {#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(frame, SYNC_NO_ORDER_CHECK);#endif /* UNIV_SYNC_DEBUG */ ut_memcpy(page, frame, UNIV_PAGE_SIZE); } else { /* Read it from file */ fil_io(OS_FILE_READ, TRUE, space1, page_no, 0, UNIV_PAGE_SIZE, page, NULL); } frame = buf_page_get_gen(space2, page_no, RW_S_LATCH, NULL, BUF_GET_IF_IN_POOL, __FILE__, __LINE__, &mtr); if (frame) {#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(frame, SYNC_NO_ORDER_CHECK);#endif /* UNIV_SYNC_DEBUG */ ut_memcpy(replica, frame, UNIV_PAGE_SIZE); } else { /* Read it from file */ fil_io(OS_FILE_READ, TRUE, space2, page_no, 0, UNIV_PAGE_SIZE, replica, NULL); } recv_check_identical(page + FIL_PAGE_DATA, replica + FIL_PAGE_DATA, PAGE_HEADER + PAGE_MAX_TRX_ID - FIL_PAGE_DATA); recv_check_identical(page + PAGE_HEADER + PAGE_MAX_TRX_ID + 8, replica + PAGE_HEADER + PAGE_MAX_TRX_ID + 8, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END - PAGE_HEADER - PAGE_MAX_TRX_ID - 8); mtr_commit(&mtr); } buf_frame_free(replica); buf_frame_free(page);}/***********************************************************************Checks that a replica of a space is identical to the original space. Disablesibuf operations and flushes and invalidates the buffer pool pages after thetest. This function can be used to check the recovery before dict or trxsystems are initialized. */voidrecv_compare_spaces_low(/*====================*/ ulint space1, /* in: space id */ ulint space2, /* in: space id */ ulint n_pages)/* in: number of pages */{ mutex_enter(&(log_sys->mutex)); recv_apply_hashed_log_recs(FALSE); mutex_exit(&(log_sys->mutex)); recv_compare_spaces(space1, space2, n_pages);}#endif /* UNIV_LOG_REPLICATE *//***********************************************************************Tries to parse a single log record and returns its length. */staticulintrecv_parse_log_rec(/*===============*/ /* out: length of the record, or 0 if the record was not complete */ byte* ptr, /* in: pointer to a buffer */ byte* end_ptr,/* in: pointer to the buffer end */ byte* type, /* out: type */ ulint* space, /* out: space id */ ulint* page_no,/* out: page number */ byte** body) /* out: log record body start */{ byte* new_ptr; *body = NULL; if (ptr == end_ptr) { return(0); } if (*ptr == MLOG_MULTI_REC_END) { *type = *ptr; return(1); } if (*ptr == MLOG_DUMMY_RECORD) { *type = *ptr; *space = ULINT_UNDEFINED - 1; /* For debugging */ return(1); } new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space, page_no); *body = new_ptr; if (UNIV_UNLIKELY(!new_ptr)) { return(0); } /* Check that page_no is sensible */ if (UNIV_UNLIKELY(*page_no > 0x8FFFFFFFUL)) { recv_sys->found_corrupt_log = TRUE; return(0); } new_ptr = recv_parse_or_apply_log_rec_body(*type, new_ptr, end_ptr, NULL, NULL); if (UNIV_UNLIKELY(new_ptr == NULL)) { return(0); } if (*page_no > recv_max_parsed_page_no) { recv_max_parsed_page_no = *page_no; } return(new_ptr - ptr);}/***********************************************************Calculates the new value for lsn when more data is added to the log. */staticdulintrecv_calc_lsn_on_data_add(/*======================*/ dulint lsn, /* in: old lsn */ ulint len) /* in: this many bytes of data is added, log block headers not included */{ ulint frag_len; ulint lsn_len; frag_len = (ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) - LOG_BLOCK_HDR_SIZE; ut_ad(frag_len < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE - LOG_BLOCK_TRL_SIZE); lsn_len = len + ((len + frag_len) / (OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE - LOG_BLOCK_TRL_SIZE)) * (LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE); return(ut_dulint_add(lsn, lsn_len));}/***********************************************************Checks that the parser recognizes incomplete initial segments of a logrecord as incomplete. */voidrecv_check_incomplete_log_recs(/*===========================*/ byte* ptr, /* in: pointer to a complete log record */ ulint len) /* in: length of the log record */{ ulint i; byte type; ulint space; ulint page_no; byte* body; for (i = 0; i < len; i++) { ut_a(0 == recv_parse_log_rec(ptr, ptr + i, &type, &space, &page_no, &body)); }} /***********************************************************Prints diagnostic info of corrupt log. */staticvoidrecv_report_corrupt_log(/*====================*/ byte* ptr, /* in: pointer to corrupt log record */ byte type, /* in: type of the record */ ulint space, /* in: space id, this may also be garbage */ ulint page_no)/* in: page number, this may also be garbage */{ fprintf(stderr,"InnoDB: ############### CORRUPT LOG RECORD FOUND\n""InnoDB: Log record type %lu, space id %lu, page number %lu\n""InnoDB: Log parsing proceeded successfully up to %lu %lu\n""InnoDB: Previous log record type %lu, is multi %lu\n""InnoDB: Recv offset %lu, prev %lu\n", (ulong) type, (ulong) space, (ulong) page_no, (ulong) ut_dulint_get_high(recv_sys->recovered_lsn), (ulong) ut_dulint_get_low(recv_sys->recovered_lsn), (ulong) recv_previous_parsed_rec_type, (ulong) recv_previous_parsed_rec_is_multi, (ulong) (ptr - recv_sys->buf), (ulong) recv_previous_parsed_rec_offset); if ((ulint)(ptr - recv_sys->buf + 100) > recv_previous_parsed_rec_offset && (ulint)(ptr - recv_sys->buf + 100 - recv_previous_parsed_rec_offset) < 200000) { fputs("InnoDB: Hex dump of corrupt log starting 100 bytes before the start\n""InnoDB: of the previous log rec,\n""InnoDB: and ending 100 bytes after the start of the corrupt rec:\n", stderr); ut_print_buf(stderr, recv_sys->buf + recv_previous_parsed_rec_offset - 100, ptr - recv_sys->buf + 200 - recv_previous_parsed_rec_offset); putc('\n', stderr); } fputs( "InnoDB: WARNING: the log file may have been corrupt and it\n" "InnoDB: is possible that the log scan did not proceed\n" "InnoDB: far enough in recovery! Please run CHECK TABLE\n" "InnoDB: on your InnoDB tables to check that they are ok!\n" "InnoDB: If mysqld crashes after this recovery, look at\n" "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" "InnoDB: about forcing recovery.\n", stderr); fflush(stderr);}/***********************************************************Parses log records from a buffer and stores them to a hash table to waitmerging to file pages. */staticiboolrecv_parse_log_recs(/*================*/ /* out: currently always returns FALSE */ ibool store_to_hash) /* in: TRUE if the records should be stored to the hash table; this is set to FALSE if just debug checking is needed */{ byte* ptr; byte* end_ptr; ulint single_rec; ulint len; ulint total_len; dulint new_recovered_lsn; dulint old_lsn; byte type; ulint space; ulint page_no; byte* body; ulint n_recs; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ ut_ad(!ut_dulint_is_zero(recv_sys->parse_start_lsn));loop: ptr = recv_sys->buf + recv_sys->recovered_offset; end_ptr = recv_sys->buf + recv_sys->len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -