snapshot_non_vacuumable_v3.patch
application/octet-stream
Filename: snapshot_non_vacuumable_v3.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v3
| File | + | − |
|---|---|---|
| src/backend/utils/adt/selfuncs.c | 13 | 13 |
| src/backend/utils/time/tqual.c | 21 | 0 |
| src/include/utils/tqual.h | 22 | 0 |
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index a35b93b..00fc926 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -5245,7 +5245,7 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
HeapTuple tup;
Datum values[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
- SnapshotData SnapshotDirty;
+ SnapshotData SnapshotNonVacuumable;
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
@@ -5268,7 +5268,7 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRel));
econtext->ecxt_scantuple = slot;
get_typlenbyval(vardata->atttype, &typLen, &typByVal);
- InitDirtySnapshot(SnapshotDirty);
+ InitNonVacuumableSnapshot(SnapshotNonVacuumable, heapRel);
/* set up an IS NOT NULL scan key so that we ignore nulls */
ScanKeyEntryInitialize(&scankeys[0],
@@ -5290,17 +5290,17 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
* active snapshot, which is the best approximation we've got
* to what the query will see when executed. But that won't
* be exact if a new snap is taken before running the query,
- * and it can be very expensive if a lot of uncommitted rows
- * exist at the end of the index (because we'll laboriously
- * fetch each one and reject it). What seems like a good
- * compromise is to use SnapshotDirty. That will accept
- * uncommitted rows, and thus avoid fetching multiple heap
- * tuples in this scenario. On the other hand, it will reject
- * known-dead rows, and thus not give a bogus answer when the
- * extreme value has been deleted; that case motivates not
- * using SnapshotAny here.
+ * and it can be very expensive if a lot of uncommitted or dead
+ * rows exist at the beginning or end of the index (because we'll
+ * laboriously fetch each one and reject it). What seems like a
+ * good compromise is to use SnapshotNonVacuumable. That will
+ * accept uncommitted rows and recently dead rows, and thus avoid
+ * fetching multiple heap tuples in this scenario. On the other
+ * hand, it will reject known-dead rows, and thus not give a bogus
+ * answer when the extreme value has been deleted; that case
+ * motivates not using SnapshotAny here.
*/
- index_scan = index_beginscan(heapRel, indexRel, &SnapshotDirty,
+ index_scan = index_beginscan(heapRel, indexRel, &SnapshotNonVacuumable,
1, 0);
index_rescan(index_scan, scankeys, 1, NULL, 0);
@@ -5332,7 +5332,7 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
/* If max is requested, and we didn't find the index is empty */
if (max && have_data)
{
- index_scan = index_beginscan(heapRel, indexRel, &SnapshotDirty,
+ index_scan = index_beginscan(heapRel, indexRel, &SnapshotNonVacuumable,
1, 0);
index_rescan(index_scan, scankeys, 1, NULL, 0);
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index 519f3b6..3254426 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -49,6 +49,9 @@
* visible unless part of interrupted vacuum, used for TOAST
* HeapTupleSatisfiesAny()
* all tuples are visible
+ * HeapTupleSatisfiesNonVacuumable()
+ * all non-vacuumable tuples are visible, i.e all tuples
+ * except known dead tuples
*
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
@@ -1392,6 +1395,24 @@ HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
return HEAPTUPLE_DEAD;
}
+
+/*
+ * HeapTupleSatisfiesNonVacuumable
+ * False if tuple not visible to any transactionn, i.e. dead.
+ * True in all other cases.
+ *
+ * Use result of HeapTupleSatisfiesVacuum and return
+ * corresponding boolean.
+ */
+bool
+HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot,
+ Buffer buffer)
+{
+ return HeapTupleSatisfiesVacuum(htup, snapshot->xmin, buffer)
+ != HEAPTUPLE_DEAD;
+}
+
+
/*
* HeapTupleIsSurelyDead
*
diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h
index f39f21b..a11482e 100644
--- a/src/include/utils/tqual.h
+++ b/src/include/utils/tqual.h
@@ -16,7 +16,9 @@
#define TQUAL_H
#include "utils/snapshot.h"
+#include "utils/snapmgr.h"
#include "access/xlogdefs.h"
+#include "catalog/catalog.h"
/* Static variables representing various special snapshot semantics */
@@ -68,6 +70,8 @@ extern bool HeapTupleSatisfiesDirty(HeapTuple htup,
Snapshot snapshot, Buffer buffer);
extern bool HeapTupleSatisfiesHistoricMVCC(HeapTuple htup,
Snapshot snapshot, Buffer buffer);
+extern bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup,
+ Snapshot snapshot, Buffer buffer);
/* Special "satisfies" routines with different APIs */
extern HTSU_Result HeapTupleSatisfiesUpdate(HeapTuple htup,
@@ -101,6 +105,24 @@ extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data,
((snapshotdata).satisfies = HeapTupleSatisfiesDirty)
/*
+ * Similarly, some initialization is required for SnapshotNonVacuumable.
+ * We need to set xmin horizon for this relation. If it's a proper
+ * catalog relation or a user defined, additional, catalog relation, we
+ * need to use the horizon that includes slots, otherwise the data-only
+ * horizon can be used. Note that the toast relation of user defined
+ * relations are *not* considered catalog relations.
+ */
+#define InitNonVacuumableSnapshot(snapshotdata, relation) \
+ do { \
+ if (IsCatalogRelation(relation) || \
+ RelationIsAccessibleInLogicalDecoding(relation)) \
+ (snapshotdata).xmin = RecentGlobalXmin; \
+ else \
+ (snapshotdata).xmin = RecentGlobalDataXmin; \
+ (snapshotdata).satisfies = HeapTupleSatisfiesNonVacuumable; \
+ } while(0)
+
+/*
* Similarly, some initialization is required for SnapshotToast. We need
* to set lsn and whenTaken correctly to support snapshot_too_old.
*/