Skip to content

Commit 52edc37

Browse files
committed
Merge 10.4 into 10.5
2 parents 50a11f3 + 70d4500 commit 52edc37

File tree

4 files changed

+163
-117
lines changed

4 files changed

+163
-117
lines changed

storage/innobase/buf/buf0dblwr.cc

Lines changed: 46 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,8 @@ buf_dblwr_init_or_load_pages(
483483
void
484484
buf_dblwr_process()
485485
{
486+
ut_ad(recv_sys.parse_start_lsn);
487+
486488
ulint page_no_dblwr = 0;
487489
byte* read_buf;
488490
recv_dblwr_t& recv_dblwr = recv_sys.dblwr;
@@ -492,27 +494,50 @@ buf_dblwr_process()
492494
}
493495

494496
read_buf = static_cast<byte*>(
495-
aligned_malloc(2 * srv_page_size, srv_page_size));
497+
aligned_malloc(3 * srv_page_size, srv_page_size));
496498
byte* const buf = read_buf + srv_page_size;
497499

498500
for (recv_dblwr_t::list::iterator i = recv_dblwr.pages.begin();
499501
i != recv_dblwr.pages.end();
500502
++i, ++page_no_dblwr) {
501-
byte* page = *i;
502-
ulint space_id = page_get_space_id(page);
503-
fil_space_t* space = fil_space_get(space_id);
503+
byte* page = *i;
504+
const ulint page_no = page_get_page_no(page);
505+
506+
if (!page_no) {
507+
/* page 0 should have been recovered
508+
already via Datafile::restore_from_doublewrite() */
509+
continue;
510+
}
511+
512+
const ulint space_id = page_get_space_id(page);
513+
const lsn_t lsn = mach_read_from_8(page + FIL_PAGE_LSN);
514+
515+
if (recv_sys.parse_start_lsn > lsn) {
516+
/* Pages written before the checkpoint are
517+
not useful for recovery. */
518+
continue;
519+
}
504520

505-
if (space == NULL) {
521+
const page_id_t page_id(space_id, page_no);
522+
523+
if (recv_sys.scanned_lsn < lsn) {
524+
ib::warn() << "Ignoring a doublewrite copy of page "
525+
<< page_id
526+
<< " with future log sequence number "
527+
<< lsn;
528+
continue;
529+
}
530+
531+
fil_space_t* space = fil_space_acquire_for_io(space_id);
532+
533+
if (!space) {
506534
/* Maybe we have dropped the tablespace
507535
and this page once belonged to it: do nothing */
508536
continue;
509537
}
510538

511539
fil_space_open_if_needed(space);
512540

513-
const ulint page_no = page_get_page_no(page);
514-
const page_id_t page_id(space_id, page_no);
515-
516541
if (UNIV_UNLIKELY(page_no >= space->size)) {
517542

518543
/* Do not report the warning for undo
@@ -525,6 +550,8 @@ buf_dblwr_process()
525550
<< space->name
526551
<< " (" << space->size << " pages)";
527552
}
553+
next_page:
554+
space->release_for_io();
528555
continue;
529556
}
530557

@@ -557,92 +584,32 @@ buf_dblwr_process()
557584
fio.node->space->release_for_io();
558585
}
559586

560-
const bool is_all_zero = buf_is_zeroes(
561-
span<const byte>(read_buf, physical_size));
562-
const bool expect_encrypted = space->crypt_data
563-
&& space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED;
564-
bool is_corrupted = false;
565-
566-
if (is_all_zero) {
587+
if (buf_is_zeroes(span<const byte>(read_buf, physical_size))) {
567588
/* We will check if the copy in the
568589
doublewrite buffer is valid. If not, we will
569590
ignore this page (there should be redo log
570591
records to initialize it). */
592+
} else if (recv_dblwr.validate_page(
593+
page_id, read_buf, space, buf)) {
594+
goto next_page;
571595
} else {
572-
/* Decompress the page before
573-
validating the checksum. */
574-
ulint decomp = fil_page_decompress(buf, read_buf,
575-
space->flags);
576-
if (!decomp || (zip_size && decomp != srv_page_size)) {
577-
goto bad;
578-
}
579-
580-
if (expect_encrypted
581-
&& buf_page_get_key_version(read_buf, space->flags)) {
582-
is_corrupted = !buf_page_verify_crypt_checksum(
583-
read_buf, space->flags);
584-
} else {
585-
is_corrupted = buf_page_is_corrupted(
586-
true, read_buf, space->flags);
587-
}
588-
589-
if (!is_corrupted) {
590-
/* The page is good; there is no need
591-
to consult the doublewrite buffer. */
592-
continue;
593-
}
594-
595-
bad:
596596
/* We intentionally skip this message for
597-
is_all_zero pages. */
597+
all-zero pages. */
598598
ib::info()
599599
<< "Trying to recover page " << page_id
600600
<< " from the doublewrite buffer.";
601601
}
602602

603-
ulint decomp = fil_page_decompress(buf, page, space->flags);
604-
if (!decomp || (zip_size && decomp != srv_page_size)) {
605-
continue;
606-
}
607-
608-
if (expect_encrypted
609-
&& buf_page_get_key_version(read_buf, space->flags)) {
610-
is_corrupted = !buf_page_verify_crypt_checksum(
611-
page, space->flags);
612-
} else {
613-
is_corrupted = buf_page_is_corrupted(
614-
true, page, space->flags);
615-
}
616-
617-
if (is_corrupted) {
618-
/* Theoretically we could have another good
619-
copy for this page in the doublewrite
620-
buffer. If not, we will report a fatal error
621-
for a corrupted page somewhere else if that
622-
page was truly needed. */
623-
continue;
624-
}
603+
page = recv_dblwr.find_page(page_id, space, buf);
625604

626-
if (page_no == 0) {
627-
/* Check the FSP_SPACE_FLAGS. */
628-
ulint flags = fsp_header_get_flags(page);
629-
if (!fil_space_t::is_valid_flags(flags, space_id)
630-
&& fsp_flags_convert_from_101(flags)
631-
== ULINT_UNDEFINED) {
632-
ib::warn() << "Ignoring a doublewrite copy"
633-
" of page " << page_id
634-
<< " due to invalid flags "
635-
<< ib::hex(flags);
636-
continue;
637-
}
638-
/* The flags on the page should be converted later. */
605+
if (!page) {
606+
goto next_page;
639607
}
640608

641609
/* Write the good page from the doublewrite buffer to
642610
the intended position. */
643611
fio = fil_io(IORequestWrite, true, page_id, zip_size,
644-
0, physical_size, const_cast<byte*>(page),
645-
nullptr);
612+
0, physical_size, page, nullptr);
646613

647614
if (fio.node) {
648615
ut_ad(fio.err == DB_SUCCESS);
@@ -651,6 +618,8 @@ buf_dblwr_process()
651618
<< "' from the doublewrite buffer.";
652619
fio.node->space->release_for_io();
653620
}
621+
622+
goto next_page;
654623
}
655624

656625
recv_dblwr.pages.clear();

storage/innobase/fsp/fsp0file.cc

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -768,10 +768,10 @@ Datafile::restore_from_doublewrite()
768768
}
769769

