PostgreSQL Source Code  git master
snapmgr.c File Reference
#include "postgres.h"
#include <sys/stat.h>
#include <unistd.h>
#include "access/subtrans.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 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)
 
FullTransactionId GetFullRecentGlobalXmin (void)
 
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)
 
bool XidInMVCCSnapshot (TransactionId xid, Snapshot snapshot)
 

Variables

int old_snapshot_threshold
 
static volatile OldSnapshotControlDataoldSnapshotControl
 
static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC}
 
static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC}
 
SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC}
 
SnapshotData SnapshotSelfData = {SNAPSHOT_SELF}
 
SnapshotData SnapshotAnyData = {SNAPSHOT_ANY}
 
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 215 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 853 of file snapmgr.c.

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

854 {
855  return ActiveSnapshot != NULL;
856 }
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190

◆ AlignTimestampToMinuteBoundary()

static TimestampTz AlignTimestampToMinuteBoundary ( TimestampTz  ts)
static

Definition at line 1706 of file snapmgr.c.

References USECS_PER_MINUTE.

Referenced by MaintainOldSnapshotTimeMapping(), and TransactionIdLimitedForOldSnapshots().

1707 {
1708  TimestampTz retval = ts + (USECS_PER_MINUTE - 1);
1709 
1710  return retval - (retval % USECS_PER_MINUTE);
1711 }
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 1091 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().

1092 {
1093  /*
1094  * In transaction-snapshot mode we must release our privately-managed
1095  * reference to the transaction snapshot. We must remove it from
1096  * RegisteredSnapshots to keep the check below happy. But we don't bother
1097  * to do FreeSnapshot, for two reasons: the memory will go away with
1098  * TopTransactionContext anyway, and if someone has left the snapshot
1099  * stacked as active, we don't want the code below to be chasing through a
1100  * dangling pointer.
1101  */
1102  if (FirstXactSnapshot != NULL)
1103  {
1107  }
1108  FirstXactSnapshot = NULL;
1109 
1110  /*
1111  * If we exported any snapshots, clean them up.
1112  */
1113  if (exportedSnapshots != NIL)
1114  {
1115  ListCell *lc;
1116 
1117  /*
1118  * Get rid of the files. Unlink failure is only a WARNING because (1)
1119  * it's too late to abort the transaction, and (2) leaving a leaked
1120  * file around has little real consequence anyway.
1121  *
1122  * We also need to remove the snapshots from RegisteredSnapshots to
1123  * prevent a warning below.
1124  *
1125  * As with the FirstXactSnapshot, we don't need to free resources of
1126  * the snapshot itself as it will go away with the memory context.
1127  */
1128  foreach(lc, exportedSnapshots)
1129  {
1130  ExportedSnapshot *esnap = (ExportedSnapshot *) lfirst(lc);
1131 
1132  if (unlink(esnap->snapfile))
1133  elog(WARNING, "could not unlink file \"%s\": %m",
1134  esnap->snapfile);
1135 
1137  &esnap->snapshot->ph_node);
1138  }
1139 
1141  }
1142 
1143  /* Drop catalog snapshot if any */
1145 
1146  /* On commit, complain about leftover snapshots */
1147  if (isCommit)
1148  {
1149  ActiveSnapshotElt *active;
1150 
1152  elog(WARNING, "registered snapshots seem to remain after cleanup");
1153 
1154  /* complain about unpopped active snapshots */
1155  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
1156  elog(WARNING, "snapshot %p still active", active);
1157  }
1158 
1159  /*
1160  * And reset our state. We don't need to free the memory explicitly --
1161  * it'll go away with TopTransactionContext.
1162  */
1163  ActiveSnapshot = NULL;
1164  OldestActiveSnapshot = NULL;
1166 
1167  CurrentSnapshot = NULL;
1168  SecondarySnapshot = NULL;
1169 
1170  FirstSnapshotSet = false;
1171 
1172  /*
1173  * During normal commit processing, we call ProcArrayEndTransaction() to
1174  * reset the MyPgXact->xmin. That call happens prior to the call to
1175  * AtEOXact_Snapshot(), so we need not touch xmin here at all.
1176  */
1177  if (resetXmin)
1179 
1180  Assert(resetXmin || MyPgXact->xmin == 0);
1181 }
#define NIL
Definition: pg_list.h:65
#define pairingheap_reset(h)
Definition: pairingheap.h:93
TransactionId xmin
Definition: proc.h:228
static void SnapshotResetXmin(void)
Definition: snapmgr.c:1010
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
static Snapshot FirstXactSnapshot
Definition: snapmgr.c:212
uint32 regd_count
Definition: snapshot.h:199
static Snapshot CurrentSnapshot
Definition: snapmgr.c:151
PGXACT * MyPgXact
Definition: proc.c:69
static List * exportedSnapshots
Definition: snapmgr.c:225
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
bool FirstSnapshotSet
Definition: snapmgr.c:205
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:193
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:186
Snapshot snapshot
Definition: snapmgr.c:221
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:512
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190
char * snapfile
Definition: snapmgr.c:220
#define WARNING
Definition: elog.h:40
pairingheap_node ph_node
Definition: snapshot.h:200
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
#define elog(elevel,...)
Definition: elog.h:226
static Snapshot SecondarySnapshot
Definition: snapmgr.c:152
void pairingheap_remove(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:170

◆ AtSubAbort_Snapshot()

void AtSubAbort_Snapshot ( int  level)

Definition at line 1055 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().

1056 {
1057  /* Forget the active snapshots set by this subtransaction */
1058  while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
1059  {
1061 
1062  next = ActiveSnapshot->as_next;
1063 
1064  /*
1065  * Decrement the snapshot's active count. If it's still registered or
1066  * marked as active by an outer subtransaction, we can't free it yet.
1067  */
1070 
1071  if (ActiveSnapshot->as_snap->active_count == 0 &&
1074 
1075  /* and free the stack element */
1077 
1078  ActiveSnapshot = next;
1079  if (ActiveSnapshot == NULL)
1080  OldestActiveSnapshot = NULL;
1081  }
1082 
1084 }
Snapshot as_snap
Definition: snapmgr.c:184
static int32 next
Definition: blutils.c:215
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:717
static void SnapshotResetXmin(void)
Definition: snapmgr.c:1010
uint32 regd_count
Definition: snapshot.h:199
void pfree(void *pointer)
Definition: mcxt.c:1056
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:193
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:186
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190
#define Assert(condition)
Definition: c.h:732
uint32 active_count
Definition: snapshot.h:198

◆ AtSubCommit_Snapshot()

void AtSubCommit_Snapshot ( int  level)

Definition at line 1034 of file snapmgr.c.

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

Referenced by CommitSubTransaction().

1035 {
1036  ActiveSnapshotElt *active;
1037 
1038  /*
1039  * Relabel the active snapshots set in this subtransaction as though they
1040  * are owned by the parent subxact.
1041  */
1042  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
1043  {
1044  if (active->as_level < level)
1045  break;
1046  active->as_level = level - 1;
1047  }
1048 }
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:186
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190

◆ CopySnapshot()

static Snapshot CopySnapshot ( Snapshot  snapshot)
static

Definition at line 662 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().

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

◆ DeleteAllExportedSnapshotFiles()

void DeleteAllExportedSnapshotFiles ( void  )

Definition at line 1650 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().

1651 {
1652  char buf[MAXPGPATH + sizeof(SNAPSHOT_EXPORT_DIR)];
1653  DIR *s_dir;
1654  struct dirent *s_de;
1655 
1656  /*
1657  * Problems in reading the directory, or unlinking files, are reported at
1658  * LOG level. Since we're running in the startup process, ERROR level
1659  * would prevent database start, and it's not important enough for that.
1660  */
1662 
1663  while ((s_de = ReadDirExtended(s_dir, SNAPSHOT_EXPORT_DIR, LOG)) != NULL)
1664  {
1665  if (strcmp(s_de->d_name, ".") == 0 ||
1666  strcmp(s_de->d_name, "..") == 0)
1667  continue;
1668 
1669  snprintf(buf, sizeof(buf), SNAPSHOT_EXPORT_DIR "/%s", s_de->d_name);
1670 
1671  if (unlink(buf) != 0)
1672  ereport(LOG,
1674  errmsg("could not remove file \"%s\": %m", buf)));
1675  }
1676 
1677  FreeDir(s_dir);
1678 }
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2547
#define LOG
Definition: elog.h:26
Definition: dirent.h:9
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:215
Definition: dirent.c:25
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:68
int errcode_for_file_access(void)
Definition: elog.c:593
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2466
#define ereport(elevel, rest)
Definition: elog.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:784
char d_name[MAX_PATH]
Definition: dirent.h:14
#define snprintf
Definition: port.h:192
int FreeDir(DIR *dir)
Definition: fd.c:2584

◆ EstimateSnapshotSpace()

Size EstimateSnapshotSpace ( Snapshot  snap)

Definition at line 2078 of file snapmgr.c.

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

Referenced by ExecBitmapHeapEstimate(), index_parallelscan_estimate(), index_parallelscan_initialize(), InitializeParallelDSM(), and table_parallelscan_estimate().

2079 {
2080  Size size;
2081 
2082  Assert(snap != InvalidSnapshot);
2084 
2085  /* We allocate any XID arrays needed in the same palloc block. */
2086  size = add_size(sizeof(SerializedSnapshotData),
2087  mul_size(snap->xcnt, sizeof(TransactionId)));
2088  if (snap->subxcnt > 0 &&
2089  (!snap->suboverflowed || snap->takenDuringRecovery))
2090  size = add_size(size,
2091  mul_size(snap->subxcnt, sizeof(TransactionId)));
2092 
2093  return size;
2094 }
uint32 TransactionId
Definition: c.h:507
bool suboverflowed
Definition: snapshot.h:182
SnapshotType snapshot_type
Definition: snapshot.h:144
#define InvalidSnapshot
Definition: snapshot.h:123
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:732
bool takenDuringRecovery
Definition: snapshot.h:184
size_t Size
Definition: c.h:466
uint32 xcnt
Definition: snapshot.h:169
int32 subxcnt
Definition: snapshot.h:181

◆ ExportSnapshot()

char* ExportSnapshot ( Snapshot  snapshot)

Definition at line 1191 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().

1192 {
1193  TransactionId topXid;
1194  TransactionId *children;
1195  ExportedSnapshot *esnap;
1196  int nchildren;
1197  int addTopXid;
1199  FILE *f;
1200  int i;
1201  MemoryContext oldcxt;
1202  char path[MAXPGPATH];
1203  char pathtmp[MAXPGPATH];
1204 
1205  /*
1206  * It's tempting to call RequireTransactionBlock here, since it's not very
1207  * useful to export a snapshot that will disappear immediately afterwards.
1208  * However, we haven't got enough information to do that, since we don't
1209  * know if we're at top level or not. For example, we could be inside a
1210  * plpgsql function that is going to fire off other transactions via
1211  * dblink. Rather than disallow perfectly legitimate usages, don't make a
1212  * check.
1213  *
1214  * Also note that we don't make any restriction on the transaction's
1215  * isolation level; however, importers must check the level if they are
1216  * serializable.
1217  */
1218 
1219  /*
1220  * Get our transaction ID if there is one, to include in the snapshot.
1221  */
1222  topXid = GetTopTransactionIdIfAny();
1223 
1224  /*
1225  * We cannot export a snapshot from a subtransaction because there's no
1226  * easy way for importers to verify that the same subtransaction is still
1227  * running.
1228  */
1229  if (IsSubTransaction())
1230  ereport(ERROR,
1231  (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1232  errmsg("cannot export a snapshot from a subtransaction")));
1233 
1234  /*
1235  * We do however allow previous committed subtransactions to exist.
1236  * Importers of the snapshot must see them as still running, so get their
1237  * XIDs to add them to the snapshot.
1238  */
1239  nchildren = xactGetCommittedChildren(&children);
1240 
1241  /*
1242  * Generate file path for the snapshot. We start numbering of snapshots
1243  * inside the transaction from 1.
1244  */
1245  snprintf(path, sizeof(path), SNAPSHOT_EXPORT_DIR "/%08X-%08X-%d",
1247 
1248  /*
1249  * Copy the snapshot into TopTransactionContext, add it to the
1250  * exportedSnapshots list, and mark it pseudo-registered. We do this to
1251  * ensure that the snapshot's xmin is honored for the rest of the
1252  * transaction.
1253  */
1254  snapshot = CopySnapshot(snapshot);
1255 
1257  esnap = (ExportedSnapshot *) palloc(sizeof(ExportedSnapshot));
1258  esnap->snapfile = pstrdup(path);
1259  esnap->snapshot = snapshot;
1261  MemoryContextSwitchTo(oldcxt);
1262 
1263  snapshot->regd_count++;
1265 
1266  /*
1267  * Fill buf with a text serialization of the snapshot, plus identification
1268  * data about this transaction. The format expected by ImportSnapshot is
1269  * pretty rigid: each line must be fieldname:value.
1270  */
1271  initStringInfo(&buf);
1272 
1273  appendStringInfo(&buf, "vxid:%d/%u\n", MyProc->backendId, MyProc->lxid);
1274  appendStringInfo(&buf, "pid:%d\n", MyProcPid);
1275  appendStringInfo(&buf, "dbid:%u\n", MyDatabaseId);
1276  appendStringInfo(&buf, "iso:%d\n", XactIsoLevel);
1277  appendStringInfo(&buf, "ro:%d\n", XactReadOnly);
1278 
1279  appendStringInfo(&buf, "xmin:%u\n", snapshot->xmin);
1280  appendStringInfo(&buf, "xmax:%u\n", snapshot->xmax);
1281 
1282  /*
1283  * We must include our own top transaction ID in the top-xid data, since
1284  * by definition we will still be running when the importing transaction
1285  * adopts the snapshot, but GetSnapshotData never includes our own XID in
1286  * the snapshot. (There must, therefore, be enough room to add it.)
1287  *
1288  * However, it could be that our topXid is after the xmax, in which case
1289  * we shouldn't include it because xip[] members are expected to be before
1290  * xmax. (We need not make the same check for subxip[] members, see
1291  * snapshot.h.)
1292  */
1293  addTopXid = (TransactionIdIsValid(topXid) &&
1294  TransactionIdPrecedes(topXid, snapshot->xmax)) ? 1 : 0;
1295  appendStringInfo(&buf, "xcnt:%d\n", snapshot->xcnt + addTopXid);
1296  for (i = 0; i < snapshot->xcnt; i++)
1297  appendStringInfo(&buf, "xip:%u\n", snapshot->xip[i]);
1298  if (addTopXid)
1299  appendStringInfo(&buf, "xip:%u\n", topXid);
1300 
1301  /*
1302  * Similarly, we add our subcommitted child XIDs to the subxid data. Here,
1303  * we have to cope with possible overflow.
1304  */
1305  if (snapshot->suboverflowed ||
1306  snapshot->subxcnt + nchildren > GetMaxSnapshotSubxidCount())
1307  appendStringInfoString(&buf, "sof:1\n");
1308  else
1309  {
1310  appendStringInfoString(&buf, "sof:0\n");
1311  appendStringInfo(&buf, "sxcnt:%d\n", snapshot->subxcnt + nchildren);
1312  for (i = 0; i < snapshot->subxcnt; i++)
1313  appendStringInfo(&buf, "sxp:%u\n", snapshot->subxip[i]);
1314  for (i = 0; i < nchildren; i++)
1315  appendStringInfo(&buf, "sxp:%u\n", children[i]);
1316  }
1317  appendStringInfo(&buf, "rec:%u\n", snapshot->takenDuringRecovery);
1318 
1319  /*
1320  * Now write the text representation into a file. We first write to a
1321  * ".tmp" filename, and rename to final filename if no error. This
1322  * ensures that no other backend can read an incomplete file
1323  * (ImportSnapshot won't allow it because of its valid-characters check).
1324  */
1325  snprintf(pathtmp, sizeof(pathtmp), "%s.tmp", path);
1326  if (!(f = AllocateFile(pathtmp, PG_BINARY_W)))
1327  ereport(ERROR,
1329  errmsg("could not create file \"%s\": %m", pathtmp)));
1330 
1331  if (fwrite(buf.data, buf.len, 1, f) != 1)
1332  ereport(ERROR,
1334  errmsg("could not write to file \"%s\": %m", pathtmp)));
1335 
1336  /* no fsync() since file need not survive a system crash */
1337 
1338  if (FreeFile(f))
1339  ereport(ERROR,
1341  errmsg("could not write to file \"%s\": %m", pathtmp)));
1342 
1343  /*
1344  * Now that we have written everything into a .tmp file, rename the file
1345  * to remove the .tmp suffix.
1346  */
1347  if (rename(pathtmp, path) < 0)
1348  ereport(ERROR,
1350  errmsg("could not rename file \"%s\" to \"%s\": %m",
1351  pathtmp, path)));
1352 
1353  /*
1354  * The basename of the file is what we return from pg_export_snapshot().
1355  * It's already in path in a textual format and we know that the path
1356  * starts with SNAPSHOT_EXPORT_DIR. Skip over the prefix and the slash
1357  * and pstrdup it so as not to return the address of a local variable.
1358  */
1359  return pstrdup(path + strlen(SNAPSHOT_EXPORT_DIR) + 1);
1360 }
int xactGetCommittedChildren(TransactionId **ptr)
Definition: xact.c:5419
int MyProcPid
Definition: globals.c:40
MemoryContext TopTransactionContext
Definition: mcxt.c:49
BackendId backendId
Definition: proc.h:113
uint32 TransactionId
Definition: c.h:507
PGPROC * MyProc
Definition: proc.c:68
char * pstrdup(const char *in)
Definition: mcxt.c:1186
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:570
#define PG_BINARY_W
Definition: c.h:1194
bool suboverflowed
Definition: snapshot.h:182
uint32 regd_count
Definition: snapshot.h:199
static List * exportedSnapshots
Definition: snapmgr.c:225
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:215
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define ERROR
Definition: elog.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
#define MAXPGPATH
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:163
static char * buf
Definition: pg_test_fsync.c:68
int errcode_for_file_access(void)
Definition: elog.c:593
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2205
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:410
#define ereport(elevel, rest)
Definition: elog.h:141
Snapshot snapshot
Definition: snapmgr.c:221
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
TransactionId * xip
Definition: snapshot.h:168
List * lappend(List *list, void *datum)
Definition: list.c:322
char * snapfile
Definition: snapmgr.c:220
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
Oid MyDatabaseId
Definition: globals.c:85
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:662
bool XactReadOnly
Definition: xact.c:78
pairingheap_node ph_node
Definition: snapshot.h:200
bool takenDuringRecovery
Definition: snapshot.h:184
static int list_length(const List *l)
Definition: pg_list.h:169
int XactIsoLevel
Definition: xact.c:75
int FreeFile(FILE *file)
Definition: fd.c:2404
bool IsSubTransaction(void)
Definition: xact.c:4706
uint32 xcnt
Definition: snapshot.h:169
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:784
int i
int GetMaxSnapshotSubxidCount(void)
Definition: procarray.c:1461
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define snprintf
Definition: port.h:192
TransactionId * subxip
Definition: snapshot.h:180
int32 subxcnt
Definition: snapshot.h:181
LocalTransactionId lxid
Definition: proc.h:106

