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