Drizzled Public API Documentation

log0recv.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
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 /* !UNIV_HOTBACKUP */
00054 
00058 UNIV_INTERN ibool recv_replay_file_ops  = TRUE;
00059 #endif /* !UNIV_HOTBACKUP */
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 /* UNIV_LOG_ARCHIVE */
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 /* UNIV_DEBUG */
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 /* !UNIV_HOTBACKUP */
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 /* !UNIV_HOTBACKUP */
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 /* UNIV_PFS_THREAD */
00159 
00160 #ifdef UNIV_PFS_MUTEX
00161 UNIV_INTERN mysql_pfs_key_t recv_sys_mutex_key;
00162 #endif /* UNIV_PFS_MUTEX */
00163 
00164 /* prototypes */
00165 
00166 #ifndef UNIV_HOTBACKUP
00167 /*******************************************************/
00170 static
00171 void
00172 recv_init_crash_recovery(void);
00173 /*===========================*/
00174 #endif /* !UNIV_HOTBACKUP */
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 Reset the state of the recovery system variables. */
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 /* UNIV_LOG_ARCHIVE */
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 /* !UNIV_HOTBACKUP */
00298 
00299 /************************************************************
00300 Inits the recovery system for a recovery operation. */
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   /* Initialize red-black tree for fast insertions into the
00314   flush_list during recovery process.
00315   As this initialization is done while holding the buffer pool
00316   mutex we perform it before acquiring recv_sys->mutex. */
00317 #ifndef UNIV_HOTBACKUP
00318   buf_flush_init_flush_rbt();
00319 #endif /* !UNIV_HOTBACKUP */
00320 
00321   mutex_enter(&(recv_sys->mutex));
00322 
00323   recv_sys->heap = mem_heap_create_in_buffer(256);
00324 #else /* !UNIV_HOTBACKUP */
00325   recv_sys->heap = mem_heap_create(256);
00326   recv_is_from_backup = TRUE;
00327 #endif /* !UNIV_HOTBACKUP */
00328 
00329   /* Set appropriate value of recv_n_pool_free_frames. */
00330   if (buf_pool_get_curr_size() >= (10 * 1024 * 1024)) {
00331     /* Buffer pool of size greater than 10 MB. */
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   /* Free up the flush_rbt. */
00404   buf_flush_free_flush_rbt();
00405 }
00406 # endif /* UNIV_LOG_DEBUG */
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     /* Checkpoint was taken in the NOARCHIVELOG mode */
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     /* We do not know how far we should erase log records: erase
00447     as much as possible */
00448 
00449     finish_lsn = finish_lsn1;
00450   } else {
00451     /* It is enough to erase the length of the log buffer */
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   /* Write the log buffer full of zeros */
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     /* Copy the last incomplete log block to the log buffer and
00469     edit its data length: */
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     /* Write the log buffer full of zeros */
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   /* Read the last recovered log block to the recovery system buffer:
00579   the block is always incomplete */
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       /* Copy log data if needed */
00596 
00597       recv_copy_group(group, up_to_date_group,
00598           recovered_lsn);
00599     }
00600 
00601     /* Update the fields in the group struct to correspond to
00602     recovered_lsn */
00603 
00604     log_group_set_fields(group, recovered_lsn);
00605 
00606     group = UT_LIST_GET_NEXT(log_groups, group);
00607   }
00608 
00609   /* Copy the checkpoint info to the groups; remember that we have
00610   incremented checkpoint_no by one, and the info will not be written
00611   over the max checkpoint info, thus making the preservation of max
00612   checkpoint info on disk certain */
00613 
00614   log_groups_write_checkpoint_info();
00615 
00616   mutex_exit(&(log_sys->mutex));
00617 
00618   /* Wait for the checkpoint write to complete */
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 /* !UNIV_HOTBACKUP */
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 /* UNIV_DEBUG */
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 /* UNIV_DEBUG */
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 /* !UNIV_HOTBACKUP */
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   /* If the user is running a pre-3.23.50 version of InnoDB, its
00810   checkpoint data does not contain the fsp limit info */
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   /*  fprintf(stderr, "fsp limit %lu MB\n", *fsp_limit); */
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 /* !UNIV_HOTBACKUP */
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 /* UNIV_LOG_DEBUG */
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     /* We assume the log block is in the format of
00856     InnoDB version < 3.23.52 and the block is ok */
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       /* Garbage or an incompletely written log block */
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       /* Garbage from a log buffer flush which was made
00930       before the most recent database recovery */
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       /* Log data ends here */
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 /* UNIV_HOTBACKUP */
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 /* UNIV_DEBUG */
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     /* The LSN is checked in recv_parse_log_rec(). */
01002     break;
01003 #endif /* UNIV_LOG_LSN_DEBUG */
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       /* It is OK to set FIL_PAGE_TYPE and certain
01009       list node fields on an empty page.  Any other
01010       write is not OK. */
01011 
01012       /* NOTE: There may be bogus assertion failures for
01013       dict_hdr_create(), trx_rseg_header_create(),
01014       trx_sys_create_doublewrite_buf(), and
01015       trx_sysf_create().
01016       These are only called during database creation. */
01017       ulint offs = mach_read_from_2(ptr);
01018 
01019       switch (type) {
01020       default:
01021         ut_error;
01022       case MLOG_2BYTES:
01023         /* Note that this can fail when the
01024         redo log been written with something
01025         older than InnoDB Plugin 1.0.4. */
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 /*FLST_PREV*/
01041               || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
01042               + PAGE_HEADER + FIL_ADDR_BYTE
01043               + FIL_ADDR_SIZE /*FLST_NEXT*/);
01044         break;
01045       case MLOG_4BYTES:
01046         /* Note that this can fail when the
01047         redo log been written with something
01048         older than InnoDB Plugin 1.0.4. */
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/* flst_init */
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 /*FLST_PREV*/
01072               || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
01073               + PAGE_HEADER + FIL_ADDR_PAGE
01074               + FIL_ADDR_SIZE /*FLST_NEXT*/);
01075         break;
01076       }
01077     }
01078 #endif /* UNIV_DEBUG */
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     /* This log record type is obsolete, but we process it for
01112     backward compatibility with MySQL 5.0.3 and 5.0.4. */
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     /* Fall through */
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     /* Allow anything in page_type when creating a page. */
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     /* Allow anything in page_type when creating a page. */
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     /* On a compressed page, MLOG_COMP_REC_MIN_MARK
01215     will be followed by MLOG_COMP_REC_DELETE
01216     or MLOG_ZIP_WRITE_HEADER(FIL_PAGE_PREV, FIL_NULL)
01217     in the same mini-transaction. */
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     /* Allow anything in page_type when creating a page. */
01239     ptr = ibuf_parse_bitmap_init(ptr, end_ptr, block, mtr);
01240     break;
01241   case MLOG_INIT_FILE_PAGE:
01242     /* Allow anything in page_type when creating a page. */
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     /* Allow anything in page_type when creating a page. */
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     /* The tablespace does not exist any more: do not store the
01367     log record */
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   /* Store the log record body in chunks of less than UNIV_PAGE_SIZE:
01405   recv_sys->heap grows into the buffer pool, and bigger chunks could not
01406   be allocated */
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 /* !UNIV_HOTBACKUP */
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 /* !UNIV_HOTBACKUP */
01490   mtr_t   mtr;
01491 
01492   mutex_enter(&(recv_sys->mutex));
01493 
01494   if (recv_sys->apply_log_recs == FALSE) {
01495 
01496     /* Log records should not be applied now */
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     /* Move the ownership of the x-latch on the page to
01533     this OS thread, so that we can acquire a second
01534     x-latch on it.  This is needed for the operations to
01535     the page to pass the debug checks. */
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 /* !UNIV_HOTBACKUP */
01548 
01549   /* Read the newest modification lsn from the page */
01550   page_lsn = mach_read_from_8(page + FIL_PAGE_LSN);
01551 
01552 #ifndef UNIV_HOTBACKUP
01553   /* It may be that the page has been modified in the buffer
01554   pool: read the newest modification lsn there */
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 /* !UNIV_HOTBACKUP */
01563   /* In recovery from a backup we do not really use the buffer pool */
01564   page_newest_lsn = 0;
01565 #endif /* !UNIV_HOTBACKUP */
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       /* We have to copy the record body to a separate
01577       buffer */
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 /* UNIV_DEBUG */
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 /* UNIV_ZIP_DEBUG */
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 /* !UNIV_HOTBACKUP */
01675 
01676   /* Make sure that committing mtr does not change the modification
01677   lsn values of page */
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   fprintf(stderr, "Recv pages at %lu n %lu\n", page_nos[0], n);
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   /* Wait until all the pages have been processed */
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     /* Flush all the file pages to disk and invalidate them in
01851     the buffer pool */
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 /* !UNIV_HOTBACKUP */
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     /* The address hash table is externally chained */
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       /* We simulate a page read made by the buffer pool, to
01937       make sure the recovery apparatus works ok. We must init
01938       the block. */
01939 
01940       buf_page_init_for_backup_restore(
01941         recv_addr->space, recv_addr->page_no,
01942         zip_size, block);
01943 
01944       /* Extend the tablespace's last file if the page_no
01945       does not fall inside its bounds; we assume the last
01946       file is auto-extending, and ibbackup copied the file
01947       when it still was smaller */
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       /* Read the page from the tablespace file using the
01962       fil0fil.c routines */
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       /* Apply the log records to this page */
01993       recv_recover_page(FALSE, block);
01994 
01995       /* Write the page back to the tablespace file using the
01996       fil0fil.c routines */
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 /* !UNIV_HOTBACKUP */
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; /* For debugging */
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 /* UNIV_LOG_DEBUG */
02084     ut_a(lsn == recv_sys->recovered_lsn);
02085 # endif /* UNIV_LOG_DEBUG */
02086   }
02087 #endif /* UNIV_LOG_LSN_DEBUG */
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 /* UNIV_LOG_DEBUG */
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 /* !UNIV_HOTBACKUP */
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     /* The mtr only modified a single page, or this is a file op */
02257 
02258     old_lsn = recv_sys->recovered_lsn;
02259 
02260     /* Try to parse a log record, fetching its type, space id,
02261     page no, and a pointer to the body of the log record */
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       /* The log record filled a log block, and we require
02280       that also the next log block should have been scanned
02281       in */
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 /* UNIV_DEBUG */
02302 
02303     if (type == MLOG_DUMMY_RECORD) {
02304       /* Do nothing */
02305 
02306     } else if (!store_to_hash) {
02307       /* In debug checking, update a replicate page
02308       according to the log record, and check that it
02309       becomes identical with the original page */
02310 #ifdef UNIV_LOG_DEBUG
02311       recv_check_incomplete_log_recs(ptr, len);
02312 #endif/* UNIV_LOG_DEBUG */
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         /* In ibbackup --apply-log, replay an .ibd file
02323         operation, if possible; note that
02324         fil_path_to_mysql_datadir is set in ibbackup to
02325         point to the datadir we should use there */
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       /* In normal mysqld crash recovery we do not try to
02344       replay file operations */
02345 #ifdef UNIV_LOG_LSN_DEBUG
02346     } else if (type == MLOG_LSN) {
02347       /* Do not add these records to the hash table.
02348       The page number and space id fields are misused
02349       for something else. */
02350 #endif /* UNIV_LOG_LSN_DEBUG */
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     /* Check that all the records associated with the single mtr
02358     are included within the buffer */
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 /* UNIV_LOG_DEBUG */
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 /* UNIV_DEBUG */
02398 
02399       total_len += len;
02400       n_recs++;
02401 
02402       ptr += len;
02403 
02404       if (type == MLOG_MULTI_REC_END) {
02405 
02406         /* Found the end mark for the records */
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       /* The log record filled a log block, and we require
02417       that also the next log block should have been scanned
02418       in */
02419 
02420       return(FALSE);
02421     }
02422 
02423     /* Add all the records to the hash table */
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         /* Found the end mark for the records */
02446 
02447         break;
02448       }
02449 
02450       if (store_to_hash
02451 #ifdef UNIV_LOG_LSN_DEBUG
02452           && type != MLOG_LSN
02453 #endif /* UNIV_LOG_LSN_DEBUG */
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     /* Cannot start parsing yet because no start point for
02489     it found */
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     fprintf(stderr, "Log block header no %lu\n", no);
02607 
02608     fprintf(stderr, "Scanned lsn no %lu\n",
02609     log_block_convert_lsn_to_no(scanned_lsn));
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       /* Garbage or an incompletely written log block */
02631 
02632       finished = TRUE;
02633 
02634       break;
02635     }
02636 
02637     if (log_block_get_flush_bit(log_block)) {
02638       /* This block was a start of a log flush operation:
02639       we know that the previous flush operation must have
02640       been completed for all log groups before this block
02641       can have been flushed to any of the groups. Therefore,
02642       we know that log data is contiguous up to scanned_lsn
02643       in all non-corrupt log groups. */
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       /* Garbage from a log buffer flush which was made
02662       before the most recent database recovery */
02663 
02664       finished = TRUE;
02665 #ifdef UNIV_LOG_DEBUG
02666       /* This is not really an error, but currently
02667       we stop here in the debug version: */
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       /* We found a point from which to start the parsing
02678       of log records */
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       /* We have found more entries. If this scan is
02691       of startup type, we must initiate crash recovery
02692       environment before parsing these log records. */
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 /* !UNIV_HOTBACKUP */
02705 
02706       /* We were able to find more log data: add it to the
02707       parsing buffer if parse_start_lsn is already
02708       non-zero */
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 /* !UNIV_HOTBACKUP */
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       /* Log data for this group ends here */
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     /* Try to parse more log records */
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       /* Hash table of log records has grown too big:
02773       empty it; FALSE means no ibuf operations
02774       allowed, as we cannot add new records to the
02775       log yet: they would be produced by ibuf
02776       operations */
02777 
02778       recv_apply_hashed_log_recs(FALSE);
02779     }
02780 #endif /* !UNIV_HOTBACKUP */
02781 
02782     if (recv_sys->recovered_offset > RECV_PARSING_BUF_SIZE / 4) {
02783       /* Move parsing buffer data to the buffer start */
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 /* UNIV_DEBUG */
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   /* If we are using the doublewrite method, we will
02864   check if there are half-written pages in data files,
02865   and restore them from the doublewrite buffer if
02866   possible */
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 /* UNIV_LOG_ARCHIVE */
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 /* UNIV_LOG_ARCHIVE */
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 /* UNIV_LOG_ARCHIVE */
02927 
02928 # define TYPE_CHECKPOINT  1
02929 
02930 # define LIMIT_LSN    IB_ULONGLONG_MAX
02931 #endif /* UNIV_LOG_ARCHIVE */
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   /* Look for the latest checkpoint from any of the log groups */
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 /* UNIV_LOG_ARCHIVE */
02971 
02972   /* Read the first log file header to print a note if this is
02973   a recovery from a restored InnoDB Hot Backup */
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     /* This log file was created by ibbackup --restore: print
02982     a note to the user about it */
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           /* Wipe over the label now */
02991 
02992           memset(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
02993                  ' ', 4);
02994           /* Write to the log file to wipe over the label */
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     /* 0 means default value */
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 /* UNIV_LOG_ARCHIVE */
03027 
03028   if (TYPE_CHECKPOINT) {
03029     /* Start reading the log groups from the checkpoint lsn up. The
03030     variable contiguous_lsn contains an lsn up to which the log is
03031     known to be contiguously written to all log groups. */
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     /* Try to recover the remaining part from logs: first from
03050     the logs of the archived group */
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       /* The group does not contain enough log: probably
03061       an archived log file was missing or corrupt */
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       /* The group did not contain enough log: an archived
03073       log file was missing or invalid, or the log group
03074       was corrupt */
03075 
03076       return(DB_ERROR);
03077     }
03078 
03079     group->scanned_lsn = group_scanned_lsn;
03080     up_to_date_group = group;
03081 #endif /* UNIV_LOG_ARCHIVE */
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 /* UNIV_LOG_ARCHIVE */
03093 
03094   /* Set the flag to publish that we are doing startup scan. */
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       /* We found a more up-to-date group */
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 /* UNIV_LOG_ARCHIVE */
03115 
03116     group = UT_LIST_GET_NEXT(log_groups, group);
03117   }
03118 
03119   /* Done with startup scan. Clear the flag. */
03120   recv_log_scan_is_startup_type = FALSE;
03121   if (TYPE_CHECKPOINT) {
03122     /* NOTE: we always do a 'recovery' at startup, but only if
03123     there is something wrong we will print a message to the
03124     user about recovery: */
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       /* Init the doublewrite buffer memory structure */
03163       trx_sys_doublewrite_init_or_restore_pages(FALSE);
03164     }
03165   }
03166 
03167   /* We currently have only one log group */
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   /* Synchronize the uncorrupted log groups to the most up-to-date log
03199   group; we also copy checkpoint info to groups */
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 /* UNIV_LOG_ARCHIVE */
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 /* UNIV_LOG_ARCHIVE */
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   /* The database is now ready to start almost normal processing of user
03247   transactions: transaction rollbacks and the application of the log
03248   records in the hash table can be run in background. */
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   /* Apply the hashed log records to the respective file pages */
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 /* UNIV_DEBUG */
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   /* Free the resources of the recovery system */
03286 
03287   recv_recovery_on = FALSE;
03288 
03289 #ifndef UNIV_LOG_DEBUG
03290   recv_sys_debug_free();
03291 #endif
03292   /* Roll back any recovered data dictionary transactions, so
03293   that the data dictionary tables will be free of any locks.
03294   The data dictionary latch should guarantee that there is at
03295   most one data dictionary transaction active at a time. */
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   /* Wait for a while so that created threads have time to suspend
03311   themselves before we switch the latching order checks on */
03312   os_thread_sleep(1000000);
03313 
03314   /* Switch latching order checks on in sync0sync.c */
03315   sync_order_checks_on = TRUE;
03316 #endif
03317   /* Drop partially created indexes. */
03318   row_merge_drop_temp_indexes();
03319   /* Drop temporary tables. */
03320   row_mysql_drop_temp_tables();
03321 
03322   if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
03323     /* Rollback the uncommitted transactions which have no user
03324     session */
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 /* UNIV_LOG_ARCHIVE */
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 /* UNIV_LOG_ARCHIVE */
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 /* UNIV_LOG_ARCHIVE */
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   /* Reset the checkpoint fields in logs */
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 /* !UNIV_HOTBACKUP */
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   /* full path name of ib_logfile consists of log dir path + basename
03425   + number. This must fit in the name buffer.
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   /* We pretend there is a checkpoint at lsn + LOG_BLOCK_HDR_SIZE */
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 /* UNIV_HOTBACKUP */
03495 
03496 #ifdef UNIV_LOG_ARCHIVE
03497 /* Dead code */
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   /* Add the file to the archive file space; open the file */
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   /* Add the archive file as a node to the space */
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   /* Read the archive file header */
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   /* Check if the archive file header is consistent */
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 /* UNIV_DEBUG */
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     /* Close and truncate a possible processed archive file
03754     from the file space */
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 /* UNIV_LOG_ARCHIVE */