770770
/* Find if double write buffer contains page_no of given space id. */
771-
const byte* page = recv_sys.dblwr.find_page(m_space_id, 0);
772771
const page_id_t page_id(m_space_id, 0);
772+
const byte* page = recv_sys.dblwr.find_page(page_id);
773773

774-
if (page == NULL) {
774+
if (!page) {
775775
/* If the first page of the given user tablespace is not there
776776
in the doublewrite buffer, then the recovery is going to fail
777777
now. Hence this is treated as an error. */
@@ -788,15 +788,10 @@ Datafile::restore_from_doublewrite()
788788
FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page);
789789

790790
if (!fil_space_t::is_valid_flags(flags, m_space_id)) {
791-
ulint cflags = fsp_flags_convert_from_101(flags);
792-
if (cflags == ULINT_UNDEFINED) {
793-
ib::warn()
794-
<< "Ignoring a doublewrite copy of page "
795-
<< page_id
796-
<< " due to invalid flags " << ib::hex(flags);
797-
return(true);
798-
}
799-
flags = cflags;
791+
flags = fsp_flags_convert_from_101(flags);
792+
/* recv_dblwr_t::validate_page() inside find_page()
793+
checked this already. */
794+
ut_ad(flags != ULINT_UNDEFINED);
800795
/* The flags on the page should be converted later. */
801796
}
802797

storage/innobase/include/log0recv.h

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -116,23 +116,35 @@ struct log_rec_t
116116
const lsn_t lsn;
117117
};
118118

