Skip to content

Commit eaa7bfb

Browse files
committed
MDEV-12396 IMPORT TABLESPACE: Simplify validation
fil_iterate(): Validate the pages directly. import_page_status_t, PageConverter::validate(): Remove. AbstractCallback::filename(): New accessor. AbstractCallback::is_interrupted(): Replaces periodic_check(). PageConverter::trigger_corruption(): Remove.
1 parent 6247c64 commit eaa7bfb

File tree

2 files changed

+112
-318
lines changed

2 files changed

+112
-318
lines changed

storage/innobase/row/row0import.cc

Lines changed: 56 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,8 @@ class AbstractCallback
421421
return(m_page_size);
422422
}
423423

424+
const char* filename() const { return m_filepath; }
425+
424426
/**
425427
Called for every page in the tablespace. If the page was not
426428
updated then its state must be set to BUF_PAGE_NOT_USED. For
@@ -437,6 +439,8 @@ class AbstractCallback
437439
@return the space id of the tablespace */
438440
virtual ulint get_space_id() const UNIV_NOTHROW = 0;
439441

442+
bool is_interrupted() const { return trx_is_interrupted(m_trx); }
443+
440444
protected:
441445
/**
442446
Get the data page depending on the table type, compressed or not.
@@ -451,18 +455,6 @@ class AbstractCallback
451455
return(buf_block_get_frame(block));
452456
}
453457

454-
/** Check for session interrupt. If required we could
455-
even flush to disk here every N pages.
456-
@retval DB_SUCCESS or error code */
457-
dberr_t periodic_check() UNIV_NOTHROW
458-
{
459-
if (trx_is_interrupted(m_trx)) {
460-
return(DB_INTERRUPTED);
461-
}
462-
463-
return(DB_SUCCESS);
464-
}
465-
466458
/**
467459
Get the physical offset of the extent descriptor within the page.
468460
@param page_no - page number of the extent descriptor
@@ -732,11 +724,7 @@ FetchIndexRootPages::operator() (
732724
os_offset_t offset,
733725
buf_block_t* block) UNIV_NOTHROW
734726
{
735-
dberr_t err;
736-
737-
if ((err = periodic_check()) != DB_SUCCESS) {
738-
return(err);
739-
}
727+
if (is_interrupted()) return DB_INTERRUPTED;
740728

741729
const page_t* page = get_frame(block);
742730

@@ -749,9 +737,9 @@ FetchIndexRootPages::operator() (
749737
block->page.offset,
750738
(ulint) (offset / m_page_size));
751739

752-
err = DB_CORRUPTION;
740+
return DB_CORRUPTION;
753741
} else if (page_type == FIL_PAGE_TYPE_XDES) {
754-
err = set_current_xdes(block->page.offset, page);
742+
return set_current_xdes(block->page.offset, page);
755743
} else if (page_type == FIL_PAGE_INDEX
756744
&& !is_free(block->page.offset)
757745
&& is_root_page(page)) {
@@ -776,7 +764,7 @@ FetchIndexRootPages::operator() (
776764
}
777765
}
778766

779-
return(err);
767+
return DB_SUCCESS;
780768
}
781769

782770
/**
@@ -900,14 +888,6 @@ class PageConverter : public AbstractCallback {
900888
os_offset_t offset,
901889
buf_block_t* block) UNIV_NOTHROW;
902890
private:
903-
904-
/** Status returned by PageConverter::validate() */
905-
enum import_page_status_t {
906-
IMPORT_PAGE_STATUS_OK, /*!< Page is OK */
907-
IMPORT_PAGE_STATUS_ALL_ZERO, /*!< Page is all zeros */
908-
IMPORT_PAGE_STATUS_CORRUPTED /*!< Page is corrupted */
909-
};
910-
911891
/**
912892
Update the page, set the space id, max trx id and index id.
913893
@param block - block read from file
@@ -917,17 +897,6 @@ class PageConverter : public AbstractCallback {
917897
buf_block_t* block,
918898
ulint& page_type) UNIV_NOTHROW;
919899

920-
#if defined UNIV_DEBUG
921-
/**
922-
@return true error condition is enabled. */
923-
bool trigger_corruption() UNIV_NOTHROW
924-
{
925-
return(false);
926-
}
927-
#else
928-
#define trigger_corruption() (false)
929-
#endif /* UNIV_DEBUG */
930-
931900
/**
932901
Update the space, index id, trx id.
933902
@param block - block to convert
@@ -940,15 +909,6 @@ class PageConverter : public AbstractCallback {
940909
@retval DB_SUCCESS or error code */
941910
dberr_t update_records(buf_block_t* block) UNIV_NOTHROW;
942911

943-
/**
944-
Validate the page, check for corruption.
945-
@param offset - physical offset within file.
946-
@param page - page read from file.
947-
@return 0 on success, 1 if all zero, 2 if corrupted */
948-
import_page_status_t validate(
949-
os_offset_t offset,
950-
buf_block_t* page) UNIV_NOTHROW;
951-
952912
/**
953913
Validate the space flags and update tablespace header page.
954914
@param block - block read from file, not from the buffer pool.
@@ -2075,97 +2035,24 @@ PageConverter::update_page(
20752035
return(DB_CORRUPTION);
20762036
}
20772037

2078-
/**
2079-
Validate the page
2080-
@param offset - physical offset within file.
2081-
@param page - page read from file.
2082-
@return status */
2083-
PageConverter::import_page_status_t
2084-
PageConverter::validate(
2085-
os_offset_t offset,
2086-
buf_block_t* block) UNIV_NOTHROW
2087-
{
2088-
buf_frame_t* page = get_frame(block);
2089-
2090-
/* Check that the page number corresponds to the offset in
2091-
the file. Flag as corrupt if it doesn't. Disable the check
2092-
for LSN in buf_page_is_corrupted() */
2093-
2094-
if (buf_page_is_corrupted(false, page, get_zip_size(), NULL)
2095-
|| (page_get_page_no(page) != offset / m_page_size
2096-
&& page_get_page_no(page) != 0)) {
2097-
2098-
return(IMPORT_PAGE_STATUS_CORRUPTED);
2099-
2100-
} else if (offset > 0 && page_get_page_no(page) == 0) {
2101-
ulint checksum;
2102-
2103-
checksum = mach_read_from_4(page + FIL_PAGE_SPACE_OR_CHKSUM);
2104-
if (checksum != 0) {
2105-
/* Checksum check passed in buf_page_is_corrupted(). */
2106-
ib_logf(IB_LOG_LEVEL_WARN,
2107-
"%s: Page %lu checksum " ULINTPF
2108-
" should be zero.",
2109-
m_filepath, (ulong) (offset / m_page_size),
2110-
checksum);
2111-
}
2112-
2113-
const byte* b = page + FIL_PAGE_OFFSET;
2114-
const byte* e = page + m_page_size
2115-
- FIL_PAGE_END_LSN_OLD_CHKSUM;
2116-
2117-
/* If the page number is zero and offset > 0 then
2118-
the entire page MUST consist of zeroes. If not then
2119-
we flag it as corrupt. */
2120-
2121-
while (b != e) {
2122-
2123-
if (*b++ && !trigger_corruption()) {
2124-
return(IMPORT_PAGE_STATUS_CORRUPTED);
2125-
}
2126-
}
2127-
2128-
/* The page is all zero: do nothing. */
2129-
return(IMPORT_PAGE_STATUS_ALL_ZERO);
2130-
}
2131-
2132-
return(IMPORT_PAGE_STATUS_OK);
2133-
}
2134-
21352038
/**
21362039
Called for every page in the tablespace. If the page was not
21372040
updated then its state must be set to BUF_PAGE_NOT_USED.
2138-
@param offset - physical offset within the file
21392041
@param block - block read from file, note it is not from the buffer pool
21402042
@retval DB_SUCCESS or error code. */
21412043
dberr_t
2142-
PageConverter::operator() (
2143-
os_offset_t offset,
2144-
buf_block_t* block) UNIV_NOTHROW
2044+
PageConverter::operator() (os_offset_t, buf_block_t* block) UNIV_NOTHROW
21452045
{
21462046
ulint page_type;
2147-
dberr_t err = DB_SUCCESS;
2148-
2149-
if ((err = periodic_check()) != DB_SUCCESS) {
2150-
return(err);
2151-
}
21522047

21532048
if (is_compressed_table()) {
21542049
m_page_zip_ptr = &block->page.zip;
21552050
} else {
21562051
ut_ad(m_page_zip_ptr == 0);
21572052
}
21582053

2159-
switch(validate(offset, block)) {
2160-
case IMPORT_PAGE_STATUS_OK:
2161-
2162-
/* We have to decompress the compressed pages before
2163-
we can work on them */
2164-
2165-
if ((err = update_page(block, page_type)) != DB_SUCCESS) {
2166-
break;
2167-
}
2168-
2054+
dberr_t err = update_page(block, page_type);
2055+
if (err == DB_SUCCESS) {
21692056
/* Note: For compressed pages this function will write to the
21702057
zip descriptor and for uncompressed pages it will write to
21712058
page (ie. the block->frame). Therefore the caller should write
@@ -2187,23 +2074,9 @@ PageConverter::operator() (
21872074
get_frame(block), get_zip_size(),
21882075
m_current_lsn);
21892076
}
2190-
2191-
break;
2192-
2193-
case IMPORT_PAGE_STATUS_ALL_ZERO:
2194-
/* The page is all zero: leave it as is. */
2195-
break;
2196-
2197-
case IMPORT_PAGE_STATUS_CORRUPTED:
2198-
2199-
ib_logf(IB_LOG_LEVEL_WARN,
2200-
"%s: Page %lu at offset " UINT64PF " looks corrupted.",
2201-
m_filepath, (ulong) (offset / m_page_size), offset);
2202-
2203-
err = DB_CORRUPTION;
22042077
}
22052078

2206-
/* If we already had and old page with matching number
2079+
/* If we already had an old page with matching number
22072080
in the buffer pool, evict it now, because
22082081
we no longer evict the pages on DISCARD TABLESPACE. */
22092082
buf_page_get_gen(get_space_id(), get_zip_size(), block->page.offset,
@@ -3519,8 +3392,6 @@ fil_iterate(
35193392
AbstractCallback& callback)
35203393
{
35213394
os_offset_t offset;
3522-
ulint page_no = 0;
3523-
ulint space_id = callback.get_space_id();
35243395
ulint n_bytes = iter.n_io_buffers * iter.page_size;
35253396

35263397
ut_ad(!srv_read_only_mode);
@@ -3531,6 +3402,9 @@ fil_iterate(
35313402
const bool row_compressed = callback.get_zip_size() > 0;
35323403

35333404
for (offset = iter.start; offset < iter.end; offset += n_bytes) {
3405+
if (callback.is_interrupted()) {
3406+
return DB_INTERRUPTED;
3407+
}
35343408

35353409
byte* io_buffer = iter.io_buffer;
35363410

@@ -3572,30 +3446,45 @@ fil_iterate(
35723446
os_offset_t page_off = offset;
35733447
ulint n_pages_read = (ulint) n_bytes / iter.page_size;
35743448
bool decrypted = false;
3449+
const ulint size = iter.page_size;
3450+
block->page.offset = page_off / size;
35753451

3576-
for (ulint i = 0; i < n_pages_read; ++i) {
3577-
ulint size = iter.page_size;
3452+
for (ulint i = 0; i < n_pages_read;
3453+
++i, page_off += size, block->frame += size,
3454+
block->page.offset++) {
35783455
dberr_t err = DB_SUCCESS;
35793456
byte* src = readptr + (i * size);
35803457
byte* dst = io_buffer + (i * size);
35813458
bool frame_changed = false;
3582-
35833459
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
3584-
35853460
const bool page_compressed
3586-
= page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
3461+
= page_type
3462+
== FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
35873463
|| page_type == FIL_PAGE_PAGE_COMPRESSED;
3464+
const ulint page_no = page_get_page_no(src);
3465+
if (!page_no && page_off) {
3466+
const ulint* b = reinterpret_cast<const ulint*>
3467+
(src);
3468+
const ulint* const e = b + size / sizeof *b;
3469+
do {
3470+
if (*b++) {
3471+
goto page_corrupted;
3472+
}
3473+
} while (b != e);
3474+
3475+
/* Proceed to the next page,
3476+
because this one is all zero. */
3477+
continue;
3478+
}
3479+
3480+
if (page_no != page_off / size) {
3481+
goto page_corrupted;
3482+
}
35883483

3589-
/* If tablespace is encrypted, we need to decrypt
3590-
the page. Note that tablespaces are not in
3591-
fil_system during import. */
35923484
if (encrypted) {
35933485
decrypted = fil_space_decrypt(
3594-
iter.crypt_data,
3595-
dst, //dst
3596-
iter.page_size,
3597-
src, // src
3598-
&err);
3486+
iter.crypt_data, dst,
3487+
iter.page_size, src, &err);
35993488

36003489
if (err != DB_SUCCESS) {
36013490
return err;
@@ -3619,10 +3508,20 @@ fil_iterate(
36193508
fil_decompress_page(NULL, dst, ulong(size),
36203509
NULL);
36213510
updated = true;
3511+
} else if (buf_page_is_corrupted(
3512+
false,
3513+
encrypted && !frame_changed
3514+
? dst : src,
3515+
callback.get_zip_size(), NULL)) {
3516+
page_corrupted:
3517+
ib_logf(IB_LOG_LEVEL_WARN,
3518+
"%s: Page %lu at offset "
3519+
UINT64PF " looks corrupted.",
3520+
callback.filename(),
3521+
ulong(offset / size), offset);
3522+
return DB_CORRUPTION;
36223523
}
36233524

3624-
buf_block_set_file_page(block, space_id, page_no++);
3625-
36263525
if ((err = callback(page_off, block)) != DB_SUCCESS) {
36273526
return err;
36283527
} else if (!updated) {
@@ -3714,9 +3613,6 @@ fil_iterate(
37143613

37153614
updated = true;
37163615
}
3717-
3718-
page_off += iter.page_size;
3719-
block->frame += iter.page_size;
37203616
}
37213617

37223618
/* A page was updated in the set, write back to disk. */
@@ -3820,6 +3716,7 @@ fil_tablespace_iterate(
38203716

38213717
memset(&block, 0, sizeof block);
38223718
block.frame = page;
3719+
block.page.space = callback.get_space_id();
38233720
block.page.io_fix = BUF_IO_NONE;
38243721
block.page.buf_fix_count = 1;
38253722
block.page.state = BUF_BLOCK_FILE_PAGE;

0 commit comments

Comments
 (0)