PostgreSQL Source Code  git master
snapmgr.c File Reference
#include "postgres.h"
#include <sys/stat.h>
#include <unistd.h>
#include "access/transam.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "lib/pairingheap.h"
#include "miscadmin.h"
#include "storage/predicate.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/sinval.h"
#include "storage/sinvaladt.h"
#include "storage/spin.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/resowner_private.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
Include dependency graph for snapmgr.c:

Go to the source code of this file.

Data Structures

struct  OldSnapshotControlData
 
struct  ActiveSnapshotElt
 
struct  ExportedSnapshot
 
struct  SerializedSnapshotData
 

Macros

#define SNAPSHOT_EXPORT_DIR   "pg_snapshots"
 

Typedefs

typedef struct OldSnapshotControlData OldSnapshotControlData
 
typedef struct ActiveSnapshotElt ActiveSnapshotElt
 
typedef struct ExportedSnapshot ExportedSnapshot
 
typedef struct SerializedSnapshotData SerializedSnapshotData
 

Functions

static int xmin_cmp (const pairingheap_node *a, const pairingheap_node *b, void *arg)
 
static TimestampTz AlignTimestampToMinuteBoundary (TimestampTz ts)
 
static Snapshot CopySnapshot (Snapshot snapshot)
 
static void FreeSnapshot (Snapshot snapshot)
 
static void SnapshotResetXmin (void)
 
Size SnapMgrShmemSize (void)
 
void SnapMgrInit (void)
 
Snapshot GetTransactionSnapshot (void)
 
Snapshot GetLatestSnapshot (void)
 
Snapshot GetOldestSnapshot (void)
 
Snapshot GetCatalogSnapshot (Oid relid)
 
Snapshot GetNonHistoricCatalogSnapshot (Oid relid)
 
void InvalidateCatalogSnapshot (void)
 
void InvalidateCatalogSnapshotConditionally (void)
 
void SnapshotSetCommandId (CommandId curcid)
 
static void SetTransactionSnapshot (Snapshot sourcesnap, VirtualTransactionId *sourcevxid, int sourcepid, PGPROC *sourceproc)
 
void PushActiveSnapshot (Snapshot snap)
 
void PushCopiedSnapshot (Snapshot snapshot)
 
void UpdateActiveSnapshotCommandId (void)
 
void PopActiveSnapshot (void)
 
Snapshot GetActiveSnapshot (void)
 
bool ActiveSnapshotSet (void)
 
Snapshot RegisterSnapshot (Snapshot snapshot)
 
Snapshot RegisterSnapshotOnOwner (Snapshot snapshot, ResourceOwner owner)
 
void UnregisterSnapshot (Snapshot snapshot)
 
void UnregisterSnapshotFromOwner (Snapshot snapshot, ResourceOwner owner)
 
void AtSubCommit_Snapshot (int level)
 
void AtSubAbort_Snapshot (int level)
 
void AtEOXact_Snapshot (bool isCommit, bool resetXmin)
 
char * ExportSnapshot (Snapshot snapshot)
 
Datum pg_export_snapshot (PG_FUNCTION_ARGS)
 
static int parseIntFromText (const char *prefix, char **s, const char *filename)
 
static TransactionId parseXidFromText (const char *prefix, char **s, const char *filename)
 
static void parseVxidFromText (const char *prefix, char **s, const char *filename, VirtualTransactionId *vxid)
 
void ImportSnapshot (const char *idstr)
 
bool XactHasExportedSnapshots (void)
 
void DeleteAllExportedSnapshotFiles (void)
 
bool ThereAreNoPriorRegisteredSnapshots (void)
 
TimestampTz GetSnapshotCurrentTimestamp (void)
 
TimestampTz GetOldSnapshotThresholdTimestamp (void)
 
static void SetOldSnapshotThresholdTimestamp (TimestampTz ts, TransactionId xlimit)
 
TransactionId TransactionIdLimitedForOldSnapshots (TransactionId recentXmin, Relation relation)
 
void MaintainOldSnapshotTimeMapping (TimestampTz whenTaken, TransactionId xmin)
 
void SetupHistoricSnapshot (Snapshot historic_snapshot, HTAB *tuplecids)
 
void TeardownHistoricSnapshot (bool is_error)
 
bool HistoricSnapshotActive (void)
 
HTABHistoricSnapshotGetTupleCids (void)
 
Size EstimateSnapshotSpace (Snapshot snap)
 
void SerializeSnapshot (Snapshot snapshot, char *start_address)
 
Snapshot RestoreSnapshot (char *start_address)
 
void RestoreTransactionSnapshot (Snapshot snapshot, void *master_pgproc)
 

Variables

int old_snapshot_threshold
 
static volatile OldSnapshotControlDataoldSnapshotControl
 
static SnapshotData CurrentSnapshotData = {HeapTupleSatisfiesMVCC}
 
static SnapshotData SecondarySnapshotData = {HeapTupleSatisfiesMVCC}
 
SnapshotData CatalogSnapshotData = {HeapTupleSatisfiesMVCC}
 
static Snapshot CurrentSnapshot = NULL
 
static Snapshot SecondarySnapshot = NULL
 
static Snapshot CatalogSnapshot = NULL
 
static Snapshot HistoricSnapshot = NULL
 
TransactionId TransactionXmin = FirstNormalTransactionId
 
TransactionId RecentXmin = FirstNormalTransactionId
 
TransactionId RecentGlobalXmin = InvalidTransactionId
 
TransactionId RecentGlobalDataXmin = InvalidTransactionId
 
static HTABtuplecid_data = NULL
 
static ActiveSnapshotEltActiveSnapshot = NULL
 
static ActiveSnapshotEltOldestActiveSnapshot = NULL
 
static pairingheap RegisteredSnapshots = {&xmin_cmp, NULL, NULL}
 
bool FirstSnapshotSet = false
 
static Snapshot FirstXactSnapshot = NULL
 
static ListexportedSnapshots = NIL
 

Macro Definition Documentation

◆ SNAPSHOT_EXPORT_DIR

#define SNAPSHOT_EXPORT_DIR   "pg_snapshots"

Definition at line 213 of file snapmgr.c.

Referenced by DeleteAllExportedSnapshotFiles(), ExportSnapshot(), and ImportSnapshot().

Typedef Documentation

◆ ActiveSnapshotElt

◆ ExportedSnapshot

◆ OldSnapshotControlData

◆ SerializedSnapshotData

Function Documentation

◆ ActiveSnapshotSet()

bool ActiveSnapshotSet ( void  )

Definition at line 851 of file snapmgr.c.

Referenced by _SPI_execute_plan(), BuildCachedPlan(), pg_plan_query(), PortalRunUtility(), postquel_start(), RevalidateCachedQuery(), SPI_commit(), and vacuum().

852 {
853  return ActiveSnapshot != NULL;
854 }
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188

◆ AlignTimestampToMinuteBoundary()

static TimestampTz AlignTimestampToMinuteBoundary ( TimestampTz  ts)
static

Definition at line 1672 of file snapmgr.c.

References USECS_PER_MINUTE.

Referenced by MaintainOldSnapshotTimeMapping(), and TransactionIdLimitedForOldSnapshots().

1673 {
1674  TimestampTz retval = ts + (USECS_PER_MINUTE - 1);
1675 
1676  return retval - (retval % USECS_PER_MINUTE);
1677 }
int64 TimestampTz
Definition: timestamp.h:39
#define USECS_PER_MINUTE
Definition: timestamp.h:93

◆ AtEOXact_Snapshot()

void AtEOXact_Snapshot ( bool  isCommit,
bool  resetXmin 
)

Definition at line 1059 of file snapmgr.c.

References ActiveSnapshotElt::as_next, Assert, elog, FirstSnapshotSet, InvalidateCatalogSnapshot(), lfirst, MyPgXact, NIL, pairingheap_is_empty, pairingheap_remove(), pairingheap_reset, SnapshotData::ph_node, SnapshotData::regd_count, ExportedSnapshot::snapfile, ExportedSnapshot::snapshot, SnapshotResetXmin(), WARNING, and PGXACT::xmin.

Referenced by CleanupTransaction(), CommitTransaction(), and PrepareTransaction().

1060 {
1061  /*
1062  * In transaction-snapshot mode we must release our privately-managed
1063  * reference to the transaction snapshot. We must remove it from
1064  * RegisteredSnapshots to keep the check below happy. But we don't bother
1065  * to do FreeSnapshot, for two reasons: the memory will go away with
1066  * TopTransactionContext anyway, and if someone has left the snapshot
1067  * stacked as active, we don't want the code below to be chasing through a
1068  * dangling pointer.
1069  */
1070  if (FirstXactSnapshot != NULL)
1071  {
1075  }
1076  FirstXactSnapshot = NULL;
1077 
1078  /*
1079  * If we exported any snapshots, clean them up.
1080  */
1081  if (exportedSnapshots != NIL)
1082  {
1083  ListCell *lc;
1084 
1085  /*
1086  * Get rid of the files. Unlink failure is only a WARNING because (1)
1087  * it's too late to abort the transaction, and (2) leaving a leaked
1088  * file around has little real consequence anyway.
1089  *
1090  * We also also need to remove the snapshots from RegisteredSnapshots
1091  * to prevent a warning below.
1092  *
1093  * As with the FirstXactSnapshot, we don't need to free resources of
1094  * the snapshot iself as it will go away with the memory context.
1095  */
1096  foreach(lc, exportedSnapshots)
1097  {
1098  ExportedSnapshot *esnap = (ExportedSnapshot *) lfirst(lc);
1099 
1100  if (unlink(esnap->snapfile))
1101  elog(WARNING, "could not unlink file \"%s\": %m",
1102  esnap->snapfile);
1103 
1105  &esnap->snapshot->ph_node);
1106  }
1107 
1109  }
1110 
1111  /* Drop catalog snapshot if any */
1113 
1114  /* On commit, complain about leftover snapshots */
1115  if (isCommit)
1116  {
1117  ActiveSnapshotElt *active;
1118 
1120  elog(WARNING, "registered snapshots seem to remain after cleanup");
1121 
1122  /* complain about unpopped active snapshots */
1123  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
1124  elog(WARNING, "snapshot %p still active", active);
1125  }
1126 
1127  /*
1128  * And reset our state. We don't need to free the memory explicitly --
1129  * it'll go away with TopTransactionContext.
1130  */
1131  ActiveSnapshot = NULL;
1132  OldestActiveSnapshot = NULL;
1134 
1135  CurrentSnapshot = NULL;
1136  SecondarySnapshot = NULL;
1137 
1138  FirstSnapshotSet = false;
1139 
1140  /*
1141  * During normal commit processing, we call ProcArrayEndTransaction() to
1142  * reset the PgXact->xmin. That call happens prior to the call to
1143  * AtEOXact_Snapshot(), so we need not touch xmin here at all.
1144  */
1145  if (resetXmin)
1147 
1148  Assert(resetXmin || MyPgXact->xmin == 0);
1149 }
#define NIL
Definition: pg_list.h:69
#define pairingheap_reset(h)
Definition: pairingheap.h:93
TransactionId xmin
Definition: proc.h:225
static void SnapshotResetXmin(void)
Definition: snapmgr.c:978
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
static Snapshot FirstXactSnapshot
Definition: snapmgr.c:210
uint32 regd_count
Definition: snapshot.h:110
static Snapshot CurrentSnapshot
Definition: snapmgr.c:149
PGXACT * MyPgXact
Definition: proc.c:68
static List * exportedSnapshots
Definition: snapmgr.c:223
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
bool FirstSnapshotSet
Definition: snapmgr.c:203
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:191
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:184
Snapshot snapshot
Definition: snapmgr.c:219
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:510
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188
char * snapfile
Definition: snapmgr.c:218
#define WARNING
Definition: elog.h:40
pairingheap_node ph_node
Definition: snapshot.h:111
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
static Snapshot SecondarySnapshot
Definition: snapmgr.c:150
void pairingheap_remove(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:170
#define elog
Definition: elog.h:219

◆ AtSubAbort_Snapshot()

void AtSubAbort_Snapshot ( int  level)

Definition at line 1023 of file snapmgr.c.

References SnapshotData::active_count, ActiveSnapshotElt::as_level, ActiveSnapshotElt::as_next, ActiveSnapshotElt::as_snap, Assert, FreeSnapshot(), next, pfree(), SnapshotData::regd_count, and SnapshotResetXmin().

Referenced by AbortSubTransaction().

1024 {
1025  /* Forget the active snapshots set by this subtransaction */
1026  while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
1027  {
1029 
1030  next = ActiveSnapshot->as_next;
1031 
1032  /*
1033  * Decrement the snapshot's active count. If it's still registered or
1034  * marked as active by an outer subtransaction, we can't free it yet.
1035  */
1038 
1039  if (ActiveSnapshot->as_snap->active_count == 0 &&
1042 
1043  /* and free the stack element */
1045 
1046  ActiveSnapshot = next;
1047  if (ActiveSnapshot == NULL)
1048  OldestActiveSnapshot = NULL;
1049  }
1050 
1052 }
Snapshot as_snap
Definition: snapmgr.c:182
static int32 next
Definition: blutils.c:211
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:715
static void SnapshotResetXmin(void)
Definition: snapmgr.c:978
uint32 regd_count
Definition: snapshot.h:110
void pfree(void *pointer)
Definition: mcxt.c:1031
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:191
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:184
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188
#define Assert(condition)
Definition: c.h:699
uint32 active_count
Definition: snapshot.h:109

◆ AtSubCommit_Snapshot()

void AtSubCommit_Snapshot ( int  level)

Definition at line 1002 of file snapmgr.c.

References ActiveSnapshotElt::as_level, and ActiveSnapshotElt::as_next.

Referenced by CommitSubTransaction().

1003 {
1004  ActiveSnapshotElt *active;
1005 
1006  /*
1007  * Relabel the active snapshots set in this subtransaction as though they
1008  * are owned by the parent subxact.
1009  */
1010  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
1011  {
1012  if (active->as_level < level)
1013  break;
1014  active->as_level = level - 1;
1015  }
1016 }
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:184
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188

◆ CopySnapshot()

static Snapshot CopySnapshot ( Snapshot  snapshot)
static

Definition at line 660 of file snapmgr.c.

References SnapshotData::active_count, Assert, SnapshotData::copied, InvalidSnapshot, MemoryContextAlloc(), SnapshotData::regd_count, SnapshotData::suboverflowed, SnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TopTransactionContext, SnapshotData::xcnt, and SnapshotData::xip.

Referenced by ExportSnapshot(), GetTransactionSnapshot(), PushActiveSnapshot(), PushCopiedSnapshot(), RegisterSnapshotOnOwner(), and SetTransactionSnapshot().

661 {
662  Snapshot newsnap;
663  Size subxipoff;
664  Size size;
665 
666  Assert(snapshot != InvalidSnapshot);
667 
668  /* We allocate any XID arrays needed in the same palloc block. */
669  size = subxipoff = sizeof(SnapshotData) +
670  snapshot->xcnt * sizeof(TransactionId);
671  if (snapshot->subxcnt > 0)
672  size += snapshot->subxcnt * sizeof(TransactionId);
673 
675  memcpy(newsnap, snapshot, sizeof(SnapshotData));
676 
677  newsnap->regd_count = 0;
678  newsnap->active_count = 0;
679  newsnap->copied = true;
680 
681  /* setup XID array */
682  if (snapshot->xcnt > 0)
683  {
684  newsnap->xip = (TransactionId *) (newsnap + 1);
685  memcpy(newsnap->xip, snapshot->xip,
686  snapshot->xcnt * sizeof(TransactionId));
687  }
688  else
689  newsnap->xip = NULL;
690 
691  /*
692  * Setup subXID array. Don't bother to copy it if it had overflowed,
693  * though, because it's not used anywhere in that case. Except if it's a
694  * snapshot taken during recovery; all the top-level XIDs are in subxip as
695  * well in that case, so we mustn't lose them.
696  */
697  if (snapshot->subxcnt > 0 &&
698  (!snapshot->suboverflowed || snapshot->takenDuringRecovery))
699  {
700  newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);
701  memcpy(newsnap->subxip, snapshot->subxip,
702  snapshot->subxcnt * sizeof(TransactionId));
703  }
704  else
705  newsnap->subxip = NULL;
706 
707  return newsnap;
708 }
MemoryContext TopTransactionContext
Definition: mcxt.c:49
uint32 TransactionId
Definition: c.h:474
bool copied
Definition: snapshot.h:96
bool suboverflowed
Definition: snapshot.h:93
struct SnapshotData * Snapshot
Definition: snapshot.h:23
uint32 regd_count
Definition: snapshot.h:110
struct SnapshotData SnapshotData
TransactionId * xip
Definition: snapshot.h:79
#define InvalidSnapshot
Definition: snapshot.h:25
#define Assert(condition)
Definition: c.h:699
bool takenDuringRecovery
Definition: snapshot.h:95
size_t Size
Definition: c.h:433
uint32 xcnt
Definition: snapshot.h:80
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
TransactionId * subxip
Definition: snapshot.h:91
uint32 active_count
Definition: snapshot.h:109
int32 subxcnt
Definition: snapshot.h:92

◆ DeleteAllExportedSnapshotFiles()

void DeleteAllExportedSnapshotFiles ( void  )

Definition at line 1616 of file snapmgr.c.

References AllocateDir(), buf, dirent::d_name, ereport, errcode_for_file_access(), errmsg(), FreeDir(), LOG, MAXPGPATH, ReadDirExtended(), SNAPSHOT_EXPORT_DIR, and snprintf().

Referenced by StartupXLOG().

1617 {
1618  char buf[MAXPGPATH + sizeof(SNAPSHOT_EXPORT_DIR)];
1619  DIR *s_dir;
1620  struct dirent *s_de;
1621 
1622  /*
1623  * Problems in reading the directory, or unlinking files, are reported at
1624  * LOG level. Since we're running in the startup process, ERROR level
1625  * would prevent database start, and it's not important enough for that.
1626  */
1628 
1629  while ((s_de = ReadDirExtended(s_dir, SNAPSHOT_EXPORT_DIR, LOG)) != NULL)
1630  {
1631  if (strcmp(s_de->d_name, ".") == 0 ||
1632  strcmp(s_de->d_name, "..") == 0)
1633  continue;
1634 
1635  snprintf(buf, sizeof(buf), SNAPSHOT_EXPORT_DIR "/%s", s_de->d_name);
1636 
1637  if (unlink(buf) != 0)
1638  ereport(LOG,
1640  errmsg("could not remove file \"%s\": %m", buf)));
1641  }
1642 
1643  FreeDir(s_dir);
1644 }
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2671
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:213
Definition: dirent.c:25
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:67
int errcode_for_file_access(void)
Definition: elog.c:598
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2590
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797
char d_name[MAX_PATH]
Definition: dirent.h:14
int FreeDir(DIR *dir)
Definition: fd.c:2708