◆ FreeSnapshot()

static void FreeSnapshot ( Snapshot  snapshot)
static

Definition at line 717 of file snapmgr.c.

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

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

718 {
719  Assert(snapshot->regd_count == 0);
720  Assert(snapshot->active_count == 0);
721  Assert(snapshot->copied);
722 
723  pfree(snapshot);
724 }
bool copied
Definition: snapshot.h:185
uint32 regd_count
Definition: snapshot.h:199
void pfree(void *pointer)
Definition: mcxt.c:1056
#define Assert(condition)
Definition: c.h:732
uint32 active_count
Definition: snapshot.h:198

◆ GetActiveSnapshot()

◆ GetCatalogSnapshot()

Snapshot GetCatalogSnapshot ( Oid  relid)

Definition at line 442 of file snapmgr.c.

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

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

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

◆ GetFullRecentGlobalXmin()

FullTransactionId GetFullRecentGlobalXmin ( void  )

Definition at line 963 of file snapmgr.c.

References Assert, epoch, EpochFromFullTransactionId, FullTransactionIdFromEpochAndXid(), ReadNextFullTransactionId(), RecentGlobalXmin, TransactionIdIsNormal, and XidFromFullTransactionId.

Referenced by gistPageRecyclable().

964 {
965  FullTransactionId nextxid_full;
966  uint32 nextxid_epoch;
967  TransactionId nextxid_xid;
968  uint32 epoch;
969 
971 
972  /*
973  * Compute the epoch from the next XID's epoch. This relies on the fact
974  * that RecentGlobalXmin must be within the 2 billion XID horizon from the
975  * next XID.
976  */
977  nextxid_full = ReadNextFullTransactionId();
978  nextxid_epoch = EpochFromFullTransactionId(nextxid_full);
979  nextxid_xid = XidFromFullTransactionId(nextxid_full);
980 
981  if (RecentGlobalXmin > nextxid_xid)
982  epoch = nextxid_epoch - 1;
983  else
984  epoch = nextxid_epoch;
985 
987 }
uint32 TransactionId
Definition: c.h:507
#define XidFromFullTransactionId(x)
Definition: transam.h:48
TransactionId RecentGlobalXmin
Definition: snapmgr.c:168
unsigned int uint32
Definition: c.h:358
FullTransactionId ReadNextFullTransactionId(void)
Definition: varsup.c:246
#define EpochFromFullTransactionId(x)
Definition: transam.h:47
#define Assert(condition)
Definition: c.h:732
static FullTransactionId FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid)
Definition: transam.h:65
static const unsigned __int64 epoch
Definition: gettimeofday.c:34
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

