v1-0002-amcheck-Fix-bt_index_parent_check-false-positive.patch
application/octet-stream
Filename: v1-0002-amcheck-Fix-bt_index_parent_check-false-positive.patch
Type: application/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch v1-0002
Subject: amcheck: Fix bt_index_parent_check false positive.
| File | + | − |
|---|---|---|
| contrib/amcheck/verify_nbtree.c | 12 | 5 |
From d2f6e01ec2ad76fabc340bda9dfe7ba37d46e223 Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Fri, 19 May 2023 16:32:40 -0700
Subject: [PATCH v1 2/2] amcheck: Fix bt_index_parent_check false positive.
There is no reason why nbtree VACUUM page deletion that targets the
leftmost leaf page cannot be interrupted (e.g., by a hard crash). That
violates the assumption that nbtree verification (when run with relation
level ShareLock) ought to reliably land on the leftmost page on each
level according to the leftmost internal page one level up.
To fix, demote the ERROR to a DEBUG1 message, since it does still seem
useful to draw a little attention to the issue. It might help when
debugging amcheck itself.
---
contrib/amcheck/verify_nbtree.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index 6979aff72..5cad9f88f 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -767,10 +767,13 @@ bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level)
if (state->readonly)
{
if (!P_LEFTMOST(opaque))
- ereport(ERROR,
- (errcode(ERRCODE_INDEX_CORRUPTED),
+ {
+ ereport(DEBUG1,
+ (errcode(ERRCODE_NO_DATA),
errmsg("block %u is not leftmost in index \"%s\"",
current, RelationGetRelationName(state->rel))));
+ leftcurrent = opaque->btpo_prev;
+ }
if (level.istruerootlevel && !P_ISROOT(opaque))
ereport(ERROR,
@@ -1924,10 +1927,14 @@ bt_child_highkey_check(BtreeCheckState *state,
opaque = BTPageGetOpaque(page);
- /* The first page we visit at the level should be leftmost */
+ /*
+ * The first page we visit at the level will usually be the leftmost,
+ * but not if there was an interrupted page deletion during some
+ * earlier VACUUM
+ */
if (first && !BlockNumberIsValid(state->prevrightlink) && !P_LEFTMOST(opaque))
- ereport(ERROR,
- (errcode(ERRCODE_INDEX_CORRUPTED),
+ ereport(DEBUG1,
+ (errcode(ERRCODE_NO_DATA),
errmsg("the first child of leftmost target page is not leftmost of its level in index \"%s\"",
RelationGetRelationName(state->rel)),
errdetail_internal("Target block=%u child block=%u target page lsn=%X/%X.",
--
2.40.1