Skip to content

Commit

Permalink
MDEV-35394 Innochecksum misinterprets freed pages
Browse files Browse the repository at this point in the history
- Innochecksum misinterprets the freed pages as active one.
This leads the user to think there are too many valid
pages exist.

- To avoid this confusion, innochecksum introduced one
more option --skip-freed-pages and -r to avoid the freed
pages while dumping or printing the summary of the tablespace.

- Innochecksum can safely assume the page is freed if
the respective extent doesn't belong to a segment and marked as
freed in XDES_BITMAP in extent descriptor page.

- Innochecksum shouldn't assume that zero-filled page as extent
descriptor page.
  • Loading branch information
Thirunarayanan committed Nov 21, 2024
1 parent df3855a commit e95959e
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 1 deletion.
20 changes: 19 additions & 1 deletion extra/innochecksum.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ FILE* log_file = NULL;
/* Enabled for log write option. */
static bool is_log_enabled = false;

/* Skip freed pages */
static bool skip_freed_pages= false;
static byte field_ref_zero_buf[UNIV_PAGE_SIZE_MAX];
const byte *field_ref_zero = field_ref_zero_buf;

Expand Down Expand Up @@ -786,6 +788,16 @@ parse_page(

/* Check whether page is doublewrite buffer. */
str = skip_page ? "Double_write_buffer" : "-";
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
if (skip_freed_pages) {
const byte *des= xdes + XDES_ARR_OFFSET +
XDES_SIZE * ((page_no & (physical_page_size - 1))
/ FSP_EXTENT_SIZE);
if (mach_read_from_4(des) != XDES_FSEG &&
xdes_is_free(des, page_no % FSP_EXTENT_SIZE)) {
return;
}
}

switch (fil_page_get_type(page)) {

Expand Down Expand Up @@ -1211,6 +1223,9 @@ static struct my_option innochecksum_options[] = {
&do_leaf, &do_leaf, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"merge", 'm', "leaf page count if merge given number of consecutive pages",
&n_merge, &n_merge, 0, GET_ULONG, REQUIRED_ARG, 0, 0, (longlong)10L, 0, 1, 0},
{"skip-freed-pages", 'r', "skip freed pages for the tablespace",
&skip_freed_pages, &skip_freed_pages, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
Expand Down Expand Up @@ -1288,6 +1303,9 @@ innochecksum_get_one_option(
case 'l':
is_log_enabled = true;
break;
case 'r':
skip_freed_pages = true;
break;
case 'I':
case '?':
usage();
Expand Down Expand Up @@ -1861,7 +1879,7 @@ int main(
printf("page " UINT32PF " ", cur_page_num);
}

if (page_get_page_no(buf) % physical_page_size == 0) {
if (cur_page_num % physical_page_size == 0) {
memcpy(xdes, buf, physical_page_size);
}

Expand Down
7 changes: 7 additions & 0 deletions mysql-test/suite/innodb/r/innochecksum_undo_page.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
SET GLOBAL INNODB_FILE_PER_TABLE= 0;
CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
DROP TABLE t1;
SET GLOBAL innodb_fast_shutdown=0;
FOUND 1 /Undo page state: 0 active, 0 cached, 0 to_purge, 0 prepared, 0 other/ in result.log
# restart
1 change: 1 addition & 0 deletions mysql-test/suite/innodb/t/innochecksum_undo_page.opt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--innodb_undo_tablespaces=0
18 changes: 18 additions & 0 deletions mysql-test/suite/innodb/t/innochecksum_undo_page.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--source include/have_innodb.inc
--source include/not_embedded.inc
let MYSQLD_DATADIR= `SELECT @@datadir`;

SET GLOBAL INNODB_FILE_PER_TABLE= 0;
CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
DROP TABLE t1;
SET GLOBAL innodb_fast_shutdown=0;
--source include/shutdown_mysqld.inc
let $resultlog=$MYSQLTEST_VARDIR/tmp/result.log;
exec $INNOCHECKSUM -S -r $MYSQLD_DATADIR/ibdata1 > $resultlog;

let SEARCH_FILE = $MYSQLTEST_VARDIR/tmp/result.log;
let SEARCH_PATTERN= Undo page state: 0 active, 0 cached, 0 to_purge, 0 prepared, 0 other;
--source include/search_pattern_in_file.inc
--remove_file $resultlog
--source include/start_mysqld.inc
4 changes: 4 additions & 0 deletions mysql-test/suite/innodb_zip/r/innochecksum_2.result
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ per-page-details FALSE
log (No default value)
leaf FALSE
merge 0
skip-freed-pages FALSE
[1]:# check the both short and long options for "help"
[2]:# Run the innochecksum when file isn't provided.
# It will print the innochecksum usage similar to --help option.
Expand Down Expand Up @@ -66,6 +67,8 @@ See https://mariadb.com/kb/en/library/innochecksum/ for usage hints.
-f, --leaf Examine leaf index pages
-m, --merge=# leaf page count if merge given number of consecutive
pages
-r, --skip-freed-pages
skip freed pages for the tablespace

Variables (--variable-name=value)
and boolean options {FALSE|TRUE} Value (after reading options)
Expand All @@ -84,6 +87,7 @@ per-page-details FALSE
log (No default value)
leaf FALSE
merge 0
skip-freed-pages FALSE
[3]:# check the both short and long options for "count" and exit
Number of pages:#
Number of pages:#
Expand Down
1 change: 1 addition & 0 deletions mysql-test/suite/innodb_zip/r/innochecksum_3.result
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ per-page-details FALSE
log (No default value)
leaf FALSE
merge 0
skip-freed-pages FALSE
[5]: Page type dump for with shortform for tab1.ibd


Expand Down

0 comments on commit e95959e

Please sign in to comment.