summaryrefslogtreecommitdiff
path: root/src/backend/utils/time/snapmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/time/snapmgr.c')
-rw-r--r--src/backend/utils/time/snapmgr.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index e739d2d192b..584d70c805c 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -46,10 +46,12 @@
#include "storage/predicate.h"
#include "storage/proc.h"
#include "storage/procarray.h"
+#include "storage/sinval.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/resowner_private.h"
#include "utils/snapmgr.h"
+#include "utils/syscache.h"
#include "utils/tqual.h"
@@ -58,17 +60,26 @@
* mode, and to the latest one taken in a read-committed transaction.
* SecondarySnapshot is a snapshot that's always up-to-date as of the current
* instant, even in transaction-snapshot mode. It should only be used for
- * special-purpose code (say, RI checking.)
+ * special-purpose code (say, RI checking.) CatalogSnapshot points to an
+ * MVCC snapshot intended to be used for catalog scans; we must refresh it
+ * whenever a system catalog change occurs.
*
* These SnapshotData structs are static to simplify memory allocation
* (see the hack in GetSnapshotData to avoid repeated malloc/free).
*/
static SnapshotData CurrentSnapshotData = {HeapTupleSatisfiesMVCC};
static SnapshotData SecondarySnapshotData = {HeapTupleSatisfiesMVCC};
+static SnapshotData CatalogSnapshotData = {HeapTupleSatisfiesMVCC};
/* Pointers to valid snapshots */
static Snapshot CurrentSnapshot = NULL;
static Snapshot SecondarySnapshot = NULL;
+static Snapshot CatalogSnapshot = NULL;
+
+/*
+ * Staleness detection for CatalogSnapshot.
+ */
+static bool CatalogSnapshotStale = true;
/*
* These are updated by GetSnapshotData. We initialize them this way
@@ -177,6 +188,9 @@ GetTransactionSnapshot(void)
else
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
+ /* Don't allow catalog snapshot to be older than xact snapshot. */
+ CatalogSnapshotStale = true;
+
FirstSnapshotSet = true;
return CurrentSnapshot;
}
@@ -184,6 +198,9 @@ GetTransactionSnapshot(void)
if (IsolationUsesXactSnapshot())
return CurrentSnapshot;
+ /* Don't allow catalog snapshot to be older than xact snapshot. */
+ CatalogSnapshotStale = true;
+
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
return CurrentSnapshot;
@@ -207,6 +224,54 @@ GetLatestSnapshot(void)
}
/*
+ * GetCatalogSnapshot
+ * Get a snapshot that is sufficiently up-to-date for scan of the
+ * system catalog with the specified OID.
+ */
+Snapshot
+GetCatalogSnapshot(Oid relid)
+{
+ /*
+ * If the caller is trying to scan a relation that has no syscache,
+ * no catcache invalidations will be sent when it is updated. For a
+ * a few key relations, snapshot invalidations are sent instead. If
+ * we're trying to scan a relation for which neither catcache nor
+ * snapshot invalidations are sent, we must refresh the snapshot every
+ * time.
+ */
+ if (!CatalogSnapshotStale && !RelationInvalidatesSnapshotsOnly(relid) &&
+ !RelationHasSysCache(relid))
+ CatalogSnapshotStale = true;
+
+ if (CatalogSnapshotStale)
+ {
+ /* Get new snapshot. */
+ CatalogSnapshot = GetSnapshotData(&CatalogSnapshotData);
+
+ /*
+ * Mark new snapshost as valid. We must do this last, in case an
+ * ERROR occurs inside GetSnapshotData().
+ */
+ CatalogSnapshotStale = false;
+ }
+
+ return CatalogSnapshot;
+}
+
+/*
+ * Mark the current catalog snapshot as invalid. We could change this API
+ * to allow the caller to provide more fine-grained invalidation details, so
+ * that a change to relation A wouldn't prevent us from using our cached
+ * snapshot to scan relation B, but so far there's no evidence that the CPU
+ * cycles we spent tracking such fine details would be well-spent.
+ */
+void
+InvalidateCatalogSnapshot()
+{
+ CatalogSnapshotStale = true;
+}
+
+/*
* SnapshotSetCommandId
* Propagate CommandCounterIncrement into the static snapshots, if set
*/