119-
struct recv_dblwr_t {
120-
/** Add a page frame to the doublewrite recovery buffer. */
121-
void add(byte* page) {
122-
pages.push_front(page);
123-
}
124-
125-
/** Find a doublewrite copy of a page.
126-
@param[in] space_id tablespace identifier
127-
@param[in] page_no page number
128-
@return page frame
129-
@retval NULL if no page was found */
130-
const byte* find_page(ulint space_id, ulint page_no);
131-
132-
typedef std::deque<byte*, ut_allocator<byte*> > list;
133-
134-
/** Recovered doublewrite buffer page frames */
135-
list pages;
119+
struct recv_dblwr_t
120+
{
121+
/** Add a page frame to the doublewrite recovery buffer. */
122+
void add(byte *page) { pages.push_front(page); }
123+
124+
/** Validate the page.
125+
@param page_id page identifier
126+
@param page page contents
127+
@param space the tablespace of the page (not available for page 0)
128+
@param tmp_buf 2*srv_page_size for decrypting and decompressing any
129+
page_compressed or encrypted pages
130+
@return whether the page is valid */
131+
bool validate_page(const page_id_t page_id, const byte *page,
132+
const fil_space_t *space, byte *tmp_buf);
133+
134+
/** Find a doublewrite copy of a page.
135+
@param page_id page identifier
136+
@param space tablespace (not available for page_id.page_no()==0)
137+
@param tmp_buf 2*srv_page_size for decrypting and decompressing any
138+
page_compressed or encrypted pages
139+
@return page frame
140+
@retval NULL if no valid page for page_id was found */
141+
byte* find_page(const page_id_t page_id, const fil_space_t *space= NULL,
142+
byte *tmp_buf= NULL);
143+
144+
typedef std::deque<byte*, ut_allocator<byte*> > list;
145+
146+
/** Recovered doublewrite buffer page frames */
147+
list pages;
136148
};
137149

138150
/** the recovery state and buffered records for a page */

storage/innobase/log/log0recv.cc

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Created 9/20/1997 Heikki Tuuri
5454
#include "buf0rea.h"
5555
#include "srv0srv.h"
5656
#include "srv0start.h"
57+
#include "fil0pagecompress.h"
5758

5859
/** Read-ahead area in applying log records to file pages */
5960
#define RECV_READ_AHEAD_AREA 32U
@@ -3542,6 +3543,8 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn)
35423543
rescan = true;
35433544
}
35443545

3546+
recv_sys.parse_start_lsn = checkpoint_lsn;
3547+
35453548
if (srv_operation == SRV_OPERATION_NORMAL) {
35463549
buf_dblwr_process();
35473550
}
@@ -3671,25 +3674,92 @@ recv_recovery_from_checkpoint_finish(void)
36713674
ut_d(sync_check_enable());
36723675
}
36733676

