Skip to content

Conversation

@satya-bodapati
Copy link
Contributor

Merge 8.0 fix to 8.4

https://perconadev.atlassian.net/browse/PS-9683

Problem:
--------
In some of the customer environments, it is found that an external LOB's first
page is shared between two records. This shouldn't be possible. But it can happen
rarely. The root cause is not known yet. Using table in state, can lead to corruption
and assertion failures.

Fix:
---
But we can detect such a scenario by scanning all records and the external LOB's first
page. the EXTENDED keyword currently is ignored by InnoDB.

We use it to enable the LOB checks and mark index as corrupted if an external LOB's first
page is shared between two records.

A thread local blob map is used to identify the duplicate user record
that has the same external LOB page.

usage:
------

CHECK TABLE t1 EXTENDED

A sample error log when such corruption is detected:

2025-04-11T10:30:28.078607Z 9 [ERROR] [MY-011825] [InnoDB] Invalid record! External LOB first page cannot be shared between two records
2025-04-11T10:30:28.078625Z 9 [ERROR] [MY-011825] [InnoDB] The external LOB first page is [page id: space=6, page number=347]
2025-04-11T10:30:28.078631Z 9 [ERROR] [MY-011825] [InnoDB] The first occurence of the external LOB first page is in record : page_no: 3 with heap_no: 6
2025-04-11T10:30:28.078638Z 9 [ERROR] [MY-011825] [InnoDB] The second occurence of the external LOB first page is in record: page_no: 4 with heap no: 7
2025-04-11T10:30:28.078646Z 9 [ERROR] [MY-012738] [InnoDB] Apparent corruption in space 6 page 4 index `PRIMARY`
2025-04-11T10:30:28.078663Z 9 [ERROR] [MY-013050] [InnoDB] In page 4 of index `PRIMARY` of table `test`.`t1`
2025-04-11T10:30:28.088156Z 9 [Warning] [MY-012382] [InnoDB] Cannot open table test/t1Please refer to http://dev.mysql.com/doc/refman/8.0/en/innodb-troubleshooting.html for how to resolve the issue.
@satya-bodapati satya-bodapati requested a review from dlenev April 15, 2025 09:43
@satya-bodapati satya-bodapati changed the title (8.4) PS-9683 : Enable CHECK TABLE EXTENDED to detect InnoDB LOB corruptions [8.4] PS-9683 : Enable CHECK TABLE EXTENDED to detect InnoDB LOB corruptions Apr 15, 2025
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Clang-Tidy found issue(s) with the introduced code (1/1)

}

/* true if user uses CHECK TABLE t1 EXTENDED */
const bool is_extended = check_opt->flags & T_EXTEND;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ readability-implicit-bool-conversion ⚠️
implicit conversion unsigned long -> bool

Suggested change
const bool is_extended = check_opt->flags & T_EXTEND;
const bool is_extended = (check_opt->flags & T_EXTEND) != 0u;

Comment on lines +19124 to +19126
} else {
continue;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ llvm-else-after-return ⚠️
do not use else after break

Suggested change
} else {
continue;
}
} continue;

ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
ut_a(seg_inode);
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ bugprone-implicit-widening-of-multiplication-result ⚠️
performing an implicit widening conversion to type unsigned long of a multiplication performed in type unsigned int

ulint n_fields = rec_offs_n_fields(offsets);

for (ulint i = 0; i < n_fields; i++) {
if (rec_offs_nth_extern(index, offsets, i)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ readability-implicit-bool-conversion ⚠️
implicit conversion ulint (aka unsigned long) -> bool

Suggested change
if (rec_offs_nth_extern(index, offsets, i)) {
if (rec_offs_nth_extern(index, offsets, i) != 0u) {

if (rec_offs_nth_extern(index, offsets, i)) {
// We do const_cast to remove constness because lob::ref_t doesn't have a
// variant that takes const record pointer
byte *field_ref = const_cast<byte *>(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ cppcoreguidelines-pro-type-const-cast ⚠️
do not use const_cast

goto func_exit;
}

if (!page_rec_blob_validate(const_cast<byte *>(rec), index, offsets)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ cppcoreguidelines-pro-type-const-cast ⚠️
do not use const_cast

}

if (!page_rec_blob_validate(const_cast<byte *>(rec), index, offsets)) {
goto func_exit;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ cppcoreguidelines-avoid-goto ⚠️
avoid using goto for flow control

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant