Verify true root on replicas with amcheck

godjan • <[email protected]>
Newsgroups gmane.comp.db.postgresql.devel.general
Message-ID <[email protected]>
Hi, we have trouble to detect true root corruptions on replicas. I made a patch for resolving it with the locking meta page and potential root page. I heard that amcheck has an invariant about locking no more than 1 page at a moment for avoiding deadlocks. Is there possible a deadlock situation?
amcheck_trueroot.patch (application/octet-stream, 2.4 KB)
commit 26b97b68db2727de3c946d7fcb7d47aa699cf277
Author: Georgy Rylov <[email protected]>
Date:   Thu Jan 9 13:36:02 2020 +0500

    amcheck verify true root on replicas
    
    Here I add checking true root by getting info about it from meta page under
    lock instead of taking lock for the whole table like in parent_check.

diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index 6a058ccdac..67d07f2ba5 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -167,6 +167,7 @@ static ItemId PageGetItemIdCareful(BtreeCheckState *state, BlockNumber block,
 								   Page page, OffsetNumber offset);
 static inline ItemPointer BTreeTupleGetHeapTIDCareful(BtreeCheckState *state,
 													  IndexTuple itup, bool nonpivot);
+static void bt_check_trueroot(BtreeCheckState *state);
 
 /*
  * bt_index_check(index regclass, heapallindexed boolean)
@@ -738,6 +739,10 @@ bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level)
 							 errmsg("block %u is not true root in index \"%s\"",
 									current, RelationGetRelationName(state->rel))));
 			}
+			else
+			{
+				bt_check_trueroot(state);
+			}
 
 			/*
 			 * Before beginning any non-trivial examination of level, prepare
@@ -2571,3 +2576,34 @@ BTreeTupleGetHeapTIDCareful(BtreeCheckState *state, IndexTuple itup,
 
 	return result;
 }
+
+static void bt_check_trueroot(BtreeCheckState *state)
+{
+	Buffer meta_buffer;
+	Page meta_page, root_page;
+	BTMetaPageData *metad;
+	BTPageOpaque root_opaque;
+	bool is_root;
+	meta_page = palloc(BLCKSZ);
+	meta_buffer = ReadBufferExtended(state->rel, MAIN_FORKNUM, BTREE_METAPAGE, RBM_NORMAL,
+									 state->checkstrategy);
+	LockBuffer(meta_buffer, BT_READ);
+	/*
+	 * Perform the same basic sanity checking that nbtree itself performs for
+	 * every page:
+	 */
+	_bt_checkpage(state->rel, meta_buffer);	
+	/* Only use copy of page in palloc()'d memory */
+	memcpy(meta_page, BufferGetPage(meta_buffer), BLCKSZ);
+	/* Get true root block from meta-page */
+	metad = BTPageGetMeta(meta_page);
+	root_page = palloc_btree_page(state, metad->btm_root);
+	root_opaque = (BTPageOpaque) PageGetSpecialPointer(root_page);
+	is_root = P_ISROOT(root_opaque);
+	UnlockReleaseBuffer(meta_buffer);
+	if (!is_root)
+		ereport(ERROR,
+				(errcode(ERRCODE_INDEX_CORRUPTED),
+				 errmsg("block %u is not true root in index \"%s\"",
+						metad->btm_root, RelationGetRelationName(state->rel))));
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.