◆ GetLatestSnapshot()

Snapshot GetLatestSnapshot ( void  )

Definition at line 381 of file snapmgr.c.

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

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

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

◆ GetNonHistoricCatalogSnapshot()

Snapshot GetNonHistoricCatalogSnapshot ( Oid  relid)

Definition at line 464 of file snapmgr.c.

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

Referenced by GetCatalogSnapshot(), and ScanPgRelation().

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

◆ GetOldestSnapshot()

Snapshot GetOldestSnapshot ( void  )

Definition at line 413 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().

414 {
415  Snapshot OldestRegisteredSnapshot = NULL;
416  XLogRecPtr RegisteredLSN = InvalidXLogRecPtr;
417 
419  {
420  OldestRegisteredSnapshot = pairingheap_container(SnapshotData, ph_node,
422  RegisteredLSN = OldestRegisteredSnapshot->lsn;
423  }
424 
425  if (OldestActiveSnapshot != NULL)
426  {
428 
429  if (XLogRecPtrIsInvalid(RegisteredLSN) || RegisteredLSN > ActiveLSN)
431  }
432 
433  return OldestRegisteredSnapshot;
434 }
pairingheap_node * pairingheap_first(pairingheap *heap)
Definition: pairingheap.c:130
Snapshot as_snap
Definition: snapmgr.c:184
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
XLogRecPtr lsn
Definition: snapshot.h:203
#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:202
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:193
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
uint64 XLogRecPtr
Definition: xlogdefs.h:21

◆ GetOldSnapshotThresholdTimestamp()

TimestampTz GetOldSnapshotThresholdTimestamp ( void  )

Definition at line 1745 of file snapmgr.c.

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

Referenced by TestForOldSnapshot_impl().

1746 {
1747  TimestampTz threshold_timestamp;
1748 
1750  threshold_timestamp = oldSnapshotControl->threshold_timestamp;
1752 
1753  return threshold_timestamp;
1754 }
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 1720 of file snapmgr.c.

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

Referenced by GetSnapshotData(), and TransactionIdLimitedForOldSnapshots().

1721 {
1723 
1724  /*
1725  * Don't let time move backward; if it hasn't advanced, use the old value.
1726  */
1728  if (now <= oldSnapshotControl->current_timestamp)
1730  else
1733 
1734  return now;
1735 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
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:1547

◆ GetTransactionSnapshot()

Snapshot GetTransactionSnapshot ( void  )

Definition at line 306 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(), exec_stmt_call(), execute_sql_string(), fmgr_sql(), get_database_list(), get_subscription_list(), GetLatestSnapshot(), HandleFunctionRequest(), heapam_index_build_range_scan(), initialize_worker_spi(), InitializeParallelDSM(), InitPostgres(), LogicalRepSyncTableStart(), pg_get_constraintdef_worker(), PortalRunMulti(), PortalRunUtility(), PortalStart(), ReindexMultipleTables(), ReindexRelationConcurrently(), RevalidateCachedQuery(), ri_PerformCheck(), SPI_cursor_open_internal(), vacuum(), vacuum_rel(), and XidIsConcurrent().

307 {
308  /*
309  * Return historic snapshot if doing logical decoding. We'll never need a
310  * non-historic transaction snapshot in this (sub-)transaction, so there's
311  * no need to be careful to set one up for later calls to
312  * GetTransactionSnapshot().
313  */
315  {
317  return HistoricSnapshot;
318  }
319 
320  /* First call in transaction? */
321  if (!FirstSnapshotSet)
322  {
323  /*
324  * Don't allow catalog snapshot to be older than xact snapshot. Must
325  * do this first to allow the empty-heap Assert to succeed.
326  */
328 
330  Assert(FirstXactSnapshot == NULL);
331 
332  if (IsInParallelMode())
333  elog(ERROR,
334  "cannot take query snapshot during a parallel operation");
335 
336  /*
337  * In transaction-snapshot mode, the first snapshot must live until
338  * end of xact regardless of what the caller does with it, so we must
339  * make a copy of it rather than returning CurrentSnapshotData
340  * directly. Furthermore, if we're running in serializable mode,
341  * predicate.c needs to wrap the snapshot fetch in its own processing.
342  */
344  {
345  /* First, create the snapshot in CurrentSnapshotData */
348  else
350  /* Make a saved copy */
353  /* Mark it as "registered" in FirstXactSnapshot */
356  }
357  else
359 
360  FirstSnapshotSet = true;
361  return CurrentSnapshot;
362  }
363 
365  return CurrentSnapshot;
366 
367  /* Don't allow catalog snapshot to be older than xact snapshot. */
369 
371 
372  return CurrentSnapshot;
373 }
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
static Snapshot HistoricSnapshot
Definition: snapmgr.c:154
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
static SnapshotData CurrentSnapshotData
Definition: snapmgr.c:144
static Snapshot FirstXactSnapshot
Definition: snapmgr.c:212
uint32 regd_count
Definition: snapshot.h:199
static Snapshot CurrentSnapshot
Definition: snapmgr.c:151
bool IsInParallelMode(void)
Definition: xact.c:994
#define ERROR
Definition: elog.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
bool FirstSnapshotSet
Definition: snapmgr.c:205
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:512
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:662
pairingheap_node ph_node
Definition: snapshot.h:200
#define Assert(condition)
Definition: c.h:732
Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot)
Definition: predicate.c:1613
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1503
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2058
#define IsolationIsSerializable()
Definition: xact.h:52
#define elog(elevel,...)
Definition: elog.h:226
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112

◆ HistoricSnapshotActive()

bool HistoricSnapshotActive ( void  )

◆ HistoricSnapshotGetTupleCids()

HTAB* HistoricSnapshotGetTupleCids ( void  )

Definition at line 2064 of file snapmgr.c.

References Assert, HistoricSnapshotActive(), and tuplecid_data.

Referenced by HeapTupleSatisfiesHistoricMVCC().

2065 {
2067  return tuplecid_data;
2068 }
static HTAB * tuplecid_data
Definition: snapmgr.c:172
#define Assert(condition)
Definition: c.h:732
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2058

◆ ImportSnapshot()

void ImportSnapshot ( const char *  idstr)

Definition at line 1462 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, SNAPSHOT_MVCC, SnapshotData::snapshot_type, 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().

1463 {
1464  char path[MAXPGPATH];
1465  FILE *f;
1466  struct stat stat_buf;
1467  char *filebuf;
1468  int xcnt;
1469  int i;
1470  VirtualTransactionId src_vxid;
1471  int src_pid;
1472  Oid src_dbid;
1473  int src_isolevel;
1474  bool src_readonly;
1475  SnapshotData snapshot;
1476 
1477  /*
1478  * Must be at top level of a fresh transaction. Note in particular that
1479  * we check we haven't acquired an XID --- if we have, it's conceivable
1480  * that the snapshot would show it as not running, making for very screwy
1481  * behavior.
1482  */
1483  if (FirstSnapshotSet ||
1485  IsSubTransaction())
1486  ereport(ERROR,
1487  (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1488  errmsg("SET TRANSACTION SNAPSHOT must be called before any query")));
1489 
1490  /*
1491  * If we are in read committed mode then the next query would execute with
1492  * a new snapshot thus making this function call quite useless.
1493  */
1495  ereport(ERROR,
1496  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1497  errmsg("a snapshot-importing transaction must have isolation level SERIALIZABLE or REPEATABLE READ")));
1498 
1499  /*
1500  * Verify the identifier: only 0-9, A-F and hyphens are allowed. We do
1501  * this mainly to prevent reading arbitrary files.
1502  */
1503  if (strspn(idstr, "0123456789ABCDEF-") != strlen(idstr))
1504  ereport(ERROR,
1505  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1506  errmsg("invalid snapshot identifier: \"%s\"", idstr)));
1507 
1508  /* OK, read the file */
1509  snprintf(path, MAXPGPATH, SNAPSHOT_EXPORT_DIR "/%s", idstr);
1510 
1511  f = AllocateFile(path, PG_BINARY_R);
1512  if (!f)
1513  ereport(ERROR,
1514  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1515  errmsg("invalid snapshot identifier: \"%s\"", idstr)));
1516 
1517  /* get the size of the file so that we know how much memory we need */
1518  if (fstat(fileno(f), &stat_buf))
1519  elog(ERROR, "could not stat file \"%s\": %m", path);
1520 
1521  /* and read the file into a palloc'd string */
1522  filebuf = (char *) palloc(stat_buf.st_size + 1);
1523  if (fread(filebuf, stat_buf.st_size, 1, f) != 1)
1524  elog(ERROR, "could not read file \"%s\": %m", path);
1525 
1526  filebuf[stat_buf.st_size] = '\0';
1527 
1528  FreeFile(f);
1529 
1530  /*
1531  * Construct a snapshot struct by parsing the file content.
1532  */
1533  memset(&snapshot, 0, sizeof(snapshot));
1534 
1535  parseVxidFromText("vxid:", &filebuf, path, &src_vxid);
1536  src_pid = parseIntFromText("pid:", &filebuf, path);
1537  /* we abuse parseXidFromText a bit here ... */
1538  src_dbid = parseXidFromText("dbid:", &filebuf, path);
1539  src_isolevel = parseIntFromText("iso:", &filebuf, path);
1540  src_readonly = parseIntFromText("ro:", &filebuf, path);
1541 
1542  snapshot.snapshot_type = SNAPSHOT_MVCC;
1543 
1544  snapshot.xmin = parseXidFromText("xmin:", &filebuf, path);
1545  snapshot.xmax = parseXidFromText("xmax:", &filebuf, path);
1546 
1547  snapshot.xcnt = xcnt = parseIntFromText("xcnt:", &filebuf, path);
1548 
1549  /* sanity-check the xid count before palloc */
1550  if (xcnt < 0 || xcnt > GetMaxSnapshotXidCount())
1551  ereport(ERROR,
1552  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1553  errmsg("invalid snapshot data in file \"%s\"", path)));
1554 
1555  snapshot.xip = (TransactionId *) palloc(xcnt * sizeof(TransactionId));
1556  for (i = 0; i < xcnt; i++)
1557  snapshot.xip[i] = parseXidFromText("xip:", &filebuf, path);
1558 
1559  snapshot.suboverflowed = parseIntFromText("sof:", &filebuf, path);
1560 
1561  if (!snapshot.suboverflowed)
1562  {
1563  snapshot.subxcnt = xcnt = parseIntFromText("sxcnt:", &filebuf, path);
1564 
1565  /* sanity-check the xid count before palloc */
1566  if (xcnt < 0 || xcnt > GetMaxSnapshotSubxidCount())
1567  ereport(ERROR,
1568  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1569  errmsg("invalid snapshot data in file \"%s\"", path)));
1570 
1571  snapshot.subxip = (TransactionId *) palloc(xcnt * sizeof(TransactionId));
1572  for (i = 0; i < xcnt; i++)
1573  snapshot.subxip[i] = parseXidFromText("sxp:", &filebuf, path);
1574  }
1575  else
1576  {
1577  snapshot.subxcnt = 0;
1578  snapshot.subxip = NULL;
1579  }
1580 
1581  snapshot.takenDuringRecovery = parseIntFromText("rec:", &filebuf, path);
1582 
1583  /*
1584  * Do some additional sanity checking, just to protect ourselves. We
1585  * don't trouble to check the array elements, just the most critical
1586  * fields.
1587  */
1588  if (!VirtualTransactionIdIsValid(src_vxid) ||
1589  !OidIsValid(src_dbid) ||
1590  !TransactionIdIsNormal(snapshot.xmin) ||
1591  !TransactionIdIsNormal(snapshot.xmax))
1592  ereport(ERROR,
1593  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1594  errmsg("invalid snapshot data in file \"%s\"", path)));
1595 
1596  /*
1597  * If we're serializable, the source transaction must be too, otherwise
1598  * predicate.c has problems (SxactGlobalXmin could go backwards). Also, a
1599  * non-read-only transaction can't adopt a snapshot from a read-only
1600  * transaction, as predicate.c handles the cases very differently.
1601  */
1603  {
1604  if (src_isolevel != XACT_SERIALIZABLE)
1605  ereport(ERROR,
1606  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1607  errmsg("a serializable transaction cannot import a snapshot from a non-serializable transaction")));
1608  if (src_readonly && !XactReadOnly)
1609  ereport(ERROR,
1610  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1611  errmsg("a non-read-only serializable transaction cannot import a snapshot from a read-only transaction")));
1612  }
1613 
1614  /*
1615  * We cannot import a snapshot that was taken in a different database,
1616  * because vacuum calculates OldestXmin on a per-database basis; so the
1617  * source transaction's xmin doesn't protect us from data loss. This
1618  * restriction could be removed if the source transaction were to mark its
1619  * xmin as being globally applicable. But that would require some
1620  * additional syntax, since that has to be known when the snapshot is
1621  * initially taken. (See pgsql-hackers discussion of 2011-10-21.)
1622  */
1623  if (src_dbid != MyDatabaseId)
1624  ereport(ERROR,
1625  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1626  errmsg("cannot import a snapshot from a different database")));
1627 
1628  /* OK, install the snapshot */
1629  SetTransactionSnapshot(&snapshot, &src_vxid, src_pid, NULL);
1630 }
static TransactionId parseXidFromText(const char *prefix, char **s, const char *filename)
Definition: snapmgr.c:1407
uint32 TransactionId
Definition: c.h:507
static int parseIntFromText(const char *prefix, char **s, const char *filename)
Definition: snapmgr.c:1382
static void SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid, int sourcepid, PGPROC *sourceproc)
Definition: snapmgr.c:567
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
int errcode(int sqlerrcode)
Definition: elog.c:570
bool suboverflowed
Definition: snapshot.h:182
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
#define PG_BINARY_R
Definition: c.h:1193
#define XACT_SERIALIZABLE
Definition: xact.h:39
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:215
#define ERROR
Definition: elog.h:43
struct stat stat_buf
Definition: pg_standby.c:101
bool FirstSnapshotSet
Definition: snapmgr.c:205
#define MAXPGPATH
static void parseVxidFromText(const char *prefix, char **s, const char *filename, VirtualTransactionId *vxid)
Definition: snapmgr.c:1432
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2205
#define InvalidTransactionId
Definition: transam.h:31
SnapshotType snapshot_type
Definition: snapshot.h:144
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:410
#define ereport(elevel, rest)
Definition: elog.h:141
TransactionId * xip
Definition: snapshot.h:168
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
#define stat(a, b)
Definition: win32_port.h:255
Oid MyDatabaseId
Definition: globals.c:85
int GetMaxSnapshotXidCount(void)
Definition: procarray.c:1450
bool XactReadOnly
Definition: xact.c:78
bool takenDuringRecovery
Definition: snapshot.h:184
int FreeFile(FILE *file)
Definition: fd.c:2404
bool IsSubTransaction(void)
Definition: xact.c:4706
uint32 xcnt
Definition: snapshot.h:169
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define IsolationIsSerializable()
Definition: xact.h:52
#define elog(elevel,...)
Definition: elog.h:226
int i
int GetMaxSnapshotSubxidCount(void)
Definition: procarray.c:1461
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define snprintf
Definition: port.h:192
TransactionId * subxip
Definition: snapshot.h:180
int32 subxcnt
Definition: snapshot.h:181