◆ EstimateSnapshotSpace()

Size EstimateSnapshotSpace ( Snapshot  snap)

Definition at line 2044 of file snapmgr.c.

References add_size(), Assert, HeapTupleSatisfiesMVCC(), InvalidSnapshot, mul_size(), SnapshotData::satisfies, SnapshotData::suboverflowed, SnapshotData::subxcnt, SnapshotData::takenDuringRecovery, and SnapshotData::xcnt.

Referenced by _bt_parallel_estimate_shared(), ExecBitmapHeapEstimate(), heap_parallelscan_estimate(), index_parallelscan_estimate(), index_parallelscan_initialize(), and InitializeParallelDSM().

2045 {
2046  Size size;
2047 
2048  Assert(snap != InvalidSnapshot);
2050 
2051  /* We allocate any XID arrays needed in the same palloc block. */
2052  size = add_size(sizeof(SerializedSnapshotData),
2053  mul_size(snap->xcnt, sizeof(TransactionId)));
2054  if (snap->subxcnt > 0 &&
2055  (!snap->suboverflowed || snap->takenDuringRecovery))
2056  size = add_size(size,
2057  mul_size(snap->subxcnt, sizeof(TransactionId)));
2058 
2059  return size;
2060 }
SnapshotSatisfiesFunc satisfies
Definition: snapshot.h:55
uint32 TransactionId
Definition: c.h:474
bool suboverflowed
Definition: snapshot.h:93
#define InvalidSnapshot
Definition: snapshot.h:25
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
#define Assert(condition)
Definition: c.h:699
bool takenDuringRecovery
Definition: snapshot.h:95
size_t Size
Definition: c.h:433
uint32 xcnt
Definition: snapshot.h:80
bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
Definition: tqual.c:963
int32 subxcnt
Definition: snapshot.h:92

◆ ExportSnapshot()

char* ExportSnapshot ( Snapshot  snapshot)

Definition at line 1159 of file snapmgr.c.

References AllocateFile(), appendStringInfo(), appendStringInfoString(), PGPROC::backendId, buf, CopySnapshot(), StringInfoData::data, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, FreeFile(), GetMaxSnapshotSubxidCount(), GetTopTransactionIdIfAny(), i, initStringInfo(), IsSubTransaction(), lappend(), StringInfoData::len, list_length(), PGPROC::lxid, MAXPGPATH, MemoryContextSwitchTo(), MyDatabaseId, MyProc, MyProcPid, pairingheap_add(), palloc(), PG_BINARY_W, SnapshotData::ph_node, pstrdup(), SnapshotData::regd_count, ExportedSnapshot::snapfile, ExportedSnapshot::snapshot, SNAPSHOT_EXPORT_DIR, snprintf(), SnapshotData::suboverflowed, SnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TopTransactionContext, TransactionIdIsValid, TransactionIdPrecedes(), xactGetCommittedChildren(), XactIsoLevel, XactReadOnly, SnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by pg_export_snapshot(), and SnapBuildExportSnapshot().

1160 {
1161  TransactionId topXid;
1162  TransactionId *children;
1163  ExportedSnapshot *esnap;
1164  int nchildren;
1165  int addTopXid;
1167  FILE *f;
1168  int i;
1169  MemoryContext oldcxt;
1170  char path[MAXPGPATH];
1171  char pathtmp[MAXPGPATH];
1172 
1173  /*
1174  * It's tempting to call RequireTransactionBlock here, since it's not very
1175  * useful to export a snapshot that will disappear immediately afterwards.
1176  * However, we haven't got enough information to do that, since we don't
1177  * know if we're at top level or not. For example, we could be inside a
1178  * plpgsql function that is going to fire off other transactions via
1179  * dblink. Rather than disallow perfectly legitimate usages, don't make a
1180  * check.
1181  *
1182  * Also note that we don't make any restriction on the transaction's
1183  * isolation level; however, importers must check the level if they are
1184  * serializable.
1185  */
1186 
1187  /*
1188  * Get our transaction ID if there is one, to include in the snapshot.
1189  */
1190  topXid = GetTopTransactionIdIfAny();
1191 
1192  /*
1193  * We cannot export a snapshot from a subtransaction because there's no
1194  * easy way for importers to verify that the same subtransaction is still
1195  * running.
1196  */
1197  if (IsSubTransaction())
1198  ereport(ERROR,
1199  (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1200  errmsg("cannot export a snapshot from a subtransaction")));
1201 
1202  /*
1203  * We do however allow previous committed subtransactions to exist.
1204  * Importers of the snapshot must see them as still running, so get their
1205  * XIDs to add them to the snapshot.
1206  */
1207  nchildren = xactGetCommittedChildren(&children);
1208 
1209  /*
1210  * Generate file path for the snapshot. We start numbering of snapshots
1211  * inside the transaction from 1.
1212  */
1213  snprintf(path, sizeof(path), SNAPSHOT_EXPORT_DIR "/%08X-%08X-%d",
1215 
1216  /*
1217  * Copy the snapshot into TopTransactionContext, add it to the
1218  * exportedSnapshots list, and mark it pseudo-registered. We do this to
1219  * ensure that the snapshot's xmin is honored for the rest of the
1220  * transaction.
1221  */
1222  snapshot = CopySnapshot(snapshot);
1223 
1225  esnap = (ExportedSnapshot *) palloc(sizeof(ExportedSnapshot));
1226  esnap->snapfile = pstrdup(path);
1227  esnap->snapshot = snapshot;
1229  MemoryContextSwitchTo(oldcxt);
1230 
1231  snapshot->regd_count++;
1233 
1234  /*
1235  * Fill buf with a text serialization of the snapshot, plus identification
1236  * data about this transaction. The format expected by ImportSnapshot is
1237  * pretty rigid: each line must be fieldname:value.
1238  */
1239  initStringInfo(&buf);
1240 
1241  appendStringInfo(&buf, "vxid:%d/%u\n", MyProc->backendId, MyProc->lxid);
1242  appendStringInfo(&buf, "pid:%d\n", MyProcPid);
1243  appendStringInfo(&buf, "dbid:%u\n", MyDatabaseId);
1244  appendStringInfo(&buf, "iso:%d\n", XactIsoLevel);
1245  appendStringInfo(&buf, "ro:%d\n", XactReadOnly);
1246 
1247  appendStringInfo(&buf, "xmin:%u\n", snapshot->xmin);
1248  appendStringInfo(&buf, "xmax:%u\n", snapshot->xmax);
1249 
1250  /*
1251  * We must include our own top transaction ID in the top-xid data, since
1252  * by definition we will still be running when the importing transaction
1253  * adopts the snapshot, but GetSnapshotData never includes our own XID in
1254  * the snapshot. (There must, therefore, be enough room to add it.)
1255  *
1256  * However, it could be that our topXid is after the xmax, in which case
1257  * we shouldn't include it because xip[] members are expected to be before
1258  * xmax. (We need not make the same check for subxip[] members, see
1259  * snapshot.h.)
1260  */
1261  addTopXid = (TransactionIdIsValid(topXid) &&
1262  TransactionIdPrecedes(topXid, snapshot->xmax)) ? 1 : 0;
1263  appendStringInfo(&buf, "xcnt:%d\n", snapshot->xcnt + addTopXid);
1264  for (i = 0; i < snapshot->xcnt; i++)
1265  appendStringInfo(&buf, "xip:%u\n", snapshot->xip[i]);
1266  if (addTopXid)
1267  appendStringInfo(&buf, "xip:%u\n", topXid);
1268 
1269  /*
1270  * Similarly, we add our subcommitted child XIDs to the subxid data. Here,
1271  * we have to cope with possible overflow.
1272  */
1273  if (snapshot->suboverflowed ||
1274  snapshot->subxcnt + nchildren > GetMaxSnapshotSubxidCount())
1275  appendStringInfoString(&buf, "sof:1\n");
1276  else
1277  {
1278  appendStringInfoString(&buf, "sof:0\n");
1279  appendStringInfo(&buf, "sxcnt:%d\n", snapshot->subxcnt + nchildren);
1280  for (i = 0; i < snapshot->subxcnt; i++)
1281  appendStringInfo(&buf, "sxp:%u\n", snapshot->subxip[i]);
1282  for (i = 0; i < nchildren; i++)
1283  appendStringInfo(&buf, "sxp:%u\n", children[i]);
1284  }
1285  appendStringInfo(&buf, "rec:%u\n", snapshot->takenDuringRecovery);
1286 
1287  /*
1288  * Now write the text representation into a file. We first write to a
1289  * ".tmp" filename, and rename to final filename if no error. This
1290  * ensures that no other backend can read an incomplete file
1291  * (ImportSnapshot won't allow it because of its valid-characters check).
1292  */
1293  snprintf(pathtmp, sizeof(pathtmp), "%s.tmp", path);
1294  if (!(f = AllocateFile(pathtmp, PG_BINARY_W)))
1295  ereport(ERROR,
1297  errmsg("could not create file \"%s\": %m", pathtmp)));
1298 
1299  if (fwrite(buf.data, buf.len, 1, f) != 1)
1300  ereport(ERROR,
1302  errmsg("could not write to file \"%s\": %m", pathtmp)));
1303 
1304  /* no fsync() since file need not survive a system crash */
1305 
1306  if (FreeFile(f))
1307  ereport(ERROR,
1309  errmsg("could not write to file \"%s\": %m", pathtmp)));
1310 
1311  /*
1312  * Now that we have written everything into a .tmp file, rename the file
1313  * to remove the .tmp suffix.
1314  */
1315  if (rename(pathtmp, path) < 0)
1316  ereport(ERROR,
1318  errmsg("could not rename file \"%s\" to \"%s\": %m",
1319  pathtmp, path)));
1320 
1321  /*
1322  * The basename of the file is what we return from pg_export_snapshot().
1323  * It's already in path in a textual format and we know that the path
1324  * starts with SNAPSHOT_EXPORT_DIR. Skip over the prefix and the slash
1325  * and pstrdup it so as not to return the address of a local variable.
1326  */
1327  return pstrdup(path + strlen(SNAPSHOT_EXPORT_DIR) + 1);
1328 }
int xactGetCommittedChildren(TransactionId **ptr)
Definition: xact.c:5208
int MyProcPid
Definition: globals.c:40
MemoryContext TopTransactionContext
Definition: mcxt.c:49
BackendId backendId
Definition: proc.h:113
uint32 TransactionId
Definition: c.h:474
PGPROC * MyProc
Definition: proc.c:67
char * pstrdup(const char *in)
Definition: mcxt.c:1161
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PG_BINARY_W
Definition: c.h:1083
bool suboverflowed
Definition: snapshot.h:93
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
uint32 regd_count
Definition: snapshot.h:110
static List * exportedSnapshots
Definition: snapmgr.c:223
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:213
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define ERROR
Definition: elog.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
#define MAXPGPATH
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static char * buf
Definition: pg_test_fsync.c:67
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2336
TransactionId xmax
Definition: snapshot.h:69
TransactionId xmin
Definition: snapshot.h:68
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:404
#define ereport(elevel, rest)
Definition: elog.h:122
Snapshot snapshot
Definition: snapmgr.c:219
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
TransactionId * xip
Definition: snapshot.h:79
List * lappend(List *list, void *datum)
Definition: list.c:128
char * snapfile
Definition: snapmgr.c:218
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
Oid MyDatabaseId
Definition: globals.c:84
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:660
bool XactReadOnly
Definition: xact.c:76
pairingheap_node ph_node
Definition: snapshot.h:111
bool takenDuringRecovery
Definition: snapshot.h:95
static int list_length(const List *l)
Definition: pg_list.h:89
int XactIsoLevel
Definition: xact.c:73
int FreeFile(FILE *file)
Definition: fd.c:2528
bool IsSubTransaction(void)
Definition: xact.c:4495
uint32 xcnt
Definition: snapshot.h:80
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
int GetMaxSnapshotSubxidCount(void)
Definition: procarray.c:1467
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId * subxip
Definition: snapshot.h:91
int32 subxcnt
Definition: snapshot.h:92
LocalTransactionId lxid
Definition: proc.h:106

