0002-Split-SnapshotData-into-separate-structs-for-each-ki.patch
text/x-patch
Filename: 0002-Split-SnapshotData-into-separate-structs-for-each-ki.patch
Type: text/x-patch
Part: 1
From 3bbfeea35698db6c1e5947bef7e9ad7964a1f3e3 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Fri, 20 Dec 2024 00:36:33 +0200
Subject: [PATCH 2/9] Split SnapshotData into separate structs for each kind of
snapshot
The SnapshotData fields were repurposed for different uses depending
the kind of snapshot. Split it into separate structs for different
kinds of snapshots, so that it is more clear which fields are used
with which snapshot kind, and the fields can have more descriptive
names.
---
contrib/amcheck/verify_heapam.c | 2 +-
contrib/amcheck/verify_nbtree.c | 2 +-
src/backend/access/heap/heapam.c | 3 +-
src/backend/access/heap/heapam_handler.c | 6 +-
src/backend/access/heap/heapam_visibility.c | 24 +--
src/backend/access/index/indexam.c | 11 +-
src/backend/access/nbtree/nbtinsert.c | 4 +-
src/backend/access/spgist/spgvacuum.c | 2 +-
src/backend/access/table/tableam.c | 10 +-
src/backend/access/transam/parallel.c | 14 +-
src/backend/catalog/pg_inherits.c | 2 +-
src/backend/commands/async.c | 4 +-
src/backend/commands/indexcmds.c | 4 +-
src/backend/commands/tablecmds.c | 2 +-
src/backend/executor/execIndexing.c | 4 +-
src/backend/executor/execReplication.c | 8 +-
src/backend/partitioning/partdesc.c | 2 +-
src/backend/replication/logical/decode.c | 2 +-
src/backend/replication/logical/origin.c | 4 +-
.../replication/logical/reorderbuffer.c | 114 +++++-----
src/backend/replication/logical/snapbuild.c | 113 +++++-----
src/backend/replication/walsender.c | 2 +-
src/backend/storage/ipc/procarray.c | 6 +-
src/backend/storage/lmgr/predicate.c | 32 +--
src/backend/utils/adt/xid8funcs.c | 4 +-
src/backend/utils/time/snapmgr.c | 200 +++++++++++-------
src/include/access/heapam.h | 2 +-
src/include/access/relscan.h | 6 +-
src/include/replication/reorderbuffer.h | 12 +-
src/include/replication/snapbuild.h | 6 +-
src/include/replication/snapbuild_internal.h | 2 +-
src/include/storage/predicate.h | 4 +-
src/include/storage/procarray.h | 2 +-
src/include/utils/snapmgr.h | 16 +-
src/include/utils/snapshot.h | 155 ++++++++++----
src/tools/pgindent/typedefs.list | 4 +
36 files changed, 453 insertions(+), 337 deletions(-)
diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index 130b3533463..75907349f42 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -310,7 +310,7 @@ verify_heapam(PG_FUNCTION_ARGS)
* Any xmin newer than the xmin of our snapshot can't become all-visible
* while we're running.
*/
- ctx.safe_xmin = GetTransactionSnapshot()->xmin;
+ ctx.safe_xmin = GetTransactionSnapshot()->mvcc.xmin;
/*
* If we report corruption when not examining some individual attribute,
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index f91392a3a49..b91ac1f3fdf 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -454,7 +454,7 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
*/
if (IsolationUsesXactSnapshot() && rel->rd_index->indcheckxmin &&
!TransactionIdPrecedes(HeapTupleHeaderGetXmin(rel->rd_indextuple->t_data),
- state->snapshot->xmin))
+ state->snapshot->mvcc.xmin))
ereport(ERROR,
errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("index \"%s\" cannot be verified using transaction snapshot",
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 6daf4a87dec..1fa424fa131 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -616,7 +616,8 @@ heap_prepare_pagescan(TableScanDesc sscan)
* full page write. Until we can prove that beyond doubt, let's check each
* tuple for visibility the hard way.
*/
- all_visible = PageIsAllVisible(page) && !snapshot->takenDuringRecovery;
+ all_visible = PageIsAllVisible(page) &&
+ (snapshot->snapshot_type != SNAPSHOT_MVCC || !snapshot->mvcc.takenDuringRecovery);
check_serializable =
CheckForSerializableConflictOutNeeded(scan->rs_base.rs_rd, snapshot);
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index dd4fe6bf62f..26b72a88f65 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -390,7 +390,7 @@ tuple_lock_retry:
if (!ItemPointerEquals(&tmfd->ctid, &tuple->t_self))
{
- SnapshotData SnapshotDirty;
+ DirtySnapshotData SnapshotDirty;
TransactionId priorXmax;
/* it was updated, so look at the updated version */
@@ -415,7 +415,7 @@ tuple_lock_retry:
errmsg("tuple to be locked was already moved to another partition due to concurrent update")));
tuple->t_self = *tid;
- if (heap_fetch(relation, &SnapshotDirty, tuple, &buffer, true))
+ if (heap_fetch(relation, (Snapshot) &SnapshotDirty, tuple, &buffer, true))
{
/*
* If xmin isn't what we're expecting, the slot must have
@@ -2282,7 +2282,7 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
page = BufferGetPage(hscan->rs_cbuf);
all_visible = PageIsAllVisible(page) &&
- !scan->rs_snapshot->takenDuringRecovery;
+ (scan->rs_snapshot->snapshot_type != SNAPSHOT_MVCC || !scan->rs_snapshot->mvcc.takenDuringRecovery);
maxoffset = PageGetMaxOffsetNumber(page);
for (;;)
diff --git a/src/backend/access/heap/heapam_visibility.c b/src/backend/access/heap/heapam_visibility.c
index 05f6946fe60..f5d69b558f1 100644
--- a/src/backend/access/heap/heapam_visibility.c
+++ b/src/backend/access/heap/heapam_visibility.c
@@ -740,7 +740,7 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
* token is also returned in snapshot->speculativeToken.
*/
static bool
-HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
+HeapTupleSatisfiesDirty(HeapTuple htup, DirtySnapshotData *snapshot,
Buffer buffer)
{
HeapTupleHeader tuple = htup->t_data;
@@ -957,7 +957,7 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
* and more contention on ProcArrayLock.
*/
static bool
-HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
+HeapTupleSatisfiesMVCC(HeapTuple htup, MVCCSnapshot snapshot,
Buffer buffer)
{
HeapTupleHeader tuple = htup->t_data;
@@ -1435,7 +1435,7 @@ HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *de
* snapshot->vistest must have been set up with the horizon to use.
*/
static bool
-HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot,
+HeapTupleSatisfiesNonVacuumable(HeapTuple htup, NonVacuumableSnapshotData *snapshot,
Buffer buffer)
{
TransactionId dead_after = InvalidTransactionId;
@@ -1593,7 +1593,7 @@ TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
* complicated than when dealing "only" with the present.
*/
static bool
-HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
+HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, HistoricMVCCSnapshot snapshot,
Buffer buffer)
{
HeapTupleHeader tuple = htup->t_data;
@@ -1610,7 +1610,7 @@ HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
return false;
}
/* check if it's one of our txids, toplevel is also in there */
- else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
+ else if (TransactionIdInArray(xmin, snapshot->curxip, snapshot->curxcnt))
{
bool resolved;
CommandId cmin = HeapTupleHeaderGetRawCommandId(tuple);
@@ -1669,7 +1669,7 @@ HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
return false;
}
/* check if it's a committed transaction in [xmin, xmax) */
- else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
+ else if (TransactionIdInArray(xmin, snapshot->committed_xids, snapshot->xcnt))
{
/* fall through */
}
@@ -1702,7 +1702,7 @@ HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
}
/* check if it's one of our txids, toplevel is also in there */
- if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
+ if (TransactionIdInArray(xmax, snapshot->curxip, snapshot->curxcnt))
{
bool resolved;
CommandId cmin;
@@ -1755,7 +1755,7 @@ HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
return true;
/* xmax is between [xmin, xmax), check known committed array */
- else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
+ else if (TransactionIdInArray(xmax, snapshot->committed_xids, snapshot->xcnt))
return false;
/* xmax is between [xmin, xmax), but known not to have committed yet */
else
@@ -1778,7 +1778,7 @@ HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer)
switch (snapshot->snapshot_type)
{
case SNAPSHOT_MVCC:
- return HeapTupleSatisfiesMVCC(htup, snapshot, buffer);
+ return HeapTupleSatisfiesMVCC(htup, &snapshot->mvcc, buffer);
case SNAPSHOT_SELF:
return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
case SNAPSHOT_ANY:
@@ -1786,11 +1786,11 @@ HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer)
case SNAPSHOT_TOAST:
return HeapTupleSatisfiesToast(htup, snapshot, buffer);
case SNAPSHOT_DIRTY:
- return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
+ return HeapTupleSatisfiesDirty(htup, &snapshot->dirty, buffer);
case SNAPSHOT_HISTORIC_MVCC:
- return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
+ return HeapTupleSatisfiesHistoricMVCC(htup, &snapshot->historic_mvcc, buffer);
case SNAPSHOT_NON_VACUUMABLE:
- return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
+ return HeapTupleSatisfiesNonVacuumable(htup, &snapshot->nonvacuumable, buffer);
}
return false; /* keep compiler quiet */
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 0492d92d23b..7ef5031d716 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -479,7 +479,7 @@ index_parallelscan_estimate(Relation indexRelation, int nkeys, int norderbys,
RELATION_CHECKS;
nbytes = offsetof(ParallelIndexScanDescData, ps_snapshot_data);
- nbytes = add_size(nbytes, EstimateSnapshotSpace(snapshot));
+ nbytes = add_size(nbytes, EstimateSnapshotSpace(&snapshot->mvcc));
nbytes = MAXALIGN(nbytes);
if (instrument)
@@ -528,16 +528,17 @@ index_parallelscan_initialize(Relation heapRelation, Relation indexRelation,
Assert(instrument || parallel_aware);
RELATION_CHECKS;
+ Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
offset = add_size(offsetof(ParallelIndexScanDescData, ps_snapshot_data),
- EstimateSnapshotSpace(snapshot));
+ EstimateSnapshotSpace((MVCCSnapshot) snapshot));
offset = MAXALIGN(offset);
target->ps_locator = heapRelation->rd_locator;
target->ps_indexlocator = indexRelation->rd_locator;
target->ps_offset_ins = 0;
target->ps_offset_am = 0;
- SerializeSnapshot(snapshot, target->ps_snapshot_data);
+ SerializeSnapshot((MVCCSnapshot) snapshot, target->ps_snapshot_data);
if (instrument)
{
@@ -601,8 +602,8 @@ index_beginscan_parallel(Relation heaprel, Relation indexrel,
Assert(RelFileLocatorEquals(heaprel->rd_locator, pscan->ps_locator));
Assert(RelFileLocatorEquals(indexrel->rd_locator, pscan->ps_indexlocator));
- snapshot = RestoreSnapshot(pscan->ps_snapshot_data);
- RegisterSnapshot(snapshot);
+ snapshot = (Snapshot) RestoreSnapshot(pscan->ps_snapshot_data);
+ snapshot = RegisterSnapshot(snapshot);
scan = index_beginscan_internal(indexrel, nkeys, norderbys, snapshot,
pscan, true);
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 031eb76ba8c..ae91a30afc9 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -415,7 +415,7 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
IndexTuple curitup = NULL;
ItemId curitemid = NULL;
BTScanInsert itup_key = insertstate->itup_key;
- SnapshotData SnapshotDirty;
+ DirtySnapshotData SnapshotDirty;
OffsetNumber offset;
OffsetNumber maxoff;
Page page;
@@ -560,7 +560,7 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
* index entry for the entire chain.
*/
else if (table_index_fetch_tuple_check(heapRel, &htid,
- &SnapshotDirty,
+ (Snapshot) &SnapshotDirty,
&all_dead))
{
TransactionId xwait;
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index cb5671c1a4e..4bd25e50606 100644
--- a/src/backend/access/spgist/spgvacuum.c
+++ b/src/backend/access/spgist/spgvacuum.c
@@ -808,7 +808,7 @@ spgvacuumscan(spgBulkDeleteState *bds)
/* Finish setting up spgBulkDeleteState */
initSpGistState(&bds->spgstate, index);
bds->pendingList = NULL;
- bds->myXmin = GetActiveSnapshot()->xmin;
+ bds->myXmin = GetActiveSnapshot()->mvcc.xmin;
bds->lastFilledBlock = SPGIST_LAST_FIXED_BLKNO;
/*
diff --git a/src/backend/access/table/tableam.c b/src/backend/access/table/tableam.c
index 73ebc01a08f..fde28accfd3 100644
--- a/src/backend/access/table/tableam.c
+++ b/src/backend/access/table/tableam.c
@@ -133,7 +133,7 @@ table_parallelscan_estimate(Relation rel, Snapshot snapshot)
Size sz = 0;
if (IsMVCCSnapshot(snapshot))
- sz = add_size(sz, EstimateSnapshotSpace(snapshot));
+ sz = add_size(sz, EstimateSnapshotSpace((MVCCSnapshot) snapshot));
else
Assert(snapshot == SnapshotAny);
@@ -152,7 +152,7 @@ table_parallelscan_initialize(Relation rel, ParallelTableScanDesc pscan,
if (IsMVCCSnapshot(snapshot))
{
- SerializeSnapshot(snapshot, (char *) pscan + pscan->phs_snapshot_off);
+ SerializeSnapshot((MVCCSnapshot) snapshot, (char *) pscan + pscan->phs_snapshot_off);
pscan->phs_snapshot_any = false;
}
else
@@ -174,8 +174,8 @@ table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan)
if (!pscan->phs_snapshot_any)
{
/* Snapshot was serialized -- restore it */
- snapshot = RestoreSnapshot((char *) pscan + pscan->phs_snapshot_off);
- RegisterSnapshot(snapshot);
+ snapshot = (Snapshot) RestoreSnapshot((char *) pscan + pscan->phs_snapshot_off);
+ snapshot = RegisterSnapshot(snapshot);
flags |= SO_TEMP_SNAPSHOT;
}
else
@@ -204,7 +204,7 @@ table_beginscan_parallel_tidrange(Relation relation,
if (!pscan->phs_snapshot_any)
{
/* Snapshot was serialized -- restore it */
- snapshot = RestoreSnapshot((char *) pscan + pscan->phs_snapshot_off);
+ snapshot = (Snapshot) RestoreSnapshot((char *) pscan + pscan->phs_snapshot_off);
RegisterSnapshot(snapshot);
flags |= SO_TEMP_SNAPSHOT;
}
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 642c61fc55c..1fd2146358d 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -279,10 +279,10 @@ InitializeParallelDSM(ParallelContext *pcxt)
shm_toc_estimate_chunk(&pcxt->estimator, combocidlen);
if (IsolationUsesXactSnapshot())
{
- tsnaplen = EstimateSnapshotSpace(transaction_snapshot);
+ tsnaplen = EstimateSnapshotSpace((MVCCSnapshot) transaction_snapshot);
shm_toc_estimate_chunk(&pcxt->estimator, tsnaplen);
}
- asnaplen = EstimateSnapshotSpace(active_snapshot);
+ asnaplen = EstimateSnapshotSpace((MVCCSnapshot) active_snapshot);
shm_toc_estimate_chunk(&pcxt->estimator, asnaplen);
tstatelen = EstimateTransactionStateSpace();
shm_toc_estimate_chunk(&pcxt->estimator, tstatelen);
@@ -401,14 +401,14 @@ InitializeParallelDSM(ParallelContext *pcxt)
if (IsolationUsesXactSnapshot())
{
tsnapspace = shm_toc_allocate(pcxt->toc, tsnaplen);
- SerializeSnapshot(transaction_snapshot, tsnapspace);
+ SerializeSnapshot((MVCCSnapshot) transaction_snapshot, tsnapspace);
shm_toc_insert(pcxt->toc, PARALLEL_KEY_TRANSACTION_SNAPSHOT,
tsnapspace);
}
/* Serialize the active snapshot. */
asnapspace = shm_toc_allocate(pcxt->toc, asnaplen);
- SerializeSnapshot(active_snapshot, asnapspace);
+ SerializeSnapshot((MVCCSnapshot) active_snapshot, asnapspace);
shm_toc_insert(pcxt->toc, PARALLEL_KEY_ACTIVE_SNAPSHOT, asnapspace);
/* Provide the handle for per-session segment. */
@@ -1500,9 +1500,9 @@ ParallelWorkerMain(Datum main_arg)
*/
asnapspace = shm_toc_lookup(toc, PARALLEL_KEY_ACTIVE_SNAPSHOT, false);
tsnapspace = shm_toc_lookup(toc, PARALLEL_KEY_TRANSACTION_SNAPSHOT, true);
- asnapshot = RestoreSnapshot(asnapspace);
- tsnapshot = tsnapspace ? RestoreSnapshot(tsnapspace) : asnapshot;
- RestoreTransactionSnapshot(tsnapshot,
+ asnapshot = (Snapshot) RestoreSnapshot(asnapspace);
+ tsnapshot = tsnapspace ? (Snapshot) RestoreSnapshot(tsnapspace) : asnapshot;
+ RestoreTransactionSnapshot((MVCCSnapshot) tsnapshot,
fps->parallel_leader_pgproc);
PushActiveSnapshot(asnapshot);
diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c
index 929bb53b620..b658601bf77 100644
--- a/src/backend/catalog/pg_inherits.c
+++ b/src/backend/catalog/pg_inherits.c
@@ -148,7 +148,7 @@ find_inheritance_children_extended(Oid parentrelId, bool omit_detached,
xmin = HeapTupleHeaderGetXmin(inheritsTuple->t_data);
snap = GetActiveSnapshot();
- if (!XidInMVCCSnapshot(xmin, snap))
+ if (!XidInMVCCSnapshot(xmin, (MVCCSnapshot) snap))
{
if (detached_xmin)
{
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eb86402cae4..7c32d28a9b2 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1996,6 +1996,8 @@ asyncQueueProcessPageEntries(QueuePosition *current,
InvalidTransactionId);
page_buffer = NotifyCtl->shared->page_buffer[slotno];
+ Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
+
do
{
QueuePosition thisentry = *current;
@@ -2016,7 +2018,7 @@ asyncQueueProcessPageEntries(QueuePosition *current,
/* Ignore messages destined for other databases */
if (qe->dboid == MyDatabaseId)
{
- if (XidInMVCCSnapshot(qe->xid, snapshot))
+ if (XidInMVCCSnapshot(qe->xid, (MVCCSnapshot) snapshot))
{
/*
* The source transaction is still in progress, so we can't
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index d9cccb6ac18..76a94172200 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1760,7 +1760,7 @@ DefineIndex(Oid tableId,
* they must wait for. But first, save the snapshot's xmin to use as
* limitXmin for GetCurrentVirtualXIDs().
*/
- limitXmin = snapshot->xmin;
+ limitXmin = snapshot->mvcc.xmin;
PopActiveSnapshot();
UnregisterSnapshot(snapshot);
@@ -4190,7 +4190,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
* We can now do away with our active snapshot, we still need to save
* the xmin limit to wait for older snapshots.
*/
- limitXmin = snapshot->xmin;
+ limitXmin = snapshot->mvcc.xmin;
PopActiveSnapshot();
UnregisterSnapshot(snapshot);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 6b1a00ed477..b2d52f610f5 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -21474,7 +21474,7 @@ ATExecDetachPartitionFinalize(Relation rel, RangeVar *name)
* all such queries are complete (otherwise we would present them with an
* inconsistent view of catalogs).
*/
- WaitForOlderSnapshots(snap->xmin, false);
+ WaitForOlderSnapshots(snap->mvcc.xmin, false);
DetachPartitionFinalize(rel, partRel, true, InvalidOid);
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 0b3a31f1703..44a40416448 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -717,7 +717,7 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index,
int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
IndexScanDesc index_scan;
ScanKeyData scankeys[INDEX_MAX_KEYS];
- SnapshotData DirtySnapshot;
+ DirtySnapshotData DirtySnapshot;
int i;
bool conflict;
bool found_self;
@@ -816,7 +816,7 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index,
retry:
conflict = false;
found_self = false;
- index_scan = index_beginscan(heap, index, &DirtySnapshot, NULL, indnkeyatts, 0);
+ index_scan = index_beginscan(heap, index, (Snapshot) &DirtySnapshot, NULL, indnkeyatts, 0);
index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
while (index_getnext_slot(index_scan, ForwardScanDirection, existing_slot))
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 860f79f9cc1..de01fe57384 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -186,7 +186,7 @@ RelationFindReplTupleByIndex(Relation rel, Oid idxoid,
ScanKeyData skey[INDEX_MAX_KEYS];
int skey_attoff;
IndexScanDesc scan;
- SnapshotData snap;
+ DirtySnapshotData snap;
TransactionId xwait;
Relation idxrel;
bool found;
@@ -204,7 +204,7 @@ RelationFindReplTupleByIndex(Relation rel, Oid idxoid,
skey_attoff = build_replindex_scan_key(skey, rel, idxrel, searchslot);
/* Start an index scan. */
- scan = index_beginscan(rel, idxrel, &snap, NULL, skey_attoff, 0);
+ scan = index_beginscan(rel, idxrel, (Snapshot) &snap, NULL, skey_attoff, 0);
retry:
found = false;
@@ -370,7 +370,7 @@ RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode,
{
TupleTableSlot *scanslot;
TableScanDesc scan;
- SnapshotData snap;
+ DirtySnapshotData snap;
TypeCacheEntry **eq;
TransactionId xwait;
bool found;
@@ -382,7 +382,7 @@ RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode,
/* Start a heap scan. */
InitDirtySnapshot(snap);
- scan = table_beginscan(rel, &snap, 0, NULL);
+ scan = table_beginscan(rel, (Snapshot) &snap, 0, NULL);
scanslot = table_slot_create(rel, NULL);
retry:
diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c
index 985f48fc34d..a4a3e2b0ab1 100644
--- a/src/backend/partitioning/partdesc.c
+++ b/src/backend/partitioning/partdesc.c
@@ -102,7 +102,7 @@ RelationGetPartitionDesc(Relation rel, bool omit_detached)
Assert(TransactionIdIsValid(rel->rd_partdesc_nodetached_xmin));
activesnap = GetActiveSnapshot();
- if (!XidInMVCCSnapshot(rel->rd_partdesc_nodetached_xmin, activesnap))
+ if (!XidInMVCCSnapshot(rel->rd_partdesc_nodetached_xmin, &activesnap->mvcc))
return rel->rd_partdesc_nodetached;
}
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 5e15cb1825e..4730d935bac 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -590,7 +590,7 @@ logicalmsg_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
TransactionId xid = XLogRecGetXid(r);
uint8 info = XLogRecGetInfo(r) & ~XLR_INFO_MASK;
RepOriginId origin_id = XLogRecGetOrigin(r);
- Snapshot snapshot = NULL;
+ HistoricMVCCSnapshot snapshot = NULL;
xl_logical_message *message;
if (info != XLOG_LOGICAL_MESSAGE)
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 2380f369578..2d3ee773f9d 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -260,7 +260,7 @@ replorigin_create(const char *roname)
HeapTuple tuple = NULL;
Relation rel;
Datum roname_d;
- SnapshotData SnapshotDirty;
+ DirtySnapshotData SnapshotDirty;
SysScanDesc scan;
ScanKeyData key;
@@ -325,7 +325,7 @@ replorigin_create(const char *roname)
scan = systable_beginscan(rel, ReplicationOriginIdentIndex,
true /* indexOK */ ,
- &SnapshotDirty,
+ (Snapshot) &SnapshotDirty,
1, &key);
collides = HeapTupleIsValid(systable_getnext(scan));
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index f18c6fb52b5..4d522787129 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -280,9 +280,9 @@ static void ReorderBufferSerializedPath(char *path, ReplicationSlot *slot,
TransactionId xid, XLogSegNo segno);
static int ReorderBufferTXNSizeCompare(const pairingheap_node *a, const pairingheap_node *b, void *arg);
-static void ReorderBufferFreeSnap(ReorderBuffer *rb, Snapshot snap);
-static Snapshot ReorderBufferCopySnap(ReorderBuffer *rb, Snapshot orig_snap,
- ReorderBufferTXN *txn, CommandId cid);
+static void ReorderBufferFreeSnap(ReorderBuffer *rb, HistoricMVCCSnapshot snap);
+static HistoricMVCCSnapshot ReorderBufferCopySnap(ReorderBuffer *rb, HistoricMVCCSnapshot orig_snap,
+ ReorderBufferTXN *txn, CommandId cid);
/*
* ---------------------------------------
@@ -871,7 +871,7 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
*/
void
ReorderBufferQueueMessage(ReorderBuffer *rb, TransactionId xid,
- Snapshot snap, XLogRecPtr lsn,
+ HistoricMVCCSnapshot snap, XLogRecPtr lsn,
bool transactional, const char *prefix,
Size message_size, const char *message)
{
@@ -905,7 +905,7 @@ ReorderBufferQueueMessage(ReorderBuffer *rb, TransactionId xid,
else
{
ReorderBufferTXN *txn = NULL;
- volatile Snapshot snapshot_now = snap;
+ volatile HistoricMVCCSnapshot snapshot_now = snap;
/* Non-transactional changes require a valid snapshot. */
Assert(snapshot_now);
@@ -1905,55 +1905,55 @@ ReorderBufferBuildTupleCidHash(ReorderBuffer *rb, ReorderBufferTXN *txn)
* that catalog modifying transactions can look into intermediate catalog
* states.
*/
-static Snapshot
-ReorderBufferCopySnap(ReorderBuffer *rb, Snapshot orig_snap,
+static HistoricMVCCSnapshot
+ReorderBufferCopySnap(ReorderBuffer *rb, HistoricMVCCSnapshot orig_snap,
ReorderBufferTXN *txn, CommandId cid)
{
- Snapshot snap;
+ HistoricMVCCSnapshot snap;
dlist_iter iter;
int i = 0;
Size size;
- size = sizeof(SnapshotData) +
+ size = sizeof(HistoricMVCCSnapshotData) +
sizeof(TransactionId) * orig_snap->xcnt +
sizeof(TransactionId) * (txn->nsubtxns + 1);
snap = MemoryContextAllocZero(rb->context, size);
- memcpy(snap, orig_snap, sizeof(SnapshotData));
+ memcpy(snap, orig_snap, sizeof(HistoricMVCCSnapshotData));
snap->copied = true;
- snap->active_count = 1; /* mark as active so nobody frees it */
+ snap->refcount = 1; /* mark as active so nobody frees it */
snap->regd_count = 0;
- snap->xip = (TransactionId *) (snap + 1);
+ snap->committed_xids = (TransactionId *) (snap + 1);
- memcpy(snap->xip, orig_snap->xip, sizeof(TransactionId) * snap->xcnt);
+ memcpy(snap->committed_xids, orig_snap->committed_xids, sizeof(TransactionId) * snap->xcnt);
/*
- * snap->subxip contains all txids that belong to our transaction which we
+ * snap->curxip contains all txids that belong to our transaction which we
* need to check via cmin/cmax. That's why we store the toplevel
* transaction in there as well.
*/
- snap->subxip = snap->xip + snap->xcnt;
- snap->subxip[i++] = txn->xid;
+ snap->curxip = snap->committed_xids + snap->xcnt;
+ snap->curxip[i++] = txn->xid;
/*
* txn->nsubtxns isn't decreased when subtransactions abort, so count
* manually. Since it's an upper boundary it is safe to use it for the
* allocation above.
*/
- snap->subxcnt = 1;
+ snap->curxcnt = 1;
dlist_foreach(iter, &txn->subtxns)
{
ReorderBufferTXN *sub_txn;
sub_txn = dlist_container(ReorderBufferTXN, node, iter.cur);
- snap->subxip[i++] = sub_txn->xid;
- snap->subxcnt++;
+ snap->curxip[i++] = sub_txn->xid;
+ snap->curxcnt++;
}
/* sort so we can bsearch() later */
- qsort(snap->subxip, snap->subxcnt, sizeof(TransactionId), xidComparator);
+ qsort(snap->curxip, snap->curxcnt, sizeof(TransactionId), xidComparator);
/* store the specified current CommandId */
snap->curcid = cid;
@@ -1965,7 +1965,7 @@ ReorderBufferCopySnap(ReorderBuffer *rb, Snapshot orig_snap,
* Free a previously ReorderBufferCopySnap'ed snapshot
*/
static void
-ReorderBufferFreeSnap(ReorderBuffer *rb, Snapshot snap)
+ReorderBufferFreeSnap(ReorderBuffer *rb, HistoricMVCCSnapshot snap)
{
if (snap->copied)
pfree(snap);
@@ -2118,7 +2118,7 @@ ReorderBufferApplyMessage(ReorderBuffer *rb, ReorderBufferTXN *txn,
*/
static inline void
ReorderBufferSaveTXNSnapshot(ReorderBuffer *rb, ReorderBufferTXN *txn,
- Snapshot snapshot_now, CommandId command_id)
+ HistoricMVCCSnapshot snapshot_now, CommandId command_id)
{
txn->command_id = command_id;
@@ -2163,7 +2163,7 @@ ReorderBufferMaybeMarkTXNStreamed(ReorderBuffer *rb, ReorderBufferTXN *txn)
*/
static void
ReorderBufferResetTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
- Snapshot snapshot_now,
+ HistoricMVCCSnapshot snapshot_now,
CommandId command_id,
XLogRecPtr last_lsn,
ReorderBufferChange *specinsert)
@@ -2210,7 +2210,7 @@ ReorderBufferResetTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
static void
ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
XLogRecPtr commit_lsn,
- volatile Snapshot snapshot_now,
+ volatile HistoricMVCCSnapshot snapshot_now,
volatile CommandId command_id,
bool streaming)
{
@@ -2826,7 +2826,7 @@ ReorderBufferReplay(ReorderBufferTXN *txn,
TimestampTz commit_time,
RepOriginId origin_id, XLogRecPtr origin_lsn)
{
- Snapshot snapshot_now;
+ HistoricMVCCSnapshot snapshot_now;
CommandId command_id = FirstCommandId;
txn->final_lsn = commit_lsn;
@@ -3306,7 +3306,7 @@ ReorderBufferProcessXid(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn)
*/
void
ReorderBufferAddSnapshot(ReorderBuffer *rb, TransactionId xid,
- XLogRecPtr lsn, Snapshot snap)
+ XLogRecPtr lsn, HistoricMVCCSnapshot snap)
{
ReorderBufferChange *change = ReorderBufferAllocChange(rb);
@@ -3324,7 +3324,7 @@ ReorderBufferAddSnapshot(ReorderBuffer *rb, TransactionId xid,
*/
void
ReorderBufferSetBaseSnapshot(ReorderBuffer *rb, TransactionId xid,
- XLogRecPtr lsn, Snapshot snap)
+ XLogRecPtr lsn, HistoricMVCCSnapshot snap)
{
ReorderBufferTXN *txn;
bool is_new;
@@ -4207,14 +4207,14 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
}
case REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:
{
- Snapshot snap;
+ HistoricMVCCSnapshot snap;
char *data;
snap = change->data.snapshot;
- sz += sizeof(SnapshotData) +
+ sz += sizeof(HistoricMVCCSnapshotData) +
sizeof(TransactionId) * snap->xcnt +
- sizeof(TransactionId) * snap->subxcnt;
+ sizeof(TransactionId) * snap->curxcnt;
/* make sure we have enough space */
ReorderBufferSerializeReserve(rb, sz);
@@ -4222,21 +4222,21 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
/* might have been reallocated above */
ondisk = (ReorderBufferDiskChange *) rb->outbuf;
- memcpy(data, snap, sizeof(SnapshotData));
- data += sizeof(SnapshotData);
+ memcpy(data, snap, sizeof(HistoricMVCCSnapshotData));
+ data += sizeof(HistoricMVCCSnapshotData);
if (snap->xcnt)
{
- memcpy(data, snap->xip,
+ memcpy(data, snap->committed_xids,
sizeof(TransactionId) * snap->xcnt);
data += sizeof(TransactionId) * snap->xcnt;
}
- if (snap->subxcnt)
+ if (snap->curxcnt)
{
- memcpy(data, snap->subxip,
- sizeof(TransactionId) * snap->subxcnt);
- data += sizeof(TransactionId) * snap->subxcnt;
+ memcpy(data, snap->curxip,
+ sizeof(TransactionId) * snap->curxcnt);
+ data += sizeof(TransactionId) * snap->curxcnt;
}
break;
}
@@ -4341,7 +4341,7 @@ ReorderBufferCanStartStreaming(ReorderBuffer *rb)
static void
ReorderBufferStreamTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
{
- Snapshot snapshot_now;
+ HistoricMVCCSnapshot snapshot_now;
CommandId command_id;
Size stream_bytes;
bool txn_is_streamed;
@@ -4360,10 +4360,10 @@ ReorderBufferStreamTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
* After that we need to reuse the snapshot from the previous run.
*
* Unlike DecodeCommit which adds xids of all the subtransactions in
- * snapshot's xip array via SnapBuildCommitTxn, we can't do that here but
- * we do add them to subxip array instead via ReorderBufferCopySnap. This
- * allows the catalog changes made in subtransactions decoded till now to
- * be visible.
+ * snapshot's committed_xids array via SnapBuildCommitTxn, we can't do
+ * that here but we do add them to curxip array instead via
+ * ReorderBufferCopySnap. This allows the catalog changes made in
+ * subtransactions decoded till now to be visible.
*/
if (txn->snapshot_now == NULL)
{
@@ -4509,13 +4509,13 @@ ReorderBufferChangeSize(ReorderBufferChange *change)
}
case REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:
{
- Snapshot snap;
+ HistoricMVCCSnapshot snap;
snap = change->data.snapshot;
- sz += sizeof(SnapshotData) +
+ sz += sizeof(HistoricMVCCSnapshotData) +
sizeof(TransactionId) * snap->xcnt +
- sizeof(TransactionId) * snap->subxcnt;
+ sizeof(TransactionId) * snap->curxcnt;
break;
}
@@ -4793,24 +4793,24 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
}
case REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:
{
- Snapshot oldsnap;
- Snapshot newsnap;
+ HistoricMVCCSnapshot oldsnap;
+ HistoricMVCCSnapshot newsnap;
Size size;
- oldsnap = (Snapshot) data;
+ oldsnap = (HistoricMVCCSnapshot) data;
- size = sizeof(SnapshotData) +
+ size = sizeof(HistoricMVCCSnapshotData) +
sizeof(TransactionId) * oldsnap->xcnt +
- sizeof(TransactionId) * (oldsnap->subxcnt + 0);
+ sizeof(TransactionId) * (oldsnap->curxcnt + 0);
change->data.snapshot = MemoryContextAllocZero(rb->context, size);
newsnap = change->data.snapshot;
memcpy(newsnap, data, size);
- newsnap->xip = (TransactionId *)
- (((char *) newsnap) + sizeof(SnapshotData));
- newsnap->subxip = newsnap->xip + newsnap->xcnt;
+ newsnap->committed_xids = (TransactionId *)
+ (((char *) newsnap) + sizeof(HistoricMVCCSnapshotData));
+ newsnap->curxip = newsnap->committed_xids + newsnap->xcnt;
newsnap->copied = true;
break;
}
@@ -5476,7 +5476,7 @@ file_sort_by_lsn(const ListCell *a_p, const ListCell *b_p)
* transaction for relid.
*/
static void
-UpdateLogicalMappings(HTAB *tuplecid_data, Oid relid, Snapshot snapshot)
+UpdateLogicalMappings(HTAB *tuplecid_data, Oid relid, HistoricMVCCSnapshot snapshot)
{
DIR *mapping_dir;
struct dirent *mapping_de;
@@ -5524,7 +5524,7 @@ UpdateLogicalMappings(HTAB *tuplecid_data, Oid relid, Snapshot snapshot)
continue;
/* not for our transaction */
- if (!TransactionIdInArray(f_mapped_xid, snapshot->subxip, snapshot->subxcnt))
+ if (!TransactionIdInArray(f_mapped_xid, snapshot->curxip, snapshot->curxcnt))
continue;
/* ok, relevant, queue for apply */
@@ -5543,7 +5543,7 @@ UpdateLogicalMappings(HTAB *tuplecid_data, Oid relid, Snapshot snapshot)
RewriteMappingFile *f = (RewriteMappingFile *) lfirst(file);
elog(DEBUG1, "applying mapping: \"%s\" in %u", f->fname,
- snapshot->subxip[0]);
+ snapshot->curxip[0]);
ApplyLogicalMappingFile(tuplecid_data, relid, f->fname);
pfree(f);
}
@@ -5555,7 +5555,7 @@ UpdateLogicalMappings(HTAB *tuplecid_data, Oid relid, Snapshot snapshot)
*/
bool
ResolveCminCmaxDuringDecoding(HTAB *tuplecid_data,
- Snapshot snapshot,
+ HistoricMVCCSnapshot snapshot,
HeapTuple htup, Buffer buffer,
CommandId *cmin, CommandId *cmax)
{
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index d6ab1e017eb..80f4b620520 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -155,11 +155,11 @@ static bool ExportInProgress = false;
static void SnapBuildPurgeOlderTxn(SnapBuild *builder);
/* snapshot building/manipulation/distribution functions */
-static Snapshot SnapBuildBuildSnapshot(SnapBuild *builder);
+static HistoricMVCCSnapshot SnapBuildBuildSnapshot(SnapBuild *builder);
-static void SnapBuildFreeSnapshot(Snapshot snap);
+static void SnapBuildFreeSnapshot(HistoricMVCCSnapshot snap);
-static void SnapBuildSnapIncRefcount(Snapshot snap);
+static void SnapBuildSnapIncRefcount(HistoricMVCCSnapshot snap);
static void SnapBuildDistributeSnapshotAndInval(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid);
@@ -249,23 +249,21 @@ FreeSnapshotBuilder(SnapBuild *builder)
* Free an unreferenced snapshot that has previously been built by us.
*/
static void
-SnapBuildFreeSnapshot(Snapshot snap)
+SnapBuildFreeSnapshot(HistoricMVCCSnapshot snap)
{
/* make sure we don't get passed an external snapshot */
Assert(snap->snapshot_type == SNAPSHOT_HISTORIC_MVCC);
/* make sure nobody modified our snapshot */
Assert(snap->curcid == FirstCommandId);
- Assert(!snap->suboverflowed);
- Assert(!snap->takenDuringRecovery);
Assert(snap->regd_count == 0);
/* slightly more likely, so it's checked even without c-asserts */
if (snap->copied)
elog(ERROR, "cannot free a copied snapshot");
- if (snap->active_count)
- elog(ERROR, "cannot free an active snapshot");
+ if (snap->refcount)
+ elog(ERROR, "cannot free a snapshot that's in use");
pfree(snap);
}
@@ -313,9 +311,9 @@ SnapBuildXactNeedsSkip(SnapBuild *builder, XLogRecPtr ptr)
* adding a Snapshot as builder->snapshot.
*/
static void
-SnapBuildSnapIncRefcount(Snapshot snap)
+SnapBuildSnapIncRefcount(HistoricMVCCSnapshot snap)
{
- snap->active_count++;
+ snap->refcount++;
}
/*
@@ -325,26 +323,23 @@ SnapBuildSnapIncRefcount(Snapshot snap)
* IncRef'ed Snapshot can adjust its refcount easily.
*/
void
-SnapBuildSnapDecRefcount(Snapshot snap)
+SnapBuildSnapDecRefcount(HistoricMVCCSnapshot snap)
{
/* make sure we don't get passed an external snapshot */
Assert(snap->snapshot_type == SNAPSHOT_HISTORIC_MVCC);
/* make sure nobody modified our snapshot */
Assert(snap->curcid == FirstCommandId);
- Assert(!snap->suboverflowed);
- Assert(!snap->takenDuringRecovery);
+ Assert(snap->refcount > 0);
Assert(snap->regd_count == 0);
- Assert(snap->active_count > 0);
-
/* slightly more likely, so it's checked even without casserts */
if (snap->copied)
elog(ERROR, "cannot free a copied snapshot");
- snap->active_count--;
- if (snap->active_count == 0)
+ snap->refcount--;
+ if (snap->refcount == 0)
SnapBuildFreeSnapshot(snap);
}
@@ -356,15 +351,15 @@ SnapBuildSnapDecRefcount(Snapshot snap)
* these snapshots; they have to copy them and fill in appropriate ->curcid
* and ->subxip/subxcnt values.
*/
-static Snapshot
+static HistoricMVCCSnapshot
SnapBuildBuildSnapshot(SnapBuild *builder)
{
- Snapshot snapshot;
+ HistoricMVCCSnapshot snapshot;
Size ssize;
Assert(builder->state >= SNAPBUILD_FULL_SNAPSHOT);
- ssize = sizeof(SnapshotData)
+ ssize = sizeof(HistoricMVCCSnapshotData)
+ sizeof(TransactionId) * builder->committed.xcnt
+ sizeof(TransactionId) * 1 /* toplevel xid */ ;
@@ -400,31 +395,28 @@ SnapBuildBuildSnapshot(SnapBuild *builder)
snapshot->xmax = builder->xmax;
/* store all transactions to be treated as committed by this snapshot */
- snapshot->xip =
- (TransactionId *) ((char *) snapshot + sizeof(SnapshotData));
+ snapshot->committed_xids =
+ (TransactionId *) ((char *) snapshot + sizeof(HistoricMVCCSnapshotData));
snapshot->xcnt = builder->committed.xcnt;
- memcpy(snapshot->xip,
+ memcpy(snapshot->committed_xids,
builder->committed.xip,
builder->committed.xcnt * sizeof(TransactionId));
/* sort so we can bsearch() */
- qsort(snapshot->xip, snapshot->xcnt, sizeof(TransactionId), xidComparator);
+ qsort(snapshot->committed_xids, snapshot->xcnt, sizeof(TransactionId), xidComparator);
/*
- * Initially, subxip is empty, i.e. it's a snapshot to be used by
+ * Initially, curxip is empty, i.e. it's a snapshot to be used by
* transactions that don't modify the catalog. Will be filled by
* ReorderBufferCopySnap() if necessary.
*/
- snapshot->subxcnt = 0;
- snapshot->subxip = NULL;
+ snapshot->curxcnt = 0;
+ snapshot->curxip = NULL;
- snapshot->suboverflowed = false;
- snapshot->takenDuringRecovery = false;
snapshot->copied = false;
snapshot->curcid = FirstCommandId;
- snapshot->active_count = 0;
+ snapshot->refcount = 0;
snapshot->regd_count = 0;
- snapshot->snapXactCompletionCount = 0;
return snapshot;
}
@@ -436,13 +428,13 @@ SnapBuildBuildSnapshot(SnapBuild *builder)
* The snapshot will be usable directly in current transaction or exported
* for loading in different transaction.
*/
-Snapshot
+MVCCSnapshot
SnapBuildInitialSnapshot(SnapBuild *builder)
{
- Snapshot snap;
+ HistoricMVCCSnapshot historicsnap;
+ MVCCSnapshot mvccsnap;
TransactionId xid;
TransactionId safeXid;
- TransactionId *newxip;
int newxcnt = 0;
Assert(XactIsoLevel == XACT_REPEATABLE_READ);
@@ -464,10 +456,10 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
if (TransactionIdIsValid(MyProc->xmin))
elog(ERROR, "cannot build an initial slot snapshot when MyProc->xmin already is valid");
- snap = SnapBuildBuildSnapshot(builder);
+ historicsnap = SnapBuildBuildSnapshot(builder);
/*
- * We know that snap->xmin is alive, enforced by the logical xmin
+ * We know that historicsnap->xmin is alive, enforced by the logical xmin
* mechanism. Due to that we can do this without locks, we're only
* changing our own value.
*
@@ -479,14 +471,18 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
safeXid = GetOldestSafeDecodingTransactionId(false);
LWLockRelease(ProcArrayLock);
- if (TransactionIdFollows(safeXid, snap->xmin))
+ if (TransactionIdFollows(safeXid, historicsnap->xmin))
elog(ERROR, "cannot build an initial slot snapshot as oldest safe xid %u follows snapshot's xmin %u",
- safeXid, snap->xmin);
+ safeXid, historicsnap->xmin);
- MyProc->xmin = snap->xmin;
+ MyProc->xmin = historicsnap->xmin;
/* allocate in transaction context */
- newxip = palloc_array(TransactionId, GetMaxSnapshotXidCount());
+ mvccsnap = palloc(sizeof(MVCCSnapshotData) + sizeof(TransactionId) * GetMaxSnapshotXidCount());
+ mvccsnap->snapshot_type = SNAPSHOT_MVCC;
+ mvccsnap->xmin = historicsnap->xmin;
+ mvccsnap->xmax = historicsnap->xmax;
+ mvccsnap->xip = (TransactionId *) ((char *) mvccsnap + sizeof(MVCCSnapshotData));
/*
* snapbuild.c builds transactions in an "inverted" manner, which means it
@@ -494,15 +490,15 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
* classical snapshot by marking all non-committed transactions as
* in-progress. This can be expensive.
*/
- for (xid = snap->xmin; NormalTransactionIdPrecedes(xid, snap->xmax);)
+ for (xid = historicsnap->xmin; NormalTransactionIdPrecedes(xid, historicsnap->xmax);)
{
void *test;
/*
- * Check whether transaction committed using the decoding snapshot
- * meaning of ->xip.
+ * Check whether transaction committed using the decoding snapshot's
+ * committed_xids array.
*/
- test = bsearch(&xid, snap->xip, snap->xcnt,
+ test = bsearch(&xid, historicsnap->committed_xids, historicsnap->xcnt,
sizeof(TransactionId), xidComparator);
if (test == NULL)
@@ -512,18 +508,27 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("initial slot snapshot too large")));
- newxip[newxcnt++] = xid;
+ mvccsnap->xip[newxcnt++] = xid;
}
TransactionIdAdvance(xid);
}
-
- /* adjust remaining snapshot fields as needed */
- snap->snapshot_type = SNAPSHOT_MVCC;
- snap->xcnt = newxcnt;
- snap->xip = newxip;
-
- return snap;
+ mvccsnap->xcnt = newxcnt;
+
+ /* Initialize remaining MVCCSnapshot fields */
+ mvccsnap->subxip = NULL;
+ mvccsnap->subxcnt = 0;
+ mvccsnap->suboverflowed = false;
+ mvccsnap->takenDuringRecovery = false;
+ mvccsnap->copied = true;
+ mvccsnap->curcid = FirstCommandId;
+ mvccsnap->active_count = 0;
+ mvccsnap->regd_count = 0;
+ mvccsnap->snapXactCompletionCount = 0;
+
+ pfree(historicsnap);
+
+ return mvccsnap;
}
/*
@@ -537,7 +542,7 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
const char *
SnapBuildExportSnapshot(SnapBuild *builder)
{
- Snapshot snap;
+ MVCCSnapshot snap;
char *snapname;
if (IsTransactionOrTransactionBlock())
@@ -574,7 +579,7 @@ SnapBuildExportSnapshot(SnapBuild *builder)
/*
* Ensure there is a snapshot and if not build one for current transaction.
*/
-Snapshot
+HistoricMVCCSnapshot
SnapBuildGetOrBuildSnapshot(SnapBuild *builder)
{
Assert(builder->state == SNAPBUILD_CONSISTENT);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 449632ad1aa..ac8a9d33323 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1329,7 +1329,7 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
}
else if (snapshot_action == CRS_USE_SNAPSHOT)
{
- Snapshot snap;
+ MVCCSnapshot snap;
snap = SnapBuildInitialSnapshot(ctx->snapshot_builder);
RestoreTransactionSnapshot(snap, MyProc);
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index f3a1603204e..2292d8a09af 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2040,7 +2040,7 @@ GetMaxSnapshotSubxidCount(void)
* least in the case we already hold a snapshot), but that's for another day.
*/
static bool
-GetSnapshotDataReuse(Snapshot snapshot)
+GetSnapshotDataReuse(MVCCSnapshot snapshot)
{
uint64 curXactCompletionCount;
@@ -2119,8 +2119,8 @@ GetSnapshotDataReuse(Snapshot snapshot)
* Note: this function should probably not be called with an argument that's
* not statically allocated (see xip allocation below).
*/
-Snapshot
-GetSnapshotData(Snapshot snapshot)
+MVCCSnapshot
+GetSnapshotData(MVCCSnapshot snapshot)
{
ProcArrayStruct *arrayP = procArray;
TransactionId *other_xids = ProcGlobal->xids;
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 149c69a1873..8d97127668c 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -449,10 +449,10 @@ static void SerialSetActiveSerXmin(TransactionId xid);
static uint32 predicatelock_hash(const void *key, Size keysize);
static void SummarizeOldestCommittedSxact(void);
-static Snapshot GetSafeSnapshot(Snapshot origSnapshot);
-static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot,
- VirtualTransactionId *sourcevxid,
- int sourcepid);
+static MVCCSnapshot GetSafeSnapshot(MVCCSnapshot origSnapshot);
+static MVCCSnapshot GetSerializableTransactionSnapshotInt(MVCCSnapshot snapshot,
+ VirtualTransactionId *sourcevxid,
+ int sourcepid);
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag);
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag,
PREDICATELOCKTARGETTAG *parent);
@@ -1552,10 +1552,10 @@ SummarizeOldestCommittedSxact(void)
* for), the passed-in Snapshot pointer should reference a static data
* area that can safely be passed to GetSnapshotData.
*/
-static Snapshot
-GetSafeSnapshot(Snapshot origSnapshot)
+static MVCCSnapshot
+GetSafeSnapshot(MVCCSnapshot origSnapshot)
{
- Snapshot snapshot;
+ MVCCSnapshot snapshot;
Assert(XactReadOnly && XactDeferrable);
@@ -1676,8 +1676,8 @@ GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
* always this same pointer; no new snapshot data structure is allocated
* within this function.
*/
-Snapshot
-GetSerializableTransactionSnapshot(Snapshot snapshot)
+MVCCSnapshot
+GetSerializableTransactionSnapshot(MVCCSnapshot snapshot)
{
Assert(IsolationIsSerializable());
@@ -1717,7 +1717,7 @@ GetSerializableTransactionSnapshot(Snapshot snapshot)
* read-only.
*/
void
-SetSerializableTransactionSnapshot(Snapshot snapshot,
+SetSerializableTransactionSnapshot(MVCCSnapshot snapshot,
VirtualTransactionId *sourcevxid,
int sourcepid)
{
@@ -1758,8 +1758,8 @@ SetSerializableTransactionSnapshot(Snapshot snapshot,
* source xact is still running after we acquire SerializableXactHashLock.
* We do that by calling ProcArrayInstallImportedXmin.
*/
-static Snapshot
-GetSerializableTransactionSnapshotInt(Snapshot snapshot,
+static MVCCSnapshot
+GetSerializableTransactionSnapshotInt(MVCCSnapshot snapshot,
VirtualTransactionId *sourcevxid,
int sourcepid)
{
@@ -3969,12 +3969,12 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
static bool
XidIsConcurrent(TransactionId xid)
{
- Snapshot snap;
+ MVCCSnapshot snap;
Assert(TransactionIdIsValid(xid));
Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
- snap = GetTransactionSnapshot();
+ snap = (MVCCSnapshot) GetTransactionSnapshot();
if (TransactionIdPrecedes(xid, snap->xmin))
return false;
@@ -4222,7 +4222,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
}
else if (!SxactIsDoomed(sxact)
&& (!SxactIsCommitted(sxact)
- || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
+ || TransactionIdPrecedes(TransactionXmin,
sxact->finishedBefore))
&& !RWConflictExists(sxact, MySerializableXact))
{
@@ -4235,7 +4235,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
*/
if (!SxactIsDoomed(sxact)
&& (!SxactIsCommitted(sxact)
- || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
+ || TransactionIdPrecedes(TransactionXmin,
sxact->finishedBefore))
&& !RWConflictExists(sxact, MySerializableXact))
{
diff --git a/src/backend/utils/adt/xid8funcs.c b/src/backend/utils/adt/xid8funcs.c
index 4b3f7a69b3b..0407d16fe12 100644
--- a/src/backend/utils/adt/xid8funcs.c
+++ b/src/backend/utils/adt/xid8funcs.c
@@ -373,10 +373,10 @@ pg_current_snapshot(PG_FUNCTION_ARGS)
pg_snapshot *snap;
uint32 nxip,
i;
- Snapshot cur;
+ MVCCSnapshot cur;
FullTransactionId next_fxid = ReadNextFullTransactionId();
- cur = GetActiveSnapshot();
+ cur = (MVCCSnapshot) GetActiveSnapshot();
if (cur == NULL)
elog(ERROR, "no active snapshot set");
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 5af8326d5e8..85395f0a8df 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -138,18 +138,18 @@
* These SnapshotData structs are static to simplify memory allocation
* (see the hack in GetSnapshotData to avoid repeated malloc/free).
*/
-static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC};
-static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC};
-static SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC};
+static MVCCSnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC};
+static MVCCSnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC};
+static MVCCSnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC};
SnapshotData SnapshotSelfData = {SNAPSHOT_SELF};
SnapshotData SnapshotAnyData = {SNAPSHOT_ANY};
SnapshotData SnapshotToastData = {SNAPSHOT_TOAST};
/* Pointers to valid snapshots */
-static Snapshot CurrentSnapshot = NULL;
-static Snapshot SecondarySnapshot = NULL;
-static Snapshot CatalogSnapshot = NULL;
-static Snapshot HistoricSnapshot = NULL;
+static MVCCSnapshot CurrentSnapshot = NULL;
+static MVCCSnapshot SecondarySnapshot = NULL;
+static MVCCSnapshot CatalogSnapshot = NULL;
+static HistoricMVCCSnapshot HistoricSnapshot = NULL;
/*
* These are updated by GetSnapshotData. We initialize them this way
@@ -172,7 +172,7 @@ static HTAB *tuplecid_data = NULL;
*/
typedef struct ActiveSnapshotElt
{
- Snapshot as_snap;
+ MVCCSnapshot as_snap;
int as_level;
struct ActiveSnapshotElt *as_next;
} ActiveSnapshotElt;
@@ -197,7 +197,7 @@ bool FirstSnapshotSet = false;
* FirstSnapshotSet in combination with IsolationUsesXactSnapshot(), because
* GUC may be reset before us, changing the value of IsolationUsesXactSnapshot.
*/
-static Snapshot FirstXactSnapshot = NULL;
+static MVCCSnapshot FirstXactSnapshot = NULL;
/* Define pathname of exported-snapshot files */
#define SNAPSHOT_EXPORT_DIR "pg_snapshots"
@@ -206,16 +206,16 @@ static Snapshot FirstXactSnapshot = NULL;
typedef struct ExportedSnapshot
{
char *snapfile;
- Snapshot snapshot;
+ MVCCSnapshot snapshot;
} ExportedSnapshot;
/* Current xact's exported snapshots (a list of ExportedSnapshot structs) */
static List *exportedSnapshots = NIL;
/* Prototypes for local functions */
-static Snapshot CopySnapshot(Snapshot snapshot);
+static MVCCSnapshot CopyMVCCSnapshot(MVCCSnapshot snapshot);
static void UnregisterSnapshotNoOwner(Snapshot snapshot);
-static void FreeSnapshot(Snapshot snapshot);
+static void FreeMVCCSnapshot(MVCCSnapshot snapshot);
static void SnapshotResetXmin(void);
/* ResourceOwner callbacks to track snapshot references */
@@ -287,7 +287,7 @@ GetTransactionSnapshot(void)
* for later calls to GetTransactionSnapshot().
*/
Assert(!FirstSnapshotSet);
- return HistoricSnapshot;
+ return (Snapshot) HistoricSnapshot;
}
/* First call in transaction? */
@@ -320,8 +320,9 @@ GetTransactionSnapshot(void)
CurrentSnapshot = GetSerializableTransactionSnapshot(&CurrentSnapshotData);
else
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
+
/* Make a saved copy */
- CurrentSnapshot = CopySnapshot(CurrentSnapshot);
+ CurrentSnapshot = CopyMVCCSnapshot(CurrentSnapshot);
FirstXactSnapshot = CurrentSnapshot;
/* Mark it as "registered" in FirstXactSnapshot */
FirstXactSnapshot->regd_count++;
@@ -331,18 +332,18 @@ GetTransactionSnapshot(void)
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
FirstSnapshotSet = true;
- return CurrentSnapshot;
+ return (Snapshot) CurrentSnapshot;
}
if (IsolationUsesXactSnapshot())
- return CurrentSnapshot;
+ return (Snapshot) CurrentSnapshot;
/* Don't allow catalog snapshot to be older than xact snapshot. */
InvalidateCatalogSnapshot();
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
- return CurrentSnapshot;
+ return (Snapshot) CurrentSnapshot;
}
/*
@@ -373,7 +374,7 @@ GetLatestSnapshot(void)
SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData);
- return SecondarySnapshot;
+ return (Snapshot) SecondarySnapshot;
}
/*
@@ -392,7 +393,7 @@ GetCatalogSnapshot(Oid relid)
* finishing decoding.
*/
if (HistoricSnapshotActive())
- return HistoricSnapshot;
+ return (Snapshot) HistoricSnapshot;
return GetNonHistoricCatalogSnapshot(relid);
}
@@ -438,7 +439,7 @@ GetNonHistoricCatalogSnapshot(Oid relid)
pairingheap_add(&RegisteredSnapshots, &CatalogSnapshot->ph_node);
}
- return CatalogSnapshot;
+ return (Snapshot) CatalogSnapshot;
}
/*
@@ -508,7 +509,7 @@ SnapshotSetCommandId(CommandId curcid)
* in GetTransactionSnapshot.
*/
static void
-SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid,
+SetTransactionSnapshot(MVCCSnapshot sourcesnap, VirtualTransactionId *sourcevxid,
int sourcepid, PGPROC *sourceproc)
{
/* Caller should have checked this already */
@@ -587,7 +588,7 @@ SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid,
SetSerializableTransactionSnapshot(CurrentSnapshot, sourcevxid,
sourcepid);
/* Make a saved copy */
- CurrentSnapshot = CopySnapshot(CurrentSnapshot);
+ CurrentSnapshot = CopyMVCCSnapshot(CurrentSnapshot);
FirstXactSnapshot = CurrentSnapshot;
/* Mark it as "registered" in FirstXactSnapshot */
FirstXactSnapshot->regd_count++;
@@ -598,29 +599,27 @@ SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid,
}
/*
- * CopySnapshot
+ * CopyMVCCSnapshot
* Copy the given snapshot.
*
* The copy is palloc'd in TopTransactionContext and has initial refcounts set
* to 0. The returned snapshot has the copied flag set.
*/
-static Snapshot
-CopySnapshot(Snapshot snapshot)
+static MVCCSnapshot
+CopyMVCCSnapshot(MVCCSnapshot snapshot)
{
- Snapshot newsnap;
+ MVCCSnapshot newsnap;
Size subxipoff;
Size size;
- Assert(snapshot != InvalidSnapshot);
-
/* We allocate any XID arrays needed in the same palloc block. */
- size = subxipoff = sizeof(SnapshotData) +
+ size = subxipoff = sizeof(MVCCSnapshotData) +
snapshot->xcnt * sizeof(TransactionId);
if (snapshot->subxcnt > 0)
size += snapshot->subxcnt * sizeof(TransactionId);
- newsnap = (Snapshot) MemoryContextAlloc(TopTransactionContext, size);
- memcpy(newsnap, snapshot, sizeof(SnapshotData));
+ newsnap = (MVCCSnapshot) MemoryContextAlloc(TopTransactionContext, size);
+ memcpy(newsnap, snapshot, sizeof(MVCCSnapshotData));
newsnap->regd_count = 0;
newsnap->active_count = 0;
@@ -657,11 +656,11 @@ CopySnapshot(Snapshot snapshot)
}
/*
- * FreeSnapshot
+ * FreeMVCCSnapshot
* Free the memory associated with a snapshot.
*/
static void
-FreeSnapshot(Snapshot snapshot)
+FreeMVCCSnapshot(MVCCSnapshot snapshot)
{
Assert(snapshot->regd_count == 0);
Assert(snapshot->active_count == 0);
@@ -677,6 +676,8 @@ FreeSnapshot(Snapshot snapshot)
* If the passed snapshot is a statically-allocated one, or it is possibly
* subject to a future command counter update, create a new long-lived copy
* with active refcount=1. Otherwise, only increment the refcount.
+ *
+ * Only regular MVCC snaphots can be used as the active snapshot.
*/
void
PushActiveSnapshot(Snapshot snapshot)
@@ -695,9 +696,12 @@ PushActiveSnapshot(Snapshot snapshot)
void
PushActiveSnapshotWithLevel(Snapshot snapshot, int snap_level)
{
+ MVCCSnapshot origsnap;
ActiveSnapshotElt *newactive;
- Assert(snapshot != InvalidSnapshot);
+ Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
+ origsnap = &snapshot->mvcc;
+
Assert(ActiveSnapshot == NULL || snap_level >= ActiveSnapshot->as_level);
newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt));
@@ -706,11 +710,11 @@ PushActiveSnapshotWithLevel(Snapshot snapshot, int snap_level)
* Checking SecondarySnapshot is probably useless here, but it seems
* better to be sure.
*/
- if (snapshot == CurrentSnapshot || snapshot == SecondarySnapshot ||
- !snapshot->copied)
- newactive->as_snap = CopySnapshot(snapshot);
+ if (origsnap == CurrentSnapshot || origsnap == SecondarySnapshot ||
+ !origsnap->copied)
+ newactive->as_snap = CopyMVCCSnapshot(origsnap);
else
- newactive->as_snap = snapshot;
+ newactive->as_snap = origsnap;
newactive->as_next = ActiveSnapshot;
newactive->as_level = snap_level;
@@ -731,7 +735,8 @@ PushActiveSnapshotWithLevel(Snapshot snapshot, int snap_level)
void
PushCopiedSnapshot(Snapshot snapshot)
{
- PushActiveSnapshot(CopySnapshot(snapshot));
+ Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
+ PushActiveSnapshot((Snapshot) CopyMVCCSnapshot(&snapshot->mvcc));
}
/*
@@ -784,7 +789,7 @@ PopActiveSnapshot(void)
if (ActiveSnapshot->as_snap->active_count == 0 &&
ActiveSnapshot->as_snap->regd_count == 0)
- FreeSnapshot(ActiveSnapshot->as_snap);
+ FreeMVCCSnapshot(ActiveSnapshot->as_snap);
pfree(ActiveSnapshot);
ActiveSnapshot = newstack;
@@ -801,7 +806,7 @@ GetActiveSnapshot(void)
{
Assert(ActiveSnapshot != NULL);
- return ActiveSnapshot->as_snap;
+ return (Snapshot) ActiveSnapshot->as_snap;
}
/*
@@ -818,7 +823,8 @@ ActiveSnapshotSet(void)
* RegisterSnapshot
* Register a snapshot as being in use by the current resource owner
*
- * If InvalidSnapshot is passed, it is not registered.
+ * Only regular MVCC snaphots and "historic" MVCC snapshots can be registered.
+ * InvalidSnapshot is also accepted, as a no-op.
*/
Snapshot
RegisterSnapshot(Snapshot snapshot)
@@ -834,25 +840,39 @@ RegisterSnapshot(Snapshot snapshot)
* As above, but use the specified resource owner
*/
Snapshot
-RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner)
+RegisterSnapshotOnOwner(Snapshot orig_snapshot, ResourceOwner owner)
{
- Snapshot snap;
+ MVCCSnapshot snapshot;
- if (snapshot == InvalidSnapshot)
+ if (orig_snapshot == InvalidSnapshot)
return InvalidSnapshot;
+ if (orig_snapshot->snapshot_type == SNAPSHOT_HISTORIC_MVCC)
+ {
+ HistoricMVCCSnapshot historicsnap = &orig_snapshot->historic_mvcc;
+
+ ResourceOwnerEnlarge(owner);
+ historicsnap->regd_count++;
+ ResourceOwnerRememberSnapshot(owner, (Snapshot) historicsnap);
+
+ return (Snapshot) historicsnap;
+ }
+
+ Assert(orig_snapshot->snapshot_type == SNAPSHOT_MVCC);
+ snapshot = &orig_snapshot->mvcc;
+
/* Static snapshot? Create a persistent copy */
- snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
+ snapshot = snapshot->copied ? snapshot : CopyMVCCSnapshot(snapshot);
/* and tell resowner.c about it */
ResourceOwnerEnlarge(owner);
- snap->regd_count++;
- ResourceOwnerRememberSnapshot(owner, snap);
+ snapshot->regd_count++;
+ ResourceOwnerRememberSnapshot(owner, (Snapshot) snapshot);
- if (snap->regd_count == 1)
- pairingheap_add(&RegisteredSnapshots, &snap->ph_node);
+ if (snapshot->regd_count == 1)
+ pairingheap_add(&RegisteredSnapshots, &snapshot->ph_node);
- return snap;
+ return (Snapshot) snapshot;
}
/*
@@ -888,18 +908,41 @@ UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
static void
UnregisterSnapshotNoOwner(Snapshot snapshot)
{
- Assert(snapshot->regd_count > 0);
- Assert(!pairingheap_is_empty(&RegisteredSnapshots));
+ if (snapshot->snapshot_type == SNAPSHOT_MVCC)
+ {
+ MVCCSnapshot mvccsnap = &snapshot->mvcc;
+
+ Assert(mvccsnap->regd_count > 0);
+ Assert(!pairingheap_is_empty(&RegisteredSnapshots));
- snapshot->regd_count--;
- if (snapshot->regd_count == 0)
- pairingheap_remove(&RegisteredSnapshots, &snapshot->ph_node);
+ mvccsnap->regd_count--;
+ if (mvccsnap->regd_count == 0)
+ pairingheap_remove(&RegisteredSnapshots, &mvccsnap->ph_node);
- if (snapshot->regd_count == 0 && snapshot->active_count == 0)
+ if (mvccsnap->regd_count == 0 && mvccsnap->active_count == 0)
+ {
+ FreeMVCCSnapshot(mvccsnap);
+ SnapshotResetXmin();
+ }
+ }
+ else if (snapshot->snapshot_type == SNAPSHOT_HISTORIC_MVCC)
{
- FreeSnapshot(snapshot);
- SnapshotResetXmin();
+ HistoricMVCCSnapshot historicsnap = &snapshot->historic_mvcc;
+
+ /*
+ * Historic snapshots don't rely on the resource owner machinery for
+ * cleanup, the snapbuild.c machinery ensures that whenever a historic
+ * snapshot is in use, it has a non-zero refcount. Registration is
+ * only supported so that the callers don't need to treat regular MVCC
+ * catalog snapshots and historic snapshots differently.
+ */
+ Assert(historicsnap->refcount > 0);
+
+ Assert(historicsnap->regd_count > 0);
+ historicsnap->regd_count--;
}
+ else
+ elog(ERROR, "registered snapshot has unexpected type");
}
/*
@@ -909,8 +952,8 @@ UnregisterSnapshotNoOwner(Snapshot snapshot)
static int
xmin_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
{
- const SnapshotData *asnap = pairingheap_const_container(SnapshotData, ph_node, a);
- const SnapshotData *bsnap = pairingheap_const_container(SnapshotData, ph_node, b);
+ const MVCCSnapshotData *asnap = pairingheap_const_container(MVCCSnapshotData, ph_node, a);
+ const MVCCSnapshotData *bsnap = pairingheap_const_container(MVCCSnapshotData, ph_node, b);
if (TransactionIdPrecedes(asnap->xmin, bsnap->xmin))
return 1;
@@ -936,7 +979,7 @@ xmin_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
static void
SnapshotResetXmin(void)
{
- Snapshot minSnapshot;
+ MVCCSnapshot minSnapshot;
if (ActiveSnapshot != NULL)
return;
@@ -947,7 +990,7 @@ SnapshotResetXmin(void)
return;
}
- minSnapshot = pairingheap_container(SnapshotData, ph_node,
+ minSnapshot = pairingheap_container(MVCCSnapshotData, ph_node,
pairingheap_first(&RegisteredSnapshots));
if (TransactionIdPrecedes(MyProc->xmin, minSnapshot->xmin))
@@ -997,7 +1040,7 @@ AtSubAbort_Snapshot(int level)
if (ActiveSnapshot->as_snap->active_count == 0 &&
ActiveSnapshot->as_snap->regd_count == 0)
- FreeSnapshot(ActiveSnapshot->as_snap);
+ FreeMVCCSnapshot(ActiveSnapshot->as_snap);
/* and free the stack element */
pfree(ActiveSnapshot);
@@ -1019,7 +1062,7 @@ AtEOXact_Snapshot(bool isCommit, bool resetXmin)
* In transaction-snapshot mode we must release our privately-managed
* reference to the transaction snapshot. We must remove it from
* RegisteredSnapshots to keep the check below happy. But we don't bother
- * to do FreeSnapshot, for two reasons: the memory will go away with
+ * to do FreeMVCCSnapshot, for two reasons: the memory will go away with
* TopTransactionContext anyway, and if someone has left the snapshot
* stacked as active, we don't want the code below to be chasing through a
* dangling pointer.
@@ -1112,7 +1155,7 @@ AtEOXact_Snapshot(bool isCommit, bool resetXmin)
* snapshot.
*/
char *
-ExportSnapshot(Snapshot snapshot)
+ExportSnapshot(MVCCSnapshot snapshot)
{
TransactionId topXid;
TransactionId *children;
@@ -1176,7 +1219,7 @@ ExportSnapshot(Snapshot snapshot)
* ensure that the snapshot's xmin is honored for the rest of the
* transaction.
*/
- snapshot = CopySnapshot(snapshot);
+ snapshot = CopyMVCCSnapshot(snapshot);
oldcxt = MemoryContextSwitchTo(TopTransactionContext);
esnap = palloc_object(ExportedSnapshot);
@@ -1293,7 +1336,7 @@ pg_export_snapshot(PG_FUNCTION_ARGS)
{
char *snapshotName;
- snapshotName = ExportSnapshot(GetActiveSnapshot());
+ snapshotName = ExportSnapshot((MVCCSnapshot) GetActiveSnapshot());
PG_RETURN_TEXT_P(cstring_to_text(snapshotName));
}
@@ -1397,7 +1440,7 @@ ImportSnapshot(const char *idstr)
Oid src_dbid;
int src_isolevel;
bool src_readonly;
- SnapshotData snapshot;
+ MVCCSnapshotData snapshot;
/*
* Must be at top level of a fresh transaction. Note in particular that
@@ -1666,7 +1709,7 @@ HaveRegisteredOrActiveSnapshot(void)
* Needed for logical decoding.
*/
void
-SetupHistoricSnapshot(Snapshot historic_snapshot, HTAB *tuplecids)
+SetupHistoricSnapshot(HistoricMVCCSnapshot historic_snapshot, HTAB *tuplecids)
{
Assert(historic_snapshot != NULL);
@@ -1709,11 +1752,10 @@ HistoricSnapshotGetTupleCids(void)
* SerializedSnapshotData.
*/
Size
-EstimateSnapshotSpace(Snapshot snapshot)
+EstimateSnapshotSpace(MVCCSnapshot snapshot)
{
Size size;
- Assert(snapshot != InvalidSnapshot);
Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
/* We allocate any XID arrays needed in the same palloc block. */
@@ -1733,7 +1775,7 @@ EstimateSnapshotSpace(Snapshot snapshot)
* memory location at start_address.
*/
void
-SerializeSnapshot(Snapshot snapshot, char *start_address)
+SerializeSnapshot(MVCCSnapshot snapshot, char *start_address)
{
SerializedSnapshotData serialized_snapshot;
@@ -1789,12 +1831,12 @@ SerializeSnapshot(Snapshot snapshot, char *start_address)
* The copy is palloc'd in TopTransactionContext and has initial refcounts set
* to 0. The returned snapshot has the copied flag set.
*/
-Snapshot
+MVCCSnapshot
RestoreSnapshot(char *start_address)
{
SerializedSnapshotData serialized_snapshot;
Size size;
- Snapshot snapshot;
+ MVCCSnapshot snapshot;
TransactionId *serialized_xids;
memcpy(&serialized_snapshot, start_address,
@@ -1803,12 +1845,12 @@ RestoreSnapshot(char *start_address)
(start_address + sizeof(SerializedSnapshotData));
/* We allocate any XID arrays needed in the same palloc block. */
- size = sizeof(SnapshotData)
+ size = sizeof(MVCCSnapshotData)
+ serialized_snapshot.xcnt * sizeof(TransactionId)
+ serialized_snapshot.subxcnt * sizeof(TransactionId);
/* Copy all required fields */
- snapshot = (Snapshot) MemoryContextAlloc(TopTransactionContext, size);
+ snapshot = (MVCCSnapshot) MemoryContextAlloc(TopTransactionContext, size);
snapshot->snapshot_type = SNAPSHOT_MVCC;
snapshot->xmin = serialized_snapshot.xmin;
snapshot->xmax = serialized_snapshot.xmax;
@@ -1850,7 +1892,7 @@ RestoreSnapshot(char *start_address)
* Install a restored snapshot as the transaction snapshot.
*/
void
-RestoreTransactionSnapshot(Snapshot snapshot, PGPROC *source_pgproc)
+RestoreTransactionSnapshot(MVCCSnapshot snapshot, PGPROC *source_pgproc)
{
SetTransactionSnapshot(snapshot, NULL, InvalidPid, source_pgproc);
}
@@ -1866,7 +1908,7 @@ RestoreTransactionSnapshot(Snapshot snapshot, PGPROC *source_pgproc)
* XID could not be ours anyway.
*/
bool
-XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
+XidInMVCCSnapshot(TransactionId xid, MVCCSnapshot snapshot)
{
/*
* Make a quick range check to eliminate most XIDs without looking at the
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index f7e4ae3843c..b64731f926c 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -455,7 +455,7 @@ extern bool HeapTupleIsSurelyDead(HeapTuple htup,
*/
struct HTAB;
extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data,
- Snapshot snapshot,
+ HistoricMVCCSnapshot snapshot,
HeapTuple htup,
Buffer buffer,
CommandId *cmin, CommandId *cmax);
diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h
index 78989a959d4..0f8fdcff782 100644
--- a/src/include/access/relscan.h
+++ b/src/include/access/relscan.h
@@ -34,7 +34,7 @@ typedef struct TableScanDescData
{
/* scan parameters */
Relation rs_rd; /* heap relation descriptor */
- struct SnapshotData *rs_snapshot; /* snapshot to see */
+ union SnapshotData *rs_snapshot; /* snapshot to see */
int rs_nkeys; /* number of scan keys */
struct ScanKeyData *rs_key; /* array of scan key descriptors */
@@ -137,7 +137,7 @@ typedef struct IndexScanDescData
/* scan parameters */
Relation heapRelation; /* heap relation descriptor, or NULL */
Relation indexRelation; /* index relation descriptor */
- struct SnapshotData *xs_snapshot; /* snapshot to see */
+ union SnapshotData *xs_snapshot; /* snapshot to see */
int numberOfKeys; /* number of index qualifier conditions */
int numberOfOrderBys; /* number of ordering operators */
struct ScanKeyData *keyData; /* array of index qualifier descriptors */
@@ -212,7 +212,7 @@ typedef struct SysScanDescData
Relation irel; /* NULL if doing heap scan */
struct TableScanDescData *scan; /* only valid in storage-scan case */
struct IndexScanDescData *iscan; /* only valid in index-scan case */
- struct SnapshotData *snapshot; /* snapshot to unregister at end of scan */
+ union SnapshotData *snapshot; /* snapshot to unregister at end of scan */
struct TupleTableSlot *slot;
} SysScanDescData;
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 3cbe106a3c7..bfe14d5144a 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -127,7 +127,7 @@ typedef struct ReorderBufferChange
} msg;
/* New snapshot, set when action == *_INTERNAL_SNAPSHOT */
- Snapshot snapshot;
+ HistoricMVCCSnapshot snapshot;
/*
* New command id for existing snapshot in a catalog changing tx. Set
@@ -366,7 +366,7 @@ typedef struct ReorderBufferTXN
* transaction modifies the catalog, or another catalog-modifying
* transaction commits.
*/
- Snapshot base_snapshot;
+ HistoricMVCCSnapshot base_snapshot;
XLogRecPtr base_snapshot_lsn;
dlist_node base_snapshot_node; /* link in txns_by_base_snapshot_lsn */
@@ -374,7 +374,7 @@ typedef struct ReorderBufferTXN
* Snapshot/CID from the previous streaming run. Only valid for already
* streamed transactions (NULL/InvalidCommandId otherwise).
*/
- Snapshot snapshot_now;
+ HistoricMVCCSnapshot snapshot_now;
CommandId command_id;
/*
@@ -719,7 +719,7 @@ extern void ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid,
XLogRecPtr lsn, ReorderBufferChange *change,
bool toast_insert);
extern void ReorderBufferQueueMessage(ReorderBuffer *rb, TransactionId xid,
- Snapshot snap, XLogRecPtr lsn,
+ HistoricMVCCSnapshot snap, XLogRecPtr lsn,
bool transactional, const char *prefix,
Size message_size, const char *message);
extern void ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
@@ -743,9 +743,9 @@ extern void ReorderBufferForget(ReorderBuffer *rb, TransactionId xid, XLogRecPtr
extern void ReorderBufferInvalidate(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn);
extern void ReorderBufferSetBaseSnapshot(ReorderBuffer *rb, TransactionId xid,
- XLogRecPtr lsn, Snapshot snap);
+ XLogRecPtr lsn, HistoricMVCCSnapshot snap);
extern void ReorderBufferAddSnapshot(ReorderBuffer *rb, TransactionId xid,
- XLogRecPtr lsn, Snapshot snap);
+ XLogRecPtr lsn, HistoricMVCCSnapshot snap);
extern void ReorderBufferAddNewCommandId(ReorderBuffer *rb, TransactionId xid,
XLogRecPtr lsn, CommandId cid);
extern void ReorderBufferAddNewTupleCids(ReorderBuffer *rb, TransactionId xid,
diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h
index 44031dcf6e3..5930ffb55a8 100644
--- a/src/include/replication/snapbuild.h
+++ b/src/include/replication/snapbuild.h
@@ -70,15 +70,15 @@ extern SnapBuild *AllocateSnapshotBuilder(struct ReorderBuffer *reorder,
XLogRecPtr two_phase_at);
extern void FreeSnapshotBuilder(SnapBuild *builder);
-extern void SnapBuildSnapDecRefcount(Snapshot snap);
+extern void SnapBuildSnapDecRefcount(HistoricMVCCSnapshot snap);
-extern Snapshot SnapBuildInitialSnapshot(SnapBuild *builder);
+extern MVCCSnapshot SnapBuildInitialSnapshot(SnapBuild *builder);
extern const char *SnapBuildExportSnapshot(SnapBuild *builder);
extern void SnapBuildClearExportedSnapshot(void);
extern void SnapBuildResetExportedSnapshotState(void);
extern SnapBuildState SnapBuildCurrentState(SnapBuild *builder);
-extern Snapshot SnapBuildGetOrBuildSnapshot(SnapBuild *builder);
+extern HistoricMVCCSnapshot SnapBuildGetOrBuildSnapshot(SnapBuild *builder);
extern bool SnapBuildXactNeedsSkip(SnapBuild *builder, XLogRecPtr ptr);
extern XLogRecPtr SnapBuildGetTwoPhaseAt(SnapBuild *builder);
diff --git a/src/include/replication/snapbuild_internal.h b/src/include/replication/snapbuild_internal.h
index 3b915dc8793..9bed20efa31 100644
--- a/src/include/replication/snapbuild_internal.h
+++ b/src/include/replication/snapbuild_internal.h
@@ -74,7 +74,7 @@ struct SnapBuild
/*
* Snapshot that's valid to see the catalog state seen at this moment.
*/
- Snapshot snapshot;
+ HistoricMVCCSnapshot snapshot;
/*
* LSN of the last location we are sure a snapshot has been serialized to.
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 8f5f0348a23..9a7f53c900c 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -47,8 +47,8 @@ extern void CheckPointPredicate(void);
extern bool PageIsPredicateLocked(Relation relation, BlockNumber blkno);
/* predicate lock maintenance */
-extern Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot);
-extern void SetSerializableTransactionSnapshot(Snapshot snapshot,
+extern MVCCSnapshot GetSerializableTransactionSnapshot(MVCCSnapshot snapshot);
+extern void SetSerializableTransactionSnapshot(MVCCSnapshot snapshot,
VirtualTransactionId *sourcevxid,
int sourcepid);
extern void RegisterPredicateLockingXid(TransactionId xid);
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index 2f4ae06c279..c40c2ee5d1b 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -44,7 +44,7 @@ extern void KnownAssignedTransactionIdsIdleMaintenance(void);
extern int GetMaxSnapshotXidCount(void);
extern int GetMaxSnapshotSubxidCount(void);
-extern Snapshot GetSnapshotData(Snapshot snapshot);
+extern MVCCSnapshot GetSnapshotData(MVCCSnapshot snapshot);
extern bool ProcArrayInstallImportedXmin(TransactionId xmin,
VirtualTransactionId *sourcevxid);
diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h
index b663d3bbc8c..5d85526b4c9 100644
--- a/src/include/utils/snapmgr.h
+++ b/src/include/utils/snapmgr.h
@@ -49,7 +49,7 @@ extern PGDLLIMPORT SnapshotData SnapshotToastData;
*/
#define InitNonVacuumableSnapshot(snapshotdata, vistestp) \
((snapshotdata).snapshot_type = SNAPSHOT_NON_VACUUMABLE, \
- (snapshotdata).vistest = (vistestp))
+ (snapshotdata).nonvacuumable.vistest = (vistestp))
/* This macro encodes the knowledge of which snapshots are MVCC-safe */
#define IsMVCCSnapshot(snapshot) \
@@ -92,7 +92,7 @@ extern void WaitForOlderSnapshots(TransactionId limitXmin, bool progress);
extern bool ThereAreNoPriorRegisteredSnapshots(void);
extern bool HaveRegisteredOrActiveSnapshot(void);
-extern char *ExportSnapshot(Snapshot snapshot);
+extern char *ExportSnapshot(MVCCSnapshot snapshot);
/*
* These live in procarray.c because they're intimately linked to the
@@ -108,19 +108,19 @@ extern bool GlobalVisCheckRemovableFullXid(Relation rel, FullTransactionId fxid)
/*
* Utility functions for implementing visibility routines in table AMs.
*/
-extern bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
+extern bool XidInMVCCSnapshot(TransactionId xid, MVCCSnapshot snapshot);
/* Support for catalog timetravel for logical decoding */
struct HTAB;
extern struct HTAB *HistoricSnapshotGetTupleCids(void);
-extern void SetupHistoricSnapshot(Snapshot historic_snapshot, struct HTAB *tuplecids);
+extern void SetupHistoricSnapshot(HistoricMVCCSnapshot historic_snapshot, struct HTAB *tuplecids);
extern void TeardownHistoricSnapshot(bool is_error);
extern bool HistoricSnapshotActive(void);
-extern Size EstimateSnapshotSpace(Snapshot snapshot);
-extern void SerializeSnapshot(Snapshot snapshot, char *start_address);
-extern Snapshot RestoreSnapshot(char *start_address);
+extern Size EstimateSnapshotSpace(MVCCSnapshot snapshot);
+extern void SerializeSnapshot(MVCCSnapshot snapshot, char *start_address);
+extern MVCCSnapshot RestoreSnapshot(char *start_address);
struct PGPROC;
-extern void RestoreTransactionSnapshot(Snapshot snapshot, struct PGPROC *source_pgproc);
+extern void RestoreTransactionSnapshot(MVCCSnapshot snapshot, struct PGPROC *source_pgproc);
#endif /* SNAPMGR_H */
diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h
index 0e546ec1497..93c1f51784f 100644
--- a/src/include/utils/snapshot.h
+++ b/src/include/utils/snapshot.h
@@ -17,7 +17,7 @@
/*
- * The different snapshot types. We use SnapshotData structures to represent
+ * The different snapshot types. We use the SnapshotData union to represent
* both "regular" (MVCC) snapshots and "special" snapshots that have non-MVCC
* semantics. The specific semantics of a snapshot are encoded by its type.
*
@@ -27,6 +27,9 @@
* The reason the snapshot type rather than a callback as it used to be is
* that that allows to use the same snapshot for different table AMs without
* having one callback per AM.
+ *
+ * The executor deals with MVCC snapshots, but the table AM and some other
+ * parts of the system also support the special snapshots.
*/
typedef enum SnapshotType
{
@@ -100,7 +103,9 @@ typedef enum SnapshotType
/*
* A tuple is visible iff it follows the rules of SNAPSHOT_MVCC, but
* supports being called in timetravel context (for decoding catalog
- * contents in the context of logical decoding).
+ * contents in the context of logical decoding). A historic MVCC snapshot
+ * should only be used on catalog tables, as we only track XIDs that
+ * modify catalogs during logical decoding.
*/
SNAPSHOT_HISTORIC_MVCC,
@@ -114,37 +119,18 @@ typedef enum SnapshotType
SNAPSHOT_NON_VACUUMABLE,
} SnapshotType;
-typedef struct SnapshotData *Snapshot;
-
-#define InvalidSnapshot ((Snapshot) NULL)
-
/*
- * Struct representing all kind of possible snapshots.
+ * Struct representing a normal MVCC snapshot.
*
- * There are several different kinds of snapshots:
- * * Normal MVCC snapshots
- * * MVCC snapshots taken during recovery (in Hot-Standby mode)
- * * Historic MVCC snapshots used during logical decoding
- * * snapshots passed to HeapTupleSatisfiesDirty()
- * * snapshots passed to HeapTupleSatisfiesNonVacuumable()
- * * snapshots used for SatisfiesAny, Toast, Self where no members are
- * accessed.
- *
- * TODO: It's probably a good idea to split this struct using a NodeTag
- * similar to how parser and executor nodes are handled, with one type for
- * each different kind of snapshot to avoid overloading the meaning of
- * individual fields.
+ * MVCC snapshots come in two variants: those taken during recovery in hot
+ * standby mode, and "normal" MVCC snapshots. They are distinguished by
+ * takenDuringRecovery.
*/
-typedef struct SnapshotData
+typedef struct MVCCSnapshotData
{
- SnapshotType snapshot_type; /* type of snapshot */
+ SnapshotType snapshot_type; /* type of snapshot, must be first */
/*
- * The remaining fields are used only for MVCC snapshots, and are normally
- * just zeroes in special snapshots. (But xmin and xmax are used
- * specially by HeapTupleSatisfiesDirty, and xmin is used specially by
- * HeapTupleSatisfiesNonVacuumable.)
- *
* An MVCC snapshot can never see the effects of XIDs >= xmax. It can see
* the effects of all older XIDs except those listed in the snapshot. xmin
* is stored as an optimization to avoid needing to search the XID arrays
@@ -154,10 +140,8 @@ typedef struct SnapshotData
TransactionId xmax; /* all XID >= xmax are invisible to me */
/*
- * For normal MVCC snapshot this contains the all xact IDs that are in
- * progress, unless the snapshot was taken during recovery in which case
- * it's empty. For historic MVCC snapshots, the meaning is inverted, i.e.
- * it contains *committed* transactions between xmin and xmax.
+ * xip contains the all xact IDs that are in progress, unless the snapshot
+ * was taken during recovery in which case it's empty.
*
* note: all ids in xip[] satisfy xmin <= xip[i] < xmax
*/
@@ -165,10 +149,8 @@ typedef struct SnapshotData
uint32 xcnt; /* # of xact ids in xip[] */
/*
- * For non-historic MVCC snapshots, this contains subxact IDs that are in
- * progress (and other transactions that are in progress if taken during
- * recovery). For historic snapshot it contains *all* xids assigned to the
- * replayed transaction, including the toplevel xid.
+ * subxip contains subxact IDs that are in progress (and other
+ * transactions that are in progress if taken during recovery).
*
* note: all ids in subxip[] are >= xmin, but we don't bother filtering
* out any that are >= xmax
@@ -182,18 +164,6 @@ typedef struct SnapshotData
CommandId curcid; /* in my xact, CID < curcid are visible */
- /*
- * An extra return value for HeapTupleSatisfiesDirty, not used in MVCC
- * snapshots.
- */
- uint32 speculativeToken;
-
- /*
- * For SNAPSHOT_NON_VACUUMABLE (and hopefully more in the future) this is
- * used to determine whether row could be vacuumed.
- */
- struct GlobalVisState *vistest;
-
/*
* Book-keeping information, used by the snapshot manager
*/
@@ -207,6 +177,97 @@ typedef struct SnapshotData
* transactions completed since the last GetSnapshotData().
*/
uint64 snapXactCompletionCount;
+} MVCCSnapshotData;
+
+typedef struct MVCCSnapshotData *MVCCSnapshot;
+
+#define InvalidMVCCSnapshot ((MVCCSnapshot) NULL)
+
+/*
+ * Struct representing a "historic" MVCC snapshot during logical decoding.
+ * These are constructed by src/replication/logical/snapbuild.c.
+ */
+typedef struct HistoricMVCCSnapshotData
+{
+ SnapshotType snapshot_type; /* type of snapshot, must be first */
+
+ /*
+ * xmin and xmax like in a normal MVCC snapshot.
+ */
+ TransactionId xmin; /* all XID < xmin are visible to me */
+ TransactionId xmax; /* all XID >= xmax are invisible to me */
+
+ /*
+ * committed_xids contains *committed* transactions between xmin and xmax.
+ * (This is the inverse of 'xip' in normal MVCC snapshots, which contains
+ * all non-committed transactions.) The array is sorted by XID to allow
+ * binary search.
+ *
+ * note: all ids in committed_xids[] satisfy xmin <= committed_xids[i] <
+ * xmax
+ */
+ TransactionId *committed_xids;
+ uint32 xcnt; /* # of xact ids in committed_xids[] */
+
+ /*
+ * curxip contains *all* xids assigned to the replayed transaction,
+ * including the toplevel xid.
+ */
+ TransactionId *curxip;
+ int32 curxcnt; /* # of xact ids in curxip[] */
+
+ CommandId curcid; /* in my xact, CID < curcid are visible */
+
+ bool copied; /* false if it's a "base" snapshot */
+
+ uint32 refcount; /* refcount managed by snapbuild.c */
+ uint32 regd_count; /* refcount registered with resource owners */
+
+} HistoricMVCCSnapshotData;
+
+typedef struct HistoricMVCCSnapshotData *HistoricMVCCSnapshot;
+
+/*
+ * Struct representing a special "snapshot" which sees all tuples as visible
+ * if they are visible to anyone, i.e. if they are not vacuumable.
+ * i.e. SNAPSHOT_NON_VACUUMABLE.
+ */
+typedef struct NonVacuumableSnapshotData
+{
+ SnapshotType snapshot_type; /* type of snapshot, must be first */
+
+ /* This is used to determine whether row could be vacuumed. */
+ struct GlobalVisState *vistest;
+} NonVacuumableSnapshotData;
+
+/*
+ * Return values to the caller of HeapTupleSatisfyDirty.
+ */
+typedef struct DirtySnapshotData
+{
+ SnapshotType snapshot_type; /* type of snapshot, must be first */
+
+ TransactionId xmin;
+ TransactionId xmax;
+ uint32 speculativeToken;
+} DirtySnapshotData;
+
+/*
+ * Generic union representing all kind of possible snapshots. Some have
+ * type-specific structs.
+ */
+typedef union SnapshotData
+{
+ SnapshotType snapshot_type; /* type of snapshot */
+
+ MVCCSnapshotData mvcc;
+ DirtySnapshotData dirty;
+ HistoricMVCCSnapshotData historic_mvcc;
+ NonVacuumableSnapshotData nonvacuumable;
} SnapshotData;
+typedef union SnapshotData *Snapshot;
+
+#define InvalidSnapshot ((Snapshot) NULL)
+
#endif /* SNAPSHOT_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 04845d5e680..8f26256464f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -656,6 +656,7 @@ DictThesaurus
DimensionInfo
DirectoryMethodData
DirectoryMethodFile
+DirtySnapshotData
DisableTimeoutParams
DiscardMode
DiscardStmt
@@ -1217,6 +1218,7 @@ HeapTupleFreeze
HeapTupleHeader
HeapTupleHeaderData
HeapTupleTableSlot
+HistoricMVCCSnapshotData
HistControl
HotStandbyState
I32
@@ -1673,6 +1675,7 @@ MINIDUMPWRITEDUMP
MINIDUMP_TYPE
MJEvalResult
MTTargetRelLookup
+MVCCSnapshotData
MVDependencies
MVDependency
MVNDistinct
@@ -1779,6 +1782,7 @@ Node
NodeTag
NonEmptyRange
NoneCompressorState
+NonVacuumableSnapshotData
Notification
NotificationList
NotifyStmt
--
2.47.3