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