◆ InvalidateCatalogSnapshot()

void InvalidateCatalogSnapshot ( void  )

Definition at line 512 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().

513 {
514  if (CatalogSnapshot)
515  {
517  CatalogSnapshot = NULL;
519  }
520 }
static void SnapshotResetXmin(void)
Definition: snapmgr.c:1010
static Snapshot CatalogSnapshot
Definition: snapmgr.c:153
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
pairingheap_node ph_node
Definition: snapshot.h:200
void pairingheap_remove(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:170

◆ InvalidateCatalogSnapshotConditionally()

void InvalidateCatalogSnapshotConditionally ( void  )

Definition at line 533 of file snapmgr.c.

References InvalidateCatalogSnapshot(), and pairingheap_is_singular.

Referenced by PostgresMain().

534 {
535  if (CatalogSnapshot &&
536  ActiveSnapshot == NULL &&
539 }
static Snapshot CatalogSnapshot
Definition: snapmgr.c:153
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:512
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190
#define pairingheap_is_singular(h)
Definition: pairingheap.h:99

◆ MaintainOldSnapshotTimeMapping()

void MaintainOldSnapshotTimeMapping ( TimestampTz  whenTaken,
TransactionId  xmin 
)

Definition at line 1882 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().

1883 {
1884  TimestampTz ts;
1885  TransactionId latest_xmin;
1886  TimestampTz update_ts;
1887  bool map_update_required = false;
1888 
1889  /* Never call this function when old snapshot checking is disabled. */
1891 
1892  ts = AlignTimestampToMinuteBoundary(whenTaken);
1893 
1894  /*
1895  * Keep track of the latest xmin seen by any process. Update mapping with
1896  * a new value when we have crossed a bucket boundary.
1897  */
1899  latest_xmin = oldSnapshotControl->latest_xmin;
1900  update_ts = oldSnapshotControl->next_map_update;
1901  if (ts > update_ts)
1902  {
1904  map_update_required = true;
1905  }
1906  if (TransactionIdFollows(xmin, latest_xmin))
1909 
1910  /* We only needed to update the most recent xmin value. */
1911  if (!map_update_required)
1912  return;
1913 
1914  /* No further tracking needed for 0 (used for testing). */
1915  if (old_snapshot_threshold == 0)
1916  return;
1917 
1918  /*
1919  * We don't want to do something stupid with unusual values, but we don't
1920  * want to litter the log with warnings or break otherwise normal
1921  * processing for this feature; so if something seems unreasonable, just
1922  * log at DEBUG level and return without doing anything.
1923  */
1924  if (whenTaken < 0)
1925  {
1926  elog(DEBUG1,
1927  "MaintainOldSnapshotTimeMapping called with negative whenTaken = %ld",
1928  (long) whenTaken);
1929  return;
1930  }
1931  if (!TransactionIdIsNormal(xmin))
1932  {
1933  elog(DEBUG1,
1934  "MaintainOldSnapshotTimeMapping called with xmin = %lu",
1935  (unsigned long) xmin);
1936  return;
1937  }
1938 
1939  LWLockAcquire(OldSnapshotTimeMapLock, LW_EXCLUSIVE);
1940 
1946 
1947  if (oldSnapshotControl->count_used == 0)
1948  {
1949  /* set up first entry for empty mapping */
1953  oldSnapshotControl->xid_by_minute[0] = xmin;
1954  }
1955  else if (ts < oldSnapshotControl->head_timestamp)
1956  {
1957  /* old ts; log it at DEBUG */
1958  LWLockRelease(OldSnapshotTimeMapLock);
1959  elog(DEBUG1,
1960  "MaintainOldSnapshotTimeMapping called with old whenTaken = %ld",
1961  (long) whenTaken);
1962  return;
1963  }
1964  else if (ts <= (oldSnapshotControl->head_timestamp +
1966  * USECS_PER_MINUTE)))
1967  {
1968  /* existing mapping; advance xid if possible */
1969  int bucket = (oldSnapshotControl->head_offset
1971  / USECS_PER_MINUTE))
1973 
1975  oldSnapshotControl->xid_by_minute[bucket] = xmin;
1976  }
1977  else
1978  {
1979  /* We need a new bucket, but it might not be the very next one. */
1980  int advance = ((ts - oldSnapshotControl->head_timestamp)
1981  / USECS_PER_MINUTE);
1982 
1984 
1985  if (advance >= OLD_SNAPSHOT_TIME_MAP_ENTRIES)
1986  {
1987  /* Advance is so far that all old data is junk; start over. */
1990  oldSnapshotControl->xid_by_minute[0] = xmin;
1991  }
1992  else
1993  {
1994  /* Store the new value in one or more buckets. */
1995  int i;
1996 
1997  for (i = 0; i < advance; i++)
1998  {
2000  {
2001  /* Map full and new value replaces old head. */
2002  int old_head = oldSnapshotControl->head_offset;
2003 
2004  if (old_head == (OLD_SNAPSHOT_TIME_MAP_ENTRIES - 1))
2006  else
2007  oldSnapshotControl->head_offset = old_head + 1;
2008  oldSnapshotControl->xid_by_minute[old_head] = xmin;
2009  }
2010  else
2011  {
2012  /* Extend map to unused entry. */
2013  int new_tail = (oldSnapshotControl->head_offset
2016 
2018  oldSnapshotControl->xid_by_minute[new_tail] = xmin;
2019  }
2020  }
2021  }
2022  }
2023 
2024  LWLockRelease(OldSnapshotTimeMapLock);
2025 }
#define DEBUG1
Definition: elog.h:25
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:507
int64 TimestampTz
Definition: timestamp.h:39
#define USECS_PER_MINUTE
Definition: timestamp.h:93
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#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:732
TransactionId xid_by_minute[FLEXIBLE_ARRAY_MEMBER]
Definition: snapmgr.c:126
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static TimestampTz AlignTimestampToMinuteBoundary(TimestampTz ts)
Definition: snapmgr.c:1706
#define elog(elevel,...)
Definition: elog.h:226
int old_snapshot_threshold
Definition: snapmgr.c:75
TimestampTz head_timestamp
Definition: snapmgr.c:124
int i
#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 1382 of file snapmgr.c.

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

Referenced by ImportSnapshot().

1383 {
1384  char *ptr = *s;
1385  int prefixlen = strlen(prefix);
1386  int val;
1387 
1388  if (strncmp(ptr, prefix, prefixlen) != 0)
1389  ereport(ERROR,
1390  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1391  errmsg("invalid snapshot data in file \"%s\"", filename)));
1392  ptr += prefixlen;
1393  if (sscanf(ptr, "%d", &val) != 1)
1394  ereport(ERROR,
1395  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1396  errmsg("invalid snapshot data in file \"%s\"", filename)));
1397  ptr = strchr(ptr, '\n');
1398  if (!ptr)
1399  ereport(ERROR,
1400  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1401  errmsg("invalid snapshot data in file \"%s\"", filename)));
1402  *s = ptr + 1;
1403  return val;
1404 }
int errcode(int sqlerrcode)
Definition: elog.c:570
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
static char * filename
Definition: pg_dumpall.c:91
int errmsg(const char *fmt,...)
Definition: elog.c:784
long val
Definition: informix.c:684