3674-
/** Find a doublewrite copy of a page.
3675-
@param[in] space_id tablespace identifier
3676-
@param[in] page_no page number
3677-
@return page frame
3678-
@retval NULL if no page was found */
3679-
const byte*
3680-
recv_dblwr_t::find_page(ulint space_id, ulint page_no)
3677+
bool recv_dblwr_t::validate_page(const page_id_t page_id,
3678+
const byte *page,
3679+
const fil_space_t *space,
3680+
byte *tmp_buf)
36813681
{
3682-
const byte *result= NULL;
3682+
if (page_id.page_no() == 0)
3683+
{
3684+
ulint flags= fsp_header_get_flags(page);
3685+
if (!fil_space_t::is_valid_flags(flags, page_id.space()))
3686+
{
3687+
ulint cflags= fsp_flags_convert_from_101(flags);
3688+
if (cflags == ULINT_UNDEFINED)
3689+
{
3690+
ib::warn() << "Ignoring a doublewrite copy of page " << page_id
3691+
<< "due to invalid flags " << ib::hex(flags);
3692+
return false;
3693+
}
3694+
3695+
flags= cflags;
3696+
}
3697+
3698+
/* Page 0 is never page_compressed or encrypted. */
3699+
return !buf_page_is_corrupted(true, page, flags);
3700+
}
3701+
3702+
ut_ad(tmp_buf);
3703+
byte *tmp_frame= tmp_buf;
3704+
byte *tmp_page= tmp_buf + srv_page_size;
3705+
const uint16_t page_type= mach_read_from_2(page + FIL_PAGE_TYPE);
3706+
const bool expect_encrypted= space->crypt_data &&
3707+
space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED;
3708+
3709+
if (space->full_crc32())
3710+
return !buf_page_is_corrupted(true, page, space->flags);
3711+
3712+
if (expect_encrypted &&
3713+
mach_read_from_4(page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION))
3714+
{
3715+
if (!fil_space_verify_crypt_checksum(page, space->zip_size()))
3716+
return false;
3717+
if (page_type != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED)
3718+
return true;
3719+
if (space->zip_size())
3720+
return false;
3721+
memcpy(tmp_page, page, space->physical_size());
3722+
if (!fil_space_decrypt(space, tmp_frame, tmp_page))
3723+
return false;
3724+
}
3725+
3726+
switch (page_type) {
3727+
case FIL_PAGE_PAGE_COMPRESSED:
3728+
memcpy(tmp_page, page, space->physical_size());
3729+
/* fall through */
3730+
case FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED:
3731+
if (space->zip_size())
3732+
return false; /* ROW_FORMAT=COMPRESSED cannot be page_compressed */
3733+
ulint decomp= fil_page_decompress(tmp_frame, tmp_page, space->flags);
3734+
if (!decomp)
3735+
return false; /* decompression failed */
3736+
if (decomp == srv_page_size)
3737+
return false; /* the page was not compressed (invalid page type) */
3738+
return !buf_page_is_corrupted(true, tmp_page, space->flags);
3739+
}
3740+
3741+
return !buf_page_is_corrupted(true, page, space->flags);
3742+
}
3743+
3744+
byte *recv_dblwr_t::find_page(const page_id_t page_id,
3745+
const fil_space_t *space, byte *tmp_buf)
3746+
{
3747+
byte *result= NULL;
36833748
lsn_t max_lsn= 0;
36843749

3685-
for (const byte *page : pages)
3750+
for (byte *page : pages)
36863751
{
3687-
if (page_get_page_no(page) != page_no ||
3688-
page_get_space_id(page) != space_id)
3752+
if (page_get_page_no(page) != page_id.page_no() ||
3753+
page_get_space_id(page) != page_id.space())
36893754
continue;
36903755
const lsn_t lsn= mach_read_from_8(page + FIL_PAGE_LSN);
3691-
if (lsn <= max_lsn)
3756+
if (lsn <= max_lsn ||
3757+
!validate_page(page_id, page, space, tmp_buf))
3758+
{
3759+
/* Mark processed for subsequent iterations in buf_dblwr_process() */
3760+
memset(page + FIL_PAGE_LSN, 0, 8);
36923761
continue;
3762+
}
36933763
max_lsn= lsn;
36943764
result= page;
36953765
}

0 commit comments

Comments
 (0)