◆ FreeSnapshot()

static void FreeSnapshot ( Snapshot  snapshot)
static

Definition at line 715 of file snapmgr.c.

References SnapshotData::active_count, Assert, SnapshotData::copied, pfree(), and SnapshotData::regd_count.

Referenced by AtSubAbort_Snapshot(), PopActiveSnapshot(), and UnregisterSnapshotFromOwner().

716 {
717  Assert(snapshot->regd_count == 0);
718  Assert(snapshot->active_count == 0);
719  Assert(snapshot->copied);
720 
721  pfree(snapshot);
722 }
bool copied
Definition: snapshot.h:96
uint32 regd_count
Definition: snapshot.h:110
void pfree(void *pointer)
Definition: mcxt.c:1031
#define Assert(condition)
Definition: c.h:699
uint32 active_count
Definition: snapshot.h:109

◆ GetActiveSnapshot()

◆ GetCatalogSnapshot()

Snapshot GetCatalogSnapshot ( Oid  relid)

Definition at line 440 of file snapmgr.c.

References GetNonHistoricCatalogSnapshot(), HistoricSnapshot, and HistoricSnapshotActive().

Referenced by heap_beginscan_catalog(), process_settings(), ScanPgRelation(), systable_beginscan(), systable_beginscan_ordered(), and systable_recheck_tuple().

441 {
442  /*
443  * Return historic snapshot while we're doing logical decoding, so we can
444  * see the appropriate state of the catalog.
445  *
446  * This is the primary reason for needing to reset the system caches after
447  * finishing decoding.
448  */
450  return HistoricSnapshot;
451 
452  return GetNonHistoricCatalogSnapshot(relid);
453 }
static Snapshot HistoricSnapshot
Definition: snapmgr.c:152
Snapshot GetNonHistoricCatalogSnapshot(Oid relid)
Definition: snapmgr.c:462
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2024

◆ GetLatestSnapshot()

Snapshot GetLatestSnapshot ( void  )

Definition at line 379 of file snapmgr.c.

References Assert, elog, ERROR, FirstSnapshotSet, GetSnapshotData(), GetTransactionSnapshot(), HistoricSnapshotActive(), IsInParallelMode(), and SecondarySnapshot.

