diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 5580637..ea0dcff 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -538,7 +538,7 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen) if (all_visible) { /* Don't pass rel; that will fail in recovery. */ - OldestXmin = GetOldestXmin(NULL, true); + OldestXmin = GetOldestXmin(NULL, IGNORE_FLAGS_VACUUM); } rel = relation_open(relid, AccessShareLock); @@ -660,7 +660,7 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen) * a buffer lock. And this shouldn't happen often, so it's * worth being careful so as to avoid false positives. */ - RecomputedOldestXmin = GetOldestXmin(NULL, true); + RecomputedOldestXmin = GetOldestXmin(NULL, IGNORE_FLAGS_VACUUM); if (!TransactionIdPrecedes(OldestXmin, RecomputedOldestXmin)) record_corrupt_item(items, &tuple.t_self); diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index 8db1e20..b6680d8 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -70,7 +70,7 @@ statapprox_heap(Relation rel, output_type *stat) TransactionId OldestXmin; uint64 misc_count = 0; - OldestXmin = GetOldestXmin(rel, true); + OldestXmin = GetOldestXmin(rel, IGNORE_FLAGS_VACUUM); bstrategy = GetAccessStrategy(BAS_BULKREAD); nblocks = RelationGetNumberOfBlocks(rel); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 2dcff7f..03bb7e6 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -8855,7 +8855,7 @@ CreateCheckPoint(int flags) * StartupSUBTRANS hasn't been called yet. */ if (!RecoveryInProgress()) - TruncateSUBTRANS(GetOldestXmin(NULL, false)); + TruncateSUBTRANS(GetOldestXmin(NULL, IGNORE_FLAGS_DEFAULT)); /* Real work is done, but log and update stats before releasing lock. */ LogCheckpointEnd(false); @@ -9218,7 +9218,7 @@ CreateRestartPoint(int flags) * this because StartupSUBTRANS hasn't been called yet. */ if (EnableHotStandby) - TruncateSUBTRANS(GetOldestXmin(NULL, false)); + TruncateSUBTRANS(GetOldestXmin(NULL, IGNORE_FLAGS_DEFAULT)); /* Real work is done, but log and update before releasing lock. */ LogCheckpointEnd(true); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index f8d9214..5d184ca 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2270,7 +2270,7 @@ IndexBuildHeapRangeScan(Relation heapRelation, { snapshot = SnapshotAny; /* okay to ignore lazy VACUUMs here */ - OldestXmin = GetOldestXmin(heapRelation, true); + OldestXmin = GetOldestXmin(heapRelation, IGNORE_FLAGS_VACUUM); } scan = heap_beginscan_strat(heapRelation, /* relation */ diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index ed3acb1..d6b37c8 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -993,7 +993,7 @@ acquire_sample_rows(Relation onerel, int elevel, totalblocks = RelationGetNumberOfBlocks(onerel); /* Need a cutoff xmin for HeapTupleSatisfiesVacuum */ - OldestXmin = GetOldestXmin(onerel, true); + OldestXmin = GetOldestXmin(onerel, IGNORE_FLAGS_VACUUM); /* Prepare for sampling block numbers */ BlockSampler_Init(&bs, totalblocks, targrows, random()); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 812fb4a..c10789f 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -497,7 +497,7 @@ vacuum_set_xid_limits(Relation rel, * always an independent transaction. */ *oldestXmin = - TransactionIdLimitedForOldSnapshots(GetOldestXmin(rel, true), rel); + TransactionIdLimitedForOldSnapshots(GetOldestXmin(rel, IGNORE_FLAGS_VACUUM), rel); Assert(TransactionIdIsNormal(*oldestXmin)); @@ -909,7 +909,7 @@ vac_update_datfrozenxid(void) * committed pg_class entries for new tables; see AddNewRelationTuple(). * So we cannot produce a wrong minimum by starting with this. */ - newFrozenXid = GetOldestXmin(NULL, true); + newFrozenXid = GetOldestXmin(NULL, IGNORE_FLAGS_VACUUM); /* * Similarly, initialize the MultiXact "min" with the value that would be diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 5c2e72b..d18f103 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -1223,7 +1223,7 @@ XLogWalRcvSendHSFeedback(bool immed) * everything else has been checked. */ if (hot_standby_feedback) - xmin = GetOldestXmin(NULL, false); + xmin = GetOldestXmin(NULL, IGNORE_FLAGS_DEFAULT); else xmin = InvalidTransactionId; diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index cd14667..980fedc 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -170,6 +170,7 @@ static void KnownAssignedXidsReset(void); static inline void ProcArrayEndTransactionInternal(PGPROC *proc, PGXACT *pgxact, TransactionId latestXid); static void ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid); +static uint8 ConvertIgnoreFlagToVacuumFlag(uint ignoreFlags); /* * Report shared-memory space needed by CreateSharedProcArray. @@ -1252,6 +1253,22 @@ TransactionIdIsActive(TransactionId xid) return result; } +static uint8 +ConvertIgnoreFlagToVacuumFlag(uint ignoreFlags) +{ + uint8 result = 0; + + if (ignoreFlags & IGNORE_A_FLAG_VACUUM) + result |= PROC_IN_VACUUM; + + if (ignoreFlags & IGNORE_A_FLAG_ANALYZE) + result |= PROC_IN_ANALYZE; + + if (ignoreFlags & IGNORE_A_FLAG_LOGICAL_DECODING) + result |= PROC_IN_LOGICAL_DECODING; + + return result; +} /* * GetOldestXmin -- returns oldest transaction that was running @@ -1302,16 +1319,19 @@ TransactionIdIsActive(TransactionId xid) * GetOldestXmin() move backwards, with no consequences for data integrity. */ TransactionId -GetOldestXmin(Relation rel, bool ignoreVacuum) +GetOldestXmin(Relation rel, uint8 ignoreFlags) { ProcArrayStruct *arrayP = procArray; TransactionId result; int index; bool allDbs; + uint8 ignoreVacuumFlags; volatile TransactionId replication_slot_xmin = InvalidTransactionId; volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId; + ignoreVacuumFlags = ConvertIgnoreFlagToVacuumFlag(ignoreFlags); + /* * If we're not computing a relation specific limit, or if a shared * relation has been passed in, backends in all databases have to be @@ -1340,14 +1360,7 @@ GetOldestXmin(Relation rel, bool ignoreVacuum) volatile PGPROC *proc = &allProcs[pgprocno]; volatile PGXACT *pgxact = &allPgXact[pgprocno]; - /* - * Backend is doing logical decoding which manages xmin separately, - * check below. - */ - if (pgxact->vacuumFlags & PROC_IN_LOGICAL_DECODING) - continue; - - if (ignoreVacuum && (pgxact->vacuumFlags & PROC_IN_VACUUM)) + if (pgxact->vacuumFlags & ignoreVacuumFlags) continue; if (allDbs || diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index 9d5a13e..1da2abd 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -20,6 +20,18 @@ #include "utils/snapshot.h" +/* These are to implement IGNORE_FLAGS_XXX */ +#define IGNORE_A_FLAG_VACUUM 0x02 /* currently running lazy vacuum */ +#define IGNORE_A_FLAG_ANALYZE 0x04 /* currently running analyze */ +#define IGNORE_A_FLAG_LOGICAL_DECODING 0x10 /* currently doing logical + * decoding outside xact */ + +/* Use these flags in GetOldestXmin as ignoreFlags */ +#define IGNORE_FLAGS_DEFAULT IGNORE_A_FLAG_LOGICAL_DECODING +#define IGNORE_FLAGS_VACUUM IGNORE_FLAGS_DEFAULT | IGNORE_A_FLAG_VACUUM +#define IGNORE_FLAGS_ANALYZE IGNORE_FLAGS_DEFAULT | IGNORE_A_FLAG_ANALYZE +#define IGNORE_FLAGS_VACUUM_ANALYZE IGNORE_FLAGS_DEFAULT | IGNORE_A_FLAG_VACUUM | IGNORE_A_FLAG_ANALYZE + extern Size ProcArrayShmemSize(void); extern void CreateSharedProcArray(void); extern void ProcArrayAdd(PGPROC *proc); @@ -53,7 +65,7 @@ extern RunningTransactions GetRunningTransactionData(void); extern bool TransactionIdIsInProgress(TransactionId xid); extern bool TransactionIdIsActive(TransactionId xid); -extern TransactionId GetOldestXmin(Relation rel, bool ignoreVacuum); +extern TransactionId GetOldestXmin(Relation rel, uint8 ignoreFlags); extern TransactionId GetOldestActiveTransactionId(void); extern TransactionId GetOldestSafeDecodingTransactionId(void);