◆ parseVxidFromText()

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

Definition at line 1432 of file snapmgr.c.

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

Referenced by ImportSnapshot().

1434 {
1435  char *ptr = *s;
1436  int prefixlen = strlen(prefix);
1437 
1438  if (strncmp(ptr, prefix, prefixlen) != 0)
1439  ereport(ERROR,
1440  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1441  errmsg("invalid snapshot data in file \"%s\"", filename)));
1442  ptr += prefixlen;
1443  if (sscanf(ptr, "%d/%u", &vxid->backendId, &vxid->localTransactionId) != 2)
1444  ereport(ERROR,
1445  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1446  errmsg("invalid snapshot data in file \"%s\"", filename)));
1447  ptr = strchr(ptr, '\n');
1448  if (!ptr)
1449  ereport(ERROR,
1450  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1451  errmsg("invalid snapshot data in file \"%s\"", filename)));
1452  *s = ptr + 1;
1453 }
int errcode(int sqlerrcode)
Definition: elog.c:570
LocalTransactionId localTransactionId
Definition: lock.h:66
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
BackendId backendId
Definition: lock.h:65
static char * filename
Definition: pg_dumpall.c:91
int errmsg(const char *fmt,...)
Definition: elog.c:784

◆ parseXidFromText()

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

Definition at line 1407 of file snapmgr.c.

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

Referenced by ImportSnapshot().

1408 {
1409  char *ptr = *s;
1410  int prefixlen = strlen(prefix);
1412 
1413  if (strncmp(ptr, prefix, prefixlen) != 0)
1414  ereport(ERROR,
1415  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1416  errmsg("invalid snapshot data in file \"%s\"", filename)));
1417  ptr += prefixlen;
1418  if (sscanf(ptr, "%u", &val) != 1)
1419  ereport(ERROR,
1420  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1421  errmsg("invalid snapshot data in file \"%s\"", filename)));
1422  ptr = strchr(ptr, '\n');
1423  if (!ptr)
1424  ereport(ERROR,
1425  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1426  errmsg("invalid snapshot data in file \"%s\"", filename)));
1427  *s = ptr + 1;
1428  return val;
1429 }
uint32 TransactionId
Definition: c.h:507
int errcode(int sqlerrcode)
Definition: elog.c:570
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
static char * filename
Definition: pg_dumpall.c:91
int errmsg(const char *fmt,...)
Definition: elog.c:784
long val
Definition: informix.c:684

◆ pg_export_snapshot()

Datum pg_export_snapshot ( PG_FUNCTION_ARGS  )

Definition at line 1367 of file snapmgr.c.

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

1368 {
1369  char *snapshotName;
1370 
1371  snapshotName = ExportSnapshot(GetActiveSnapshot());
1372  PG_RETURN_TEXT_P(cstring_to_text(snapshotName));
1373 }
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
char * ExportSnapshot(Snapshot snapshot)
Definition: snapmgr.c:1191
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:361
text * cstring_to_text(const char *s)
Definition: varlena.c:171

◆ PopActiveSnapshot()

void PopActiveSnapshot ( void  )

