1 /*****************************************************************************
2
3
4 Copyright (c) 2018, 2020, Oracle and/or its affiliates. All Rights Reserved.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2.0,
8 as published by the Free Software Foundation.
9
10 This program is also distributed with certain software (including
11 but not limited to OpenSSL) that is licensed under separate terms,
12 as designated in a particular file or component or in included license
13 documentation. The authors of MySQL hereby grant you an additional
14 permission to link the program and your derivative works with the
15 separately licensed software that they have included with MySQL.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License, version 2.0, for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26 *****************************************************************************/
27
28 /**************************************************/ /**
29 @file include/arch0recv.h
30 Interface for crash recovery for page archiver system.
31
32 *******************************************************/
33
34 #include "arch0recv.h"
35
recover()36 dberr_t Arch_Page_Sys::recover() {
37 DBUG_PRINT("page_archiver", ("Crash Recovery"));
38
39 Recv arch_recv(ARCH_DIR);
40 dberr_t err;
41
42 err = arch_recv.init();
43
44 if (!arch_recv.scan_group()) {
45 DBUG_PRINT("page_archiver", ("No group information available"));
46 return (DB_SUCCESS);
47 }
48
49 err = arch_recv.fill_info(this);
50
51 if (err != DB_SUCCESS) {
52 ib::error(ER_IB_ERR_PAGE_ARCH_RECOVERY_FAILED);
53 return (DB_OUT_OF_MEMORY);
54 }
55
56 return (err);
57 }
58
init()59 dberr_t Arch_Page_Sys::Recv::init() {
60 dberr_t err;
61
62 err = m_dblwr_ctx.init(
63 ARCH_DBLWR_DIR, ARCH_DBLWR_FILE, ARCH_DBLWR_NUM_FILES,
64 static_cast<uint64_t>(ARCH_PAGE_BLK_SIZE) * ARCH_DBLWR_FILE_CAPACITY);
65
66 if (err != DB_SUCCESS) {
67 return (err);
68 }
69
70 err = m_dblwr_ctx.read_blocks();
71
72 return (err);
73 }
74
init(const char * dblwr_path,const char * dblwr_base_file,uint dblwr_num_files,uint64_t dblwr_file_size)75 dberr_t Arch_Dblwr_Ctx::init(const char *dblwr_path,
76 const char *dblwr_base_file, uint dblwr_num_files,
77 uint64_t dblwr_file_size) {
78 m_file_size = dblwr_file_size;
79
80 m_buf = static_cast<byte *>(UT_NEW_ARRAY_NOKEY(byte, m_file_size));
81
82 if (m_buf == nullptr) {
83 return (DB_OUT_OF_MEMORY);
84 }
85
86 memset(m_buf, 0, m_file_size);
87
88 auto err = m_file_ctx.init(ARCH_DIR, dblwr_path, dblwr_base_file,
89 dblwr_num_files, m_file_size);
90
91 return (err);
92 }
93
read_blocks()94 dberr_t Arch_Dblwr_Ctx::read_blocks() {
95 ut_ad(m_buf != nullptr);
96
97 auto err = m_file_ctx.open(true, LSN_MAX, 0, 0);
98
99 if (err != DB_SUCCESS) {
100 return (err);
101 }
102
103 ut_ad(m_file_ctx.get_phy_size() == m_file_size);
104
105 /* Read the entire file. */
106 err = m_file_ctx.read(m_buf, 0, static_cast<uint>(m_file_size));
107
108 if (err != DB_SUCCESS) {
109 return (err);
110 }
111
112 Arch_Dblwr_Block dblwr_block;
113
114 for (uint block_num = 0; block_num < m_file_size / ARCH_PAGE_BLK_SIZE;
115 ++block_num) {
116 auto block = m_buf + (block_num * ARCH_PAGE_BLK_SIZE);
117
118 if (!Arch_Block::validate(block)) {
119 continue;
120 }
121
122 if (block_num == ARCH_PAGE_DBLWR_RESET_PAGE) {
123 dblwr_block.m_block_type = ARCH_RESET_BLOCK;
124 dblwr_block.m_flush_type = ARCH_FLUSH_NORMAL;
125 } else {
126 dblwr_block.m_block_type = ARCH_DATA_BLOCK;
127 dblwr_block.m_flush_type = (block_num == ARCH_PAGE_DBLWR_FULL_FLUSH_PAGE)
128 ? ARCH_FLUSH_NORMAL
129 : ARCH_FLUSH_PARTIAL;
130 }
131
132 dblwr_block.m_block_num = Arch_Block::get_block_number(block);
133 dblwr_block.m_block = block;
134 m_blocks.push_back(dblwr_block);
135 }
136
137 m_file_ctx.close();
138
139 return (err);
140 }
141
142 #ifdef UNIV_DEBUG
print()143 void Arch_Page_Sys::Recv::print() {
144 for (auto group : m_dir_group_info_map) {
145 DBUG_PRINT("page_archiver",
146 ("Group : %s\t%u", group.first.c_str(), group.second.m_active));
147 }
148 }
149 #endif
150
read_group_dirs(const std::string file_path)151 void Arch_Page_Sys::Recv::read_group_dirs(const std::string file_path) {
152 if (file_path.find(ARCH_PAGE_DIR) == std::string::npos) {
153 return;
154 }
155
156 Arch_Recv_Group_Info info;
157 m_dir_group_info_map.insert(
158 std::pair<std::string, Arch_Recv_Group_Info>(file_path, info));
159 }
160
read_group_files(const std::string dir_path,const std::string file_path)161 void Arch_Page_Sys::Recv::read_group_files(const std::string dir_path,
162 const std::string file_path) {
163 if (file_path.find(ARCH_PAGE_FILE) == std::string::npos &&
164 file_path.find(ARCH_PAGE_GROUP_ACTIVE_FILE_NAME) == std::string::npos &&
165 file_path.find(ARCH_PAGE_GROUP_DURABLE_FILE_NAME) == std::string::npos) {
166 return;
167 }
168
169 Arch_Recv_Group_Info &info = m_dir_group_info_map[dir_path];
170
171 if (file_path.find(ARCH_PAGE_GROUP_ACTIVE_FILE_NAME) != std::string::npos) {
172 info.m_active = true;
173 return;
174 }
175
176 if (file_path.find(ARCH_PAGE_GROUP_DURABLE_FILE_NAME) != std::string::npos) {
177 info.m_durable = true;
178 return;
179 }
180
181 info.m_num_files += 1;
182
183 auto found = file_path.find(ARCH_PAGE_FILE);
184 ut_ad(found != std::string::npos);
185 uint file_index = 0;
186
187 /* Fetch start index. */
188 try {
189 file_index = static_cast<uint>(
190 std::stoi(file_path.substr(found + strlen(ARCH_PAGE_FILE))));
191 } catch (const std::exception &) {
192 ut_ad(0);
193 ib::error(ER_IB_ERR_PAGE_ARCH_INVALID_FORMAT) << ARCH_PAGE_FILE;
194 return;
195 }
196
197 if (info.m_file_start_index > file_index) {
198 info.m_file_start_index = file_index;
199 }
200 }
201
scan_group()202 bool Arch_Page_Sys::Recv::scan_group() {
203 os_file_type_t type;
204 bool exists;
205
206 os_file_status(m_arch_dir_name.c_str(), &exists, &type);
207
208 if (!exists || type != OS_FILE_TYPE_DIR) {
209 return (false);
210 }
211
212 Dir_Walker::walk(m_arch_dir_name, false, [&](const std::string file_path) {
213 read_group_dirs(file_path);
214 });
215
216 if (m_dir_group_info_map.size() == 0) {
217 return (false);
218 }
219
220 for (auto it : m_dir_group_info_map) {
221 Dir_Walker::walk(it.first, true, [&](const std::string file_path) {
222 read_group_files(it.first, file_path);
223 });
224 }
225
226 ut_d(print());
227
228 return (true);
229 }
230
recovery_replace_pages_from_dblwr(Arch_Dblwr_Ctx * dblwr_ctx)231 dberr_t Arch_Group::recovery_replace_pages_from_dblwr(
232 Arch_Dblwr_Ctx *dblwr_ctx) {
233 auto ARCH_UNKNOWN_BLOCK = std::numeric_limits<uint64_t>::max();
234 uint64_t full_flush_blk_num = ARCH_UNKNOWN_BLOCK;
235 auto dblwr_blocks = dblwr_ctx->get_blocks();
236 size_t num_files = get_file_count();
237
238 ut_ad(num_files > 0);
239
240 for (uint index = 0; index < dblwr_blocks.size(); ++index) {
241 auto dblwr_block = dblwr_blocks[index];
242
243 switch (dblwr_block.m_block_type) {
244 case ARCH_RESET_BLOCK:
245
246 ut_ad(dblwr_block.m_block_num < num_files);
247 /* If the block does not belong to the last file then ignore. */
248 if (dblwr_block.m_block_num != num_files - 1) {
249 continue;
250 } else {
251 break;
252 }
253
254 case ARCH_DATA_BLOCK: {
255 uint file_index = Arch_Block::get_file_index(dblwr_block.m_block_num);
256 ut_ad(file_index < num_files);
257
258 /* If the block does not belong to the last file then ignore. */
259 if (file_index < num_files - 1) {
260 continue;
261 }
262
263 if (dblwr_block.m_flush_type == ARCH_FLUSH_NORMAL) {
264 full_flush_blk_num = dblwr_block.m_block_num;
265 } else {
266 /* It's possible that the partial flush block might have been fully
267 flushed, in which case we need to skip this block. */
268 if (full_flush_blk_num != ARCH_UNKNOWN_BLOCK &&
269 full_flush_blk_num >= dblwr_block.m_block_num) {
270 continue;
271 }
272 }
273 } break;
274
275 default:
276 ut_ad(false);
277 }
278
279 uint64_t offset = Arch_Block::get_file_offset(dblwr_block.m_block_num,
280 dblwr_block.m_block_type);
281
282 ut_ad(m_file_ctx.is_closed());
283
284 dberr_t err;
285
286 err = m_file_ctx.open(false, m_begin_lsn, static_cast<uint>(num_files) - 1,
287 0);
288
289 if (err != DB_SUCCESS) {
290 return (err);
291 }
292
293 err = m_file_ctx.write(nullptr, dblwr_block.m_block,
294 static_cast<uint>(offset), ARCH_PAGE_BLK_SIZE);
295
296 if (err != DB_SUCCESS) {
297 return (err);
298 }
299
300 m_file_ctx.close();
301 }
302
303 return (DB_SUCCESS);
304 }
305
recovery_cleanup_if_required(uint & num_files,uint start_index,bool durable,bool & empty_file)306 dberr_t Arch_Group::recovery_cleanup_if_required(uint &num_files,
307 uint start_index, bool durable,
308 bool &empty_file) {
309 dberr_t err;
310
311 ut_ad(!durable || num_files > 0);
312 ut_ad(m_file_ctx.is_closed());
313
314 uint index = start_index + num_files - 1;
315
316 /* Open the last file in the group. */
317 err = m_file_ctx.open(true, m_begin_lsn, index, 0);
318
319 if (err != DB_SUCCESS) {
320 return (err);
321 }
322
323 if (m_file_ctx.get_phy_size() != 0 && durable) {
324 m_file_ctx.close();
325 return (DB_SUCCESS);
326 }
327
328 empty_file = true;
329
330 /* No blocks have been flushed into the file so delete the file. */
331
332 char file_path[MAX_ARCH_PAGE_FILE_NAME_LEN];
333 char dir_path[MAX_ARCH_DIR_NAME_LEN];
334
335 m_file_ctx.build_name(index, m_begin_lsn, file_path,
336 MAX_ARCH_PAGE_FILE_NAME_LEN);
337
338 auto found = std::string(file_path).find(ARCH_PAGE_FILE);
339 ut_ad(found != std::string::npos);
340 auto file_name = std::string(file_path).substr(found);
341
342 m_file_ctx.build_dir_name(m_begin_lsn, dir_path, MAX_ARCH_DIR_NAME_LEN);
343
344 m_file_ctx.close();
345
346 arch_remove_file(dir_path, file_name.c_str());
347
348 --num_files;
349
350 /* If there are no archive files in the group we might as well
351 purge it. */
352 if (num_files == 0 || !durable) {
353 m_is_active = false;
354
355 found = std::string(dir_path).find(ARCH_PAGE_DIR);
356 ut_ad(found != std::string::npos);
357
358 auto path = std::string(dir_path).substr(0, found - 1);
359 auto dir_name = std::string(dir_path).substr(found);
360
361 num_files = 0;
362 arch_remove_dir(path.c_str(), dir_name.c_str());
363 }
364
365 /* Need to reinitialize the file context as num_files has changed. */
366 err = m_file_ctx.init(
367 ARCH_DIR, ARCH_PAGE_DIR, ARCH_PAGE_FILE, num_files,
368 static_cast<uint64_t>(ARCH_PAGE_BLK_SIZE) * ARCH_PAGE_FILE_CAPACITY);
369
370 return (err);
371 }
372
fill_info(Arch_Page_Sys * page_sys)373 dberr_t Arch_Page_Sys::Recv::fill_info(Arch_Page_Sys *page_sys) {
374 uint num_active = 0;
375 dberr_t err = DB_SUCCESS;
376 bool new_empty_file = false;
377
378 for (auto info = m_dir_group_info_map.begin();
379 info != m_dir_group_info_map.end(); ++info) {
380 auto group_info = info->second;
381 auto dir_name = info->first;
382
383 auto pos = dir_name.find(ARCH_PAGE_DIR);
384 lsn_t start_lsn = static_cast<lsn_t>(
385 std::stoull(dir_name.substr(pos + strlen(ARCH_PAGE_DIR))));
386
387 Arch_Group *group = UT_NEW(
388 Arch_Group(start_lsn, ARCH_PAGE_FILE_HDR_SIZE, page_sys->get_mutex()),
389 mem_key_archive);
390
391 Arch_Page_Pos write_pos;
392 Arch_Page_Pos reset_pos;
393
394 err = group->recover(&group_info, new_empty_file, &m_dblwr_ctx, write_pos,
395 reset_pos);
396
397 if (err != DB_SUCCESS) {
398 UT_DELETE(group);
399 return (err);
400 }
401
402 if (group_info.m_num_files == 0) {
403 UT_DELETE(group);
404 continue;
405 }
406
407 page_sys->m_group_list.push_back(group);
408
409 if (group_info.m_active) {
410 /* Group was active at the time of shutdown/crash, so
411 we need to start page archiving */
412
413 page_sys->m_write_pos = write_pos;
414 page_sys->m_reset_pos = reset_pos;
415
416 ++num_active;
417 int error = page_sys->start_during_recovery(group, new_empty_file);
418
419 if (error != 0) {
420 return (DB_ERROR);
421 }
422 }
423 }
424
425 /* There can be only one active group at a time. */
426 ut_ad(num_active <= 1);
427
428 return (DB_SUCCESS);
429 }
430
recover(Arch_Recv_Group_Info * group_info,bool & new_empty_file,Arch_Dblwr_Ctx * dblwr_ctx,Arch_Page_Pos & write_pos,Arch_Page_Pos & reset_pos)431 dberr_t Arch_Group::recover(Arch_Recv_Group_Info *group_info,
432 bool &new_empty_file, Arch_Dblwr_Ctx *dblwr_ctx,
433 Arch_Page_Pos &write_pos,
434 Arch_Page_Pos &reset_pos) {
435 dberr_t err;
436
437 err = init_file_ctx(
438 ARCH_DIR, ARCH_PAGE_DIR, ARCH_PAGE_FILE, group_info->m_num_files,
439 static_cast<uint64_t>(ARCH_PAGE_BLK_SIZE) * ARCH_PAGE_FILE_CAPACITY);
440
441 if (err != DB_SUCCESS) {
442 return (err);
443 }
444
445 if (group_info->m_active) {
446 /* Since the group was active at the time of crash it's possible that the
447 doublewrite buffer might have the latest data in case of a crash. */
448
449 err = recovery_replace_pages_from_dblwr(dblwr_ctx);
450
451 if (err != DB_SUCCESS) {
452 return (err);
453 }
454 }
455
456 err = recovery_cleanup_if_required(group_info->m_num_files,
457 group_info->m_file_start_index,
458 group_info->m_durable, new_empty_file);
459
460 if (err != DB_SUCCESS) {
461 return (err);
462 }
463
464 if (group_info->m_num_files == 0) {
465 return (err);
466 }
467
468 err = recovery_parse(write_pos, reset_pos, group_info->m_file_start_index);
469
470 if (err != DB_SUCCESS) {
471 return (err);
472 }
473
474 if (!group_info->m_active) {
475 /* Group was inactive at the time of shutdown/crash, so
476 we just add the group to the group list that the
477 archiver maintains. */
478
479 attach_during_recovery();
480 m_stop_pos = write_pos;
481
482 auto end_lsn = m_file_ctx.get_last_stop_point();
483 ut_ad(end_lsn != LSN_MAX);
484
485 disable(end_lsn);
486 } else {
487 err = open_file_during_recovery(write_pos, new_empty_file);
488 }
489
490 ut_d(m_file_ctx.recovery_reset_print(group_info->m_file_start_index));
491
492 return (err);
493 }
494
495 #ifdef UNIV_DEBUG
recovery_reset_print(uint file_start_index)496 void Arch_File_Ctx::recovery_reset_print(uint file_start_index) {
497 Arch_Reset reset;
498 Arch_Reset_File reset_file;
499 Arch_Point start_point;
500
501 DBUG_PRINT("page_archiver", ("No. of files : %u", m_count));
502
503 if (m_reset.size() == 0) {
504 DBUG_PRINT("page_archiver", ("No reset info available for this group."));
505 }
506
507 for (auto reset_file : m_reset) {
508 DBUG_PRINT("page_archiver", ("File %u\tFile LSN : %" PRIu64 "",
509 reset_file.m_file_index, reset_file.m_lsn));
510
511 if (reset_file.m_start_point.size() == 0) {
512 DBUG_PRINT("page_archiver", ("No reset info available for this file."));
513 }
514
515 for (uint i = 0; i < reset_file.m_start_point.size(); i++) {
516 start_point = reset_file.m_start_point[i];
517 DBUG_PRINT("page_archiver",
518 ("\tReset lsn : %" PRIu64 ", reset_pos : %" PRIu64 "\t %u",
519 start_point.lsn, start_point.pos.m_block_num,
520 start_point.pos.m_offset));
521 }
522 }
523
524 DBUG_PRINT("page_archiver",
525 ("Starting index of the file : %u", file_start_index));
526
527 DBUG_PRINT("page_archiver", ("Latest stop points"));
528 uint file_index = 0;
529 for (auto stop_point : m_stop_points) {
530 DBUG_PRINT("page_archiver",
531 ("\tFile %u : %" PRIu64 "", file_index, stop_point));
532 ++file_index;
533 }
534 }
535 #endif
536
recovery_parse(Arch_Page_Pos & write_pos,Arch_Page_Pos & reset_pos,size_t start_index)537 dberr_t Arch_Group::recovery_parse(Arch_Page_Pos &write_pos,
538 Arch_Page_Pos &reset_pos,
539 size_t start_index) {
540 size_t num_files = get_file_count();
541 dberr_t err = DB_SUCCESS;
542
543 if (num_files == 0) {
544 DBUG_PRINT("page_archiver", ("No group information available"));
545 return (DB_SUCCESS);
546 }
547
548 ut_ad(m_file_ctx.is_closed());
549
550 size_t file_count = start_index + num_files;
551
552 for (auto file_index = start_index; file_index < file_count; ++file_index) {
553 if (file_index == start_index) {
554 err =
555 m_file_ctx.open(true, m_begin_lsn, static_cast<uint>(start_index), 0);
556 } else {
557 err = m_file_ctx.open_next(m_begin_lsn, 0);
558 }
559
560 if (err != DB_SUCCESS) {
561 break;
562 }
563
564 err =
565 m_file_ctx.fetch_reset_points(static_cast<uint>(file_index), reset_pos);
566
567 if (err != DB_SUCCESS) {
568 break;
569 }
570
571 bool last_file = (file_index + 1 == file_count);
572 err = m_file_ctx.fetch_stop_points(last_file, write_pos);
573
574 if (err != DB_SUCCESS) {
575 break;
576 }
577
578 m_file_ctx.close();
579 }
580
581 m_file_ctx.close();
582
583 return (err);
584 }
585
fetch_stop_points(bool last_file,Arch_Page_Pos & write_pos)586 dberr_t Arch_File_Ctx::fetch_stop_points(bool last_file,
587 Arch_Page_Pos &write_pos) {
588 ut_ad(!is_closed());
589
590 uint64_t offset;
591 byte buf[ARCH_PAGE_BLK_SIZE];
592
593 if (last_file) {
594 offset = get_phy_size() - ARCH_PAGE_BLK_SIZE;
595 } else {
596 offset = ARCH_PAGE_FILE_DATA_CAPACITY * ARCH_PAGE_BLK_SIZE;
597 }
598
599 auto err = read(buf, offset, ARCH_PAGE_BLK_SIZE);
600
601 if (err != DB_SUCCESS) {
602 return (err);
603 }
604
605 auto stop_lsn = Arch_Block::get_stop_lsn(buf);
606 m_stop_points.push_back(stop_lsn);
607
608 write_pos.init();
609 write_pos.m_block_num = Arch_Block::get_block_number(buf);
610 write_pos.m_offset =
611 Arch_Block::get_data_len(buf) + ARCH_PAGE_BLK_HEADER_LENGTH;
612
613 return (err);
614 }
615
fetch_reset_points(uint file_index,Arch_Page_Pos & reset_pos)616 dberr_t Arch_File_Ctx::fetch_reset_points(uint file_index,
617 Arch_Page_Pos &reset_pos) {
618 ut_ad(!is_closed());
619 ut_ad(m_index == file_index);
620
621 byte buf[ARCH_PAGE_BLK_SIZE];
622
623 /* Read reset block to fetch reset points. */
624 auto err = read(buf, 0, ARCH_PAGE_BLK_SIZE);
625
626 if (err != DB_SUCCESS) {
627 return (err);
628 }
629
630 auto block_num = Arch_Block::get_block_number(buf);
631 auto data_len = Arch_Block::get_data_len(buf);
632
633 if (file_index != block_num) {
634 /* This means there was no reset for this file and hence the
635 reset block was not flushed. */
636
637 ut_ad(Arch_Block::is_zeroes(buf));
638 reset_pos.init();
639 reset_pos.m_block_num = file_index;
640 return (err);
641 }
642
643 /* Normal case. */
644 reset_pos.m_block_num = block_num;
645 reset_pos.m_offset = data_len + ARCH_PAGE_BLK_HEADER_LENGTH;
646
647 Arch_Reset_File reset_file;
648 reset_file.init();
649 reset_file.m_file_index = file_index;
650
651 if (data_len != 0) {
652 uint length = 0;
653 byte *buf1 = buf + ARCH_PAGE_BLK_HEADER_LENGTH;
654
655 ut_ad(data_len >= ARCH_PAGE_FILE_HEADER_RESET_LSN_SIZE +
656 ARCH_PAGE_FILE_HEADER_RESET_POS_SIZE);
657
658 reset_file.m_lsn = mach_read_from_8(buf1);
659 length += ARCH_PAGE_FILE_HEADER_RESET_LSN_SIZE;
660
661 Arch_Point start_point;
662 Arch_Page_Pos pos;
663
664 while (length != data_len) {
665 ut_ad((data_len - length) % ARCH_PAGE_FILE_HEADER_RESET_POS_SIZE == 0);
666
667 pos.m_block_num = mach_read_from_2(buf1 + length);
668 length += ARCH_PAGE_FILE_HEADER_RESET_BLOCK_NUM_SIZE;
669
670 pos.m_offset = mach_read_from_2(buf1 + length);
671 length += ARCH_PAGE_FILE_HEADER_RESET_BLOCK_OFFSET_SIZE;
672
673 start_point.lsn = fetch_reset_lsn(pos.m_block_num);
674 start_point.pos = pos;
675
676 reset_file.m_start_point.push_back(start_point);
677 }
678
679 m_reset.push_back(reset_file);
680 }
681
682 return (err);
683 }
684
fetch_reset_lsn(uint64_t block_num)685 lsn_t Arch_File_Ctx::fetch_reset_lsn(uint64_t block_num) {
686 ut_ad(!is_closed());
687 ut_ad(Arch_Block::get_file_index(block_num) == m_index);
688
689 byte buf[ARCH_PAGE_BLK_SIZE];
690
691 auto offset = Arch_Block::get_file_offset(block_num, ARCH_DATA_BLOCK);
692
693 ut_ad(offset + ARCH_PAGE_BLK_SIZE <= get_phy_size());
694
695 auto err = read(buf, offset, ARCH_PAGE_BLK_HEADER_LENGTH);
696
697 if (err != DB_SUCCESS) {
698 return (LSN_MAX);
699 }
700
701 auto lsn = Arch_Block::get_reset_lsn(buf);
702
703 ut_ad(lsn != LSN_MAX);
704
705 return (lsn);
706 }
707
recovery_read_latest_blocks(byte * buf,uint64_t offset,Arch_Blk_Type type)708 dberr_t Arch_Group::recovery_read_latest_blocks(byte *buf, uint64_t offset,
709 Arch_Blk_Type type) {
710 dberr_t err = DB_SUCCESS;
711
712 ut_ad(!m_file_ctx.is_closed());
713
714 switch (type) {
715 case ARCH_RESET_BLOCK: {
716 ut_d(uint64_t file_size = m_file_ctx.get_phy_size());
717 ut_ad((file_size > ARCH_PAGE_FILE_NUM_RESET_PAGE * ARCH_PAGE_BLK_SIZE) &&
718 (file_size % ARCH_PAGE_BLK_SIZE == 0));
719
720 err = m_file_ctx.read(buf, 0, ARCH_PAGE_BLK_SIZE);
721 } break;
722
723 case ARCH_DATA_BLOCK:
724 err = m_file_ctx.read(buf, offset, ARCH_PAGE_BLK_SIZE);
725 break;
726 }
727
728 return (err);
729 }
730