Referenced by AlterDomainNotNull(), asyncQueueReadAllNotifications(), ATRewriteTable(), check_default_allows_bound(), currtid_byrelname(), currtid_byreloid(), DefineQueryRewrite(), IndexCheckExclusion(), pgstat_collect_oids(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RI_Initial_Check(), ri_PerformCheck(), validateCheckConstraint(), validateDomainConstraint(), validateForeignKeyConstraint(), and wait_for_relation_state_change().

380 {
381  /*
382  * We might be able to relax this, but nothing that could otherwise work
383  * needs it.
384  */
385  if (IsInParallelMode())
386  elog(ERROR,
387  "cannot update SecondarySnapshot during a parallel operation");
388 
389  /*
390  * So far there are no cases requiring support for GetLatestSnapshot()
391  * during logical decoding, but it wouldn't be hard to add if required.
392  */
394 
395  /* If first call in transaction, go ahead and set the xact snapshot */
396  if (!FirstSnapshotSet)
397  return GetTransactionSnapshot();
398 
400 
401  return SecondarySnapshot;
402 }
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
bool IsInParallelMode(void)
Definition: xact.c:905
#define ERROR
Definition: elog.h:43
bool FirstSnapshotSet
Definition: snapmgr.c:203
static SnapshotData SecondarySnapshotData
Definition: snapmgr.c:145
#define Assert(condition)
Definition: c.h:699
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1509
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2024
static Snapshot SecondarySnapshot
Definition: snapmgr.c:150
#define elog
Definition: elog.h:219

◆ GetNonHistoricCatalogSnapshot()

Snapshot GetNonHistoricCatalogSnapshot ( Oid  relid)

Definition at line 462 of file snapmgr.c.

References CatalogSnapshot, GetSnapshotData(), InvalidateCatalogSnapshot(), pairingheap_add(), SnapshotData::ph_node, RelationHasSysCache(), and RelationInvalidatesSnapshotsOnly().

Referenced by GetCatalogSnapshot(), and ScanPgRelation().

463 {
464  /*
465  * If the caller is trying to scan a relation that has no syscache, no
466  * catcache invalidations will be sent when it is updated. For a few key
467  * relations, snapshot invalidations are sent instead. If we're trying to
468  * scan a relation for which neither catcache nor snapshot invalidations
469  * are sent, we must refresh the snapshot every time.
470  */
471  if (CatalogSnapshot &&
473  !RelationHasSysCache(relid))
475 
476  if (CatalogSnapshot == NULL)
477  {
478  /* Get new snapshot. */
480 
481  /*
482  * Make sure the catalog snapshot will be accounted for in decisions
483  * about advancing PGXACT->xmin. We could apply RegisterSnapshot, but
484  * that would result in making a physical copy, which is overkill; and
485  * it would also create a dependency on some resource owner, which we
486  * do not want for reasons explained at the head of this file. Instead
487  * just shove the CatalogSnapshot into the pairing heap manually. This
488  * has to be reversed in InvalidateCatalogSnapshot, of course.
489  *
490  * NB: it had better be impossible for this to throw error, since the
491  * CatalogSnapshot pointer is already valid.
492  */
494  }
495 
496  return CatalogSnapshot;
497 }
SnapshotData CatalogSnapshotData
Definition: snapmgr.c:146
bool RelationHasSysCache(Oid relid)
Definition: syscache.c:1487
static Snapshot CatalogSnapshot
Definition: snapmgr.c:151
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:510
pairingheap_node ph_node
Definition: snapshot.h:111
bool RelationInvalidatesSnapshotsOnly(Oid relid)
Definition: syscache.c:1464
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1509
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112

◆ GetOldestSnapshot()

Snapshot GetOldestSnapshot ( void  )

Definition at line 411 of file snapmgr.c.

References ActiveSnapshotElt::as_snap, InvalidXLogRecPtr, SnapshotData::lsn, pairingheap_container, pairingheap_first(), pairingheap_is_empty, and XLogRecPtrIsInvalid.

Referenced by init_toast_snapshot().

412 {
413  Snapshot OldestRegisteredSnapshot = NULL;
414  XLogRecPtr RegisteredLSN = InvalidXLogRecPtr;
415 
417  {
418  OldestRegisteredSnapshot = pairingheap_container(SnapshotData, ph_node,
420  RegisteredLSN = OldestRegisteredSnapshot->lsn;
421  }
422 
423  if (OldestActiveSnapshot != NULL)
424  {
426 
427  if (XLogRecPtrIsInvalid(RegisteredLSN) || RegisteredLSN > ActiveLSN)
429  }
430 
431  return OldestRegisteredSnapshot;
432 }
pairingheap_node * pairingheap_first(pairingheap *heap)
Definition: pairingheap.c:130
Snapshot as_snap
Definition: snapmgr.c:182
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
XLogRecPtr lsn
Definition: snapshot.h:114
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
#define pairingheap_container(type, membername, ptr)
Definition: pairingheap.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:191
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
uint64 XLogRecPtr
Definition: xlogdefs.h:21

◆ GetOldSnapshotThresholdTimestamp()

TimestampTz GetOldSnapshotThresholdTimestamp ( void  )

Definition at line 1711 of file snapmgr.c.

References OldSnapshotControlData::mutex_threshold, SpinLockAcquire, SpinLockRelease, and OldSnapshotControlData::threshold_timestamp.

Referenced by TestForOldSnapshot_impl().

1712 {
1713  TimestampTz threshold_timestamp;
1714 
1716  threshold_timestamp = oldSnapshotControl->threshold_timestamp;
1718 
1719  return threshold_timestamp;
1720 }
int64 TimestampTz
Definition: timestamp.h:39
slock_t mutex_threshold
Definition: snapmgr.c:91
#define SpinLockAcquire(lock)
Definition: spin.h:62
TimestampTz threshold_timestamp
Definition: snapmgr.c:92
static volatile OldSnapshotControlData * oldSnapshotControl
Definition: snapmgr.c:129
#define SpinLockRelease(lock)
Definition: spin.h:64

◆ GetSnapshotCurrentTimestamp()

TimestampTz GetSnapshotCurrentTimestamp ( void  )

Definition at line 1686 of file snapmgr.c.

References OldSnapshotControlData::current_timestamp, GetCurrentTimestamp(), OldSnapshotControlData::mutex_current, now(), SpinLockAcquire, and SpinLockRelease.

Referenced by GetSnapshotData(), and TransactionIdLimitedForOldSnapshots().

1687 {
1689 
1690  /*
1691  * Don't let time move backward; if it hasn't advanced, use the old value.
1692  */
1694  if (now <= oldSnapshotControl->current_timestamp)
1696  else
1699 
1700  return now;
1701 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1570
int64 TimestampTz
Definition: timestamp.h:39
#define SpinLockAcquire(lock)
Definition: spin.h:62
TimestampTz current_timestamp
Definition: snapmgr.c:87
static volatile OldSnapshotControlData * oldSnapshotControl
Definition: snapmgr.c:129
#define SpinLockRelease(lock)
Definition: spin.h:64
slock_t mutex_current
Definition: snapmgr.c:86
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1534

◆ GetTransactionSnapshot()

Snapshot GetTransactionSnapshot ( void  )

Definition at line 304 of file snapmgr.c.

References Assert, CopySnapshot(), CurrentSnapshot, elog, ERROR, FirstSnapshotSet, GetSerializableTransactionSnapshot(), GetSnapshotData(), HistoricSnapshot, HistoricSnapshotActive(), InvalidateCatalogSnapshot(), IsInParallelMode(), IsolationIsSerializable, IsolationUsesXactSnapshot, pairingheap_add(), pairingheap_is_empty, SnapshotData::ph_node, and SnapshotData::regd_count.

Referenced by _bt_begin_parallel(), _SPI_execute_plan(), AfterTriggerFireDeferred(), AfterTriggerSetState(), apply_handle_delete(), apply_handle_insert(), apply_handle_update(), bt_check_every_level(), BuildCachedPlan(), CheckTargetForConflictsIn(), cluster(), DefineIndex(), exec_bind_message(), exec_eval_simple_expr(), exec_parse_message(), exec_simple_query(), execute_sql_string(), fmgr_sql(), get_database_list(), get_subscription_list(), GetLatestSnapshot(), HandleFunctionRequest(), IndexBuildHeapRangeScan(), initialize_worker_spi(), InitializeParallelDSM(), InitPostgres(), LogicalRepSyncTableStart(), pg_get_constraintdef_worker(), PortalRunMulti(), PortalRunUtility(), PortalStart(), ReindexMultipleTables(), RevalidateCachedQuery(), ri_PerformCheck(), SPI_cursor_open_internal(), vacuum(), vacuum_rel(), and XidIsConcurrent().

305 {
306  /*
307  * Return historic snapshot if doing logical decoding. We'll never need a
308  * non-historic transaction snapshot in this (sub-)transaction, so there's
309  * no need to be careful to set one up for later calls to
310  * GetTransactionSnapshot().
311  */
313  {
315  return HistoricSnapshot;
316  }
317 
318  /* First call in transaction? */
319  if (!FirstSnapshotSet)
320  {
321  /*
322  * Don't allow catalog snapshot to be older than xact snapshot. Must
323  * do this first to allow the empty-heap Assert to succeed.
324  */
326 
328  Assert(FirstXactSnapshot == NULL);
329 
330  if (IsInParallelMode())
331  elog(ERROR,
332  "cannot take query snapshot during a parallel operation");
333 
334  /*
335  * In transaction-snapshot mode, the first snapshot must live until
336  * end of xact regardless of what the caller does with it, so we must
337  * make a copy of it rather than returning CurrentSnapshotData
338  * directly. Furthermore, if we're running in serializable mode,
339  * predicate.c needs to wrap the snapshot fetch in its own processing.
340  */
342  {
343  /* First, create the snapshot in CurrentSnapshotData */
346  else
348  /* Make a saved copy */
351  /* Mark it as "registered" in FirstXactSnapshot */
354  }
355  else
357 
358  FirstSnapshotSet = true;
359  return CurrentSnapshot;
360  }
361 
363  return CurrentSnapshot;
364 
365  /* Don't allow catalog snapshot to be older than xact snapshot. */
367 
369 
370  return CurrentSnapshot;
371 }
#define IsolationUsesXactSnapshot()
Definition: xact.h:50
static Snapshot HistoricSnapshot
Definition: snapmgr.c:152
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
static SnapshotData CurrentSnapshotData
Definition: snapmgr.c:144
static Snapshot FirstXactSnapshot
Definition: snapmgr.c:210
uint32 regd_count
Definition: snapshot.h:110
static Snapshot CurrentSnapshot
Definition: snapmgr.c:149
bool IsInParallelMode(void)
Definition: xact.c:905
#define ERROR
Definition: elog.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
bool FirstSnapshotSet
Definition: snapmgr.c:203
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:510
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:660
pairingheap_node ph_node
Definition: snapshot.h:111
#define Assert(condition)
Definition: c.h:699
Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot)
Definition: predicate.c:1590
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1509
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2024
#define IsolationIsSerializable()
Definition: xact.h:51
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
#define elog
Definition: elog.h:219

◆ HistoricSnapshotActive()

bool HistoricSnapshotActive ( void  )

◆ HistoricSnapshotGetTupleCids()

HTAB* HistoricSnapshotGetTupleCids ( void  )

Definition at line 2030 of file snapmgr.c.

References Assert, HistoricSnapshotActive(), and tuplecid_data.

Referenced by HeapTupleSatisfiesHistoricMVCC().

2031 {
2033  return tuplecid_data;
2034 }
static HTAB * tuplecid_data
Definition: snapmgr.c:170
#define Assert(condition)
Definition: c.h:699
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2024

◆ ImportSnapshot()

void ImportSnapshot ( const char *  idstr)

Definition at line 1430 of file snapmgr.c.

References AllocateFile(), elog, ereport, errcode(), errmsg(), ERROR, FirstSnapshotSet, FreeFile(), GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), GetTopTransactionIdIfAny(), i, InvalidTransactionId, IsolationIsSerializable, IsolationUsesXactSnapshot, IsSubTransaction(), MAXPGPATH, MyDatabaseId, OidIsValid, palloc(), parseIntFromText(), parseVxidFromText(), parseXidFromText(), PG_BINARY_R, SetTransactionSnapshot(), SNAPSHOT_EXPORT_DIR, snprintf(), stat, SnapshotData::suboverflowed, SnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TransactionIdIsNormal, VirtualTransactionIdIsValid, XACT_SERIALIZABLE, XactReadOnly, SnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by ExecSetVariableStmt().

1431 {
1432  char path[MAXPGPATH];
1433  FILE *f;
1434  struct stat stat_buf;
1435  char *filebuf;
1436  int xcnt;
1437  int i;
1438  VirtualTransactionId src_vxid;
1439  int src_pid;
1440  Oid src_dbid;
1441  int src_isolevel;
1442  bool src_readonly;
1443  SnapshotData snapshot;
1444 
1445  /*
1446  * Must be at top level of a fresh transaction. Note in particular that
1447  * we check we haven't acquired an XID --- if we have, it's conceivable
1448  * that the snapshot would show it as not running, making for very screwy
1449  * behavior.
1450  */
1451  if (FirstSnapshotSet ||
1453  IsSubTransaction())
1454  ereport(ERROR,
1455  (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1456  errmsg("SET TRANSACTION SNAPSHOT must be called before any query")));
1457 
1458  /*
1459  * If we are in read committed mode then the next query would execute with
1460  * a new snapshot thus making this function call quite useless.
1461  */
1463  ereport(ERROR,
1464  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1465  errmsg("a snapshot-importing transaction must have isolation level SERIALIZABLE or REPEATABLE READ")));
1466 
1467  /*
1468  * Verify the identifier: only 0-9, A-F and hyphens are allowed. We do
1469  * this mainly to prevent reading arbitrary files.
1470  */
1471  if (strspn(idstr, "0123456789ABCDEF-") != strlen(idstr))
1472  ereport(ERROR,
1473  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1474  errmsg("invalid snapshot identifier: \"%s\"", idstr)));
1475 
1476  /* OK, read the file */
1477  snprintf(path, MAXPGPATH, SNAPSHOT_EXPORT_DIR "/%s", idstr);
1478 
1479  f = AllocateFile(path, PG_BINARY_R);
1480  if (!f)
1481  ereport(ERROR,
1482  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1483  errmsg("invalid snapshot identifier: \"%s\"", idstr)));
1484 
1485  /* get the size of the file so that we know how much memory we need */
1486  if (fstat(fileno(f), &stat_buf))
1487  elog(ERROR, "could not stat file \"%s\": %m", path);
1488 
1489  /* and read the file into a palloc'd string */
1490  filebuf = (char *) palloc(stat_buf.st_size + 1);
1491  if (fread(filebuf, stat_buf.st_size, 1, f) != 1)
1492  elog(ERROR, "could not read file \"%s\": %m", path);
1493 
1494  filebuf[stat_buf.st_size] = '\0';
1495 
1496  FreeFile(f);
1497 
1498  /*
1499  * Construct a snapshot struct by parsing the file content.
1500  */
1501  memset(&snapshot, 0, sizeof(snapshot));
1502 
1503  parseVxidFromText("vxid:", &filebuf, path, &src_vxid);
1504  src_pid = parseIntFromText("pid:", &filebuf, path);
1505  /* we abuse parseXidFromText a bit here ... */
1506  src_dbid = parseXidFromText("dbid:", &filebuf, path);
1507  src_isolevel = parseIntFromText("iso:", &filebuf, path);
1508  src_readonly = parseIntFromText("ro:", &filebuf, path);
1509 
1510  snapshot.xmin = parseXidFromText("xmin:", &filebuf, path);
1511  snapshot.xmax = parseXidFromText("xmax:", &filebuf, path);
1512 
1513  snapshot.xcnt = xcnt = parseIntFromText("xcnt:", &filebuf, path);
1514 
1515  /* sanity-check the xid count before palloc */
1516  if (xcnt < 0 || xcnt > GetMaxSnapshotXidCount())
1517  ereport(ERROR,
1518  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1519  errmsg("invalid snapshot data in file \"%s\"", path)));
1520 
1521  snapshot.xip = (TransactionId *) palloc(xcnt * sizeof(TransactionId));
1522  for (i = 0; i < xcnt; i++)
1523  snapshot.xip[i] = parseXidFromText("xip:", &filebuf, path);
1524 
1525  snapshot.suboverflowed = parseIntFromText("sof:", &filebuf, path);
1526 
1527  if (!snapshot.suboverflowed)
1528  {
1529  snapshot.subxcnt = xcnt = parseIntFromText("sxcnt:", &filebuf, path);
1530 
1531  /* sanity-check the xid count before palloc */
1532  if (xcnt < 0 || xcnt > GetMaxSnapshotSubxidCount())
1533  ereport(ERROR,
1534  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1535  errmsg("invalid snapshot data in file \"%s\"", path)));
1536 
1537  snapshot.subxip = (TransactionId *) palloc(xcnt * sizeof(TransactionId));
1538  for (i = 0; i < xcnt; i++)
1539  snapshot.subxip[i] = parseXidFromText("sxp:", &filebuf, path);
1540  }
1541  else
1542  {
1543  snapshot.subxcnt = 0;
1544  snapshot.subxip = NULL;
1545  }
1546 
1547  snapshot.takenDuringRecovery = parseIntFromText("rec:", &filebuf, path);
1548 
1549  /*
1550  * Do some additional sanity checking, just to protect ourselves. We
1551  * don't trouble to check the array elements, just the most critical
1552  * fields.
1553  */
1554  if (!VirtualTransactionIdIsValid(src_vxid) ||
1555  !OidIsValid(src_dbid) ||
1556  !TransactionIdIsNormal(snapshot.xmin) ||
1557  !TransactionIdIsNormal(snapshot.xmax))
1558  ereport(ERROR,
1559  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1560  errmsg("invalid snapshot data in file \"%s\"", path)));
1561 
1562  /*
1563  * If we're serializable, the source transaction must be too, otherwise
1564  * predicate.c has problems (SxactGlobalXmin could go backwards). Also, a
1565  * non-read-only transaction can't adopt a snapshot from a read-only
1566  * transaction, as predicate.c handles the cases very differently.
1567  */
1569  {
1570  if (src_isolevel != XACT_SERIALIZABLE)
1571  ereport(ERROR,
1572  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1573  errmsg("a serializable transaction cannot import a snapshot from a non-serializable transaction")));
1574  if (src_readonly && !XactReadOnly)
1575  ereport(ERROR,
1576  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1577  errmsg("a non-read-only serializable transaction cannot import a snapshot from a read-only transaction")));
1578  }
1579 
1580  /*
1581  * We cannot import a snapshot that was taken in a different database,
1582  * because vacuum calculates OldestXmin on a per-database basis; so the
1583  * source transaction's xmin doesn't protect us from data loss. This
1584  * restriction could be removed if the source transaction were to mark its
1585  * xmin as being globally applicable. But that would require some
1586  * additional syntax, since that has to be known when the snapshot is
1587  * initially taken. (See pgsql-hackers discussion of 2011-10-21.)
1588  */
1589  if (src_dbid != MyDatabaseId)
1590  ereport(ERROR,
1591  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1592  errmsg("cannot import a snapshot from a different database")));
1593 
1594  /* OK, install the snapshot */
1595  SetTransactionSnapshot(&snapshot, &src_vxid, src_pid, NULL);
1596 }
static TransactionId parseXidFromText(const char *prefix, char **s, const char *filename)
Definition: snapmgr.c:1375
uint32 TransactionId
Definition: c.h:474
static int parseIntFromText(const char *prefix, char **s, const char *filename)
Definition: snapmgr.c:1350
static void SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid, int sourcepid, PGPROC *sourceproc)
Definition: snapmgr.c:565
#define IsolationUsesXactSnapshot()
Definition: xact.h:50
int errcode(int sqlerrcode)
Definition: elog.c:575
bool suboverflowed
Definition: snapshot.h:93
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define PG_BINARY_R
Definition: c.h:1082
#define XACT_SERIALIZABLE
Definition: xact.h:38
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:213
#define ERROR
Definition: elog.h:43
struct stat stat_buf
Definition: pg_standby.c:103
bool FirstSnapshotSet
Definition: snapmgr.c:203
#define MAXPGPATH
static void parseVxidFromText(const char *prefix, char **s, const char *filename, VirtualTransactionId *vxid)
Definition: snapmgr.c:1400
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2336
#define InvalidTransactionId
Definition: transam.h:31
TransactionId xmax
Definition: snapshot.h:69
TransactionId xmin
Definition: snapshot.h:68
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:404
#define ereport(elevel, rest)
Definition: elog.h:122
TransactionId * xip
Definition: snapshot.h:79
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
#define stat(a, b)
Definition: win32_port.h:266
Oid MyDatabaseId
Definition: globals.c:84
int GetMaxSnapshotXidCount(void)
Definition: procarray.c:1456
bool XactReadOnly
Definition: xact.c:76
bool takenDuringRecovery
Definition: snapshot.h:95
int FreeFile(FILE *file)
Definition: fd.c:2528
bool IsSubTransaction(void)
Definition: xact.c:4495
uint32 xcnt
Definition: snapshot.h:80
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define IsolationIsSerializable()
Definition: xact.h:51
int i
int GetMaxSnapshotSubxidCount(void)
Definition: procarray.c:1467
#define elog
Definition: elog.h:219
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
TransactionId * subxip
Definition: snapshot.h:91
int32 subxcnt
Definition: snapshot.h:92

◆ InvalidateCatalogSnapshot()

void InvalidateCatalogSnapshot ( void  )

