log0recv.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:87k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. Recovery
  3. (c) 1997 Innobase Oy
  4. Created 9/20/1997 Heikki Tuuri
  5. *******************************************************/
  6. #include "log0recv.h"
  7. #ifdef UNIV_NONINL
  8. #include "log0recv.ic"
  9. #endif
  10. #include "mem0mem.h"
  11. #include "buf0buf.h"
  12. #include "buf0flu.h"
  13. #include "buf0rea.h"
  14. #include "srv0srv.h"
  15. #include "srv0start.h"
  16. #include "mtr0mtr.h"
  17. #include "mtr0log.h"
  18. #include "page0page.h"
  19. #include "page0cur.h"
  20. #include "btr0btr.h"
  21. #include "btr0cur.h"
  22. #include "ibuf0ibuf.h"
  23. #include "trx0undo.h"
  24. #include "trx0rec.h"
  25. #include "trx0roll.h"
  26. #include "btr0cur.h"
  27. #include "btr0cur.h"
  28. #include "btr0cur.h"
  29. #include "dict0boot.h"
  30. #include "fil0fil.h"
  31. #ifdef UNIV_HOTBACKUP
  32. /* This is set to FALSE if the backup was originally taken with the
  33. ibbackup --include regexp option: then we do not want to create tables in
  34. directories which were not included */
  35. ibool recv_replay_file_ops = TRUE;
  36. #endif /* UNIV_HOTBACKUP */
  37. /* Log records are stored in the hash table in chunks at most of this size;
  38. this must be less than UNIV_PAGE_SIZE as it is stored in the buffer pool */
  39. #define RECV_DATA_BLOCK_SIZE (MEM_MAX_ALLOC_IN_BUF - sizeof(recv_data_t))
  40. /* Read-ahead area in applying log records to file pages */
  41. #define RECV_READ_AHEAD_AREA 32
  42. recv_sys_t* recv_sys = NULL;
  43. ibool recv_recovery_on = FALSE;
  44. ibool recv_recovery_from_backup_on = FALSE;
  45. ibool recv_needed_recovery = FALSE;
  46. ibool recv_lsn_checks_on = FALSE;
  47. /* If the following is TRUE, the buffer pool file pages must be invalidated
  48. after recovery and no ibuf operations are allowed; this becomes TRUE if
  49. the log record hash table becomes too full, and log records must be merged
  50. to file pages already before the recovery is finished: in this case no
  51. ibuf operations are allowed, as they could modify the pages read in the
  52. buffer pool before the pages have been recovered to the up-to-date state */
  53. /* Recovery is running and no operations on the log files are allowed
  54. yet: the variable name is misleading */
  55. ibool recv_no_ibuf_operations = FALSE;
  56. /* The following counter is used to decide when to print info on
  57. log scan */
  58. ulint recv_scan_print_counter = 0;
  59. ibool recv_is_from_backup = FALSE;
  60. #ifdef UNIV_HOTBACKUP
  61. ibool recv_is_making_a_backup = FALSE;
  62. #else
  63. # define recv_is_making_a_backup FALSE
  64. #endif /* UNIV_HOTBACKUP */
  65. ulint recv_previous_parsed_rec_type = 999999;
  66. ulint recv_previous_parsed_rec_offset = 0;
  67. ulint recv_previous_parsed_rec_is_multi = 0;
  68. ulint recv_max_parsed_page_no = 0;
  69. /* This many frames must be left free in the buffer pool when we scan
  70. the log and store the scanned log records in the buffer pool: we will
  71. use these free frames to read in pages when we start applying the
  72. log records to the database. */
  73. ulint  recv_n_pool_free_frames         = 256;
  74. /* The maximum lsn we see for a page during the recovery process. If this
  75. is bigger than the lsn we are able to scan up to, that is an indication that
  76. the recovery failed and the database may be corrupt. */
  77. dulint recv_max_page_lsn;
  78. /************************************************************
  79. Creates the recovery system. */
  80. void
  81. recv_sys_create(void)
  82. /*=================*/
  83. {
  84. if (recv_sys != NULL) {
  85. return;
  86. }
  87. recv_sys = mem_alloc(sizeof(recv_sys_t));
  88. mutex_create(&(recv_sys->mutex));
  89. mutex_set_level(&(recv_sys->mutex), SYNC_RECV);
  90. recv_sys->heap = NULL;
  91. recv_sys->addr_hash = NULL;
  92. }
  93. /************************************************************
  94. Inits the recovery system for a recovery operation. */
  95. void
  96. recv_sys_init(
  97. /*==========*/
  98. ibool recover_from_backup, /* in: TRUE if this is called
  99. to recover from a hot backup */
  100. ulint available_memory) /* in: available memory in bytes */
  101. {
  102. if (recv_sys->heap != NULL) {
  103. return;
  104. }
  105. mutex_enter(&(recv_sys->mutex));
  106. if (!recover_from_backup) {
  107. recv_sys->heap = mem_heap_create_in_buffer(256);
  108. } else {
  109. recv_sys->heap = mem_heap_create(256);
  110. recv_is_from_backup = TRUE;
  111. }
  112. recv_sys->buf = ut_malloc(RECV_PARSING_BUF_SIZE);
  113. recv_sys->len = 0;
  114. recv_sys->recovered_offset = 0;
  115. recv_sys->addr_hash = hash_create(available_memory / 64);
  116. recv_sys->n_addrs = 0;
  117. recv_sys->apply_log_recs = FALSE;
  118. recv_sys->apply_batch_on = FALSE;
  119. recv_sys->last_block_buf_start = mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE);
  120. recv_sys->last_block = ut_align(recv_sys->last_block_buf_start,
  121. OS_FILE_LOG_BLOCK_SIZE);
  122. recv_sys->found_corrupt_log = FALSE;
  123. recv_max_page_lsn = ut_dulint_zero;
  124. mutex_exit(&(recv_sys->mutex));
  125. }
  126. /************************************************************
  127. Empties the hash table when it has been fully processed. */
  128. static
  129. void
  130. recv_sys_empty_hash(void)
  131. /*=====================*/
  132. {
  133. #ifdef UNIV_SYNC_DEBUG
  134. ut_ad(mutex_own(&(recv_sys->mutex)));
  135. #endif /* UNIV_SYNC_DEBUG */
  136. if (recv_sys->n_addrs != 0) {
  137. fprintf(stderr,
  138. "InnoDB: Error: %lu pages with log records were left unprocessed!n"
  139. "InnoDB: Maximum page number with log records on it %lun",
  140. (ulong) recv_sys->n_addrs, 
  141. (ulong) recv_max_parsed_page_no);
  142. ut_error;
  143. }
  144. hash_table_free(recv_sys->addr_hash);
  145. mem_heap_empty(recv_sys->heap);
  146. recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 256);
  147. }
  148. /************************************************************
  149. Frees the recovery system. */
  150. static
  151. void
  152. recv_sys_free(void)
  153. /*===============*/
  154. {
  155. mutex_enter(&(recv_sys->mutex));
  156. hash_table_free(recv_sys->addr_hash);
  157. mem_heap_free(recv_sys->heap);
  158. ut_free(recv_sys->buf);
  159. mem_free(recv_sys->last_block_buf_start);
  160. recv_sys->addr_hash = NULL;
  161. recv_sys->heap = NULL;
  162. mutex_exit(&(recv_sys->mutex));
  163. }
  164. /************************************************************
  165. Truncates possible corrupted or extra records from a log group. */
  166. static
  167. void
  168. recv_truncate_group(
  169. /*================*/
  170. log_group_t* group, /* in: log group */
  171. dulint recovered_lsn, /* in: recovery succeeded up to this
  172. lsn */
  173. dulint limit_lsn, /* in: this was the limit for
  174. recovery */
  175. dulint checkpoint_lsn, /* in: recovery was started from this
  176. checkpoint */
  177. dulint archived_lsn) /* in: the log has been archived up to
  178. this lsn */
  179. {
  180. dulint start_lsn;
  181. dulint end_lsn;
  182. dulint finish_lsn1;
  183. dulint finish_lsn2;
  184. dulint finish_lsn;
  185. ulint len;
  186. ulint i;
  187. if (ut_dulint_cmp(archived_lsn, ut_dulint_max) == 0) {
  188. /* Checkpoint was taken in the NOARCHIVELOG mode */
  189. archived_lsn = checkpoint_lsn;
  190. }
  191. finish_lsn1 = ut_dulint_add(ut_dulint_align_down(archived_lsn,
  192. OS_FILE_LOG_BLOCK_SIZE),
  193. log_group_get_capacity(group));
  194. finish_lsn2 = ut_dulint_add(ut_dulint_align_up(recovered_lsn,
  195. OS_FILE_LOG_BLOCK_SIZE),
  196. recv_sys->last_log_buf_size);
  197. if (ut_dulint_cmp(limit_lsn, ut_dulint_max) != 0) {
  198. /* We do not know how far we should erase log records: erase
  199. as much as possible */
  200. finish_lsn = finish_lsn1;
  201. } else {
  202. /* It is enough to erase the length of the log buffer */
  203. finish_lsn = ut_dulint_get_min(finish_lsn1, finish_lsn2);
  204. }
  205. ut_a(RECV_SCAN_SIZE <= log_sys->buf_size);
  206. /* Write the log buffer full of zeros */
  207. for (i = 0; i < RECV_SCAN_SIZE; i++) {
  208. *(log_sys->buf + i) = '';
  209. }
  210. start_lsn = ut_dulint_align_down(recovered_lsn,
  211. OS_FILE_LOG_BLOCK_SIZE);
  212. if (ut_dulint_cmp(start_lsn, recovered_lsn) != 0) {
  213. /* Copy the last incomplete log block to the log buffer and
  214. edit its data length: */
  215. ut_memcpy(log_sys->buf, recv_sys->last_block,
  216. OS_FILE_LOG_BLOCK_SIZE);
  217. log_block_set_data_len(log_sys->buf,
  218. ut_dulint_minus(recovered_lsn, start_lsn));
  219. }
  220. if (ut_dulint_cmp(start_lsn, finish_lsn) >= 0) {
  221. return;
  222. }
  223.      for (;;) {
  224. end_lsn = ut_dulint_add(start_lsn, RECV_SCAN_SIZE);
  225.     
  226. if (ut_dulint_cmp(end_lsn, finish_lsn) > 0) {
  227. end_lsn = finish_lsn;
  228. }
  229. len = ut_dulint_minus(end_lsn, start_lsn);
  230. log_group_write_buf(group, log_sys->buf, len, start_lsn, 0);
  231. if (ut_dulint_cmp(end_lsn, finish_lsn) >= 0) {
  232. return;
  233. }
  234. /* Write the log buffer full of zeros */
  235. for (i = 0; i < RECV_SCAN_SIZE; i++) {
  236. *(log_sys->buf + i) = '';
  237. }
  238. start_lsn = end_lsn;
  239. }
  240. }
  241. /************************************************************
  242. Copies the log segment between group->recovered_lsn and recovered_lsn from the
  243. most up-to-date log group to group, so that it contains the latest log data. */
  244. static
  245. void
  246. recv_copy_group(
  247. /*============*/
  248. log_group_t* up_to_date_group, /* in: the most up-to-date log
  249. group */
  250. log_group_t* group, /* in: copy to this log
  251. group */
  252. dulint recovered_lsn) /* in: recovery succeeded up
  253. to this lsn */
  254. {
  255. dulint start_lsn;
  256. dulint end_lsn;
  257. ulint len;
  258. if (ut_dulint_cmp(group->scanned_lsn, recovered_lsn) >= 0) {
  259. return;
  260. }
  261. ut_a(RECV_SCAN_SIZE <= log_sys->buf_size);
  262. start_lsn = ut_dulint_align_down(group->scanned_lsn,
  263. OS_FILE_LOG_BLOCK_SIZE);
  264.      for (;;) {
  265. end_lsn = ut_dulint_add(start_lsn, RECV_SCAN_SIZE);
  266.     
  267. if (ut_dulint_cmp(end_lsn, recovered_lsn) > 0) {
  268. end_lsn = ut_dulint_align_up(recovered_lsn,
  269. OS_FILE_LOG_BLOCK_SIZE);
  270. }
  271. log_group_read_log_seg(LOG_RECOVER, log_sys->buf,
  272. up_to_date_group, start_lsn, end_lsn);
  273. len = ut_dulint_minus(end_lsn, start_lsn);
  274. log_group_write_buf(group, log_sys->buf, len, start_lsn, 0);
  275. if (ut_dulint_cmp(end_lsn, recovered_lsn) >= 0) {
  276. return;
  277. }
  278. start_lsn = end_lsn;
  279. }
  280. }
  281. /************************************************************
  282. Copies a log segment from the most up-to-date log group to the other log
  283. groups, so that they all contain the latest log data. Also writes the info
  284. about the latest checkpoint to the groups, and inits the fields in the group
  285. memory structs to up-to-date values. */
  286. static
  287. void
  288. recv_synchronize_groups(
  289. /*====================*/
  290. log_group_t* up_to_date_group) /* in: the most up-to-date
  291. log group */
  292. {
  293. log_group_t* group;
  294. dulint start_lsn;
  295. dulint end_lsn;
  296. dulint recovered_lsn;
  297. dulint limit_lsn;
  298. recovered_lsn = recv_sys->recovered_lsn;
  299. limit_lsn = recv_sys->limit_lsn;
  300. /* Read the last recovered log block to the recovery system buffer:
  301. the block is always incomplete */
  302. start_lsn = ut_dulint_align_down(recovered_lsn,
  303. OS_FILE_LOG_BLOCK_SIZE);
  304. end_lsn = ut_dulint_align_up(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE);
  305. ut_a(ut_dulint_cmp(start_lsn, end_lsn) != 0);
  306. log_group_read_log_seg(LOG_RECOVER, recv_sys->last_block,
  307. up_to_date_group, start_lsn, end_lsn);
  308. group = UT_LIST_GET_FIRST(log_sys->log_groups);
  309. while (group) {
  310. if (group != up_to_date_group) {
  311. /* Copy log data if needed */
  312. recv_copy_group(group, up_to_date_group,
  313. recovered_lsn);
  314. }
  315. /* Update the fields in the group struct to correspond to
  316. recovered_lsn */
  317. log_group_set_fields(group, recovered_lsn);
  318. group = UT_LIST_GET_NEXT(log_groups, group);
  319. }
  320. /* Copy the checkpoint info to the groups; remember that we have
  321. incremented checkpoint_no by one, and the info will not be written
  322. over the max checkpoint info, thus making the preservation of max
  323. checkpoint info on disk certain */
  324. log_groups_write_checkpoint_info();
  325. mutex_exit(&(log_sys->mutex));
  326. /* Wait for the checkpoint write to complete */
  327. rw_lock_s_lock(&(log_sys->checkpoint_lock));
  328. rw_lock_s_unlock(&(log_sys->checkpoint_lock));
  329. mutex_enter(&(log_sys->mutex));
  330. }
  331. /***************************************************************************
  332. Checks the consistency of the checkpoint info */
  333. static
  334. ibool
  335. recv_check_cp_is_consistent(
  336. /*========================*/
  337. /* out: TRUE if ok */
  338. byte* buf) /* in: buffer containing checkpoint info */
  339. {
  340. ulint fold;
  341. fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
  342. if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(buf
  343. + LOG_CHECKPOINT_CHECKSUM_1)) {
  344. return(FALSE);
  345. }
  346. fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
  347. LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
  348. if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(buf
  349. + LOG_CHECKPOINT_CHECKSUM_2)) {
  350. return(FALSE);
  351. }
  352. return(TRUE);
  353. }
  354. /************************************************************
  355. Looks for the maximum consistent checkpoint from the log groups. */
  356. static
  357. ulint
  358. recv_find_max_checkpoint(
  359. /*=====================*/
  360. /* out: error code or DB_SUCCESS */
  361. log_group_t** max_group, /* out: max group */
  362. ulint* max_field) /* out: LOG_CHECKPOINT_1 or
  363. LOG_CHECKPOINT_2 */
  364. {
  365. log_group_t* group;
  366. dulint max_no;
  367. dulint checkpoint_no;
  368. ulint field;
  369. byte* buf;
  370. group = UT_LIST_GET_FIRST(log_sys->log_groups);
  371. max_no = ut_dulint_zero;
  372. *max_group = NULL;
  373. buf = log_sys->checkpoint_buf;
  374. while (group) {
  375. group->state = LOG_GROUP_CORRUPTED;
  376. for (field = LOG_CHECKPOINT_1; field <= LOG_CHECKPOINT_2;
  377. field += LOG_CHECKPOINT_2 - LOG_CHECKPOINT_1) {
  378. log_group_read_checkpoint_info(group, field);
  379. if (!recv_check_cp_is_consistent(buf)) {
  380. if (log_debug_writes) {
  381. fprintf(stderr, 
  382.     "InnoDB: Checkpoint in group %lu at %lu invalid, %lun",
  383. (ulong) group->id,
  384. (ulong) field,
  385.                                  (ulong) mach_read_from_4(buf
  386.       + LOG_CHECKPOINT_CHECKSUM_1));
  387. }
  388. goto not_consistent;
  389. }
  390. group->state = LOG_GROUP_OK;
  391. group->lsn = mach_read_from_8(buf
  392. + LOG_CHECKPOINT_LSN);
  393. group->lsn_offset = mach_read_from_4(buf
  394. + LOG_CHECKPOINT_OFFSET);
  395. checkpoint_no =
  396. mach_read_from_8(buf + LOG_CHECKPOINT_NO);
  397. if (log_debug_writes) {
  398. fprintf(stderr, 
  399. "InnoDB: Checkpoint number %lu found in group %lun",
  400. (ulong) ut_dulint_get_low(checkpoint_no),
  401. (ulong) group->id);
  402. }
  403. if (ut_dulint_cmp(checkpoint_no, max_no) >= 0) {
  404. *max_group = group;
  405. *max_field = field;
  406. max_no = checkpoint_no;
  407. }
  408. not_consistent:
  409. ;
  410. }
  411. group = UT_LIST_GET_NEXT(log_groups, group);
  412. }
  413. if (*max_group == NULL) {
  414. fprintf(stderr,
  415. "InnoDB: No valid checkpoint found.n"
  416. "InnoDB: If this error appears when you are creating an InnoDB database,n"
  417. "InnoDB: the problem may be that during an earlier attempt you managedn"
  418. "InnoDB: to create the InnoDB data files, but log file creation failed.n"
  419. "InnoDB: If that is the case, please refer ton"
  420. "InnoDB: http://dev.mysql.com/doc/mysql/en/Error_creating_InnoDB.htmln");
  421. return(DB_ERROR);
  422. }
  423. return(DB_SUCCESS);
  424. }
  425. /***********************************************************************
  426. Reads the checkpoint info needed in hot backup. */
  427. ibool
  428. recv_read_cp_info_for_backup(
  429. /*=========================*/
  430. /* out: TRUE if success */
  431. byte* hdr, /* in: buffer containing the log group header */
  432. dulint* lsn, /* out: checkpoint lsn */
  433. ulint* offset, /* out: checkpoint offset in the log group */
  434. ulint* fsp_limit,/* out: fsp limit of space 0, 1000000000 if the
  435. database is running with < version 3.23.50 of InnoDB */
  436. dulint* cp_no, /* out: checkpoint number */
  437. dulint* first_header_lsn)
  438. /* out: lsn of of the start of the first log file */
  439. {
  440. ulint max_cp = 0;
  441. dulint max_cp_no = ut_dulint_zero;
  442. byte* cp_buf;
  443. cp_buf = hdr + LOG_CHECKPOINT_1;
  444. if (recv_check_cp_is_consistent(cp_buf)) {
  445. max_cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO);
  446. max_cp = LOG_CHECKPOINT_1;
  447. }
  448. cp_buf = hdr + LOG_CHECKPOINT_2;
  449. if (recv_check_cp_is_consistent(cp_buf)) {
  450. if (ut_dulint_cmp(mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO),
  451. max_cp_no) > 0) {
  452. max_cp = LOG_CHECKPOINT_2;
  453. }
  454. }
  455. if (max_cp == 0) {
  456. return(FALSE);
  457. }
  458. cp_buf = hdr + max_cp;
  459. *lsn = mach_read_from_8(cp_buf + LOG_CHECKPOINT_LSN);
  460. *offset = mach_read_from_4(cp_buf + LOG_CHECKPOINT_OFFSET);
  461. /* If the user is running a pre-3.23.50 version of InnoDB, its
  462. checkpoint data does not contain the fsp limit info */
  463. if (mach_read_from_4(cp_buf + LOG_CHECKPOINT_FSP_MAGIC_N)
  464.     == LOG_CHECKPOINT_FSP_MAGIC_N_VAL) {
  465. *fsp_limit = mach_read_from_4(
  466. cp_buf + LOG_CHECKPOINT_FSP_FREE_LIMIT);
  467. if (*fsp_limit == 0) {
  468. *fsp_limit = 1000000000;
  469. }
  470. } else {
  471. *fsp_limit = 1000000000;
  472. }
  473. /* fprintf(stderr, "fsp limit %lu MBn", *fsp_limit); */
  474. *cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO);
  475. *first_header_lsn = mach_read_from_8(hdr + LOG_FILE_START_LSN);
  476. return(TRUE);
  477. }
  478. /**********************************************************
  479. Checks the 4-byte checksum to the trailer checksum field of a log block.
  480. We also accept a log block in the old format < InnoDB-3.23.52 where the
  481. checksum field contains the log block number. */
  482. static
  483. ibool
  484. log_block_checksum_is_ok_or_old_format(
  485. /*===================================*/
  486. /* out: TRUE if ok, or if the log block may be in the
  487. format of InnoDB version < 3.23.52 */
  488. byte* block) /* in: pointer to a log block */
  489. {
  490. #ifdef UNIV_LOG_DEBUG
  491. return(TRUE);
  492. #endif /* UNIV_LOG_DEBUG */
  493. if (log_block_calc_checksum(block) == log_block_get_checksum(block)) {
  494. return(TRUE);
  495. }
  496. if (log_block_get_hdr_no(block) == log_block_get_checksum(block)) {
  497. /* We assume the log block is in the format of
  498. InnoDB version < 3.23.52 and the block is ok */
  499. /*
  500. fprintf(stderr,
  501. "InnoDB: Scanned old format < InnoDB-3.23.52 log block number %lun",
  502. log_block_get_hdr_no(block));
  503. */
  504. return(TRUE);
  505. }
  506. return(FALSE);
  507. }
  508. /***********************************************************************
  509. Scans the log segment and n_bytes_scanned is set to the length of valid
  510. log scanned. */
  511. void
  512. recv_scan_log_seg_for_backup(
  513. /*=========================*/
  514. byte* buf, /* in: buffer containing log data */
  515. ulint buf_len, /* in: data length in that buffer */
  516. dulint* scanned_lsn, /* in/out: lsn of buffer start,
  517. we return scanned lsn */
  518. ulint* scanned_checkpoint_no,
  519. /* in/out: 4 lowest bytes of the
  520. highest scanned checkpoint number so
  521. far */
  522. ulint* n_bytes_scanned)/* out: how much we were able to
  523. scan, smaller than buf_len if log
  524. data ended here */
  525. {
  526. ulint data_len;
  527. byte* log_block;
  528. ulint no;
  529. *n_bytes_scanned = 0;
  530. for (log_block = buf; log_block < buf + buf_len;
  531. log_block += OS_FILE_LOG_BLOCK_SIZE) {
  532. no = log_block_get_hdr_no(log_block);
  533. /* fprintf(stderr, "Log block header no %lun", no); */
  534. if (no != log_block_convert_lsn_to_no(*scanned_lsn)
  535.     || !log_block_checksum_is_ok_or_old_format(log_block)) {
  536. /*
  537. fprintf(stderr,
  538. "Log block n:o %lu, scanned lsn n:o %lun",
  539. no, log_block_convert_lsn_to_no(*scanned_lsn));
  540. */
  541. /* Garbage or an incompletely written log block */
  542. log_block += OS_FILE_LOG_BLOCK_SIZE;
  543. /*
  544. fprintf(stderr,
  545. "Next log block n:o %lun",
  546. log_block_get_hdr_no(log_block));
  547. */
  548. break;
  549. }
  550. if (*scanned_checkpoint_no > 0
  551.     && log_block_get_checkpoint_no(log_block)
  552. < *scanned_checkpoint_no
  553.     && *scanned_checkpoint_no
  554. - log_block_get_checkpoint_no(log_block)
  555. > 0x80000000UL) {
  556. /* Garbage from a log buffer flush which was made
  557. before the most recent database recovery */
  558. /*
  559. fprintf(stderr,
  560. "Scanned cp n:o %lu, block cp n:o %lun",
  561. *scanned_checkpoint_no,
  562. log_block_get_checkpoint_no(log_block));
  563. */
  564. break;
  565. }
  566. data_len = log_block_get_data_len(log_block);
  567. *scanned_checkpoint_no
  568. = log_block_get_checkpoint_no(log_block);
  569. *scanned_lsn = ut_dulint_add(*scanned_lsn, data_len);
  570. *n_bytes_scanned += data_len;
  571. if (data_len < OS_FILE_LOG_BLOCK_SIZE) {
  572. /* Log data ends here */
  573. /* fprintf(stderr, "Log block data len %lun",
  574. data_len); */
  575. break;
  576. }
  577. }
  578. }
  579. /***********************************************************************
  580. Tries to parse a single log record body and also applies it to a page if
  581. specified. File ops are parsed, but not applied in this function. */
  582. static
  583. byte*
  584. recv_parse_or_apply_log_rec_body(
  585. /*=============================*/
  586. /* out: log record end, NULL if not a complete
  587. record */
  588. byte type, /* in: type */
  589. byte* ptr, /* in: pointer to a buffer */
  590. byte* end_ptr,/* in: pointer to the buffer end */
  591. page_t* page, /* in: buffer page or NULL; if not NULL, then the log
  592. record is applied to the page, and the log record
  593. should be complete then */
  594. mtr_t* mtr) /* in: mtr or NULL; should be non-NULL if and only if
  595. page is non-NULL */
  596. {
  597. byte* new_ptr;
  598. if (type <= MLOG_8BYTES) {
  599. new_ptr = mlog_parse_nbytes(type, ptr, end_ptr, page);
  600. } else if (type == MLOG_REC_INSERT) {
  601. new_ptr = page_cur_parse_insert_rec(FALSE, ptr, end_ptr, page,
  602. mtr);
  603. } else if (type == MLOG_REC_CLUST_DELETE_MARK) {
  604. new_ptr = btr_cur_parse_del_mark_set_clust_rec(ptr, end_ptr,
  605. page);
  606. } else if (type == MLOG_REC_SEC_DELETE_MARK) {
  607. new_ptr = btr_cur_parse_del_mark_set_sec_rec(ptr, end_ptr,
  608. page);
  609. } else if (type == MLOG_REC_UPDATE_IN_PLACE) {
  610. new_ptr = btr_cur_parse_update_in_place(ptr, end_ptr, page);
  611. } else if ((type == MLOG_LIST_END_DELETE)
  612.    || (type == MLOG_LIST_START_DELETE)) {
  613. new_ptr = page_parse_delete_rec_list(type, ptr, end_ptr, page,
  614. mtr);
  615. } else if (type == MLOG_LIST_END_COPY_CREATED) {
  616. new_ptr = page_parse_copy_rec_list_to_created_page(ptr,
  617. end_ptr, page, mtr);
  618. } else if (type == MLOG_PAGE_REORGANIZE) {
  619. new_ptr = btr_parse_page_reorganize(ptr, end_ptr, page, mtr);
  620. } else if (type == MLOG_PAGE_CREATE) {
  621. new_ptr = page_parse_create(ptr, end_ptr, page, mtr);
  622. } else if (type == MLOG_UNDO_INSERT) {
  623. new_ptr = trx_undo_parse_add_undo_rec(ptr, end_ptr, page);
  624. } else if (type == MLOG_UNDO_ERASE_END) {
  625. new_ptr = trx_undo_parse_erase_page_end(ptr, end_ptr, page,
  626. mtr);
  627. } else if (type == MLOG_UNDO_INIT) {
  628. new_ptr = trx_undo_parse_page_init(ptr, end_ptr, page, mtr);
  629. } else if (type == MLOG_UNDO_HDR_DISCARD) {
  630. new_ptr = trx_undo_parse_discard_latest(ptr, end_ptr, page,
  631. mtr);
  632. } else if ((type == MLOG_UNDO_HDR_CREATE)
  633.    || (type == MLOG_UNDO_HDR_REUSE)) {
  634. new_ptr = trx_undo_parse_page_header(type, ptr, end_ptr, page,
  635. mtr);
  636. } else if (type == MLOG_REC_MIN_MARK) {
  637. new_ptr = btr_parse_set_min_rec_mark(ptr, end_ptr, page, mtr);
  638. } else if (type == MLOG_REC_DELETE) {
  639. new_ptr = page_cur_parse_delete_rec(ptr, end_ptr, page, mtr);
  640. } else if (type == MLOG_IBUF_BITMAP_INIT) {
  641. new_ptr = ibuf_parse_bitmap_init(ptr, end_ptr, page, mtr);
  642. } else if (type == MLOG_INIT_FILE_PAGE) {
  643. new_ptr = fsp_parse_init_file_page(ptr, end_ptr, page);
  644. } else if (type == MLOG_WRITE_STRING) {
  645. new_ptr = mlog_parse_string(ptr, end_ptr, page);
  646. } else if (type == MLOG_FILE_CREATE
  647.    || type == MLOG_FILE_RENAME
  648.    || type == MLOG_FILE_DELETE) {
  649. new_ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, FALSE,
  650. ULINT_UNDEFINED);
  651. } else {
  652. new_ptr = NULL;
  653.  
  654. recv_sys->found_corrupt_log = TRUE;
  655. }
  656. ut_ad(!page || new_ptr);
  657. return(new_ptr);
  658. }
  659. /*************************************************************************
  660. Calculates the fold value of a page file address: used in inserting or
  661. searching for a log record in the hash table. */
  662. UNIV_INLINE
  663. ulint
  664. recv_fold(
  665. /*======*/
  666. /* out: folded value */
  667. ulint space, /* in: space */
  668. ulint page_no)/* in: page number */
  669. {
  670. return(ut_fold_ulint_pair(space, page_no));
  671. }
  672. /*************************************************************************
  673. Calculates the hash value of a page file address: used in inserting or
  674. searching for a log record in the hash table. */
  675. UNIV_INLINE
  676. ulint
  677. recv_hash(
  678. /*======*/
  679. /* out: folded value */
  680. ulint space, /* in: space */
  681. ulint page_no)/* in: page number */
  682. {
  683. return(hash_calc_hash(recv_fold(space, page_no), recv_sys->addr_hash));
  684. }
  685. /*************************************************************************
  686. Gets the hashed file address struct for a page. */
  687. static
  688. recv_addr_t*
  689. recv_get_fil_addr_struct(
  690. /*=====================*/
  691. /* out: file address struct, NULL if not found from
  692. the hash table */
  693. ulint space, /* in: space id */
  694. ulint page_no)/* in: page number */
  695. {
  696. recv_addr_t* recv_addr;
  697. recv_addr = HASH_GET_FIRST(recv_sys->addr_hash,
  698. recv_hash(space, page_no));
  699. while (recv_addr) {
  700. if ((recv_addr->space == space)
  701. && (recv_addr->page_no == page_no)) {
  702. break;
  703. }
  704. recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
  705. }
  706. return(recv_addr);
  707. }
  708. /***********************************************************************
  709. Adds a new log record to the hash table of log records. */
  710. static
  711. void
  712. recv_add_to_hash_table(
  713. /*===================*/
  714. byte type, /* in: log record type */
  715. ulint space, /* in: space id */
  716. ulint page_no, /* in: page number */
  717. byte* body, /* in: log record body */
  718. byte* rec_end, /* in: log record end */
  719. dulint start_lsn, /* in: start lsn of the mtr */
  720. dulint end_lsn) /* in: end lsn of the mtr */
  721. {
  722. recv_t* recv;
  723. ulint len;
  724. recv_data_t* recv_data;
  725. recv_data_t** prev_field;
  726. recv_addr_t* recv_addr;
  727. if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
  728. /* The tablespace does not exist any more: do not store the
  729. log record */
  730. return;
  731. }
  732. len = rec_end - body;
  733. recv = mem_heap_alloc(recv_sys->heap, sizeof(recv_t));
  734. recv->type = type;
  735. recv->len = rec_end - body;
  736. recv->start_lsn = start_lsn;
  737. recv->end_lsn = end_lsn;
  738. recv_addr = recv_get_fil_addr_struct(space, page_no);
  739. if (recv_addr == NULL) {
  740. recv_addr = mem_heap_alloc(recv_sys->heap,
  741. sizeof(recv_addr_t));
  742. recv_addr->space = space;
  743. recv_addr->page_no = page_no;
  744. recv_addr->state = RECV_NOT_PROCESSED;
  745. UT_LIST_INIT(recv_addr->rec_list);
  746. HASH_INSERT(recv_addr_t, addr_hash, recv_sys->addr_hash,
  747. recv_fold(space, page_no), recv_addr);
  748. recv_sys->n_addrs++;
  749. /* fprintf(stderr, "Inserting log rec for space %lu, page %lun",
  750.   space, page_no); */
  751. }
  752. UT_LIST_ADD_LAST(rec_list, recv_addr->rec_list, recv);
  753. prev_field = &(recv->data);
  754. /* Store the log record body in chunks of less than UNIV_PAGE_SIZE:
  755. recv_sys->heap grows into the buffer pool, and bigger chunks could not
  756. be allocated */
  757. while (rec_end > body) {
  758. len = rec_end - body;
  759. if (len > RECV_DATA_BLOCK_SIZE) {
  760. len = RECV_DATA_BLOCK_SIZE;
  761. }
  762. recv_data = mem_heap_alloc(recv_sys->heap,
  763. sizeof(recv_data_t) + len);
  764. *prev_field = recv_data;
  765. ut_memcpy(((byte*)recv_data) + sizeof(recv_data_t), body, len);
  766. prev_field = &(recv_data->next);
  767. body += len;
  768. }
  769. *prev_field = NULL;
  770. }
  771. /*************************************************************************
  772. Copies the log record body from recv to buf. */
  773. static
  774. void
  775. recv_data_copy_to_buf(
  776. /*==================*/
  777. byte* buf, /* in: buffer of length at least recv->len */
  778. recv_t* recv) /* in: log record */
  779. {
  780. recv_data_t* recv_data;
  781. ulint part_len;
  782. ulint len;
  783. len = recv->len;
  784. recv_data = recv->data;
  785. while (len > 0) {
  786. if (len > RECV_DATA_BLOCK_SIZE) {
  787. part_len = RECV_DATA_BLOCK_SIZE;
  788. } else {
  789. part_len = len;
  790. }
  791. ut_memcpy(buf, ((byte*)recv_data) + sizeof(recv_data_t),
  792. part_len);
  793. buf += part_len;
  794. len -= part_len;
  795. recv_data = recv_data->next;
  796. }
  797. }
  798. /****************************************************************************
  799. Applies the hashed log records to the page, if the page lsn is less than the
  800. lsn of a log record. This can be called when a buffer page has just been
  801. read in, or also for a page already in the buffer pool. */
  802. void
  803. recv_recover_page(
  804. /*==============*/
  805. ibool recover_backup, /* in: TRUE if we are recovering a backup
  806. page: then we do not acquire any latches
  807. since the page was read in outside the
  808. buffer pool */
  809. ibool just_read_in, /* in: TRUE if the i/o-handler calls this for
  810. a freshly read page */
  811. page_t* page, /* in: buffer page */
  812. ulint space, /* in: space id */
  813. ulint page_no) /* in: page number */
  814. {
  815. buf_block_t* block = NULL;
  816. recv_addr_t* recv_addr;
  817. recv_t* recv;
  818. byte* buf;
  819. dulint start_lsn;
  820. dulint end_lsn;
  821. dulint page_lsn;
  822. dulint page_newest_lsn;
  823. ibool modification_to_page;
  824. ibool success;
  825. mtr_t mtr;
  826. mutex_enter(&(recv_sys->mutex));
  827. if (recv_sys->apply_log_recs == FALSE) {
  828. /* Log records should not be applied now */
  829. mutex_exit(&(recv_sys->mutex));
  830. return;
  831. }
  832. recv_addr = recv_get_fil_addr_struct(space, page_no);
  833. if ((recv_addr == NULL)
  834.     || (recv_addr->state == RECV_BEING_PROCESSED)
  835.     || (recv_addr->state == RECV_PROCESSED)) {
  836. mutex_exit(&(recv_sys->mutex));
  837. return;
  838. }
  839. /* fprintf(stderr, "Recovering space %lu, page %lun", space, page_no); */
  840. recv_addr->state = RECV_BEING_PROCESSED;
  841. mutex_exit(&(recv_sys->mutex));
  842. mtr_start(&mtr);
  843. mtr_set_log_mode(&mtr, MTR_LOG_NONE);
  844. if (!recover_backup) {
  845. block = buf_block_align(page);
  846. if (just_read_in) {
  847.   /* Move the ownership of the x-latch on the page to this OS
  848.   thread, so that we can acquire a second x-latch on it. This
  849.   is needed for the operations to the page to pass the debug
  850.   checks. */
  851. rw_lock_x_lock_move_ownership(&(block->lock));
  852. }
  853. success = buf_page_get_known_nowait(RW_X_LATCH, page,
  854. BUF_KEEP_OLD,
  855. __FILE__, __LINE__,
  856. &mtr);
  857. ut_a(success);
  858. #ifdef UNIV_SYNC_DEBUG
  859. buf_page_dbg_add_level(page, SYNC_NO_ORDER_CHECK);
  860. #endif /* UNIV_SYNC_DEBUG */
  861. }
  862. /* Read the newest modification lsn from the page */
  863. page_lsn = mach_read_from_8(page + FIL_PAGE_LSN);
  864. if (!recover_backup) {
  865. /* It may be that the page has been modified in the buffer
  866. pool: read the newest modification lsn there */
  867. page_newest_lsn = buf_frame_get_newest_modification(page);
  868. if (!ut_dulint_is_zero(page_newest_lsn)) {
  869. page_lsn = page_newest_lsn;
  870. }
  871. } else {
  872. /* In recovery from a backup we do not really use the buffer
  873. pool */
  874. page_newest_lsn = ut_dulint_zero;
  875. }
  876. modification_to_page = FALSE;
  877. recv = UT_LIST_GET_FIRST(recv_addr->rec_list);
  878. while (recv) {
  879. end_lsn = recv->end_lsn;
  880. if (recv->len > RECV_DATA_BLOCK_SIZE) {
  881. /* We have to copy the record body to a separate
  882. buffer */
  883. buf = mem_alloc(recv->len);
  884. recv_data_copy_to_buf(buf, recv);
  885. } else {
  886. buf = ((byte*)(recv->data)) + sizeof(recv_data_t);
  887. }
  888. if (recv->type == MLOG_INIT_FILE_PAGE) {
  889. page_lsn = page_newest_lsn;
  890. mach_write_to_8(page + UNIV_PAGE_SIZE
  891. - FIL_PAGE_END_LSN_OLD_CHKSUM, ut_dulint_zero);
  892. mach_write_to_8(page + FIL_PAGE_LSN, ut_dulint_zero);
  893. }
  894. if (ut_dulint_cmp(recv->start_lsn, page_lsn) >= 0) {
  895. if (!modification_to_page) {
  896. modification_to_page = TRUE;
  897. start_lsn = recv->start_lsn;
  898. }
  899. if (log_debug_writes) {
  900. fprintf(stderr, 
  901.      "InnoDB: Applying log rec type %lu len %lu to space %lu page no %lun",
  902. (ulong) recv->type, (ulong) recv->len,
  903. (ulong) recv_addr->space,
  904. (ulong) recv_addr->page_no);
  905. }
  906. recv_parse_or_apply_log_rec_body(recv->type, buf,
  907. buf + recv->len, page, &mtr);
  908. mach_write_to_8(page + UNIV_PAGE_SIZE
  909. - FIL_PAGE_END_LSN_OLD_CHKSUM,
  910. ut_dulint_add(recv->start_lsn,
  911. recv->len));
  912. mach_write_to_8(page + FIL_PAGE_LSN,
  913. ut_dulint_add(recv->start_lsn,
  914. recv->len));
  915. }
  916. if (recv->len > RECV_DATA_BLOCK_SIZE) {
  917. mem_free(buf);
  918. }
  919. recv = UT_LIST_GET_NEXT(rec_list, recv);
  920. }
  921. mutex_enter(&(recv_sys->mutex));
  922. if (ut_dulint_cmp(recv_max_page_lsn, page_lsn) < 0) {
  923. recv_max_page_lsn = page_lsn;
  924. }
  925. recv_addr->state = RECV_PROCESSED;
  926. ut_a(recv_sys->n_addrs);
  927. recv_sys->n_addrs--;
  928. mutex_exit(&(recv_sys->mutex));
  929. if (!recover_backup && modification_to_page) {
  930. ut_a(block);
  931. buf_flush_recv_note_modification(block, start_lsn, end_lsn);
  932. }
  933. /* Make sure that committing mtr does not change the modification
  934. lsn values of page */
  935. mtr.modifications = FALSE;
  936. mtr_commit(&mtr);
  937. }
  938. /***********************************************************************
  939. Reads in pages which have hashed log records, from an area around a given
  940. page number. */
  941. static
  942. ulint
  943. recv_read_in_area(
  944. /*==============*/
  945. /* out: number of pages found */
  946. ulint space, /* in: space */
  947. ulint page_no)/* in: page number */
  948. {
  949. recv_addr_t* recv_addr;
  950. ulint page_nos[RECV_READ_AHEAD_AREA];
  951. ulint low_limit;
  952. ulint n;
  953. low_limit = page_no - (page_no % RECV_READ_AHEAD_AREA);
  954. n = 0;
  955. for (page_no = low_limit; page_no < low_limit + RECV_READ_AHEAD_AREA;
  956. page_no++) {
  957. recv_addr = recv_get_fil_addr_struct(space, page_no);
  958. if (recv_addr && !buf_page_peek(space, page_no)) {
  959. mutex_enter(&(recv_sys->mutex));
  960. if (recv_addr->state == RECV_NOT_PROCESSED) {
  961. recv_addr->state = RECV_BEING_READ;
  962. page_nos[n] = page_no;
  963. n++;
  964. }
  965. mutex_exit(&(recv_sys->mutex));
  966. }
  967. }
  968. buf_read_recv_pages(FALSE, space, page_nos, n);
  969. /*
  970. fprintf(stderr, "Recv pages at %lu n %lun", page_nos[0], n);
  971. */
  972. return(n);
  973. }
  974. /***********************************************************************
  975. Empties the hash table of stored log records, applying them to appropriate
  976. pages. */
  977. void
  978. recv_apply_hashed_log_recs(
  979. /*=======================*/
  980. ibool allow_ibuf) /* in: if TRUE, also ibuf operations are
  981. allowed during the application; if FALSE,
  982. no ibuf operations are allowed, and after
  983. the application all file pages are flushed to
  984. disk and invalidated in buffer pool: this
  985. alternative means that no new log records
  986. can be generated during the application;
  987. the caller must in this case own the log
  988. mutex */
  989. {
  990. recv_addr_t* recv_addr;
  991. page_t* page;
  992. ulint i;
  993. ulint space;
  994. ulint page_no;
  995. ulint n_pages;
  996. ibool has_printed = FALSE;
  997. mtr_t mtr;
  998. loop:
  999. mutex_enter(&(recv_sys->mutex));
  1000. if (recv_sys->apply_batch_on) {
  1001. mutex_exit(&(recv_sys->mutex));
  1002. os_thread_sleep(500000);
  1003. goto loop;
  1004. }
  1005. #ifdef UNIV_SYNC_DEBUG
  1006. ut_ad(!allow_ibuf == mutex_own(&log_sys->mutex));
  1007. #endif /* UNIV_SYNC_DEBUG */
  1008. if (!allow_ibuf) {
  1009. recv_no_ibuf_operations = TRUE;
  1010. }
  1011. recv_sys->apply_log_recs = TRUE;
  1012. recv_sys->apply_batch_on = TRUE;
  1013. for (i = 0; i < hash_get_n_cells(recv_sys->addr_hash); i++) {
  1014. recv_addr = HASH_GET_FIRST(recv_sys->addr_hash, i);
  1015. while (recv_addr) {
  1016. space = recv_addr->space;
  1017. page_no = recv_addr->page_no;
  1018. if (recv_addr->state == RECV_NOT_PROCESSED) {
  1019. if (!has_printed) {
  1020.      ut_print_timestamp(stderr);
  1021. fputs( 
  1022. "  InnoDB: Starting an apply batch of log records to the database...n"
  1023. "InnoDB: Progress in percents: ",stderr);
  1024. has_printed = TRUE;
  1025. }
  1026. mutex_exit(&(recv_sys->mutex));
  1027. if (buf_page_peek(space, page_no)) {
  1028. mtr_start(&mtr);
  1029. page = buf_page_get(space, page_no,
  1030. RW_X_LATCH, &mtr);
  1031. #ifdef UNIV_SYNC_DEBUG
  1032. buf_page_dbg_add_level(page,
  1033. SYNC_NO_ORDER_CHECK);
  1034. #endif /* UNIV_SYNC_DEBUG */
  1035. recv_recover_page(FALSE, FALSE, page,
  1036. space, page_no);
  1037. mtr_commit(&mtr);
  1038. } else {
  1039. recv_read_in_area(space, page_no);
  1040. }
  1041. mutex_enter(&(recv_sys->mutex));
  1042. }
  1043. recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
  1044. }
  1045. if (has_printed
  1046.     && (i * 100) / hash_get_n_cells(recv_sys->addr_hash)
  1047.     != ((i + 1) * 100)
  1048.              / hash_get_n_cells(recv_sys->addr_hash)) {
  1049.         fprintf(stderr, "%lu ",
  1050. (ulong) ((i * 100) / hash_get_n_cells(recv_sys->addr_hash)));
  1051. }
  1052. }
  1053. /* Wait until all the pages have been processed */
  1054. while (recv_sys->n_addrs != 0) {
  1055. mutex_exit(&(recv_sys->mutex));
  1056. os_thread_sleep(500000);
  1057. mutex_enter(&(recv_sys->mutex));
  1058. }
  1059. if (has_printed) {
  1060.         fprintf(stderr, "n");
  1061. }
  1062. if (!allow_ibuf) {
  1063. /* Flush all the file pages to disk and invalidate them in
  1064. the buffer pool */
  1065. mutex_exit(&(recv_sys->mutex));
  1066. mutex_exit(&(log_sys->mutex));
  1067. n_pages = buf_flush_batch(BUF_FLUSH_LIST, ULINT_MAX,
  1068. ut_dulint_max);
  1069. ut_a(n_pages != ULINT_UNDEFINED);
  1070. buf_flush_wait_batch_end(BUF_FLUSH_LIST);
  1071. buf_pool_invalidate();
  1072. mutex_enter(&(log_sys->mutex));
  1073. mutex_enter(&(recv_sys->mutex));
  1074. recv_no_ibuf_operations = FALSE;
  1075. }
  1076. recv_sys->apply_log_recs = FALSE;
  1077. recv_sys->apply_batch_on = FALSE;
  1078. recv_sys_empty_hash();
  1079. if (has_printed) {
  1080. fprintf(stderr, "InnoDB: Apply batch completedn");
  1081. }
  1082. mutex_exit(&(recv_sys->mutex));
  1083. }
  1084. /* This page is allocated from the buffer pool and used in the function
  1085. below */
  1086. page_t* recv_backup_application_page = NULL;
  1087. /***********************************************************************
  1088. Applies log records in the hash table to a backup. */
  1089. void
  1090. recv_apply_log_recs_for_backup(void)
  1091. /*================================*/
  1092. {
  1093. recv_addr_t* recv_addr;
  1094. ulint n_hash_cells;
  1095. byte* page;
  1096. ulint actual_size;
  1097. ibool success;
  1098. ulint error;
  1099. ulint i;
  1100. recv_sys->apply_log_recs = TRUE;
  1101. recv_sys->apply_batch_on = TRUE;
  1102. if (recv_backup_application_page == NULL) {
  1103. recv_backup_application_page = buf_frame_alloc();
  1104. }
  1105. page = recv_backup_application_page;
  1106. fputs(
  1107. "InnoDB: Starting an apply batch of log records to the database...n"
  1108. "InnoDB: Progress in percents: ", stderr);
  1109. n_hash_cells = hash_get_n_cells(recv_sys->addr_hash);
  1110. for (i = 0; i < n_hash_cells; i++) {
  1111.         /* The address hash table is externally chained */
  1112. recv_addr = hash_get_nth_cell(recv_sys->addr_hash, i)->node;
  1113. while (recv_addr != NULL) {
  1114. if (!fil_tablespace_exists_in_mem(recv_addr->space)) {
  1115. /*
  1116. fprintf(stderr,
  1117. "InnoDB: Warning: cannot apply log record to tablespace %lu page %lu,n"
  1118. "InnoDB: because tablespace with that id does not exist.n",
  1119.       recv_addr->space, recv_addr->page_no);
  1120. */
  1121. recv_addr->state = RECV_PROCESSED;
  1122. ut_a(recv_sys->n_addrs);
  1123. recv_sys->n_addrs--;
  1124. goto skip_this_recv_addr;
  1125. }
  1126. /* We simulate a page read made by the buffer pool, to
  1127. make sure the recovery apparatus works ok, for
  1128. example, the buf_frame_align() function. We must init
  1129. the block corresponding to buf_pool->frame_zero
  1130. (== page). */
  1131. buf_page_init_for_backup_restore(recv_addr->space,
  1132. recv_addr->page_no,
  1133. buf_block_align(page));
  1134. /* Extend the tablespace's last file if the page_no
  1135. does not fall inside its bounds; we assume the last
  1136. file is auto-extending, and ibbackup copied the file
  1137. when it still was smaller */
  1138. success = fil_extend_space_to_desired_size(
  1139. &actual_size,
  1140. recv_addr->space,
  1141. recv_addr->page_no + 1);
  1142. if (!success) {
  1143.   fprintf(stderr,
  1144. "InnoDB: Fatal error: cannot extend tablespace %lu to hold %lu pagesn",
  1145.      recv_addr->space, recv_addr->page_no);
  1146.      
  1147. exit(1);
  1148. }
  1149. /* Read the page from the tablespace file using the
  1150. fil0fil.c routines */
  1151. error = fil_io(OS_FILE_READ, TRUE, recv_addr->space,
  1152. recv_addr->page_no, 0, UNIV_PAGE_SIZE,
  1153. page, NULL);
  1154. if (error != DB_SUCCESS) {
  1155.   fprintf(stderr,
  1156. "InnoDB: Fatal error: cannot read from tablespace %lu page number %lun",
  1157.      (ulong) recv_addr->space, (ulong) recv_addr->page_no);
  1158.      
  1159. exit(1);
  1160. }
  1161. /* Apply the log records to this page */
  1162. recv_recover_page(TRUE, FALSE, page, recv_addr->space,
  1163.        recv_addr->page_no);
  1164. /* Write the page back to the tablespace file using the
  1165. fil0fil.c routines */
  1166. buf_flush_init_for_writing(page,
  1167. mach_read_from_8(page + FIL_PAGE_LSN),
  1168. recv_addr->space, recv_addr->page_no);
  1169. error = fil_io(OS_FILE_WRITE, TRUE, recv_addr->space,
  1170. recv_addr->page_no, 0, UNIV_PAGE_SIZE,
  1171. page, NULL);
  1172. skip_this_recv_addr:
  1173. recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
  1174. }
  1175. if ((100 * i) / n_hash_cells
  1176. != (100 * (i + 1)) / n_hash_cells) {
  1177. fprintf(stderr, "%lu ",
  1178.                                 (ulong) ((100 * i) / n_hash_cells));
  1179. fflush(stderr);
  1180. }
  1181. }
  1182. recv_sys_empty_hash();
  1183. }
  1184. #ifdef notdefined
  1185. /***********************************************************************
  1186. In the debug version, updates the replica of a file page, based on a log
  1187. record. */
  1188. static
  1189. void
  1190. recv_update_replicate(
  1191. /*==================*/
  1192. byte type, /* in: log record type */
  1193. ulint space, /* in: space id */
  1194. ulint page_no,/* in: page number */
  1195. byte* body, /* in: log record body */
  1196. byte* end_ptr)/* in: log record end */
  1197. {
  1198. page_t* replica;
  1199. mtr_t mtr;
  1200. byte* ptr;
  1201. mtr_start(&mtr);
  1202. mtr_set_log_mode(&mtr, MTR_LOG_NONE);
  1203. replica = buf_page_get(space + RECV_REPLICA_SPACE_ADD, page_no,
  1204. RW_X_LATCH, &mtr);
  1205. #ifdef UNIV_SYNC_DEBUG
  1206. buf_page_dbg_add_level(replica, SYNC_NO_ORDER_CHECK);
  1207. #endif /* UNIV_SYNC_DEBUG */
  1208. ptr = recv_parse_or_apply_log_rec_body(type, body, end_ptr, replica,
  1209. &mtr);
  1210. ut_a(ptr == end_ptr);
  1211. /* Notify the buffer manager that the page has been updated */
  1212. buf_flush_recv_note_modification(buf_block_align(replica),
  1213. log_sys->old_lsn, log_sys->old_lsn);
  1214. /* Make sure that committing mtr does not call log routines, as
  1215. we currently own the log mutex */
  1216. mtr.modifications = FALSE;
  1217. mtr_commit(&mtr);
  1218. }
  1219. /***********************************************************************
  1220. Checks that two strings are identical. */
  1221. static
  1222. void
  1223. recv_check_identical(
  1224. /*=================*/
  1225. byte* str1, /* in: first string */
  1226. byte* str2, /* in: second string */
  1227. ulint len) /* in: length of strings */
  1228. {
  1229. ulint i;
  1230. for (i = 0; i < len; i++) {
  1231. if (str1[i] != str2[i]) {
  1232. fprintf(stderr,
  1233. "Strings do not match at offset %lun", i);
  1234. ut_print_buf(str1 + i, 16);
  1235. fprintf(stderr, "n");
  1236. ut_print_buf(str2 + i, 16);
  1237. ut_error;
  1238. }
  1239. }
  1240. }
  1241. /***********************************************************************
  1242. In the debug version, checks that the replica of a file page is identical
  1243. to the original page. */
  1244. static
  1245. void
  1246. recv_compare_replicate(
  1247. /*===================*/
  1248. ulint space, /* in: space id */
  1249. ulint page_no)/* in: page number */
  1250. {
  1251. page_t* replica;
  1252. page_t* page;
  1253. mtr_t mtr;
  1254. mtr_start(&mtr);
  1255. mutex_enter(&(buf_pool->mutex));
  1256. page = buf_page_hash_get(space, page_no)->frame;
  1257. mutex_exit(&(buf_pool->mutex));
  1258. replica = buf_page_get(space + RECV_REPLICA_SPACE_ADD, page_no,
  1259. RW_X_LATCH, &mtr);
  1260. #ifdef UNIV_SYNC_DEBUG
  1261. buf_page_dbg_add_level(replica, SYNC_NO_ORDER_CHECK);
  1262. #endif /* UNIV_SYNC_DEBUG */
  1263. recv_check_identical(page + FIL_PAGE_DATA,
  1264. replica + FIL_PAGE_DATA,
  1265. PAGE_HEADER + PAGE_MAX_TRX_ID - FIL_PAGE_DATA);
  1266. recv_check_identical(page + PAGE_HEADER + PAGE_MAX_TRX_ID + 8,
  1267. replica + PAGE_HEADER + PAGE_MAX_TRX_ID + 8,
  1268. UNIV_PAGE_SIZE - FIL_PAGE_DATA_END
  1269. - PAGE_HEADER - PAGE_MAX_TRX_ID - 8);
  1270. mtr_commit(&mtr);
  1271. }
  1272. /***********************************************************************
  1273. Checks that a replica of a space is identical to the original space. */
  1274. void
  1275. recv_compare_spaces(
  1276. /*================*/
  1277. ulint space1, /* in: space id */
  1278. ulint space2, /* in: space id */
  1279. ulint n_pages)/* in: number of pages */
  1280. {
  1281. page_t* replica;
  1282. page_t* page;
  1283. mtr_t mtr;
  1284. page_t* frame;
  1285. ulint page_no;
  1286. replica = buf_frame_alloc();
  1287. page = buf_frame_alloc();
  1288. for (page_no = 0; page_no < n_pages; page_no++) {
  1289. mtr_start(&mtr);
  1290. frame = buf_page_get_gen(space1, page_no, RW_S_LATCH, NULL,
  1291. BUF_GET_IF_IN_POOL,
  1292. __FILE__, __LINE__,
  1293. &mtr);
  1294. if (frame) {
  1295. #ifdef UNIV_SYNC_DEBUG
  1296. buf_page_dbg_add_level(frame, SYNC_NO_ORDER_CHECK);
  1297. #endif /* UNIV_SYNC_DEBUG */
  1298. ut_memcpy(page, frame, UNIV_PAGE_SIZE);
  1299. } else {
  1300. /* Read it from file */
  1301. fil_io(OS_FILE_READ, TRUE, space1, page_no, 0,
  1302. UNIV_PAGE_SIZE, page, NULL);
  1303. }
  1304. frame = buf_page_get_gen(space2, page_no, RW_S_LATCH, NULL,
  1305. BUF_GET_IF_IN_POOL,
  1306. __FILE__, __LINE__,
  1307. &mtr);
  1308. if (frame) {
  1309. #ifdef UNIV_SYNC_DEBUG
  1310. buf_page_dbg_add_level(frame, SYNC_NO_ORDER_CHECK);
  1311. #endif /* UNIV_SYNC_DEBUG */
  1312. ut_memcpy(replica, frame, UNIV_PAGE_SIZE);
  1313. } else {
  1314. /* Read it from file */
  1315. fil_io(OS_FILE_READ, TRUE, space2, page_no, 0,
  1316. UNIV_PAGE_SIZE, replica, NULL);
  1317. }
  1318. recv_check_identical(page + FIL_PAGE_DATA,
  1319. replica + FIL_PAGE_DATA,
  1320. PAGE_HEADER + PAGE_MAX_TRX_ID - FIL_PAGE_DATA);
  1321. recv_check_identical(page + PAGE_HEADER + PAGE_MAX_TRX_ID + 8,
  1322. replica + PAGE_HEADER + PAGE_MAX_TRX_ID + 8,
  1323. UNIV_PAGE_SIZE - FIL_PAGE_DATA_END
  1324. - PAGE_HEADER - PAGE_MAX_TRX_ID - 8);
  1325. mtr_commit(&mtr);
  1326. }
  1327. buf_frame_free(replica);
  1328. buf_frame_free(page);
  1329. }
  1330. /***********************************************************************
  1331. Checks that a replica of a space is identical to the original space. Disables
  1332. ibuf operations and flushes and invalidates the buffer pool pages after the
  1333. test. This function can be used to check the recovery before dict or trx
  1334. systems are initialized. */
  1335. void
  1336. recv_compare_spaces_low(
  1337. /*====================*/
  1338. ulint space1, /* in: space id */
  1339. ulint space2, /* in: space id */
  1340. ulint n_pages)/* in: number of pages */
  1341. {
  1342. mutex_enter(&(log_sys->mutex));
  1343. recv_apply_hashed_log_recs(FALSE);
  1344. mutex_exit(&(log_sys->mutex));
  1345. recv_compare_spaces(space1, space2, n_pages);
  1346. }
  1347. #endif /* UNIV_LOG_REPLICATE */
  1348. /***********************************************************************
  1349. Tries to parse a single log record and returns its length. */
  1350. static
  1351. ulint
  1352. recv_parse_log_rec(
  1353. /*===============*/
  1354. /* out: length of the record, or 0 if the record was
  1355. not complete */
  1356. byte* ptr, /* in: pointer to a buffer */
  1357. byte* end_ptr,/* in: pointer to the buffer end */
  1358. byte* type, /* out: type */
  1359. ulint* space, /* out: space id */
  1360. ulint* page_no,/* out: page number */
  1361. byte** body) /* out: log record body start */
  1362. {
  1363. byte* new_ptr;
  1364. if (ptr == end_ptr) {
  1365. return(0);
  1366. }
  1367. if (*ptr == MLOG_MULTI_REC_END) {
  1368. *type = *ptr;
  1369. return(1);
  1370. }
  1371. if (*ptr == MLOG_DUMMY_RECORD) {
  1372. *type = *ptr;
  1373. *space = ULINT_UNDEFINED - 1; /* For debugging */
  1374. return(1);
  1375. }
  1376. new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space,
  1377. page_no);
  1378. if (!new_ptr) {
  1379.         return(0);
  1380. }
  1381. /* Check that page_no is sensible */
  1382. if (*page_no > 0x8FFFFFFFUL) {
  1383. recv_sys->found_corrupt_log = TRUE;
  1384. return(0);
  1385. }
  1386. *body = new_ptr;
  1387. new_ptr = recv_parse_or_apply_log_rec_body(*type, new_ptr, end_ptr,
  1388. NULL, NULL);
  1389. if (new_ptr == NULL) {
  1390. return(0);
  1391. }
  1392. if (*page_no > recv_max_parsed_page_no) {
  1393. recv_max_parsed_page_no = *page_no;
  1394. }
  1395. return(new_ptr - ptr);
  1396. }
  1397. /***********************************************************
  1398. Calculates the new value for lsn when more data is added to the log. */
  1399. static
  1400. dulint
  1401. recv_calc_lsn_on_data_add(
  1402. /*======================*/
  1403. dulint lsn, /* in: old lsn */
  1404. ulint len) /* in: this many bytes of data is added, log block
  1405. headers not included */
  1406. {
  1407. ulint frag_len;
  1408. ulint lsn_len;
  1409. frag_len = (ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE)
  1410.     - LOG_BLOCK_HDR_SIZE;
  1411. ut_ad(frag_len < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE
  1412.        - LOG_BLOCK_TRL_SIZE);
  1413. lsn_len = len + ((len + frag_len)
  1414.       / (OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE
  1415.        - LOG_BLOCK_TRL_SIZE))
  1416.        * (LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE);
  1417. return(ut_dulint_add(lsn, lsn_len));
  1418. }
  1419. /***********************************************************
  1420. Checks that the parser recognizes incomplete initial segments of a log
  1421. record as incomplete. */
  1422. void
  1423. recv_check_incomplete_log_recs(
  1424. /*===========================*/
  1425. byte* ptr, /* in: pointer to a complete log record */
  1426. ulint len) /* in: length of the log record */
  1427. {
  1428. ulint i;
  1429. byte type;
  1430. ulint space;
  1431. ulint page_no;
  1432. byte* body;
  1433. for (i = 0; i < len; i++) {
  1434. ut_a(0 == recv_parse_log_rec(ptr, ptr + i, &type, &space,
  1435. &page_no, &body));
  1436. }
  1437. }
  1438. /***********************************************************
  1439. Prints diagnostic info of corrupt log. */
  1440. static
  1441. void
  1442. recv_report_corrupt_log(
  1443. /*====================*/
  1444. byte* ptr, /* in: pointer to corrupt log record */
  1445. byte type, /* in: type of the record */
  1446. ulint space, /* in: space id, this may also be garbage */
  1447. ulint page_no)/* in: page number, this may also be garbage */
  1448. {
  1449. fprintf(stderr,
  1450. "InnoDB: ############### CORRUPT LOG RECORD FOUNDn"
  1451. "InnoDB: Log record type %lu, space id %lu, page number %lun"
  1452. "InnoDB: Log parsing proceeded successfully up to %lu %lun"
  1453. "InnoDB: Previous log record type %lu, is multi %lun"
  1454. "InnoDB: Recv offset %lu, prev %lun",
  1455. (ulong) type, (ulong) space, (ulong) page_no,
  1456. (ulong) ut_dulint_get_high(recv_sys->recovered_lsn),
  1457.         (ulong) ut_dulint_get_low(recv_sys->recovered_lsn),
  1458. (ulong) recv_previous_parsed_rec_type,
  1459. (ulong) recv_previous_parsed_rec_is_multi,
  1460. (ulong) (ptr - recv_sys->buf),
  1461. (ulong) recv_previous_parsed_rec_offset);
  1462. if ((ulint)(ptr - recv_sys->buf + 100)
  1463. > recv_previous_parsed_rec_offset
  1464.     && (ulint)(ptr - recv_sys->buf + 100
  1465. - recv_previous_parsed_rec_offset)
  1466.        < 200000) {
  1467. fputs(
  1468. "InnoDB: Hex dump of corrupt log starting 100 bytes before the startn"
  1469. "InnoDB: of the previous log rec,n"
  1470. "InnoDB: and ending 100 bytes after the start of the corrupt rec:n",
  1471. stderr);
  1472.  
  1473. ut_print_buf(stderr,
  1474.      recv_sys->buf + recv_previous_parsed_rec_offset - 100,
  1475.      ptr - recv_sys->buf + 200 -
  1476. recv_previous_parsed_rec_offset);
  1477. putc('n', stderr);
  1478. }
  1479. fputs(
  1480. "InnoDB: WARNING: the log file may have been corrupt and itn"
  1481. "InnoDB: is possible that the log scan did not proceedn"
  1482. "InnoDB: far enough in recovery! Please run CHECK TABLEn"
  1483. "InnoDB: on your InnoDB tables to check that they are ok!n"
  1484. "InnoDB: If mysqld crashes after this recovery, look atn"
  1485. "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.htmln"
  1486. "InnoDB: about forcing recovery.n", stderr);
  1487. fflush(stderr);
  1488. }
  1489. /***********************************************************
  1490. Parses log records from a buffer and stores them to a hash table to wait
  1491. merging to file pages. */
  1492. static
  1493. ibool
  1494. recv_parse_log_recs(
  1495. /*================*/
  1496. /* out: currently always returns FALSE */
  1497. ibool store_to_hash) /* in: TRUE if the records should be stored
  1498. to the hash table; this is set to FALSE if just
  1499. debug checking is needed */
  1500. {
  1501. byte* ptr;
  1502. byte* end_ptr;
  1503. ulint single_rec;
  1504. ulint len;
  1505. ulint total_len;
  1506. dulint new_recovered_lsn;
  1507. dulint old_lsn;
  1508. byte type;
  1509. ulint space;
  1510. ulint page_no;
  1511. byte* body;
  1512. ulint n_recs;
  1513. #ifdef UNIV_SYNC_DEBUG
  1514. ut_ad(mutex_own(&(log_sys->mutex)));
  1515. #endif /* UNIV_SYNC_DEBUG */
  1516. ut_ad(!ut_dulint_is_zero(recv_sys->parse_start_lsn));
  1517. loop:
  1518. ptr = recv_sys->buf + recv_sys->recovered_offset;
  1519. end_ptr = recv_sys->buf + recv_sys->len;
  1520. if (ptr == end_ptr) {
  1521. return(FALSE);
  1522. }
  1523. single_rec = (ulint)*ptr & MLOG_SINGLE_REC_FLAG;
  1524. if (single_rec || *ptr == MLOG_DUMMY_RECORD) {
  1525. /* The mtr only modified a single page, or this is a file op */
  1526. old_lsn = recv_sys->recovered_lsn;
  1527. /* Try to parse a log record, fetching its type, space id,
  1528. page no, and a pointer to the body of the log record */
  1529. len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
  1530. &page_no, &body);
  1531. if (len == 0 || recv_sys->found_corrupt_log) {
  1532. if (recv_sys->found_corrupt_log) {
  1533. recv_report_corrupt_log(ptr,
  1534. type, space, page_no);
  1535. }
  1536. return(FALSE);
  1537. }
  1538. new_recovered_lsn = recv_calc_lsn_on_data_add(old_lsn, len);
  1539. if (ut_dulint_cmp(new_recovered_lsn, recv_sys->scanned_lsn)
  1540. > 0) {
  1541. /* The log record filled a log block, and we require
  1542. that also the next log block should have been scanned
  1543. in */
  1544. return(FALSE);
  1545. }
  1546. recv_previous_parsed_rec_type = (ulint)type;
  1547. recv_previous_parsed_rec_offset = recv_sys->recovered_offset;
  1548. recv_previous_parsed_rec_is_multi = 0;
  1549. recv_sys->recovered_offset += len;
  1550. recv_sys->recovered_lsn = new_recovered_lsn;
  1551. if (log_debug_writes) {
  1552. fprintf(stderr, 
  1553. "InnoDB: Parsed a single log rec type %lu len %lu space %lu page no %lun",
  1554. (ulong) type, (ulong) len, (ulong) space,
  1555. (ulong) page_no);
  1556. }
  1557. if (type == MLOG_DUMMY_RECORD) {
  1558. /* Do nothing */
  1559. } else if (store_to_hash && (type == MLOG_FILE_CREATE
  1560.      || type == MLOG_FILE_RENAME
  1561.      || type == MLOG_FILE_DELETE)) {
  1562. #ifdef UNIV_HOTBACKUP
  1563. if (recv_replay_file_ops) {
  1564. /* In ibbackup --apply-log, replay an .ibd file
  1565. operation, if possible; note that
  1566. fil_path_to_mysql_datadir is set in ibbackup to
  1567. point to the datadir we should use there */
  1568. if (NULL == fil_op_log_parse_or_replay(body,
  1569. end_ptr, type, TRUE, space)) {
  1570. fprintf(stderr,
  1571. "InnoDB: Error: file op log record of type %lu space %lu not complete inn"
  1572. "InnoDB: the replay phase. Path %sn", (ulint)type, space, (char*)(body + 2));
  1573. ut_a(0);
  1574. }
  1575. }
  1576. #endif
  1577. /* In normal mysqld crash recovery we do not try to
  1578. replay file operations */
  1579. } else if (store_to_hash) {
  1580. recv_add_to_hash_table(type, space, page_no, body,
  1581. ptr + len, old_lsn,
  1582. recv_sys->recovered_lsn);
  1583. } else {
  1584. /* In debug checking, update a replicate page
  1585. according to the log record, and check that it
  1586. becomes identical with the original page */
  1587. #ifdef UNIV_LOG_DEBUG
  1588. recv_check_incomplete_log_recs(ptr, len);
  1589. #endif/* UNIV_LOG_DEBUG */
  1590. #ifdef UNIV_LOG_REPLICATE
  1591. recv_update_replicate(type, space, page_no, body,
  1592. ptr + len);
  1593. recv_compare_replicate(space, page_no);
  1594. #endif /* UNIV_LOG_REPLICATE */
  1595. }
  1596. } else {
  1597. /* Check that all the records associated with the single mtr
  1598. are included within the buffer */
  1599. total_len = 0;
  1600. n_recs = 0;
  1601. for (;;) {
  1602. len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
  1603. &page_no, &body);
  1604. if (len == 0 || recv_sys->found_corrupt_log) {
  1605.      if (recv_sys->found_corrupt_log) {
  1606. recv_report_corrupt_log(ptr,
  1607. type, space, page_no);
  1608.      }
  1609.      return(FALSE);
  1610. }
  1611. recv_previous_parsed_rec_type = (ulint)type;
  1612. recv_previous_parsed_rec_offset
  1613. = recv_sys->recovered_offset + total_len;
  1614. recv_previous_parsed_rec_is_multi = 1;
  1615. if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) {
  1616. /* In debug checking, update a replicate page
  1617. according to the log record */
  1618. #ifdef UNIV_LOG_DEBUG
  1619. recv_check_incomplete_log_recs(ptr, len);
  1620. #endif /* UNIV_LOG_DEBUG */
  1621. #ifdef UNIV_LOG_REPLICATE
  1622. recv_update_replicate(type, space, page_no,
  1623. body, ptr + len);
  1624. #endif /* UNIV_LOG_REPLICATE */
  1625. }
  1626. if (log_debug_writes) {
  1627. fprintf(stderr, 
  1628. "InnoDB: Parsed a multi log rec type %lu len %lu space %lu page no %lun",
  1629. (ulong) type, (ulong) len, (ulong) space,
  1630. (ulong) page_no);
  1631. }
  1632. total_len += len;
  1633. n_recs++;
  1634. ptr += len;
  1635. if (type == MLOG_MULTI_REC_END) {
  1636. /* Found the end mark for the records */
  1637. break;
  1638. }
  1639. }
  1640. new_recovered_lsn = recv_calc_lsn_on_data_add(
  1641. recv_sys->recovered_lsn, total_len);
  1642. if (ut_dulint_cmp(new_recovered_lsn, recv_sys->scanned_lsn)
  1643. > 0) {
  1644. /* The log record filled a log block, and we require
  1645. that also the next log block should have been scanned
  1646. in */
  1647. return(FALSE);
  1648. }
  1649. /* Add all the records to the hash table */
  1650. ptr = recv_sys->buf + recv_sys->recovered_offset;
  1651. for (;;) {
  1652. old_lsn = recv_sys->recovered_lsn;
  1653. len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
  1654. &page_no, &body);
  1655. if (recv_sys->found_corrupt_log) {
  1656. recv_report_corrupt_log(ptr,
  1657. type, space, page_no);
  1658. }
  1659. ut_a(len != 0);
  1660. ut_a(0 == ((ulint)*ptr & MLOG_SINGLE_REC_FLAG));
  1661. recv_sys->recovered_offset += len;
  1662. recv_sys->recovered_lsn = recv_calc_lsn_on_data_add(
  1663. old_lsn, len);
  1664. if (type == MLOG_MULTI_REC_END) {
  1665. /* Found the end mark for the records */
  1666. break;
  1667. }
  1668. if (store_to_hash) {
  1669. recv_add_to_hash_table(type, space, page_no,
  1670. body, ptr + len, old_lsn,
  1671. new_recovered_lsn);
  1672. #ifdef UNIV_LOG_REPLICATE
  1673. } else {
  1674. /* In debug checking, check that the replicate
  1675. page has become identical with the original
  1676. page */
  1677. recv_compare_replicate(space, page_no);
  1678. #endif /* UNIV_LOG_REPLICATE */
  1679. }
  1680. ptr += len;
  1681. }
  1682. }
  1683.    
  1684. goto loop;
  1685. }
  1686. /***********************************************************
  1687. Adds data from a new log block to the parsing buffer of recv_sys if
  1688. recv_sys->parse_start_lsn is non-zero. */
  1689. static
  1690. ibool
  1691. recv_sys_add_to_parsing_buf(
  1692. /*========================*/
  1693. /* out: TRUE if more data added */
  1694. byte* log_block, /* in: log block */
  1695. dulint scanned_lsn) /* in: lsn of how far we were able to find
  1696. data in this log block */
  1697. {
  1698. ulint more_len;
  1699. ulint data_len;
  1700. ulint start_offset;
  1701. ulint end_offset;
  1702. ut_ad(ut_dulint_cmp(scanned_lsn, recv_sys->scanned_lsn) >= 0);
  1703. if (ut_dulint_is_zero(recv_sys->parse_start_lsn)) {
  1704. /* Cannot start parsing yet because no start point for
  1705. it found */
  1706. return(FALSE);
  1707. }
  1708. data_len = log_block_get_data_len(log_block);
  1709. if (ut_dulint_cmp(recv_sys->parse_start_lsn, scanned_lsn) >= 0) {
  1710. return(FALSE);
  1711. } else if (ut_dulint_cmp(recv_sys->scanned_lsn, scanned_lsn) >= 0) {
  1712. return(FALSE);
  1713. } else if (ut_dulint_cmp(recv_sys->parse_start_lsn,
  1714. recv_sys->scanned_lsn) > 0) {
  1715. more_len = ut_dulint_minus(scanned_lsn,
  1716. recv_sys->parse_start_lsn);
  1717. } else {
  1718. more_len = ut_dulint_minus(scanned_lsn, recv_sys->scanned_lsn);
  1719. }
  1720. if (more_len == 0) {
  1721. return(FALSE);
  1722. }
  1723. ut_ad(data_len >= more_len);
  1724. start_offset = data_len - more_len;
  1725. if (start_offset < LOG_BLOCK_HDR_SIZE) {
  1726. start_offset = LOG_BLOCK_HDR_SIZE;
  1727. }
  1728. end_offset = data_len;
  1729. if (end_offset > OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
  1730. end_offset = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE;
  1731. }
  1732. ut_ad(start_offset <= end_offset);
  1733. if (start_offset < end_offset) {
  1734. ut_memcpy(recv_sys->buf + recv_sys->len,
  1735. log_block + start_offset, end_offset - start_offset);
  1736. recv_sys->len += end_offset - start_offset;
  1737. ut_a(recv_sys->len <= RECV_PARSING_BUF_SIZE);
  1738. }
  1739. return(TRUE);
  1740. }
  1741. /***********************************************************
  1742. Moves the parsing buffer data left to the buffer start. */
  1743. static
  1744. void
  1745. recv_sys_justify_left_parsing_buf(void)
  1746. /*===================================*/
  1747. {
  1748. ut_memmove(recv_sys->buf, recv_sys->buf + recv_sys->recovered_offset,
  1749. recv_sys->len - recv_sys->recovered_offset);
  1750. recv_sys->len -= recv_sys->recovered_offset;
  1751. recv_sys->recovered_offset = 0;
  1752. }
  1753. /***********************************************************
  1754. Scans log from a buffer and stores new log data to the parsing buffer. Parses
  1755. and hashes the log records if new data found. */
  1756. ibool
  1757. recv_scan_log_recs(
  1758. /*===============*/
  1759. /* out: TRUE if limit_lsn has been reached, or
  1760. not able to scan any more in this log group */
  1761. ibool apply_automatically,/* in: TRUE if we want this function to
  1762. apply log records automatically when the
  1763. hash table becomes full; in the hot backup tool
  1764. the tool does the applying, not this
  1765. function */
  1766. ulint available_memory,/* in: we let the hash table of recs to grow
  1767. to this size, at the maximum */
  1768. ibool store_to_hash, /* in: TRUE if the records should be stored
  1769. to the hash table; this is set to FALSE if just
  1770. debug checking is needed */
  1771. byte* buf, /* in: buffer containing a log segment or
  1772. garbage */
  1773. ulint len, /* in: buffer length */
  1774. dulint start_lsn, /* in: buffer start lsn */
  1775. dulint* contiguous_lsn, /* in/out: it is known that all log groups
  1776. contain contiguous log data up to this lsn */
  1777. dulint* group_scanned_lsn)/* out: scanning succeeded up to this lsn */
  1778. {
  1779. byte* log_block;
  1780. ulint no;
  1781. dulint scanned_lsn;
  1782. ibool finished;
  1783. ulint data_len;
  1784. ibool more_data;
  1785. ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
  1786. ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0);
  1787. ut_ad(len > 0);
  1788. ut_a(apply_automatically <= TRUE);
  1789. ut_a(store_to_hash <= TRUE);
  1790. finished = FALSE;
  1791. log_block = buf;
  1792. scanned_lsn = start_lsn;
  1793. more_data = FALSE;
  1794. while (log_block < buf + len && !finished) {
  1795. no = log_block_get_hdr_no(log_block);
  1796. /*
  1797. fprintf(stderr, "Log block header no %lun", no);
  1798. fprintf(stderr, "Scanned lsn no %lun",
  1799. log_block_convert_lsn_to_no(scanned_lsn));
  1800. */
  1801. if (no != log_block_convert_lsn_to_no(scanned_lsn)
  1802.     || !log_block_checksum_is_ok_or_old_format(log_block)) {
  1803. if (no == log_block_convert_lsn_to_no(scanned_lsn)
  1804.     && !log_block_checksum_is_ok_or_old_format(
  1805. log_block)) {
  1806. fprintf(stderr,
  1807. "InnoDB: Log block no %lu at lsn %lu %lu hasn"
  1808. "InnoDB: ok header, but checksum field contains %lu, should be %lun",
  1809. (ulong) no,
  1810. (ulong) ut_dulint_get_high(scanned_lsn),
  1811. (ulong) ut_dulint_get_low(scanned_lsn),
  1812. (ulong) log_block_get_checksum(log_block),
  1813. (ulong) log_block_calc_checksum(log_block));
  1814. }
  1815. /* Garbage or an incompletely written log block */
  1816. finished = TRUE;
  1817. break;
  1818. }
  1819. if (log_block_get_flush_bit(log_block)) {
  1820. /* This block was a start of a log flush operation:
  1821. we know that the previous flush operation must have
  1822. been completed for all log groups before this block
  1823. can have been flushed to any of the groups. Therefore,
  1824. we know that log data is contiguous up to scanned_lsn
  1825. in all non-corrupt log groups. */
  1826. if (ut_dulint_cmp(scanned_lsn, *contiguous_lsn) > 0) {
  1827. *contiguous_lsn = scanned_lsn;
  1828. }
  1829. }
  1830. data_len = log_block_get_data_len(log_block);
  1831. if ((store_to_hash || (data_len == OS_FILE_LOG_BLOCK_SIZE))
  1832.     && (ut_dulint_cmp(ut_dulint_add(scanned_lsn, data_len),
  1833. recv_sys->scanned_lsn) > 0)
  1834.     && (recv_sys->scanned_checkpoint_no > 0)
  1835.     && (log_block_get_checkpoint_no(log_block)
  1836.        < recv_sys->scanned_checkpoint_no)
  1837.     && (recv_sys->scanned_checkpoint_no
  1838. - log_block_get_checkpoint_no(log_block)
  1839. > 0x80000000UL)) {
  1840. /* Garbage from a log buffer flush which was made
  1841. before the most recent database recovery */
  1842. finished = TRUE;
  1843. #ifdef UNIV_LOG_DEBUG
  1844. /* This is not really an error, but currently
  1845. we stop here in the debug version: */
  1846. ut_error;
  1847. #endif
  1848. break;
  1849. }     
  1850. if (ut_dulint_is_zero(recv_sys->parse_start_lsn)
  1851. && (log_block_get_first_rec_group(log_block) > 0)) {
  1852. /* We found a point from which to start the parsing
  1853. of log records */
  1854. recv_sys->parse_start_lsn =
  1855. ut_dulint_add(scanned_lsn,
  1856.    log_block_get_first_rec_group(log_block));
  1857. recv_sys->scanned_lsn = recv_sys->parse_start_lsn;
  1858. recv_sys->recovered_lsn = recv_sys->parse_start_lsn;
  1859. }
  1860. scanned_lsn = ut_dulint_add(scanned_lsn, data_len);
  1861. if (ut_dulint_cmp(scanned_lsn, recv_sys->scanned_lsn) > 0) {
  1862. /* We were able to find more log data: add it to the
  1863. parsing buffer if parse_start_lsn is already
  1864. non-zero */
  1865. if (recv_sys->len + 4 * OS_FILE_LOG_BLOCK_SIZE
  1866. >= RECV_PARSING_BUF_SIZE) {
  1867. fprintf(stderr,
  1868. "InnoDB: Error: log parsing buffer overflow. Recovery may have failed!n");
  1869. recv_sys->found_corrupt_log = TRUE;
  1870. } else if (!recv_sys->found_corrupt_log) {
  1871. more_data = recv_sys_add_to_parsing_buf(
  1872. log_block, scanned_lsn);
  1873. }
  1874. recv_sys->scanned_lsn = scanned_lsn;
  1875. recv_sys->scanned_checkpoint_no =
  1876. log_block_get_checkpoint_no(log_block);
  1877. }
  1878. if (data_len < OS_FILE_LOG_BLOCK_SIZE) {
  1879. /* Log data for this group ends here */
  1880. finished = TRUE;
  1881. } else {
  1882. log_block += OS_FILE_LOG_BLOCK_SIZE;
  1883. }
  1884. }
  1885. *group_scanned_lsn = scanned_lsn;
  1886. if (recv_needed_recovery
  1887.     || (recv_is_from_backup && !recv_is_making_a_backup)) {
  1888. recv_scan_print_counter++;
  1889. if (finished || (recv_scan_print_counter % 80 == 0)) {
  1890. fprintf(stderr, 
  1891. "InnoDB: Doing recovery: scanned up to log sequence number %lu %lun",
  1892. (ulong) ut_dulint_get_high(*group_scanned_lsn),
  1893. (ulong) ut_dulint_get_low(*group_scanned_lsn));
  1894. }
  1895. }
  1896. if (more_data && !recv_sys->found_corrupt_log) {
  1897. /* Try to parse more log records */
  1898. recv_parse_log_recs(store_to_hash);
  1899. if (store_to_hash && mem_heap_get_size(recv_sys->heap)
  1900. > available_memory
  1901.     && apply_automatically) {
  1902. /* Hash table of log records has grown too big:
  1903. empty it; FALSE means no ibuf operations
  1904. allowed, as we cannot add new records to the
  1905. log yet: they would be produced by ibuf
  1906. operations */
  1907. recv_apply_hashed_log_recs(FALSE);
  1908. if (recv_sys->recovered_offset > RECV_PARSING_BUF_SIZE / 4) {
  1909. /* Move parsing buffer data to the buffer start */
  1910. recv_sys_justify_left_parsing_buf();
  1911. }
  1912. }
  1913. return(finished);
  1914. }
  1915. /***********************************************************
  1916. Scans log from a buffer and stores new log data to the parsing buffer. Parses
  1917. and hashes the log records if new data found. */
  1918. static
  1919. void
  1920. recv_group_scan_log_recs(
  1921. /*=====================*/
  1922. log_group_t* group, /* in: log group */
  1923. dulint* contiguous_lsn, /* in/out: it is known that all log groups
  1924. contain contiguous log data up to this lsn */
  1925. dulint* group_scanned_lsn)/* out: scanning succeeded up to this lsn */
  1926. {
  1927. ibool finished;
  1928. dulint start_lsn;
  1929. dulint end_lsn;
  1930. finished = FALSE;
  1931. start_lsn = *contiguous_lsn;
  1932. while (!finished) {
  1933. end_lsn = ut_dulint_add(start_lsn, RECV_SCAN_SIZE);
  1934. log_group_read_log_seg(LOG_RECOVER, log_sys->buf,
  1935. group, start_lsn, end_lsn);
  1936. finished = recv_scan_log_recs(TRUE,
  1937.                                 (buf_pool->n_frames
  1938.                                 - recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
  1939. TRUE, log_sys->buf,
  1940. RECV_SCAN_SIZE, start_lsn,
  1941. contiguous_lsn, group_scanned_lsn);
  1942. start_lsn = end_lsn;
  1943. }
  1944. if (log_debug_writes) {
  1945. fprintf(stderr,
  1946. "InnoDB: Scanned group %lu up to log sequence number %lu %lun",
  1947. (ulong) group->id,
  1948. (ulong) ut_dulint_get_high(*group_scanned_lsn),
  1949. (ulong) ut_dulint_get_low(*group_scanned_lsn));
  1950. }
  1951. }
  1952. /************************************************************
  1953. Recovers from a checkpoint. When this function returns, the database is able
  1954. to start processing of new user transactions, but the function
  1955. recv_recovery_from_checkpoint_finish should be called later to complete
  1956. the recovery and free the resources used in it. */
  1957. ulint
  1958. recv_recovery_from_checkpoint_start(
  1959. /*================================*/
  1960. /* out: error code or DB_SUCCESS */
  1961. ulint type, /* in: LOG_CHECKPOINT or LOG_ARCHIVE */
  1962. dulint limit_lsn, /* in: recover up to this lsn if possible */
  1963. dulint min_flushed_lsn,/* in: min flushed lsn from data files */
  1964. dulint max_flushed_lsn)/* in: max flushed lsn from data files */
  1965. {
  1966. log_group_t* group;
  1967. log_group_t* max_cp_group;
  1968. log_group_t* up_to_date_group;
  1969. ulint max_cp_field;
  1970. dulint checkpoint_lsn;
  1971. dulint checkpoint_no;
  1972. dulint old_scanned_lsn;
  1973. dulint group_scanned_lsn;
  1974. dulint contiguous_lsn;
  1975. dulint archived_lsn;
  1976. ulint capacity;
  1977. byte* buf;
  1978. byte log_hdr_buf[LOG_FILE_HDR_SIZE];
  1979. ulint err;
  1980. ut_ad((type != LOG_CHECKPOINT)
  1981. || (ut_dulint_cmp(limit_lsn, ut_dulint_max) == 0));
  1982. if (type == LOG_CHECKPOINT) {
  1983. recv_sys_create();
  1984. recv_sys_init(FALSE, buf_pool_get_curr_size());
  1985. }
  1986. if (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) {
  1987. fprintf(stderr,
  1988. "InnoDB: The user has set SRV_FORCE_NO_LOG_REDO onn");
  1989. fprintf(stderr,
  1990. "InnoDB: Skipping log redon");
  1991. return(DB_SUCCESS);
  1992. }
  1993. recv_recovery_on = TRUE;
  1994. recv_sys->limit_lsn = limit_lsn;
  1995. mutex_enter(&(log_sys->mutex));
  1996. /* Look for the latest checkpoint from any of the log groups */
  1997. err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
  1998. if (err != DB_SUCCESS) {
  1999. mutex_exit(&(log_sys->mutex));
  2000. return(err);
  2001. }
  2002. log_group_read_checkpoint_info(max_cp_group, max_cp_field);
  2003. buf = log_sys->checkpoint_buf;
  2004. checkpoint_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_LSN);
  2005. checkpoint_no = mach_read_from_8(buf + LOG_CHECKPOINT_NO);
  2006. archived_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN);
  2007. /* Read the first log file header to print a note if this is
  2008. a recovery from a restored InnoDB Hot Backup */
  2009. fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, max_cp_group->space_id,
  2010. 0, 0, LOG_FILE_HDR_SIZE,
  2011. log_hdr_buf, max_cp_group);
  2012. if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
  2013. (byte*)"ibbackup", (sizeof "ibbackup") - 1)) {
  2014. /* This log file was created by ibbackup --restore: print
  2015. a note to the user about it */
  2016. fprintf(stderr,
  2017. "InnoDB: The log file was created by ibbackup --apply-log atn"
  2018. "InnoDB: %sn", log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP);
  2019. fprintf(stderr,
  2020. "InnoDB: NOTE: the following crash recovery is part of a normal restore.n");
  2021. /* Wipe over the label now */
  2022. memset(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
  2023. ' ', 4);
  2024. /* Write to the log file to wipe over the label */
  2025. fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE,
  2026. max_cp_group->space_id,
  2027. 0, 0, OS_FILE_LOG_BLOCK_SIZE,
  2028. log_hdr_buf, max_cp_group);
  2029. }
  2030. #ifdef UNIV_LOG_ARCHIVE
  2031. group = UT_LIST_GET_FIRST(log_sys->log_groups);
  2032. while (group) {
  2033. log_checkpoint_get_nth_group_info(buf, group->id,
  2034. &(group->archived_file_no),
  2035. &(group->archived_offset));
  2036. group = UT_LIST_GET_NEXT(log_groups, group);
  2037. }
  2038. #endif /* UNIV_LOG_ARCHIVE */
  2039. if (type == LOG_CHECKPOINT) {
  2040. /* Start reading the log groups from the checkpoint lsn up. The
  2041. variable contiguous_lsn contains an lsn up to which the log is
  2042. known to be contiguously written to all log groups. */
  2043. recv_sys->parse_start_lsn = checkpoint_lsn;
  2044. recv_sys->scanned_lsn = checkpoint_lsn;
  2045. recv_sys->scanned_checkpoint_no = 0;
  2046. recv_sys->recovered_lsn = checkpoint_lsn;
  2047. srv_start_lsn = checkpoint_lsn;
  2048. /* NOTE: we always do a 'recovery' at startup, but only if
  2049. there is something wrong we will print a message to the
  2050. user about recovery: */
  2051. if (ut_dulint_cmp(checkpoint_lsn, max_flushed_lsn) != 0
  2052.         || ut_dulint_cmp(checkpoint_lsn, min_flushed_lsn) != 0) {
  2053. if (ut_dulint_cmp(checkpoint_lsn, max_flushed_lsn)
  2054. < 0) {
  2055. fprintf(stderr,
  2056. "InnoDB: ##########################################################n"
  2057. "InnoDB:                          WARNING!n"
  2058. "InnoDB: The log sequence number in ibdata files is highern"
  2059. "InnoDB: than the log sequence number in the ib_logfiles! Are you suren"
  2060. "InnoDB: you are using the right ib_logfiles to start up the database?n"
  2061. "InnoDB: Log sequence number in ib_logfiles is %lu %lu, logn"
  2062. "InnoDB: sequence numbers stamped to ibdata file headers are betweenn"
  2063. "InnoDB: %lu %lu and %lu %lu.n"
  2064. "InnoDB: ##########################################################n",
  2065. (ulong) ut_dulint_get_high(checkpoint_lsn),
  2066. (ulong) ut_dulint_get_low(checkpoint_lsn),
  2067. (ulong) ut_dulint_get_high(min_flushed_lsn),
  2068. (ulong) ut_dulint_get_low(min_flushed_lsn),
  2069. (ulong) ut_dulint_get_high(max_flushed_lsn),
  2070. (ulong) ut_dulint_get_low(max_flushed_lsn));
  2071. }
  2072.          recv_needed_recovery = TRUE;
  2073.         
  2074. ut_print_timestamp(stderr);
  2075.      fprintf(stderr,
  2076. "  InnoDB: Database was not shut down normally!n"
  2077. "InnoDB: Starting crash recovery.n");
  2078. fprintf(stderr,
  2079. "InnoDB: Reading tablespace information from the .ibd files...n");
  2080. fil_load_single_table_tablespaces();
  2081. /* If we are using the doublewrite method, we will
  2082. check if there are half-written pages in data files,
  2083. and restore them from the doublewrite buffer if
  2084. possible */
  2085. if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
  2086. fprintf(stderr,
  2087. "InnoDB: Restoring possible half-written data pages from the doublewriten"
  2088. "InnoDB: buffer...n");
  2089. trx_sys_doublewrite_init_or_restore_pages(
  2090. TRUE);
  2091. }
  2092. ut_print_timestamp(stderr);
  2093. fprintf(stderr, 
  2094. "  InnoDB: Starting log scan based on checkpoint atn"
  2095. "InnoDB: log sequence number %lu %lu.n",
  2096.   (ulong) ut_dulint_get_high(checkpoint_lsn),
  2097. (ulong) ut_dulint_get_low(checkpoint_lsn));
  2098. } else {
  2099. /* Init the doublewrite buffer memory structure */
  2100. trx_sys_doublewrite_init_or_restore_pages(FALSE);
  2101. }
  2102. }
  2103. contiguous_lsn = ut_dulint_align_down(recv_sys->scanned_lsn,
  2104. OS_FILE_LOG_BLOCK_SIZE);
  2105. if (type == LOG_ARCHIVE) {
  2106.   /* Try to recover the remaining part from logs: first from
  2107. the logs of the archived group */
  2108. group = recv_sys->archive_group;
  2109. capacity = log_group_get_capacity(group);
  2110. if ((ut_dulint_cmp(recv_sys->scanned_lsn,
  2111. ut_dulint_add(checkpoint_lsn, capacity)) > 0)
  2112.    || (ut_dulint_cmp(checkpoint_lsn,
  2113. ut_dulint_add(recv_sys->scanned_lsn, capacity)) > 0)) {
  2114. mutex_exit(&(log_sys->mutex));
  2115. /* The group does not contain enough log: probably
  2116. an archived log file was missing or corrupt */
  2117. return(DB_ERROR);
  2118. }
  2119. recv_group_scan_log_recs(group, &contiguous_lsn,
  2120. &group_scanned_lsn);
  2121. if (ut_dulint_cmp(recv_sys->scanned_lsn, checkpoint_lsn) < 0) {
  2122. mutex_exit(&(log_sys->mutex));
  2123. /* The group did not contain enough log: an archived
  2124. log file was missing or invalid, or the log group
  2125. was corrupt */
  2126. return(DB_ERROR);
  2127. }
  2128. group->scanned_lsn = group_scanned_lsn;
  2129. up_to_date_group = group;
  2130. } else {
  2131. up_to_date_group = max_cp_group;
  2132. }
  2133. ut_ad(RECV_SCAN_SIZE <= log_sys->buf_size);
  2134. group = UT_LIST_GET_FIRST(log_sys->log_groups);
  2135. if ((type == LOG_ARCHIVE) && (group == recv_sys->archive_group)) {
  2136. group = UT_LIST_GET_NEXT(log_groups, group);
  2137. }
  2138. while (group) {
  2139. old_scanned_lsn = recv_sys->scanned_lsn;
  2140. recv_group_scan_log_recs(group, &contiguous_lsn,
  2141. &group_scanned_lsn);
  2142. group->scanned_lsn = group_scanned_lsn;
  2143. if (ut_dulint_cmp(old_scanned_lsn, group_scanned_lsn) < 0) {
  2144. /* We found a more up-to-date group */
  2145. up_to_date_group = group;
  2146. }
  2147. if ((type == LOG_ARCHIVE)
  2148. && (group == recv_sys->archive_group)) {
  2149. group = UT_LIST_GET_NEXT(log_groups, group);
  2150. }
  2151. group = UT_LIST_GET_NEXT(log_groups, group);
  2152. }
  2153. /* We currently have only one log group */
  2154. if (ut_dulint_cmp(group_scanned_lsn, checkpoint_lsn) < 0) {
  2155. ut_print_timestamp(stderr);
  2156. fprintf(stderr,
  2157. "  InnoDB: ERROR: We were only able to scan the log up ton"
  2158. "InnoDB: %lu %lu, but a checkpoint was at %lu %lu.n"
  2159. "InnoDB: It is possible that the database is now corrupt!n",
  2160.  (ulong) ut_dulint_get_high(group_scanned_lsn),
  2161.  (ulong) ut_dulint_get_low(group_scanned_lsn),
  2162.  (ulong) ut_dulint_get_high(checkpoint_lsn),
  2163.  (ulong) ut_dulint_get_low(checkpoint_lsn));
  2164. }
  2165. if (ut_dulint_cmp(group_scanned_lsn, recv_max_page_lsn) < 0) {
  2166. ut_print_timestamp(stderr);
  2167. fprintf(stderr,
  2168. "  InnoDB: ERROR: We were only able to scan the log up to %lu %lun"
  2169. "InnoDB: but a database page a had an lsn %lu %lu. It is possible that then"
  2170. "InnoDB: database is now corrupt!n",
  2171.  (ulong) ut_dulint_get_high(group_scanned_lsn),
  2172.  (ulong) ut_dulint_get_low(group_scanned_lsn),
  2173.  (ulong) ut_dulint_get_high(recv_max_page_lsn),
  2174.  (ulong) ut_dulint_get_low(recv_max_page_lsn));
  2175. }
  2176. if (ut_dulint_cmp(recv_sys->recovered_lsn, checkpoint_lsn) < 0) {
  2177. mutex_exit(&(log_sys->mutex));
  2178. if (ut_dulint_cmp(recv_sys->recovered_lsn, limit_lsn) >= 0) {
  2179. return(DB_SUCCESS);
  2180. }
  2181. ut_error;
  2182. return(DB_ERROR);
  2183. }
  2184. /* Synchronize the uncorrupted log groups to the most up-to-date log
  2185. group; we also copy checkpoint info to groups */
  2186. log_sys->next_checkpoint_lsn = checkpoint_lsn;
  2187. log_sys->next_checkpoint_no = ut_dulint_add(checkpoint_no, 1);
  2188. #ifdef UNIV_LOG_ARCHIVE
  2189. log_sys->archived_lsn = archived_lsn;
  2190. #endif /* UNIV_LOG_ARCHIVE */
  2191. recv_synchronize_groups(up_to_date_group);
  2192. if (!recv_needed_recovery) {
  2193. if (ut_dulint_cmp(checkpoint_lsn, recv_sys->recovered_lsn)
  2194. != 0) {
  2195. fprintf(stderr,
  2196. "InnoDB: Warning: we did not need to do crash recovery, but log scann"
  2197. "InnoDB: progressed past the checkpoint lsn %lu %lu up to lsn %lu %lun",
  2198.  (ulong) ut_dulint_get_high(checkpoint_lsn),
  2199.  (ulong) ut_dulint_get_low(checkpoint_lsn),
  2200.  (ulong) ut_dulint_get_high(recv_sys->recovered_lsn),
  2201.  (ulong) ut_dulint_get_low(recv_sys->recovered_lsn));
  2202. }
  2203. } else {
  2204. srv_start_lsn = recv_sys->recovered_lsn;
  2205. }
  2206. log_sys->lsn = recv_sys->recovered_lsn;
  2207. ut_memcpy(log_sys->buf, recv_sys->last_block, OS_FILE_LOG_BLOCK_SIZE);
  2208. log_sys->buf_free = ut_dulint_get_low(log_sys->lsn)
  2209. % OS_FILE_LOG_BLOCK_SIZE;
  2210. log_sys->buf_next_to_write = log_sys->buf_free;
  2211. log_sys->written_to_some_lsn = log_sys->lsn;
  2212. log_sys->written_to_all_lsn = log_sys->lsn;
  2213. log_sys->last_checkpoint_lsn = checkpoint_lsn;
  2214. log_sys->next_checkpoint_no = ut_dulint_add(checkpoint_no, 1);
  2215. #ifdef UNIV_LOG_ARCHIVE
  2216. if (ut_dulint_cmp(archived_lsn, ut_dulint_max) == 0) {
  2217. log_sys->archiving_state = LOG_ARCH_OFF;
  2218. }
  2219. #endif /* UNIV_LOG_ARCHIVE */
  2220. mutex_enter(&(recv_sys->mutex));
  2221. recv_sys->apply_log_recs = TRUE;
  2222.   mutex_exit(&(recv_sys->mutex));
  2223. mutex_exit(&(log_sys->mutex));
  2224. recv_lsn_checks_on = TRUE;
  2225. /* The database is now ready to start almost normal processing of user
  2226. transactions: transaction rollbacks and the application of the log
  2227. records in the hash table can be run in background. */
  2228. return(DB_SUCCESS);
  2229. }
  2230. /************************************************************
  2231. Completes recovery from a checkpoint. */
  2232. void
  2233. recv_recovery_from_checkpoint_finish(void)
  2234. /*======================================*/
  2235. {
  2236. /* Rollback the uncommitted transactions which have no user session */
  2237. if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
  2238. trx_rollback_or_clean_all_without_sess();
  2239. }
  2240. /* Apply the hashed log records to the respective file pages */
  2241. if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
  2242. recv_apply_hashed_log_recs(TRUE);
  2243. }
  2244. if (log_debug_writes) {
  2245. fprintf(stderr,
  2246. "InnoDB: Log records applied to the databasen");
  2247. }
  2248. if (recv_needed_recovery) {
  2249. trx_sys_print_mysql_master_log_pos();
  2250. trx_sys_print_mysql_binlog_offset();
  2251. }
  2252. if (recv_sys->found_corrupt_log) {
  2253. fprintf(stderr,
  2254. "InnoDB: WARNING: the log file may have been corrupt and itn"
  2255. "InnoDB: is possible that the log scan or parsing did not proceedn"
  2256. "InnoDB: far enough in recovery. Please run CHECK TABLEn"
  2257. "InnoDB: on your InnoDB tables to check that they are ok!n"
  2258. "InnoDB: It may be safest to recover your InnoDB database fromn"
  2259. "InnoDB: a backup!n");
  2260. }
  2261. /* Free the resources of the recovery system */
  2262. recv_recovery_on = FALSE;
  2263. #ifndef UNIV_LOG_DEBUG
  2264. recv_sys_free();
  2265. #endif
  2266. }
  2267. /**********************************************************
  2268. Resets the logs. The contents of log files will be lost! */
  2269. void
  2270. recv_reset_logs(
  2271. /*============*/
  2272. dulint lsn, /* in: reset to this lsn rounded up to
  2273. be divisible by OS_FILE_LOG_BLOCK_SIZE,
  2274. after which we add LOG_BLOCK_HDR_SIZE */
  2275. #ifdef UNIV_LOG_ARCHIVE
  2276. ulint arch_log_no, /* in: next archived log file number */
  2277. #endif /* UNIV_LOG_ARCHIVE */
  2278. ibool new_logs_created)/* in: TRUE if resetting logs is done
  2279. at the log creation; FALSE if it is done
  2280. after archive recovery */
  2281. {
  2282. log_group_t* group;
  2283. #ifdef UNIV_SYNC_DEBUG
  2284. ut_ad(mutex_own(&(log_sys->mutex)));
  2285. #endif /* UNIV_SYNC_DEBUG */
  2286. log_sys->lsn = ut_dulint_align_up(lsn, OS_FILE_LOG_BLOCK_SIZE);
  2287. group = UT_LIST_GET_FIRST(log_sys->log_groups);
  2288. while (group) {
  2289. group->lsn = log_sys->lsn;
  2290. group->lsn_offset = LOG_FILE_HDR_SIZE;
  2291. #ifdef UNIV_LOG_ARCHIVE
  2292. group->archived_file_no = arch_log_no;
  2293. group->archived_offset = 0;
  2294. #endif /* UNIV_LOG_ARCHIVE */
  2295. if (!new_logs_created) {
  2296. recv_truncate_group(group, group->lsn, group->lsn,
  2297. group->lsn, group->lsn);
  2298. }
  2299. group = UT_LIST_GET_NEXT(log_groups, group);
  2300. }
  2301. log_sys->buf_next_to_write = 0;
  2302. log_sys->written_to_some_lsn = log_sys->lsn;
  2303. log_sys->written_to_all_lsn = log_sys->lsn;
  2304. log_sys->next_checkpoint_no = ut_dulint_zero;
  2305. log_sys->last_checkpoint_lsn = ut_dulint_zero;
  2306. #ifdef UNIV_LOG_ARCHIVE
  2307. log_sys->archived_lsn = log_sys->lsn;
  2308. #endif /* UNIV_LOG_ARCHIVE */
  2309. log_block_init(log_sys->buf, log_sys->lsn);
  2310. log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE);
  2311. log_sys->buf_free = LOG_BLOCK_HDR_SIZE;
  2312. log_sys->lsn = ut_dulint_add(log_sys->lsn, LOG_BLOCK_HDR_SIZE);
  2313. mutex_exit(&(log_sys->mutex));
  2314. /* Reset the checkpoint fields in logs */
  2315. log_make_checkpoint_at(ut_dulint_max, TRUE);
  2316. log_make_checkpoint_at(ut_dulint_max, TRUE);
  2317. mutex_enter(&(log_sys->mutex));
  2318. }
  2319. #ifdef UNIV_HOTBACKUP
  2320. /**********************************************************
  2321. Creates new log files after a backup has been restored. */
  2322. void
  2323. recv_reset_log_files_for_backup(
  2324. /*============================*/
  2325. const char* log_dir, /* in: log file directory path */
  2326. ulint n_log_files, /* in: number of log files */
  2327. ulint log_file_size, /* in: log file size */
  2328. dulint lsn) /* in: new start lsn, must be
  2329. divisible by OS_FILE_LOG_BLOCK_SIZE */
  2330. {
  2331. os_file_t log_file;
  2332. ibool success;
  2333. byte* buf;
  2334. ulint i;
  2335. ulint log_dir_len;
  2336. char* name;
  2337. static const
  2338. char logfilename[] = "ib_logfile";
  2339. log_dir_len = strlen(log_dir);
  2340. /* reserve space for log_dir, "ib_logfile" and a number */
  2341. name = memcpy(mem_alloc(log_dir_len + ((sizeof logfilename) + 11)),
  2342. log_dir, log_dir_len);
  2343. memcpy(name + log_dir_len, logfilename, sizeof logfilename);
  2344. buf = ut_malloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
  2345.         memset(buf, '', LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
  2346. for (i = 0; i < n_log_files; i++) {
  2347. sprintf(name + log_dir_len + sizeof logfilename, "%lu", (ulong) i);
  2348. log_file = os_file_create_simple(name, OS_FILE_CREATE,
  2349. OS_FILE_READ_WRITE, &success);
  2350. if (!success) {
  2351. fprintf(stderr,
  2352. "InnoDB: Cannot create %s. Check that the file does not exist yet.n", name);
  2353. exit(1);
  2354. }
  2355. fprintf(stderr,
  2356. "Setting log file size to %lu %lun",
  2357. (ulong) ut_get_high32(log_file_size),
  2358. (ulong) log_file_size & 0xFFFFFFFFUL);
  2359. success = os_file_set_size(name, log_file,
  2360. log_file_size & 0xFFFFFFFFUL,
  2361. ut_get_high32(log_file_size));
  2362. if (!success) {
  2363. fprintf(stderr,
  2364. "InnoDB: Cannot set %s size to %lu %lun", name, (ulong) ut_get_high32(log_file_size),
  2365. (ulong) (log_file_size & 0xFFFFFFFFUL));
  2366. exit(1);
  2367. }
  2368. os_file_flush(log_file);
  2369. os_file_close(log_file);
  2370. }
  2371. /* We pretend there is a checkpoint at lsn + LOG_BLOCK_HDR_SIZE */
  2372. log_reset_first_header_and_checkpoint(buf, lsn);
  2373. log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn);
  2374. log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE,
  2375. LOG_BLOCK_HDR_SIZE);
  2376. strcpy(name + log_dir_len + sizeof logfilename, "0");
  2377. log_file = os_file_create_simple(name, OS_FILE_OPEN,
  2378. OS_FILE_READ_WRITE, &success);
  2379. if (!success) {
  2380. fprintf(stderr, "InnoDB: Cannot open %s.n", name);
  2381. exit(1);
  2382. }
  2383. os_file_write(name, log_file, buf, 0, 0,
  2384. LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
  2385. os_file_flush(log_file);
  2386. os_file_close(log_file);
  2387. mem_free(name);
  2388. ut_free(buf);
  2389. }
  2390. #endif /* UNIV_HOTBACKUP */
  2391. #ifdef UNIV_LOG_ARCHIVE
  2392. /**********************************************************
  2393. Reads from the archive of a log group and performs recovery. */
  2394. static
  2395. ibool
  2396. log_group_recover_from_archive_file(
  2397. /*================================*/
  2398. /* out: TRUE if no more complete
  2399. consistent archive files */
  2400. log_group_t* group) /* in: log group */
  2401. {
  2402. os_file_t file_handle;
  2403. dulint start_lsn;
  2404. dulint file_end_lsn;
  2405. dulint dummy_lsn;
  2406. dulint scanned_lsn;
  2407. ulint len;
  2408. ibool ret;
  2409. byte* buf;
  2410. ulint read_offset;
  2411. ulint file_size;
  2412. ulint file_size_high;
  2413. int input_char;
  2414. char name[10000];
  2415. ut_a(0);
  2416. try_open_again:
  2417. buf = log_sys->buf;
  2418. /* Add the file to the archive file space; open the file */
  2419. log_archived_file_name_gen(name, group->id, group->archived_file_no);
  2420. file_handle = os_file_create(name, OS_FILE_OPEN,
  2421. OS_FILE_LOG, OS_FILE_AIO, &ret);
  2422. if (ret == FALSE) {
  2423. ask_again:
  2424. fprintf(stderr, 
  2425. "InnoDB: Do you want to copy additional archived log filesn"
  2426. "InnoDB: to the directoryn");
  2427. fprintf(stderr, 
  2428. "InnoDB: or were these all the files needed in recovery?n");
  2429. fprintf(stderr, 
  2430. "InnoDB: (Y == copy more files; N == this is all)?");
  2431. input_char = getchar();
  2432. if (input_char == (int) 'N') {
  2433. return(TRUE);
  2434. } else if (input_char == (int) 'Y') {
  2435. goto try_open_again;
  2436. } else {
  2437. goto ask_again;
  2438. }
  2439. }
  2440. ret = os_file_get_size(file_handle, &file_size, &file_size_high);
  2441. ut_a(ret);
  2442. ut_a(file_size_high == 0);
  2443. fprintf(stderr, "InnoDB: Opened archived log file %sn", name);
  2444. ret = os_file_close(file_handle);
  2445. if (file_size < LOG_FILE_HDR_SIZE) {
  2446. fprintf(stderr,
  2447. "InnoDB: Archive file header incomplete %sn", name);
  2448.     
  2449. return(TRUE);
  2450. }
  2451. ut_a(ret);
  2452. /* Add the archive file as a node to the space */
  2453. fil_node_create(name, 1 + file_size / UNIV_PAGE_SIZE,
  2454.     group->archive_space_id, FALSE);
  2455. ut_a(RECV_SCAN_SIZE >= LOG_FILE_HDR_SIZE);
  2456. /* Read the archive file header */
  2457. fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, group->archive_space_id, 0, 0,
  2458. LOG_FILE_HDR_SIZE, buf, NULL);
  2459. /* Check if the archive file header is consistent */
  2460. if (mach_read_from_4(buf + LOG_GROUP_ID) != group->id
  2461.     || mach_read_from_4(buf + LOG_FILE_NO)
  2462. != group->archived_file_no) {
  2463. fprintf(stderr,
  2464. "InnoDB: Archive file header inconsistent %sn", name);
  2465.     
  2466. return(TRUE);
  2467. }
  2468. if (!mach_read_from_4(buf + LOG_FILE_ARCH_COMPLETED)) {
  2469. fprintf(stderr,
  2470. "InnoDB: Archive file not completely written %sn", name);
  2471. return(TRUE);
  2472. }
  2473. start_lsn = mach_read_from_8(buf + LOG_FILE_START_LSN);
  2474. file_end_lsn = mach_read_from_8(buf + LOG_FILE_END_LSN);
  2475. if (ut_dulint_is_zero(recv_sys->scanned_lsn)) {
  2476. if (ut_dulint_cmp(recv_sys->parse_start_lsn, start_lsn) < 0) {
  2477. fprintf(stderr, 
  2478. "InnoDB: Archive log file %s starts from too big a lsnn",
  2479. name);     
  2480. return(TRUE);
  2481. }
  2482. recv_sys->scanned_lsn = start_lsn;
  2483. }
  2484. if (ut_dulint_cmp(recv_sys->scanned_lsn, start_lsn) != 0) {
  2485. fprintf(stderr,
  2486. "InnoDB: Archive log file %s starts from a wrong lsnn",
  2487. name);
  2488. return(TRUE);
  2489. }
  2490. read_offset = LOG_FILE_HDR_SIZE;
  2491. for (;;) {
  2492. len = RECV_SCAN_SIZE;
  2493. if (read_offset + len > file_size) {
  2494. len = ut_calc_align_down(file_size - read_offset,
  2495. OS_FILE_LOG_BLOCK_SIZE);
  2496. }
  2497. if (len == 0) {
  2498. break;
  2499. }
  2500. if (log_debug_writes) {
  2501. fprintf(stderr, 
  2502. "InnoDB: Archive read starting at lsn %lu %lu, len %lu from file %sn",
  2503. (ulong) ut_dulint_get_high(start_lsn),
  2504. (ulong) ut_dulint_get_low(start_lsn),
  2505. (ulong) len, name);
  2506. }
  2507. fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE,
  2508. group->archive_space_id, read_offset / UNIV_PAGE_SIZE,
  2509. read_offset % UNIV_PAGE_SIZE, len, buf, NULL);
  2510. ret = recv_scan_log_recs(TRUE,
  2511.                                 (buf_pool->n_frames -
  2512.                                 recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
  2513. TRUE, buf, len, start_lsn,
  2514. &dummy_lsn, &scanned_lsn);
  2515. if (ut_dulint_cmp(scanned_lsn, file_end_lsn) == 0) {
  2516. return(FALSE);
  2517. }
  2518. if (ret) {
  2519. fprintf(stderr,
  2520. "InnoDB: Archive log file %s does not scan rightn",
  2521. name);     
  2522. return(TRUE);
  2523. }
  2524. read_offset += len;
  2525. start_lsn = ut_dulint_add(start_lsn, len);
  2526. ut_ad(ut_dulint_cmp(start_lsn, scanned_lsn) == 0);
  2527. }
  2528. return(FALSE);
  2529. }
  2530. /************************************************************
  2531. Recovers from archived log files, and also from log files, if they exist. */
  2532. ulint
  2533. recv_recovery_from_archive_start(
  2534. /*=============================*/
  2535. /* out: error code or DB_SUCCESS */
  2536. dulint min_flushed_lsn,/* in: min flushed lsn field from the
  2537. data files */
  2538. dulint limit_lsn, /* in: recover up to this lsn if possible */
  2539. ulint first_log_no) /* in: number of the first archived log file
  2540. to use in the recovery; the file will be
  2541. searched from INNOBASE_LOG_ARCH_DIR specified
  2542. in server config file */
  2543. {
  2544. log_group_t* group;
  2545. ulint group_id;
  2546. ulint trunc_len;
  2547. ibool ret;
  2548. ulint err;
  2549. ut_a(0);
  2550. recv_sys_create();
  2551. recv_sys_init(FALSE, buf_pool_get_curr_size());
  2552. recv_recovery_on = TRUE;
  2553. recv_recovery_from_backup_on = TRUE;
  2554. recv_sys->limit_lsn = limit_lsn;
  2555. group_id = 0;
  2556. group = UT_LIST_GET_FIRST(log_sys->log_groups);
  2557. while (group) {
  2558. if (group->id == group_id) {
  2559.   break;
  2560. }
  2561. group = UT_LIST_GET_NEXT(log_groups, group);
  2562. }
  2563. if (!group) {
  2564. fprintf(stderr,
  2565. "InnoDB: There is no log group defined with id %lu!n",
  2566.    (ulong) group_id);
  2567. return(DB_ERROR);
  2568. }
  2569. group->archived_file_no = first_log_no;
  2570. recv_sys->parse_start_lsn = min_flushed_lsn;
  2571. recv_sys->scanned_lsn = ut_dulint_zero;
  2572. recv_sys->scanned_checkpoint_no = 0;
  2573. recv_sys->recovered_lsn = recv_sys->parse_start_lsn;
  2574. recv_sys->archive_group = group;
  2575. ret = FALSE;
  2576. mutex_enter(&(log_sys->mutex));
  2577. while (!ret) {
  2578. ret = log_group_recover_from_archive_file(group);
  2579. /* Close and truncate a possible processed archive file
  2580. from the file space */
  2581. trunc_len = UNIV_PAGE_SIZE
  2582.     * fil_space_get_size(group->archive_space_id);
  2583. if (trunc_len > 0) {
  2584. fil_space_truncate_start(group->archive_space_id,
  2585. trunc_len);
  2586. }
  2587. group->archived_file_no++;
  2588. }
  2589. if (ut_dulint_cmp(recv_sys->recovered_lsn, limit_lsn) < 0) {
  2590. if (ut_dulint_is_zero(recv_sys->scanned_lsn)) {
  2591. recv_sys->scanned_lsn = recv_sys->parse_start_lsn;
  2592. }
  2593. mutex_exit(&(log_sys->mutex));
  2594. err = recv_recovery_from_checkpoint_start(LOG_ARCHIVE,
  2595. limit_lsn,
  2596. ut_dulint_max,
  2597. ut_dulint_max);
  2598. if (err != DB_SUCCESS) {
  2599. return(err);
  2600. }
  2601. mutex_enter(&(log_sys->mutex));
  2602. }
  2603. if (ut_dulint_cmp(limit_lsn, ut_dulint_max) != 0) {
  2604. recv_apply_hashed_log_recs(FALSE);
  2605. recv_reset_logs(recv_sys->recovered_lsn, 0, FALSE);
  2606. }
  2607. mutex_exit(&(log_sys->mutex));
  2608. return(DB_SUCCESS);
  2609. }
  2610. /************************************************************
  2611. Completes recovery from archive. */
  2612. void
  2613. recv_recovery_from_archive_finish(void)
  2614. /*===================================*/
  2615. {
  2616. recv_recovery_from_checkpoint_finish();
  2617. recv_recovery_from_backup_on = FALSE;
  2618. }
  2619. #endif /* UNIV_LOG_ARCHIVE */