Definition at line 814 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_commit(), _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(), exec_stmt_call(), 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(), ReindexRelationConcurrently(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RevalidateCachedQuery(), ShutdownSQLFunction(), vacuum(), vacuum_rel(), and wait_for_relation_state_change().

815 {
816  ActiveSnapshotElt *newstack;
817 
818  newstack = ActiveSnapshot->as_next;
819 
821 
823 
824  if (ActiveSnapshot->as_snap->active_count == 0 &&
827 
829  ActiveSnapshot = newstack;
830  if (ActiveSnapshot == NULL)
831  OldestActiveSnapshot = NULL;
832 
834 }
Snapshot as_snap
Definition: snapmgr.c:184
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:717
static void SnapshotResetXmin(void)
Definition: snapmgr.c:1010
uint32 regd_count
Definition: snapshot.h:199
void pfree(void *pointer)
Definition: mcxt.c:1056
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:193
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:186
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190
#define Assert(condition)
Definition: c.h:732
uint32 active_count
Definition: snapshot.h:198

◆ PushActiveSnapshot()

void PushActiveSnapshot ( Snapshot  snap)

Definition at line 735 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(), exec_stmt_call(), execute_sql_string(), fmgr_sql(), HandleFunctionRequest(), initialize_worker_spi(), LogicalRepSyncTableStart(), ParallelWorkerMain(), PersistHoldablePortal(), PortalRunSelect(), PortalRunUtility(), PortalStart(), PushCopiedSnapshot(), ReindexMultipleTables(), ReindexRelationConcurrently(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RevalidateCachedQuery(), ShutdownSQLFunction(), vacuum(), vacuum_rel(), and wait_for_relation_state_change().

736 {
737  ActiveSnapshotElt *newactive;
738 
739  Assert(snap != InvalidSnapshot);
740 
742 
743  /*
744  * Checking SecondarySnapshot is probably useless here, but it seems
745  * better to be sure.
746  */
747  if (snap == CurrentSnapshot || snap == SecondarySnapshot || !snap->copied)
748  newactive->as_snap = CopySnapshot(snap);
749  else
750  newactive->as_snap = snap;
751 
752  newactive->as_next = ActiveSnapshot;
754 
755  newactive->as_snap->active_count++;
756 
757  ActiveSnapshot = newactive;
758  if (OldestActiveSnapshot == NULL)
760 }
Snapshot as_snap
Definition: snapmgr.c:184
MemoryContext TopTransactionContext
Definition: mcxt.c:49
bool copied
Definition: snapshot.h:185
static Snapshot CurrentSnapshot
Definition: snapmgr.c:151
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:193
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:186
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190
#define InvalidSnapshot
Definition: snapshot.h:123
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:662
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:842
#define Assert(condition)
Definition: c.h:732
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
static Snapshot SecondarySnapshot
Definition: snapmgr.c:152
uint32 active_count
Definition: snapshot.h:198

◆ PushCopiedSnapshot()

void PushCopiedSnapshot ( Snapshot  snapshot)

Definition at line 771 of file snapmgr.c.

References CopySnapshot(), and PushActiveSnapshot().

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

772 {
773  PushActiveSnapshot(CopySnapshot(snapshot));
774 }
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:662

◆ RegisterSnapshot()

◆ RegisterSnapshotOnOwner()

Snapshot RegisterSnapshotOnOwner ( Snapshot  snapshot,
ResourceOwner  owner 
)

Definition at line 878 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().

879 {
880  Snapshot snap;
881 
882  if (snapshot == InvalidSnapshot)
883  return InvalidSnapshot;
884 
885  /* Static snapshot? Create a persistent copy */
886  snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
887 
888  /* and tell resowner.c about it */
890  snap->regd_count++;
891  ResourceOwnerRememberSnapshot(owner, snap);
892 
893  if (snap->regd_count == 1)
895 
896  return snap;
897 }
bool copied
Definition: snapshot.h:185
void ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
Definition: resowner.c:1187
uint32 regd_count
Definition: snapshot.h:199
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
#define InvalidSnapshot
Definition: snapshot.h:123
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:662
pairingheap_node ph_node
Definition: snapshot.h:200
void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1198
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112

◆ RestoreSnapshot()

Snapshot RestoreSnapshot ( char *  start_address)

Definition at line 2161 of file snapmgr.c.

References SnapshotData::active_count, SnapshotData::copied, SnapshotData::curcid, SerializedSnapshotData::curcid, SnapshotData::lsn, SerializedSnapshotData::lsn, MemoryContextAlloc(), SnapshotData::regd_count, SNAPSHOT_MVCC, SnapshotData::snapshot_type, 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(), index_beginscan_parallel(), ParallelWorkerMain(), and table_beginscan_parallel().

2162 {
2163  SerializedSnapshotData serialized_snapshot;
2164  Size size;
2165  Snapshot snapshot;
2166  TransactionId *serialized_xids;
2167 
2168  memcpy(&serialized_snapshot, start_address,
2169  sizeof(SerializedSnapshotData));
2170  serialized_xids = (TransactionId *)
2171  (start_address + sizeof(SerializedSnapshotData));
2172 
2173  /* We allocate any XID arrays needed in the same palloc block. */
2174  size = sizeof(SnapshotData)
2175  + serialized_snapshot.xcnt * sizeof(TransactionId)
2176  + serialized_snapshot.subxcnt * sizeof(TransactionId);
2177 
2178  /* Copy all required fields */
2180  snapshot->snapshot_type = SNAPSHOT_MVCC;
2181  snapshot->xmin = serialized_snapshot.xmin;
2182  snapshot->xmax = serialized_snapshot.xmax;
2183  snapshot->xip = NULL;
2184  snapshot->xcnt = serialized_snapshot.xcnt;
2185  snapshot->subxip = NULL;
2186  snapshot->subxcnt = serialized_snapshot.subxcnt;
2187  snapshot->suboverflowed = serialized_snapshot.suboverflowed;
2188  snapshot->takenDuringRecovery = serialized_snapshot.takenDuringRecovery;
2189  snapshot->curcid = serialized_snapshot.curcid;
2190  snapshot->whenTaken = serialized_snapshot.whenTaken;
2191  snapshot->lsn = serialized_snapshot.lsn;
2192 
2193  /* Copy XIDs, if present. */
2194  if (serialized_snapshot.xcnt > 0)
2195  {
2196  snapshot->xip = (TransactionId *) (snapshot + 1);
2197  memcpy(snapshot->xip, serialized_xids,
2198  serialized_snapshot.xcnt * sizeof(TransactionId));
2199  }
2200 
2201  /* Copy SubXIDs, if present. */
2202  if (serialized_snapshot.subxcnt > 0)
2203  {
2204  snapshot->subxip = ((TransactionId *) (snapshot + 1)) +
2205  serialized_snapshot.xcnt;
2206  memcpy(snapshot->subxip, serialized_xids + serialized_snapshot.xcnt,
2207  serialized_snapshot.subxcnt * sizeof(TransactionId));
2208  }
2209 
2210  /* Set the copied flag so that the caller will set refcounts correctly. */
2211  snapshot->regd_count = 0;
2212  snapshot->active_count = 0;
2213  snapshot->copied = true;
2214 
2215  return snapshot;
2216 }
MemoryContext TopTransactionContext
Definition: mcxt.c:49
uint32 TransactionId
Definition: c.h:507
bool copied
Definition: snapshot.h:185
XLogRecPtr lsn
Definition: snapshot.h:203
TimestampTz whenTaken
Definition: snapmgr.c:248
bool suboverflowed
Definition: snapshot.h:182
struct SnapshotData * Snapshot
Definition: snapshot.h:121
uint32 regd_count
Definition: snapshot.h:199
struct SnapshotData SnapshotData
SnapshotType snapshot_type
Definition: snapshot.h:144
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
TransactionId * xip
Definition: snapshot.h:168
TransactionId xmax
Definition: snapmgr.c:242
CommandId curcid
Definition: snapshot.h:187
bool takenDuringRecovery
Definition: snapshot.h:184
size_t Size
Definition: c.h:466
uint32 xcnt
Definition: snapshot.h:169
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
TransactionId xmin
Definition: snapmgr.c:241
TimestampTz whenTaken
Definition: snapshot.h:202
TransactionId * subxip
Definition: snapshot.h:180
uint32 active_count
Definition: snapshot.h:198
int32 subxcnt
Definition: snapshot.h:181

◆ RestoreTransactionSnapshot()

void RestoreTransactionSnapshot ( Snapshot  snapshot,
void *  master_pgproc 
)

Definition at line 2225 of file snapmgr.c.

References InvalidPid, and SetTransactionSnapshot().

Referenced by CreateReplicationSlot(), and ParallelWorkerMain().

2226 {
2227  SetTransactionSnapshot(snapshot, NULL, InvalidPid, master_pgproc);
2228 }
static void SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid, int sourcepid, PGPROC *sourceproc)
Definition: snapmgr.c:567
#define InvalidPid
Definition: miscadmin.h:32

◆ SerializeSnapshot()

void SerializeSnapshot ( Snapshot  snapshot,
char *  start_address 
)

Definition at line 2102 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(), index_parallelscan_initialize(), InitializeParallelDSM(), and table_parallelscan_initialize().

2103 {
2104  SerializedSnapshotData serialized_snapshot;
2105 
2106  Assert(snapshot->subxcnt >= 0);
2107 
2108  /* Copy all required fields */
2109  serialized_snapshot.xmin = snapshot->xmin;
2110  serialized_snapshot.xmax = snapshot->xmax;
2111  serialized_snapshot.xcnt = snapshot->xcnt;
2112  serialized_snapshot.subxcnt = snapshot->subxcnt;
2113  serialized_snapshot.suboverflowed = snapshot->suboverflowed;
2114  serialized_snapshot.takenDuringRecovery = snapshot->takenDuringRecovery;
2115  serialized_snapshot.curcid = snapshot->curcid;
2116  serialized_snapshot.whenTaken = snapshot->whenTaken;
2117  serialized_snapshot.lsn = snapshot->lsn;
2118 
2119  /*
2120  * Ignore the SubXID array if it has overflowed, unless the snapshot was
2121  * taken during recovery - in that case, top-level XIDs are in subxip as
2122  * well, and we mustn't lose them.
2123  */
2124  if (serialized_snapshot.suboverflowed && !snapshot->takenDuringRecovery)
2125  serialized_snapshot.subxcnt = 0;
2126 
2127  /* Copy struct to possibly-unaligned buffer */
2128  memcpy(start_address,
2129  &serialized_snapshot, sizeof(SerializedSnapshotData));
2130 
2131  /* Copy XID array */
2132  if (snapshot->xcnt > 0)
2133  memcpy((TransactionId *) (start_address +
2134  sizeof(SerializedSnapshotData)),
2135  snapshot->xip, snapshot->xcnt * sizeof(TransactionId));
2136 
2137  /*
2138  * Copy SubXID array. Don't bother to copy it if it had overflowed,
2139  * though, because it's not used anywhere in that case. Except if it's a
2140  * snapshot taken during recovery; all the top-level XIDs are in subxip as
2141  * well in that case, so we mustn't lose them.
2142  */
2143  if (serialized_snapshot.subxcnt > 0)
2144  {
2145  Size subxipoff = sizeof(SerializedSnapshotData) +
2146  snapshot->xcnt * sizeof(TransactionId);
2147 
2148  memcpy((TransactionId *) (start_address + subxipoff),
2149  snapshot->subxip, snapshot->subxcnt * sizeof(TransactionId));
2150  }
2151 }
uint32 TransactionId
Definition: c.h:507
XLogRecPtr lsn
Definition: snapshot.h:203
TimestampTz whenTaken
Definition: snapmgr.c:248
bool suboverflowed
Definition: snapshot.h:182
struct SerializedSnapshotData SerializedSnapshotData
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
TransactionId * xip
Definition: snapshot.h:168
TransactionId xmax
Definition: snapmgr.c:242
CommandId curcid
Definition: snapshot.h:187
#define Assert(condition)
Definition: c.h:732
bool takenDuringRecovery
Definition: snapshot.h:184
size_t Size
Definition: c.h:466
uint32 xcnt
Definition: snapshot.h:169
TransactionId xmin
Definition: snapmgr.c:241
TimestampTz whenTaken
Definition: snapshot.h:202
TransactionId * subxip
Definition: snapshot.h:180
int32 subxcnt
Definition: snapshot.h:181

◆ SetOldSnapshotThresholdTimestamp()

static void SetOldSnapshotThresholdTimestamp ( TimestampTz  ts,
TransactionId  xlimit 
)
static

Definition at line 1757 of file snapmgr.c.

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

Referenced by TransactionIdLimitedForOldSnapshots().

1758 {
1763 }
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 567 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().

569 {
570  /* Caller should have checked this already */
572 
573  /* Better do this to ensure following Assert succeeds. */
575 
577  Assert(FirstXactSnapshot == NULL);
579 
580  /*
581  * Even though we are not going to use the snapshot it computes, we must
582  * call GetSnapshotData, for two reasons: (1) to be sure that
583  * CurrentSnapshotData's XID arrays have been allocated, and (2) to update
584  * RecentXmin and RecentGlobalXmin. (We could alternatively include those
585  * two variables in exported snapshot files, but it seems better to have
586  * snapshot importers compute reasonably up-to-date values for them.)
587  */
589 
590  /*
591  * Now copy appropriate fields from the source snapshot.
592  */
593  CurrentSnapshot->xmin = sourcesnap->xmin;
594  CurrentSnapshot->xmax = sourcesnap->xmax;
595  CurrentSnapshot->xcnt = sourcesnap->xcnt;
596  Assert(sourcesnap->xcnt <= GetMaxSnapshotXidCount());
597  memcpy(CurrentSnapshot->xip, sourcesnap->xip,
598  sourcesnap->xcnt * sizeof(TransactionId));
599  CurrentSnapshot->subxcnt = sourcesnap->subxcnt;
600  Assert(sourcesnap->subxcnt <= GetMaxSnapshotSubxidCount());
601  memcpy(CurrentSnapshot->subxip, sourcesnap->subxip,
602  sourcesnap->subxcnt * sizeof(TransactionId));
605  /* NB: curcid should NOT be copied, it's a local matter */
606 
607  /*
608  * Now we have to fix what GetSnapshotData did with MyPgXact->xmin and
609  * TransactionXmin. There is a race condition: to make sure we are not
610  * causing the global xmin to go backwards, we have to test that the
611  * source transaction is still running, and that has to be done
612  * atomically. So let procarray.c do it.
613  *
614  * Note: in serializable mode, predicate.c will do this a second time. It
615  * doesn't seem worth contorting the logic here to avoid two calls,
616  * especially since it's not clear that predicate.c *must* do this.
617  */
618  if (sourceproc != NULL)
619  {
621  ereport(ERROR,
622  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
623  errmsg("could not import the requested snapshot"),
624  errdetail("The source transaction is not running anymore.")));
625  }
626  else if (!ProcArrayInstallImportedXmin(CurrentSnapshot->xmin, sourcevxid))
627  ereport(ERROR,
628  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
629  errmsg("could not import the requested snapshot"),
630  errdetail("The source process with PID %d is not running anymore.",
631  sourcepid)));
632 
633  /*
634  * In transaction-snapshot mode, the first snapshot must live until end of
635  * xact, so we must make a copy of it. Furthermore, if we're running in
636  * serializable mode, predicate.c needs to do its own processing.
637  */
639  {
642  sourcepid);
643  /* Make a saved copy */
646  /* Mark it as "registered" in FirstXactSnapshot */
649  }
650 
651  FirstSnapshotSet = true;
652 }
void SetSerializableTransactionSnapshot(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1653
uint32 TransactionId
Definition: c.h:507
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
int errcode(int sqlerrcode)
Definition: elog.c:570
bool suboverflowed
Definition: snapshot.h:182
static SnapshotData CurrentSnapshotData
Definition: snapmgr.c:144
static Snapshot FirstXactSnapshot
Definition: snapmgr.c:212
uint32 regd_count
Definition: snapshot.h:199
static Snapshot CurrentSnapshot
Definition: snapmgr.c:151
#define ERROR
Definition: elog.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
bool FirstSnapshotSet
Definition: snapmgr.c:205
int errdetail(const char *fmt,...)
Definition: elog.c:860
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
#define ereport(elevel, rest)
Definition: elog.h:141
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:512
TransactionId * xip
Definition: snapshot.h:168
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:662
int GetMaxSnapshotXidCount(void)
Definition: procarray.c:1450
pairingheap_node ph_node
Definition: snapshot.h:200
#define Assert(condition)
Definition: c.h:732
bool takenDuringRecovery
Definition: snapshot.h:184
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1503
bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc)
Definition: procarray.c:1869
uint32 xcnt
Definition: snapshot.h:169
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2058
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define IsolationIsSerializable()
Definition: xact.h:52
int GetMaxSnapshotSubxidCount(void)
Definition: procarray.c:1461
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:1794
TransactionId * subxip
Definition: snapshot.h:180
int32 subxcnt
Definition: snapshot.h:181