Definition at line 510 of file snapmgr.c.

References pairingheap_remove(), SnapshotData::ph_node, and SnapshotResetXmin().

Referenced by AtEOXact_Snapshot(), CopyFrom(), GetNonHistoricCatalogSnapshot(), GetTransactionSnapshot(), InitPostgres(), InvalidateCatalogSnapshotConditionally(), InvalidateSystemCaches(), LocalExecuteInvalidationMessage(), and SetTransactionSnapshot().

511 {
512  if (CatalogSnapshot)
513  {
515  CatalogSnapshot = NULL;
517  }
518 }
static void SnapshotResetXmin(void)
Definition: snapmgr.c:978
static Snapshot CatalogSnapshot
Definition: snapmgr.c:151
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
pairingheap_node ph_node
Definition: snapshot.h:111
void pairingheap_remove(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:170

◆ InvalidateCatalogSnapshotConditionally()

void InvalidateCatalogSnapshotConditionally ( void  )

Definition at line 531 of file snapmgr.c.

References InvalidateCatalogSnapshot(), and pairingheap_is_singular.

Referenced by PostgresMain().

532 {
533  if (CatalogSnapshot &&
534  ActiveSnapshot == NULL &&
537 }
static Snapshot CatalogSnapshot
Definition: snapmgr.c:151
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:510
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188
#define pairingheap_is_singular(h)
Definition: pairingheap.h:99

◆ MaintainOldSnapshotTimeMapping()

void MaintainOldSnapshotTimeMapping ( TimestampTz  whenTaken,
TransactionId  xmin 
)

Definition at line 1848 of file snapmgr.c.

References AlignTimestampToMinuteBoundary(), Assert, OldSnapshotControlData::count_used, DEBUG1, elog, OldSnapshotControlData::head_offset, OldSnapshotControlData::head_timestamp, i, OldSnapshotControlData::latest_xmin, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), OldSnapshotControlData::mutex_latest_xmin, OldSnapshotControlData::next_map_update, old_snapshot_threshold, OLD_SNAPSHOT_TIME_MAP_ENTRIES, SpinLockAcquire, SpinLockRelease, TransactionIdFollows(), TransactionIdIsNormal, TransactionIdPrecedes(), USECS_PER_MINUTE, and OldSnapshotControlData::xid_by_minute.

Referenced by GetSnapshotData().

1849 {
1850  TimestampTz ts;
1851  TransactionId latest_xmin;
1852  TimestampTz update_ts;
1853  bool map_update_required = false;
1854 
1855  /* Never call this function when old snapshot checking is disabled. */
1857 
1858  ts = AlignTimestampToMinuteBoundary(whenTaken);
1859 
1860  /*
1861  * Keep track of the latest xmin seen by any process. Update mapping with
1862  * a new value when we have crossed a bucket boundary.
1863  */
1865  latest_xmin = oldSnapshotControl->latest_xmin;
1866  update_ts = oldSnapshotControl->next_map_update;
1867  if (ts > update_ts)
1868  {
1870  map_update_required = true;
1871  }
1872  if (TransactionIdFollows(xmin, latest_xmin))
1875 
1876  /* We only needed to update the most recent xmin value. */
1877  if (!map_update_required)
1878  return;
1879 
1880  /* No further tracking needed for 0 (used for testing). */
1881  if (old_snapshot_threshold == 0)
1882  return;
1883 
1884  /*
1885  * We don't want to do something stupid with unusual values, but we don't
1886  * want to litter the log with warnings or break otherwise normal
1887  * processing for this feature; so if something seems unreasonable, just
1888  * log at DEBUG level and return without doing anything.
1889  */
1890  if (whenTaken < 0)
1891  {
1892  elog(DEBUG1,
1893  "MaintainOldSnapshotTimeMapping called with negative whenTaken = %ld",
1894  (long) whenTaken);
1895  return;
1896  }
1897  if (!TransactionIdIsNormal(xmin))
1898  {
1899  elog(DEBUG1,
1900  "MaintainOldSnapshotTimeMapping called with xmin = %lu",
1901  (unsigned long) xmin);
1902  return;
1903  }
1904 
1905  LWLockAcquire(OldSnapshotTimeMapLock, LW_EXCLUSIVE);
1906 
1912 
1913  if (oldSnapshotControl->count_used == 0)
1914  {
1915  /* set up first entry for empty mapping */
1919  oldSnapshotControl->xid_by_minute[0] = xmin;
1920  }
1921  else if (ts < oldSnapshotControl->head_timestamp)
1922  {
1923  /* old ts; log it at DEBUG */
1924  LWLockRelease(OldSnapshotTimeMapLock);
1925  elog(DEBUG1,
1926  "MaintainOldSnapshotTimeMapping called with old whenTaken = %ld",
1927  (long) whenTaken);
1928  return;
1929  }
1930  else if (ts <= (oldSnapshotControl->head_timestamp +
1932  * USECS_PER_MINUTE)))
1933  {
1934  /* existing mapping; advance xid if possible */
1935  int bucket = (oldSnapshotControl->head_offset
1937  / USECS_PER_MINUTE))
1939 
1941  oldSnapshotControl->xid_by_minute[bucket] = xmin;
1942  }
1943  else
1944  {
1945  /* We need a new bucket, but it might not be the very next one. */
1946  int advance = ((ts - oldSnapshotControl->head_timestamp)
1947  / USECS_PER_MINUTE);
1948 
1950 
1951  if (advance >= OLD_SNAPSHOT_TIME_MAP_ENTRIES)
1952  {
1953  /* Advance is so far that all old data is junk; start over. */
1956  oldSnapshotControl->xid_by_minute[0] = xmin;
1957  }
1958  else
1959  {
1960  /* Store the new value in one or more buckets. */
1961  int i;
1962 
1963  for (i = 0; i < advance; i++)
1964  {
1966  {
1967  /* Map full and new value replaces old head. */
1968  int old_head = oldSnapshotControl->head_offset;
1969 
1970  if (old_head == (OLD_SNAPSHOT_TIME_MAP_ENTRIES - 1))
1972  else
1973  oldSnapshotControl->head_offset = old_head + 1;
1974  oldSnapshotControl->xid_by_minute[old_head] = xmin;
1975  }
1976  else
1977  {
1978  /* Extend map to unused entry. */
1979  int new_tail = (oldSnapshotControl->head_offset
1982 
1984  oldSnapshotControl->xid_by_minute[new_tail] = xmin;
1985  }
1986  }
1987  }
1988  }
1989 
1990  LWLockRelease(OldSnapshotTimeMapLock);
1991 }
#define DEBUG1
Definition: elog.h:25
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:474
int64 TimestampTz
Definition: timestamp.h:39
#define USECS_PER_MINUTE
Definition: timestamp.h:93
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define SpinLockAcquire(lock)
Definition: spin.h:62
slock_t mutex_latest_xmin
Definition: snapmgr.c:88
TimestampTz next_map_update
Definition: snapmgr.c:90
static volatile OldSnapshotControlData * oldSnapshotControl
Definition: snapmgr.c:129
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define SpinLockRelease(lock)
Definition: spin.h:64
TransactionId latest_xmin
Definition: snapmgr.c:89
#define Assert(condition)
Definition: c.h:699
TransactionId xid_by_minute[FLEXIBLE_ARRAY_MEMBER]
Definition: snapmgr.c:126
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static TimestampTz AlignTimestampToMinuteBoundary(TimestampTz ts)
Definition: snapmgr.c:1672
int old_snapshot_threshold
Definition: snapmgr.c:75
TimestampTz head_timestamp
Definition: snapmgr.c:124
int i
#define elog
Definition: elog.h:219
#define OLD_SNAPSHOT_TIME_MAP_ENTRIES
Definition: snapmgr.h:32
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

◆ parseIntFromText()

static int parseIntFromText ( const char *  prefix,
char **  s,
const char *  filename 
)
static

Definition at line 1350 of file snapmgr.c.

References ereport, errcode(), errmsg(), ERROR, and val.

Referenced by ImportSnapshot().

1351 {
1352  char *ptr = *s;
1353  int prefixlen = strlen(prefix);
1354  int val;
1355 
1356  if (strncmp(ptr, prefix, prefixlen) != 0)
1357  ereport(ERROR,
1358  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1359  errmsg("invalid snapshot data in file \"%s\"", filename)));
1360  ptr += prefixlen;
1361  if (sscanf(ptr, "%d", &val) != 1)
1362  ereport(ERROR,
1363  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1364  errmsg("invalid snapshot data in file \"%s\"", filename)));
1365  ptr = strchr(ptr, '\n');
1366  if (!ptr)
1367  ereport(ERROR,
1368  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1369  errmsg("invalid snapshot data in file \"%s\"", filename)));
1370  *s = ptr + 1;
1371  return val;
1372 }
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
static char * filename
Definition: pg_dumpall.c:87
int errmsg(const char *fmt,...)
Definition: elog.c:797
long val
Definition: informix.c:689

◆ parseVxidFromText()

static void parseVxidFromText ( const char *  prefix,
char **  s,
const char *  filename,
VirtualTransactionId vxid 
)
static

Definition at line 1400 of file snapmgr.c.

References VirtualTransactionId::backendId, ereport, errcode(), errmsg(), ERROR, and VirtualTransactionId::localTransactionId.

Referenced by ImportSnapshot().

1402 {
1403  char *ptr = *s;
1404  int prefixlen = strlen(prefix);
1405 
1406  if (strncmp(ptr, prefix, prefixlen) != 0)
1407  ereport(ERROR,
1408  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1409  errmsg("invalid snapshot data in file \"%s\"", filename)));
1410  ptr += prefixlen;
1411  if (sscanf(ptr, "%d/%u", &vxid->backendId, &vxid->localTransactionId) != 2)
1412  ereport(ERROR,
1413  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1414  errmsg("invalid snapshot data in file \"%s\"", filename)));
1415  ptr = strchr(ptr, '\n');
1416  if (!ptr)
1417  ereport(ERROR,
1418  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1419  errmsg("invalid snapshot data in file \"%s\"", filename)));
1420  *s = ptr + 1;
1421 }
int errcode(int sqlerrcode)
Definition: elog.c:575
LocalTransactionId localTransactionId
Definition: lock.h:66
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
BackendId backendId
Definition: lock.h:65
static char * filename
Definition: pg_dumpall.c:87
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ parseXidFromText()

static TransactionId parseXidFromText ( const char *  prefix,
char **  s,
const char *  filename 
)
static

Definition at line 1375 of file snapmgr.c.

References ereport, errcode(), errmsg(), ERROR, and val.

Referenced by ImportSnapshot().

1376 {
1377  char *ptr = *s;
1378  int prefixlen = strlen(prefix);
1380 
1381  if (strncmp(ptr, prefix, prefixlen) != 0)
1382  ereport(ERROR,
1383  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1384  errmsg("invalid snapshot data in file \"%s\"", filename)));
1385  ptr += prefixlen;
1386  if (sscanf(ptr, "%u", &val) != 1)
1387  ereport(ERROR,
1388  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1389  errmsg("invalid snapshot data in file \"%s\"", filename)));
1390  ptr = strchr(ptr, '\n');
1391  if (!ptr)
1392  ereport(ERROR,
1393  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1394  errmsg("invalid snapshot data in file \"%s\"", filename)));
1395  *s = ptr + 1;
1396  return val;
1397 }
uint32 TransactionId
Definition: c.h:474
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
static char * filename
Definition: pg_dumpall.c:87
int errmsg(const char *fmt,...)
Definition: elog.c:797
long val
Definition: informix.c:689

◆ pg_export_snapshot()

Datum pg_export_snapshot ( PG_FUNCTION_ARGS  )

Definition at line 1335 of file snapmgr.c.

References cstring_to_text(), ExportSnapshot(), GetActiveSnapshot(), and PG_RETURN_TEXT_P.

1336 {
1337  char *snapshotName;
1338 
1339  snapshotName = ExportSnapshot(GetActiveSnapshot());
1340  PG_RETURN_TEXT_P(cstring_to_text(snapshotName));
1341 }
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:839
char * ExportSnapshot(Snapshot snapshot)
Definition: snapmgr.c:1159
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:336
text * cstring_to_text(const char *s)
Definition: varlena.c:149

◆ PopActiveSnapshot()

void PopActiveSnapshot ( void  )

Definition at line 812 of file snapmgr.c.

References SnapshotData::active_count, ActiveSnapshotElt::as_next, ActiveSnapshotElt::as_snap, Assert, FreeSnapshot(), pfree(), SnapshotData::regd_count, and SnapshotResetXmin().

