v3-0004-amcheck-Report-an-error-when-the-next-page-to-a-l.patch

application/octet-stream

Filename: v3-0004-amcheck-Report-an-error-when-the-next-page-to-a-l.patch
Type: application/octet-stream
Part: 1
Message: Re: [PATCH] Improve amcheck to also check UNIQUE constraint in btree index.

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v3-0004
Subject: amcheck: Report an error when the next page to a leaf is not a leaf
File+
contrib/amcheck/verify_nbtree.c 16 6
From b4645780074cdb0a3abdb7c84435d6abad4e3bec Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Fri, 10 May 2024 03:07:22 +0300
Subject: [PATCH v3 4/4] amcheck: Report an error when the next page to a leaf
 is not a leaf

This is a very unlikely condition during checking a B-tree unique constraint,
meaning that the index structure is violated badly, and we shouldn't continue
checking to avoid endless loops, etc.  So it's worth immediately throwing an
error.

Reported-by: Peter Geoghegan
Discussion: https://postgr.es/m/CAH2-Wzk%2B2116uOXdOViA27SHcr31WKPgmjsxXLBs_aTxAeThzg%40mail.gmail.com
Author: Pavel Borisov
---
 contrib/amcheck/verify_nbtree.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index 977f8b6799d..e9bbc18c4a5 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -1849,7 +1849,6 @@ bt_target_page_check(BtreeCheckState *state)
 		if (offset == max)
 		{
 			BTScanInsert rightkey;
-			BlockNumber rightblock_number;
 
 			/* first offset on a right index page (log only) */
 			OffsetNumber rightfirstoffset = InvalidOffsetNumber;
@@ -1894,10 +1893,11 @@ bt_target_page_check(BtreeCheckState *state)
 			 * If index has unique constraint make sure that no more than one
 			 * found equal items is visible.
 			 */
-			rightblock_number = topaque->btpo_next;
 			if (state->checkunique && state->indexinfo->ii_Unique &&
-				rightkey && P_ISLEAF(topaque) && rightblock_number != P_NONE)
+				rightkey && P_ISLEAF(topaque) && !P_RIGHTMOST(topaque))
 			{
+				BlockNumber rightblock_number = topaque->btpo_next;
+
 				elog(DEBUG2, "check cross page unique condition");
 
 				/*
@@ -1924,9 +1924,19 @@ bt_target_page_check(BtreeCheckState *state)
 												  rightblock_number);
 					topaque = BTPageGetOpaque(rightpage);
 
-					if (P_IGNORE(topaque) || !P_ISLEAF(topaque))
-						break;
-
+					if (P_IGNORE(topaque))
+					{
+						if (unlikely(!P_ISLEAF(topaque)))
+							ereport(ERROR,
+									(errcode(ERRCODE_INDEX_CORRUPTED),
+									 errmsg("right block of leaf block is non-leaf for index \"%s\"",
+											RelationGetRelationName(state->rel)),
+									 errdetail_internal("Block=%u page lsn=%X/%X.",
+														state->targetblock,
+														LSN_FORMAT_ARGS(state->targetlsn))));
+						else
+							break;
+					}
 					itemid = PageGetItemIdCareful(state, rightblock_number,
 												  rightpage,
 												  rightfirstoffset);
-- 
2.39.3 (Apple Git-145)