◆ SetupHistoricSnapshot()

void SetupHistoricSnapshot ( Snapshot  historic_snapshot,
HTAB tuplecids 
)

Definition at line 2035 of file snapmgr.c.

References Assert.

Referenced by ReorderBufferCommit(), and ReorderBufferQueueMessage().

2036 {
2037  Assert(historic_snapshot != NULL);
2038 
2039  /* setup the timetravel snapshot */
2040  HistoricSnapshot = historic_snapshot;
2041 
2042  /* setup (cmin, cmax) lookup hash */
2043  tuplecid_data = tuplecids;
2044 }
static Snapshot HistoricSnapshot
Definition: snapmgr.c:154
static HTAB * tuplecid_data
Definition: snapmgr.c:172
#define Assert(condition)
Definition: c.h:732

◆ SnapMgrInit()

void SnapMgrInit ( void  )

Definition at line 269 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().

270 {
271  bool found;
272 
273  /*
274  * Create or attach to the OldSnapshotControlData structure.
275  */
277  ShmemInitStruct("OldSnapshotControlData",
278  SnapMgrShmemSize(), &found);
279 
280  if (!found)
281  {
293  }
294 }
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:253

◆ SnapMgrShmemSize()

Size SnapMgrShmemSize ( void  )

Definition at line 253 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().