Referenced by _SPI_execute_plan(), AfterTriggerFireDeferred(), AfterTriggerSetState(), apply_handle_delete(), apply_handle_insert(), apply_handle_update(), BuildCachedPlan(), cluster(), DefineIndex(), DoPortalRewind(), EndCopyTo(), exec_bind_message(), exec_eval_simple_expr(), exec_parse_message(), exec_simple_query(), ExecCreateTableAs(), execute_sql_string(), ExplainOnePlan(), fmgr_sql(), HandleFunctionRequest(), index_drop(), initialize_worker_spi(), LogicalRepSyncTableStart(), movedb(), ParallelWorkerMain(), PersistHoldablePortal(), PortalRunMulti(), PortalRunSelect(), PortalRunUtility(), PortalStart(), refresh_matview_datafill(), ReindexMultipleTables(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RevalidateCachedQuery(), ShutdownSQLFunction(), SPI_commit(), vacuum(), vacuum_rel(), and wait_for_relation_state_change().

813 {
814  ActiveSnapshotElt *newstack;
815 
816  newstack = ActiveSnapshot->as_next;
817 
819 
821 
822  if (ActiveSnapshot->as_snap->active_count == 0 &&
825 
827  ActiveSnapshot = newstack;
828  if (ActiveSnapshot == NULL)
829  OldestActiveSnapshot = NULL;
830 
832 }
Snapshot as_snap
Definition: snapmgr.c:182
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:715
static void SnapshotResetXmin(void)
Definition: snapmgr.c:978
uint32 regd_count
Definition: snapshot.h:110
void pfree(void *pointer)
Definition: mcxt.c:1031
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:191
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:184
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188
#define Assert(condition)
Definition: c.h:699
uint32 active_count
Definition: snapshot.h:109

◆ PushActiveSnapshot()

void PushActiveSnapshot ( Snapshot  snap)

Definition at line 733 of file snapmgr.c.

References SnapshotData::active_count, ActiveSnapshot, ActiveSnapshotElt::as_level, ActiveSnapshotElt::as_next, ActiveSnapshotElt::as_snap, Assert, SnapshotData::copied, CopySnapshot(), GetCurrentTransactionNestLevel(), InvalidSnapshot, MemoryContextAlloc(), and TopTransactionContext.

Referenced by _SPI_execute_plan(), AfterTriggerFireDeferred(), AfterTriggerSetState(), apply_handle_delete(), apply_handle_insert(), apply_handle_update(), BuildCachedPlan(), cluster(), DefineIndex(), DoPortalRewind(), exec_bind_message(), exec_eval_simple_expr(), exec_parse_message(), exec_simple_query(), execute_sql_string(), fmgr_sql(), HandleFunctionRequest(), initialize_worker_spi(), LogicalRepSyncTableStart(), ParallelWorkerMain(), PersistHoldablePortal(), PortalRunSelect(), PortalRunUtility(), PortalStart(), PushCopiedSnapshot(), ReindexMultipleTables(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RevalidateCachedQuery(), ShutdownSQLFunction(), vacuum(), vacuum_rel(), and wait_for_relation_state_change().

734 {
735  ActiveSnapshotElt *newactive;
736 
737  Assert(snap != InvalidSnapshot);
738 
740 
741  /*
742  * Checking SecondarySnapshot is probably useless here, but it seems
743  * better to be sure.
744  */
745  if (snap == CurrentSnapshot || snap == SecondarySnapshot || !snap->copied)
746  newactive->as_snap = CopySnapshot(snap);
747  else
748  newactive->as_snap = snap;
749 
750  newactive->as_next = ActiveSnapshot;
752 
753  newactive->as_snap->active_count++;
754 
755  ActiveSnapshot = newactive;
756  if (OldestActiveSnapshot == NULL)
758 }
Snapshot as_snap
Definition: snapmgr.c:182
MemoryContext TopTransactionContext
Definition: mcxt.c:49
bool copied
Definition: snapshot.h:96
static Snapshot CurrentSnapshot
Definition: snapmgr.c:149
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:191
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:184
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188
#define InvalidSnapshot
Definition: snapshot.h:25
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:660
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:753
#define Assert(condition)
Definition: c.h:699
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
static Snapshot SecondarySnapshot
Definition: snapmgr.c:150
uint32 active_count
Definition: snapshot.h:109

◆ PushCopiedSnapshot()

void PushCopiedSnapshot ( Snapshot  snapshot)

Definition at line 769 of file snapmgr.c.

References CopySnapshot(), and PushActiveSnapshot().

Referenced by _SPI_execute_plan(), BeginCopy(), ExecCreateTableAs(), ExplainOnePlan(), PortalRunMulti(), and refresh_matview_datafill().

770 {
771  PushActiveSnapshot(CopySnapshot(snapshot));
772 }
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:660

◆ RegisterSnapshot()

◆ RegisterSnapshotOnOwner()

Snapshot RegisterSnapshotOnOwner ( Snapshot  snapshot,
ResourceOwner  owner 
)

Definition at line 876 of file snapmgr.c.

References SnapshotData::copied, CopySnapshot(), InvalidSnapshot, pairingheap_add(), SnapshotData::ph_node, SnapshotData::regd_count, ResourceOwnerEnlargeSnapshots(), and ResourceOwnerRememberSnapshot().

Referenced by inv_open(), and RegisterSnapshot().

877 {
878  Snapshot snap;
879 
880  if (snapshot == InvalidSnapshot)
881  return InvalidSnapshot;
882 
883  /* Static snapshot? Create a persistent copy */
884  snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
885 
886  /* and tell resowner.c about it */
888  snap->regd_count++;
889  ResourceOwnerRememberSnapshot(owner, snap);
890 
891  if (snap->regd_count == 1)
893 
894  return snap;
895 }
bool copied
Definition: snapshot.h:96
void ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
Definition: resowner.c:1142
uint32 regd_count
Definition: snapshot.h:110
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
#define InvalidSnapshot
Definition: snapshot.h:25
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:660
pairingheap_node ph_node
Definition: snapshot.h:111
void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1153
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112

◆ RestoreSnapshot()

Snapshot RestoreSnapshot ( char *  start_address)

Definition at line 2127 of file snapmgr.c.

References SnapshotData::active_count, SnapshotData::copied, SnapshotData::curcid, SerializedSnapshotData::curcid, HeapTupleSatisfiesMVCC(), SnapshotData::lsn, SerializedSnapshotData::lsn, MemoryContextAlloc(), SnapshotData::regd_count, SnapshotData::satisfies, SnapshotData::suboverflowed, SerializedSnapshotData::suboverflowed, SnapshotData::subxcnt, SerializedSnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, SerializedSnapshotData::takenDuringRecovery, TopTransactionContext, SnapshotData::whenTaken, SerializedSnapshotData::whenTaken, SnapshotData::xcnt, SerializedSnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, SerializedSnapshotData::xmax, SnapshotData::xmin, and SerializedSnapshotData::xmin.

Referenced by ExecBitmapHeapInitializeWorker(), heap_beginscan_parallel(), index_beginscan_parallel(), and ParallelWorkerMain().

2128 {
2129  SerializedSnapshotData serialized_snapshot;
2130  Size size;
2131  Snapshot snapshot;
2132  TransactionId *serialized_xids;
2133 
2134  memcpy(&serialized_snapshot, start_address,
2135  sizeof(SerializedSnapshotData));
2136  serialized_xids = (TransactionId *)
2137  (start_address + sizeof(SerializedSnapshotData));
2138 
2139  /* We allocate any XID arrays needed in the same palloc block. */
2140  size = sizeof(SnapshotData)
2141  + serialized_snapshot.xcnt * sizeof(TransactionId)
2142  + serialized_snapshot.subxcnt * sizeof(TransactionId);
2143 
2144  /* Copy all required fields */
2146  snapshot->satisfies = HeapTupleSatisfiesMVCC;
2147  snapshot->xmin = serialized_snapshot.xmin;
2148  snapshot->xmax = serialized_snapshot.xmax;
2149  snapshot->xip = NULL;
2150  snapshot->xcnt = serialized_snapshot.xcnt;
2151  snapshot->subxip = NULL;
2152  snapshot->subxcnt = serialized_snapshot.subxcnt;
2153  snapshot->suboverflowed = serialized_snapshot.suboverflowed;
2154  snapshot->takenDuringRecovery = serialized_snapshot.takenDuringRecovery;
2155  snapshot->curcid = serialized_snapshot.curcid;
2156  snapshot->whenTaken = serialized_snapshot.whenTaken;
2157  snapshot->lsn = serialized_snapshot.lsn;
2158 
2159  /* Copy XIDs, if present. */
2160  if (serialized_snapshot.xcnt > 0)
2161  {
2162  snapshot->xip = (TransactionId *) (snapshot + 1);
2163  memcpy(snapshot->xip, serialized_xids,
2164  serialized_snapshot.xcnt * sizeof(TransactionId));
2165  }
2166 
2167  /* Copy SubXIDs, if present. */
2168  if (serialized_snapshot.subxcnt > 0)
2169  {
2170  snapshot->subxip = ((TransactionId *) (snapshot + 1)) +
2171  serialized_snapshot.xcnt;
2172  memcpy(snapshot->subxip, serialized_xids + serialized_snapshot.xcnt,
2173  serialized_snapshot.subxcnt * sizeof(TransactionId));
2174  }
2175 
2176  /* Set the copied flag so that the caller will set refcounts correctly. */
2177  snapshot->regd_count = 0;
2178  snapshot->active_count = 0;
2179  snapshot->copied = true;
2180 
2181  return snapshot;
2182 }
SnapshotSatisfiesFunc satisfies
Definition: snapshot.h:55
MemoryContext TopTransactionContext
Definition: mcxt.c:49
uint32 TransactionId
Definition: c.h:474
bool copied
Definition: snapshot.h:96
XLogRecPtr lsn
Definition: snapshot.h:114
TimestampTz whenTaken
Definition: snapmgr.c:246
bool suboverflowed
Definition: snapshot.h:93
struct SnapshotData * Snapshot
Definition: snapshot.h:23
uint32 regd_count
Definition: snapshot.h:110
struct SnapshotData SnapshotData
TransactionId xmax
Definition: snapshot.h:69
TransactionId xmin
Definition: snapshot.h:68
TransactionId * xip
Definition: snapshot.h:79
TransactionId xmax
Definition: snapmgr.c:240
CommandId curcid
Definition: snapshot.h:98
bool takenDuringRecovery
Definition: snapshot.h:95
size_t Size
Definition: c.h:433
uint32 xcnt
Definition: snapshot.h:80
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
TransactionId xmin
Definition: snapmgr.c:239
TimestampTz whenTaken
Definition: snapshot.h:113
bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
Definition: tqual.c:963
TransactionId * subxip
Definition: snapshot.h:91
uint32 active_count
Definition: snapshot.h:109
int32 subxcnt
Definition: snapshot.h:92

◆ RestoreTransactionSnapshot()

void RestoreTransactionSnapshot ( Snapshot  snapshot,
void *  master_pgproc 
)

Definition at line 2191 of file snapmgr.c.

References InvalidPid, and SetTransactionSnapshot().

Referenced by CreateReplicationSlot(), and ParallelWorkerMain().

2192 {
2193  SetTransactionSnapshot(snapshot, NULL, InvalidPid, master_pgproc);
2194 }
static void SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid, int sourcepid, PGPROC *sourceproc)
Definition: snapmgr.c:565
#define InvalidPid
Definition: miscadmin.h:31

◆ SerializeSnapshot()

void SerializeSnapshot ( Snapshot  snapshot,
char *  start_address 
)

Definition at line 2068 of file snapmgr.c.

References Assert, SnapshotData::curcid, SerializedSnapshotData::curcid, SnapshotData::lsn, SerializedSnapshotData::lsn, SnapshotData::suboverflowed, SerializedSnapshotData::suboverflowed, SnapshotData::subxcnt, SerializedSnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, SerializedSnapshotData::takenDuringRecovery, SnapshotData::whenTaken, SerializedSnapshotData::whenTaken, SnapshotData::xcnt, SerializedSnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, SerializedSnapshotData::xmax, SnapshotData::xmin, and SerializedSnapshotData::xmin.

Referenced by ExecBitmapHeapInitializeDSM(), heap_parallelscan_initialize(), index_parallelscan_initialize(), and InitializeParallelDSM().

2069 {
2070  SerializedSnapshotData serialized_snapshot;
2071 
2072  Assert(snapshot->subxcnt >= 0);
2073 
2074  /* Copy all required fields */
2075  serialized_snapshot.xmin = snapshot->xmin;
2076  serialized_snapshot.xmax = snapshot->xmax;
2077  serialized_snapshot.xcnt = snapshot->xcnt;
2078  serialized_snapshot.subxcnt = snapshot->subxcnt;
2079  serialized_snapshot.suboverflowed = snapshot->suboverflowed;
2080  serialized_snapshot.takenDuringRecovery = snapshot->takenDuringRecovery;
2081  serialized_snapshot.curcid = snapshot->curcid;
2082  serialized_snapshot.whenTaken = snapshot->whenTaken;
2083  serialized_snapshot.lsn = snapshot->lsn;
2084 
2085  /*
2086  * Ignore the SubXID array if it has overflowed, unless the snapshot was
2087  * taken during recovery - in that case, top-level XIDs are in subxip as
2088  * well, and we mustn't lose them.
2089  */
2090  if (serialized_snapshot.suboverflowed && !snapshot->takenDuringRecovery)
2091  serialized_snapshot.subxcnt = 0;
2092 
2093  /* Copy struct to possibly-unaligned buffer */
2094  memcpy(start_address,
2095  &serialized_snapshot, sizeof(SerializedSnapshotData));
2096 
2097  /* Copy XID array */
2098  if (snapshot->xcnt > 0)
2099  memcpy((TransactionId *) (start_address +
2100  sizeof(SerializedSnapshotData)),
2101  snapshot->xip, snapshot->xcnt * sizeof(TransactionId));
2102 
2103  /*
2104  * Copy SubXID array. Don't bother to copy it if it had overflowed,
2105  * though, because it's not used anywhere in that case. Except if it's a
2106  * snapshot taken during recovery; all the top-level XIDs are in subxip as
2107  * well in that case, so we mustn't lose them.
2108  */
2109  if (serialized_snapshot.subxcnt > 0)
2110  {
2111  Size subxipoff = sizeof(SerializedSnapshotData) +
2112  snapshot->xcnt * sizeof(TransactionId);
2113 
2114  memcpy((TransactionId *) (start_address + subxipoff),
2115  snapshot->subxip, snapshot->subxcnt * sizeof(TransactionId));
2116  }
2117 }
uint32 TransactionId
Definition: c.h:474
XLogRecPtr lsn
Definition: snapshot.h:114
TimestampTz whenTaken
Definition: snapmgr.c:246
bool suboverflowed
Definition: snapshot.h:93
struct SerializedSnapshotData SerializedSnapshotData
TransactionId xmax
Definition: snapshot.h:69
TransactionId xmin
Definition: snapshot.h:68
TransactionId * xip
Definition: snapshot.h:79
TransactionId xmax
Definition: snapmgr.c:240
CommandId curcid
Definition: snapshot.h:98
#define Assert(condition)
Definition: c.h:699
bool takenDuringRecovery
Definition: snapshot.h:95
size_t Size
Definition: c.h:433
uint32 xcnt
Definition: snapshot.h:80
TransactionId xmin
Definition: snapmgr.c:239
TimestampTz whenTaken
Definition: snapshot.h:113
TransactionId * subxip
Definition: snapshot.h:91
int32 subxcnt
Definition: snapshot.h:92

◆ SetOldSnapshotThresholdTimestamp()

static void SetOldSnapshotThresholdTimestamp ( TimestampTz  ts,
TransactionId  xlimit 
)
static

Definition at line 1723 of file snapmgr.c.

References OldSnapshotControlData::mutex_threshold, SpinLockAcquire, SpinLockRelease, OldSnapshotControlData::threshold_timestamp, and OldSnapshotControlData::threshold_xid.

Referenced by TransactionIdLimitedForOldSnapshots().

1724 {
1729 }
slock_t mutex_threshold
Definition: snapmgr.c:91
#define SpinLockAcquire(lock)
Definition: spin.h:62
TimestampTz threshold_timestamp
Definition: snapmgr.c:92
TransactionId threshold_xid
Definition: snapmgr.c:93
static volatile OldSnapshotControlData * oldSnapshotControl
Definition: snapmgr.c:129
#define SpinLockRelease(lock)
Definition: spin.h:64

◆ SetTransactionSnapshot()

static void SetTransactionSnapshot ( Snapshot  sourcesnap,
VirtualTransactionId sourcevxid,
int  sourcepid,
PGPROC sourceproc 
)
static

Definition at line 565 of file snapmgr.c.

References Assert, CopySnapshot(), CurrentSnapshot, ereport, errcode(), errdetail(), errmsg(), ERROR, FirstSnapshotSet, GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), GetSnapshotData(), HistoricSnapshotActive(), InvalidateCatalogSnapshot(), IsolationIsSerializable, IsolationUsesXactSnapshot, pairingheap_add(), pairingheap_is_empty, SnapshotData::ph_node, ProcArrayInstallImportedXmin(), ProcArrayInstallRestoredXmin(), SnapshotData::regd_count, SetSerializableTransactionSnapshot(), SnapshotData::suboverflowed, SnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, SnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by ImportSnapshot(), and RestoreTransactionSnapshot().

567 {
568  /* Caller should have checked this already */
570 
571  /* Better do this to ensure following Assert succeeds. */
573 
575  Assert(FirstXactSnapshot == NULL);
577 
578  /*
579  * Even though we are not going to use the snapshot it computes, we must
580  * call GetSnapshotData, for two reasons: (1) to be sure that
581  * CurrentSnapshotData's XID arrays have been allocated, and (2) to update
582  * RecentXmin and RecentGlobalXmin. (We could alternatively include those
583  * two variables in exported snapshot files, but it seems better to have
584  * snapshot importers compute reasonably up-to-date values for them.)
585  */
587 
588  /*
589  * Now copy appropriate fields from the source snapshot.
590  */
591  CurrentSnapshot->xmin = sourcesnap->xmin;
592  CurrentSnapshot->xmax = sourcesnap->xmax;
593  CurrentSnapshot->xcnt = sourcesnap->xcnt;
594  Assert(sourcesnap->xcnt <= GetMaxSnapshotXidCount());
595  memcpy(CurrentSnapshot->xip, sourcesnap->xip,
596  sourcesnap->xcnt * sizeof(TransactionId));
597  CurrentSnapshot->subxcnt = sourcesnap->subxcnt;
598  Assert(sourcesnap->subxcnt <= GetMaxSnapshotSubxidCount());
599  memcpy(CurrentSnapshot->subxip, sourcesnap->subxip,
600  sourcesnap->subxcnt * sizeof(TransactionId));
603  /* NB: curcid should NOT be copied, it's a local matter */
604 
605  /*
606  * Now we have to fix what GetSnapshotData did with MyPgXact->xmin and
607  * TransactionXmin. There is a race condition: to make sure we are not
608  * causing the global xmin to go backwards, we have to test that the
609  * source transaction is still running, and that has to be done
610  * atomically. So let procarray.c do it.
611  *
612  * Note: in serializable mode, predicate.c will do this a second time. It
613  * doesn't seem worth contorting the logic here to avoid two calls,
614  * especially since it's not clear that predicate.c *must* do this.
615  */
616  if (sourceproc != NULL)
617  {
619  ereport(ERROR,
620  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
621  errmsg("could not import the requested snapshot"),
622  errdetail("The source transaction is not running anymore.")));
623  }
624  else if (!ProcArrayInstallImportedXmin(CurrentSnapshot->xmin, sourcevxid))
625  ereport(ERROR,
626  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
627  errmsg("could not import the requested snapshot"),
628  errdetail("The source process with PID %d is not running anymore.",
629  sourcepid)));
630 
631  /*
632  * In transaction-snapshot mode, the first snapshot must live until end of
633  * xact, so we must make a copy of it. Furthermore, if we're running in
634  * serializable mode, predicate.c needs to do its own processing.
635  */
637  {
640  sourcepid);
641  /* Make a saved copy */
644  /* Mark it as "registered" in FirstXactSnapshot */
647  }
648 
649  FirstSnapshotSet = true;
650 }
void SetSerializableTransactionSnapshot(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1630
uint32 TransactionId
Definition: c.h:474
#define IsolationUsesXactSnapshot()
Definition: xact.h:50
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
int errcode(int sqlerrcode)
Definition: elog.c:575
bool suboverflowed
Definition: snapshot.h:93
static SnapshotData CurrentSnapshotData
Definition: snapmgr.c:144
static Snapshot FirstXactSnapshot
Definition: snapmgr.c:210
uint32 regd_count
Definition: snapshot.h:110
static Snapshot CurrentSnapshot
Definition: snapmgr.c:149
#define ERROR
Definition: elog.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
bool FirstSnapshotSet
Definition: snapmgr.c:203
int errdetail(const char *fmt,...)
Definition: elog.c:873
TransactionId xmax
Definition: snapshot.h:69
TransactionId xmin
Definition: snapshot.h:68
#define ereport(elevel, rest)
Definition: elog.h:122
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:510
TransactionId * xip
Definition: snapshot.h:79
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:660
int GetMaxSnapshotXidCount(void)
Definition: procarray.c:1456
pairingheap_node ph_node
Definition: snapshot.h:111
#define Assert(condition)
Definition: c.h:699
bool takenDuringRecovery
Definition: snapshot.h:95
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1509
bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc)
Definition: procarray.c:1872
uint32 xcnt
Definition: snapshot.h:80
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2024
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define IsolationIsSerializable()
Definition: xact.h:51
int GetMaxSnapshotSubxidCount(void)
Definition: procarray.c:1467
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:1797
TransactionId * subxip
Definition: snapshot.h:91
int32 subxcnt
Definition: snapshot.h:92

