From d2f6e01ec2ad76fabc340bda9dfe7ba37d46e223 Mon Sep 17 00:00:00 2001 From: Peter Geoghegan 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