254 {
255  Size size;
256 
257  size = offsetof(OldSnapshotControlData, xid_by_minute);
258  if (old_snapshot_threshold > 0)
259  size = add_size(size, mul_size(sizeof(TransactionId),
261 
262  return size;
263 }
uint32 TransactionId
Definition: c.h:507
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:466
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:655

◆ SnapshotResetXmin()

static void SnapshotResetXmin ( void  )
static

Definition at line 1010 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().

1011 {
1012  Snapshot minSnapshot;
1013 
1014  if (ActiveSnapshot != NULL)
1015  return;
1016 
1018  {
1020  return;
1021  }
1022 
1023  minSnapshot = pairingheap_container(SnapshotData, ph_node,
1025 
1026  if (TransactionIdPrecedes(MyPgXact->xmin, minSnapshot->xmin))
1027  MyPgXact->xmin = minSnapshot->xmin;
1028 }
pairingheap_node * pairingheap_first(pairingheap *heap)
Definition: pairingheap.c:130
TransactionId xmin
Definition: proc.h:228
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
PGXACT * MyPgXact
Definition: proc.c:69
#define pairingheap_container(type, membername, ptr)
Definition: pairingheap.h:43
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
#define InvalidTransactionId
Definition: transam.h:31
TransactionId xmin
Definition: snapshot.h:157
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190

◆ SnapshotSetCommandId()

void SnapshotSetCommandId ( CommandId  curcid)

Definition at line 546 of file snapmgr.c.

References SnapshotData::curcid, and FirstSnapshotSet.

Referenced by CommandCounterIncrement().

547 {
548  if (!FirstSnapshotSet)
549  return;
550 
551  if (CurrentSnapshot)
552  CurrentSnapshot->curcid = curcid;
553  if (SecondarySnapshot)
554  SecondarySnapshot->curcid = curcid;
555  /* Should we do the same with CatalogSnapshot? */
556 }
static Snapshot CurrentSnapshot
Definition: snapmgr.c:151
bool FirstSnapshotSet
Definition: snapmgr.c:205
CommandId curcid
Definition: snapshot.h:187
static Snapshot SecondarySnapshot
Definition: snapmgr.c:152

◆ TeardownHistoricSnapshot()

void TeardownHistoricSnapshot ( bool  is_error)

Definition at line 2051 of file snapmgr.c.

Referenced by ReorderBufferCommit(), and ReorderBufferQueueMessage().

2052 {
2053  HistoricSnapshot = NULL;
2054  tuplecid_data = NULL;
2055 }
static Snapshot HistoricSnapshot
Definition: snapmgr.c:154
static HTAB * tuplecid_data
Definition: snapmgr.c:172

◆ ThereAreNoPriorRegisteredSnapshots()

bool ThereAreNoPriorRegisteredSnapshots ( void  )

Definition at line 1689 of file snapmgr.c.

References pairingheap_is_empty, and pairingheap_is_singular.

Referenced by CopyFrom().

1690 {
1693  return true;
1694 
1695  return false;
1696 }
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
#define pairingheap_is_singular(h)
Definition: pairingheap.h:99

◆ TransactionIdLimitedForOldSnapshots()

TransactionId TransactionIdLimitedForOldSnapshots ( TransactionId  recentXmin,
Relation  relation 
)

Definition at line 1775 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().

1777 {
1778  if (TransactionIdIsNormal(recentXmin)
1779  && old_snapshot_threshold >= 0
1780  && RelationAllowsEarlyPruning(relation))
1781  {
1783  TransactionId xlimit = recentXmin;
1784  TransactionId latest_xmin;
1785  TimestampTz update_ts;
1786  bool same_ts_as_threshold = false;
1787 
1789  latest_xmin = oldSnapshotControl->latest_xmin;
1790  update_ts = oldSnapshotControl->next_map_update;
1792 
1793  /*
1794  * Zero threshold always overrides to latest xmin, if valid. Without
1795  * some heuristic it will find its own snapshot too old on, for
1796  * example, a simple UPDATE -- which would make it useless for most
1797  * testing, but there is no principled way to ensure that it doesn't
1798  * fail in this way. Use a five-second delay to try to get useful
1799  * testing behavior, but this may need adjustment.
1800  */
1801  if (old_snapshot_threshold == 0)
1802  {
1803  if (TransactionIdPrecedes(latest_xmin, MyPgXact->xmin)
1804  && TransactionIdFollows(latest_xmin, xlimit))
1805  xlimit = latest_xmin;
1806 
1807  ts -= 5 * USECS_PER_SEC;
1809 
1810  return xlimit;
1811  }
1812 
1815 
1816  /* Check for fast exit without LW locking. */
1819  {
1821  same_ts_as_threshold = true;
1822  }
1824 
1825  if (!same_ts_as_threshold)
1826  {
1827  if (ts == update_ts)
1828  {
1829  xlimit = latest_xmin;
1830  if (NormalTransactionIdFollows(xlimit, recentXmin))
1832  }
1833  else
1834  {
1835  LWLockAcquire(OldSnapshotTimeMapLock, LW_SHARED);
1836 
1839  {
1840  int offset;
1841 
1842  offset = ((ts - oldSnapshotControl->head_timestamp)
1843  / USECS_PER_MINUTE);
1844  if (offset > oldSnapshotControl->count_used - 1)
1845  offset = oldSnapshotControl->count_used - 1;
1846  offset = (oldSnapshotControl->head_offset + offset)
1848  xlimit = oldSnapshotControl->xid_by_minute[offset];
1849 
1850  if (NormalTransactionIdFollows(xlimit, recentXmin))
1852  }
1853 
1854  LWLockRelease(OldSnapshotTimeMapLock);
1855  }
1856  }
1857 
1858  /*
1859  * Failsafe protection against vacuuming work of active transaction.
1860  *
1861  * This is not an assertion because we avoid the spinlock for
1862  * performance, leaving open the possibility that xlimit could advance
1863  * and be more current; but it seems prudent to apply this limit. It
1864  * might make pruning a tiny bit less aggressive than it could be, but
1865  * protects against data loss bugs.
1866  */
1867  if (TransactionIdIsNormal(latest_xmin)
1868  && TransactionIdPrecedes(latest_xmin, xlimit))
1869  xlimit = latest_xmin;
1870 
1871  if (NormalTransactionIdFollows(xlimit, recentXmin))
1872  return xlimit;
1873  }
1874 
1875  return recentXmin;
1876 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:507
#define USECS_PER_SEC
Definition: timestamp.h:94
TransactionId xmin
Definition: proc.h:228
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:69
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define SpinLockAcquire(lock)
Definition: spin.h:62
TimestampTz threshold_timestamp
Definition: snapmgr.c:92
TimestampTz GetSnapshotCurrentTimestamp(void)
Definition: snapmgr.c:1720
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:1757
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:103
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static TimestampTz AlignTimestampToMinuteBoundary(TimestampTz ts)
Definition: snapmgr.c:1706
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 920 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(), PreCommit_Portals(), and UnregisterSnapshot().

921 {
922  if (snapshot == NULL)
923  return;
924 
925  Assert(snapshot->regd_count > 0);
927 
928  ResourceOwnerForgetSnapshot(owner, snapshot);
929 
930  snapshot->regd_count--;
931  if (snapshot->regd_count == 0)
933 
934  if (snapshot->regd_count == 0 && snapshot->active_count == 0)
935  {
936  FreeSnapshot(snapshot);
938  }
939 }
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:717
static void SnapshotResetXmin(void)
Definition: snapmgr.c:1010
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
uint32 regd_count
Definition: snapshot.h:199
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:202
void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1207
pairingheap_node ph_node
Definition: snapshot.h:200
#define Assert(condition)
Definition: c.h:732
void pairingheap_remove(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:170
uint32 active_count
Definition: snapshot.h:198

◆ UpdateActiveSnapshotCommandId()

void UpdateActiveSnapshotCommandId ( void  )

Definition at line 783 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().

784 {
785  CommandId save_curcid,
786  curcid;
787 
788  Assert(ActiveSnapshot != NULL);
791 
792  /*
793  * Don't allow modification of the active snapshot during parallel
794  * operation. We share the snapshot to worker backends at the beginning
795  * of parallel operation, so any change to the snapshot can lead to
796  * inconsistencies. We have other defenses against
797  * CommandCounterIncrement, but there are a few places that call this
798  * directly, so we put an additional guard here.
799  */
800  save_curcid = ActiveSnapshot->as_snap->curcid;
801  curcid = GetCurrentCommandId(false);
802  if (IsInParallelMode() && save_curcid != curcid)
803  elog(ERROR, "cannot modify commandid in active snapshot during a parallel operation");
804  ActiveSnapshot->as_snap->curcid = curcid;
805 }
uint32 CommandId
Definition: c.h:521
Snapshot as_snap
Definition: snapmgr.c:184
uint32 regd_count
Definition: snapshot.h:199
bool IsInParallelMode(void)
Definition: xact.c:994
#define ERROR
Definition: elog.h:43
static ActiveSnapshotElt * ActiveSnapshot
Definition: snapmgr.c:190
CommandId curcid
Definition: snapshot.h:187
#define Assert(condition)
Definition: c.h:732
#define elog(elevel,...)
Definition: elog.h:226
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:746
uint32 active_count
Definition: snapshot.h:198

◆ XactHasExportedSnapshots()

bool XactHasExportedSnapshots ( void  )

Definition at line 1637 of file snapmgr.c.

References NIL.

Referenced by PrepareTransaction().

1638 {
1639  return (exportedSnapshots != NIL);
1640 }
#define NIL
Definition: pg_list.h:65
static List * exportedSnapshots
Definition: snapmgr.c:225

◆ XidInMVCCSnapshot()

bool XidInMVCCSnapshot ( TransactionId  xid,
Snapshot  snapshot 
)

Definition at line 2241 of file snapmgr.c.

References i, SnapshotData::suboverflowed, SubTransGetTopmostTransaction(), SnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TransactionIdEquals, TransactionIdFollowsOrEquals(), TransactionIdPrecedes(), SnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by asyncQueueProcessPageEntries(), and HeapTupleSatisfiesMVCC().

2242 {
2243  uint32 i;
2244 
2245  /*
2246  * Make a quick range check to eliminate most XIDs without looking at the
2247  * xip arrays. Note that this is OK even if we convert a subxact XID to
2248  * its parent below, because a subxact with XID < xmin has surely also got
2249  * a parent with XID < xmin, while one with XID >= xmax must belong to a
2250  * parent that was not yet committed at the time of this snapshot.
2251  */
2252 
2253  /* Any xid < xmin is not in-progress */
2254  if (TransactionIdPrecedes(xid, snapshot->xmin))
2255  return false;
2256  /* Any xid >= xmax is in-progress */
2257  if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
2258  return true;
2259 
2260  /*
2261  * Snapshot information is stored slightly differently in snapshots taken
2262  * during recovery.
2263  */
2264  if (!snapshot->takenDuringRecovery)
2265  {
2266  /*
2267  * If the snapshot contains full subxact data, the fastest way to
2268  * check things is just to compare the given XID against both subxact
2269  * XIDs and top-level XIDs. If the snapshot overflowed, we have to
2270  * use pg_subtrans to convert a subxact XID to its parent XID, but
2271  * then we need only look at top-level XIDs not subxacts.
2272  */
2273  if (!snapshot->suboverflowed)
2274  {
2275  /* we have full data, so search subxip */
2276  int32 j;
2277 
2278  for (j = 0; j < snapshot->subxcnt; j++)
2279  {
2280  if (TransactionIdEquals(xid, snapshot->subxip[j]))
2281  return true;
2282  }
2283 
2284  /* not there, fall through to search xip[] */
2285  }
2286  else
2287  {
2288  /*
2289  * Snapshot overflowed, so convert xid to top-level. This is safe
2290  * because we eliminated too-old XIDs above.
2291  */
2292  xid = SubTransGetTopmostTransaction(xid);
2293 
2294  /*
2295  * If xid was indeed a subxact, we might now have an xid < xmin,
2296  * so recheck to avoid an array scan. No point in rechecking
2297  * xmax.
2298  */
2299  if (TransactionIdPrecedes(xid, snapshot->xmin))
2300  return false;
2301  }
2302 
2303  for (i = 0; i < snapshot->xcnt; i++)
2304  {
2305  if (TransactionIdEquals(xid, snapshot->xip[i]))
2306  return true;
2307  }
2308  }
2309  else
2310  {
2311  int32 j;
2312 
2313  /*
2314  * In recovery we store all xids in the subxact array because it is by
2315  * far the bigger array, and we mostly don't know which xids are
2316  * top-level and which are subxacts. The xip array is empty.
2317  *
2318  * We start by searching subtrans, if we overflowed.
2319  */
2320  if (snapshot->suboverflowed)
2321  {
2322  /*
2323  * Snapshot overflowed, so convert xid to top-level. This is safe
2324  * because we eliminated too-old XIDs above.
2325  */
2326  xid = SubTransGetTopmostTransaction(xid);
2327 
2328  /*
2329  * If xid was indeed a subxact, we might now have an xid < xmin,
2330  * so recheck to avoid an array scan. No point in rechecking
2331  * xmax.
2332  */
2333  if (TransactionIdPrecedes(xid, snapshot->xmin))
2334  return false;
2335  }
2336 
2337  /*
2338  * We now have either a top-level xid higher than xmin or an
2339  * indeterminate xid. We don't know whether it's top level or subxact
2340  * but it doesn't matter. If it's present, the xid is visible.
2341  */
2342  for (j = 0; j < snapshot->subxcnt; j++)
2343  {
2344  if (TransactionIdEquals(xid, snapshot->subxip[j]))
2345  return true;
2346  }
2347  }
2348 
2349  return false;
2350 }
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:150
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
bool suboverflowed
Definition: snapshot.h:182
signed int int32
Definition: c.h:346
unsigned int uint32
Definition: c.h:358
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
TransactionId * xip
Definition: snapshot.h:168
bool takenDuringRecovery
Definition: snapshot.h:184
uint32 xcnt
Definition: snapshot.h:169
int i
TransactionId * subxip
Definition: snapshot.h:180
int32 subxcnt
Definition: snapshot.h:181

◆ xmin_cmp()

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

Definition at line 946 of file snapmgr.c.

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

947 {
948  const SnapshotData *asnap = pairingheap_const_container(SnapshotData, ph_node, a);
949  const SnapshotData *bsnap = pairingheap_const_container(SnapshotData, ph_node, b);
950 
951  if (TransactionIdPrecedes(asnap->xmin, bsnap->xmin))
952  return 1;
953  else if (TransactionIdFollows(asnap->xmin, bsnap->xmin))
954  return -1;
955  else
956  return 0;
957 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
TransactionId xmin
Definition: snapshot.h:157
#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 190 of file snapmgr.c.

Referenced by PushActiveSnapshot().

◆ CatalogSnapshot

Snapshot CatalogSnapshot = NULL
static

Definition at line 153 of file snapmgr.c.

Referenced by GetNonHistoricCatalogSnapshot().

◆ CatalogSnapshotData

SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC}

Definition at line 146 of file snapmgr.c.

◆ CurrentSnapshot

Snapshot CurrentSnapshot = NULL
static

Definition at line 151 of file snapmgr.c.

Referenced by GetTransactionSnapshot(), and SetTransactionSnapshot().

◆ CurrentSnapshotData

SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC}
static

Definition at line 144 of file snapmgr.c.

◆ exportedSnapshots

List* exportedSnapshots = NIL
static

Definition at line 225 of file snapmgr.c.

◆ FirstSnapshotSet

◆ FirstXactSnapshot

Snapshot FirstXactSnapshot = NULL
static

Definition at line 212 of file snapmgr.c.

◆ HistoricSnapshot

Snapshot HistoricSnapshot = NULL
static

Definition at line 154 of file snapmgr.c.

Referenced by GetCatalogSnapshot(), and GetTransactionSnapshot().

◆ old_snapshot_threshold

◆ OldestActiveSnapshot

ActiveSnapshotElt* OldestActiveSnapshot = NULL
static

Definition at line 193 of file snapmgr.c.

◆ oldSnapshotControl

volatile OldSnapshotControlData* oldSnapshotControl
static

Definition at line 129 of file snapmgr.c.

◆ RecentGlobalDataXmin

TransactionId RecentGlobalDataXmin = InvalidTransactionId

Definition at line 169 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 202 of file snapmgr.c.

◆ SecondarySnapshot

Snapshot SecondarySnapshot = NULL
static

Definition at line 152 of file snapmgr.c.

Referenced by GetLatestSnapshot().

◆ SecondarySnapshotData

SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC}
static

Definition at line 145 of file snapmgr.c.

◆ SnapshotAnyData

SnapshotData SnapshotAnyData = {SNAPSHOT_ANY}

Definition at line 148 of file snapmgr.c.

◆ SnapshotSelfData

SnapshotData SnapshotSelfData = {SNAPSHOT_SELF}

Definition at line 147 of file snapmgr.c.

◆ TransactionXmin

◆ tuplecid_data

HTAB* tuplecid_data = NULL
static

Definition at line 172 of file snapmgr.c.

Referenced by HistoricSnapshotGetTupleCids().