◆ SetupHistoricSnapshot()

void SetupHistoricSnapshot ( Snapshot  historic_snapshot,
HTAB tuplecids 
)

Definition at line 2001 of file snapmgr.c.

References Assert.

Referenced by ReorderBufferCommit(), and ReorderBufferQueueMessage().

2002 {
2003  Assert(historic_snapshot != NULL);
2004 
2005  /* setup the timetravel snapshot */
2006  HistoricSnapshot = historic_snapshot;
2007 
2008  /* setup (cmin, cmax) lookup hash */
2009  tuplecid_data = tuplecids;
2010 }
static Snapshot HistoricSnapshot
Definition: snapmgr.c:152
static HTAB * tuplecid_data
Definition: snapmgr.c:170
#define Assert(condition)
Definition: c.h:699

◆ SnapMgrInit()

void SnapMgrInit ( void  )

Definition at line 267 of file snapmgr.c.

References OldSnapshotControlData::count_used, OldSnapshotControlData::current_timestamp, OldSnapshotControlData::head_offset, OldSnapshotControlData::head_timestamp, InvalidTransactionId, OldSnapshotControlData::latest_xmin, OldSnapshotControlData::mutex_current, OldSnapshotControlData::mutex_latest_xmin, OldSnapshotControlData::mutex_threshold, OldSnapshotControlData::next_map_update, ShmemInitStruct(), SnapMgrShmemSize(), SpinLockInit, OldSnapshotControlData::threshold_timestamp, and OldSnapshotControlData::threshold_xid.

Referenced by CreateSharedMemoryAndSemaphores().

268 {
269  bool found;
270 
271  /*
272  * Create or attach to the OldSnapshotControlData structure.
273  */
275  ShmemInitStruct("OldSnapshotControlData",
276  SnapMgrShmemSize(), &found);
277 
278  if (!found)
279  {
291  }
292 }
slock_t mutex_threshold
Definition: snapmgr.c:91
#define SpinLockInit(lock)
Definition: spin.h:60
TimestampTz threshold_timestamp
Definition: snapmgr.c:92
slock_t mutex_latest_xmin
Definition: snapmgr.c:88
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
TimestampTz next_map_update
Definition: snapmgr.c:90
TimestampTz current_timestamp
Definition: snapmgr.c:87
TransactionId threshold_xid
Definition: snapmgr.c:93
#define InvalidTransactionId
Definition: transam.h:31
static volatile OldSnapshotControlData * oldSnapshotControl
Definition: snapmgr.c:129
TransactionId latest_xmin
Definition: snapmgr.c:89
slock_t mutex_current
Definition: snapmgr.c:86
TimestampTz head_timestamp
Definition: snapmgr.c:124
Size SnapMgrShmemSize(void)
Definition: snapmgr.c:251

◆ SnapMgrShmemSize()

Size SnapMgrShmemSize ( void  )

Definition at line 251 of file snapmgr.c.

References add_size(), mul_size(), offsetof, old_snapshot_threshold, OLD_SNAPSHOT_TIME_MAP_ENTRIES, and OldSnapshotControlData::xid_by_minute.

Referenced by CreateSharedMemoryAndSemaphores(), and SnapMgrInit().

