From 218e39d073a50aed1fd30a010a792b38d396951b Mon Sep 17 00:00:00 2001 From: Arseniy Mukhin Date: Tue, 22 Jul 2025 17:37:13 +0300 Subject: [PATCH v10 3/4] amcheck: common_verify - snapshot indcheckxmin check Moves check to common_verify. Every index needs it for heapallindexed check. --- contrib/amcheck/verify_common.c | 25 +++++++++++++++++++++++++ contrib/amcheck/verify_common.h | 3 +++ contrib/amcheck/verify_nbtree.c | 22 +--------------------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/contrib/amcheck/verify_common.c b/contrib/amcheck/verify_common.c index a31ce06ed99..c8d14ac158f 100644 --- a/contrib/amcheck/verify_common.c +++ b/contrib/amcheck/verify_common.c @@ -189,3 +189,28 @@ index_checkable(Relation rel, Oid am_id) return amcheck_index_mainfork_expected(rel); } + +/* + * GetTransactionSnapshot() always acquires a new MVCC snapshot in + * READ COMMITTED mode. A new snapshot is guaranteed to have all + * the entries it requires in the index. + * + * We must defend against the possibility that an old xact + * snapshot was returned at higher isolation levels when that + * snapshot is not safe for index scans of the target index. This + * is possible when the snapshot sees tuples that are before the + * index's indcheckxmin horizon. Throwing an error here should be + * very rare. It doesn't seem worth using a secondary snapshot to + * avoid this. + */ +void +check_indcheckxmin(Relation idxrel, Snapshot snapshot) +{ + if (IsolationUsesXactSnapshot() && idxrel->rd_index->indcheckxmin && + !TransactionIdPrecedes(HeapTupleHeaderGetXmin(idxrel->rd_indextuple->t_data), + snapshot->xmin)) + ereport(ERROR, + (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), + errmsg("index \"%s\" cannot be verified using transaction snapshot", + RelationGetRelationName(idxrel)))); +} diff --git a/contrib/amcheck/verify_common.h b/contrib/amcheck/verify_common.h index 3f4c57f963d..711514707b2 100644 --- a/contrib/amcheck/verify_common.h +++ b/contrib/amcheck/verify_common.h @@ -14,6 +14,7 @@ #include "storage/lmgr.h" #include "storage/lockdefs.h" #include "utils/relcache.h" +#include "utils/snapshot.h" #include "miscadmin.h" /* Typedef for callback function for amcheck_lock_relation_and_check */ @@ -26,3 +27,5 @@ extern void amcheck_lock_relation_and_check(Oid indrelid, Oid am_id, IndexDoCheckCallback check, LOCKMODE lockmode, void *state); + +extern void check_indcheckxmin(Relation idxrel, Snapshot snapshot); diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index 0949c88983a..6231d83ade9 100644 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@ -442,27 +442,7 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace, if (!state->readonly) { snapshot = RegisterSnapshot(GetTransactionSnapshot()); - - /* - * GetTransactionSnapshot() always acquires a new MVCC snapshot in - * READ COMMITTED mode. A new snapshot is guaranteed to have all - * the entries it requires in the index. - * - * We must defend against the possibility that an old xact - * snapshot was returned at higher isolation levels when that - * snapshot is not safe for index scans of the target index. This - * is possible when the snapshot sees tuples that are before the - * index's indcheckxmin horizon. Throwing an error here should be - * very rare. It doesn't seem worth using a secondary snapshot to - * avoid this. - */ - if (IsolationUsesXactSnapshot() && rel->rd_index->indcheckxmin && - !TransactionIdPrecedes(HeapTupleHeaderGetXmin(rel->rd_indextuple->t_data), - snapshot->xmin)) - ereport(ERROR, - (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), - errmsg("index \"%s\" cannot be verified using transaction snapshot", - RelationGetRelationName(rel)))); + check_indcheckxmin(state->rel, snapshot); } } -- 2.43.0