Drizzled Public API Documentation

log0recv.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "log0recv.h"
27 
28 #ifdef UNIV_NONINL
29 #include "log0recv.ic"
30 #endif
31 
32 #include "mem0mem.h"
33 #include "buf0buf.h"
34 #include "buf0flu.h"
35 #include "mtr0mtr.h"
36 #include "mtr0log.h"
37 #include "page0cur.h"
38 #include "page0zip.h"
39 #include "btr0btr.h"
40 #include "btr0cur.h"
41 #include "ibuf0ibuf.h"
42 #include "trx0undo.h"
43 #include "trx0rec.h"
44 #include "fil0fil.h"
45 #include "xtrabackup_api.h"
46 #ifndef UNIV_HOTBACKUP
47 # include "buf0rea.h"
48 # include "srv0srv.h"
49 # include "srv0start.h"
50 # include "trx0roll.h"
51 # include "row0merge.h"
52 # include "sync0sync.h"
53 #else /* !UNIV_HOTBACKUP */
54 
58 UNIV_INTERN ibool recv_replay_file_ops = TRUE;
59 #endif /* !UNIV_HOTBACKUP */
60 
61 #include <boost/scoped_array.hpp>
62 
63 #include <drizzled/errmsg_print.h>
64 
67 #define RECV_DATA_BLOCK_SIZE (MEM_MAX_ALLOC_IN_BUF - sizeof(recv_data_t))
68 
70 #define RECV_READ_AHEAD_AREA 32
71 
73 UNIV_INTERN recv_sys_t* recv_sys = NULL;
77 UNIV_INTERN ibool recv_recovery_on;
78 #ifdef UNIV_LOG_ARCHIVE
79 
80 UNIV_INTERN ibool recv_recovery_from_backup_on;
81 #endif /* UNIV_LOG_ARCHIVE */
82 
83 #ifndef UNIV_HOTBACKUP
84 
85 UNIV_INTERN ibool recv_needed_recovery;
86 # ifdef UNIV_DEBUG
87 
89 UNIV_INTERN ibool recv_no_log_write = FALSE;
90 # endif /* UNIV_DEBUG */
91 
95 UNIV_INTERN ibool recv_lsn_checks_on;
96 
105 static ibool recv_log_scan_is_startup_type;
106 
116 UNIV_INTERN ibool recv_no_ibuf_operations;
118 # define recv_is_making_a_backup FALSE
119 
120 # define recv_is_from_backup FALSE
121 #else /* !UNIV_HOTBACKUP */
122 # define recv_needed_recovery FALSE
123 
124 UNIV_INTERN ibool recv_is_making_a_backup = FALSE;
126 UNIV_INTERN ibool recv_is_from_backup = FALSE;
127 # define buf_pool_get_curr_size() (5 * 1024 * 1024)
128 #endif /* !UNIV_HOTBACKUP */
129 
131 static ulint recv_scan_print_counter;
132 
134 static ulint recv_previous_parsed_rec_type;
136 static ulint recv_previous_parsed_rec_offset;
138 static ulint recv_previous_parsed_rec_is_multi;
139 
141 UNIV_INTERN ulint recv_max_parsed_page_no;
142 
149 UNIV_INTERN ulint recv_n_pool_free_frames;
150 
154 UNIV_INTERN ib_uint64_t recv_max_page_lsn;
155 
156 #ifdef UNIV_PFS_THREAD
157 UNIV_INTERN mysql_pfs_key_t trx_rollback_clean_thread_key;
158 #endif /* UNIV_PFS_THREAD */
159 
160 #ifdef UNIV_PFS_MUTEX
161 UNIV_INTERN mysql_pfs_key_t recv_sys_mutex_key;
162 #endif /* UNIV_PFS_MUTEX */
163 
164 /* prototypes */
165 
166 #ifndef UNIV_HOTBACKUP
167 /*******************************************************/
170 static
171 void
172 recv_init_crash_recovery(void);
173 /*===========================*/
174 #endif /* !UNIV_HOTBACKUP */
175 
176 /********************************************************/
178 UNIV_INTERN
179 void
181 /*=================*/
182 {
183  if (recv_sys != NULL) {
184 
185  return;
186  }
187 
188  recv_sys = static_cast<recv_sys_t *>(mem_alloc(sizeof(*recv_sys)));
189  memset(recv_sys, 0x0, sizeof(*recv_sys));
190 
191  mutex_create(recv_sys_mutex_key, &recv_sys->mutex, SYNC_RECV);
192 
193  recv_sys->heap = NULL;
194  recv_sys->addr_hash = NULL;
195 }
196 
197 /********************************************************/
199 UNIV_INTERN
200 void
202 /*================*/
203 {
204  if (recv_sys != NULL) {
205  if (recv_sys->addr_hash != NULL) {
206  hash_table_free(recv_sys->addr_hash);
207  }
208 
209  if (recv_sys->heap != NULL) {
211  }
212 
213  if (recv_sys->buf != NULL) {
214  ut_free(recv_sys->buf);
215  }
216 
217  if (recv_sys->last_block_buf_start != NULL) {
219  }
220 
221  mutex_free(&recv_sys->mutex);
222 
224  recv_sys = NULL;
225  }
226 }
227 
228 /********************************************************/
230 UNIV_INTERN
231 void
233 /*===================*/
234 {
235  if (recv_sys != NULL) {
236  if (recv_sys->addr_hash != NULL) {
237  hash_table_free(recv_sys->addr_hash);
238  }
239 
240  if (recv_sys->heap != NULL) {
242  }
243 
244  if (recv_sys->buf != NULL) {
245  ut_free(recv_sys->buf);
246  }
247 
248  if (recv_sys->last_block_buf_start != NULL) {
250  }
251 
253  recv_sys = NULL;
254  }
255 }
256 
257 #ifndef UNIV_HOTBACKUP
258 /************************************************************
259 Reset the state of the recovery system variables. */
260 UNIV_INTERN
261 void
263 /*===================*/
264 {
265  recv_lsn_checks_on = FALSE;
266 
268 
269  recv_recovery_on = FALSE;
270 
271 #ifdef UNIV_LOG_ARCHIVE
272  recv_recovery_from_backup_on = FALSE;
273 #endif /* UNIV_LOG_ARCHIVE */
274 
275  recv_needed_recovery = FALSE;
276 
277  recv_lsn_checks_on = FALSE;
278 
279  recv_log_scan_is_startup_type = FALSE;
280 
281  recv_no_ibuf_operations = FALSE;
282 
283  recv_scan_print_counter = 0;
284 
285  recv_previous_parsed_rec_type = 999999;
286 
287  recv_previous_parsed_rec_offset = 0;
288 
289  recv_previous_parsed_rec_is_multi = 0;
290 
292 
294 
295  recv_max_page_lsn = 0;
296 }
297 #endif /* !UNIV_HOTBACKUP */
298 
299 /************************************************************
300 Inits the recovery system for a recovery operation. */
301 UNIV_INTERN
302 void
304 /*==========*/
305  ulint available_memory)
306 {
307  if (recv_sys->heap != NULL) {
308 
309  return;
310  }
311 
312 #ifndef UNIV_HOTBACKUP
313  /* Initialize red-black tree for fast insertions into the
314  flush_list during recovery process.
315  As this initialization is done while holding the buffer pool
316  mutex we perform it before acquiring recv_sys->mutex. */
317 #ifndef UNIV_HOTBACKUP
318  buf_flush_init_flush_rbt();
319 #endif /* !UNIV_HOTBACKUP */
320 
321  mutex_enter(&(recv_sys->mutex));
322 
324 #else /* !UNIV_HOTBACKUP */
325  recv_sys->heap = mem_heap_create(256);
326  recv_is_from_backup = TRUE;
327 #endif /* !UNIV_HOTBACKUP */
328 
329  /* Set appropriate value of recv_n_pool_free_frames. */
330  if (buf_pool_get_curr_size() >= (10 * 1024 * 1024)) {
331  /* Buffer pool of size greater than 10 MB. */
333  }
334 
335  recv_sys->buf = static_cast<byte *>(ut_malloc(RECV_PARSING_BUF_SIZE));
336  recv_sys->len = 0;
338 
339  recv_sys->addr_hash = hash_create(available_memory / 512);
340  recv_sys->n_addrs = 0;
341 
342  recv_sys->apply_log_recs = FALSE;
343  recv_sys->apply_batch_on = FALSE;
344 
345  recv_sys->last_block_buf_start = static_cast<byte *>(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE));
346 
347  recv_sys->last_block = static_cast<byte *>(ut_align(recv_sys->last_block_buf_start,
349  recv_sys->found_corrupt_log = FALSE;
350 
351  recv_max_page_lsn = 0;
352 
353  mutex_exit(&(recv_sys->mutex));
354 }
355 
356 /********************************************************/
358 static
359 void
360 recv_sys_empty_hash(void)
361 /*=====================*/
362 {
363  ut_ad(mutex_own(&(recv_sys->mutex)));
364 
365  if (recv_sys->n_addrs != 0) {
366  drizzled::errmsg_printf(drizzled::error::ERROR,
367  "InnoDB: Error: %lu pages with log records were left unprocessed!\n"
368  "InnoDB: Maximum page number with log records on it %lu\n",
369  (ulong) recv_sys->n_addrs,
370  (ulong) recv_max_parsed_page_no);
371  ut_error;
372  }
373 
374  hash_table_free(recv_sys->addr_hash);
376 
377  recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 512);
378 }
379 
380 #ifndef UNIV_HOTBACKUP
381 # ifndef UNIV_LOG_DEBUG
382 /********************************************************/
384 static
385 void
386 recv_sys_debug_free(void)
387 /*=====================*/
388 {
389  mutex_enter(&(recv_sys->mutex));
390 
391  hash_table_free(recv_sys->addr_hash);
393  ut_free(recv_sys->buf);
395 
396  recv_sys->buf = NULL;
397  recv_sys->heap = NULL;
398  recv_sys->addr_hash = NULL;
400 
401  mutex_exit(&(recv_sys->mutex));
402 
403  /* Free up the flush_rbt. */
404  buf_flush_free_flush_rbt();
405 }
406 # endif /* UNIV_LOG_DEBUG */
407 
408 /********************************************************/
410 static
411 void
412 recv_truncate_group(
413 /*================*/
414  log_group_t* group,
415  ib_uint64_t recovered_lsn,
417  ib_uint64_t limit_lsn,
419  ib_uint64_t checkpoint_lsn,
421  ib_uint64_t archived_lsn)
423 {
424  ib_uint64_t start_lsn;
425  ib_uint64_t end_lsn;
426  ib_uint64_t finish_lsn1;
427  ib_uint64_t finish_lsn2;
428  ib_uint64_t finish_lsn;
429  ulint len;
430  ulint i;
431 
432  if (archived_lsn == IB_ULONGLONG_MAX) {
433  /* Checkpoint was taken in the NOARCHIVELOG mode */
434  archived_lsn = checkpoint_lsn;
435  }
436 
437  finish_lsn1 = ut_uint64_align_down(archived_lsn,
439  + log_group_get_capacity(group);
440 
441  finish_lsn2 = ut_uint64_align_up(recovered_lsn,
444 
445  if (limit_lsn != IB_ULONGLONG_MAX) {
446  /* We do not know how far we should erase log records: erase
447  as much as possible */
448 
449  finish_lsn = finish_lsn1;
450  } else {
451  /* It is enough to erase the length of the log buffer */
452  finish_lsn = finish_lsn1 < finish_lsn2
453  ? finish_lsn1 : finish_lsn2;
454  }
455 
456  ut_a(RECV_SCAN_SIZE <= log_sys->buf_size);
457 
458  /* Write the log buffer full of zeros */
459  for (i = 0; i < RECV_SCAN_SIZE; i++) {
460 
461  *(log_sys->buf + i) = '\0';
462  }
463 
464  start_lsn = ut_uint64_align_down(recovered_lsn,
466 
467  if (start_lsn != recovered_lsn) {
468  /* Copy the last incomplete log block to the log buffer and
469  edit its data length: */
470 
471  ut_memcpy(log_sys->buf, recv_sys->last_block,
473  log_block_set_data_len(log_sys->buf,
474  (ulint) (recovered_lsn - start_lsn));
475  }
476 
477  if (start_lsn >= finish_lsn) {
478 
479  return;
480  }
481 
482  for (;;) {
483  end_lsn = start_lsn + RECV_SCAN_SIZE;
484 
485  if (end_lsn > finish_lsn) {
486 
487  end_lsn = finish_lsn;
488  }
489 
490  len = (ulint) (end_lsn - start_lsn);
491 
492  log_group_write_buf(group, log_sys->buf, len, start_lsn, 0);
493  if (end_lsn >= finish_lsn) {
494 
495  return;
496  }
497 
498  /* Write the log buffer full of zeros */
499  for (i = 0; i < RECV_SCAN_SIZE; i++) {
500 
501  *(log_sys->buf + i) = '\0';
502  }
503 
504  start_lsn = end_lsn;
505  }
506 }
507 
508 /********************************************************/
511 static
512 void
513 recv_copy_group(
514 /*============*/
515  log_group_t* up_to_date_group,
517  log_group_t* group,
519  ib_uint64_t recovered_lsn)
521 {
522  ib_uint64_t start_lsn;
523  ib_uint64_t end_lsn;
524  ulint len;
525 
526  if (group->scanned_lsn >= recovered_lsn) {
527 
528  return;
529  }
530 
531  ut_a(RECV_SCAN_SIZE <= log_sys->buf_size);
532 
533  start_lsn = ut_uint64_align_down(group->scanned_lsn,
535  for (;;) {
536  end_lsn = start_lsn + RECV_SCAN_SIZE;
537 
538  if (end_lsn > recovered_lsn) {
539  end_lsn = ut_uint64_align_up(recovered_lsn,
541  }
542 
543  log_group_read_log_seg(LOG_RECOVER, log_sys->buf,
544  up_to_date_group, start_lsn, end_lsn);
545 
546  len = (ulint) (end_lsn - start_lsn);
547 
548  log_group_write_buf(group, log_sys->buf, len, start_lsn, 0);
549 
550  if (end_lsn >= recovered_lsn) {
551 
552  return;
553  }
554 
555  start_lsn = end_lsn;
556  }
557 }
558 
559 /********************************************************/
564 static
565 void
566 recv_synchronize_groups(
567 /*====================*/
568  log_group_t* up_to_date_group)
570 {
571  log_group_t* group;
572  ib_uint64_t start_lsn;
573  ib_uint64_t end_lsn;
574  ib_uint64_t recovered_lsn;
575 
576  recovered_lsn = recv_sys->recovered_lsn;
577 
578  /* Read the last recovered log block to the recovery system buffer:
579  the block is always incomplete */
580 
581  start_lsn = ut_uint64_align_down(recovered_lsn,
583  end_lsn = ut_uint64_align_up(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE);
584 
585  ut_a(start_lsn != end_lsn);
586 
588  up_to_date_group, start_lsn, end_lsn);
589 
590  group = UT_LIST_GET_FIRST(log_sys->log_groups);
591 
592  while (group) {
593  if (group != up_to_date_group) {
594 
595  /* Copy log data if needed */
596 
597  recv_copy_group(group, up_to_date_group,
598  recovered_lsn);
599  }
600 
601  /* Update the fields in the group struct to correspond to
602  recovered_lsn */
603 
604  log_group_set_fields(group, recovered_lsn);
605 
606  group = UT_LIST_GET_NEXT(log_groups, group);
607  }
608 
609  /* Copy the checkpoint info to the groups; remember that we have
610  incremented checkpoint_no by one, and the info will not be written
611  over the max checkpoint info, thus making the preservation of max
612  checkpoint info on disk certain */
613 
615 
616  mutex_exit(&(log_sys->mutex));
617 
618  /* Wait for the checkpoint write to complete */
619  rw_lock_s_lock(&(log_sys->checkpoint_lock));
620  rw_lock_s_unlock(&(log_sys->checkpoint_lock));
621 
622  mutex_enter(&(log_sys->mutex));
623 }
624 #endif /* !UNIV_HOTBACKUP */
625 
626 /***********************************************************************/
629 ibool
630 recv_check_cp_is_consistent(
631 /*========================*/
632  const byte* buf)
633 {
634  ulint fold;
635 
636  fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
637 
638  if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(
639  buf + LOG_CHECKPOINT_CHECKSUM_1)) {
640  return(FALSE);
641  }
642 
643  fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
644  LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
645 
646  if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(
647  buf + LOG_CHECKPOINT_CHECKSUM_2)) {
648  return(FALSE);
649  }
650 
651  return(TRUE);
652 }
653 
654 #ifndef UNIV_HOTBACKUP
655 /********************************************************/
658 ulint
659 recv_find_max_checkpoint(
660 /*=====================*/
661  log_group_t** max_group,
662  ulint* max_field)
664 {
665  log_group_t* group;
666  ib_uint64_t max_no;
667  ib_uint64_t checkpoint_no;
668  ulint field;
669  byte* buf;
670 
671  group = UT_LIST_GET_FIRST(log_sys->log_groups);
672 
673  max_no = 0;
674  *max_group = NULL;
675  *max_field = 0;
676 
677  buf = log_sys->checkpoint_buf;
678 
679  while (group) {
680  group->state = LOG_GROUP_CORRUPTED;
681 
682  for (field = LOG_CHECKPOINT_1; field <= LOG_CHECKPOINT_2;
683  field += LOG_CHECKPOINT_2 - LOG_CHECKPOINT_1) {
684 
685  log_group_read_checkpoint_info(group, field);
686 
687  if (!recv_check_cp_is_consistent(buf)) {
688 #ifdef UNIV_DEBUG
689  if (log_debug_writes) {
690  drizzled::errmsg_printf(drizzled::error::INFO,
691  "InnoDB: Checkpoint in group %lu at %lu invalid, %lu\n",
692  (ulong) group->id,
693  (ulong) field,
694  (ulong) mach_read_from_4(
695  buf
696  + LOG_CHECKPOINT_CHECKSUM_1));
697 
698  }
699 #endif /* UNIV_DEBUG */
700  goto not_consistent;
701  }
702 
703  group->state = LOG_GROUP_OK;
704 
705  group->lsn = mach_read_from_8(
706  buf + LOG_CHECKPOINT_LSN);
707 
708 #ifdef UNIV_LOG_ARCHIVE
709 #error "UNIV_LOG_ARCHIVE could not be enabled"
710 #endif
711  {
712  ib_uint64_t tmp_lsn_offset = mach_read_from_8(
713  buf + LOG_CHECKPOINT_ARCHIVED_LSN);
714  if (sizeof(ulint) != 4
715  && tmp_lsn_offset != IB_ULONGLONG_MAX) {
716  group->lsn_offset = (ulint) tmp_lsn_offset;
717  } else {
718  group->lsn_offset = mach_read_from_4(
719  buf + LOG_CHECKPOINT_OFFSET);
720  }
721  }
722 
723  checkpoint_no = mach_read_from_8(
724  buf + LOG_CHECKPOINT_NO);
725 
726 #ifdef UNIV_DEBUG
727  if (log_debug_writes) {
728  drizzled::errmsg_printf(drizzled::error::INFO,
729  "InnoDB: Checkpoint number %lu found in group %lu\n",
730  (ulong) checkpoint_no,
731  (ulong) group->id);
732  }
733 #endif /* UNIV_DEBUG */
734 
735  if (checkpoint_no >= max_no) {
736  *max_group = group;
737  *max_field = field;
738  max_no = checkpoint_no;
739  }
740 
741 not_consistent:
742  ;
743  }
744 
745  group = UT_LIST_GET_NEXT(log_groups, group);
746  }
747 
748  if (*max_group == NULL) {
749 
750  drizzled::errmsg_printf(drizzled::error::ERROR,
751  "InnoDB: No valid checkpoint found. If this error appears when you are"
752  " creating an InnoDB database,InnoDB: the problem may be that during"
753  " an earlier attempt you managed to create the InnoDB data files,"
754  " but log file creation failed. If that is the case, please refer to\n"
755  "InnoDB: " REFMAN "error-creating-innodb.html\n");
756  return(DB_ERROR);
757  }
758 
759  return(DB_SUCCESS);
760 }
761 #else /* !UNIV_HOTBACKUP */
762 /*******************************************************************/
765 UNIV_INTERN
766 ibool
767 recv_read_cp_info_for_backup(
768 /*=========================*/
769  const byte* hdr,
771  ib_uint64_t* lsn,
772  ulint* offset,
773  ulint* fsp_limit,
776  ib_uint64_t* cp_no,
777  ib_uint64_t* first_header_lsn)
780 {
781  ulint max_cp = 0;
782  ib_uint64_t max_cp_no = 0;
783  const byte* cp_buf;
784 
785  cp_buf = hdr + LOG_CHECKPOINT_1;
786 
787  if (recv_check_cp_is_consistent(cp_buf)) {
788  max_cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO);
789  max_cp = LOG_CHECKPOINT_1;
790  }
791 
792  cp_buf = hdr + LOG_CHECKPOINT_2;
793 
794  if (recv_check_cp_is_consistent(cp_buf)) {
795  if (mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO) > max_cp_no) {
796  max_cp = LOG_CHECKPOINT_2;
797  }
798  }
799 
800  if (max_cp == 0) {
801  return(FALSE);
802  }
803 
804  cp_buf = hdr + max_cp;
805 
806  *lsn = mach_read_from_8(cp_buf + LOG_CHECKPOINT_LSN);
807  *offset = mach_read_from_4(cp_buf + LOG_CHECKPOINT_OFFSET);
808 
809  /* If the user is running a pre-3.23.50 version of InnoDB, its
810  checkpoint data does not contain the fsp limit info */
811  if (mach_read_from_4(cp_buf + LOG_CHECKPOINT_FSP_MAGIC_N)
812  == LOG_CHECKPOINT_FSP_MAGIC_N_VAL) {
813 
814  *fsp_limit = mach_read_from_4(
815  cp_buf + LOG_CHECKPOINT_FSP_FREE_LIMIT);
816 
817  if (*fsp_limit == 0) {
818  *fsp_limit = 1000000000;
819  }
820  } else {
821  *fsp_limit = 1000000000;
822  }
823 
824  /* fprintf(stderr, "fsp limit %lu MB\n", *fsp_limit); */
825 
826  *cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO);
827 
828  *first_header_lsn = mach_read_from_8(hdr + LOG_FILE_START_LSN);
829 
830  return(TRUE);
831 }
832 #endif /* !UNIV_HOTBACKUP */
833 
834 /******************************************************/
840 ibool
841 log_block_checksum_is_ok_or_old_format(
842 /*===================================*/
843  const byte* block)
844 {
845 #ifdef UNIV_LOG_DEBUG
846  return(TRUE);
847 #endif /* UNIV_LOG_DEBUG */
848  if (log_block_calc_checksum(block) == log_block_get_checksum(block)) {
849 
850  return(TRUE);
851  }
852 
853  if (log_block_get_hdr_no(block) == log_block_get_checksum(block)) {
854 
855  /* We assume the log block is in the format of
856  InnoDB version < 3.23.52 and the block is ok */
857 #if 0
858  fprintf(stderr,
859  "InnoDB: Scanned old format < InnoDB-3.23.52"
860  " log block number %lu\n",
861  log_block_get_hdr_no(block));
862 #endif
863  return(TRUE);
864  }
865 
866  return(FALSE);
867 }
868 
869 #ifdef UNIV_HOTBACKUP
870 /*******************************************************************/
873 UNIV_INTERN
874 void
875 recv_scan_log_seg_for_backup(
876 /*=========================*/
877  byte* buf,
878  ulint buf_len,
879  ib_uint64_t* scanned_lsn,
881  ulint* scanned_checkpoint_no,
885  ulint* n_bytes_scanned)
888 {
889  ulint data_len;
890  byte* log_block;
891  ulint no;
892 
893  *n_bytes_scanned = 0;
894 
895  for (log_block = buf; log_block < buf + buf_len;
896  log_block += OS_FILE_LOG_BLOCK_SIZE) {
897 
898  no = log_block_get_hdr_no(log_block);
899 
900 #if 0
901  fprintf(stderr, "Log block header no %lu\n", no);
902 #endif
903 
904  if (no != log_block_convert_lsn_to_no(*scanned_lsn)
905  || !log_block_checksum_is_ok_or_old_format(log_block)) {
906 #if 0
907  fprintf(stderr,
908  "Log block n:o %lu, scanned lsn n:o %lu\n",
909  no, log_block_convert_lsn_to_no(*scanned_lsn));
910 #endif
911  /* Garbage or an incompletely written log block */
912 
913  log_block += OS_FILE_LOG_BLOCK_SIZE;
914 #if 0
915  fprintf(stderr,
916  "Next log block n:o %lu\n",
917  log_block_get_hdr_no(log_block));
918 #endif
919  break;
920  }
921 
922  if (*scanned_checkpoint_no > 0
923  && log_block_get_checkpoint_no(log_block)
924  < *scanned_checkpoint_no
925  && *scanned_checkpoint_no
926  - log_block_get_checkpoint_no(log_block)
927  > 0x80000000UL) {
928 
929  /* Garbage from a log buffer flush which was made
930  before the most recent database recovery */
931 #if 0
932  fprintf(stderr,
933  "Scanned cp n:o %lu, block cp n:o %lu\n",
934  *scanned_checkpoint_no,
935  log_block_get_checkpoint_no(log_block));
936 #endif
937  break;
938  }
939 
940  data_len = log_block_get_data_len(log_block);
941 
942  *scanned_checkpoint_no
943  = log_block_get_checkpoint_no(log_block);
944  *scanned_lsn += data_len;
945 
946  *n_bytes_scanned += data_len;
947 
948  if (data_len < OS_FILE_LOG_BLOCK_SIZE) {
949  /* Log data ends here */
950 
951 #if 0
952  fprintf(stderr, "Log block data len %lu\n",
953  data_len);
954 #endif
955  break;
956  }
957  }
958 }
959 #endif /* UNIV_HOTBACKUP */
960 
961 /*******************************************************************/
965 static
966 byte*
967 recv_parse_or_apply_log_rec_body(
968 /*=============================*/
969  byte type,
970  byte* ptr,
971  byte* end_ptr,
972  buf_block_t* block,
976  mtr_t* mtr)
978 {
979  dict_index_t* index = NULL;
980  page_t* page;
981  page_zip_des_t* page_zip;
982 #ifdef UNIV_DEBUG
983  ulint page_type;
984 #endif /* UNIV_DEBUG */
985 
986  ut_ad(!block == !mtr);
987 
988  if (block) {
989  page = block->frame;
990  page_zip = buf_block_get_page_zip(block);
991  ut_d(page_type = fil_page_get_type(page));
992  } else {
993  page = NULL;
994  page_zip = NULL;
995  ut_d(page_type = FIL_PAGE_TYPE_ALLOCATED);
996  }
997 
998  switch (type) {
999 #ifdef UNIV_LOG_LSN_DEBUG
1000  case MLOG_LSN:
1001  /* The LSN is checked in recv_parse_log_rec(). */
1002  break;
1003 #endif /* UNIV_LOG_LSN_DEBUG */
1004  case MLOG_1BYTE: case MLOG_2BYTES: case MLOG_4BYTES: case MLOG_8BYTES:
1005 #ifdef UNIV_DEBUG
1006  if (page && page_type == FIL_PAGE_TYPE_ALLOCATED
1007  && end_ptr >= ptr + 2) {
1008  /* It is OK to set FIL_PAGE_TYPE and certain
1009  list node fields on an empty page. Any other
1010  write is not OK. */
1011 
1012  /* NOTE: There may be bogus assertion failures for
1013  dict_hdr_create(), trx_rseg_header_create(),
1014  trx_sys_create_doublewrite_buf(), and
1015  trx_sysf_create().
1016  These are only called during database creation. */
1017  ulint offs = mach_read_from_2(ptr);
1018 
1019  switch (type) {
1020  default:
1021  ut_error;
1022  case MLOG_2BYTES:
1023  /* Note that this can fail when the
1024  redo log been written with something
1025  older than InnoDB Plugin 1.0.4. */
1026  ut_ad(offs == FIL_PAGE_TYPE
1027  || offs == IBUF_TREE_SEG_HEADER
1028  + IBUF_HEADER + FSEG_HDR_OFFSET
1029  || offs == PAGE_BTR_IBUF_FREE_LIST
1030  + PAGE_HEADER + FIL_ADDR_BYTE
1031  || offs == PAGE_BTR_IBUF_FREE_LIST
1032  + PAGE_HEADER + FIL_ADDR_BYTE
1033  + FIL_ADDR_SIZE
1034  || offs == PAGE_BTR_SEG_LEAF
1035  + PAGE_HEADER + FSEG_HDR_OFFSET
1036  || offs == PAGE_BTR_SEG_TOP
1037  + PAGE_HEADER + FSEG_HDR_OFFSET
1038  || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
1039  + PAGE_HEADER + FIL_ADDR_BYTE
1040  + 0 /*FLST_PREV*/
1041  || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
1042  + PAGE_HEADER + FIL_ADDR_BYTE
1043  + FIL_ADDR_SIZE /*FLST_NEXT*/);
1044  break;
1045  case MLOG_4BYTES:
1046  /* Note that this can fail when the
1047  redo log been written with something
1048  older than InnoDB Plugin 1.0.4. */
1049  ut_ad(0
1050  || offs == IBUF_TREE_SEG_HEADER
1051  + IBUF_HEADER + FSEG_HDR_SPACE
1052  || offs == IBUF_TREE_SEG_HEADER
1053  + IBUF_HEADER + FSEG_HDR_PAGE_NO
1054  || offs == PAGE_BTR_IBUF_FREE_LIST
1055  + PAGE_HEADER/* flst_init */
1056  || offs == PAGE_BTR_IBUF_FREE_LIST
1057  + PAGE_HEADER + FIL_ADDR_PAGE
1058  || offs == PAGE_BTR_IBUF_FREE_LIST
1059  + PAGE_HEADER + FIL_ADDR_PAGE
1060  + FIL_ADDR_SIZE
1061  || offs == PAGE_BTR_SEG_LEAF
1062  + PAGE_HEADER + FSEG_HDR_PAGE_NO
1063  || offs == PAGE_BTR_SEG_LEAF
1064  + PAGE_HEADER + FSEG_HDR_SPACE
1065  || offs == PAGE_BTR_SEG_TOP
1066  + PAGE_HEADER + FSEG_HDR_PAGE_NO
1067  || offs == PAGE_BTR_SEG_TOP
1068  + PAGE_HEADER + FSEG_HDR_SPACE
1069  || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
1070  + PAGE_HEADER + FIL_ADDR_PAGE
1071  + 0 /*FLST_PREV*/
1072  || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
1073  + PAGE_HEADER + FIL_ADDR_PAGE
1074  + FIL_ADDR_SIZE /*FLST_NEXT*/);
1075  break;
1076  }
1077  }
1078 #endif /* UNIV_DEBUG */
1079  ptr = mlog_parse_nbytes(type, ptr, end_ptr, page, page_zip);
1080  break;
1082  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1083 
1084  if (NULL != (ptr = mlog_parse_index(
1085  ptr, end_ptr,
1086  type == MLOG_COMP_REC_INSERT,
1087  &index))) {
1088  ut_a(!page
1089  || (ibool)!!page_is_comp(page)
1090  == dict_table_is_comp(index->table));
1091  ptr = page_cur_parse_insert_rec(FALSE, ptr, end_ptr,
1092  block, index, mtr);
1093  }
1094  break;
1096  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1097 
1098  if (NULL != (ptr = mlog_parse_index(
1099  ptr, end_ptr,
1101  &index))) {
1102  ut_a(!page
1103  || (ibool)!!page_is_comp(page)
1104  == dict_table_is_comp(index->table));
1105  ptr = btr_cur_parse_del_mark_set_clust_rec(
1106  ptr, end_ptr, page, page_zip, index);
1107  }
1108  break;
1110  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1111  /* This log record type is obsolete, but we process it for
1112  backward compatibility with MySQL 5.0.3 and 5.0.4. */
1113  ut_a(!page || page_is_comp(page));
1114  ut_a(!page_zip);
1115  ptr = mlog_parse_index(ptr, end_ptr, TRUE, &index);
1116  if (!ptr) {
1117  break;
1118  }
1119  /* Fall through */
1121  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1122  ptr = btr_cur_parse_del_mark_set_sec_rec(ptr, end_ptr,
1123  page, page_zip);
1124  break;
1126  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1127 
1128  if (NULL != (ptr = mlog_parse_index(
1129  ptr, end_ptr,
1131  &index))) {
1132  ut_a(!page
1133  || (ibool)!!page_is_comp(page)
1134  == dict_table_is_comp(index->table));
1135  ptr = btr_cur_parse_update_in_place(ptr, end_ptr, page,
1136  page_zip, index);
1137  }
1138  break;
1141  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1142 
1143  if (NULL != (ptr = mlog_parse_index(
1144  ptr, end_ptr,
1146  || type == MLOG_COMP_LIST_START_DELETE,
1147  &index))) {
1148  ut_a(!page
1149  || (ibool)!!page_is_comp(page)
1150  == dict_table_is_comp(index->table));
1151  ptr = page_parse_delete_rec_list(type, ptr, end_ptr,
1152  block, index, mtr);
1153  }
1154  break;
1156  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1157 
1158  if (NULL != (ptr = mlog_parse_index(
1159  ptr, end_ptr,
1161  &index))) {
1162  ut_a(!page
1163  || (ibool)!!page_is_comp(page)
1164  == dict_table_is_comp(index->table));
1166  ptr, end_ptr, block, index, mtr);
1167  }
1168  break;
1170  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1171 
1172  if (NULL != (ptr = mlog_parse_index(
1173  ptr, end_ptr,
1174  type == MLOG_COMP_PAGE_REORGANIZE,
1175  &index))) {
1176  ut_a(!page
1177  || (ibool)!!page_is_comp(page)
1178  == dict_table_is_comp(index->table));
1179  ptr = btr_parse_page_reorganize(ptr, end_ptr, index,
1180  block, mtr);
1181  }
1182  break;
1184  /* Allow anything in page_type when creating a page. */
1185  ut_a(!page_zip);
1186  ptr = page_parse_create(ptr, end_ptr,
1187  type == MLOG_COMP_PAGE_CREATE,
1188  block, mtr);
1189  break;
1190  case MLOG_UNDO_INSERT:
1191  ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
1192  ptr = trx_undo_parse_add_undo_rec(ptr, end_ptr, page);
1193  break;
1194  case MLOG_UNDO_ERASE_END:
1195  ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
1196  ptr = trx_undo_parse_erase_page_end(ptr, end_ptr, page, mtr);
1197  break;
1198  case MLOG_UNDO_INIT:
1199  /* Allow anything in page_type when creating a page. */
1200  ptr = trx_undo_parse_page_init(ptr, end_ptr, page, mtr);
1201  break;
1202  case MLOG_UNDO_HDR_DISCARD:
1203  ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
1204  ptr = trx_undo_parse_discard_latest(ptr, end_ptr, page, mtr);
1205  break;
1206  case MLOG_UNDO_HDR_CREATE:
1207  case MLOG_UNDO_HDR_REUSE:
1208  ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
1209  ptr = trx_undo_parse_page_header(type, ptr, end_ptr,
1210  page, mtr);
1211  break;
1213  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1214  /* On a compressed page, MLOG_COMP_REC_MIN_MARK
1215  will be followed by MLOG_COMP_REC_DELETE
1216  or MLOG_ZIP_WRITE_HEADER(FIL_PAGE_PREV, FIL_NULL)
1217  in the same mini-transaction. */
1218  ut_a(type == MLOG_COMP_REC_MIN_MARK || !page_zip);
1219  ptr = btr_parse_set_min_rec_mark(
1220  ptr, end_ptr, type == MLOG_COMP_REC_MIN_MARK,
1221  page, mtr);
1222  break;
1224  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1225 
1226  if (NULL != (ptr = mlog_parse_index(
1227  ptr, end_ptr,
1228  type == MLOG_COMP_REC_DELETE,
1229  &index))) {
1230  ut_a(!page
1231  || (ibool)!!page_is_comp(page)
1232  == dict_table_is_comp(index->table));
1233  ptr = page_cur_parse_delete_rec(ptr, end_ptr,
1234  block, index, mtr);
1235  }
1236  break;
1237  case MLOG_IBUF_BITMAP_INIT:
1238  /* Allow anything in page_type when creating a page. */
1239  ptr = ibuf_parse_bitmap_init(ptr, end_ptr, block, mtr);
1240  break;
1241  case MLOG_INIT_FILE_PAGE:
1242  /* Allow anything in page_type when creating a page. */
1243  ptr = fsp_parse_init_file_page(ptr, end_ptr, block);
1244  break;
1245  case MLOG_WRITE_STRING:
1246  ut_ad(!page || page_type != FIL_PAGE_TYPE_ALLOCATED);
1247  ptr = mlog_parse_string(ptr, end_ptr, page, page_zip);
1248  break;
1249  case MLOG_FILE_CREATE:
1250  case MLOG_FILE_RENAME:
1251  case MLOG_FILE_DELETE:
1252  case MLOG_FILE_CREATE2:
1253  ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, 0, 0);
1254  break;
1256  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1257  ptr = page_zip_parse_write_node_ptr(ptr, end_ptr,
1258  page, page_zip);
1259  break;
1261  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1262  ptr = page_zip_parse_write_blob_ptr(ptr, end_ptr,
1263  page, page_zip);
1264  break;
1265  case MLOG_ZIP_WRITE_HEADER:
1266  ut_ad(!page || page_type == FIL_PAGE_INDEX);
1267  ptr = page_zip_parse_write_header(ptr, end_ptr,
1268  page, page_zip);
1269  break;
1271  /* Allow anything in page_type when creating a page. */
1272  ptr = page_zip_parse_compress(ptr, end_ptr,
1273  page, page_zip);
1274  break;
1275  default:
1276  ptr = NULL;
1277  recv_sys->found_corrupt_log = TRUE;
1278  }
1279 
1280  if (index) {
1281  dict_table_t* table = index->table;
1282 
1283  dict_mem_index_free(index);
1284  dict_mem_table_free(table);
1285  }
1286 
1287  return(ptr);
1288 }
1289 
1290 /*********************************************************************/
1294 UNIV_INLINE
1295 ulint
1296 recv_fold(
1297 /*======*/
1298  ulint space,
1299  ulint page_no)
1300 {
1301  return(ut_fold_ulint_pair(space, page_no));
1302 }
1303 
1304 /*********************************************************************/
1308 UNIV_INLINE
1309 ulint
1310 recv_hash(
1311 /*======*/
1312  ulint space,
1313  ulint page_no)
1314 {
1315  return(hash_calc_hash(recv_fold(space, page_no), recv_sys->addr_hash));
1316 }
1317 
1318 /*********************************************************************/
1321 static
1322 recv_addr_t*
1323 recv_get_fil_addr_struct(
1324 /*=====================*/
1325  ulint space,
1326  ulint page_no)
1327 {
1328  recv_addr_t* recv_addr;
1329 
1330  recv_addr = static_cast<recv_addr_t *>(HASH_GET_FIRST(recv_sys->addr_hash,
1331  recv_hash(space, page_no)));
1332  while (recv_addr) {
1333  if ((recv_addr->space == space)
1334  && (recv_addr->page_no == page_no)) {
1335 
1336  break;
1337  }
1338 
1339  recv_addr = static_cast<recv_addr_t *>(HASH_GET_NEXT(addr_hash, recv_addr));
1340  }
1341 
1342  return(recv_addr);
1343 }
1344 
1345 /*******************************************************************/
1347 static
1348 void
1349 recv_add_to_hash_table(
1350 /*===================*/
1351  byte type,
1352  ulint space,
1353  ulint page_no,
1354  byte* body,
1355  byte* rec_end,
1356  ib_uint64_t start_lsn,
1357  ib_uint64_t end_lsn)
1358 {
1359  recv_t* recv;
1360  ulint len;
1361  recv_data_t* recv_data;
1362  recv_data_t** prev_field;
1363  recv_addr_t* recv_addr;
1364 
1365  if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
1366  /* The tablespace does not exist any more: do not store the
1367  log record */
1368 
1369  return;
1370  }
1371 
1372  len = rec_end - body;
1373 
1374  recv = static_cast<recv_t *>(mem_heap_alloc(recv_sys->heap, sizeof(recv_t)));
1375  recv->type = type;
1376  recv->len = rec_end - body;
1377  recv->start_lsn = start_lsn;
1378  recv->end_lsn = end_lsn;
1379 
1380  recv_addr = recv_get_fil_addr_struct(space, page_no);
1381 
1382  if (recv_addr == NULL) {
1383  recv_addr = static_cast<recv_addr_t *>(mem_heap_alloc(recv_sys->heap,
1384  sizeof(recv_addr_t)));
1385  recv_addr->space = space;
1386  recv_addr->page_no = page_no;
1387  recv_addr->state = RECV_NOT_PROCESSED;
1388 
1389  UT_LIST_INIT(recv_addr->rec_list);
1390 
1392  recv_fold(space, page_no), recv_addr);
1393  recv_sys->n_addrs++;
1394 #if 0
1395  fprintf(stderr, "Inserting log rec for space %lu, page %lu\n",
1396  space, page_no);
1397 #endif
1398  }
1399 
1400  UT_LIST_ADD_LAST(rec_list, recv_addr->rec_list, recv);
1401 
1402  prev_field = &(recv->data);
1403 
1404  /* Store the log record body in chunks of less than UNIV_PAGE_SIZE:
1405  recv_sys->heap grows into the buffer pool, and bigger chunks could not
1406  be allocated */
1407 
1408  while (rec_end > body) {
1409 
1410  len = rec_end - body;
1411 
1412  if (len > RECV_DATA_BLOCK_SIZE) {
1413  len = RECV_DATA_BLOCK_SIZE;
1414  }
1415 
1416  recv_data = static_cast<recv_data_t *>(mem_heap_alloc(recv_sys->heap,
1417  sizeof(recv_data_t) + len));
1418  *prev_field = recv_data;
1419 
1420  memcpy(recv_data + 1, body, len);
1421 
1422  prev_field = &(recv_data->next);
1423 
1424  body += len;
1425  }
1426 
1427  *prev_field = NULL;
1428 }
1429 
1430 /*********************************************************************/
1432 static
1433 void
1434 recv_data_copy_to_buf(
1435 /*==================*/
1436  byte* buf,
1437  recv_t* recv)
1438 {
1439  recv_data_t* recv_data;
1440  ulint part_len;
1441  ulint len;
1442 
1443  len = recv->len;
1444  recv_data = recv->data;
1445 
1446  while (len > 0) {
1447  if (len > RECV_DATA_BLOCK_SIZE) {
1448  part_len = RECV_DATA_BLOCK_SIZE;
1449  } else {
1450  part_len = len;
1451  }
1452 
1453  ut_memcpy(buf, ((byte*)recv_data) + sizeof(recv_data_t),
1454  part_len);
1455  buf += part_len;
1456  len -= part_len;
1457 
1458  recv_data = recv_data->next;
1459  }
1460 }
1461 
1462 /************************************************************************/
1466 UNIV_INTERN
1467 void
1469 /*===================*/
1470 #ifndef UNIV_HOTBACKUP
1471  ibool just_read_in,
1474 #endif /* !UNIV_HOTBACKUP */
1475  buf_block_t* block)
1476 {
1477  page_t* page;
1478  page_zip_des_t* page_zip;
1479  recv_addr_t* recv_addr;
1480  recv_t* recv;
1481  byte* buf;
1482  ib_uint64_t start_lsn;
1483  ib_uint64_t end_lsn;
1484  ib_uint64_t page_lsn;
1485  ib_uint64_t page_newest_lsn;
1486  ibool modification_to_page;
1487 #ifndef UNIV_HOTBACKUP
1488  ibool success;
1489 #endif /* !UNIV_HOTBACKUP */
1490  mtr_t mtr;
1491 
1492  mutex_enter(&(recv_sys->mutex));
1493 
1494  if (recv_sys->apply_log_recs == FALSE) {
1495 
1496  /* Log records should not be applied now */
1497 
1498  mutex_exit(&(recv_sys->mutex));
1499 
1500  return;
1501  }
1502 
1503  recv_addr = recv_get_fil_addr_struct(buf_block_get_space(block),
1504  buf_block_get_page_no(block));
1505 
1506  if ((recv_addr == NULL)
1507  || (recv_addr->state == RECV_BEING_PROCESSED)
1508  || (recv_addr->state == RECV_PROCESSED)) {
1509 
1510  mutex_exit(&(recv_sys->mutex));
1511 
1512  return;
1513  }
1514 
1515 #if 0
1516  fprintf(stderr, "Recovering space %lu, page %lu\n",
1518 #endif
1519 
1520  recv_addr->state = RECV_BEING_PROCESSED;
1521 
1522  mutex_exit(&(recv_sys->mutex));
1523 
1524  mtr_start(&mtr);
1525  mtr_set_log_mode(&mtr, MTR_LOG_NONE);
1526 
1527  page = block->frame;
1528  page_zip = buf_block_get_page_zip(block);
1529 
1530 #ifndef UNIV_HOTBACKUP
1531  if (just_read_in) {
1532  /* Move the ownership of the x-latch on the page to
1533  this OS thread, so that we can acquire a second
1534  x-latch on it. This is needed for the operations to
1535  the page to pass the debug checks. */
1536 
1537  rw_lock_x_lock_move_ownership(&block->lock);
1538  }
1539 
1540  success = buf_page_get_known_nowait(RW_X_LATCH, block,
1541  BUF_KEEP_OLD,
1542  __FILE__, __LINE__,
1543  &mtr);
1544  ut_a(success);
1545 
1546  buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
1547 #endif /* !UNIV_HOTBACKUP */
1548 
1549  /* Read the newest modification lsn from the page */
1550  page_lsn = mach_read_from_8(page + FIL_PAGE_LSN);
1551 
1552 #ifndef UNIV_HOTBACKUP
1553  /* It may be that the page has been modified in the buffer
1554  pool: read the newest modification lsn there */
1555 
1556  page_newest_lsn = buf_page_get_newest_modification(&block->page);
1557 
1558  if (page_newest_lsn) {
1559 
1560  page_lsn = page_newest_lsn;
1561  }
1562 #else /* !UNIV_HOTBACKUP */
1563  /* In recovery from a backup we do not really use the buffer pool */
1564  page_newest_lsn = 0;
1565 #endif /* !UNIV_HOTBACKUP */
1566 
1567  modification_to_page = FALSE;
1568  start_lsn = end_lsn = 0;
1569 
1570  recv = UT_LIST_GET_FIRST(recv_addr->rec_list);
1571 
1572  while (recv) {
1573  end_lsn = recv->end_lsn;
1574 
1575  if (recv->len > RECV_DATA_BLOCK_SIZE) {
1576  /* We have to copy the record body to a separate
1577  buffer */
1578 
1579  buf = static_cast<byte *>(mem_alloc(recv->len));
1580 
1581  recv_data_copy_to_buf(buf, recv);
1582  } else {
1583  buf = ((byte*)(recv->data)) + sizeof(recv_data_t);
1584  }
1585 
1586  if (recv->type == MLOG_INIT_FILE_PAGE) {
1587  page_lsn = page_newest_lsn;
1588 
1589  memset(FIL_PAGE_LSN + page, 0, 8);
1590  memset(UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM
1591  + page, 0, 8);
1592 
1593  if (page_zip) {
1594  memset(FIL_PAGE_LSN + page_zip->data, 0, 8);
1595  }
1596  }
1597 
1598  if (recv->start_lsn >= page_lsn) {
1599 
1600  ib_uint64_t page_end_lsn;
1601 
1602  if (!modification_to_page) {
1603 
1604  modification_to_page = TRUE;
1605  start_lsn = recv->start_lsn;
1606  }
1607 
1608 #ifdef UNIV_DEBUG
1609  if (log_debug_writes) {
1610  fprintf(stderr,
1611  "InnoDB: Applying log rec"
1612  " type %lu len %lu"
1613  " to space %lu page no %lu\n",
1614  (ulong) recv->type, (ulong) recv->len,
1615  (ulong) recv_addr->space,
1616  (ulong) recv_addr->page_no);
1617  }
1618 #endif /* UNIV_DEBUG */
1619 
1620  recv_parse_or_apply_log_rec_body(recv->type, buf,
1621  buf + recv->len,
1622  block, &mtr);
1623 
1624  page_end_lsn = recv->start_lsn + recv->len;
1625  mach_write_to_8(FIL_PAGE_LSN + page, page_end_lsn);
1626  mach_write_to_8(UNIV_PAGE_SIZE
1628  + page, page_end_lsn);
1629 
1630  if (page_zip) {
1632  + page_zip->data, page_end_lsn);
1633  }
1634  }
1635 
1636  if (recv->len > RECV_DATA_BLOCK_SIZE) {
1637  mem_free(buf);
1638  }
1639 
1640  recv = UT_LIST_GET_NEXT(rec_list, recv);
1641  }
1642 
1643 #ifdef UNIV_ZIP_DEBUG
1644  if (fil_page_get_type(page) == FIL_PAGE_INDEX) {
1645  page_zip_des_t* page_zip = buf_block_get_page_zip(block);
1646 
1647  if (page_zip) {
1648  ut_a(page_zip_validate_low(page_zip, page, FALSE));
1649  }
1650  }
1651 #endif /* UNIV_ZIP_DEBUG */
1652 
1653  mutex_enter(&(recv_sys->mutex));
1654 
1655  if (recv_max_page_lsn < page_lsn) {
1656  recv_max_page_lsn = page_lsn;
1657  }
1658 
1659  recv_addr->state = RECV_PROCESSED;
1660 
1661  ut_a(recv_sys->n_addrs);
1662  recv_sys->n_addrs--;
1663 
1664  mutex_exit(&(recv_sys->mutex));
1665 
1666 #ifndef UNIV_HOTBACKUP
1667  if (modification_to_page) {
1668  ut_a(block);
1669 
1671  buf_flush_recv_note_modification(block, start_lsn, end_lsn);
1673  }
1674 #endif /* !UNIV_HOTBACKUP */
1675 
1676  /* Make sure that committing mtr does not change the modification
1677  lsn values of page */
1678 
1679  mtr.modifications = FALSE;
1680 
1681  mtr_commit(&mtr);
1682 }
1683 
1684 #ifndef UNIV_HOTBACKUP
1685 /*******************************************************************/
1689 static
1690 ulint
1691 recv_read_in_area(
1692 /*==============*/
1693  ulint space,
1694  ulint zip_size,
1695  ulint page_no)
1696 {
1697  recv_addr_t* recv_addr;
1698  ulint page_nos[RECV_READ_AHEAD_AREA];
1699  ulint low_limit;
1700  ulint n;
1701 
1702  low_limit = page_no - (page_no % RECV_READ_AHEAD_AREA);
1703 
1704  n = 0;
1705 
1706  for (page_no = low_limit; page_no < low_limit + RECV_READ_AHEAD_AREA;
1707  page_no++) {
1708  recv_addr = recv_get_fil_addr_struct(space, page_no);
1709 
1710  if (recv_addr && !buf_page_peek(space, page_no)) {
1711 
1712  mutex_enter(&(recv_sys->mutex));
1713 
1714  if (recv_addr->state == RECV_NOT_PROCESSED) {
1715  recv_addr->state = RECV_BEING_READ;
1716 
1717  page_nos[n] = page_no;
1718 
1719  n++;
1720  }
1721 
1722  mutex_exit(&(recv_sys->mutex));
1723  }
1724  }
1725 
1726  buf_read_recv_pages(FALSE, space, zip_size, page_nos, n);
1727  /*
1728  fprintf(stderr, "Recv pages at %lu n %lu\n", page_nos[0], n);
1729  */
1730  return(n);
1731 }
1732 
1733 /*******************************************************************/
1736 UNIV_INTERN
1737 void
1739 /*=======================*/
1740  ibool allow_ibuf)
1749 {
1750  recv_addr_t* recv_addr;
1751  ulint i;
1752  ulint n_pages;
1753  ibool has_printed = FALSE;
1754  mtr_t mtr;
1755 loop:
1756  mutex_enter(&(recv_sys->mutex));
1757 
1758  if (recv_sys->apply_batch_on) {
1759 
1760  mutex_exit(&(recv_sys->mutex));
1761 
1762  os_thread_sleep(500000);
1763 
1764  goto loop;
1765  }
1766 
1767  ut_ad(!allow_ibuf == mutex_own(&log_sys->mutex));
1768 
1769  if (!allow_ibuf) {
1770  recv_no_ibuf_operations = TRUE;
1771  }
1772 
1773  recv_sys->apply_log_recs = TRUE;
1774  recv_sys->apply_batch_on = TRUE;
1775 
1776  for (i = 0; i < hash_get_n_cells(recv_sys->addr_hash); i++) {
1777 
1778  recv_addr = static_cast<recv_addr_t *>(HASH_GET_FIRST(recv_sys->addr_hash, i));
1779 
1780  while (recv_addr) {
1781  ulint space = recv_addr->space;
1782  ulint zip_size = fil_space_get_zip_size(space);
1783  ulint page_no = recv_addr->page_no;
1784 
1785  if (recv_addr->state == RECV_NOT_PROCESSED) {
1786  if (!has_printed) {
1787  ut_print_timestamp(stderr);
1788  fputs(" InnoDB: Starting an"
1789  " apply batch of log records"
1790  " to the database...\n"
1791  "InnoDB: Progress in percents: ",
1792  stderr);
1793  has_printed = TRUE;
1794  }
1795 
1796  mutex_exit(&(recv_sys->mutex));
1797 
1798  if (buf_page_peek(space, page_no)) {
1799  buf_block_t* block;
1800 
1801  mtr_start(&mtr);
1802 
1803  block = buf_page_get(
1804  space, zip_size, page_no,
1805  RW_X_LATCH, &mtr);
1806  buf_block_dbg_add_level(
1807  block, SYNC_NO_ORDER_CHECK);
1808 
1809  recv_recover_page(FALSE, block);
1810  mtr_commit(&mtr);
1811  } else {
1812  recv_read_in_area(space, zip_size,
1813  page_no);
1814  }
1815 
1816  mutex_enter(&(recv_sys->mutex));
1817  }
1818 
1819  recv_addr = static_cast<recv_addr_t *>(HASH_GET_NEXT(addr_hash, recv_addr));
1820  }
1821 
1822  if (has_printed
1823  && (i * 100) / hash_get_n_cells(recv_sys->addr_hash)
1824  != ((i + 1) * 100)
1826 
1827  fprintf(stderr, "%lu ", (ulong)
1828  ((i * 100)
1830  }
1831  }
1832 
1833  /* Wait until all the pages have been processed */
1834 
1835  while (recv_sys->n_addrs != 0) {
1836 
1837  mutex_exit(&(recv_sys->mutex));
1838 
1839  os_thread_sleep(500000);
1840 
1841  mutex_enter(&(recv_sys->mutex));
1842  }
1843 
1844  if (has_printed) {
1845 
1846  fprintf(stderr, "\n");
1847  }
1848 
1849  if (!allow_ibuf) {
1850  /* Flush all the file pages to disk and invalidate them in
1851  the buffer pool */
1852 
1853  ut_d(recv_no_log_write = TRUE);
1854  mutex_exit(&(recv_sys->mutex));
1855  mutex_exit(&(log_sys->mutex));
1856 
1857  n_pages = buf_flush_list(ULINT_MAX, IB_ULONGLONG_MAX);
1858  ut_a(n_pages != ULINT_UNDEFINED);
1859 
1860  buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
1861 
1862  buf_pool_invalidate();
1863 
1864  mutex_enter(&(log_sys->mutex));
1865  mutex_enter(&(recv_sys->mutex));
1866  ut_d(recv_no_log_write = FALSE);
1867 
1868  recv_no_ibuf_operations = FALSE;
1869  }
1870 
1871  recv_sys->apply_log_recs = FALSE;
1872  recv_sys->apply_batch_on = FALSE;
1873 
1874  recv_sys_empty_hash();
1875 
1876  if (has_printed) {
1877  fprintf(stderr, "InnoDB: Apply batch completed\n");
1878  }
1879 
1880  mutex_exit(&(recv_sys->mutex));
1881 }
1882 #else /* !UNIV_HOTBACKUP */
1883 /*******************************************************************/
1885 UNIV_INTERN
1886 void
1887 recv_apply_log_recs_for_backup(void)
1888 /*================================*/
1889 {
1890  recv_addr_t* recv_addr;
1891  ulint n_hash_cells;
1892  buf_block_t* block;
1893  ulint actual_size;
1894  ibool success;
1895  ulint error;
1896  ulint i;
1897 
1898  recv_sys->apply_log_recs = TRUE;
1899  recv_sys->apply_batch_on = TRUE;
1900 
1901  block = back_block1;
1902 
1903  fputs("InnoDB: Starting an apply batch of log records"
1904  " to the database...\n"
1905  "InnoDB: Progress in percents: ", stderr);
1906 
1907  n_hash_cells = hash_get_n_cells(recv_sys->addr_hash);
1908 
1909  for (i = 0; i < n_hash_cells; i++) {
1910  /* The address hash table is externally chained */
1911  recv_addr = hash_get_nth_cell(recv_sys->addr_hash, i)->node;
1912 
1913  while (recv_addr != NULL) {
1914 
1915  ulint zip_size
1916  = fil_space_get_zip_size(recv_addr->space);
1917 
1918  if (zip_size == ULINT_UNDEFINED) {
1919 #if 0
1920  fprintf(stderr,
1921  "InnoDB: Warning: cannot apply"
1922  " log record to"
1923  " tablespace %lu page %lu,\n"
1924  "InnoDB: because tablespace with"
1925  " that id does not exist.\n",
1926  recv_addr->space, recv_addr->page_no);
1927 #endif
1928  recv_addr->state = RECV_PROCESSED;
1929 
1930  ut_a(recv_sys->n_addrs);
1931  recv_sys->n_addrs--;
1932 
1933  goto skip_this_recv_addr;
1934  }
1935 
1936  /* We simulate a page read made by the buffer pool, to
1937  make sure the recovery apparatus works ok. We must init
1938  the block. */
1939 
1940  buf_page_init_for_backup_restore(
1941  recv_addr->space, recv_addr->page_no,
1942  zip_size, block);
1943 
1944  /* Extend the tablespace's last file if the page_no
1945  does not fall inside its bounds; we assume the last
1946  file is auto-extending, and ibbackup copied the file
1947  when it still was smaller */
1948 
1949  success = fil_extend_space_to_desired_size(
1950  &actual_size,
1951  recv_addr->space, recv_addr->page_no + 1);
1952  if (!success) {
1953  fprintf(stderr,
1954  "InnoDB: Fatal error: cannot extend"
1955  " tablespace %lu to hold %lu pages\n",
1956  recv_addr->space, recv_addr->page_no);
1957 
1958  exit(1);
1959  }
1960 
1961  /* Read the page from the tablespace file using the
1962  fil0fil.c routines */
1963 
1964  if (zip_size) {
1965  error = fil_io(OS_FILE_READ, TRUE,
1966  recv_addr->space, zip_size,
1967  recv_addr->page_no, 0, zip_size,
1968  block->page.zip.data, NULL);
1969  if (error == DB_SUCCESS
1970  && !buf_zip_decompress(block, TRUE)) {
1971  exit(1);
1972  }
1973  } else {
1974  error = fil_io(OS_FILE_READ, TRUE,
1975  recv_addr->space, 0,
1976  recv_addr->page_no, 0,
1977  UNIV_PAGE_SIZE,
1978  block->frame, NULL);
1979  }
1980 
1981  if (error != DB_SUCCESS) {
1982  fprintf(stderr,
1983  "InnoDB: Fatal error: cannot read"
1984  " from tablespace"
1985  " %lu page number %lu\n",
1986  (ulong) recv_addr->space,
1987  (ulong) recv_addr->page_no);
1988 
1989  exit(1);
1990  }
1991 
1992  /* Apply the log records to this page */
1993  recv_recover_page(FALSE, block);
1994 
1995  /* Write the page back to the tablespace file using the
1996  fil0fil.c routines */
1997 
1998  buf_flush_init_for_writing(
1999  block->frame, buf_block_get_page_zip(block),
2000  mach_read_from_8(block->frame + FIL_PAGE_LSN));
2001 
2002  if (zip_size) {
2003  error = fil_io(OS_FILE_WRITE, TRUE,
2004  recv_addr->space, zip_size,
2005  recv_addr->page_no, 0,
2006  zip_size,
2007  block->page.zip.data, NULL);
2008  } else {
2009  error = fil_io(OS_FILE_WRITE, TRUE,
2010  recv_addr->space, 0,
2011  recv_addr->page_no, 0,
2012  UNIV_PAGE_SIZE,
2013  block->frame, NULL);
2014  }
2015 skip_this_recv_addr:
2016  recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
2017  }
2018 
2019  if ((100 * i) / n_hash_cells
2020  != (100 * (i + 1)) / n_hash_cells) {
2021  fprintf(stderr, "%lu ",
2022  (ulong) ((100 * i) / n_hash_cells));
2023  fflush(stderr);
2024  }
2025  }
2026 
2027  recv_sys_empty_hash();
2028 }
2029 #endif /* !UNIV_HOTBACKUP */
2030 
2031 /*******************************************************************/
2034 static
2035 ulint
2036 recv_parse_log_rec(
2037 /*===============*/
2038  byte* ptr,
2039  byte* end_ptr,
2040  byte* type,
2041  ulint* space,
2042  ulint* page_no,
2043  byte** body)
2044 {
2045  byte* new_ptr;
2046 
2047  *body = NULL;
2048 
2049  if (ptr == end_ptr) {
2050 
2051  return(0);
2052  }
2053 
2054  if (*ptr == MLOG_MULTI_REC_END) {
2055 
2056  *type = *ptr;
2057 
2058  return(1);
2059  }
2060 
2061  if (*ptr == MLOG_DUMMY_RECORD) {
2062  *type = *ptr;
2063 
2064  *space = ULINT_UNDEFINED - 1; /* For debugging */
2065 
2066  return(1);
2067  }
2068 
2069  new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space,
2070  page_no);
2071  *body = new_ptr;
2072 
2073  if (UNIV_UNLIKELY(!new_ptr)) {
2074 
2075  return(0);
2076  }
2077 
2078 #ifdef UNIV_LOG_LSN_DEBUG
2079  if (*type == MLOG_LSN) {
2080  ib_uint64_t lsn = (ib_uint64_t) *space << 32 | *page_no;
2081 # ifdef UNIV_LOG_DEBUG
2082  ut_a(lsn == log_sys->old_lsn);
2083 # else /* UNIV_LOG_DEBUG */
2084  ut_a(lsn == recv_sys->recovered_lsn);
2085 # endif /* UNIV_LOG_DEBUG */
2086  }
2087 #endif /* UNIV_LOG_LSN_DEBUG */
2088 
2089  new_ptr = recv_parse_or_apply_log_rec_body(*type, new_ptr, end_ptr,
2090  NULL, NULL);
2091  if (UNIV_UNLIKELY(new_ptr == NULL)) {
2092 
2093  return(0);
2094  }
2095 
2096  if (*page_no > recv_max_parsed_page_no) {
2097  recv_max_parsed_page_no = *page_no;
2098  }
2099 
2100  return(new_ptr - ptr);
2101 }
2102 
2103 /*******************************************************/
2105 static
2106 ib_uint64_t
2107 recv_calc_lsn_on_data_add(
2108 /*======================*/
2109  ib_uint64_t lsn,
2110  ib_uint64_t len)
2112 {
2113  ulint frag_len;
2114  ulint lsn_len;
2115 
2116  frag_len = (((ulint) lsn) % OS_FILE_LOG_BLOCK_SIZE)
2117  - LOG_BLOCK_HDR_SIZE;
2118  ut_ad(frag_len < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE
2119  - LOG_BLOCK_TRL_SIZE);
2120  lsn_len = (ulint) len;
2121  lsn_len += (lsn_len + frag_len)
2122  / (OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE
2123  - LOG_BLOCK_TRL_SIZE)
2124  * (LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE);
2125 
2126  return(lsn + lsn_len);
2127 }
2128 
2129 #ifdef UNIV_LOG_DEBUG
2130 /*******************************************************/
2133 static
2134 void
2135 recv_check_incomplete_log_recs(
2136 /*===========================*/
2137  byte* ptr,
2138  ulint len)
2139 {
2140  ulint i;
2141  byte type;
2142  ulint space;
2143  ulint page_no;
2144  byte* body;
2145 
2146  for (i = 0; i < len; i++) {
2147  ut_a(0 == recv_parse_log_rec(ptr, ptr + i, &type, &space,
2148  &page_no, &body));
2149  }
2150 }
2151 #endif /* UNIV_LOG_DEBUG */
2152 
2153 /*******************************************************/
2155 static
2156 void
2157 recv_report_corrupt_log(
2158 /*====================*/
2159  byte* ptr,
2160  byte type,
2161  ulint space,
2162  ulint page_no)
2163 {
2164  fprintf(stderr,
2165  "InnoDB: ############### CORRUPT LOG RECORD FOUND\n"
2166  "InnoDB: Log record type %lu, space id %lu, page number %lu\n"
2167  "InnoDB: Log parsing proceeded successfully up to %"PRIu64"\n"
2168  "InnoDB: Previous log record type %lu, is multi %lu\n"
2169  "InnoDB: Recv offset %lu, prev %lu\n",
2170  (ulong) type, (ulong) space, (ulong) page_no,
2172  (ulong) recv_previous_parsed_rec_type,
2173  (ulong) recv_previous_parsed_rec_is_multi,
2174  (ulong) (ptr - recv_sys->buf),
2175  (ulong) recv_previous_parsed_rec_offset);
2176 
2177  if ((ulint)(ptr - recv_sys->buf + 100)
2178  > recv_previous_parsed_rec_offset
2179  && (ulint)(ptr - recv_sys->buf + 100
2180  - recv_previous_parsed_rec_offset)
2181  < 200000) {
2182  fputs("InnoDB: Hex dump of corrupt log starting"
2183  " 100 bytes before the start\n"
2184  "InnoDB: of the previous log rec,\n"
2185  "InnoDB: and ending 100 bytes after the start"
2186  " of the corrupt rec:\n",
2187  stderr);
2188 
2189  ut_print_buf(stderr,
2190  recv_sys->buf
2191  + recv_previous_parsed_rec_offset - 100,
2192  ptr - recv_sys->buf + 200
2193  - recv_previous_parsed_rec_offset);
2194  putc('\n', stderr);
2195  }
2196 
2197 #ifndef UNIV_HOTBACKUP
2198  if (!srv_force_recovery) {
2199  fputs("InnoDB: Set innodb_force_recovery"
2200  " to ignore this error.\n", stderr);
2201  ut_error;
2202  }
2203 #endif /* !UNIV_HOTBACKUP */
2204 
2205  fputs("InnoDB: WARNING: the log file may have been corrupt and it\n"
2206  "InnoDB: is possible that the log scan did not proceed\n"
2207  "InnoDB: far enough in recovery! Please run CHECK TABLE\n"
2208  "InnoDB: on your InnoDB tables to check that they are ok!\n"
2209  "InnoDB: If mysqld crashes after this recovery, look at\n"
2210  "InnoDB: " REFMAN "forcing-recovery.html\n"
2211  "InnoDB: about forcing recovery.\n", stderr);
2212 
2213  fflush(stderr);
2214 }
2215 
2216 /*******************************************************/
2220 static
2221 ibool
2222 recv_parse_log_recs(
2223 /*================*/
2224  ibool store_to_hash)
2227 {
2228  byte* ptr;
2229  byte* end_ptr;
2230  ulint single_rec;
2231  ulint len;
2232  ulint total_len;
2233  ib_uint64_t new_recovered_lsn;
2234  ib_uint64_t old_lsn;
2235  byte type;
2236  ulint space;
2237  ulint page_no;
2238  byte* body;
2239  ulint n_recs;
2240 
2241  ut_ad(mutex_own(&(log_sys->mutex)));
2243 loop:
2245 
2246  end_ptr = recv_sys->buf + recv_sys->len;
2247 
2248  if (ptr == end_ptr) {
2249 
2250  return(FALSE);
2251  }
2252 
2253  single_rec = (ulint)*ptr & MLOG_SINGLE_REC_FLAG;
2254 
2255  if (single_rec || *ptr == MLOG_DUMMY_RECORD) {
2256  /* The mtr only modified a single page, or this is a file op */
2257 
2258  old_lsn = recv_sys->recovered_lsn;
2259 
2260  /* Try to parse a log record, fetching its type, space id,
2261  page no, and a pointer to the body of the log record */
2262 
2263  len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
2264  &page_no, &body);
2265 
2266  if (len == 0 || recv_sys->found_corrupt_log) {
2267  if (recv_sys->found_corrupt_log) {
2268 
2269  recv_report_corrupt_log(ptr,
2270  type, space, page_no);
2271  }
2272 
2273  return(FALSE);
2274  }
2275 
2276  new_recovered_lsn = recv_calc_lsn_on_data_add(old_lsn, len);
2277 
2278  if (new_recovered_lsn > recv_sys->scanned_lsn) {
2279  /* The log record filled a log block, and we require
2280  that also the next log block should have been scanned
2281  in */
2282 
2283  return(FALSE);
2284  }
2285 
2286  recv_previous_parsed_rec_type = (ulint)type;
2287  recv_previous_parsed_rec_offset = recv_sys->recovered_offset;
2288  recv_previous_parsed_rec_is_multi = 0;
2289 
2290  recv_sys->recovered_offset += len;
2291  recv_sys->recovered_lsn = new_recovered_lsn;
2292 
2293 #ifdef UNIV_DEBUG
2294  if (log_debug_writes) {
2295  fprintf(stderr,
2296  "InnoDB: Parsed a single log rec"
2297  " type %lu len %lu space %lu page no %lu\n",
2298  (ulong) type, (ulong) len, (ulong) space,
2299  (ulong) page_no);
2300  }
2301 #endif /* UNIV_DEBUG */
2302 
2303  if (type == MLOG_DUMMY_RECORD) {
2304  /* Do nothing */
2305 
2306  } else if (!store_to_hash) {
2307  /* In debug checking, update a replicate page
2308  according to the log record, and check that it
2309  becomes identical with the original page */
2310 #ifdef UNIV_LOG_DEBUG
2311  recv_check_incomplete_log_recs(ptr, len);
2312 #endif/* UNIV_LOG_DEBUG */
2313 
2314  } else if (type == MLOG_FILE_CREATE
2315  || type == MLOG_FILE_CREATE2
2316  || type == MLOG_FILE_RENAME
2317  || type == MLOG_FILE_DELETE) {
2318  ut_a(space);
2319 #ifdef UNIV_HOTBACKUP
2320  if (recv_replay_file_ops) {
2321 
2322  /* In ibbackup --apply-log, replay an .ibd file
2323  operation, if possible; note that
2324  fil_path_to_mysql_datadir is set in ibbackup to
2325  point to the datadir we should use there */
2326 
2327  if (NULL == fil_op_log_parse_or_replay(
2328  body, end_ptr, type,
2329  space, page_no)) {
2330  fprintf(stderr,
2331  "InnoDB: Error: file op"
2332  " log record of type %lu"
2333  " space %lu not complete in\n"
2334  "InnoDB: the replay phase."
2335  " Path %s\n",
2336  (ulint)type, space,
2337  (char*)(body + 2));
2338 
2339  ut_error;
2340  }
2341  }
2342 #endif
2343  /* In normal mysqld crash recovery we do not try to
2344  replay file operations */
2345 #ifdef UNIV_LOG_LSN_DEBUG
2346  } else if (type == MLOG_LSN) {
2347  /* Do not add these records to the hash table.
2348  The page number and space id fields are misused
2349  for something else. */
2350 #endif /* UNIV_LOG_LSN_DEBUG */
2351  } else {
2352  recv_add_to_hash_table(type, space, page_no, body,
2353  ptr + len, old_lsn,
2355  }
2356  } else {
2357  /* Check that all the records associated with the single mtr
2358  are included within the buffer */
2359 
2360  total_len = 0;
2361  n_recs = 0;
2362 
2363  for (;;) {
2364  len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
2365  &page_no, &body);
2366  if (len == 0 || recv_sys->found_corrupt_log) {
2367 
2368  if (recv_sys->found_corrupt_log) {
2369 
2370  recv_report_corrupt_log(
2371  ptr, type, space, page_no);
2372  }
2373 
2374  return(FALSE);
2375  }
2376 
2377  recv_previous_parsed_rec_type = (ulint)type;
2378  recv_previous_parsed_rec_offset
2379  = recv_sys->recovered_offset + total_len;
2380  recv_previous_parsed_rec_is_multi = 1;
2381 
2382 #ifdef UNIV_LOG_DEBUG
2383  if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) {
2384  recv_check_incomplete_log_recs(ptr, len);
2385  }
2386 #endif /* UNIV_LOG_DEBUG */
2387 
2388 #ifdef UNIV_DEBUG
2389  if (log_debug_writes) {
2390  fprintf(stderr,
2391  "InnoDB: Parsed a multi log rec"
2392  " type %lu len %lu"
2393  " space %lu page no %lu\n",
2394  (ulong) type, (ulong) len,
2395  (ulong) space, (ulong) page_no);
2396  }
2397 #endif /* UNIV_DEBUG */
2398 
2399  total_len += len;
2400  n_recs++;
2401 
2402  ptr += len;
2403 
2404  if (type == MLOG_MULTI_REC_END) {
2405 
2406  /* Found the end mark for the records */
2407 
2408  break;
2409  }
2410  }
2411 
2412  new_recovered_lsn = recv_calc_lsn_on_data_add(
2413  recv_sys->recovered_lsn, total_len);
2414 
2415  if (new_recovered_lsn > recv_sys->scanned_lsn) {
2416  /* The log record filled a log block, and we require
2417  that also the next log block should have been scanned
2418  in */
2419 
2420  return(FALSE);
2421  }
2422 
2423  /* Add all the records to the hash table */
2424 
2426 
2427  for (;;) {
2428  old_lsn = recv_sys->recovered_lsn;
2429  len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
2430  &page_no, &body);
2431  if (recv_sys->found_corrupt_log) {
2432 
2433  recv_report_corrupt_log(ptr,
2434  type, space, page_no);
2435  }
2436 
2437  ut_a(len != 0);
2438  ut_a(0 == ((ulint)*ptr & MLOG_SINGLE_REC_FLAG));
2439 
2440  recv_sys->recovered_offset += len;
2442  = recv_calc_lsn_on_data_add(old_lsn, len);
2443  if (type == MLOG_MULTI_REC_END) {
2444 
2445  /* Found the end mark for the records */
2446 
2447  break;
2448  }
2449 
2450  if (store_to_hash
2451 #ifdef UNIV_LOG_LSN_DEBUG
2452  && type != MLOG_LSN
2453 #endif /* UNIV_LOG_LSN_DEBUG */
2454  ) {
2455  recv_add_to_hash_table(type, space, page_no,
2456  body, ptr + len,
2457  old_lsn,
2458  new_recovered_lsn);
2459  }
2460 
2461  ptr += len;
2462  }
2463  }
2464 
2465  goto loop;
2466 }
2467 
2468 /*******************************************************/
2472 static
2473 ibool
2474 recv_sys_add_to_parsing_buf(
2475 /*========================*/
2476  const byte* log_block,
2477  ib_uint64_t scanned_lsn)
2479 {
2480  ulint more_len;
2481  ulint data_len;
2482  ulint start_offset;
2483  ulint end_offset;
2484 
2485  ut_ad(scanned_lsn >= recv_sys->scanned_lsn);
2486 
2487  if (!recv_sys->parse_start_lsn) {
2488  /* Cannot start parsing yet because no start point for
2489  it found */
2490 
2491  return(FALSE);
2492  }
2493 
2494  data_len = log_block_get_data_len(log_block);
2495 
2496  if (recv_sys->parse_start_lsn >= scanned_lsn) {
2497 
2498  return(FALSE);
2499 
2500  } else if (recv_sys->scanned_lsn >= scanned_lsn) {
2501 
2502  return(FALSE);
2503 
2504  } else if (recv_sys->parse_start_lsn > recv_sys->scanned_lsn) {
2505  more_len = (ulint) (scanned_lsn - recv_sys->parse_start_lsn);
2506  } else {
2507  more_len = (ulint) (scanned_lsn - recv_sys->scanned_lsn);
2508  }
2509 
2510  if (more_len == 0) {
2511 
2512  return(FALSE);
2513  }
2514 
2515  ut_ad(data_len >= more_len);
2516 
2517  start_offset = data_len - more_len;
2518 
2519  if (start_offset < LOG_BLOCK_HDR_SIZE) {
2520  start_offset = LOG_BLOCK_HDR_SIZE;
2521  }
2522 
2523  end_offset = data_len;
2524 
2525  if (end_offset > OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
2526  end_offset = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE;
2527  }
2528 
2529  ut_ad(start_offset <= end_offset);
2530 
2531  if (start_offset < end_offset) {
2533  log_block + start_offset, end_offset - start_offset);
2534 
2535  recv_sys->len += end_offset - start_offset;
2536 
2538  }
2539 
2540  return(TRUE);
2541 }
2542 
2543 /*******************************************************/
2545 static
2546 void
2547 recv_sys_justify_left_parsing_buf(void)
2548 /*===================================*/
2549 {
2552 
2554 
2556 }
2557 
2558 /*******************************************************/
2565 UNIV_INTERN
2566 ibool
2568 /*===============*/
2569  ulint available_memory,
2571  ibool store_to_hash,
2575  const byte* buf,
2577  ulint len,
2578  ib_uint64_t start_lsn,
2579  ib_uint64_t* contiguous_lsn,
2582  ib_uint64_t* group_scanned_lsn)
2584 {
2585  const byte* log_block;
2586  ulint no;
2587  ib_uint64_t scanned_lsn;
2588  ibool finished;
2589  ulint data_len;
2590  ibool more_data;
2591 
2592  ut_ad(start_lsn % OS_FILE_LOG_BLOCK_SIZE == 0);
2593  ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0);
2594  ut_ad(len >= OS_FILE_LOG_BLOCK_SIZE);
2595  ut_a(store_to_hash <= TRUE);
2596 
2597  finished = FALSE;
2598 
2599  log_block = buf;
2600  scanned_lsn = start_lsn;
2601  more_data = FALSE;
2602 
2603  do {
2604  no = log_block_get_hdr_no(log_block);
2605  /*
2606  fprintf(stderr, "Log block header no %lu\n", no);
2607 
2608  fprintf(stderr, "Scanned lsn no %lu\n",
2609  log_block_convert_lsn_to_no(scanned_lsn));
2610  */
2611  if (no != log_block_convert_lsn_to_no(scanned_lsn)
2612  || !log_block_checksum_is_ok_or_old_format(log_block)) {
2613 
2614  if (no == log_block_convert_lsn_to_no(scanned_lsn)
2615  && !log_block_checksum_is_ok_or_old_format(
2616  log_block)) {
2617  fprintf(stderr,
2618  "InnoDB: Log block no %lu at"
2619  " lsn %"PRIu64" has\n"
2620  "InnoDB: ok header, but checksum field"
2621  " contains %lu, should be %lu\n",
2622  (ulong) no,
2623  scanned_lsn,
2624  (ulong) log_block_get_checksum(
2625  log_block),
2626  (ulong) log_block_calc_checksum(
2627  log_block));
2628  }
2629 
2630  /* Garbage or an incompletely written log block */
2631 
2632  finished = TRUE;
2633 
2634  break;
2635  }
2636 
2637  if (log_block_get_flush_bit(log_block)) {
2638  /* This block was a start of a log flush operation:
2639  we know that the previous flush operation must have
2640  been completed for all log groups before this block
2641  can have been flushed to any of the groups. Therefore,
2642  we know that log data is contiguous up to scanned_lsn
2643  in all non-corrupt log groups. */
2644 
2645  if (scanned_lsn > *contiguous_lsn) {
2646  *contiguous_lsn = scanned_lsn;
2647  }
2648  }
2649 
2650  data_len = log_block_get_data_len(log_block);
2651 
2652  if ((store_to_hash || (data_len == OS_FILE_LOG_BLOCK_SIZE))
2653  && scanned_lsn + data_len > recv_sys->scanned_lsn
2655  && (log_block_get_checkpoint_no(log_block)
2658  - log_block_get_checkpoint_no(log_block)
2659  > 0x80000000UL)) {
2660 
2661  /* Garbage from a log buffer flush which was made
2662  before the most recent database recovery */
2663 
2664  finished = TRUE;
2665 #ifdef UNIV_LOG_DEBUG
2666  /* This is not really an error, but currently
2667  we stop here in the debug version: */
2668 
2669  ut_error;
2670 #endif
2671  break;
2672  }
2673 
2675  && (log_block_get_first_rec_group(log_block) > 0)) {
2676 
2677  /* We found a point from which to start the parsing
2678  of log records */
2679 
2680  recv_sys->parse_start_lsn = scanned_lsn
2681  + log_block_get_first_rec_group(log_block);
2684  }
2685 
2686  scanned_lsn += data_len;
2687 
2688  if (scanned_lsn > recv_sys->scanned_lsn) {
2689 
2690  /* We have found more entries. If this scan is
2691  of startup type, we must initiate crash recovery
2692  environment before parsing these log records. */
2693 
2694 #ifndef UNIV_HOTBACKUP
2695  if (recv_log_scan_is_startup_type
2696  && !recv_needed_recovery) {
2697 
2698  fprintf(stderr,
2699  "InnoDB: Log scan progressed"
2700  " past the checkpoint lsn %"PRIu64"\n",
2702  recv_init_crash_recovery();
2703  }
2704 #endif /* !UNIV_HOTBACKUP */
2705 
2706  /* We were able to find more log data: add it to the
2707  parsing buffer if parse_start_lsn is already
2708  non-zero */
2709 
2711  >= RECV_PARSING_BUF_SIZE) {
2712  fprintf(stderr,
2713  "InnoDB: Error: log parsing"
2714  " buffer overflow."
2715  " Recovery may have failed!\n");
2716 
2717  recv_sys->found_corrupt_log = TRUE;
2718 
2719 #ifndef UNIV_HOTBACKUP
2720  if (!srv_force_recovery) {
2721  fputs("InnoDB: Set"
2722  " innodb_force_recovery"
2723  " to ignore this error.\n",
2724  stderr);
2725  ut_error;
2726  }
2727 #endif /* !UNIV_HOTBACKUP */
2728 
2729  } else if (!recv_sys->found_corrupt_log) {
2730  more_data = recv_sys_add_to_parsing_buf(
2731  log_block, scanned_lsn);
2732  }
2733 
2734  recv_sys->scanned_lsn = scanned_lsn;
2736  = log_block_get_checkpoint_no(log_block);
2737  }
2738 
2739  if (data_len < OS_FILE_LOG_BLOCK_SIZE) {
2740  /* Log data for this group ends here */
2741 
2742  finished = TRUE;
2743  break;
2744  } else {
2745  log_block += OS_FILE_LOG_BLOCK_SIZE;
2746  }
2747  } while (log_block < buf + len && !finished);
2748 
2749  *group_scanned_lsn = scanned_lsn;
2750 
2752  || (recv_is_from_backup && !recv_is_making_a_backup)) {
2753  recv_scan_print_counter++;
2754 
2755  if (finished || (recv_scan_print_counter % 80 == 0)) {
2756 
2757  drizzled::errmsg_printf(drizzled::error::INFO,
2758  "InnoDB: Doing recovery: scanned up to log sequence number %"PRIu64" ",
2759  *group_scanned_lsn);
2760  }
2761  }
2762 
2763  if (more_data && !recv_sys->found_corrupt_log) {
2764  /* Try to parse more log records */
2765 
2766  recv_parse_log_recs(store_to_hash);
2767 
2768 #ifndef UNIV_HOTBACKUP
2769  if (store_to_hash
2770  && mem_heap_get_size(recv_sys->heap) > available_memory) {
2771 
2772  /* Hash table of log records has grown too big:
2773  empty it; FALSE means no ibuf operations
2774  allowed, as we cannot add new records to the
2775  log yet: they would be produced by ibuf
2776  operations */
2777 
2779  }
2780 #endif /* !UNIV_HOTBACKUP */
2781 
2783  /* Move parsing buffer data to the buffer start */
2784 
2785  recv_sys_justify_left_parsing_buf();
2786  }
2787  }
2788 
2789  return(finished);
2790 }
2791 
2792 #ifndef UNIV_HOTBACKUP
2793 /*******************************************************/
2796 static
2797 void
2798 recv_group_scan_log_recs(
2799 /*=====================*/
2800  log_group_t* group,
2801  ib_uint64_t* contiguous_lsn,
2804  ib_uint64_t* group_scanned_lsn)
2806 {
2807  ibool finished;
2808  ib_uint64_t start_lsn;
2809  ib_uint64_t end_lsn;
2810 
2811  finished = FALSE;
2812 
2813  start_lsn = *contiguous_lsn;
2814 
2815  while (!finished) {
2816  end_lsn = start_lsn + RECV_SCAN_SIZE;
2817 
2818  log_group_read_log_seg(LOG_RECOVER, log_sys->buf,
2819  group, start_lsn, end_lsn);
2820 
2821  finished = recv_scan_log_recs(
2823  - (recv_n_pool_free_frames * srv_buf_pool_instances))
2824  * UNIV_PAGE_SIZE,
2825  TRUE, log_sys->buf, RECV_SCAN_SIZE,
2826  start_lsn, contiguous_lsn, group_scanned_lsn);
2827  start_lsn = end_lsn;
2828  }
2829 
2830 #ifdef UNIV_DEBUG
2831  if (log_debug_writes) {
2832  drizzled::errmsg_printf(drizzled::error::INFO,
2833  "InnoDB: Scanned group %lu up to log sequence number %"PRIu64" ", (ulong) group->id, *group_scanned_lsn);
2834  }
2835 #endif /* UNIV_DEBUG */
2836 }
2837 
2838 /*******************************************************/
2841 static
2842 void
2843 recv_init_crash_recovery(void)
2844 /*==========================*/
2845 {
2846  ut_a(!recv_needed_recovery);
2847 
2848  recv_needed_recovery = TRUE;
2849 
2850  ut_print_timestamp(stderr);
2851 
2852  fprintf(stderr,
2853  " InnoDB: Database was not"
2854  " shut down normally!\n"
2855  "InnoDB: Starting crash recovery.\n");
2856 
2857  fprintf(stderr,
2858  "InnoDB: Reading tablespace information"
2859  " from the .ibd files...\n");
2860 
2861  fil_load_single_table_tablespaces();
2862 
2863  /* If we are using the doublewrite method, we will
2864  check if there are half-written pages in data files,
2865  and restore them from the doublewrite buffer if
2866  possible */
2867 
2868  if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
2869 
2870  fprintf(stderr,
2871  "InnoDB: Restoring possible"
2872  " half-written data pages from"
2873  " the doublewrite\n"
2874  "InnoDB: buffer...\n");
2876  }
2877 }
2878 
2879 /********************************************************/
2885 UNIV_INTERN
2886 ulint
2888 /*=====================================*/
2889 #ifdef UNIV_LOG_ARCHIVE
2890  ulint type,
2892  ib_uint64_t limit_lsn,
2894 #endif /* UNIV_LOG_ARCHIVE */
2895  ib_uint64_t min_flushed_lsn,
2897  ib_uint64_t max_flushed_lsn)
2899 {
2900  log_group_t* group;
2901  log_group_t* max_cp_group;
2902  log_group_t* up_to_date_group;
2903  ulint max_cp_field;
2904  ulint log_hdr_log_block_size;
2905  ib_uint64_t checkpoint_lsn;
2906  ib_uint64_t checkpoint_no;
2907  ib_uint64_t old_scanned_lsn;
2908  ib_uint64_t group_scanned_lsn= 0;
2909  ib_uint64_t contiguous_lsn;
2910 #ifdef UNIV_LOG_ARCHIVE
2911  ib_uint64_t archived_lsn;
2912 #endif /* UNIV_LOG_ARCHIVE */
2913  byte* buf;
2914  boost::scoped_array<byte> log_hdr_buf_base(
2915  new byte[LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE]);
2916  byte* log_hdr_buf
2917  = (byte *)ut_align(log_hdr_buf_base.get(), OS_FILE_LOG_BLOCK_SIZE);
2918  ulint err;
2919 
2920 #ifdef UNIV_LOG_ARCHIVE
2921  ut_ad(type != LOG_CHECKPOINT || limit_lsn == IB_ULONGLONG_MAX);
2923 # define TYPE_CHECKPOINT (type == LOG_CHECKPOINT)
2924 
2925 # define LIMIT_LSN limit_lsn
2926 #else /* UNIV_LOG_ARCHIVE */
2927 
2928 # define TYPE_CHECKPOINT 1
2929 
2930 # define LIMIT_LSN IB_ULONGLONG_MAX
2931 #endif /* UNIV_LOG_ARCHIVE */
2932 
2933  if (TYPE_CHECKPOINT) {
2934  recv_sys_create();
2936  }
2937 
2938  if (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) {
2939  drizzled::errmsg_printf(drizzled::error::INFO,
2940  "InnoDB: The user has set SRV_FORCE_NO_LOG_REDO on Skipping log redo.");
2941 
2942  return(DB_SUCCESS);
2943  }
2944 
2945  recv_recovery_on = TRUE;
2946 
2947  recv_sys->limit_lsn = LIMIT_LSN;
2948 
2949  mutex_enter(&(log_sys->mutex));
2950 
2951  /* Look for the latest checkpoint from any of the log groups */
2952 
2953  err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
2954 
2955  if (err != DB_SUCCESS) {
2956 
2957  mutex_exit(&(log_sys->mutex));
2958 
2959  return(err);
2960  }
2961 
2962  log_group_read_checkpoint_info(max_cp_group, max_cp_field);
2963 
2964  buf = log_sys->checkpoint_buf;
2965 
2966  checkpoint_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_LSN);
2967  checkpoint_no = mach_read_from_8(buf + LOG_CHECKPOINT_NO);
2968 #ifdef UNIV_LOG_ARCHIVE
2969  archived_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN);
2970 #endif /* UNIV_LOG_ARCHIVE */
2971 
2972  /* Read the first log file header to print a note if this is
2973  a recovery from a restored InnoDB Hot Backup */
2974 
2975  fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, max_cp_group->space_id, 0,
2976  0, 0, LOG_FILE_HDR_SIZE,
2977  log_hdr_buf, max_cp_group);
2978 
2979  if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
2980  (byte*)"ibbackup", (sizeof "ibbackup") - 1)) {
2981  /* This log file was created by ibbackup --restore: print
2982  a note to the user about it */
2983 
2984  drizzled::errmsg_printf(drizzled::error::INFO,
2985  "InnoDB: The log file was created by ibbackup --apply-log at %s\n",
2986  log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP);
2987  drizzled::errmsg_printf(drizzled::error::INFO,
2988  "InnoDB: NOTE: the following crash recovery is part of a normal restore.\n");
2989 
2990  /* Wipe over the label now */
2991 
2992  memset(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
2993  ' ', 4);
2994  /* Write to the log file to wipe over the label */
2995  fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE,
2996  max_cp_group->space_id, 0,
2997  0, 0, OS_FILE_LOG_BLOCK_SIZE,
2998  log_hdr_buf, max_cp_group);
2999  }
3000 
3001  log_hdr_log_block_size
3002  = mach_read_from_4(log_hdr_buf + LOG_FILE_OS_FILE_LOG_BLOCK_SIZE);
3003  if (log_hdr_log_block_size == 0) {
3004  /* 0 means default value */
3005  log_hdr_log_block_size = 512;
3006  }
3007  if (log_hdr_log_block_size != srv_log_block_size) {
3008  drizzled::errmsg_printf(drizzled::error::ERROR,
3009  "InnoDB: Error: The block size of ib_logfile (%lu) "
3010  "is not equal to innodb_log_block_size.\n"
3011  "InnoDB: Error: Suggestion - Recreate log files.\n",
3012  log_hdr_log_block_size);
3013  return(DB_ERROR);
3014  }
3015 
3016 #ifdef UNIV_LOG_ARCHIVE
3017  group = UT_LIST_GET_FIRST(log_sys->log_groups);
3018 
3019  while (group) {
3021  &(group->archived_file_no),
3022  &(group->archived_offset));
3023 
3024  group = UT_LIST_GET_NEXT(log_groups, group);
3025  }
3026 #endif /* UNIV_LOG_ARCHIVE */
3027 
3028  if (TYPE_CHECKPOINT) {
3029  /* Start reading the log groups from the checkpoint lsn up. The
3030  variable contiguous_lsn contains an lsn up to which the log is
3031  known to be contiguously written to all log groups. */
3032 
3033  recv_sys->parse_start_lsn = checkpoint_lsn;
3034  recv_sys->scanned_lsn = checkpoint_lsn;
3036  recv_sys->recovered_lsn = checkpoint_lsn;
3037 
3038  srv_start_lsn = checkpoint_lsn;
3039  }
3040 
3041  contiguous_lsn = ut_uint64_align_down(recv_sys->scanned_lsn,
3043  if (TYPE_CHECKPOINT) {
3044  up_to_date_group = max_cp_group;
3045 #ifdef UNIV_LOG_ARCHIVE
3046  } else {
3047  ulint capacity;
3048 
3049  /* Try to recover the remaining part from logs: first from
3050  the logs of the archived group */
3051 
3052  group = recv_sys->archive_group;
3053  capacity = log_group_get_capacity(group);
3054 
3055  if (recv_sys->scanned_lsn > checkpoint_lsn + capacity
3056  || checkpoint_lsn > recv_sys->scanned_lsn + capacity) {
3057 
3058  mutex_exit(&(log_sys->mutex));
3059 
3060  /* The group does not contain enough log: probably
3061  an archived log file was missing or corrupt */
3062 
3063  return(DB_ERROR);
3064  }
3065 
3066  recv_group_scan_log_recs(group, &contiguous_lsn,
3067  &group_scanned_lsn);
3068  if (recv_sys->scanned_lsn < checkpoint_lsn) {
3069 
3070  mutex_exit(&(log_sys->mutex));
3071 
3072  /* The group did not contain enough log: an archived
3073  log file was missing or invalid, or the log group
3074  was corrupt */
3075 
3076  return(DB_ERROR);
3077  }
3078 
3079  group->scanned_lsn = group_scanned_lsn;
3080  up_to_date_group = group;
3081 #endif /* UNIV_LOG_ARCHIVE */
3082  }
3083 
3084  ut_ad(RECV_SCAN_SIZE <= log_sys->buf_size);
3085 
3086  group = UT_LIST_GET_FIRST(log_sys->log_groups);
3087 
3088 #ifdef UNIV_LOG_ARCHIVE
3089  if ((type == LOG_ARCHIVE) && (group == recv_sys->archive_group)) {
3090  group = UT_LIST_GET_NEXT(log_groups, group);
3091  }
3092 #endif /* UNIV_LOG_ARCHIVE */
3093 
3094  /* Set the flag to publish that we are doing startup scan. */
3095  recv_log_scan_is_startup_type = TYPE_CHECKPOINT;
3096  while (group) {
3097  old_scanned_lsn = recv_sys->scanned_lsn;
3098 
3099  recv_group_scan_log_recs(group, &contiguous_lsn,
3100  &group_scanned_lsn);
3101  group->scanned_lsn = group_scanned_lsn;
3102 
3103  if (old_scanned_lsn < group_scanned_lsn) {
3104  /* We found a more up-to-date group */
3105 
3106  up_to_date_group = group;
3107  }
3108 
3109 #ifdef UNIV_LOG_ARCHIVE
3110  if ((type == LOG_ARCHIVE)
3111  && (group == recv_sys->archive_group)) {
3112  group = UT_LIST_GET_NEXT(log_groups, group);
3113  }
3114 #endif /* UNIV_LOG_ARCHIVE */
3115 
3116  group = UT_LIST_GET_NEXT(log_groups, group);
3117  }
3118 
3119  /* Done with startup scan. Clear the flag. */
3120  recv_log_scan_is_startup_type = FALSE;
3121  if (TYPE_CHECKPOINT) {
3122  /* NOTE: we always do a 'recovery' at startup, but only if
3123  there is something wrong we will print a message to the
3124  user about recovery: */
3125 
3126  if (checkpoint_lsn != max_flushed_lsn
3127  || checkpoint_lsn != min_flushed_lsn) {
3128 
3129  if (checkpoint_lsn < max_flushed_lsn) {
3130  drizzled::errmsg_printf(drizzled::error::ERROR,
3131  "InnoDB: #########################"
3132  "#################################\n"
3133  "InnoDB: "
3134  "WARNING!\n"
3135  "InnoDB: The log sequence number"
3136  " in ibdata files is higher\n"
3137  "InnoDB: than the log sequence number"
3138  " in the ib_logfiles! Are you sure\n"
3139  "InnoDB: you are using the right"
3140  " ib_logfiles to start up"
3141  " the database?\n"
3142  "InnoDB: Log sequence number in"
3143  " ib_logfiles is %"PRIu64", log\n"
3144  "InnoDB: sequence numbers stamped"
3145  " to ibdata file headers are between\n"
3146  "InnoDB: %"PRIu64" and %"PRIu64".\n"
3147  "InnoDB: #########################"
3148  "#################################\n",
3149  checkpoint_lsn,
3150  min_flushed_lsn,
3151  max_flushed_lsn);
3152  }
3153 
3154  if (not recv_needed_recovery) {
3155  drizzled::errmsg_printf(drizzled::error::ERROR,
3156  "InnoDB: The log sequence number in ibdata files does not match the log sequence number in the ib_logfiles!");
3157  recv_init_crash_recovery();
3158  }
3159  }
3160 
3161  if (!recv_needed_recovery) {
3162  /* Init the doublewrite buffer memory structure */
3164  }
3165  }
3166 
3167  /* We currently have only one log group */
3168  if (group_scanned_lsn < checkpoint_lsn) {
3169  drizzled::errmsg_printf(drizzled::error::ERROR,
3170  "InnoDB: ERROR: We were only able to scan the log up to %"PRIu64", but a checkpoint was at %"PRIu64". "
3171  "It is possible that the database is now corrupt!",
3172  group_scanned_lsn,
3173  checkpoint_lsn);
3174  }
3175 
3176  if (group_scanned_lsn < recv_max_page_lsn) {
3177  drizzled::errmsg_printf(drizzled::error::ERROR,
3178  "InnoDB: ERROR: We were only able to scan the log up to %"PRIu64" "
3179  " but a database page a had an lsn %"PRIu64". It is possible that the database is now corrupt!",
3180  group_scanned_lsn,
3181  recv_max_page_lsn);
3182  }
3183 
3184  if (recv_sys->recovered_lsn < checkpoint_lsn) {
3185 
3186  mutex_exit(&(log_sys->mutex));
3187 
3188  if (recv_sys->recovered_lsn >= LIMIT_LSN) {
3189 
3190  return(DB_SUCCESS);
3191  }
3192 
3193  ut_error;
3194 
3195  return(DB_ERROR);
3196  }
3197 
3198  /* Synchronize the uncorrupted log groups to the most up-to-date log
3199  group; we also copy checkpoint info to groups */
3200 
3201  log_sys->next_checkpoint_lsn = checkpoint_lsn;
3202  log_sys->next_checkpoint_no = checkpoint_no + 1;
3203 
3204 #ifdef UNIV_LOG_ARCHIVE
3205  log_sys->archived_lsn = archived_lsn;
3206 #endif /* UNIV_LOG_ARCHIVE */
3207 
3208  recv_synchronize_groups(up_to_date_group);
3209 
3210  if (!recv_needed_recovery) {
3211  ut_a(checkpoint_lsn == recv_sys->recovered_lsn);
3212  } else {
3214  }
3215 
3216  log_sys->lsn = recv_sys->recovered_lsn;
3217 
3219 
3220  log_sys->buf_free = (ulint) log_sys->lsn % OS_FILE_LOG_BLOCK_SIZE;
3221  log_sys->buf_next_to_write = log_sys->buf_free;
3222  log_sys->written_to_some_lsn = log_sys->lsn;
3223  log_sys->written_to_all_lsn = log_sys->lsn;
3224 
3225  log_sys->last_checkpoint_lsn = checkpoint_lsn;
3226 
3227  log_sys->next_checkpoint_no = checkpoint_no + 1;
3228 
3229 #ifdef UNIV_LOG_ARCHIVE
3230  if (archived_lsn == IB_ULONGLONG_MAX) {
3231 
3232  log_sys->archiving_state = LOG_ARCH_OFF;
3233  }
3234 #endif /* UNIV_LOG_ARCHIVE */
3235 
3236  mutex_enter(&(recv_sys->mutex));
3237 
3238  recv_sys->apply_log_recs = TRUE;
3239 
3240  mutex_exit(&(recv_sys->mutex));
3241 
3242  mutex_exit(&(log_sys->mutex));
3243 
3244  recv_lsn_checks_on = TRUE;
3245 
3246  /* The database is now ready to start almost normal processing of user
3247  transactions: transaction rollbacks and the application of the log
3248  records in the hash table can be run in background. */
3249 
3250  return(DB_SUCCESS);
3251 
3252 #undef TYPE_CHECKPOINT
3253 #undef LIMIT_LSN
3254 }
3255 
3256 /********************************************************/
3258 UNIV_INTERN
3259 void
3261 /*======================================*/
3262 {
3263  /* Apply the hashed log records to the respective file pages */
3264 
3265  if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
3266 
3268  }
3269 
3270 #ifdef UNIV_DEBUG
3271  if (log_debug_writes) {
3272  drizzled::errmsg_printf(drizzled::error::INFO,
3273  "InnoDB: Log records applied to the database.");
3274  }
3275 #endif /* UNIV_DEBUG */
3276 
3277  if (recv_sys->found_corrupt_log) {
3278  drizzled::errmsg_printf(drizzled::error::ERROR,
3279  "InnoDB: WARNING: the log file may have been corrupt and it\n"
3280  "InnoDB: is possible that the log scan or parsing did not proceed\n"
3281  "InnoDB: far enough in recovery. Please run CHECK TABLE on your InnoDB tables to check that they are ok! "
3282  "InnoDB: It may be safest to recover your database from a backup!");
3283  }
3284 
3285  /* Free the resources of the recovery system */
3286 
3287  recv_recovery_on = FALSE;
3288 
3289 #ifndef UNIV_LOG_DEBUG
3290  recv_sys_debug_free();
3291 #endif
3292  /* Roll back any recovered data dictionary transactions, so
3293  that the data dictionary tables will be free of any locks.
3294  The data dictionary latch should guarantee that there is at
3295  most one data dictionary transaction active at a time. */
3296  if (! srv_apply_log_only)
3298 }
3299 
3300 /********************************************************/
3302 UNIV_INTERN
3303 void
3305 /*===============================*/
3306 {
3307  int i;
3308 
3309 #ifdef UNIV_SYNC_DEBUG
3310  /* Wait for a while so that created threads have time to suspend
3311  themselves before we switch the latching order checks on */
3312  os_thread_sleep(1000000);
3313 
3314  /* Switch latching order checks on in sync0sync.c */
3315  sync_order_checks_on = TRUE;
3316 #endif
3317  /* Drop partially created indexes. */
3319  /* Drop temporary tables. */
3321 
3322  if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
3323  /* Rollback the uncommitted transactions which have no user
3324  session */
3325 
3327  (void *)&i, NULL);
3328  }
3329 }
3330 
3331 /******************************************************/
3333 UNIV_INTERN
3334 void
3336 /*============*/
3337  ib_uint64_t lsn,
3342 #ifdef UNIV_LOG_ARCHIVE
3343  ulint arch_log_no,
3344 #endif /* UNIV_LOG_ARCHIVE */
3345  ibool new_logs_created)
3349 {
3350  log_group_t* group;
3351 
3352  ut_ad(mutex_own(&(log_sys->mutex)));
3353 
3355 
3356  group = UT_LIST_GET_FIRST(log_sys->log_groups);
3357 
3358  while (group) {
3359  group->lsn = log_sys->lsn;
3360  group->lsn_offset = LOG_FILE_HDR_SIZE;
3361 #ifdef UNIV_LOG_ARCHIVE
3362  group->archived_file_no = arch_log_no;
3363  group->archived_offset = 0;
3364 #endif /* UNIV_LOG_ARCHIVE */
3365 
3366  if (!new_logs_created) {
3367  recv_truncate_group(group, group->lsn, group->lsn,
3368  group->lsn, group->lsn);
3369  }
3370 
3371  group = UT_LIST_GET_NEXT(log_groups, group);
3372  }
3373 
3374  log_sys->buf_next_to_write = 0;
3375  log_sys->written_to_some_lsn = log_sys->lsn;
3376  log_sys->written_to_all_lsn = log_sys->lsn;
3377 
3378  log_sys->next_checkpoint_no = 0;
3379  log_sys->last_checkpoint_lsn = 0;
3380 
3381 #ifdef UNIV_LOG_ARCHIVE
3382  log_sys->archived_lsn = log_sys->lsn;
3383 #endif /* UNIV_LOG_ARCHIVE */
3384 
3385  log_block_init(log_sys->buf, log_sys->lsn);
3386  log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE);
3387 
3388  log_sys->buf_free = LOG_BLOCK_HDR_SIZE;
3389  log_sys->lsn += LOG_BLOCK_HDR_SIZE;
3390 
3391  mutex_exit(&(log_sys->mutex));
3392 
3393  /* Reset the checkpoint fields in logs */
3394 
3395  log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
3396  log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
3397 
3398  mutex_enter(&(log_sys->mutex));
3399 }
3400 #endif /* !UNIV_HOTBACKUP */
3401 
3402 #ifdef UNIV_HOTBACKUP
3403 /******************************************************/
3405 UNIV_INTERN
3406 void
3407 recv_reset_log_files_for_backup(
3408 /*============================*/
3409  const char* log_dir,
3410  ulint n_log_files,
3411  ulint log_file_size,
3412  ib_uint64_t lsn)
3414 {
3415  os_file_t log_file;
3416  ibool success;
3417  byte* buf;
3418  ulint i;
3419  ulint log_dir_len;
3420  char name[5000];
3421  static const char ib_logfile_basename[] = "ib_logfile";
3422 
3423  log_dir_len = strlen(log_dir);
3424  /* full path name of ib_logfile consists of log dir path + basename
3425  + number. This must fit in the name buffer.
3426  */
3427  ut_a(log_dir_len + strlen(ib_logfile_basename) + 11 < sizeof(name));
3428 
3429  buf = ut_malloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
3430  memset(buf, '\0', LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
3431 
3432  for (i = 0; i < n_log_files; i++) {
3433 
3434  sprintf(name, "%s%s%lu", log_dir,
3435  ib_logfile_basename, (ulong)i);
3436 
3437  log_file = os_file_create_simple(innodb_file_log_key,
3438  name, OS_FILE_CREATE,
3439  OS_FILE_READ_WRITE,
3440  &success);
3441  if (not success) {
3442  drizzled::errmsg_printf(drizzled::error::ERROR,
3443  "InnoDB: Cannot create %s. Check that the file does not exist yet.\n", name);
3444 
3445  exit(1);
3446  }
3447 
3448  drizzled::errmsg_printf(drizzled::error::INFO,
3449  "Setting log file size to %lu %lu\n",
3450  (ulong) ut_get_high32(log_file_size),
3451  (ulong) log_file_size & 0xFFFFFFFFUL);
3452 
3453  success = os_file_set_size(name, log_file,
3454  log_file_size & 0xFFFFFFFFUL,
3455  ut_get_high32(log_file_size));
3456 
3457  if (not success) {
3458  drizzled::errmsg_printf(drizzled::error::ERROR,
3459  "InnoDB: Cannot set %s size to %lu %lu\n",
3460  name, (ulong) ut_get_high32(log_file_size),
3461  (ulong) (log_file_size & 0xFFFFFFFFUL));
3462  exit(1);
3463  }
3464 
3465  os_file_flush(log_file);
3466  os_file_close(log_file);
3467  }
3468 
3469  /* We pretend there is a checkpoint at lsn + LOG_BLOCK_HDR_SIZE */
3470 
3471  log_reset_first_header_and_checkpoint(buf, lsn);
3472 
3473  log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn);
3474  log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE,
3475  LOG_BLOCK_HDR_SIZE);
3476  sprintf(name, "%s%s%lu", log_dir, ib_logfile_basename, (ulong)0);
3477 
3478  log_file = os_file_create_simple(innodb_file_log_key,
3479  name, OS_FILE_OPEN,
3480  OS_FILE_READ_WRITE, &success);
3481  if (!success) {
3482  drizzled::errmsg_printf(drizzled::error::ERROR, "InnoDB: Cannot open %s.\n", name);
3483 
3484  exit(1);
3485  }
3486 
3487  os_file_write(name, log_file, buf, 0, 0,
3488  LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
3489  os_file_flush(log_file);
3490  os_file_close(log_file);
3491 
3492  ut_free(buf);
3493 }
3494 #endif /* UNIV_HOTBACKUP */
3495 
3496 #ifdef UNIV_LOG_ARCHIVE
3497 /* Dead code */
3498 /******************************************************/
3501 static
3502 ibool
3503 log_group_recover_from_archive_file(
3504 /*================================*/
3505  log_group_t* group)
3506 {
3507  os_file_t file_handle;
3508  ib_uint64_t start_lsn;
3509  ib_uint64_t file_end_lsn;
3510  ib_uint64_t dummy_lsn;
3511  ib_uint64_t scanned_lsn;
3512  ulint len;
3513  ibool ret;
3514  byte* buf;
3515  ulint read_offset;
3516  ulint file_size;
3517  ulint file_size_high;
3518  int input_char;
3519  char name[10000];
3520 
3521  ut_a(0);
3522 
3523 try_open_again:
3524  buf = log_sys->buf;
3525 
3526  /* Add the file to the archive file space; open the file */
3527 
3528  log_archived_file_name_gen(name, group->id, group->archived_file_no);
3529 
3530  file_handle = os_file_create(innodb_file_log_key,
3531  name, OS_FILE_OPEN,
3532  OS_FILE_LOG, OS_FILE_AIO, &ret);
3533 
3534  if (ret == FALSE) {
3535 ask_again:
3536  fprintf(stderr,
3537  "InnoDB: Do you want to copy additional"
3538  " archived log files\n"
3539  "InnoDB: to the directory\n");
3540  fprintf(stderr,
3541  "InnoDB: or were these all the files needed"
3542  " in recovery?\n");
3543  fprintf(stderr,
3544  "InnoDB: (Y == copy more files; N == this is all)?");
3545 
3546  input_char = getchar();
3547 
3548  if (input_char == (int) 'N') {
3549 
3550  return(TRUE);
3551  } else if (input_char == (int) 'Y') {
3552 
3553  goto try_open_again;
3554  } else {
3555  goto ask_again;
3556  }
3557  }
3558 
3559  ret = os_file_get_size(file_handle, &file_size, &file_size_high);
3560  ut_a(ret);
3561 
3562  ut_a(file_size_high == 0);
3563 
3564  drizzled::errmsg_printf(drizzled::error::INFO,
3565  "InnoDB: Opened archived log file %s\n", name);
3566 
3567  ret = os_file_close(file_handle);
3568 
3569  if (file_size < LOG_FILE_HDR_SIZE) {
3570  drizzled::errmsg_printf(drizzled::error::ERROR,
3571  "InnoDB: Archive file header incomplete %s\n", name);
3572 
3573  return(TRUE);
3574  }
3575 
3576  ut_a(ret);
3577 
3578  /* Add the archive file as a node to the space */
3579 
3580  fil_node_create(name, 1 + file_size / UNIV_PAGE_SIZE,
3581  group->archive_space_id, FALSE);
3582 #if RECV_SCAN_SIZE < LOG_FILE_HDR_SIZE
3583 # error "RECV_SCAN_SIZE < LOG_FILE_HDR_SIZE"
3584 #endif
3585 
3586  /* Read the archive file header */
3587  fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, group->archive_space_id, 0, 0,
3588  LOG_FILE_HDR_SIZE, buf, NULL);
3589 
3590  /* Check if the archive file header is consistent */
3591 
3592  if (mach_read_from_4(buf + LOG_GROUP_ID) != group->id
3593  || mach_read_from_4(buf + LOG_FILE_NO)
3594  != group->archived_file_no) {
3595  drizzled::errmsg_printf(drizzled::error::ERROR,
3596  "InnoDB: Archive file header inconsistent %s\n", name);
3597 
3598  return(TRUE);
3599  }
3600 
3601  if (!mach_read_from_4(buf + LOG_FILE_ARCH_COMPLETED)) {
3602  drizzled::errmsg_printf(drizzled::error::ERROR,
3603  "InnoDB: Archive file not completely written %s\n",
3604  name);
3605 
3606  return(TRUE);
3607  }
3608 
3609  start_lsn = mach_read_from_8(buf + LOG_FILE_START_LSN);
3610  file_end_lsn = mach_read_from_8(buf + LOG_FILE_END_LSN);
3611 
3612  if (!recv_sys->scanned_lsn) {
3613 
3614  if (recv_sys->parse_start_lsn < start_lsn) {
3615  drizzled::errmsg_printf(drizzled::error::ERROR,
3616  "InnoDB: Archive log file %s starts from too big a lsn\n", name);
3617  return(TRUE);
3618  }
3619 
3620  recv_sys->scanned_lsn = start_lsn;
3621  }
3622 
3623  if (recv_sys->scanned_lsn != start_lsn) {
3624 
3625  drizzled::errmsg_printf(drizzled::error::ERROR,
3626  "InnoDB: Archive log file %s starts from a wrong lsn\n", name);
3627  return(TRUE);
3628  }
3629 
3630  read_offset = LOG_FILE_HDR_SIZE;
3631 
3632  for (;;) {
3633  len = RECV_SCAN_SIZE;
3634 
3635  if (read_offset + len > file_size) {
3636  len = ut_calc_align_down(file_size - read_offset,
3638  }
3639 
3640  if (len == 0) {
3641 
3642  break;
3643  }
3644 
3645 #ifdef UNIV_DEBUG
3646  if (log_debug_writes) {
3647  drizzled::errmsg_printf(drizzled::error::INFO,
3648  "InnoDB: Archive read starting at lsn %"PRIu64", len %lu from file %s\n",
3649  start_lsn, (ulong) len, name);
3650  }
3651 #endif /* UNIV_DEBUG */
3652 
3653  fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE,
3654  group->archive_space_id, read_offset / UNIV_PAGE_SIZE,
3655  read_offset % UNIV_PAGE_SIZE, len, buf, NULL);
3656 
3657  ret = recv_scan_log_recs(
3659  - (recv_n_pool_free_frames * srv_buf_pool_instances))
3660  * UNIV_PAGE_SIZE, TRUE, buf, len, start_lsn,
3661  &dummy_lsn, &scanned_lsn);
3662 
3663  if (scanned_lsn == file_end_lsn) {
3664 
3665  return(FALSE);
3666  }
3667 
3668  if (ret) {
3669  drizzled::errmsg_printf(drizzled::error::ERROR,
3670  "InnoDB: Archive log file %s does not scan right.", name);
3671  return(TRUE);
3672  }
3673 
3674  read_offset += len;
3675  start_lsn += len;
3676 
3677  ut_ad(start_lsn == scanned_lsn);
3678  }
3679 
3680  return(FALSE);
3681 }
3682 
3683 /********************************************************/
3686 UNIV_INTERN
3687 ulint
3688 recv_recovery_from_archive_start(
3689 /*=============================*/
3690  ib_uint64_t min_flushed_lsn,
3692  ib_uint64_t limit_lsn,
3694  ulint first_log_no)
3699 {
3700  log_group_t* group;
3701  ulint group_id;
3702  ulint trunc_len;
3703  ibool ret;
3704  ulint err;
3705 
3706  ut_a(0);
3707 
3708  recv_sys_create();
3710 
3711  recv_recovery_on = TRUE;
3712  recv_recovery_from_backup_on = TRUE;
3713 
3714  recv_sys->limit_lsn = limit_lsn;
3715 
3716  group_id = 0;
3717 
3718  group = UT_LIST_GET_FIRST(log_sys->log_groups);
3719 
3720  while (group) {
3721  if (group->id == group_id) {
3722 
3723  break;
3724  }
3725 
3726  group = UT_LIST_GET_NEXT(log_groups, group);
3727  }
3728 
3729  if (!group) {
3730  drizzled::errmsg_printf(drizzled::error::ERROR,
3731  "InnoDB: There is no log group defined with id %lu!\n",
3732  (ulong) group_id);
3733  return(DB_ERROR);
3734  }
3735 
3736  group->archived_file_no = first_log_no;
3737 
3738  recv_sys->parse_start_lsn = min_flushed_lsn;
3739 
3740  recv_sys->scanned_lsn = 0;
3743 
3744  recv_sys->archive_group = group;
3745 
3746  ret = FALSE;
3747 
3748  mutex_enter(&(log_sys->mutex));
3749 
3750  while (!ret) {
3751  ret = log_group_recover_from_archive_file(group);
3752 
3753  /* Close and truncate a possible processed archive file
3754  from the file space */
3755 
3756  trunc_len = UNIV_PAGE_SIZE
3757  * fil_space_get_size(group->archive_space_id);
3758  if (trunc_len > 0) {
3759  fil_space_truncate_start(group->archive_space_id,
3760  trunc_len);
3761  }
3762 
3763  group->archived_file_no++;
3764  }
3765 
3766  if (recv_sys->recovered_lsn < limit_lsn) {
3767 
3768  if (!recv_sys->scanned_lsn) {
3769 
3771  }
3772 
3773  mutex_exit(&(log_sys->mutex));
3774 
3775  err = recv_recovery_from_checkpoint_start(LOG_ARCHIVE,
3776  limit_lsn,
3777  IB_ULONGLONG_MAX,
3778  IB_ULONGLONG_MAX);
3779  if (err != DB_SUCCESS) {
3780 
3781  return(err);
3782  }
3783 
3784  mutex_enter(&(log_sys->mutex));
3785  }
3786 
3787  if (limit_lsn != IB_ULONGLONG_MAX) {
3788 
3790 
3792  }
3793 
3794  mutex_exit(&(log_sys->mutex));
3795 
3796  return(DB_SUCCESS);
3797 }
3798 
3799 /********************************************************/
3801 UNIV_INTERN
3802 void
3803 recv_recovery_from_archive_finish(void)
3804 /*===================================*/
3805 {
3807 
3808  recv_recovery_from_backup_on = FALSE;
3809 }
3810 #endif /* UNIV_LOG_ARCHIVE */