252 {
253  Size size;
254 
255  size = offsetof(OldSnapshotControlData, xid_by_minute);
256  if (old_snapshot_threshold > 0)
257  size = add_size(size, mul_size(sizeof(TransactionId),
259 
260  return size;
261 }
uint32 TransactionId
Definition: c.h:474
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
size_t Size
Definition: c.h:433
int old_snapshot_threshold
Definition: snapmgr.c:75
#define OLD_SNAPSHOT_TIME_MAP_ENTRIES
Definition: snapmgr.h:32
#define offsetof(type, field)
Definition: c.h:622

◆ SnapshotResetXmin()

static void SnapshotResetXmin ( void  )
static

Definition at line 978 of file snapmgr.c.

References InvalidTransactionId, MyPgXact, pairingheap_container, pairingheap_first(), pairingheap_is_empty, TransactionIdPrecedes(), SnapshotData::xmin, and PGXACT::xmin.

Referenced by AtEOXact_Snapshot(), AtSubAbort_Snapshot(), InvalidateCatalogSnapshot(), PopActiveSnapshot(), and UnregisterSnapshotFromOwner().

979 {
980  Snapshot minSnapshot;
981 
982  if (ActiveSnapshot != NULL)
983  return;
984 
986  {
988  return;
989  }
990 
991  minSnapshot = pairingheap_container(SnapshotData, ph_node,
993 
994  if (TransactionIdPrecedes(MyPgXact->xmin, minSnapshot->xmin))
995  MyPgXact->xmin = minSnapshot->xmin;
996 }
pairingheap_node * pairingheap_first(pairingheap *heap)
Definition: pairingheap.c:130
TransactionId xmin
Definition: proc.h:225
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
PGXACT * MyPgXact
Definition: proc.c:68
#define pairingheap_container(type, membername, ptr)
Definition: pairingheap.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
#define InvalidTransactionId
Definition: transam.h:31
TransactionId xmin
Definition: snapshot.h:68
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188

◆ SnapshotSetCommandId()

void SnapshotSetCommandId ( CommandId  curcid)

Definition at line 544 of file snapmgr.c.

References SnapshotData::curcid, and FirstSnapshotSet.

Referenced by CommandCounterIncrement().

545 {
546  if (!FirstSnapshotSet)
547  return;
548 
549  if (CurrentSnapshot)
550  CurrentSnapshot->curcid = curcid;
551  if (SecondarySnapshot)
552  SecondarySnapshot->curcid = curcid;
553  /* Should we do the same with CatalogSnapshot? */
554 }
static Snapshot CurrentSnapshot
Definition: snapmgr.c:149
bool FirstSnapshotSet
Definition: snapmgr.c:203
CommandId curcid
Definition: snapshot.h:98
static Snapshot SecondarySnapshot
Definition: snapmgr.c:150

◆ TeardownHistoricSnapshot()

void TeardownHistoricSnapshot ( bool  is_error)

Definition at line 2017 of file snapmgr.c.

Referenced by ReorderBufferCommit(), and ReorderBufferQueueMessage().

2018 {
2019  HistoricSnapshot = NULL;
2020  tuplecid_data = NULL;
2021 }
static Snapshot HistoricSnapshot
Definition: snapmgr.c:152
static HTAB * tuplecid_data
Definition: snapmgr.c:170

◆ ThereAreNoPriorRegisteredSnapshots()

bool ThereAreNoPriorRegisteredSnapshots ( void  )

Definition at line 1655 of file snapmgr.c.

References pairingheap_is_empty, and pairingheap_is_singular.

Referenced by CopyFrom().

1656 {
1659  return true;
1660 
1661  return false;
1662 }
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
#define pairingheap_is_singular(h)
Definition: pairingheap.h:99

◆ TransactionIdLimitedForOldSnapshots()

TransactionId TransactionIdLimitedForOldSnapshots ( TransactionId  recentXmin,
Relation  relation 
)

Definition at line 1741 of file snapmgr.c.

References AlignTimestampToMinuteBoundary(), OldSnapshotControlData::count_used, GetSnapshotCurrentTimestamp(), OldSnapshotControlData::head_offset, OldSnapshotControlData::head_timestamp, OldSnapshotControlData::latest_xmin, LW_SHARED, LWLockAcquire(), LWLockRelease(), OldSnapshotControlData::mutex_latest_xmin, OldSnapshotControlData::mutex_threshold, MyPgXact, OldSnapshotControlData::next_map_update, NormalTransactionIdFollows, old_snapshot_threshold, OLD_SNAPSHOT_TIME_MAP_ENTRIES, RelationAllowsEarlyPruning, SetOldSnapshotThresholdTimestamp(), SpinLockAcquire, SpinLockRelease, OldSnapshotControlData::threshold_timestamp, OldSnapshotControlData::threshold_xid, TransactionIdFollows(), TransactionIdIsNormal, TransactionIdPrecedes(), USECS_PER_MINUTE, USECS_PER_SEC, OldSnapshotControlData::xid_by_minute, and PGXACT::xmin.

Referenced by heap_page_prune_opt(), and vacuum_set_xid_limits().

1743 {
1744  if (TransactionIdIsNormal(recentXmin)
1745  && old_snapshot_threshold >= 0
1746  && RelationAllowsEarlyPruning(relation))
1747  {
1749  TransactionId xlimit = recentXmin;
1750  TransactionId latest_xmin;
1751  TimestampTz update_ts;
1752  bool same_ts_as_threshold = false;
1753 
1755  latest_xmin = oldSnapshotControl->latest_xmin;
1756  update_ts = oldSnapshotControl->next_map_update;
1758 
1759  /*
1760  * Zero threshold always overrides to latest xmin, if valid. Without
1761  * some heuristic it will find its own snapshot too old on, for
1762  * example, a simple UPDATE -- which would make it useless for most
1763  * testing, but there is no principled way to ensure that it doesn't
1764  * fail in this way. Use a five-second delay to try to get useful
1765  * testing behavior, but this may need adjustment.
1766  */
1767  if (old_snapshot_threshold == 0)
1768  {
1769  if (TransactionIdPrecedes(latest_xmin, MyPgXact->xmin)
1770  && TransactionIdFollows(latest_xmin, xlimit))
1771  xlimit = latest_xmin;
1772 
1773  ts -= 5 * USECS_PER_SEC;
1775 
1776  return xlimit;
1777  }
1778 
1781 
1782  /* Check for fast exit without LW locking. */
1785  {
1787  same_ts_as_threshold = true;
1788  }
1790 
1791  if (!same_ts_as_threshold)
1792  {
1793  if (ts == update_ts)
1794  {
1795  xlimit = latest_xmin;
1796  if (NormalTransactionIdFollows(xlimit, recentXmin))
1798  }
1799  else
1800  {
1801  LWLockAcquire(OldSnapshotTimeMapLock, LW_SHARED);
1802 
1805  {
1806  int offset;
1807 
1808  offset = ((ts - oldSnapshotControl->head_timestamp)
1809  / USECS_PER_MINUTE);
1810  if (offset > oldSnapshotControl->count_used - 1)
1811  offset = oldSnapshotControl->count_used - 1;
1812  offset = (oldSnapshotControl->head_offset + offset)
1814  xlimit = oldSnapshotControl->xid_by_minute[offset];
1815 
1816  if (NormalTransactionIdFollows(xlimit, recentXmin))
1818  }
1819 
1820  LWLockRelease(OldSnapshotTimeMapLock);
1821  }
1822  }
1823 
1824  /*
1825  * Failsafe protection against vacuuming work of active transaction.
1826  *
1827  * This is not an assertion because we avoid the spinlock for
1828  * performance, leaving open the possibility that xlimit could advance
1829  * and be more current; but it seems prudent to apply this limit. It
1830  * might make pruning a tiny bit less aggressive than it could be, but
1831  * protects against data loss bugs.
1832  */
1833  if (TransactionIdIsNormal(latest_xmin)
1834  && TransactionIdPrecedes(latest_xmin, xlimit))
1835  xlimit = latest_xmin;
1836 
1837  if (NormalTransactionIdFollows(xlimit, recentXmin))
1838  return xlimit;
1839  }
1840 
1841  return recentXmin;
1842 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:474
#define USECS_PER_SEC
Definition: timestamp.h:94
TransactionId xmin
Definition: proc.h:225
int64 TimestampTz
Definition: timestamp.h:39
slock_t mutex_threshold
Definition: snapmgr.c:91
#define RelationAllowsEarlyPruning(rel)
Definition: snapmgr.h:38
#define USECS_PER_MINUTE
Definition: timestamp.h:93
PGXACT * MyPgXact
Definition: proc.c:68
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define SpinLockAcquire(lock)
Definition: spin.h:62
TimestampTz threshold_timestamp
Definition: snapmgr.c:92
TimestampTz GetSnapshotCurrentTimestamp(void)
Definition: snapmgr.c:1686
slock_t mutex_latest_xmin
Definition: snapmgr.c:88
TimestampTz next_map_update
Definition: snapmgr.c:90
TransactionId threshold_xid
Definition: snapmgr.c:93
static void SetOldSnapshotThresholdTimestamp(TimestampTz ts, TransactionId xlimit)
Definition: snapmgr.c:1723
static volatile OldSnapshotControlData * oldSnapshotControl
Definition: snapmgr.c:129
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define SpinLockRelease(lock)
Definition: spin.h:64
TransactionId latest_xmin
Definition: snapmgr.c:89
TransactionId xid_by_minute[FLEXIBLE_ARRAY_MEMBER]
Definition: snapmgr.c:126
#define NormalTransactionIdFollows(id1, id2)
Definition: transam.h:67
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static TimestampTz AlignTimestampToMinuteBoundary(TimestampTz ts)
Definition: snapmgr.c:1672
int old_snapshot_threshold
Definition: snapmgr.c:75
TimestampTz head_timestamp
Definition: snapmgr.c:124
#define OLD_SNAPSHOT_TIME_MAP_ENTRIES
Definition: snapmgr.h:32
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

◆ UnregisterSnapshot()

◆ UnregisterSnapshotFromOwner()

void UnregisterSnapshotFromOwner ( Snapshot  snapshot,
ResourceOwner  owner 
)

Definition at line 918 of file snapmgr.c.

References SnapshotData::active_count, Assert, FreeSnapshot(), pairingheap_is_empty, pairingheap_remove(), SnapshotData::ph_node, SnapshotData::regd_count, ResourceOwnerForgetSnapshot(), and SnapshotResetXmin().

Referenced by inv_close(), PortalDrop(), and UnregisterSnapshot().

919 {
920  if (snapshot == NULL)
921  return;
922 
923  Assert(snapshot->regd_count > 0);
925 
926  ResourceOwnerForgetSnapshot(owner, snapshot);
927 
928  snapshot->regd_count--;
929  if (snapshot->regd_count == 0)
931 
932  if (snapshot->regd_count == 0 && snapshot->active_count == 0)
933  {
934  FreeSnapshot(snapshot);
936  }
937 }
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:715
static void SnapshotResetXmin(void)
Definition: snapmgr.c:978
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
uint32 regd_count
Definition: snapshot.h:110
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:200
void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1162
pairingheap_node ph_node
Definition: snapshot.h:111
#define Assert(condition)
Definition: c.h:699
void pairingheap_remove(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:170
uint32 active_count
Definition: snapshot.h:109

◆ UpdateActiveSnapshotCommandId()

void UpdateActiveSnapshotCommandId ( void  )

Definition at line 781 of file snapmgr.c.

References SnapshotData::active_count, ActiveSnapshotElt::as_snap, Assert, SnapshotData::curcid, elog, ERROR, GetCurrentCommandId(), IsInParallelMode(), and SnapshotData::regd_count.

Referenced by _SPI_execute_plan(), BeginCopy(), ExecCreateTableAs(), ExplainOnePlan(), fmgr_sql(), PortalRunMulti(), and refresh_matview_datafill().

782 {
783  CommandId save_curcid,
784  curcid;
785 
786  Assert(ActiveSnapshot != NULL);
789 
790  /*
791  * Don't allow modification of the active snapshot during parallel
792  * operation. We share the snapshot to worker backends at the beginning
793  * of parallel operation, so any change to the snapshot can lead to
794  * inconsistencies. We have other defenses against
795  * CommandCounterIncrement, but there are a few places that call this
796  * directly, so we put an additional guard here.
797  */
798  save_curcid = ActiveSnapshot->as_snap->curcid;
799  curcid = GetCurrentCommandId(false);
800  if (IsInParallelMode() && save_curcid != curcid)
801  elog(ERROR, "cannot modify commandid in active snapshot during a parallel operation");
802  ActiveSnapshot->as_snap->curcid = curcid;
803 }
uint32 CommandId
Definition: c.h:488
Snapshot as_snap
Definition: snapmgr.c:182
uint32 regd_count
Definition: snapshot.h:110
bool IsInParallelMode(void)
Definition: xact.c:905
#define ERROR
Definition: elog.h:43
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:188
CommandId curcid
Definition: snapshot.h:98
#define Assert(condition)
Definition: c.h:699
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:679
#define elog
Definition: elog.h:219
uint32 active_count
Definition: snapshot.h:109

◆ XactHasExportedSnapshots()

bool XactHasExportedSnapshots ( void  )

Definition at line 1603 of file snapmgr.c.

References NIL.

Referenced by PrepareTransaction().

1604 {
1605  return (exportedSnapshots != NIL);
1606 }
#define NIL
Definition: pg_list.h:69
static List * exportedSnapshots
Definition: snapmgr.c:223

◆ xmin_cmp()

static int xmin_cmp ( const pairingheap_node a,
const pairingheap_node b,
void *  arg 
)
static

Definition at line 944 of file snapmgr.c.

References pairingheap_const_container, TransactionIdFollows(), TransactionIdPrecedes(), and SnapshotData::xmin.

945 {
946  const SnapshotData *asnap = pairingheap_const_container(SnapshotData, ph_node, a);
947  const SnapshotData *bsnap = pairingheap_const_container(SnapshotData, ph_node, b);
948 
949  if (TransactionIdPrecedes(asnap->xmin, bsnap->xmin))
950  return 1;
951  else if (TransactionIdFollows(asnap->xmin, bsnap->xmin))
952  return -1;
953  else
954  return 0;
955 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
TransactionId xmin
Definition: snapshot.h:68
#define pairingheap_const_container(type, membername, ptr)
Definition: pairingheap.h:51
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300

Variable Documentation

◆ ActiveSnapshot

ActiveSnapshotElt* ActiveSnapshot = NULL
static

Definition at line 188 of file snapmgr.c.

Referenced by PushActiveSnapshot().

◆ CatalogSnapshot

Snapshot CatalogSnapshot = NULL
static

Definition at line 151 of file snapmgr.c.

Referenced by GetNonHistoricCatalogSnapshot().

◆ CatalogSnapshotData

SnapshotData CatalogSnapshotData = {HeapTupleSatisfiesMVCC}

Definition at line 146 of file snapmgr.c.

◆ CurrentSnapshot

Snapshot CurrentSnapshot = NULL
static

Definition at line 149 of file snapmgr.c.

Referenced by GetTransactionSnapshot(), and SetTransactionSnapshot().

◆ CurrentSnapshotData

SnapshotData CurrentSnapshotData = {HeapTupleSatisfiesMVCC}
static

Definition at line 144 of file snapmgr.c.

◆ exportedSnapshots

List* exportedSnapshots = NIL
static

Definition at line 223 of file snapmgr.c.

◆ FirstSnapshotSet

◆ FirstXactSnapshot

Snapshot FirstXactSnapshot = NULL
static

Definition at line 210 of file snapmgr.c.

◆ HistoricSnapshot

Snapshot HistoricSnapshot = NULL
static

Definition at line 152 of file snapmgr.c.

Referenced by GetCatalogSnapshot(), and GetTransactionSnapshot().

◆ old_snapshot_threshold

◆ OldestActiveSnapshot

ActiveSnapshotElt* OldestActiveSnapshot = NULL
static

Definition at line 191 of file snapmgr.c.

◆ oldSnapshotControl

volatile OldSnapshotControlData* oldSnapshotControl
static

Definition at line 129 of file snapmgr.c.

◆ RecentGlobalDataXmin

TransactionId RecentGlobalDataXmin = InvalidTransactionId

Definition at line 167 of file snapmgr.c.

Referenced by GetSnapshotData(), and heap_page_prune_opt().

◆ RecentGlobalXmin

◆ RecentXmin

◆ RegisteredSnapshots

pairingheap RegisteredSnapshots = {&xmin_cmp, NULL, NULL}
static

Definition at line 200 of file snapmgr.c.

◆ SecondarySnapshot

Snapshot SecondarySnapshot = NULL
static

Definition at line 150 of file snapmgr.c.

Referenced by GetLatestSnapshot().

◆ SecondarySnapshotData

SnapshotData SecondarySnapshotData = {HeapTupleSatisfiesMVCC}
static

Definition at line 145 of file snapmgr.c.

◆ TransactionXmin

◆ tuplecid_data

HTAB* tuplecid_data = NULL
static

Definition at line 170 of file snapmgr.c.

Referenced by HistoricSnapshotGetTupleCids().