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