📄 log0recv.c
字号:
if (ptr == end_ptr) { return(FALSE); } single_rec = (ulint)*ptr & MLOG_SINGLE_REC_FLAG; if (single_rec || *ptr == MLOG_DUMMY_RECORD) { /* The mtr only modified a single page, or this is a file op */ old_lsn = recv_sys->recovered_lsn; /* Try to parse a log record, fetching its type, space id, page no, and a pointer to the body of the log record */ len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); if (len == 0 || recv_sys->found_corrupt_log) { if (recv_sys->found_corrupt_log) { recv_report_corrupt_log(ptr, type, space, page_no); } return(FALSE); } new_recovered_lsn = recv_calc_lsn_on_data_add(old_lsn, len); if (ut_dulint_cmp(new_recovered_lsn, recv_sys->scanned_lsn) > 0) { /* The log record filled a log block, and we require that also the next log block should have been scanned in */ return(FALSE); } recv_previous_parsed_rec_type = (ulint)type; recv_previous_parsed_rec_offset = recv_sys->recovered_offset; recv_previous_parsed_rec_is_multi = 0; recv_sys->recovered_offset += len; recv_sys->recovered_lsn = new_recovered_lsn;#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "InnoDB: Parsed a single log rec type %lu len %lu space %lu page no %lu\n", (ulong) type, (ulong) len, (ulong) space, (ulong) page_no); }#endif /* UNIV_DEBUG */ if (type == MLOG_DUMMY_RECORD) { /* Do nothing */ } else if (store_to_hash && (type == MLOG_FILE_CREATE || type == MLOG_FILE_RENAME || type == MLOG_FILE_DELETE)) {#ifdef UNIV_HOTBACKUP if (recv_replay_file_ops) { /* In ibbackup --apply-log, replay an .ibd file operation, if possible; note that fil_path_to_mysql_datadir is set in ibbackup to point to the datadir we should use there */ if (NULL == fil_op_log_parse_or_replay(body, end_ptr, type, TRUE, space)) { fprintf(stderr,"InnoDB: Error: file op log record of type %lu space %lu not complete in\n""InnoDB: the replay phase. Path %s\n", (ulint)type, space, (char*)(body + 2)); ut_a(0); } }#endif /* In normal mysqld crash recovery we do not try to replay file operations */ } else if (store_to_hash) { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, recv_sys->recovered_lsn); } else { /* In debug checking, update a replicate page according to the log record, and check that it becomes identical with the original page */#ifdef UNIV_LOG_DEBUG recv_check_incomplete_log_recs(ptr, len);#endif/* UNIV_LOG_DEBUG */#ifdef UNIV_LOG_REPLICATE recv_update_replicate(type, space, page_no, body, ptr + len); recv_compare_replicate(space, page_no);#endif /* UNIV_LOG_REPLICATE */ } } else { /* Check that all the records associated with the single mtr are included within the buffer */ total_len = 0; n_recs = 0; for (;;) { len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); if (len == 0 || recv_sys->found_corrupt_log) { if (recv_sys->found_corrupt_log) { recv_report_corrupt_log(ptr, type, space, page_no); } return(FALSE); } recv_previous_parsed_rec_type = (ulint)type; recv_previous_parsed_rec_offset = recv_sys->recovered_offset + total_len; recv_previous_parsed_rec_is_multi = 1; if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { /* In debug checking, update a replicate page according to the log record */#ifdef UNIV_LOG_DEBUG recv_check_incomplete_log_recs(ptr, len);#endif /* UNIV_LOG_DEBUG */#ifdef UNIV_LOG_REPLICATE recv_update_replicate(type, space, page_no, body, ptr + len);#endif /* UNIV_LOG_REPLICATE */ }#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "InnoDB: Parsed a multi log rec type %lu len %lu space %lu page no %lu\n", (ulong) type, (ulong) len, (ulong) space, (ulong) page_no); }#endif /* UNIV_DEBUG */ total_len += len; n_recs++; ptr += len; if (type == MLOG_MULTI_REC_END) { /* Found the end mark for the records */ break; } } new_recovered_lsn = recv_calc_lsn_on_data_add( recv_sys->recovered_lsn, total_len); if (ut_dulint_cmp(new_recovered_lsn, recv_sys->scanned_lsn) > 0) { /* The log record filled a log block, and we require that also the next log block should have been scanned in */ return(FALSE); } /* Add all the records to the hash table */ ptr = recv_sys->buf + recv_sys->recovered_offset; for (;;) { old_lsn = recv_sys->recovered_lsn; len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); if (recv_sys->found_corrupt_log) { recv_report_corrupt_log(ptr, type, space, page_no); } ut_a(len != 0); ut_a(0 == ((ulint)*ptr & MLOG_SINGLE_REC_FLAG)); recv_sys->recovered_offset += len; recv_sys->recovered_lsn = recv_calc_lsn_on_data_add( old_lsn, len); if (type == MLOG_MULTI_REC_END) { /* Found the end mark for the records */ break; } if (store_to_hash) { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, new_recovered_lsn);#ifdef UNIV_LOG_REPLICATE } else { /* In debug checking, check that the replicate page has become identical with the original page */ recv_compare_replicate(space, page_no);#endif /* UNIV_LOG_REPLICATE */ } ptr += len; } } goto loop;}/***********************************************************Adds data from a new log block to the parsing buffer of recv_sys ifrecv_sys->parse_start_lsn is non-zero. */staticiboolrecv_sys_add_to_parsing_buf(/*========================*/ /* out: TRUE if more data added */ byte* log_block, /* in: log block */ dulint scanned_lsn) /* in: lsn of how far we were able to find data in this log block */{ ulint more_len; ulint data_len; ulint start_offset; ulint end_offset; ut_ad(ut_dulint_cmp(scanned_lsn, recv_sys->scanned_lsn) >= 0); if (ut_dulint_is_zero(recv_sys->parse_start_lsn)) { /* Cannot start parsing yet because no start point for it found */ return(FALSE); } data_len = log_block_get_data_len(log_block); if (ut_dulint_cmp(recv_sys->parse_start_lsn, scanned_lsn) >= 0) { return(FALSE); } else if (ut_dulint_cmp(recv_sys->scanned_lsn, scanned_lsn) >= 0) { return(FALSE); } else if (ut_dulint_cmp(recv_sys->parse_start_lsn, recv_sys->scanned_lsn) > 0) { more_len = ut_dulint_minus(scanned_lsn, recv_sys->parse_start_lsn); } else { more_len = ut_dulint_minus(scanned_lsn, recv_sys->scanned_lsn); } if (more_len == 0) { return(FALSE); } ut_ad(data_len >= more_len); start_offset = data_len - more_len; if (start_offset < LOG_BLOCK_HDR_SIZE) { start_offset = LOG_BLOCK_HDR_SIZE; } end_offset = data_len; if (end_offset > OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) { end_offset = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; } ut_ad(start_offset <= end_offset); if (start_offset < end_offset) { ut_memcpy(recv_sys->buf + recv_sys->len, log_block + start_offset, end_offset - start_offset); recv_sys->len += end_offset - start_offset; ut_a(recv_sys->len <= RECV_PARSING_BUF_SIZE); } return(TRUE);}/***********************************************************Moves the parsing buffer data left to the buffer start. */staticvoidrecv_sys_justify_left_parsing_buf(void)/*===================================*/{ ut_memmove(recv_sys->buf, recv_sys->buf + recv_sys->recovered_offset, recv_sys->len - recv_sys->recovered_offset); recv_sys->len -= recv_sys->recovered_offset; recv_sys->recovered_offset = 0;}/***********************************************************Scans log from a buffer and stores new log data to the parsing buffer. Parsesand hashes the log records if new data found. */iboolrecv_scan_log_recs(/*===============*/ /* out: TRUE if limit_lsn has been reached, or not able to scan any more in this log group */ ibool apply_automatically,/* in: TRUE if we want this function to apply log records automatically when the hash table becomes full; in the hot backup tool the tool does the applying, not this function */ ulint available_memory,/* in: we let the hash table of recs to grow to this size, at the maximum */ 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* buf, /* in: buffer containing a log segment or garbage */ ulint len, /* in: buffer length */ dulint start_lsn, /* in: buffer start lsn */ dulint* contiguous_lsn, /* in/out: it is known that all log groups contain contiguous log data up to this lsn */ dulint* group_scanned_lsn)/* out: scanning succeeded up to this lsn */{ byte* log_block; ulint no; dulint scanned_lsn; ibool finished; ulint data_len; ibool more_data; ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(len > 0); ut_a(apply_automatically <= TRUE); ut_a(store_to_hash <= TRUE); finished = FALSE; log_block = buf; scanned_lsn = start_lsn; more_data = FALSE; while (log_block < buf + len && !finished) { no = log_block_get_hdr_no(log_block);/* fprintf(stderr, "Log block header no %lu\n", no); fprintf(stderr, "Scanned lsn no %lu\n", log_block_convert_lsn_to_no(scanned_lsn));*/ if (no != log_block_convert_lsn_to_no(scanned_lsn) || !log_block_checksum_is_ok_or_old_format(log_block)) { if (no == log_block_convert_lsn_to_no(scanned_lsn) && !log_block_checksum_is_ok_or_old_format( log_block)) { fprintf(stderr,"InnoDB: Log block no %lu at lsn %lu %lu has\n""InnoDB: ok header, but checksum field contains %lu, should be %lu\n", (ulong) no, (ulong) ut_dulint_get_high(scanned_lsn), (ulong) ut_dulint_get_low(scanned_lsn), (ulong) log_block_get_checksum(log_block), (ulong) log_block_calc_checksum(log_block)); } /* Garbage or an incompletely written log block */ finished = TRUE; break; } if (log_block_get_flush_bit(log_block)) { /* This block was a start of a log flush operation: we know that the previous flush operation must have been completed for all log groups before this block can have been flushed to any of the groups. Therefore, we know that log data is contiguous up to scanned_lsn in all non-corrupt log groups. */ if (ut_dulint_cmp(scanned_lsn, *contiguous_lsn) > 0) { *contiguous_lsn = scanned_lsn; } } data_len = log_block_get_data_len(log_block); if ((store_to_hash || (data_len == OS_FILE_LOG_BLOCK_SIZE)) && (ut_dulint_cmp(ut_dulint_add(scanned_lsn, data_len), recv_sys->scanned_lsn) > 0) && (recv_sys->scanned_checkpoint_no > 0) && (log_block_get_checkpoint_no(log_block) < recv_sys->scanned_checkpoint_no) && (recv_sys->scanned_checkpoint_no - log_block_get_checkpoint_no(log_block) > 0x80000000UL)) { /* Garbage from a log buffer flush which was made before the most recent database recovery */ finished = TRUE;#ifdef UNIV_LOG_DEBUG /* This is not really an error, but currently we stop here in the debug version: */ ut_error;#endif break; } if (ut_dulint_is_zero(recv_sys->parse_start_lsn) && (log_block_get_first_rec_group(log_block) > 0)) { /* We found a point from which to start the parsing of log records */ recv_sys->parse_start_lsn = ut_dulint_add(scanned_lsn, log_block_get_first_rec_group(log_block)); recv_sys->scanned_lsn = recv_sys->parse_start_lsn; recv_sys->recovered_lsn = recv_sys->parse_start_lsn; } scanned_lsn = ut_dulint_add(scanned_lsn, data_len); if (ut_dulint_cmp(scanned_lsn, recv_sys->scanned_lsn) > 0) { /* We were able to find more log data: add it to the parsing buffer if parse_start_lsn is already non-zero */ if (recv_sys->len + 4 * OS_FILE_LOG_BLOCK_SIZE >= RECV_PARSING_BUF_SIZE) { fprintf(stderr,"InnoDB: Error: log parsing buffer overflow. Recovery may have failed!\n"); recv_sys->found_corrupt_log = TRUE; } else if (!recv_sys->found_corrupt_log) { more_data = recv_sys_add_to_parsing_buf( log_block, scanned_lsn); } recv_sys->scanned_lsn = scanned_lsn; recv_sys->scanned_checkpoint_no = log_block_get_checkpoint_no(log_block); } if (data_len < OS_FILE_LOG_BLOCK_SIZE) { /* Log data for this group ends here */ finished = TRUE; } else { log_block += OS_FILE_LOG_BLOCK_SIZE; } } *group_scanned_lsn = scanned_lsn; if (recv_needed_recovery || (recv_is_from_backup && !recv_is_making_a_backup)) { recv_scan_print_counter++; if (finished || (recv_scan_print_counter % 80 == 0)) { fprintf(stderr, "InnoDB: Doing recovery: scanned up to log sequence number %lu %lu\n", (ulong) ut_dulint_get_high(*group_scanned_lsn), (ulong) ut_dulint_get_low(*group_scanned_lsn)); } } if (more_data && !recv_sys->found_corrupt_log) { /* Try to parse more log records */ recv_parse_log_recs(store_to_hash); if (store_to_hash && mem_heap_get_size(recv_sys->heap) > available_memory && apply_automatically) { /* Hash table of log records has grown too big: empty it; FALSE means no ibuf
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -