00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "log0recv.h"
00027
00028 #ifdef UNIV_NONINL
00029 #include "log0recv.ic"
00030 #endif
00031
00032 #include "mem0mem.h"
00033 #include "buf0buf.h"
00034 #include "buf0flu.h"
00035 #include "mtr0mtr.h"
00036 #include "mtr0log.h"
00037 #include "page0cur.h"
00038 #include "page0zip.h"
00039 #include "btr0btr.h"
00040 #include "btr0cur.h"
00041 #include "ibuf0ibuf.h"
00042 #include "trx0undo.h"
00043 #include "trx0rec.h"
00044 #include "fil0fil.h"
00045 #include "xtrabackup_api.h"
00046 #ifndef UNIV_HOTBACKUP
00047 # include "buf0rea.h"
00048 # include "srv0srv.h"
00049 # include "srv0start.h"
00050 # include "trx0roll.h"
00051 # include "row0merge.h"
00052 # include "sync0sync.h"
00053 #else
00054
00058 UNIV_INTERN ibool recv_replay_file_ops = TRUE;
00059 #endif
00060
00061 #include <boost/scoped_array.hpp>
00062
00063 #include <drizzled/errmsg_print.h>
00064
00067 #define RECV_DATA_BLOCK_SIZE (MEM_MAX_ALLOC_IN_BUF - sizeof(recv_data_t))
00068
00070 #define RECV_READ_AHEAD_AREA 32
00071
00073 UNIV_INTERN recv_sys_t* recv_sys = NULL;
00077 UNIV_INTERN ibool recv_recovery_on;
00078 #ifdef UNIV_LOG_ARCHIVE
00079
00080 UNIV_INTERN ibool recv_recovery_from_backup_on;
00081 #endif
00082
00083 #ifndef UNIV_HOTBACKUP
00084
00085 UNIV_INTERN ibool recv_needed_recovery;
00086 # ifdef UNIV_DEBUG
00087
00089 UNIV_INTERN ibool recv_no_log_write = FALSE;
00090 # endif
00091
00095 UNIV_INTERN ibool recv_lsn_checks_on;
00096
00105 static ibool recv_log_scan_is_startup_type;
00106
00116 UNIV_INTERN ibool recv_no_ibuf_operations;
00118 # define recv_is_making_a_backup FALSE
00119
00120 # define recv_is_from_backup FALSE
00121 #else
00122 # define recv_needed_recovery FALSE
00123
00124 UNIV_INTERN ibool recv_is_making_a_backup = FALSE;
00126 UNIV_INTERN ibool recv_is_from_backup = FALSE;
00127 # define buf_pool_get_curr_size() (5 * 1024 * 1024)
00128 #endif
00129
00131 static ulint recv_scan_print_counter;
00132
00134 static ulint recv_previous_parsed_rec_type;
00136 static ulint recv_previous_parsed_rec_offset;
00138 static ulint recv_previous_parsed_rec_is_multi;
00139
00141 UNIV_INTERN ulint recv_max_parsed_page_no;
00142
00149 UNIV_INTERN ulint recv_n_pool_free_frames;
00150
00154 UNIV_INTERN ib_uint64_t recv_max_page_lsn;
00155
00156 #ifdef UNIV_PFS_THREAD
00157 UNIV_INTERN mysql_pfs_key_t trx_rollback_clean_thread_key;
00158 #endif
00159
00160 #ifdef UNIV_PFS_MUTEX
00161 UNIV_INTERN mysql_pfs_key_t recv_sys_mutex_key;
00162 #endif
00163
00164
00165
00166 #ifndef UNIV_HOTBACKUP
00167
00170 static
00171 void
00172 recv_init_crash_recovery(void);
00173
00174 #endif
00175
00176
00178 UNIV_INTERN
00179 void
00180 recv_sys_create(void)
00181
00182 {
00183 if (recv_sys != NULL) {
00184
00185 return;
00186 }
00187
00188 recv_sys = static_cast<recv_sys_t *>(mem_alloc(sizeof(*recv_sys)));
00189 memset(recv_sys, 0x0, sizeof(*recv_sys));
00190
00191 mutex_create(recv_sys_mutex_key, &recv_sys->mutex, SYNC_RECV);
00192
00193 recv_sys->heap = NULL;
00194 recv_sys->addr_hash = NULL;
00195 }
00196
00197
00199 UNIV_INTERN
00200 void
00201 recv_sys_close(void)
00202
00203 {
00204 if (recv_sys != NULL) {
00205 if (recv_sys->addr_hash != NULL) {
00206 hash_table_free(recv_sys->addr_hash);
00207 }
00208
00209 if (recv_sys->heap != NULL) {
00210 mem_heap_free(recv_sys->heap);
00211 }
00212
00213 if (recv_sys->buf != NULL) {
00214 ut_free(recv_sys->buf);
00215 }
00216
00217 if (recv_sys->last_block_buf_start != NULL) {
00218 mem_free(recv_sys->last_block_buf_start);
00219 }
00220
00221 mutex_free(&recv_sys->mutex);
00222
00223 mem_free(recv_sys);
00224 recv_sys = NULL;
00225 }
00226 }
00227
00228
00230 UNIV_INTERN
00231 void
00232 recv_sys_mem_free(void)
00233
00234 {
00235 if (recv_sys != NULL) {
00236 if (recv_sys->addr_hash != NULL) {
00237 hash_table_free(recv_sys->addr_hash);
00238 }
00239
00240 if (recv_sys->heap != NULL) {
00241 mem_heap_free(recv_sys->heap);
00242 }
00243
00244 if (recv_sys->buf != NULL) {
00245 ut_free(recv_sys->buf);
00246 }
00247
00248 if (recv_sys->last_block_buf_start != NULL) {
00249 mem_free(recv_sys->last_block_buf_start);
00250 }
00251
00252 mem_free(recv_sys);
00253 recv_sys = NULL;
00254 }
00255 }
00256
00257 #ifndef UNIV_HOTBACKUP
00258
00259
00260 UNIV_INTERN
00261 void
00262 recv_sys_var_init(void)
00263
00264 {
00265 recv_lsn_checks_on = FALSE;
00266
00267 recv_n_pool_free_frames = 256;
00268
00269 recv_recovery_on = FALSE;
00270
00271 #ifdef UNIV_LOG_ARCHIVE
00272 recv_recovery_from_backup_on = FALSE;
00273 #endif
00274
00275 recv_needed_recovery = FALSE;
00276
00277 recv_lsn_checks_on = FALSE;
00278
00279 recv_log_scan_is_startup_type = FALSE;
00280
00281 recv_no_ibuf_operations = FALSE;
00282
00283 recv_scan_print_counter = 0;
00284
00285 recv_previous_parsed_rec_type = 999999;
00286
00287 recv_previous_parsed_rec_offset = 0;
00288
00289 recv_previous_parsed_rec_is_multi = 0;
00290
00291 recv_max_parsed_page_no = 0;
00292
00293 recv_n_pool_free_frames = 256;
00294
00295 recv_max_page_lsn = 0;
00296 }
00297 #endif
00298
00299
00300
00301 UNIV_INTERN
00302 void
00303 recv_sys_init(
00304
00305 ulint available_memory)
00306 {
00307 if (recv_sys->heap != NULL) {
00308
00309 return;
00310 }
00311
00312 #ifndef UNIV_HOTBACKUP
00313
00314
00315
00316
00317 #ifndef UNIV_HOTBACKUP
00318 buf_flush_init_flush_rbt();
00319 #endif
00320
00321 mutex_enter(&(recv_sys->mutex));
00322
00323 recv_sys->heap = mem_heap_create_in_buffer(256);
00324 #else
00325 recv_sys->heap = mem_heap_create(256);
00326 recv_is_from_backup = TRUE;
00327 #endif
00328
00329
00330 if (buf_pool_get_curr_size() >= (10 * 1024 * 1024)) {
00331
00332 recv_n_pool_free_frames = 512;
00333 }
00334
00335 recv_sys->buf = static_cast<byte *>(ut_malloc(RECV_PARSING_BUF_SIZE));
00336 recv_sys->len = 0;
00337 recv_sys->recovered_offset = 0;
00338
00339 recv_sys->addr_hash = hash_create(available_memory / 512);
00340 recv_sys->n_addrs = 0;
00341
00342 recv_sys->apply_log_recs = FALSE;
00343 recv_sys->apply_batch_on = FALSE;
00344
00345 recv_sys->last_block_buf_start = static_cast<byte *>(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE));
00346
00347 recv_sys->last_block = static_cast<byte *>(ut_align(recv_sys->last_block_buf_start,
00348 OS_FILE_LOG_BLOCK_SIZE));
00349 recv_sys->found_corrupt_log = FALSE;
00350
00351 recv_max_page_lsn = 0;
00352
00353 mutex_exit(&(recv_sys->mutex));
00354 }
00355
00356
00358 static
00359 void
00360 recv_sys_empty_hash(void)
00361
00362 {
00363 ut_ad(mutex_own(&(recv_sys->mutex)));
00364
00365 if (recv_sys->n_addrs != 0) {
00366 drizzled::errmsg_printf(drizzled::error::ERROR,
00367 "InnoDB: Error: %lu pages with log records were left unprocessed!\n"
00368 "InnoDB: Maximum page number with log records on it %lu\n",
00369 (ulong) recv_sys->n_addrs,
00370 (ulong) recv_max_parsed_page_no);
00371 ut_error;
00372 }
00373
00374 hash_table_free(recv_sys->addr_hash);
00375 mem_heap_empty(recv_sys->heap);
00376
00377 recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 512);
00378 }
00379
00380 #ifndef UNIV_HOTBACKUP
00381 # ifndef UNIV_LOG_DEBUG
00382
00384 static
00385 void
00386 recv_sys_debug_free(void)
00387
00388 {
00389 mutex_enter(&(recv_sys->mutex));
00390
00391 hash_table_free(recv_sys->addr_hash);
00392 mem_heap_free(recv_sys->heap);
00393 ut_free(recv_sys->buf);
00394 mem_free(recv_sys->last_block_buf_start);
00395
00396 recv_sys->buf = NULL;
00397 recv_sys->heap = NULL;
00398 recv_sys->addr_hash = NULL;
00399 recv_sys->last_block_buf_start = NULL;
00400
00401 mutex_exit(&(recv_sys->mutex));
00402
00403
00404 buf_flush_free_flush_rbt();
00405 }
00406 # endif
00407
00408
00410 static
00411 void
00412 recv_truncate_group(
00413
00414 log_group_t* group,
00415 ib_uint64_t recovered_lsn,
00417 ib_uint64_t limit_lsn,
00419 ib_uint64_t checkpoint_lsn,
00421 ib_uint64_t archived_lsn)
00423 {
00424 ib_uint64_t start_lsn;
00425 ib_uint64_t end_lsn;
00426 ib_uint64_t finish_lsn1;
00427 ib_uint64_t finish_lsn2;
00428 ib_uint64_t finish_lsn;
00429 ulint len;
00430 ulint i;
00431
00432 if (archived_lsn == IB_ULONGLONG_MAX) {
00433
00434 archived_lsn = checkpoint_lsn;
00435 }
00436
00437 finish_lsn1 = ut_uint64_align_down(archived_lsn,
00438 OS_FILE_LOG_BLOCK_SIZE)
00439 + log_group_get_capacity(group);
00440
00441 finish_lsn2 = ut_uint64_align_up(recovered_lsn,
00442 OS_FILE_LOG_BLOCK_SIZE)
00443 + recv_sys->last_log_buf_size;
00444
00445 if (limit_lsn != IB_ULONGLONG_MAX) {
00446
00447
00448
00449 finish_lsn = finish_lsn1;
00450 } else {
00451
00452 finish_lsn = finish_lsn1 < finish_lsn2
00453 ? finish_lsn1 : finish_lsn2;
00454 }
00455
00456 ut_a(RECV_SCAN_SIZE <= log_sys->buf_size);
00457
00458
00459 for (i = 0; i < RECV_SCAN_SIZE; i++) {
00460
00461 *(log_sys->buf + i) = '\0';
00462 }
00463
00464 start_lsn = ut_uint64_align_down(recovered_lsn,
00465 OS_FILE_LOG_BLOCK_SIZE);
00466
00467 if (start_lsn != recovered_lsn) {
00468
00469
00470
00471 ut_memcpy(log_sys->buf, recv_sys->last_block,
00472 OS_FILE_LOG_BLOCK_SIZE);
00473 log_block_set_data_len(log_sys->buf,
00474 (ulint) (recovered_lsn - start_lsn));
00475 }
00476
00477 if (start_lsn >= finish_lsn) {
00478
00479 return;
00480 }
00481
00482 for (;;) {
00483 end_lsn = start_lsn + RECV_SCAN_SIZE;
00484
00485 if (end_lsn > finish_lsn) {
00486
00487 end_lsn = finish_lsn;
00488 }
00489
00490 len = (ulint) (end_lsn - start_lsn);
00491
00492 log_group_write_buf(group, log_sys->buf, len, start_lsn, 0);
00493 if (end_lsn >= finish_lsn) {
00494
00495 return;
00496 }
00497
00498
00499 for (i = 0; i < RECV_SCAN_SIZE; i++) {
00500
00501 *(log_sys->buf + i) = '\0';
00502 }
00503
00504 start_lsn = end_lsn;
00505 }
00506 }
00507
00508
00511 static
00512 void
00513 recv_copy_group(
00514
00515 log_group_t* up_to_date_group,
00517 log_group_t* group,
00519 ib_uint64_t recovered_lsn)
00521 {
00522 ib_uint64_t start_lsn;
00523 ib_uint64_t end_lsn;
00524 ulint len;
00525
00526 if (group->scanned_lsn >= recovered_lsn) {
00527
00528 return;
00529 }
00530
00531 ut_a(RECV_SCAN_SIZE <= log_sys->buf_size);
00532
00533 start_lsn = ut_uint64_align_down(group->scanned_lsn,
00534 OS_FILE_LOG_BLOCK_SIZE);
00535 for (;;) {
00536 end_lsn = start_lsn + RECV_SCAN_SIZE;
00537
00538 if (end_lsn > recovered_lsn) {
00539 end_lsn = ut_uint64_align_up(recovered_lsn,
00540 OS_FILE_LOG_BLOCK_SIZE);
00541 }
00542
00543 log_group_read_log_seg(LOG_RECOVER, log_sys->buf,
00544 up_to_date_group, start_lsn, end_lsn);
00545
00546 len = (ulint) (end_lsn - start_lsn);
00547
00548 log_group_write_buf(group, log_sys->buf, len, start_lsn, 0);
00549
00550 if (end_lsn >= recovered_lsn) {
00551
00552 return;
00553 }
00554
00555 start_lsn = end_lsn;
00556 }
00557 }
00558
00559
00564 static
00565 void
00566 recv_synchronize_groups(
00567
00568 log_group_t* up_to_date_group)
00570 {
00571 log_group_t* group;
00572 ib_uint64_t start_lsn;
00573 ib_uint64_t end_lsn;
00574 ib_uint64_t recovered_lsn;
00575
00576 recovered_lsn = recv_sys->recovered_lsn;
00577
00578
00579
00580
00581 start_lsn = ut_uint64_align_down(recovered_lsn,
00582 OS_FILE_LOG_BLOCK_SIZE);
00583 end_lsn = ut_uint64_align_up(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE);
00584
00585 ut_a(start_lsn != end_lsn);
00586
00587 log_group_read_log_seg(LOG_RECOVER, recv_sys->last_block,
00588 up_to_date_group, start_lsn, end_lsn);
00589
00590 group = UT_LIST_GET_FIRST(log_sys->log_groups);
00591
00592 while (group) {
00593 if (group != up_to_date_group) {
00594
00595
00596
00597 recv_copy_group(group, up_to_date_group,
00598 recovered_lsn);
00599 }
00600
00601
00602
00603
00604 log_group_set_fields(group, recovered_lsn);
00605
00606 group = UT_LIST_GET_NEXT(log_groups, group);
00607 }
00608
00609
00610
00611
00612
00613
00614 log_groups_write_checkpoint_info();
00615
00616 mutex_exit(&(log_sys->mutex));
00617
00618
00619 rw_lock_s_lock(&(log_sys->checkpoint_lock));
00620 rw_lock_s_unlock(&(log_sys->checkpoint_lock));
00621
00622 mutex_enter(&(log_sys->mutex));
00623 }
00624 #endif
00625
00626
00629 ibool
00630 recv_check_cp_is_consistent(
00631
00632 const byte* buf)
00633 {
00634 ulint fold;
00635
00636 fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
00637
00638 if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(
00639 buf + LOG_CHECKPOINT_CHECKSUM_1)) {
00640 return(FALSE);
00641 }
00642
00643 fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
00644 LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
00645
00646 if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(
00647 buf + LOG_CHECKPOINT_CHECKSUM_2)) {
00648 return(FALSE);
00649 }
00650
00651 return(TRUE);
00652 }
00653
00654 #ifndef UNIV_HOTBACKUP
00655
00658 ulint
00659 recv_find_max_checkpoint(
00660
00661 log_group_t** max_group,
00662 ulint* max_field)
00664 {
00665 log_group_t* group;
00666 ib_uint64_t max_no;
00667 ib_uint64_t checkpoint_no;
00668 ulint field;
00669 byte* buf;
00670
00671 group = UT_LIST_GET_FIRST(log_sys->log_groups);
00672
00673 max_no = 0;
00674 *max_group = NULL;
00675 *max_field = 0;
00676
00677 buf = log_sys->checkpoint_buf;
00678
00679 while (group) {
00680 group->state = LOG_GROUP_CORRUPTED;
00681
00682 for (field = LOG_CHECKPOINT_1; field <= LOG_CHECKPOINT_2;
00683 field += LOG_CHECKPOINT_2 - LOG_CHECKPOINT_1) {
00684
00685 log_group_read_checkpoint_info(group, field);
00686
00687 if (!recv_check_cp_is_consistent(buf)) {
00688 #ifdef UNIV_DEBUG
00689 if (log_debug_writes) {
00690 drizzled::errmsg_printf(drizzled::error::INFO,
00691 "InnoDB: Checkpoint in group %lu at %lu invalid, %lu\n",
00692 (ulong) group->id,
00693 (ulong) field,
00694 (ulong) mach_read_from_4(
00695 buf
00696 + LOG_CHECKPOINT_CHECKSUM_1));
00697
00698 }
00699 #endif
00700 goto not_consistent;
00701 }
00702
00703 group->state = LOG_GROUP_OK;
00704
00705 group->lsn = mach_read_from_8(
00706 buf + LOG_CHECKPOINT_LSN);
00707
00708 #ifdef UNIV_LOG_ARCHIVE
00709 #error "UNIV_LOG_ARCHIVE could not be enabled"
00710 #endif
00711 {
00712 ib_uint64_t tmp_lsn_offset = mach_read_from_8(
00713 buf + LOG_CHECKPOINT_ARCHIVED_LSN);
00714 if (sizeof(ulint) != 4
00715 && tmp_lsn_offset != IB_ULONGLONG_MAX) {
00716 group->lsn_offset = (ulint) tmp_lsn_offset;
00717 } else {
00718 group->lsn_offset = mach_read_from_4(
00719 buf + LOG_CHECKPOINT_OFFSET);
00720 }
00721 }
00722
00723 checkpoint_no = mach_read_from_8(
00724 buf + LOG_CHECKPOINT_NO);
00725
00726 #ifdef UNIV_DEBUG
00727 if (log_debug_writes) {
00728 drizzled::errmsg_printf(drizzled::error::INFO,
00729 "InnoDB: Checkpoint number %lu found in group %lu\n",
00730 (ulong) checkpoint_no,
00731 (ulong) group->id);
00732 }
00733 #endif
00734
00735 if (checkpoint_no >= max_no) {
00736 *max_group = group;
00737 *max_field = field;
00738 max_no = checkpoint_no;
00739 }
00740
00741 not_consistent:
00742 ;
00743 }
00744
00745 group = UT_LIST_GET_NEXT(log_groups, group);
00746 }
00747
00748 if (*max_group == NULL) {
00749
00750 drizzled::errmsg_printf(drizzled::error::ERROR,
00751 "InnoDB: No valid checkpoint found. If this error appears when you are"
00752 " creating an InnoDB database,InnoDB: the problem may be that during"
00753 " an earlier attempt you managed to create the InnoDB data files,"
00754 " but log file creation failed. If that is the case, please refer to\n"
00755 "InnoDB: " REFMAN "error-creating-innodb.html\n");
00756 return(DB_ERROR);
00757 }
00758
00759 return(DB_SUCCESS);
00760 }
00761 #else
00762
00765 UNIV_INTERN
00766 ibool
00767 recv_read_cp_info_for_backup(
00768
00769 const byte* hdr,
00771 ib_uint64_t* lsn,
00772 ulint* offset,
00773 ulint* fsp_limit,
00776 ib_uint64_t* cp_no,
00777 ib_uint64_t* first_header_lsn)
00780 {
00781 ulint max_cp = 0;
00782 ib_uint64_t max_cp_no = 0;
00783 const byte* cp_buf;
00784
00785 cp_buf = hdr + LOG_CHECKPOINT_1;
00786
00787 if (recv_check_cp_is_consistent(cp_buf)) {
00788 max_cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO);
00789 max_cp = LOG_CHECKPOINT_1;
00790 }
00791
00792 cp_buf = hdr + LOG_CHECKPOINT_2;
00793
00794 if (recv_check_cp_is_consistent(cp_buf)) {
00795 if (mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO) > max_cp_no) {
00796 max_cp = LOG_CHECKPOINT_2;
00797 }
00798 }
00799
00800 if (max_cp == 0) {
00801 return(FALSE);
00802 }
00803
00804 cp_buf = hdr + max_cp;
00805
00806 *lsn = mach_read_from_8(cp_buf + LOG_CHECKPOINT_LSN);
00807 *offset = mach_read_from_4(cp_buf + LOG_CHECKPOINT_OFFSET);
00808
00809
00810
00811 if (mach_read_from_4(cp_buf + LOG_CHECKPOINT_FSP_MAGIC_N)
00812 == LOG_CHECKPOINT_FSP_MAGIC_N_VAL) {
00813
00814 *fsp_limit = mach_read_from_4(
00815 cp_buf + LOG_CHECKPOINT_FSP_FREE_LIMIT);
00816
00817 if (*fsp_limit == 0) {
00818 *fsp_limit = 1000000000;
00819 }
00820 } else {
00821 *fsp_limit = 1000000000;
00822 }
00823
00824
00825
00826 *cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO);
00827
00828 *first_header_lsn = mach_read_from_8(hdr + LOG_FILE_START_LSN);
00829
00830 return(TRUE);
00831 }
00832 #endif
00833
00834
00840 ibool
00841 log_block_checksum_is_ok_or_old_format(
00842
00843 const byte* block)
00844 {
00845 #ifdef UNIV_LOG_DEBUG
00846 return(TRUE);
00847 #endif
00848 if (log_block_calc_checksum(block) == log_block_get_checksum(block)) {
00849
00850 return(TRUE);
00851 }
00852
00853 if (log_block_get_hdr_no(block) == log_block_get_checksum(block)) {
00854
00855
00856
00857 #if 0
00858 fprintf(stderr,
00859 "InnoDB: Scanned old format < InnoDB-3.23.52"
00860 " log block number %lu\n",
00861 log_block_get_hdr_no(block));
00862 #endif
00863 return(TRUE);
00864 }
00865
00866 return(FALSE);
00867 }
00868
00869 #ifdef UNIV_HOTBACKUP
00870
00873 UNIV_INTERN
00874 void
00875 recv_scan_log_seg_for_backup(
00876
00877 byte* buf,
00878 ulint buf_len,
00879 ib_uint64_t* scanned_lsn,
00881 ulint* scanned_checkpoint_no,
00885 ulint* n_bytes_scanned)
00888 {
00889 ulint data_len;
00890 byte* log_block;
00891 ulint no;
00892
00893 *n_bytes_scanned = 0;
00894
00895 for (log_block = buf; log_block < buf + buf_len;
00896 log_block += OS_FILE_LOG_BLOCK_SIZE) {
00897
00898 no = log_block_get_hdr_no(log_block);
00899
00900 #if 0
00901 fprintf(stderr, "Log block header no %lu\n", no);
00902 #endif
00903
00904 if (no != log_block_convert_lsn_to_no(*scanned_lsn)
00905 || !log_block_checksum_is_ok_or_old_format(log_block)) {
00906 #if 0
00907 fprintf(stderr,
00908 "Log block n:o %lu, scanned lsn n:o %lu\n",
00909 no, log_block_convert_lsn_to_no(*scanned_lsn));
00910 #endif
00911
00912
00913 log_block += OS_FILE_LOG_BLOCK_SIZE;
00914 #if 0
00915 fprintf(stderr,
00916 "Next log block n:o %lu\n",
00917 log_block_get_hdr_no(log_block));
00918 #endif
00919 break;
00920 }
00921
00922 if (*scanned_checkpoint_no > 0
00923 && log_block_get_checkpoint_no(log_block)
00924 < *scanned_checkpoint_no
00925 && *scanned_checkpoint_no
00926 - log_block_get_checkpoint_no(log_block)
00927 > 0x80000000UL) {
00928
00929
00930
00931 #if 0
00932 fprintf(stderr,
00933 "Scanned cp n:o %lu, block cp n:o %lu\n",
00934 *scanned_checkpoint_no,
00935 log_block_get_checkpoint_no(log_block));
00936 #endif
00937 break;
00938 }
00939
00940 data_len = log_block_get_data_len(log_block);
00941
00942 *scanned_checkpoint_no
00943 = log_block_get_checkpoint_no(log_block);
00944 *scanned_lsn += data_len;
00945
00946 *n_bytes_scanned += data_len;
00947
00948 if (data_len < OS_FILE_LOG_BLOCK_SIZE) {
00949
00950
00951 #if 0
00952 fprintf(stderr, "Log block data len %lu\n",
00953 data_len);
00954 #endif
00955 break;
00956 }
00957 }
00958 }
00959 #endif
00960
00961
00965 static
00966 byte*
00967 recv_parse_or_apply_log_rec_body(
00968
00969 byte type,
00970 byte* ptr,
00971 byte* end_ptr,
00972 buf_block_t* block,
00976 mtr_t* mtr)
00978 {
00979 dict_index_t* index = NULL;
00980 page_t* page;
00981 page_zip_des_t* page_zip;
00982 #ifdef UNIV_DEBUG
00983 ulint page_type;
00984 #endif
00985
00986 ut_ad(!block == !mtr);
00987
00988 if (block) {
00989 page = block->frame;
00990 page_zip = buf_block_get_page_zip(block);
00991 ut_d(page_type = fil_page_get_type(page));
00992 } else {
00993 page = NULL;
00994 page_zip = NULL;
00995 ut_d(page_type = FIL_PAGE_TYPE_ALLOCATED);
00996 }
00997
00998 switch (type) {
00999 #ifdef UNIV_LOG_LSN_DEBUG
01000 case MLOG_LSN:
01001
01002 break;
01003 #endif
01004 case MLOG_1BYTE: case MLOG_2BYTES: case MLOG_4BYTES: case MLOG_8BYTES:
01005 #ifdef UNIV_DEBUG
01006 if (page && page_type == FIL_PAGE_TYPE_ALLOCATED
01007 && end_ptr >= ptr + 2) {
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017 ulint offs = mach_read_from_2(ptr);
01018
01019 switch (type) {
01020 default:
01021 ut_error;
01022 case MLOG_2BYTES:
01023
01024
01025
01026 ut_ad(offs == FIL_PAGE_TYPE
01027 || offs == IBUF_TREE_SEG_HEADER
01028 + IBUF_HEADER + FSEG_HDR_OFFSET
01029 || offs == PAGE_BTR_IBUF_FREE_LIST
01030 + PAGE_HEADER + FIL_ADDR_BYTE
01031 || offs == PAGE_BTR_IBUF_FREE_LIST
01032 + PAGE_HEADER + FIL_ADDR_BYTE
01033 + FIL_ADDR_SIZE
01034 || offs == PAGE_BTR_SEG_LEAF
01035 + PAGE_HEADER + FSEG_HDR_OFFSET
01036 || offs == PAGE_BTR_SEG_TOP
01037 + PAGE_HEADER + FSEG_HDR_OFFSET
01038 || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
01039 + PAGE_HEADER + FIL_ADDR_BYTE
01040 + 0
01041 || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
01042 + PAGE_HEADER + FIL_ADDR_BYTE
01043 + FIL_ADDR_SIZE );
01044 break;
01045 case MLOG_4BYTES:
01046
01047
01048
01049 ut_ad(0
01050 || offs == IBUF_TREE_SEG_HEADER
01051 + IBUF_HEADER + FSEG_HDR_SPACE
01052 || offs == IBUF_TREE_SEG_HEADER
01053 + IBUF_HEADER + FSEG_HDR_PAGE_NO
01054 || offs == PAGE_BTR_IBUF_FREE_LIST
01055 + PAGE_HEADER
01056 || offs == PAGE_BTR_IBUF_FREE_LIST
01057 + PAGE_HEADER + FIL_ADDR_PAGE
01058 || offs == PAGE_BTR_IBUF_FREE_LIST
01059 + PAGE_HEADER + FIL_ADDR_PAGE
01060 + FIL_ADDR_SIZE
01061 || offs == PAGE_BTR_SEG_LEAF
01062 + PAGE_HEADER + FSEG_HDR_PAGE_NO
01063 || offs == PAGE_BTR_SEG_LEAF
01064 + PAGE_HEADER + FSEG_HDR_SPACE
01065 || offs == PAGE_BTR_SEG_TOP
01066 + PAGE_HEADER + FSEG_HDR_PAGE_NO
01067 || offs == PAGE_BTR_SEG_TOP
01068 + PAGE_HEADER + FSEG_HDR_SPACE
01069 || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
01070 + PAGE_HEADER + FIL_ADDR_PAGE
01071 + 0
01072 || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
01073 + PAGE_HEADER + FIL_ADDR_PAGE
01074 + FIL_ADDR_SIZE );
01075 break;
01076 }
01077 }
01078 #endif
01079 ptr = mlog_parse_nbytes(type, ptr, end_ptr, page, page_zip);
01080 break;
01081 case MLOG_REC_INSERT: case MLOG_COMP_REC_INSERT:
01082 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01083
01084 if (NULL != (ptr = mlog_parse_index(
01085 ptr, end_ptr,
01086 type == MLOG_COMP_REC_INSERT,
01087 &index))) {
01088 ut_a(!page
01089 || (ibool)!!page_is_comp(page)
01090 == dict_table_is_comp(index->table));
01091 ptr = page_cur_parse_insert_rec(FALSE, ptr, end_ptr,
01092 block, index, mtr);
01093 }
01094 break;
01095 case MLOG_REC_CLUST_DELETE_MARK: case MLOG_COMP_REC_CLUST_DELETE_MARK:
01096 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01097
01098 if (NULL != (ptr = mlog_parse_index(
01099 ptr, end_ptr,
01100 type == MLOG_COMP_REC_CLUST_DELETE_MARK,
01101 &index))) {
01102 ut_a(!page
01103 || (ibool)!!page_is_comp(page)
01104 == dict_table_is_comp(index->table));
01105 ptr = btr_cur_parse_del_mark_set_clust_rec(
01106 ptr, end_ptr, page, page_zip, index);
01107 }
01108 break;
01109 case MLOG_COMP_REC_SEC_DELETE_MARK:
01110 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01111
01112
01113 ut_a(!page || page_is_comp(page));
01114 ut_a(!page_zip);
01115 ptr = mlog_parse_index(ptr, end_ptr, TRUE, &index);
01116 if (!ptr) {
01117 break;
01118 }
01119
01120 case MLOG_REC_SEC_DELETE_MARK:
01121 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01122 ptr = btr_cur_parse_del_mark_set_sec_rec(ptr, end_ptr,
01123 page, page_zip);
01124 break;
01125 case MLOG_REC_UPDATE_IN_PLACE: case MLOG_COMP_REC_UPDATE_IN_PLACE:
01126 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01127
01128 if (NULL != (ptr = mlog_parse_index(
01129 ptr, end_ptr,
01130 type == MLOG_COMP_REC_UPDATE_IN_PLACE,
01131 &index))) {
01132 ut_a(!page
01133 || (ibool)!!page_is_comp(page)
01134 == dict_table_is_comp(index->table));
01135 ptr = btr_cur_parse_update_in_place(ptr, end_ptr, page,
01136 page_zip, index);
01137 }
01138 break;
01139 case MLOG_LIST_END_DELETE: case MLOG_COMP_LIST_END_DELETE:
01140 case MLOG_LIST_START_DELETE: case MLOG_COMP_LIST_START_DELETE:
01141 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01142
01143 if (NULL != (ptr = mlog_parse_index(
01144 ptr, end_ptr,
01145 type == MLOG_COMP_LIST_END_DELETE
01146 || type == MLOG_COMP_LIST_START_DELETE,
01147 &index))) {
01148 ut_a(!page
01149 || (ibool)!!page_is_comp(page)
01150 == dict_table_is_comp(index->table));
01151 ptr = page_parse_delete_rec_list(type, ptr, end_ptr,
01152 block, index, mtr);
01153 }
01154 break;
01155 case MLOG_LIST_END_COPY_CREATED: case MLOG_COMP_LIST_END_COPY_CREATED:
01156 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01157
01158 if (NULL != (ptr = mlog_parse_index(
01159 ptr, end_ptr,
01160 type == MLOG_COMP_LIST_END_COPY_CREATED,
01161 &index))) {
01162 ut_a(!page
01163 || (ibool)!!page_is_comp(page)
01164 == dict_table_is_comp(index->table));
01165 ptr = page_parse_copy_rec_list_to_created_page(
01166 ptr, end_ptr, block, index, mtr);
01167 }
01168 break;
01169 case MLOG_PAGE_REORGANIZE: case MLOG_COMP_PAGE_REORGANIZE:
01170 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01171
01172 if (NULL != (ptr = mlog_parse_index(
01173 ptr, end_ptr,
01174 type == MLOG_COMP_PAGE_REORGANIZE,
01175 &index))) {
01176 ut_a(!page
01177 || (ibool)!!page_is_comp(page)
01178 == dict_table_is_comp(index->table));
01179 ptr = btr_parse_page_reorganize(ptr, end_ptr, index,
01180 block, mtr);
01181 }
01182 break;
01183 case MLOG_PAGE_CREATE: case MLOG_COMP_PAGE_CREATE:
01184
01185 ut_a(!page_zip);
01186 ptr = page_parse_create(ptr, end_ptr,
01187 type == MLOG_COMP_PAGE_CREATE,
01188 block, mtr);
01189 break;
01190 case MLOG_UNDO_INSERT:
01191 ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
01192 ptr = trx_undo_parse_add_undo_rec(ptr, end_ptr, page);
01193 break;
01194 case MLOG_UNDO_ERASE_END:
01195 ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
01196 ptr = trx_undo_parse_erase_page_end(ptr, end_ptr, page, mtr);
01197 break;
01198 case MLOG_UNDO_INIT:
01199
01200 ptr = trx_undo_parse_page_init(ptr, end_ptr, page, mtr);
01201 break;
01202 case MLOG_UNDO_HDR_DISCARD:
01203 ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
01204 ptr = trx_undo_parse_discard_latest(ptr, end_ptr, page, mtr);
01205 break;
01206 case MLOG_UNDO_HDR_CREATE:
01207 case MLOG_UNDO_HDR_REUSE:
01208 ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
01209 ptr = trx_undo_parse_page_header(type, ptr, end_ptr,
01210 page, mtr);
01211 break;
01212 case MLOG_REC_MIN_MARK: case MLOG_COMP_REC_MIN_MARK:
01213 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01214
01215
01216
01217
01218 ut_a(type == MLOG_COMP_REC_MIN_MARK || !page_zip);
01219 ptr = btr_parse_set_min_rec_mark(
01220 ptr, end_ptr, type == MLOG_COMP_REC_MIN_MARK,
01221 page, mtr);
01222 break;
01223 case MLOG_REC_DELETE: case MLOG_COMP_REC_DELETE:
01224 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01225
01226 if (NULL != (ptr = mlog_parse_index(
01227 ptr, end_ptr,
01228 type == MLOG_COMP_REC_DELETE,
01229 &index))) {
01230 ut_a(!page
01231 || (ibool)!!page_is_comp(page)
01232 == dict_table_is_comp(index->table));
01233 ptr = page_cur_parse_delete_rec(ptr, end_ptr,
01234 block, index, mtr);
01235 }
01236 break;
01237 case MLOG_IBUF_BITMAP_INIT:
01238
01239 ptr = ibuf_parse_bitmap_init(ptr, end_ptr, block, mtr);
01240 break;
01241 case MLOG_INIT_FILE_PAGE:
01242
01243 ptr = fsp_parse_init_file_page(ptr, end_ptr, block);
01244 break;
01245 case MLOG_WRITE_STRING:
01246 ut_ad(!page || page_type != FIL_PAGE_TYPE_ALLOCATED);
01247 ptr = mlog_parse_string(ptr, end_ptr, page, page_zip);
01248 break;
01249 case MLOG_FILE_CREATE:
01250 case MLOG_FILE_RENAME:
01251 case MLOG_FILE_DELETE:
01252 case MLOG_FILE_CREATE2:
01253 ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, 0, 0);
01254 break;
01255 case MLOG_ZIP_WRITE_NODE_PTR:
01256 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01257 ptr = page_zip_parse_write_node_ptr(ptr, end_ptr,
01258 page, page_zip);
01259 break;
01260 case MLOG_ZIP_WRITE_BLOB_PTR:
01261 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01262 ptr = page_zip_parse_write_blob_ptr(ptr, end_ptr,
01263 page, page_zip);
01264 break;
01265 case MLOG_ZIP_WRITE_HEADER:
01266 ut_ad(!page || page_type == FIL_PAGE_INDEX);
01267 ptr = page_zip_parse_write_header(ptr, end_ptr,
01268 page, page_zip);
01269 break;
01270 case MLOG_ZIP_PAGE_COMPRESS:
01271
01272 ptr = page_zip_parse_compress(ptr, end_ptr,
01273 page, page_zip);
01274 break;
01275 default:
01276 ptr = NULL;
01277 recv_sys->found_corrupt_log = TRUE;
01278 }
01279
01280 if (index) {
01281 dict_table_t* table = index->table;
01282
01283 dict_mem_index_free(index);
01284 dict_mem_table_free(table);
01285 }
01286
01287 return(ptr);
01288 }
01289
01290
01294 UNIV_INLINE
01295 ulint
01296 recv_fold(
01297
01298 ulint space,
01299 ulint page_no)
01300 {
01301 return(ut_fold_ulint_pair(space, page_no));
01302 }
01303
01304
01308 UNIV_INLINE
01309 ulint
01310 recv_hash(
01311
01312 ulint space,
01313 ulint page_no)
01314 {
01315 return(hash_calc_hash(recv_fold(space, page_no), recv_sys->addr_hash));
01316 }
01317
01318
01321 static
01322 recv_addr_t*
01323 recv_get_fil_addr_struct(
01324
01325 ulint space,
01326 ulint page_no)
01327 {
01328 recv_addr_t* recv_addr;
01329
01330 recv_addr = static_cast<recv_addr_t *>(HASH_GET_FIRST(recv_sys->addr_hash,
01331 recv_hash(space, page_no)));
01332 while (recv_addr) {
01333 if ((recv_addr->space == space)
01334 && (recv_addr->page_no == page_no)) {
01335
01336 break;
01337 }
01338
01339 recv_addr = static_cast<recv_addr_t *>(HASH_GET_NEXT(addr_hash, recv_addr));
01340 }
01341
01342 return(recv_addr);
01343 }
01344
01345
01347 static
01348 void
01349 recv_add_to_hash_table(
01350
01351 byte type,
01352 ulint space,
01353 ulint page_no,
01354 byte* body,
01355 byte* rec_end,
01356 ib_uint64_t start_lsn,
01357 ib_uint64_t end_lsn)
01358 {
01359 recv_t* recv;
01360 ulint len;
01361 recv_data_t* recv_data;
01362 recv_data_t** prev_field;
01363 recv_addr_t* recv_addr;
01364
01365 if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
01366
01367
01368
01369 return;
01370 }
01371
01372 len = rec_end - body;
01373
01374 recv = static_cast<recv_t *>(mem_heap_alloc(recv_sys->heap, sizeof(recv_t)));
01375 recv->type = type;
01376 recv->len = rec_end - body;
01377 recv->start_lsn = start_lsn;
01378 recv->end_lsn = end_lsn;
01379
01380 recv_addr = recv_get_fil_addr_struct(space, page_no);
01381
01382 if (recv_addr == NULL) {
01383 recv_addr = static_cast<recv_addr_t *>(mem_heap_alloc(recv_sys->heap,
01384 sizeof(recv_addr_t)));
01385 recv_addr->space = space;
01386 recv_addr->page_no = page_no;
01387 recv_addr->state = RECV_NOT_PROCESSED;
01388
01389 UT_LIST_INIT(recv_addr->rec_list);
01390
01391 HASH_INSERT(recv_addr_t, addr_hash, recv_sys->addr_hash,
01392 recv_fold(space, page_no), recv_addr);
01393 recv_sys->n_addrs++;
01394 #if 0
01395 fprintf(stderr, "Inserting log rec for space %lu, page %lu\n",
01396 space, page_no);
01397 #endif
01398 }
01399
01400 UT_LIST_ADD_LAST(rec_list, recv_addr->rec_list, recv);
01401
01402 prev_field = &(recv->data);
01403
01404
01405
01406
01407
01408 while (rec_end > body) {
01409
01410 len = rec_end - body;
01411
01412 if (len > RECV_DATA_BLOCK_SIZE) {
01413 len = RECV_DATA_BLOCK_SIZE;
01414 }
01415
01416 recv_data = static_cast<recv_data_t *>(mem_heap_alloc(recv_sys->heap,
01417 sizeof(recv_data_t) + len));
01418 *prev_field = recv_data;
01419
01420 memcpy(recv_data + 1, body, len);
01421
01422 prev_field = &(recv_data->next);
01423
01424 body += len;
01425 }
01426
01427 *prev_field = NULL;
01428 }
01429
01430
01432 static
01433 void
01434 recv_data_copy_to_buf(
01435
01436 byte* buf,
01437 recv_t* recv)
01438 {
01439 recv_data_t* recv_data;
01440 ulint part_len;
01441 ulint len;
01442
01443 len = recv->len;
01444 recv_data = recv->data;
01445
01446 while (len > 0) {
01447 if (len > RECV_DATA_BLOCK_SIZE) {
01448 part_len = RECV_DATA_BLOCK_SIZE;
01449 } else {
01450 part_len = len;
01451 }
01452
01453 ut_memcpy(buf, ((byte*)recv_data) + sizeof(recv_data_t),
01454 part_len);
01455 buf += part_len;
01456 len -= part_len;
01457
01458 recv_data = recv_data->next;
01459 }
01460 }
01461
01462
01466 UNIV_INTERN
01467 void
01468 recv_recover_page_func(
01469
01470 #ifndef UNIV_HOTBACKUP
01471 ibool just_read_in,
01474 #endif
01475 buf_block_t* block)
01476 {
01477 page_t* page;
01478 page_zip_des_t* page_zip;
01479 recv_addr_t* recv_addr;
01480 recv_t* recv;
01481 byte* buf;
01482 ib_uint64_t start_lsn;
01483 ib_uint64_t end_lsn;
01484 ib_uint64_t page_lsn;
01485 ib_uint64_t page_newest_lsn;
01486 ibool modification_to_page;
01487 #ifndef UNIV_HOTBACKUP
01488 ibool success;
01489 #endif
01490 mtr_t mtr;
01491
01492 mutex_enter(&(recv_sys->mutex));
01493
01494 if (recv_sys->apply_log_recs == FALSE) {
01495
01496
01497
01498 mutex_exit(&(recv_sys->mutex));
01499
01500 return;
01501 }
01502
01503 recv_addr = recv_get_fil_addr_struct(buf_block_get_space(block),
01504 buf_block_get_page_no(block));
01505
01506 if ((recv_addr == NULL)
01507 || (recv_addr->state == RECV_BEING_PROCESSED)
01508 || (recv_addr->state == RECV_PROCESSED)) {
01509
01510 mutex_exit(&(recv_sys->mutex));
01511
01512 return;
01513 }
01514
01515 #if 0
01516 fprintf(stderr, "Recovering space %lu, page %lu\n",
01517 buf_block_get_space(block), buf_block_get_page_no(block));
01518 #endif
01519
01520 recv_addr->state = RECV_BEING_PROCESSED;
01521
01522 mutex_exit(&(recv_sys->mutex));
01523
01524 mtr_start(&mtr);
01525 mtr_set_log_mode(&mtr, MTR_LOG_NONE);
01526
01527 page = block->frame;
01528 page_zip = buf_block_get_page_zip(block);
01529
01530 #ifndef UNIV_HOTBACKUP
01531 if (just_read_in) {
01532
01533
01534
01535
01536
01537 rw_lock_x_lock_move_ownership(&block->lock);
01538 }
01539
01540 success = buf_page_get_known_nowait(RW_X_LATCH, block,
01541 BUF_KEEP_OLD,
01542 __FILE__, __LINE__,
01543 &mtr);
01544 ut_a(success);
01545
01546 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
01547 #endif
01548
01549
01550 page_lsn = mach_read_from_8(page + FIL_PAGE_LSN);
01551
01552 #ifndef UNIV_HOTBACKUP
01553
01554
01555
01556 page_newest_lsn = buf_page_get_newest_modification(&block->page);
01557
01558 if (page_newest_lsn) {
01559
01560 page_lsn = page_newest_lsn;
01561 }
01562 #else
01563
01564 page_newest_lsn = 0;
01565 #endif
01566
01567 modification_to_page = FALSE;
01568 start_lsn = end_lsn = 0;
01569
01570 recv = UT_LIST_GET_FIRST(recv_addr->rec_list);
01571
01572 while (recv) {
01573 end_lsn = recv->end_lsn;
01574
01575 if (recv->len > RECV_DATA_BLOCK_SIZE) {
01576
01577
01578
01579 buf = static_cast<byte *>(mem_alloc(recv->len));
01580
01581 recv_data_copy_to_buf(buf, recv);
01582 } else {
01583 buf = ((byte*)(recv->data)) + sizeof(recv_data_t);
01584 }
01585
01586 if (recv->type == MLOG_INIT_FILE_PAGE) {
01587 page_lsn = page_newest_lsn;
01588
01589 memset(FIL_PAGE_LSN + page, 0, 8);
01590 memset(UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM
01591 + page, 0, 8);
01592
01593 if (page_zip) {
01594 memset(FIL_PAGE_LSN + page_zip->data, 0, 8);
01595 }
01596 }
01597
01598 if (recv->start_lsn >= page_lsn) {
01599
01600 ib_uint64_t page_end_lsn;
01601
01602 if (!modification_to_page) {
01603
01604 modification_to_page = TRUE;
01605 start_lsn = recv->start_lsn;
01606 }
01607
01608 #ifdef UNIV_DEBUG
01609 if (log_debug_writes) {
01610 fprintf(stderr,
01611 "InnoDB: Applying log rec"
01612 " type %lu len %lu"
01613 " to space %lu page no %lu\n",
01614 (ulong) recv->type, (ulong) recv->len,
01615 (ulong) recv_addr->space,
01616 (ulong) recv_addr->page_no);
01617 }
01618 #endif
01619
01620 recv_parse_or_apply_log_rec_body(recv->type, buf,
01621 buf + recv->len,
01622 block, &mtr);
01623
01624 page_end_lsn = recv->start_lsn + recv->len;
01625 mach_write_to_8(FIL_PAGE_LSN + page, page_end_lsn);
01626 mach_write_to_8(UNIV_PAGE_SIZE
01627 - FIL_PAGE_END_LSN_OLD_CHKSUM
01628 + page, page_end_lsn);
01629
01630 if (page_zip) {
01631 mach_write_to_8(FIL_PAGE_LSN
01632 + page_zip->data, page_end_lsn);
01633 }
01634 }
01635
01636 if (recv->len > RECV_DATA_BLOCK_SIZE) {
01637 mem_free(buf);
01638 }
01639
01640 recv = UT_LIST_GET_NEXT(rec_list, recv);
01641 }
01642
01643 #ifdef UNIV_ZIP_DEBUG
01644 if (fil_page_get_type(page) == FIL_PAGE_INDEX) {
01645 page_zip_des_t* page_zip = buf_block_get_page_zip(block);
01646
01647 if (page_zip) {
01648 ut_a(page_zip_validate_low(page_zip, page, FALSE));
01649 }
01650 }
01651 #endif
01652
01653 mutex_enter(&(recv_sys->mutex));
01654
01655 if (recv_max_page_lsn < page_lsn) {
01656 recv_max_page_lsn = page_lsn;
01657 }
01658
01659 recv_addr->state = RECV_PROCESSED;
01660
01661 ut_a(recv_sys->n_addrs);
01662 recv_sys->n_addrs--;
01663
01664 mutex_exit(&(recv_sys->mutex));
01665
01666 #ifndef UNIV_HOTBACKUP
01667 if (modification_to_page) {
01668 ut_a(block);
01669
01670 log_flush_order_mutex_enter();
01671 buf_flush_recv_note_modification(block, start_lsn, end_lsn);
01672 log_flush_order_mutex_exit();
01673 }
01674 #endif
01675
01676
01677
01678
01679 mtr.modifications = FALSE;
01680
01681 mtr_commit(&mtr);
01682 }
01683
01684 #ifndef UNIV_HOTBACKUP
01685
01689 static
01690 ulint
01691 recv_read_in_area(
01692
01693 ulint space,
01694 ulint zip_size,
01695 ulint page_no)
01696 {
01697 recv_addr_t* recv_addr;
01698 ulint page_nos[RECV_READ_AHEAD_AREA];
01699 ulint low_limit;
01700 ulint n;
01701
01702 low_limit = page_no - (page_no % RECV_READ_AHEAD_AREA);
01703
01704 n = 0;
01705
01706 for (page_no = low_limit; page_no < low_limit + RECV_READ_AHEAD_AREA;
01707 page_no++) {
01708 recv_addr = recv_get_fil_addr_struct(space, page_no);
01709
01710 if (recv_addr && !buf_page_peek(space, page_no)) {
01711
01712 mutex_enter(&(recv_sys->mutex));
01713
01714 if (recv_addr->state == RECV_NOT_PROCESSED) {
01715 recv_addr->state = RECV_BEING_READ;
01716
01717 page_nos[n] = page_no;
01718
01719 n++;
01720 }
01721
01722 mutex_exit(&(recv_sys->mutex));
01723 }
01724 }
01725
01726 buf_read_recv_pages(FALSE, space, zip_size, page_nos, n);
01727
01728
01729
01730 return(n);
01731 }
01732
01733
01736 UNIV_INTERN
01737 void
01738 recv_apply_hashed_log_recs(
01739
01740 ibool allow_ibuf)
01749 {
01750 recv_addr_t* recv_addr;
01751 ulint i;
01752 ulint n_pages;
01753 ibool has_printed = FALSE;
01754 mtr_t mtr;
01755 loop:
01756 mutex_enter(&(recv_sys->mutex));
01757
01758 if (recv_sys->apply_batch_on) {
01759
01760 mutex_exit(&(recv_sys->mutex));
01761
01762 os_thread_sleep(500000);
01763
01764 goto loop;
01765 }
01766
01767 ut_ad(!allow_ibuf == mutex_own(&log_sys->mutex));
01768
01769 if (!allow_ibuf) {
01770 recv_no_ibuf_operations = TRUE;
01771 }
01772
01773 recv_sys->apply_log_recs = TRUE;
01774 recv_sys->apply_batch_on = TRUE;
01775
01776 for (i = 0; i < hash_get_n_cells(recv_sys->addr_hash); i++) {
01777
01778 recv_addr = static_cast<recv_addr_t *>(HASH_GET_FIRST(recv_sys->addr_hash, i));
01779
01780 while (recv_addr) {
01781 ulint space = recv_addr->space;
01782 ulint zip_size = fil_space_get_zip_size(space);
01783 ulint page_no = recv_addr->page_no;
01784
01785 if (recv_addr->state == RECV_NOT_PROCESSED) {
01786 if (!has_printed) {
01787 ut_print_timestamp(stderr);
01788 fputs(" InnoDB: Starting an"
01789 " apply batch of log records"
01790 " to the database...\n"
01791 "InnoDB: Progress in percents: ",
01792 stderr);
01793 has_printed = TRUE;
01794 }
01795
01796 mutex_exit(&(recv_sys->mutex));
01797
01798 if (buf_page_peek(space, page_no)) {
01799 buf_block_t* block;
01800
01801 mtr_start(&mtr);
01802
01803 block = buf_page_get(
01804 space, zip_size, page_no,
01805 RW_X_LATCH, &mtr);
01806 buf_block_dbg_add_level(
01807 block, SYNC_NO_ORDER_CHECK);
01808
01809 recv_recover_page(FALSE, block);
01810 mtr_commit(&mtr);
01811 } else {
01812 recv_read_in_area(space, zip_size,
01813 page_no);
01814 }
01815
01816 mutex_enter(&(recv_sys->mutex));
01817 }
01818
01819 recv_addr = static_cast<recv_addr_t *>(HASH_GET_NEXT(addr_hash, recv_addr));
01820 }
01821
01822 if (has_printed
01823 && (i * 100) / hash_get_n_cells(recv_sys->addr_hash)
01824 != ((i + 1) * 100)
01825 / hash_get_n_cells(recv_sys->addr_hash)) {
01826
01827 fprintf(stderr, "%lu ", (ulong)
01828 ((i * 100)
01829 / hash_get_n_cells(recv_sys->addr_hash)));
01830 }
01831 }
01832
01833
01834
01835 while (recv_sys->n_addrs != 0) {
01836
01837 mutex_exit(&(recv_sys->mutex));
01838
01839 os_thread_sleep(500000);
01840
01841 mutex_enter(&(recv_sys->mutex));
01842 }
01843
01844 if (has_printed) {
01845
01846 fprintf(stderr, "\n");
01847 }
01848
01849 if (!allow_ibuf) {
01850
01851
01852
01853 ut_d(recv_no_log_write = TRUE);
01854 mutex_exit(&(recv_sys->mutex));
01855 mutex_exit(&(log_sys->mutex));
01856
01857 n_pages = buf_flush_list(ULINT_MAX, IB_ULONGLONG_MAX);
01858 ut_a(n_pages != ULINT_UNDEFINED);
01859
01860 buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
01861
01862 buf_pool_invalidate();
01863
01864 mutex_enter(&(log_sys->mutex));
01865 mutex_enter(&(recv_sys->mutex));
01866 ut_d(recv_no_log_write = FALSE);
01867
01868 recv_no_ibuf_operations = FALSE;
01869 }
01870
01871 recv_sys->apply_log_recs = FALSE;
01872 recv_sys->apply_batch_on = FALSE;
01873
01874 recv_sys_empty_hash();
01875
01876 if (has_printed) {
01877 fprintf(stderr, "InnoDB: Apply batch completed\n");
01878 }
01879
01880 mutex_exit(&(recv_sys->mutex));
01881 }
01882 #else
01883
01885 UNIV_INTERN
01886 void
01887 recv_apply_log_recs_for_backup(void)
01888
01889 {
01890 recv_addr_t* recv_addr;
01891 ulint n_hash_cells;
01892 buf_block_t* block;
01893 ulint actual_size;
01894 ibool success;
01895 ulint error;
01896 ulint i;
01897
01898 recv_sys->apply_log_recs = TRUE;
01899 recv_sys->apply_batch_on = TRUE;
01900
01901 block = back_block1;
01902
01903 fputs("InnoDB: Starting an apply batch of log records"
01904 " to the database...\n"
01905 "InnoDB: Progress in percents: ", stderr);
01906
01907 n_hash_cells = hash_get_n_cells(recv_sys->addr_hash);
01908
01909 for (i = 0; i < n_hash_cells; i++) {
01910
01911 recv_addr = hash_get_nth_cell(recv_sys->addr_hash, i)->node;
01912
01913 while (recv_addr != NULL) {
01914
01915 ulint zip_size
01916 = fil_space_get_zip_size(recv_addr->space);
01917
01918 if (zip_size == ULINT_UNDEFINED) {
01919 #if 0
01920 fprintf(stderr,
01921 "InnoDB: Warning: cannot apply"
01922 " log record to"
01923 " tablespace %lu page %lu,\n"
01924 "InnoDB: because tablespace with"
01925 " that id does not exist.\n",
01926 recv_addr->space, recv_addr->page_no);
01927 #endif
01928 recv_addr->state = RECV_PROCESSED;
01929
01930 ut_a(recv_sys->n_addrs);
01931 recv_sys->n_addrs--;
01932
01933 goto skip_this_recv_addr;
01934 }
01935
01936
01937
01938
01939
01940 buf_page_init_for_backup_restore(
01941 recv_addr->space, recv_addr->page_no,
01942 zip_size, block);
01943
01944
01945
01946
01947
01948
01949 success = fil_extend_space_to_desired_size(
01950 &actual_size,
01951 recv_addr->space, recv_addr->page_no + 1);
01952 if (!success) {
01953 fprintf(stderr,
01954 "InnoDB: Fatal error: cannot extend"
01955 " tablespace %lu to hold %lu pages\n",
01956 recv_addr->space, recv_addr->page_no);
01957
01958 exit(1);
01959 }
01960
01961
01962
01963
01964 if (zip_size) {
01965 error = fil_io(OS_FILE_READ, TRUE,
01966 recv_addr->space, zip_size,
01967 recv_addr->page_no, 0, zip_size,
01968 block->page.zip.data, NULL);
01969 if (error == DB_SUCCESS
01970 && !buf_zip_decompress(block, TRUE)) {
01971 exit(1);
01972 }
01973 } else {
01974 error = fil_io(OS_FILE_READ, TRUE,
01975 recv_addr->space, 0,
01976 recv_addr->page_no, 0,
01977 UNIV_PAGE_SIZE,
01978 block->frame, NULL);
01979 }
01980
01981 if (error != DB_SUCCESS) {
01982 fprintf(stderr,
01983 "InnoDB: Fatal error: cannot read"
01984 " from tablespace"
01985 " %lu page number %lu\n",
01986 (ulong) recv_addr->space,
01987 (ulong) recv_addr->page_no);
01988
01989 exit(1);
01990 }
01991
01992
01993 recv_recover_page(FALSE, block);
01994
01995
01996
01997
01998 buf_flush_init_for_writing(
01999 block->frame, buf_block_get_page_zip(block),
02000 mach_read_from_8(block->frame + FIL_PAGE_LSN));
02001
02002 if (zip_size) {
02003 error = fil_io(OS_FILE_WRITE, TRUE,
02004 recv_addr->space, zip_size,
02005 recv_addr->page_no, 0,
02006 zip_size,
02007 block->page.zip.data, NULL);
02008 } else {
02009 error = fil_io(OS_FILE_WRITE, TRUE,
02010 recv_addr->space, 0,
02011 recv_addr->page_no, 0,
02012 UNIV_PAGE_SIZE,
02013 block->frame, NULL);
02014 }
02015 skip_this_recv_addr:
02016 recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
02017 }
02018
02019 if ((100 * i) / n_hash_cells
02020 != (100 * (i + 1)) / n_hash_cells) {
02021 fprintf(stderr, "%lu ",
02022 (ulong) ((100 * i) / n_hash_cells));
02023 fflush(stderr);
02024 }
02025 }
02026
02027 recv_sys_empty_hash();
02028 }
02029 #endif
02030
02031
02034 static
02035 ulint
02036 recv_parse_log_rec(
02037
02038 byte* ptr,
02039 byte* end_ptr,
02040 byte* type,
02041 ulint* space,
02042 ulint* page_no,
02043 byte** body)
02044 {
02045 byte* new_ptr;
02046
02047 *body = NULL;
02048
02049 if (ptr == end_ptr) {
02050
02051 return(0);
02052 }
02053
02054 if (*ptr == MLOG_MULTI_REC_END) {
02055
02056 *type = *ptr;
02057
02058 return(1);
02059 }
02060
02061 if (*ptr == MLOG_DUMMY_RECORD) {
02062 *type = *ptr;
02063
02064 *space = ULINT_UNDEFINED - 1;
02065
02066 return(1);
02067 }
02068
02069 new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space,
02070 page_no);
02071 *body = new_ptr;
02072
02073 if (UNIV_UNLIKELY(!new_ptr)) {
02074
02075 return(0);
02076 }
02077
02078 #ifdef UNIV_LOG_LSN_DEBUG
02079 if (*type == MLOG_LSN) {
02080 ib_uint64_t lsn = (ib_uint64_t) *space << 32 | *page_no;
02081 # ifdef UNIV_LOG_DEBUG
02082 ut_a(lsn == log_sys->old_lsn);
02083 # else
02084 ut_a(lsn == recv_sys->recovered_lsn);
02085 # endif
02086 }
02087 #endif
02088
02089 new_ptr = recv_parse_or_apply_log_rec_body(*type, new_ptr, end_ptr,
02090 NULL, NULL);
02091 if (UNIV_UNLIKELY(new_ptr == NULL)) {
02092
02093 return(0);
02094 }
02095
02096 if (*page_no > recv_max_parsed_page_no) {
02097 recv_max_parsed_page_no = *page_no;
02098 }
02099
02100 return(new_ptr - ptr);
02101 }
02102
02103
02105 static
02106 ib_uint64_t
02107 recv_calc_lsn_on_data_add(
02108
02109 ib_uint64_t lsn,
02110 ib_uint64_t len)
02112 {
02113 ulint frag_len;
02114 ulint lsn_len;
02115
02116 frag_len = (((ulint) lsn) % OS_FILE_LOG_BLOCK_SIZE)
02117 - LOG_BLOCK_HDR_SIZE;
02118 ut_ad(frag_len < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE
02119 - LOG_BLOCK_TRL_SIZE);
02120 lsn_len = (ulint) len;
02121 lsn_len += (lsn_len + frag_len)
02122 / (OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE
02123 - LOG_BLOCK_TRL_SIZE)
02124 * (LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE);
02125
02126 return(lsn + lsn_len);
02127 }
02128
02129 #ifdef UNIV_LOG_DEBUG
02130
02133 static
02134 void
02135 recv_check_incomplete_log_recs(
02136
02137 byte* ptr,
02138 ulint len)
02139 {
02140 ulint i;
02141 byte type;
02142 ulint space;
02143 ulint page_no;
02144 byte* body;
02145
02146 for (i = 0; i < len; i++) {
02147 ut_a(0 == recv_parse_log_rec(ptr, ptr + i, &type, &space,
02148 &page_no, &body));
02149 }
02150 }
02151 #endif
02152
02153
02155 static
02156 void
02157 recv_report_corrupt_log(
02158
02159 byte* ptr,
02160 byte type,
02161 ulint space,
02162 ulint page_no)
02163 {
02164 fprintf(stderr,
02165 "InnoDB: ############### CORRUPT LOG RECORD FOUND\n"
02166 "InnoDB: Log record type %lu, space id %lu, page number %lu\n"
02167 "InnoDB: Log parsing proceeded successfully up to %"PRIu64"\n"
02168 "InnoDB: Previous log record type %lu, is multi %lu\n"
02169 "InnoDB: Recv offset %lu, prev %lu\n",
02170 (ulong) type, (ulong) space, (ulong) page_no,
02171 recv_sys->recovered_lsn,
02172 (ulong) recv_previous_parsed_rec_type,
02173 (ulong) recv_previous_parsed_rec_is_multi,
02174 (ulong) (ptr - recv_sys->buf),
02175 (ulong) recv_previous_parsed_rec_offset);
02176
02177 if ((ulint)(ptr - recv_sys->buf + 100)
02178 > recv_previous_parsed_rec_offset
02179 && (ulint)(ptr - recv_sys->buf + 100
02180 - recv_previous_parsed_rec_offset)
02181 < 200000) {
02182 fputs("InnoDB: Hex dump of corrupt log starting"
02183 " 100 bytes before the start\n"
02184 "InnoDB: of the previous log rec,\n"
02185 "InnoDB: and ending 100 bytes after the start"
02186 " of the corrupt rec:\n",
02187 stderr);
02188
02189 ut_print_buf(stderr,
02190 recv_sys->buf
02191 + recv_previous_parsed_rec_offset - 100,
02192 ptr - recv_sys->buf + 200
02193 - recv_previous_parsed_rec_offset);
02194 putc('\n', stderr);
02195 }
02196
02197 #ifndef UNIV_HOTBACKUP
02198 if (!srv_force_recovery) {
02199 fputs("InnoDB: Set innodb_force_recovery"
02200 " to ignore this error.\n", stderr);
02201 ut_error;
02202 }
02203 #endif
02204
02205 fputs("InnoDB: WARNING: the log file may have been corrupt and it\n"
02206 "InnoDB: is possible that the log scan did not proceed\n"
02207 "InnoDB: far enough in recovery! Please run CHECK TABLE\n"
02208 "InnoDB: on your InnoDB tables to check that they are ok!\n"
02209 "InnoDB: If mysqld crashes after this recovery, look at\n"
02210 "InnoDB: " REFMAN "forcing-recovery.html\n"
02211 "InnoDB: about forcing recovery.\n", stderr);
02212
02213 fflush(stderr);
02214 }
02215
02216
02220 static
02221 ibool
02222 recv_parse_log_recs(
02223
02224 ibool store_to_hash)
02227 {
02228 byte* ptr;
02229 byte* end_ptr;
02230 ulint single_rec;
02231 ulint len;
02232 ulint total_len;
02233 ib_uint64_t new_recovered_lsn;
02234 ib_uint64_t old_lsn;
02235 byte type;
02236 ulint space;
02237 ulint page_no;
02238 byte* body;
02239 ulint n_recs;
02240
02241 ut_ad(mutex_own(&(log_sys->mutex)));
02242 ut_ad(recv_sys->parse_start_lsn != 0);
02243 loop:
02244 ptr = recv_sys->buf + recv_sys->recovered_offset;
02245
02246 end_ptr = recv_sys->buf + recv_sys->len;
02247
02248 if (ptr == end_ptr) {
02249
02250 return(FALSE);
02251 }
02252
02253 single_rec = (ulint)*ptr & MLOG_SINGLE_REC_FLAG;
02254
02255 if (single_rec || *ptr == MLOG_DUMMY_RECORD) {
02256
02257
02258 old_lsn = recv_sys->recovered_lsn;
02259
02260
02261
02262
02263 len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
02264 &page_no, &body);
02265
02266 if (len == 0 || recv_sys->found_corrupt_log) {
02267 if (recv_sys->found_corrupt_log) {
02268
02269 recv_report_corrupt_log(ptr,
02270 type, space, page_no);
02271 }
02272
02273 return(FALSE);
02274 }
02275
02276 new_recovered_lsn = recv_calc_lsn_on_data_add(old_lsn, len);
02277
02278 if (new_recovered_lsn > recv_sys->scanned_lsn) {
02279
02280
02281
02282
02283 return(FALSE);
02284 }
02285
02286 recv_previous_parsed_rec_type = (ulint)type;
02287 recv_previous_parsed_rec_offset = recv_sys->recovered_offset;
02288 recv_previous_parsed_rec_is_multi = 0;
02289
02290 recv_sys->recovered_offset += len;
02291 recv_sys->recovered_lsn = new_recovered_lsn;
02292
02293 #ifdef UNIV_DEBUG
02294 if (log_debug_writes) {
02295 fprintf(stderr,
02296 "InnoDB: Parsed a single log rec"
02297 " type %lu len %lu space %lu page no %lu\n",
02298 (ulong) type, (ulong) len, (ulong) space,
02299 (ulong) page_no);
02300 }
02301 #endif
02302
02303 if (type == MLOG_DUMMY_RECORD) {
02304
02305
02306 } else if (!store_to_hash) {
02307
02308
02309
02310 #ifdef UNIV_LOG_DEBUG
02311 recv_check_incomplete_log_recs(ptr, len);
02312 #endif
02313
02314 } else if (type == MLOG_FILE_CREATE
02315 || type == MLOG_FILE_CREATE2
02316 || type == MLOG_FILE_RENAME
02317 || type == MLOG_FILE_DELETE) {
02318 ut_a(space);
02319 #ifdef UNIV_HOTBACKUP
02320 if (recv_replay_file_ops) {
02321
02322
02323
02324
02325
02326
02327 if (NULL == fil_op_log_parse_or_replay(
02328 body, end_ptr, type,
02329 space, page_no)) {
02330 fprintf(stderr,
02331 "InnoDB: Error: file op"
02332 " log record of type %lu"
02333 " space %lu not complete in\n"
02334 "InnoDB: the replay phase."
02335 " Path %s\n",
02336 (ulint)type, space,
02337 (char*)(body + 2));
02338
02339 ut_error;
02340 }
02341 }
02342 #endif
02343
02344
02345 #ifdef UNIV_LOG_LSN_DEBUG
02346 } else if (type == MLOG_LSN) {
02347
02348
02349
02350 #endif
02351 } else {
02352 recv_add_to_hash_table(type, space, page_no, body,
02353 ptr + len, old_lsn,
02354 recv_sys->recovered_lsn);
02355 }
02356 } else {
02357
02358
02359
02360 total_len = 0;
02361 n_recs = 0;
02362
02363 for (;;) {
02364 len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
02365 &page_no, &body);
02366 if (len == 0 || recv_sys->found_corrupt_log) {
02367
02368 if (recv_sys->found_corrupt_log) {
02369
02370 recv_report_corrupt_log(
02371 ptr, type, space, page_no);
02372 }
02373
02374 return(FALSE);
02375 }
02376
02377 recv_previous_parsed_rec_type = (ulint)type;
02378 recv_previous_parsed_rec_offset
02379 = recv_sys->recovered_offset + total_len;
02380 recv_previous_parsed_rec_is_multi = 1;
02381
02382 #ifdef UNIV_LOG_DEBUG
02383 if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) {
02384 recv_check_incomplete_log_recs(ptr, len);
02385 }
02386 #endif
02387
02388 #ifdef UNIV_DEBUG
02389 if (log_debug_writes) {
02390 fprintf(stderr,
02391 "InnoDB: Parsed a multi log rec"
02392 " type %lu len %lu"
02393 " space %lu page no %lu\n",
02394 (ulong) type, (ulong) len,
02395 (ulong) space, (ulong) page_no);
02396 }
02397 #endif
02398
02399 total_len += len;
02400 n_recs++;
02401
02402 ptr += len;
02403
02404 if (type == MLOG_MULTI_REC_END) {
02405
02406
02407
02408 break;
02409 }
02410 }
02411
02412 new_recovered_lsn = recv_calc_lsn_on_data_add(
02413 recv_sys->recovered_lsn, total_len);
02414
02415 if (new_recovered_lsn > recv_sys->scanned_lsn) {
02416
02417
02418
02419
02420 return(FALSE);
02421 }
02422
02423
02424
02425 ptr = recv_sys->buf + recv_sys->recovered_offset;
02426
02427 for (;;) {
02428 old_lsn = recv_sys->recovered_lsn;
02429 len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
02430 &page_no, &body);
02431 if (recv_sys->found_corrupt_log) {
02432
02433 recv_report_corrupt_log(ptr,
02434 type, space, page_no);
02435 }
02436
02437 ut_a(len != 0);
02438 ut_a(0 == ((ulint)*ptr & MLOG_SINGLE_REC_FLAG));
02439
02440 recv_sys->recovered_offset += len;
02441 recv_sys->recovered_lsn
02442 = recv_calc_lsn_on_data_add(old_lsn, len);
02443 if (type == MLOG_MULTI_REC_END) {
02444
02445
02446
02447 break;
02448 }
02449
02450 if (store_to_hash
02451 #ifdef UNIV_LOG_LSN_DEBUG
02452 && type != MLOG_LSN
02453 #endif
02454 ) {
02455 recv_add_to_hash_table(type, space, page_no,
02456 body, ptr + len,
02457 old_lsn,
02458 new_recovered_lsn);
02459 }
02460
02461 ptr += len;
02462 }
02463 }
02464
02465 goto loop;
02466 }
02467
02468
02472 static
02473 ibool
02474 recv_sys_add_to_parsing_buf(
02475
02476 const byte* log_block,
02477 ib_uint64_t scanned_lsn)
02479 {
02480 ulint more_len;
02481 ulint data_len;
02482 ulint start_offset;
02483 ulint end_offset;
02484
02485 ut_ad(scanned_lsn >= recv_sys->scanned_lsn);
02486
02487 if (!recv_sys->parse_start_lsn) {
02488
02489
02490
02491 return(FALSE);
02492 }
02493
02494 data_len = log_block_get_data_len(log_block);
02495
02496 if (recv_sys->parse_start_lsn >= scanned_lsn) {
02497
02498 return(FALSE);
02499
02500 } else if (recv_sys->scanned_lsn >= scanned_lsn) {
02501
02502 return(FALSE);
02503
02504 } else if (recv_sys->parse_start_lsn > recv_sys->scanned_lsn) {
02505 more_len = (ulint) (scanned_lsn - recv_sys->parse_start_lsn);
02506 } else {
02507 more_len = (ulint) (scanned_lsn - recv_sys->scanned_lsn);
02508 }
02509
02510 if (more_len == 0) {
02511
02512 return(FALSE);
02513 }
02514
02515 ut_ad(data_len >= more_len);
02516
02517 start_offset = data_len - more_len;
02518
02519 if (start_offset < LOG_BLOCK_HDR_SIZE) {
02520 start_offset = LOG_BLOCK_HDR_SIZE;
02521 }
02522
02523 end_offset = data_len;
02524
02525 if (end_offset > OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
02526 end_offset = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE;
02527 }
02528
02529 ut_ad(start_offset <= end_offset);
02530
02531 if (start_offset < end_offset) {
02532 ut_memcpy(recv_sys->buf + recv_sys->len,
02533 log_block + start_offset, end_offset - start_offset);
02534
02535 recv_sys->len += end_offset - start_offset;
02536
02537 ut_a(recv_sys->len <= RECV_PARSING_BUF_SIZE);
02538 }
02539
02540 return(TRUE);
02541 }
02542
02543
02545 static
02546 void
02547 recv_sys_justify_left_parsing_buf(void)
02548
02549 {
02550 ut_memmove(recv_sys->buf, recv_sys->buf + recv_sys->recovered_offset,
02551 recv_sys->len - recv_sys->recovered_offset);
02552
02553 recv_sys->len -= recv_sys->recovered_offset;
02554
02555 recv_sys->recovered_offset = 0;
02556 }
02557
02558
02565 UNIV_INTERN
02566 ibool
02567 recv_scan_log_recs(
02568
02569 ulint available_memory,
02571 ibool store_to_hash,
02575 const byte* buf,
02577 ulint len,
02578 ib_uint64_t start_lsn,
02579 ib_uint64_t* contiguous_lsn,
02582 ib_uint64_t* group_scanned_lsn)
02584 {
02585 const byte* log_block;
02586 ulint no;
02587 ib_uint64_t scanned_lsn;
02588 ibool finished;
02589 ulint data_len;
02590 ibool more_data;
02591
02592 ut_ad(start_lsn % OS_FILE_LOG_BLOCK_SIZE == 0);
02593 ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0);
02594 ut_ad(len >= OS_FILE_LOG_BLOCK_SIZE);
02595 ut_a(store_to_hash <= TRUE);
02596
02597 finished = FALSE;
02598
02599 log_block = buf;
02600 scanned_lsn = start_lsn;
02601 more_data = FALSE;
02602
02603 do {
02604 no = log_block_get_hdr_no(log_block);
02605
02606
02607
02608
02609
02610
02611 if (no != log_block_convert_lsn_to_no(scanned_lsn)
02612 || !log_block_checksum_is_ok_or_old_format(log_block)) {
02613
02614 if (no == log_block_convert_lsn_to_no(scanned_lsn)
02615 && !log_block_checksum_is_ok_or_old_format(
02616 log_block)) {
02617 fprintf(stderr,
02618 "InnoDB: Log block no %lu at"
02619 " lsn %"PRIu64" has\n"
02620 "InnoDB: ok header, but checksum field"
02621 " contains %lu, should be %lu\n",
02622 (ulong) no,
02623 scanned_lsn,
02624 (ulong) log_block_get_checksum(
02625 log_block),
02626 (ulong) log_block_calc_checksum(
02627 log_block));
02628 }
02629
02630
02631
02632 finished = TRUE;
02633
02634 break;
02635 }
02636
02637 if (log_block_get_flush_bit(log_block)) {
02638
02639
02640
02641
02642
02643
02644
02645 if (scanned_lsn > *contiguous_lsn) {
02646 *contiguous_lsn = scanned_lsn;
02647 }
02648 }
02649
02650 data_len = log_block_get_data_len(log_block);
02651
02652 if ((store_to_hash || (data_len == OS_FILE_LOG_BLOCK_SIZE))
02653 && scanned_lsn + data_len > recv_sys->scanned_lsn
02654 && (recv_sys->scanned_checkpoint_no > 0)
02655 && (log_block_get_checkpoint_no(log_block)
02656 < recv_sys->scanned_checkpoint_no)
02657 && (recv_sys->scanned_checkpoint_no
02658 - log_block_get_checkpoint_no(log_block)
02659 > 0x80000000UL)) {
02660
02661
02662
02663
02664 finished = TRUE;
02665 #ifdef UNIV_LOG_DEBUG
02666
02667
02668
02669 ut_error;
02670 #endif
02671 break;
02672 }
02673
02674 if (!recv_sys->parse_start_lsn
02675 && (log_block_get_first_rec_group(log_block) > 0)) {
02676
02677
02678
02679
02680 recv_sys->parse_start_lsn = scanned_lsn
02681 + log_block_get_first_rec_group(log_block);
02682 recv_sys->scanned_lsn = recv_sys->parse_start_lsn;
02683 recv_sys->recovered_lsn = recv_sys->parse_start_lsn;
02684 }
02685
02686 scanned_lsn += data_len;
02687
02688 if (scanned_lsn > recv_sys->scanned_lsn) {
02689
02690
02691
02692
02693
02694 #ifndef UNIV_HOTBACKUP
02695 if (recv_log_scan_is_startup_type
02696 && !recv_needed_recovery) {
02697
02698 fprintf(stderr,
02699 "InnoDB: Log scan progressed"
02700 " past the checkpoint lsn %"PRIu64"\n",
02701 recv_sys->scanned_lsn);
02702 recv_init_crash_recovery();
02703 }
02704 #endif
02705
02706
02707
02708
02709
02710 if (recv_sys->len + 4 * OS_FILE_LOG_BLOCK_SIZE
02711 >= RECV_PARSING_BUF_SIZE) {
02712 fprintf(stderr,
02713 "InnoDB: Error: log parsing"
02714 " buffer overflow."
02715 " Recovery may have failed!\n");
02716
02717 recv_sys->found_corrupt_log = TRUE;
02718
02719 #ifndef UNIV_HOTBACKUP
02720 if (!srv_force_recovery) {
02721 fputs("InnoDB: Set"
02722 " innodb_force_recovery"
02723 " to ignore this error.\n",
02724 stderr);
02725 ut_error;
02726 }
02727 #endif
02728
02729 } else if (!recv_sys->found_corrupt_log) {
02730 more_data = recv_sys_add_to_parsing_buf(
02731 log_block, scanned_lsn);
02732 }
02733
02734 recv_sys->scanned_lsn = scanned_lsn;
02735 recv_sys->scanned_checkpoint_no
02736 = log_block_get_checkpoint_no(log_block);
02737 }
02738
02739 if (data_len < OS_FILE_LOG_BLOCK_SIZE) {
02740
02741
02742 finished = TRUE;
02743 break;
02744 } else {
02745 log_block += OS_FILE_LOG_BLOCK_SIZE;
02746 }
02747 } while (log_block < buf + len && !finished);
02748
02749 *group_scanned_lsn = scanned_lsn;
02750
02751 if (recv_needed_recovery
02752 || (recv_is_from_backup && !recv_is_making_a_backup)) {
02753 recv_scan_print_counter++;
02754
02755 if (finished || (recv_scan_print_counter % 80 == 0)) {
02756
02757 drizzled::errmsg_printf(drizzled::error::INFO,
02758 "InnoDB: Doing recovery: scanned up to log sequence number %"PRIu64" ",
02759 *group_scanned_lsn);
02760 }
02761 }
02762
02763 if (more_data && !recv_sys->found_corrupt_log) {
02764
02765
02766 recv_parse_log_recs(store_to_hash);
02767
02768 #ifndef UNIV_HOTBACKUP
02769 if (store_to_hash
02770 && mem_heap_get_size(recv_sys->heap) > available_memory) {
02771
02772
02773
02774
02775
02776
02777
02778 recv_apply_hashed_log_recs(FALSE);
02779 }
02780 #endif
02781
02782 if (recv_sys->recovered_offset > RECV_PARSING_BUF_SIZE / 4) {
02783
02784
02785 recv_sys_justify_left_parsing_buf();
02786 }
02787 }
02788
02789 return(finished);
02790 }
02791
02792 #ifndef UNIV_HOTBACKUP
02793
02796 static
02797 void
02798 recv_group_scan_log_recs(
02799
02800 log_group_t* group,
02801 ib_uint64_t* contiguous_lsn,
02804 ib_uint64_t* group_scanned_lsn)
02806 {
02807 ibool finished;
02808 ib_uint64_t start_lsn;
02809 ib_uint64_t end_lsn;
02810
02811 finished = FALSE;
02812
02813 start_lsn = *contiguous_lsn;
02814
02815 while (!finished) {
02816 end_lsn = start_lsn + RECV_SCAN_SIZE;
02817
02818 log_group_read_log_seg(LOG_RECOVER, log_sys->buf,
02819 group, start_lsn, end_lsn);
02820
02821 finished = recv_scan_log_recs(
02822 (buf_pool_get_n_pages()
02823 - (recv_n_pool_free_frames * srv_buf_pool_instances))
02824 * UNIV_PAGE_SIZE,
02825 TRUE, log_sys->buf, RECV_SCAN_SIZE,
02826 start_lsn, contiguous_lsn, group_scanned_lsn);
02827 start_lsn = end_lsn;
02828 }
02829
02830 #ifdef UNIV_DEBUG
02831 if (log_debug_writes) {
02832 drizzled::errmsg_printf(drizzled::error::INFO,
02833 "InnoDB: Scanned group %lu up to log sequence number %"PRIu64" ", (ulong) group->id, *group_scanned_lsn);
02834 }
02835 #endif
02836 }
02837
02838
02841 static
02842 void
02843 recv_init_crash_recovery(void)
02844
02845 {
02846 ut_a(!recv_needed_recovery);
02847
02848 recv_needed_recovery = TRUE;
02849
02850 ut_print_timestamp(stderr);
02851
02852 fprintf(stderr,
02853 " InnoDB: Database was not"
02854 " shut down normally!\n"
02855 "InnoDB: Starting crash recovery.\n");
02856
02857 fprintf(stderr,
02858 "InnoDB: Reading tablespace information"
02859 " from the .ibd files...\n");
02860
02861 fil_load_single_table_tablespaces();
02862
02863
02864
02865
02866
02867
02868 if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
02869
02870 fprintf(stderr,
02871 "InnoDB: Restoring possible"
02872 " half-written data pages from"
02873 " the doublewrite\n"
02874 "InnoDB: buffer...\n");
02875 trx_sys_doublewrite_init_or_restore_pages(TRUE);
02876 }
02877 }
02878
02879
02885 UNIV_INTERN
02886 ulint
02887 recv_recovery_from_checkpoint_start_func(
02888
02889 #ifdef UNIV_LOG_ARCHIVE
02890 ulint type,
02892 ib_uint64_t limit_lsn,
02894 #endif
02895 ib_uint64_t min_flushed_lsn,
02897 ib_uint64_t max_flushed_lsn)
02899 {
02900 log_group_t* group;
02901 log_group_t* max_cp_group;
02902 log_group_t* up_to_date_group;
02903 ulint max_cp_field;
02904 ulint log_hdr_log_block_size;
02905 ib_uint64_t checkpoint_lsn;
02906 ib_uint64_t checkpoint_no;
02907 ib_uint64_t old_scanned_lsn;
02908 ib_uint64_t group_scanned_lsn= 0;
02909 ib_uint64_t contiguous_lsn;
02910 #ifdef UNIV_LOG_ARCHIVE
02911 ib_uint64_t archived_lsn;
02912 #endif
02913 byte* buf;
02914 boost::scoped_array<byte> log_hdr_buf_base(
02915 new byte[LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE]);
02916 byte* log_hdr_buf
02917 = (byte *)ut_align(log_hdr_buf_base.get(), OS_FILE_LOG_BLOCK_SIZE);
02918 ulint err;
02919
02920 #ifdef UNIV_LOG_ARCHIVE
02921 ut_ad(type != LOG_CHECKPOINT || limit_lsn == IB_ULONGLONG_MAX);
02923 # define TYPE_CHECKPOINT (type == LOG_CHECKPOINT)
02924
02925 # define LIMIT_LSN limit_lsn
02926 #else
02927
02928 # define TYPE_CHECKPOINT 1
02929
02930 # define LIMIT_LSN IB_ULONGLONG_MAX
02931 #endif
02932
02933 if (TYPE_CHECKPOINT) {
02934 recv_sys_create();
02935 recv_sys_init(buf_pool_get_curr_size());
02936 }
02937
02938 if (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) {
02939 drizzled::errmsg_printf(drizzled::error::INFO,
02940 "InnoDB: The user has set SRV_FORCE_NO_LOG_REDO on Skipping log redo.");
02941
02942 return(DB_SUCCESS);
02943 }
02944
02945 recv_recovery_on = TRUE;
02946
02947 recv_sys->limit_lsn = LIMIT_LSN;
02948
02949 mutex_enter(&(log_sys->mutex));
02950
02951
02952
02953 err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
02954
02955 if (err != DB_SUCCESS) {
02956
02957 mutex_exit(&(log_sys->mutex));
02958
02959 return(err);
02960 }
02961
02962 log_group_read_checkpoint_info(max_cp_group, max_cp_field);
02963
02964 buf = log_sys->checkpoint_buf;
02965
02966 checkpoint_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_LSN);
02967 checkpoint_no = mach_read_from_8(buf + LOG_CHECKPOINT_NO);
02968 #ifdef UNIV_LOG_ARCHIVE
02969 archived_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN);
02970 #endif
02971
02972
02973
02974
02975 fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, max_cp_group->space_id, 0,
02976 0, 0, LOG_FILE_HDR_SIZE,
02977 log_hdr_buf, max_cp_group);
02978
02979 if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
02980 (byte*)"ibbackup", (sizeof "ibbackup") - 1)) {
02981
02982
02983
02984 drizzled::errmsg_printf(drizzled::error::INFO,
02985 "InnoDB: The log file was created by ibbackup --apply-log at %s\n",
02986 log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP);
02987 drizzled::errmsg_printf(drizzled::error::INFO,
02988 "InnoDB: NOTE: the following crash recovery is part of a normal restore.\n");
02989
02990
02991
02992 memset(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
02993 ' ', 4);
02994
02995 fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE,
02996 max_cp_group->space_id, 0,
02997 0, 0, OS_FILE_LOG_BLOCK_SIZE,
02998 log_hdr_buf, max_cp_group);
02999 }
03000
03001 log_hdr_log_block_size
03002 = mach_read_from_4(log_hdr_buf + LOG_FILE_OS_FILE_LOG_BLOCK_SIZE);
03003 if (log_hdr_log_block_size == 0) {
03004
03005 log_hdr_log_block_size = 512;
03006 }
03007 if (log_hdr_log_block_size != srv_log_block_size) {
03008 drizzled::errmsg_printf(drizzled::error::ERROR,
03009 "InnoDB: Error: The block size of ib_logfile (%lu) "
03010 "is not equal to innodb_log_block_size.\n"
03011 "InnoDB: Error: Suggestion - Recreate log files.\n",
03012 log_hdr_log_block_size);
03013 return(DB_ERROR);
03014 }
03015
03016 #ifdef UNIV_LOG_ARCHIVE
03017 group = UT_LIST_GET_FIRST(log_sys->log_groups);
03018
03019 while (group) {
03020 log_checkpoint_get_nth_group_info(buf, group->id,
03021 &(group->archived_file_no),
03022 &(group->archived_offset));
03023
03024 group = UT_LIST_GET_NEXT(log_groups, group);
03025 }
03026 #endif
03027
03028 if (TYPE_CHECKPOINT) {
03029
03030
03031
03032
03033 recv_sys->parse_start_lsn = checkpoint_lsn;
03034 recv_sys->scanned_lsn = checkpoint_lsn;
03035 recv_sys->scanned_checkpoint_no = 0;
03036 recv_sys->recovered_lsn = checkpoint_lsn;
03037
03038 srv_start_lsn = checkpoint_lsn;
03039 }
03040
03041 contiguous_lsn = ut_uint64_align_down(recv_sys->scanned_lsn,
03042 OS_FILE_LOG_BLOCK_SIZE);
03043 if (TYPE_CHECKPOINT) {
03044 up_to_date_group = max_cp_group;
03045 #ifdef UNIV_LOG_ARCHIVE
03046 } else {
03047 ulint capacity;
03048
03049
03050
03051
03052 group = recv_sys->archive_group;
03053 capacity = log_group_get_capacity(group);
03054
03055 if (recv_sys->scanned_lsn > checkpoint_lsn + capacity
03056 || checkpoint_lsn > recv_sys->scanned_lsn + capacity) {
03057
03058 mutex_exit(&(log_sys->mutex));
03059
03060
03061
03062
03063 return(DB_ERROR);
03064 }
03065
03066 recv_group_scan_log_recs(group, &contiguous_lsn,
03067 &group_scanned_lsn);
03068 if (recv_sys->scanned_lsn < checkpoint_lsn) {
03069
03070 mutex_exit(&(log_sys->mutex));
03071
03072
03073
03074
03075
03076 return(DB_ERROR);
03077 }
03078
03079 group->scanned_lsn = group_scanned_lsn;
03080 up_to_date_group = group;
03081 #endif
03082 }
03083
03084 ut_ad(RECV_SCAN_SIZE <= log_sys->buf_size);
03085
03086 group = UT_LIST_GET_FIRST(log_sys->log_groups);
03087
03088 #ifdef UNIV_LOG_ARCHIVE
03089 if ((type == LOG_ARCHIVE) && (group == recv_sys->archive_group)) {
03090 group = UT_LIST_GET_NEXT(log_groups, group);
03091 }
03092 #endif
03093
03094
03095 recv_log_scan_is_startup_type = TYPE_CHECKPOINT;
03096 while (group) {
03097 old_scanned_lsn = recv_sys->scanned_lsn;
03098
03099 recv_group_scan_log_recs(group, &contiguous_lsn,
03100 &group_scanned_lsn);
03101 group->scanned_lsn = group_scanned_lsn;
03102
03103 if (old_scanned_lsn < group_scanned_lsn) {
03104
03105
03106 up_to_date_group = group;
03107 }
03108
03109 #ifdef UNIV_LOG_ARCHIVE
03110 if ((type == LOG_ARCHIVE)
03111 && (group == recv_sys->archive_group)) {
03112 group = UT_LIST_GET_NEXT(log_groups, group);
03113 }
03114 #endif
03115
03116 group = UT_LIST_GET_NEXT(log_groups, group);
03117 }
03118
03119
03120 recv_log_scan_is_startup_type = FALSE;
03121 if (TYPE_CHECKPOINT) {
03122
03123
03124
03125
03126 if (checkpoint_lsn != max_flushed_lsn
03127 || checkpoint_lsn != min_flushed_lsn) {
03128
03129 if (checkpoint_lsn < max_flushed_lsn) {
03130 drizzled::errmsg_printf(drizzled::error::ERROR,
03131 "InnoDB: #########################"
03132 "#################################\n"
03133 "InnoDB: "
03134 "WARNING!\n"
03135 "InnoDB: The log sequence number"
03136 " in ibdata files is higher\n"
03137 "InnoDB: than the log sequence number"
03138 " in the ib_logfiles! Are you sure\n"
03139 "InnoDB: you are using the right"
03140 " ib_logfiles to start up"
03141 " the database?\n"
03142 "InnoDB: Log sequence number in"
03143 " ib_logfiles is %"PRIu64", log\n"
03144 "InnoDB: sequence numbers stamped"
03145 " to ibdata file headers are between\n"
03146 "InnoDB: %"PRIu64" and %"PRIu64".\n"
03147 "InnoDB: #########################"
03148 "#################################\n",
03149 checkpoint_lsn,
03150 min_flushed_lsn,
03151 max_flushed_lsn);
03152 }
03153
03154 if (not recv_needed_recovery) {
03155 drizzled::errmsg_printf(drizzled::error::ERROR,
03156 "InnoDB: The log sequence number in ibdata files does not match the log sequence number in the ib_logfiles!");
03157 recv_init_crash_recovery();
03158 }
03159 }
03160
03161 if (!recv_needed_recovery) {
03162
03163 trx_sys_doublewrite_init_or_restore_pages(FALSE);
03164 }
03165 }
03166
03167
03168 if (group_scanned_lsn < checkpoint_lsn) {
03169 drizzled::errmsg_printf(drizzled::error::ERROR,
03170 "InnoDB: ERROR: We were only able to scan the log up to %"PRIu64", but a checkpoint was at %"PRIu64". "
03171 "It is possible that the database is now corrupt!",
03172 group_scanned_lsn,
03173 checkpoint_lsn);
03174 }
03175
03176 if (group_scanned_lsn < recv_max_page_lsn) {
03177 drizzled::errmsg_printf(drizzled::error::ERROR,
03178 "InnoDB: ERROR: We were only able to scan the log up to %"PRIu64" "
03179 " but a database page a had an lsn %"PRIu64". It is possible that the database is now corrupt!",
03180 group_scanned_lsn,
03181 recv_max_page_lsn);
03182 }
03183
03184 if (recv_sys->recovered_lsn < checkpoint_lsn) {
03185
03186 mutex_exit(&(log_sys->mutex));
03187
03188 if (recv_sys->recovered_lsn >= LIMIT_LSN) {
03189
03190 return(DB_SUCCESS);
03191 }
03192
03193 ut_error;
03194
03195 return(DB_ERROR);
03196 }
03197
03198
03199
03200
03201 log_sys->next_checkpoint_lsn = checkpoint_lsn;
03202 log_sys->next_checkpoint_no = checkpoint_no + 1;
03203
03204 #ifdef UNIV_LOG_ARCHIVE
03205 log_sys->archived_lsn = archived_lsn;
03206 #endif
03207
03208 recv_synchronize_groups(up_to_date_group);
03209
03210 if (!recv_needed_recovery) {
03211 ut_a(checkpoint_lsn == recv_sys->recovered_lsn);
03212 } else {
03213 srv_start_lsn = recv_sys->recovered_lsn;
03214 }
03215
03216 log_sys->lsn = recv_sys->recovered_lsn;
03217
03218 ut_memcpy(log_sys->buf, recv_sys->last_block, OS_FILE_LOG_BLOCK_SIZE);
03219
03220 log_sys->buf_free = (ulint) log_sys->lsn % OS_FILE_LOG_BLOCK_SIZE;
03221 log_sys->buf_next_to_write = log_sys->buf_free;
03222 log_sys->written_to_some_lsn = log_sys->lsn;
03223 log_sys->written_to_all_lsn = log_sys->lsn;
03224
03225 log_sys->last_checkpoint_lsn = checkpoint_lsn;
03226
03227 log_sys->next_checkpoint_no = checkpoint_no + 1;
03228
03229 #ifdef UNIV_LOG_ARCHIVE
03230 if (archived_lsn == IB_ULONGLONG_MAX) {
03231
03232 log_sys->archiving_state = LOG_ARCH_OFF;
03233 }
03234 #endif
03235
03236 mutex_enter(&(recv_sys->mutex));
03237
03238 recv_sys->apply_log_recs = TRUE;
03239
03240 mutex_exit(&(recv_sys->mutex));
03241
03242 mutex_exit(&(log_sys->mutex));
03243
03244 recv_lsn_checks_on = TRUE;
03245
03246
03247
03248
03249
03250 return(DB_SUCCESS);
03251
03252 #undef TYPE_CHECKPOINT
03253 #undef LIMIT_LSN
03254 }
03255
03256
03258 UNIV_INTERN
03259 void
03260 recv_recovery_from_checkpoint_finish(void)
03261
03262 {
03263
03264
03265 if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
03266
03267 recv_apply_hashed_log_recs(TRUE);
03268 }
03269
03270 #ifdef UNIV_DEBUG
03271 if (log_debug_writes) {
03272 drizzled::errmsg_printf(drizzled::error::INFO,
03273 "InnoDB: Log records applied to the database.");
03274 }
03275 #endif
03276
03277 if (recv_sys->found_corrupt_log) {
03278 drizzled::errmsg_printf(drizzled::error::ERROR,
03279 "InnoDB: WARNING: the log file may have been corrupt and it\n"
03280 "InnoDB: is possible that the log scan or parsing did not proceed\n"
03281 "InnoDB: far enough in recovery. Please run CHECK TABLE on your InnoDB tables to check that they are ok! "
03282 "InnoDB: It may be safest to recover your database from a backup!");
03283 }
03284
03285
03286
03287 recv_recovery_on = FALSE;
03288
03289 #ifndef UNIV_LOG_DEBUG
03290 recv_sys_debug_free();
03291 #endif
03292
03293
03294
03295
03296 if (! srv_apply_log_only)
03297 trx_rollback_or_clean_recovered(FALSE);
03298 }
03299
03300
03302 UNIV_INTERN
03303 void
03304 recv_recovery_rollback_active(void)
03305
03306 {
03307 int i;
03308
03309 #ifdef UNIV_SYNC_DEBUG
03310
03311
03312 os_thread_sleep(1000000);
03313
03314
03315 sync_order_checks_on = TRUE;
03316 #endif
03317
03318 row_merge_drop_temp_indexes();
03319
03320 row_mysql_drop_temp_tables();
03321
03322 if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
03323
03324
03325
03326 os_thread_create(trx_rollback_or_clean_all_recovered,
03327 (void *)&i, NULL);
03328 }
03329 }
03330
03331
03333 UNIV_INTERN
03334 void
03335 recv_reset_logs(
03336
03337 ib_uint64_t lsn,
03342 #ifdef UNIV_LOG_ARCHIVE
03343 ulint arch_log_no,
03344 #endif
03345 ibool new_logs_created)
03349 {
03350 log_group_t* group;
03351
03352 ut_ad(mutex_own(&(log_sys->mutex)));
03353
03354 log_sys->lsn = ut_uint64_align_up(lsn, OS_FILE_LOG_BLOCK_SIZE);
03355
03356 group = UT_LIST_GET_FIRST(log_sys->log_groups);
03357
03358 while (group) {
03359 group->lsn = log_sys->lsn;
03360 group->lsn_offset = LOG_FILE_HDR_SIZE;
03361 #ifdef UNIV_LOG_ARCHIVE
03362 group->archived_file_no = arch_log_no;
03363 group->archived_offset = 0;
03364 #endif
03365
03366 if (!new_logs_created) {
03367 recv_truncate_group(group, group->lsn, group->lsn,
03368 group->lsn, group->lsn);
03369 }
03370
03371 group = UT_LIST_GET_NEXT(log_groups, group);
03372 }
03373
03374 log_sys->buf_next_to_write = 0;
03375 log_sys->written_to_some_lsn = log_sys->lsn;
03376 log_sys->written_to_all_lsn = log_sys->lsn;
03377
03378 log_sys->next_checkpoint_no = 0;
03379 log_sys->last_checkpoint_lsn = 0;
03380
03381 #ifdef UNIV_LOG_ARCHIVE
03382 log_sys->archived_lsn = log_sys->lsn;
03383 #endif
03384
03385 log_block_init(log_sys->buf, log_sys->lsn);
03386 log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE);
03387
03388 log_sys->buf_free = LOG_BLOCK_HDR_SIZE;
03389 log_sys->lsn += LOG_BLOCK_HDR_SIZE;
03390
03391 mutex_exit(&(log_sys->mutex));
03392
03393
03394
03395 log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
03396 log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
03397
03398 mutex_enter(&(log_sys->mutex));
03399 }
03400 #endif
03401
03402 #ifdef UNIV_HOTBACKUP
03403
03405 UNIV_INTERN
03406 void
03407 recv_reset_log_files_for_backup(
03408
03409 const char* log_dir,
03410 ulint n_log_files,
03411 ulint log_file_size,
03412 ib_uint64_t lsn)
03414 {
03415 os_file_t log_file;
03416 ibool success;
03417 byte* buf;
03418 ulint i;
03419 ulint log_dir_len;
03420 char name[5000];
03421 static const char ib_logfile_basename[] = "ib_logfile";
03422
03423 log_dir_len = strlen(log_dir);
03424
03425
03426
03427 ut_a(log_dir_len + strlen(ib_logfile_basename) + 11 < sizeof(name));
03428
03429 buf = ut_malloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
03430 memset(buf, '\0', LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
03431
03432 for (i = 0; i < n_log_files; i++) {
03433
03434 sprintf(name, "%s%s%lu", log_dir,
03435 ib_logfile_basename, (ulong)i);
03436
03437 log_file = os_file_create_simple(innodb_file_log_key,
03438 name, OS_FILE_CREATE,
03439 OS_FILE_READ_WRITE,
03440 &success);
03441 if (not success) {
03442 drizzled::errmsg_printf(drizzled::error::ERROR,
03443 "InnoDB: Cannot create %s. Check that the file does not exist yet.\n", name);
03444
03445 exit(1);
03446 }
03447
03448 drizzled::errmsg_printf(drizzled::error::INFO,
03449 "Setting log file size to %lu %lu\n",
03450 (ulong) ut_get_high32(log_file_size),
03451 (ulong) log_file_size & 0xFFFFFFFFUL);
03452
03453 success = os_file_set_size(name, log_file,
03454 log_file_size & 0xFFFFFFFFUL,
03455 ut_get_high32(log_file_size));
03456
03457 if (not success) {
03458 drizzled::errmsg_printf(drizzled::error::ERROR,
03459 "InnoDB: Cannot set %s size to %lu %lu\n",
03460 name, (ulong) ut_get_high32(log_file_size),
03461 (ulong) (log_file_size & 0xFFFFFFFFUL));
03462 exit(1);
03463 }
03464
03465 os_file_flush(log_file);
03466 os_file_close(log_file);
03467 }
03468
03469
03470
03471 log_reset_first_header_and_checkpoint(buf, lsn);
03472
03473 log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn);
03474 log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE,
03475 LOG_BLOCK_HDR_SIZE);
03476 sprintf(name, "%s%s%lu", log_dir, ib_logfile_basename, (ulong)0);
03477
03478 log_file = os_file_create_simple(innodb_file_log_key,
03479 name, OS_FILE_OPEN,
03480 OS_FILE_READ_WRITE, &success);
03481 if (!success) {
03482 drizzled::errmsg_printf(drizzled::error::ERROR, "InnoDB: Cannot open %s.\n", name);
03483
03484 exit(1);
03485 }
03486
03487 os_file_write(name, log_file, buf, 0, 0,
03488 LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
03489 os_file_flush(log_file);
03490 os_file_close(log_file);
03491
03492 ut_free(buf);
03493 }
03494 #endif
03495
03496 #ifdef UNIV_LOG_ARCHIVE
03497
03498
03501 static
03502 ibool
03503 log_group_recover_from_archive_file(
03504
03505 log_group_t* group)
03506 {
03507 os_file_t file_handle;
03508 ib_uint64_t start_lsn;
03509 ib_uint64_t file_end_lsn;
03510 ib_uint64_t dummy_lsn;
03511 ib_uint64_t scanned_lsn;
03512 ulint len;
03513 ibool ret;
03514 byte* buf;
03515 ulint read_offset;
03516 ulint file_size;
03517 ulint file_size_high;
03518 int input_char;
03519 char name[10000];
03520
03521 ut_a(0);
03522
03523 try_open_again:
03524 buf = log_sys->buf;
03525
03526
03527
03528 log_archived_file_name_gen(name, group->id, group->archived_file_no);
03529
03530 file_handle = os_file_create(innodb_file_log_key,
03531 name, OS_FILE_OPEN,
03532 OS_FILE_LOG, OS_FILE_AIO, &ret);
03533
03534 if (ret == FALSE) {
03535 ask_again:
03536 fprintf(stderr,
03537 "InnoDB: Do you want to copy additional"
03538 " archived log files\n"
03539 "InnoDB: to the directory\n");
03540 fprintf(stderr,
03541 "InnoDB: or were these all the files needed"
03542 " in recovery?\n");
03543 fprintf(stderr,
03544 "InnoDB: (Y == copy more files; N == this is all)?");
03545
03546 input_char = getchar();
03547
03548 if (input_char == (int) 'N') {
03549
03550 return(TRUE);
03551 } else if (input_char == (int) 'Y') {
03552
03553 goto try_open_again;
03554 } else {
03555 goto ask_again;
03556 }
03557 }
03558
03559 ret = os_file_get_size(file_handle, &file_size, &file_size_high);
03560 ut_a(ret);
03561
03562 ut_a(file_size_high == 0);
03563
03564 drizzled::errmsg_printf(drizzled::error::INFO,
03565 "InnoDB: Opened archived log file %s\n", name);
03566
03567 ret = os_file_close(file_handle);
03568
03569 if (file_size < LOG_FILE_HDR_SIZE) {
03570 drizzled::errmsg_printf(drizzled::error::ERROR,
03571 "InnoDB: Archive file header incomplete %s\n", name);
03572
03573 return(TRUE);
03574 }
03575
03576 ut_a(ret);
03577
03578
03579
03580 fil_node_create(name, 1 + file_size / UNIV_PAGE_SIZE,
03581 group->archive_space_id, FALSE);
03582 #if RECV_SCAN_SIZE < LOG_FILE_HDR_SIZE
03583 # error "RECV_SCAN_SIZE < LOG_FILE_HDR_SIZE"
03584 #endif
03585
03586
03587 fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, group->archive_space_id, 0, 0,
03588 LOG_FILE_HDR_SIZE, buf, NULL);
03589
03590
03591
03592 if (mach_read_from_4(buf + LOG_GROUP_ID) != group->id
03593 || mach_read_from_4(buf + LOG_FILE_NO)
03594 != group->archived_file_no) {
03595 drizzled::errmsg_printf(drizzled::error::ERROR,
03596 "InnoDB: Archive file header inconsistent %s\n", name);
03597
03598 return(TRUE);
03599 }
03600
03601 if (!mach_read_from_4(buf + LOG_FILE_ARCH_COMPLETED)) {
03602 drizzled::errmsg_printf(drizzled::error::ERROR,
03603 "InnoDB: Archive file not completely written %s\n",
03604 name);
03605
03606 return(TRUE);
03607 }
03608
03609 start_lsn = mach_read_from_8(buf + LOG_FILE_START_LSN);
03610 file_end_lsn = mach_read_from_8(buf + LOG_FILE_END_LSN);
03611
03612 if (!recv_sys->scanned_lsn) {
03613
03614 if (recv_sys->parse_start_lsn < start_lsn) {
03615 drizzled::errmsg_printf(drizzled::error::ERROR,
03616 "InnoDB: Archive log file %s starts from too big a lsn\n", name);
03617 return(TRUE);
03618 }
03619
03620 recv_sys->scanned_lsn = start_lsn;
03621 }
03622
03623 if (recv_sys->scanned_lsn != start_lsn) {
03624
03625 drizzled::errmsg_printf(drizzled::error::ERROR,
03626 "InnoDB: Archive log file %s starts from a wrong lsn\n", name);
03627 return(TRUE);
03628 }
03629
03630 read_offset = LOG_FILE_HDR_SIZE;
03631
03632 for (;;) {
03633 len = RECV_SCAN_SIZE;
03634
03635 if (read_offset + len > file_size) {
03636 len = ut_calc_align_down(file_size - read_offset,
03637 OS_FILE_LOG_BLOCK_SIZE);
03638 }
03639
03640 if (len == 0) {
03641
03642 break;
03643 }
03644
03645 #ifdef UNIV_DEBUG
03646 if (log_debug_writes) {
03647 drizzled::errmsg_printf(drizzled::error::INFO,
03648 "InnoDB: Archive read starting at lsn %"PRIu64", len %lu from file %s\n",
03649 start_lsn, (ulong) len, name);
03650 }
03651 #endif
03652
03653 fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE,
03654 group->archive_space_id, read_offset / UNIV_PAGE_SIZE,
03655 read_offset % UNIV_PAGE_SIZE, len, buf, NULL);
03656
03657 ret = recv_scan_log_recs(
03658 (buf_pool_get_n_pages()
03659 - (recv_n_pool_free_frames * srv_buf_pool_instances))
03660 * UNIV_PAGE_SIZE, TRUE, buf, len, start_lsn,
03661 &dummy_lsn, &scanned_lsn);
03662
03663 if (scanned_lsn == file_end_lsn) {
03664
03665 return(FALSE);
03666 }
03667
03668 if (ret) {
03669 drizzled::errmsg_printf(drizzled::error::ERROR,
03670 "InnoDB: Archive log file %s does not scan right.", name);
03671 return(TRUE);
03672 }
03673
03674 read_offset += len;
03675 start_lsn += len;
03676
03677 ut_ad(start_lsn == scanned_lsn);
03678 }
03679
03680 return(FALSE);
03681 }
03682
03683
03686 UNIV_INTERN
03687 ulint
03688 recv_recovery_from_archive_start(
03689
03690 ib_uint64_t min_flushed_lsn,
03692 ib_uint64_t limit_lsn,
03694 ulint first_log_no)
03699 {
03700 log_group_t* group;
03701 ulint group_id;
03702 ulint trunc_len;
03703 ibool ret;
03704 ulint err;
03705
03706 ut_a(0);
03707
03708 recv_sys_create();
03709 recv_sys_init(buf_pool_get_curr_size());
03710
03711 recv_recovery_on = TRUE;
03712 recv_recovery_from_backup_on = TRUE;
03713
03714 recv_sys->limit_lsn = limit_lsn;
03715
03716 group_id = 0;
03717
03718 group = UT_LIST_GET_FIRST(log_sys->log_groups);
03719
03720 while (group) {
03721 if (group->id == group_id) {
03722
03723 break;
03724 }
03725
03726 group = UT_LIST_GET_NEXT(log_groups, group);
03727 }
03728
03729 if (!group) {
03730 drizzled::errmsg_printf(drizzled::error::ERROR,
03731 "InnoDB: There is no log group defined with id %lu!\n",
03732 (ulong) group_id);
03733 return(DB_ERROR);
03734 }
03735
03736 group->archived_file_no = first_log_no;
03737
03738 recv_sys->parse_start_lsn = min_flushed_lsn;
03739
03740 recv_sys->scanned_lsn = 0;
03741 recv_sys->scanned_checkpoint_no = 0;
03742 recv_sys->recovered_lsn = recv_sys->parse_start_lsn;
03743
03744 recv_sys->archive_group = group;
03745
03746 ret = FALSE;
03747
03748 mutex_enter(&(log_sys->mutex));
03749
03750 while (!ret) {
03751 ret = log_group_recover_from_archive_file(group);
03752
03753
03754
03755
03756 trunc_len = UNIV_PAGE_SIZE
03757 * fil_space_get_size(group->archive_space_id);
03758 if (trunc_len > 0) {
03759 fil_space_truncate_start(group->archive_space_id,
03760 trunc_len);
03761 }
03762
03763 group->archived_file_no++;
03764 }
03765
03766 if (recv_sys->recovered_lsn < limit_lsn) {
03767
03768 if (!recv_sys->scanned_lsn) {
03769
03770 recv_sys->scanned_lsn = recv_sys->parse_start_lsn;
03771 }
03772
03773 mutex_exit(&(log_sys->mutex));
03774
03775 err = recv_recovery_from_checkpoint_start(LOG_ARCHIVE,
03776 limit_lsn,
03777 IB_ULONGLONG_MAX,
03778 IB_ULONGLONG_MAX);
03779 if (err != DB_SUCCESS) {
03780
03781 return(err);
03782 }
03783
03784 mutex_enter(&(log_sys->mutex));
03785 }
03786
03787 if (limit_lsn != IB_ULONGLONG_MAX) {
03788
03789 recv_apply_hashed_log_recs(FALSE);
03790
03791 recv_reset_logs(recv_sys->recovered_lsn, 0, FALSE);
03792 }
03793
03794 mutex_exit(&(log_sys->mutex));
03795
03796 return(DB_SUCCESS);
03797 }
03798
03799
03801 UNIV_INTERN
03802 void
03803 recv_recovery_from_archive_finish(void)
03804
03805 {
03806 recv_recovery_from_checkpoint_finish();
03807
03808 recv_recovery_from_backup_on = FALSE;
03809 }
03810 #endif