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 "datatype/timestamp.h"
#include "lib/pairingheap.h"
#include "miscadmin.h"
#include "port/pg_lfind.h"
#include "storage/fd.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.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
Include dependency graph for snapmgr.c:

Go to the source code of this file.

Data Structures

struct  ActiveSnapshotElt
 
struct  ExportedSnapshot
 
struct  SerializedSnapshotData
 

Macros

#define SNAPSHOT_EXPORT_DIR   "pg_snapshots"
 

Typedefs

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 Snapshot CopySnapshot (Snapshot snapshot)
 
static void UnregisterSnapshotNoOwner (Snapshot snapshot)
 
static void FreeSnapshot (Snapshot snapshot)
 
static void SnapshotResetXmin (void)
 
static void ResOwnerReleaseSnapshot (Datum res)
 
static void ResourceOwnerRememberSnapshot (ResourceOwner owner, Snapshot snap)
 
static void ResourceOwnerForgetSnapshot (ResourceOwner owner, Snapshot snap)
 
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 snapshot)
 
void PushActiveSnapshotWithLevel (Snapshot snapshot, int snap_level)
 
void PushCopiedSnapshot (Snapshot snapshot)
 
void UpdateActiveSnapshotCommandId (void)
 
void PopActiveSnapshot (void)
 
Snapshot GetActiveSnapshot (void)
 
bool ActiveSnapshotSet (void)
 
Snapshot RegisterSnapshot (Snapshot snapshot)
 
Snapshot RegisterSnapshotOnOwner (Snapshot snapshot, ResourceOwner owner)
 
void UnregisterSnapshot (Snapshot snapshot)
 
void UnregisterSnapshotFromOwner (Snapshot snapshot, ResourceOwner owner)
 
void AtSubCommit_Snapshot (int level)
 
void AtSubAbort_Snapshot (int level)
 
void AtEOXact_Snapshot (bool isCommit, bool resetXmin)
 
char * ExportSnapshot (Snapshot snapshot)
 
Datum pg_export_snapshot (PG_FUNCTION_ARGS)
 
static int parseIntFromText (const char *prefix, char **s, const char *filename)
 
static TransactionId parseXidFromText (const char *prefix, char **s, const char *filename)
 
static void parseVxidFromText (const char *prefix, char **s, const char *filename, VirtualTransactionId *vxid)
 
void ImportSnapshot (const char *idstr)
 
bool XactHasExportedSnapshots (void)
 
void DeleteAllExportedSnapshotFiles (void)
 
bool ThereAreNoPriorRegisteredSnapshots (void)
 
bool HaveRegisteredOrActiveSnapshot (void)
 
void SetupHistoricSnapshot (Snapshot historic_snapshot, HTAB *tuplecids)
 
void TeardownHistoricSnapshot (bool is_error)
 
bool HistoricSnapshotActive (void)
 
HTABHistoricSnapshotGetTupleCids (void)
 
Size EstimateSnapshotSpace (Snapshot snapshot)
 
void SerializeSnapshot (Snapshot snapshot, char *start_address)
 
Snapshot RestoreSnapshot (char *start_address)
 
void RestoreTransactionSnapshot (Snapshot snapshot, void *source_pgproc)
 
bool XidInMVCCSnapshot (TransactionId xid, Snapshot snapshot)
 

Variables

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
 
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
 
static const ResourceOwnerDesc snapshot_resowner_desc
 

Macro Definition Documentation

◆ SNAPSHOT_EXPORT_DIR

#define SNAPSHOT_EXPORT_DIR   "pg_snapshots"

Definition at line 152 of file snapmgr.c.

Typedef Documentation

◆ ActiveSnapshotElt

◆ ExportedSnapshot

◆ SerializedSnapshotData

Function Documentation

◆ ActiveSnapshotSet()

◆ AtEOXact_Snapshot()

void AtEOXact_Snapshot ( bool  isCommit,
bool  resetXmin 
)

Definition at line 1002 of file snapmgr.c.

1003 {
1004  /*
1005  * In transaction-snapshot mode we must release our privately-managed
1006  * reference to the transaction snapshot. We must remove it from
1007  * RegisteredSnapshots to keep the check below happy. But we don't bother
1008  * to do FreeSnapshot, for two reasons: the memory will go away with
1009  * TopTransactionContext anyway, and if someone has left the snapshot
1010  * stacked as active, we don't want the code below to be chasing through a
1011  * dangling pointer.
1012  */
1013  if (FirstXactSnapshot != NULL)
1014  {
1018  }
1019  FirstXactSnapshot = NULL;
1020 
1021  /*
1022  * If we exported any snapshots, clean them up.
1023  */
1024  if (exportedSnapshots != NIL)
1025  {
1026  ListCell *lc;
1027 
1028  /*
1029  * Get rid of the files. Unlink failure is only a WARNING because (1)
1030  * it's too late to abort the transaction, and (2) leaving a leaked
1031  * file around has little real consequence anyway.
1032  *
1033  * We also need to remove the snapshots from RegisteredSnapshots to
1034  * prevent a warning below.
1035  *
1036  * As with the FirstXactSnapshot, we don't need to free resources of
1037  * the snapshot itself as it will go away with the memory context.
1038  */
1039  foreach(lc, exportedSnapshots)
1040  {
1041  ExportedSnapshot *esnap = (ExportedSnapshot *) lfirst(lc);
1042 
1043  if (unlink(esnap->snapfile))
1044  elog(WARNING, "could not unlink file \"%s\": %m",
1045  esnap->snapfile);
1046 
1048  &esnap->snapshot->ph_node);
1049  }
1050 
1052  }
1053 
1054  /* Drop catalog snapshot if any */
1056 
1057  /* On commit, complain about leftover snapshots */
1058  if (isCommit)
1059  {
1060  ActiveSnapshotElt *active;
1061 
1063  elog(WARNING, "registered snapshots seem to remain after cleanup");
1064 
1065  /* complain about unpopped active snapshots */
1066  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
1067  elog(WARNING, "snapshot %p still active", active);
1068  }
1069 
1070  /*
1071  * And reset our state. We don't need to free the memory explicitly --
1072  * it'll go away with TopTransactionContext.
1073  */
1074  ActiveSnapshot = NULL;
1075  OldestActiveSnapshot = NULL;
1077 
1078  CurrentSnapshot = NULL;
1079  SecondarySnapshot = NULL;
1080 
1081  FirstSnapshotSet = false;
1082 
1083  /*
1084  * During normal commit processing, we call ProcArrayEndTransaction() to
1085  * reset the MyProc->xmin. That call happens prior to the call to
1086  * AtEOXact_Snapshot(), so we need not touch xmin here at all.
1087  */
1088  if (resetXmin)
1090 
1091  Assert(resetXmin || MyProc->xmin == 0);
1092 }
#define WARNING
Definition: elog.h:36
Assert(fmt[strlen(fmt) - 1] !='\n')
void pairingheap_remove(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:170
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
#define pairingheap_reset(h)
Definition: pairingheap.h:93
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
static Snapshot FirstXactSnapshot
Definition: snapmgr.c:149
static Snapshot CurrentSnapshot
Definition: snapmgr.c:95
static Snapshot SecondarySnapshot
Definition: snapmgr.c:96
static List * exportedSnapshots
Definition: snapmgr.c:162
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:139
bool FirstSnapshotSet
Definition: snapmgr.c:142
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:130
static void SnapshotResetXmin(void)
Definition: snapmgr.c:921
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:429
PGPROC * MyProc
Definition: proc.c:66
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:123
char * snapfile
Definition: snapmgr.c:157
Snapshot snapshot
Definition: snapmgr.c:158
TransactionId xmin
Definition: proc.h:178
uint32 regd_count
Definition: snapshot.h:205
pairingheap_node ph_node
Definition: snapshot.h:206

References ActiveSnapshot, ActiveSnapshotElt::as_next, Assert(), CurrentSnapshot, elog(), exportedSnapshots, FirstSnapshotSet, FirstXactSnapshot, InvalidateCatalogSnapshot(), lfirst, MyProc, NIL, OldestActiveSnapshot, pairingheap_is_empty, pairingheap_remove(), pairingheap_reset, SnapshotData::ph_node, SnapshotData::regd_count, RegisteredSnapshots, SecondarySnapshot, ExportedSnapshot::snapfile, ExportedSnapshot::snapshot, SnapshotResetXmin(), WARNING, and PGPROC::xmin.

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

◆ AtSubAbort_Snapshot()

void AtSubAbort_Snapshot ( int  level)

Definition at line 966 of file snapmgr.c.

967 {
968  /* Forget the active snapshots set by this subtransaction */
969  while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
970  {
972 
974 
975  /*
976  * Decrement the snapshot's active count. If it's still registered or
977  * marked as active by an outer subtransaction, we can't free it yet.
978  */
981 
982  if (ActiveSnapshot->as_snap->active_count == 0 &&
985 
986  /* and free the stack element */
988 
990  if (ActiveSnapshot == NULL)
991  OldestActiveSnapshot = NULL;
992  }
993 
995 }
static int32 next
Definition: blutils.c:220
void pfree(void *pointer)
Definition: mcxt.c:1456
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:637
Snapshot as_snap
Definition: snapmgr.c:121
uint32 active_count
Definition: snapshot.h:204

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

Referenced by AbortSubTransaction().

◆ AtSubCommit_Snapshot()

void AtSubCommit_Snapshot ( int  level)

Definition at line 945 of file snapmgr.c.

946 {
947  ActiveSnapshotElt *active;
948 
949  /*
950  * Relabel the active snapshots set in this subtransaction as though they
951  * are owned by the parent subxact.
952  */
953  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
954  {
955  if (active->as_level < level)
956  break;
957  active->as_level = level - 1;
958  }
959 }

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

Referenced by CommitSubTransaction().

◆ CopySnapshot()

static Snapshot CopySnapshot ( Snapshot  snapshot)
static

Definition at line 581 of file snapmgr.c.

582 {
583  Snapshot newsnap;
584  Size subxipoff;
585  Size size;
586 
587  Assert(snapshot != InvalidSnapshot);
588 
589  /* We allocate any XID arrays needed in the same palloc block. */
590  size = subxipoff = sizeof(SnapshotData) +
591  snapshot->xcnt * sizeof(TransactionId);
592  if (snapshot->subxcnt > 0)
593  size += snapshot->subxcnt * sizeof(TransactionId);
594 
596  memcpy(newsnap, snapshot, sizeof(SnapshotData));
597 
598  newsnap->regd_count = 0;
599  newsnap->active_count = 0;
600  newsnap->copied = true;
601  newsnap->snapXactCompletionCount = 0;
602 
603  /* setup XID array */
604  if (snapshot->xcnt > 0)
605  {
606  newsnap->xip = (TransactionId *) (newsnap + 1);
607  memcpy(newsnap->xip, snapshot->xip,
608  snapshot->xcnt * sizeof(TransactionId));
609  }
610  else
611  newsnap->xip = NULL;
612 
613  /*
614  * Setup subXID array. Don't bother to copy it if it had overflowed,
615  * though, because it's not used anywhere in that case. Except if it's a
616  * snapshot taken during recovery; all the top-level XIDs are in subxip as
617  * well in that case, so we mustn't lose them.
618  */
619  if (snapshot->subxcnt > 0 &&
620  (!snapshot->suboverflowed || snapshot->takenDuringRecovery))
621  {
622  newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);
623  memcpy(newsnap->subxip, snapshot->subxip,
624  snapshot->subxcnt * sizeof(TransactionId));
625  }
626  else
627  newsnap->subxip = NULL;
628 
629  return newsnap;
630 }
uint32 TransactionId
Definition: c.h:641
size_t Size
Definition: c.h:594
MemoryContext TopTransactionContext
Definition: mcxt.c:146
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1021
struct SnapshotData * Snapshot
Definition: snapshot.h:121
struct SnapshotData SnapshotData
#define InvalidSnapshot
Definition: snapshot.h:123
int32 subxcnt
Definition: snapshot.h:181
bool copied
Definition: snapshot.h:185
uint32 xcnt
Definition: snapshot.h:169
TransactionId * subxip
Definition: snapshot.h:180
uint64 snapXactCompletionCount
Definition: snapshot.h:216
TransactionId * xip
Definition: snapshot.h:168
bool suboverflowed
Definition: snapshot.h:182
bool takenDuringRecovery
Definition: snapshot.h:184

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

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

◆ DeleteAllExportedSnapshotFiles()

void DeleteAllExportedSnapshotFiles ( void  )

Definition at line 1573 of file snapmgr.c.

1574 {
1575  char buf[MAXPGPATH + sizeof(SNAPSHOT_EXPORT_DIR)];
1576  DIR *s_dir;
1577  struct dirent *s_de;
1578 
1579  /*
1580  * Problems in reading the directory, or unlinking files, are reported at
1581  * LOG level. Since we're running in the startup process, ERROR level
1582  * would prevent database start, and it's not important enough for that.
1583  */
1585 
1586  while ((s_de = ReadDirExtended(s_dir, SNAPSHOT_EXPORT_DIR, LOG)) != NULL)
1587  {
1588  if (strcmp(s_de->d_name, ".") == 0 ||
1589  strcmp(s_de->d_name, "..") == 0)
1590  continue;
1591 
1592  snprintf(buf, sizeof(buf), SNAPSHOT_EXPORT_DIR "/%s", s_de->d_name);
1593 
1594  if (unlink(buf) != 0)
1595  ereport(LOG,
1597  errmsg("could not remove file \"%s\": %m", buf)));
1598  }
1599 
1600  FreeDir(s_dir);
1601 }
int errcode_for_file_access(void)
Definition: elog.c:881
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
int FreeDir(DIR *dir)
Definition: fd.c:2931
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2894
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2813
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:73
#define snprintf
Definition: port.h:238
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:152
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by StartupXLOG().

◆ EstimateSnapshotSpace()

Size EstimateSnapshotSpace ( Snapshot  snapshot)

Definition at line 1698 of file snapmgr.c.

1699 {
1700  Size size;
1701 
1702  Assert(snapshot != InvalidSnapshot);
1703  Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
1704 
1705  /* We allocate any XID arrays needed in the same palloc block. */
1706  size = add_size(sizeof(SerializedSnapshotData),
1707  mul_size(snapshot->xcnt, sizeof(TransactionId)));
1708  if (snapshot->subxcnt > 0 &&
1709  (!snapshot->suboverflowed || snapshot->takenDuringRecovery))
1710  size = add_size(size,
1711  mul_size(snapshot->subxcnt, sizeof(TransactionId)));
1712 
1713  return size;
1714 }
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
@ SNAPSHOT_MVCC
Definition: snapshot.h:50
SnapshotType snapshot_type
Definition: snapshot.h:144

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().

◆ ExportSnapshot()

char* ExportSnapshot ( Snapshot  snapshot)

Definition at line 1102 of file snapmgr.c.

1103 {
1104  TransactionId topXid;
1105  TransactionId *children;
1106  ExportedSnapshot *esnap;
1107  int nchildren;
1108  int addTopXid;
1110  FILE *f;
1111  int i;
1112  MemoryContext oldcxt;
1113  char path[MAXPGPATH];
1114  char pathtmp[MAXPGPATH];
1115 
1116  /*
1117  * It's tempting to call RequireTransactionBlock here, since it's not very
1118  * useful to export a snapshot that will disappear immediately afterwards.
1119  * However, we haven't got enough information to do that, since we don't
1120  * know if we're at top level or not. For example, we could be inside a
1121  * plpgsql function that is going to fire off other transactions via
1122  * dblink. Rather than disallow perfectly legitimate usages, don't make a
1123  * check.
1124  *
1125  * Also note that we don't make any restriction on the transaction's
1126  * isolation level; however, importers must check the level if they are
1127  * serializable.
1128  */
1129 
1130  /*
1131  * Get our transaction ID if there is one, to include in the snapshot.
1132  */
1133  topXid = GetTopTransactionIdIfAny();
1134 
1135  /*
1136  * We cannot export a snapshot from a subtransaction because there's no
1137  * easy way for importers to verify that the same subtransaction is still
1138  * running.
1139  */
1140  if (IsSubTransaction())
1141  ereport(ERROR,
1142  (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1143  errmsg("cannot export a snapshot from a subtransaction")));
1144 
1145  /*
1146  * We do however allow previous committed subtransactions to exist.
1147  * Importers of the snapshot must see them as still running, so get their
1148  * XIDs to add them to the snapshot.
1149  */
1150  nchildren = xactGetCommittedChildren(&children);
1151 
1152  /*
1153  * Generate file path for the snapshot. We start numbering of snapshots
1154  * inside the transaction from 1.
1155  */
1156  snprintf(path, sizeof(path), SNAPSHOT_EXPORT_DIR "/%08X-%08X-%d",
1158 
1159  /*
1160  * Copy the snapshot into TopTransactionContext, add it to the
1161  * exportedSnapshots list, and mark it pseudo-registered. We do this to
1162  * ensure that the snapshot's xmin is honored for the rest of the
1163  * transaction.
1164  */
1165  snapshot = CopySnapshot(snapshot);
1166 
1168  esnap = (ExportedSnapshot *) palloc(sizeof(ExportedSnapshot));
1169  esnap->snapfile = pstrdup(path);
1170  esnap->snapshot = snapshot;
1172  MemoryContextSwitchTo(oldcxt);
1173 
1174  snapshot->regd_count++;
1176 
1177  /*
1178  * Fill buf with a text serialization of the snapshot, plus identification
1179  * data about this transaction. The format expected by ImportSnapshot is
1180  * pretty rigid: each line must be fieldname:value.
1181  */
1182  initStringInfo(&buf);
1183 
1184  appendStringInfo(&buf, "vxid:%d/%u\n", MyProc->backendId, MyProc->lxid);
1185  appendStringInfo(&buf, "pid:%d\n", MyProcPid);
1186  appendStringInfo(&buf, "dbid:%u\n", MyDatabaseId);
1187  appendStringInfo(&buf, "iso:%d\n", XactIsoLevel);
1188  appendStringInfo(&buf, "ro:%d\n", XactReadOnly);
1189 
1190  appendStringInfo(&buf, "xmin:%u\n", snapshot->xmin);
1191  appendStringInfo(&buf, "xmax:%u\n", snapshot->xmax);
1192 
1193  /*
1194  * We must include our own top transaction ID in the top-xid data, since
1195  * by definition we will still be running when the importing transaction
1196  * adopts the snapshot, but GetSnapshotData never includes our own XID in
1197  * the snapshot. (There must, therefore, be enough room to add it.)
1198  *
1199  * However, it could be that our topXid is after the xmax, in which case
1200  * we shouldn't include it because xip[] members are expected to be before
1201  * xmax. (We need not make the same check for subxip[] members, see
1202  * snapshot.h.)
1203  */
1204  addTopXid = (TransactionIdIsValid(topXid) &&
1205  TransactionIdPrecedes(topXid, snapshot->xmax)) ? 1 : 0;
1206  appendStringInfo(&buf, "xcnt:%d\n", snapshot->xcnt + addTopXid);
1207  for (i = 0; i < snapshot->xcnt; i++)
1208  appendStringInfo(&buf, "xip:%u\n", snapshot->xip[i]);
1209  if (addTopXid)
1210  appendStringInfo(&buf, "xip:%u\n", topXid);
1211 
1212  /*
1213  * Similarly, we add our subcommitted child XIDs to the subxid data. Here,
1214  * we have to cope with possible overflow.
1215  */
1216  if (snapshot->suboverflowed ||
1217  snapshot->subxcnt + nchildren > GetMaxSnapshotSubxidCount())
1218  appendStringInfoString(&buf, "sof:1\n");
1219  else
1220  {
1221  appendStringInfoString(&buf, "sof:0\n");
1222  appendStringInfo(&buf, "sxcnt:%d\n", snapshot->subxcnt + nchildren);
1223  for (i = 0; i < snapshot->subxcnt; i++)
1224  appendStringInfo(&buf, "sxp:%u\n", snapshot->subxip[i]);
1225  for (i = 0; i < nchildren; i++)
1226  appendStringInfo(&buf, "sxp:%u\n", children[i]);
1227  }
1228  appendStringInfo(&buf, "rec:%u\n", snapshot->takenDuringRecovery);
1229 
1230  /*
1231  * Now write the text representation into a file. We first write to a
1232  * ".tmp" filename, and rename to final filename if no error. This
1233  * ensures that no other backend can read an incomplete file
1234  * (ImportSnapshot won't allow it because of its valid-characters check).
1235  */
1236  snprintf(pathtmp, sizeof(pathtmp), "%s.tmp", path);
1237  if (!(f = AllocateFile(pathtmp, PG_BINARY_W)))
1238  ereport(ERROR,
1240  errmsg("could not create file \"%s\": %m", pathtmp)));
1241 
1242  if (fwrite(buf.data, buf.len, 1, f) != 1)
1243  ereport(ERROR,
1245  errmsg("could not write to file \"%s\": %m", pathtmp)));
1246 
1247  /* no fsync() since file need not survive a system crash */
1248 
1249  if (FreeFile(f))
1250  ereport(ERROR,
1252  errmsg("could not write to file \"%s\": %m", pathtmp)));
1253 
1254  /*
1255  * Now that we have written everything into a .tmp file, rename the file
1256  * to remove the .tmp suffix.
1257  */
1258  if (rename(pathtmp, path) < 0)
1259  ereport(ERROR,
1261  errmsg("could not rename file \"%s\" to \"%s\": %m",
1262  pathtmp, path)));
1263 
1264  /*
1265  * The basename of the file is what we return from pg_export_snapshot().
1266  * It's already in path in a textual format and we know that the path
1267  * starts with SNAPSHOT_EXPORT_DIR. Skip over the prefix and the slash
1268  * and pstrdup it so as not to return the address of a local variable.
1269  */
1270  return pstrdup(path + strlen(SNAPSHOT_EXPORT_DIR) + 1);
1271 }
#define PG_BINARY_W
Definition: c.h:1286
int errcode(int sqlerrcode)
Definition: elog.c:858
#define ERROR
Definition: elog.h:39
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2553
int FreeFile(FILE *file)
Definition: fd.c:2751
int MyProcPid
Definition: globals.c:44
Oid MyDatabaseId
Definition: globals.c:89
int i
Definition: isn.c:73
List * lappend(List *list, void *datum)
Definition: list.c:338
char * pstrdup(const char *in)
Definition: mcxt.c:1644
void * palloc(Size size)
Definition: mcxt.c:1226
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
static int list_length(const List *l)
Definition: pg_list.h:152
int GetMaxSnapshotSubxidCount(void)
Definition: procarray.c:2061
static Snapshot CopySnapshot(Snapshot snapshot)
Definition: snapmgr.c:581
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
LocalTransactionId lxid
Definition: proc.h:183
BackendId backendId
Definition: proc.h:197
TransactionId xmin
Definition: snapshot.h:157
TransactionId xmax
Definition: snapshot.h:158
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool XactReadOnly
Definition: xact.c:82
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:432
int XactIsoLevel
Definition: xact.c:79
bool IsSubTransaction(void)
Definition: xact.c:4889
int xactGetCommittedChildren(TransactionId **ptr)
Definition: xact.c:5626

References AllocateFile(), appendStringInfo(), appendStringInfoString(), PGPROC::backendId, buf, CopySnapshot(), ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, exportedSnapshots, FreeFile(), GetMaxSnapshotSubxidCount(), GetTopTransactionIdIfAny(), i, initStringInfo(), IsSubTransaction(), lappend(), list_length(), PGPROC::lxid, MAXPGPATH, MemoryContextSwitchTo(), MyDatabaseId, MyProc, MyProcPid, pairingheap_add(), palloc(), PG_BINARY_W, SnapshotData::ph_node, pstrdup(), SnapshotData::regd_count, RegisteredSnapshots, 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().

◆ FreeSnapshot()

static void FreeSnapshot ( Snapshot  snapshot)
static

Definition at line 637 of file snapmgr.c.

638 {
639  Assert(snapshot->regd_count == 0);
640  Assert(snapshot->active_count == 0);
641  Assert(snapshot->copied);
642 
643  pfree(snapshot);
644 }

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

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

◆ GetActiveSnapshot()

◆ GetCatalogSnapshot()

Snapshot GetCatalogSnapshot ( Oid  relid)

Definition at line 359 of file snapmgr.c.

360 {
361  /*
362  * Return historic snapshot while we're doing logical decoding, so we can
363  * see the appropriate state of the catalog.
364  *
365  * This is the primary reason for needing to reset the system caches after
366  * finishing decoding.
367  */
369  return HistoricSnapshot;
370 
371  return GetNonHistoricCatalogSnapshot(relid);
372 }
static Snapshot HistoricSnapshot
Definition: snapmgr.c:98
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1678
Snapshot GetNonHistoricCatalogSnapshot(Oid relid)
Definition: snapmgr.c:381

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

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

◆ GetLatestSnapshot()

Snapshot GetLatestSnapshot ( void  )

Definition at line 298 of file snapmgr.c.

299 {
300  /*
301  * We might be able to relax this, but nothing that could otherwise work
302  * needs it.
303  */
304  if (IsInParallelMode())
305  elog(ERROR,
306  "cannot update SecondarySnapshot during a parallel operation");
307 
308  /*
309  * So far there are no cases requiring support for GetLatestSnapshot()
310  * during logical decoding, but it wouldn't be hard to add if required.
311  */
313 
314  /* If first call in transaction, go ahead and set the xact snapshot */
315  if (!FirstSnapshotSet)
316  return GetTransactionSnapshot();
317 
319 
320  return SecondarySnapshot;
321 }
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:2158
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:223
static SnapshotData SecondarySnapshotData
Definition: snapmgr.c:89
bool IsInParallelMode(void)
Definition: xact.c:1069

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

Referenced by AlterDomainNotNull(), asyncQueueReadAllNotifications(), ATRewriteTable(), check_default_partition_contents(), currtid_internal(), IndexCheckExclusion(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RI_Initial_Check(), RI_PartitionRemove_Check(), ri_PerformCheck(), ScanSourceDatabasePgClass(), validateDomainConstraint(), and validateForeignKeyConstraint().

◆ GetNonHistoricCatalogSnapshot()

Snapshot GetNonHistoricCatalogSnapshot ( Oid  relid)

Definition at line 381 of file snapmgr.c.

382 {
383  /*
384  * If the caller is trying to scan a relation that has no syscache, no
385  * catcache invalidations will be sent when it is updated. For a few key
386  * relations, snapshot invalidations are sent instead. If we're trying to
387  * scan a relation for which neither catcache nor snapshot invalidations
388  * are sent, we must refresh the snapshot every time.
389  */
390  if (CatalogSnapshot &&
392  !RelationHasSysCache(relid))
394 
395  if (CatalogSnapshot == NULL)
396  {
397  /* Get new snapshot. */
399 
400  /*
401  * Make sure the catalog snapshot will be accounted for in decisions
402  * about advancing PGPROC->xmin. We could apply RegisterSnapshot, but
403  * that would result in making a physical copy, which is overkill; and
404  * it would also create a dependency on some resource owner, which we
405  * do not want for reasons explained at the head of this file. Instead
406  * just shove the CatalogSnapshot into the pairing heap manually. This
407  * has to be reversed in InvalidateCatalogSnapshot, of course.
408  *
409  * NB: it had better be impossible for this to throw error, since the
410  * CatalogSnapshot pointer is already valid.
411  */
413  }
414 
415  return CatalogSnapshot;
416 }
SnapshotData CatalogSnapshotData
Definition: snapmgr.c:90
static Snapshot CatalogSnapshot
Definition: snapmgr.c:97
bool RelationHasSysCache(Oid relid)
Definition: syscache.c:1226
bool RelationInvalidatesSnapshotsOnly(Oid relid)
Definition: syscache.c:1203

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

Referenced by GetCatalogSnapshot(), and ScanPgRelation().

◆ GetOldestSnapshot()

Snapshot GetOldestSnapshot ( void  )

Definition at line 330 of file snapmgr.c.

331 {
332  Snapshot OldestRegisteredSnapshot = NULL;
333  XLogRecPtr RegisteredLSN = InvalidXLogRecPtr;
334 
336  {
337  OldestRegisteredSnapshot = pairingheap_container(SnapshotData, ph_node,
339  RegisteredLSN = OldestRegisteredSnapshot->lsn;
340  }
341 
342  if (OldestActiveSnapshot != NULL)
343  {
345 
346  if (XLogRecPtrIsInvalid(RegisteredLSN) || RegisteredLSN > ActiveLSN)
348  }
349 
350  return OldestRegisteredSnapshot;
351 }
pairingheap_node * pairingheap_first(pairingheap *heap)
Definition: pairingheap.c:130
#define pairingheap_container(type, membername, ptr)
Definition: pairingheap.h:43
XLogRecPtr lsn
Definition: snapshot.h:209
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

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

Referenced by init_toast_snapshot().

◆ GetTransactionSnapshot()

Snapshot GetTransactionSnapshot ( void  )

Definition at line 223 of file snapmgr.c.

224 {
225  /*
226  * Return historic snapshot if doing logical decoding. We'll never need a
227  * non-historic transaction snapshot in this (sub-)transaction, so there's
228  * no need to be careful to set one up for later calls to
229  * GetTransactionSnapshot().
230  */
232  {
234  return HistoricSnapshot;
235  }
236 
237  /* First call in transaction? */
238  if (!FirstSnapshotSet)
239  {
240  /*
241  * Don't allow catalog snapshot to be older than xact snapshot. Must
242  * do this first to allow the empty-heap Assert to succeed.
243  */
245 
247  Assert(FirstXactSnapshot == NULL);
248 
249  if (IsInParallelMode())
250  elog(ERROR,
251  "cannot take query snapshot during a parallel operation");
252 
253  /*
254  * In transaction-snapshot mode, the first snapshot must live until
255  * end of xact regardless of what the caller does with it, so we must
256  * make a copy of it rather than returning CurrentSnapshotData
257  * directly. Furthermore, if we're running in serializable mode,
258  * predicate.c needs to wrap the snapshot fetch in its own processing.
259  */
261  {
262  /* First, create the snapshot in CurrentSnapshotData */
265  else
267  /* Make a saved copy */
270  /* Mark it as "registered" in FirstXactSnapshot */
273  }
274  else
276 
277  FirstSnapshotSet = true;
278  return CurrentSnapshot;
279  }
280 
282  return CurrentSnapshot;
283 
284  /* Don't allow catalog snapshot to be older than xact snapshot. */
286 
288 
289  return CurrentSnapshot;
290 }
Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot)
Definition: predicate.c:1633
static SnapshotData CurrentSnapshotData
Definition: snapmgr.c:88
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
#define IsolationIsSerializable()
Definition: xact.h:52

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

Referenced by _bt_begin_parallel(), _SPI_execute_plan(), AfterTriggerFireDeferred(), AfterTriggerSetState(), begin_replication_step(), bt_check_every_level(), BuildCachedPlan(), CheckTargetForConflictsIn(), cluster_multiple_rels(), DefineIndex(), EnsurePortalSnapshotExists(), EventTriggerOnLogin(), exec_bind_message(), exec_eval_simple_expr(), exec_parse_message(), exec_simple_query(), execute_sql_string(), ExecuteCallStmt(), 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(), PreCommit_on_commit_actions(), ReindexMultipleInternal(), ReindexRelationConcurrently(), RemoveTempRelationsCallback(), RevalidateCachedQuery(), ri_PerformCheck(), SPI_cursor_open_internal(), vacuum(), vacuum_rel(), verify_heapam(), worker_spi_main(), and XidIsConcurrent().

◆ HaveRegisteredOrActiveSnapshot()

bool HaveRegisteredOrActiveSnapshot ( void  )

Definition at line 1630 of file snapmgr.c.

1631 {
1632  if (ActiveSnapshot != NULL)
1633  return true;
1634 
1635  /*
1636  * The catalog snapshot is in RegisteredSnapshots when valid, but can be
1637  * removed at any time due to invalidation processing. If explicitly
1638  * registered more than one snapshot has to be in RegisteredSnapshots.
1639  */
1640  if (CatalogSnapshot != NULL &&
1642  return false;
1643 
1645 }
#define pairingheap_is_singular(h)
Definition: pairingheap.h:99

References ActiveSnapshot, CatalogSnapshot, pairingheap_is_empty, pairingheap_is_singular, and RegisteredSnapshots.

Referenced by init_toast_snapshot(), and SnapBuildInitialSnapshot().

◆ HistoricSnapshotActive()

◆ HistoricSnapshotGetTupleCids()

HTAB* HistoricSnapshotGetTupleCids ( void  )

Definition at line 1684 of file snapmgr.c.

1685 {
1687  return tuplecid_data;
1688 }
static HTAB * tuplecid_data
Definition: snapmgr.c:109

References Assert(), HistoricSnapshotActive(), and tuplecid_data.

Referenced by HeapTupleSatisfiesHistoricMVCC().

◆ ImportSnapshot()

void ImportSnapshot ( const char *  idstr)

Definition at line 1373 of file snapmgr.c.

1374 {
1375  char path[MAXPGPATH];
1376  FILE *f;
1377  struct stat stat_buf;
1378  char *filebuf;
1379  int xcnt;
1380  int i;
1381  VirtualTransactionId src_vxid;
1382  int src_pid;
1383  Oid src_dbid;
1384  int src_isolevel;
1385  bool src_readonly;
1386  SnapshotData snapshot;
1387 
1388  /*
1389  * Must be at top level of a fresh transaction. Note in particular that
1390  * we check we haven't acquired an XID --- if we have, it's conceivable
1391  * that the snapshot would show it as not running, making for very screwy
1392  * behavior.
1393  */
1394  if (FirstSnapshotSet ||
1396  IsSubTransaction())
1397  ereport(ERROR,
1398  (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
1399  errmsg("SET TRANSACTION SNAPSHOT must be called before any query")));
1400 
1401  /*
1402  * If we are in read committed mode then the next query would execute with
1403  * a new snapshot thus making this function call quite useless.
1404  */
1406  ereport(ERROR,
1407  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1408  errmsg("a snapshot-importing transaction must have isolation level SERIALIZABLE or REPEATABLE READ")));
1409 
1410  /*
1411  * Verify the identifier: only 0-9, A-F and hyphens are allowed. We do
1412  * this mainly to prevent reading arbitrary files.
1413  */
1414  if (strspn(idstr, "0123456789ABCDEF-") != strlen(idstr))
1415  ereport(ERROR,
1416  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1417  errmsg("invalid snapshot identifier: \"%s\"", idstr)));
1418 
1419  /* OK, read the file */
1420  snprintf(path, MAXPGPATH, SNAPSHOT_EXPORT_DIR "/%s", idstr);
1421 
1422  f = AllocateFile(path, PG_BINARY_R);
1423  if (!f)
1424  {
1425  /*
1426  * If file is missing while identifier has a correct format, avoid
1427  * system errors.
1428  */
1429  if (errno == ENOENT)
1430  ereport(ERROR,
1431  (errcode(ERRCODE_UNDEFINED_OBJECT),
1432  errmsg("snapshot \"%s\" does not exist", idstr)));
1433  else
1434  ereport(ERROR,
1436  errmsg("could not open file \"%s\" for reading: %m",
1437  path)));
1438  }
1439 
1440  /* get the size of the file so that we know how much memory we need */
1441  if (fstat(fileno(f), &stat_buf))
1442  elog(ERROR, "could not stat file \"%s\": %m", path);
1443 
1444  /* and read the file into a palloc'd string */
1445  filebuf = (char *) palloc(stat_buf.st_size + 1);
1446  if (fread(filebuf, stat_buf.st_size, 1, f) != 1)
1447  elog(ERROR, "could not read file \"%s\": %m", path);
1448 
1449  filebuf[stat_buf.st_size] = '\0';
1450 
1451  FreeFile(f);
1452 
1453  /*
1454  * Construct a snapshot struct by parsing the file content.
1455  */
1456  memset(&snapshot, 0, sizeof(snapshot));
1457 
1458  parseVxidFromText("vxid:", &filebuf, path, &src_vxid);
1459  src_pid = parseIntFromText("pid:", &filebuf, path);
1460  /* we abuse parseXidFromText a bit here ... */
1461  src_dbid = parseXidFromText("dbid:", &filebuf, path);
1462  src_isolevel = parseIntFromText("iso:", &filebuf, path);
1463  src_readonly = parseIntFromText("ro:", &filebuf, path);
1464 
1465  snapshot.snapshot_type = SNAPSHOT_MVCC;
1466 
1467  snapshot.xmin = parseXidFromText("xmin:", &filebuf, path);
1468  snapshot.xmax = parseXidFromText("xmax:", &filebuf, path);
1469 
1470  snapshot.xcnt = xcnt = parseIntFromText("xcnt:", &filebuf, path);
1471 
1472  /* sanity-check the xid count before palloc */
1473  if (xcnt < 0 || xcnt > GetMaxSnapshotXidCount())
1474  ereport(ERROR,
1475  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1476  errmsg("invalid snapshot data in file \"%s\"", path)));
1477 
1478  snapshot.xip = (TransactionId *) palloc(xcnt * sizeof(TransactionId));
1479  for (i = 0; i < xcnt; i++)
1480  snapshot.xip[i] = parseXidFromText("xip:", &filebuf, path);
1481 
1482  snapshot.suboverflowed = parseIntFromText("sof:", &filebuf, path);
1483 
1484  if (!snapshot.suboverflowed)
1485  {
1486  snapshot.subxcnt = xcnt = parseIntFromText("sxcnt:", &filebuf, path);
1487 
1488  /* sanity-check the xid count before palloc */
1489  if (xcnt < 0 || xcnt > GetMaxSnapshotSubxidCount())
1490  ereport(ERROR,
1491  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1492  errmsg("invalid snapshot data in file \"%s\"", path)));
1493 
1494  snapshot.subxip = (TransactionId *) palloc(xcnt * sizeof(TransactionId));
1495  for (i = 0; i < xcnt; i++)
1496  snapshot.subxip[i] = parseXidFromText("sxp:", &filebuf, path);
1497  }
1498  else
1499  {
1500  snapshot.subxcnt = 0;
1501  snapshot.subxip = NULL;
1502  }
1503 
1504  snapshot.takenDuringRecovery = parseIntFromText("rec:", &filebuf, path);
1505 
1506  /*
1507  * Do some additional sanity checking, just to protect ourselves. We
1508  * don't trouble to check the array elements, just the most critical
1509  * fields.
1510  */
1511  if (!VirtualTransactionIdIsValid(src_vxid) ||
1512  !OidIsValid(src_dbid) ||
1513  !TransactionIdIsNormal(snapshot.xmin) ||
1514  !TransactionIdIsNormal(snapshot.xmax))
1515  ereport(ERROR,
1516  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1517  errmsg("invalid snapshot data in file \"%s\"", path)));
1518 
1519  /*
1520  * If we're serializable, the source transaction must be too, otherwise
1521  * predicate.c has problems (SxactGlobalXmin could go backwards). Also, a
1522  * non-read-only transaction can't adopt a snapshot from a read-only
1523  * transaction, as predicate.c handles the cases very differently.
1524  */
1526  {
1527  if (src_isolevel != XACT_SERIALIZABLE)
1528  ereport(ERROR,
1529  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1530  errmsg("a serializable transaction cannot import a snapshot from a non-serializable transaction")));
1531  if (src_readonly && !XactReadOnly)
1532  ereport(ERROR,
1533  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1534  errmsg("a non-read-only serializable transaction cannot import a snapshot from a read-only transaction")));
1535  }
1536 
1537  /*
1538  * We cannot import a snapshot that was taken in a different database,
1539  * because vacuum calculates OldestXmin on a per-database basis; so the
1540  * source transaction's xmin doesn't protect us from data loss. This
1541  * restriction could be removed if the source transaction were to mark its
1542  * xmin as being globally applicable. But that would require some
1543  * additional syntax, since that has to be known when the snapshot is
1544  * initially taken. (See pgsql-hackers discussion of 2011-10-21.)
1545  */
1546  if (src_dbid != MyDatabaseId)
1547  ereport(ERROR,
1548  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1549  errmsg("cannot import a snapshot from a different database")));
1550 
1551  /* OK, install the snapshot */
1552  SetTransactionSnapshot(&snapshot, &src_vxid, src_pid, NULL);
1553 }
#define PG_BINARY_R
Definition: c.h:1285
#define OidIsValid(objectId)
Definition: c.h:764
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:67
unsigned int Oid
Definition: postgres_ext.h:31
int GetMaxSnapshotXidCount(void)
Definition: procarray.c:2050
static void SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid, int sourcepid, PGPROC *sourceproc)
Definition: snapmgr.c:484
static int parseIntFromText(const char *prefix, char **s, const char *filename)
Definition: snapmgr.c:1293
static void parseVxidFromText(const char *prefix, char **s, const char *filename, VirtualTransactionId *vxid)
Definition: snapmgr.c:1343
static TransactionId parseXidFromText(const char *prefix, char **s, const char *filename)
Definition: snapmgr.c:1318
#define InvalidTransactionId
Definition: transam.h:31
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define fstat
Definition: win32_port.h:283
#define XACT_SERIALIZABLE
Definition: xact.h:39

References AllocateFile(), elog(), ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, FirstSnapshotSet, FreeFile(), fstat, 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::st_size, 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().

◆ InvalidateCatalogSnapshot()

◆ InvalidateCatalogSnapshotConditionally()

void InvalidateCatalogSnapshotConditionally ( void  )

◆ parseIntFromText()

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

Definition at line 1293 of file snapmgr.c.

1294 {
1295  char *ptr = *s;
1296  int prefixlen = strlen(prefix);
1297  int val;
1298 
1299  if (strncmp(ptr, prefix, prefixlen) != 0)
1300  ereport(ERROR,
1301  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1302  errmsg("invalid snapshot data in file \"%s\"", filename)));
1303  ptr += prefixlen;
1304  if (sscanf(ptr, "%d", &val) != 1)
1305  ereport(ERROR,
1306  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1307  errmsg("invalid snapshot data in file \"%s\"", filename)));
1308  ptr = strchr(ptr, '\n');
1309  if (!ptr)
1310  ereport(ERROR,
1311  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1312  errmsg("invalid snapshot data in file \"%s\"", filename)));
1313  *s = ptr + 1;
1314  return val;
1315 }
long val
Definition: informix.c:664
static char * filename
Definition: pg_dumpall.c:121

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

Referenced by ImportSnapshot().

◆ parseVxidFromText()

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

Definition at line 1343 of file snapmgr.c.

1345 {
1346  char *ptr = *s;
1347  int prefixlen = strlen(prefix);
1348 
1349  if (strncmp(ptr, prefix, prefixlen) != 0)
1350  ereport(ERROR,
1351  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1352  errmsg("invalid snapshot data in file \"%s\"", filename)));
1353  ptr += prefixlen;
1354  if (sscanf(ptr, "%d/%u", &vxid->backendId, &vxid->localTransactionId) != 2)
1355  ereport(ERROR,
1356  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1357  errmsg("invalid snapshot data in file \"%s\"", filename)));
1358  ptr = strchr(ptr, '\n');
1359  if (!ptr)
1360  ereport(ERROR,
1361  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1362  errmsg("invalid snapshot data in file \"%s\"", filename)));
1363  *s = ptr + 1;
1364 }
LocalTransactionId localTransactionId
Definition: lock.h:62
BackendId backendId
Definition: lock.h:61

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

Referenced by ImportSnapshot().

◆ parseXidFromText()

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

Definition at line 1318 of file snapmgr.c.

1319 {
1320  char *ptr = *s;
1321  int prefixlen = strlen(prefix);
1323 
1324  if (strncmp(ptr, prefix, prefixlen) != 0)
1325  ereport(ERROR,
1326  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1327  errmsg("invalid snapshot data in file \"%s\"", filename)));
1328  ptr += prefixlen;
1329  if (sscanf(ptr, "%u", &val) != 1)
1330  ereport(ERROR,
1331  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1332  errmsg("invalid snapshot data in file \"%s\"", filename)));
1333  ptr = strchr(ptr, '\n');
1334  if (!ptr)
1335  ereport(ERROR,
1336  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1337  errmsg("invalid snapshot data in file \"%s\"", filename)));
1338  *s = ptr + 1;
1339  return val;
1340 }

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

Referenced by ImportSnapshot().

◆ pg_export_snapshot()

Datum pg_export_snapshot ( PG_FUNCTION_ARGS  )

Definition at line 1278 of file snapmgr.c.

1279 {
1280  char *snapshotName;
1281 
1282  snapshotName = ExportSnapshot(GetActiveSnapshot());
1283  PG_RETURN_TEXT_P(cstring_to_text(snapshotName));
1284 }
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
char * ExportSnapshot(Snapshot snapshot)
Definition: snapmgr.c:1102
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:777
text * cstring_to_text(const char *s)
Definition: varlena.c:184

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

◆ PopActiveSnapshot()

void PopActiveSnapshot ( void  )

Definition at line 750 of file snapmgr.c.

751 {
752  ActiveSnapshotElt *newstack;
753 
754  newstack = ActiveSnapshot->as_next;
755 
757 
759 
760  if (ActiveSnapshot->as_snap->active_count == 0 &&
763 
765  ActiveSnapshot = newstack;
766  if (ActiveSnapshot == NULL)
767  OldestActiveSnapshot = NULL;
768 
770 }

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

Referenced by _SPI_execute_plan(), AfterTriggerFireDeferred(), AfterTriggerSetState(), ATExecDetachPartition(), BuildCachedPlan(), cluster_multiple_rels(), DefineIndex(), DoPortalRewind(), end_replication_step(), EndCopyTo(), EventTriggerOnLogin(), exec_bind_message(), exec_eval_simple_expr(), exec_parse_message(), exec_simple_query(), ExecCreateTableAs(), execute_sql_string(), ExecuteCallStmt(), ExplainOnePlan(), fmgr_sql(), ForgetPortalSnapshots(), HandleFunctionRequest(), index_drop(), initialize_worker_spi(), LogicalRepSyncTableStart(), movedb(), ParallelWorkerMain(), PersistHoldablePortal(), PortalRunMulti(), PortalRunSelect(), PortalRunUtility(), PortalStart(), PreCommit_on_commit_actions(), refresh_matview_datafill(), ReindexMultipleInternal(), ReindexRelationConcurrently(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RemoveTempRelationsCallback(), RevalidateCachedQuery(), ShutdownSQLFunction(), vacuum(), vacuum_rel(), and worker_spi_main().

◆ PushActiveSnapshot()

◆ PushActiveSnapshotWithLevel()

void PushActiveSnapshotWithLevel ( Snapshot  snapshot,
int  snap_level 
)

Definition at line 669 of file snapmgr.c.

670 {
671  ActiveSnapshotElt *newactive;
672 
673  Assert(snapshot != InvalidSnapshot);
674  Assert(ActiveSnapshot == NULL || snap_level >= ActiveSnapshot->as_level);
675 
677 
678  /*
679  * Checking SecondarySnapshot is probably useless here, but it seems
680  * better to be sure.
681  */
682  if (snapshot == CurrentSnapshot || snapshot == SecondarySnapshot ||
683  !snapshot->copied)
684  newactive->as_snap = CopySnapshot(snapshot);
685  else
686  newactive->as_snap = snapshot;
687 
688  newactive->as_next = ActiveSnapshot;
689  newactive->as_level = snap_level;
690 
691  newactive->as_snap->active_count++;
692 
693  ActiveSnapshot = newactive;
694  if (OldestActiveSnapshot == NULL)
696 }

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

Referenced by EnsurePortalSnapshotExists(), PortalRunUtility(), and PushActiveSnapshot().

◆ PushCopiedSnapshot()

void PushCopiedSnapshot ( Snapshot  snapshot)

Definition at line 707 of file snapmgr.c.

708 {
709  PushActiveSnapshot(CopySnapshot(snapshot));
710 }
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:655

References CopySnapshot(), and PushActiveSnapshot().

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

◆ RegisterSnapshot()

◆ RegisterSnapshotOnOwner()

Snapshot RegisterSnapshotOnOwner ( Snapshot  snapshot,
ResourceOwner  owner 
)

Definition at line 814 of file snapmgr.c.

815 {
816  Snapshot snap;
817 
818  if (snapshot == InvalidSnapshot)
819  return InvalidSnapshot;
820 
821  /* Static snapshot? Create a persistent copy */
822  snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
823 
824  /* and tell resowner.c about it */
825  ResourceOwnerEnlarge(owner);
826  snap->regd_count++;
827  ResourceOwnerRememberSnapshot(owner, snap);
828 
829  if (snap->regd_count == 1)
831 
832  return snap;
833 }
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:448
static void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snap)
Definition: snapmgr.c:184

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

Referenced by be_lo_open(), and RegisterSnapshot().

◆ ResourceOwnerForgetSnapshot()

static void ResourceOwnerForgetSnapshot ( ResourceOwner  owner,
Snapshot  snap 
)
inlinestatic

Definition at line 189 of file snapmgr.c.

190 {
192 }
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:555
static const ResourceOwnerDesc snapshot_resowner_desc
Definition: snapmgr.c:173

References PointerGetDatum(), ResourceOwnerForget(), and snapshot_resowner_desc.

Referenced by UnregisterSnapshotFromOwner().

◆ ResourceOwnerRememberSnapshot()

static void ResourceOwnerRememberSnapshot ( ResourceOwner  owner,
Snapshot  snap 
)
inlinestatic

Definition at line 184 of file snapmgr.c.

185 {
187 }
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:520

References PointerGetDatum(), ResourceOwnerRemember(), and snapshot_resowner_desc.

Referenced by RegisterSnapshotOnOwner().

◆ ResOwnerReleaseSnapshot()

static void ResOwnerReleaseSnapshot ( Datum  res)
static

Definition at line 1961 of file snapmgr.c.

1962 {
1964 }
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static void UnregisterSnapshotNoOwner(Snapshot snapshot)
Definition: snapmgr.c:866

References DatumGetPointer(), res, and UnregisterSnapshotNoOwner().

◆ RestoreSnapshot()

Snapshot RestoreSnapshot ( char *  start_address)

Definition at line 1781 of file snapmgr.c.

1782 {
1783  SerializedSnapshotData serialized_snapshot;
1784  Size size;
1785  Snapshot snapshot;
1786  TransactionId *serialized_xids;
1787 
1788  memcpy(&serialized_snapshot, start_address,
1789  sizeof(SerializedSnapshotData));
1790  serialized_xids = (TransactionId *)
1791  (start_address + sizeof(SerializedSnapshotData));
1792 
1793  /* We allocate any XID arrays needed in the same palloc block. */
1794  size = sizeof(SnapshotData)
1795  + serialized_snapshot.xcnt * sizeof(TransactionId)
1796  + serialized_snapshot.subxcnt * sizeof(TransactionId);
1797 
1798  /* Copy all required fields */
1800  snapshot->snapshot_type = SNAPSHOT_MVCC;
1801  snapshot->xmin = serialized_snapshot.xmin;
1802  snapshot->xmax = serialized_snapshot.xmax;
1803  snapshot->xip = NULL;
1804  snapshot->xcnt = serialized_snapshot.xcnt;
1805  snapshot->subxip = NULL;
1806  snapshot->subxcnt = serialized_snapshot.subxcnt;
1807  snapshot->suboverflowed = serialized_snapshot.suboverflowed;
1808  snapshot->takenDuringRecovery = serialized_snapshot.takenDuringRecovery;
1809  snapshot->curcid = serialized_snapshot.curcid;
1810  snapshot->whenTaken = serialized_snapshot.whenTaken;
1811  snapshot->lsn = serialized_snapshot.lsn;
1812  snapshot->snapXactCompletionCount = 0;
1813 
1814  /* Copy XIDs, if present. */
1815  if (serialized_snapshot.xcnt > 0)
1816  {
1817  snapshot->xip = (TransactionId *) (snapshot + 1);
1818  memcpy(snapshot->xip, serialized_xids,
1819  serialized_snapshot.xcnt * sizeof(TransactionId));
1820  }
1821 
1822  /* Copy SubXIDs, if present. */
1823  if (serialized_snapshot.subxcnt > 0)
1824  {
1825  snapshot->subxip = ((TransactionId *) (snapshot + 1)) +
1826  serialized_snapshot.xcnt;
1827  memcpy(snapshot->subxip, serialized_xids + serialized_snapshot.xcnt,
1828  serialized_snapshot.subxcnt * sizeof(TransactionId));
1829  }
1830 
1831  /* Set the copied flag so that the caller will set refcounts correctly. */
1832  snapshot->regd_count = 0;
1833  snapshot->active_count = 0;
1834  snapshot->copied = true;
1835 
1836  return snapshot;
1837 }
TransactionId xmax
Definition: snapmgr.c:203
TimestampTz whenTaken
Definition: snapmgr.c:209
TransactionId xmin
Definition: snapmgr.c:202
CommandId curcid
Definition: snapshot.h:187
TimestampTz whenTaken
Definition: snapshot.h:208

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

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

◆ RestoreTransactionSnapshot()

void RestoreTransactionSnapshot ( Snapshot  snapshot,
void *  source_pgproc 
)

Definition at line 1846 of file snapmgr.c.

1847 {
1848  SetTransactionSnapshot(snapshot, NULL, InvalidPid, source_pgproc);
1849 }
#define InvalidPid
Definition: miscadmin.h:32

References InvalidPid, and SetTransactionSnapshot().

Referenced by CreateReplicationSlot(), and ParallelWorkerMain().

◆ SerializeSnapshot()

void SerializeSnapshot ( Snapshot  snapshot,
char *  start_address 
)

Definition at line 1722 of file snapmgr.c.

1723 {
1724  SerializedSnapshotData serialized_snapshot;
1725 
1726  Assert(snapshot->subxcnt >= 0);
1727 
1728  /* Copy all required fields */
1729  serialized_snapshot.xmin = snapshot->xmin;
1730  serialized_snapshot.xmax = snapshot->xmax;
1731  serialized_snapshot.xcnt = snapshot->xcnt;
1732  serialized_snapshot.subxcnt = snapshot->subxcnt;
1733  serialized_snapshot.suboverflowed = snapshot->suboverflowed;
1734  serialized_snapshot.takenDuringRecovery = snapshot->takenDuringRecovery;
1735  serialized_snapshot.curcid = snapshot->curcid;
1736  serialized_snapshot.whenTaken = snapshot->whenTaken;
1737  serialized_snapshot.lsn = snapshot->lsn;
1738 
1739  /*
1740  * Ignore the SubXID array if it has overflowed, unless the snapshot was
1741  * taken during recovery - in that case, top-level XIDs are in subxip as
1742  * well, and we mustn't lose them.
1743  */
1744  if (serialized_snapshot.suboverflowed && !snapshot->takenDuringRecovery)
1745  serialized_snapshot.subxcnt = 0;
1746 
1747  /* Copy struct to possibly-unaligned buffer */
1748  memcpy(start_address,
1749  &serialized_snapshot, sizeof(SerializedSnapshotData));
1750 
1751  /* Copy XID array */
1752  if (snapshot->xcnt > 0)
1753  memcpy((TransactionId *) (start_address +
1754  sizeof(SerializedSnapshotData)),
1755  snapshot->xip, snapshot->xcnt * sizeof(TransactionId));
1756 
1757  /*
1758  * Copy SubXID array. Don't bother to copy it if it had overflowed,
1759  * though, because it's not used anywhere in that case. Except if it's a
1760  * snapshot taken during recovery; all the top-level XIDs are in subxip as
1761  * well in that case, so we mustn't lose them.
1762  */
1763  if (serialized_snapshot.subxcnt > 0)
1764  {
1765  Size subxipoff = sizeof(SerializedSnapshotData) +
1766  snapshot->xcnt * sizeof(TransactionId);
1767 
1768  memcpy((TransactionId *) (start_address + subxipoff),
1769  snapshot->subxip, snapshot->subxcnt * sizeof(TransactionId));
1770  }
1771 }
struct SerializedSnapshotData SerializedSnapshotData

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

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

◆ SetTransactionSnapshot()

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

Definition at line 484 of file snapmgr.c.

486 {
487  /* Caller should have checked this already */
489 
490  /* Better do this to ensure following Assert succeeds. */
492 
494  Assert(FirstXactSnapshot == NULL);
496 
497  /*
498  * Even though we are not going to use the snapshot it computes, we must
499  * call GetSnapshotData, for two reasons: (1) to be sure that
500  * CurrentSnapshotData's XID arrays have been allocated, and (2) to update
501  * the state for GlobalVis*.
502  */
504 
505  /*
506  * Now copy appropriate fields from the source snapshot.
507  */
508  CurrentSnapshot->xmin = sourcesnap->xmin;
509  CurrentSnapshot->xmax = sourcesnap->xmax;
510  CurrentSnapshot->xcnt = sourcesnap->xcnt;
511  Assert(sourcesnap->xcnt <= GetMaxSnapshotXidCount());
512  if (sourcesnap->xcnt > 0)
513  memcpy(CurrentSnapshot->xip, sourcesnap->xip,
514  sourcesnap->xcnt * sizeof(TransactionId));
515  CurrentSnapshot->subxcnt = sourcesnap->subxcnt;
516  Assert(sourcesnap->subxcnt <= GetMaxSnapshotSubxidCount());
517  if (sourcesnap->subxcnt > 0)
518  memcpy(CurrentSnapshot->subxip, sourcesnap->subxip,
519  sourcesnap->subxcnt * sizeof(TransactionId));
522  /* NB: curcid should NOT be copied, it's a local matter */
523 
525 
526  /*
527  * Now we have to fix what GetSnapshotData did with MyProc->xmin and
528  * TransactionXmin. There is a race condition: to make sure we are not
529  * causing the global xmin to go backwards, we have to test that the
530  * source transaction is still running, and that has to be done
531  * atomically. So let procarray.c do it.
532  *
533  * Note: in serializable mode, predicate.c will do this a second time. It
534  * doesn't seem worth contorting the logic here to avoid two calls,
535  * especially since it's not clear that predicate.c *must* do this.
536  */
537  if (sourceproc != NULL)
538  {
540  ereport(ERROR,
541  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
542  errmsg("could not import the requested snapshot"),
543  errdetail("The source transaction is not running anymore.")));
544  }
545  else if (!ProcArrayInstallImportedXmin(CurrentSnapshot->xmin, sourcevxid))
546  ereport(ERROR,
547  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
548  errmsg("could not import the requested snapshot"),
549  errdetail("The source process with PID %d is not running anymore.",
550  sourcepid)));
551 
552  /*
553  * In transaction-snapshot mode, the first snapshot must live until end of
554  * xact, so we must make a copy of it. Furthermore, if we're running in
555  * serializable mode, predicate.c needs to do its own processing.
556  */
558  {
561  sourcepid);
562  /* Make a saved copy */
565  /* Mark it as "registered" in FirstXactSnapshot */
568  }
569 
570  FirstSnapshotSet = true;
571 }
int errdetail(const char *fmt,...)
Definition: elog.c:1202
void SetSerializableTransactionSnapshot(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1673
bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc)
Definition: procarray.c:2596
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:2517

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

Referenced by ImportSnapshot(), and RestoreTransactionSnapshot().

◆ SetupHistoricSnapshot()

void SetupHistoricSnapshot ( Snapshot  historic_snapshot,
HTAB tuplecids 
)

Definition at line 1655 of file snapmgr.c.

1656 {
1657  Assert(historic_snapshot != NULL);
1658 
1659  /* setup the timetravel snapshot */
1660  HistoricSnapshot = historic_snapshot;
1661 
1662  /* setup (cmin, cmax) lookup hash */
1663  tuplecid_data = tuplecids;
1664 }

References Assert(), HistoricSnapshot, and tuplecid_data.

Referenced by ReorderBufferProcessTXN(), and ReorderBufferQueueMessage().

◆ SnapshotResetXmin()

static void SnapshotResetXmin ( void  )
static

Definition at line 921 of file snapmgr.c.

922 {
923  Snapshot minSnapshot;
924 
925  if (ActiveSnapshot != NULL)
926  return;
927 
929  {
931  return;
932  }
933 
934  minSnapshot = pairingheap_container(SnapshotData, ph_node,
936 
937  if (TransactionIdPrecedes(MyProc->xmin, minSnapshot->xmin))
938  MyProc->xmin = minSnapshot->xmin;
939 }

References ActiveSnapshot, InvalidTransactionId, MyProc, pairingheap_container, pairingheap_first(), pairingheap_is_empty, RegisteredSnapshots, TransactionIdPrecedes(), PGPROC::xmin, and SnapshotData::xmin.

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

◆ SnapshotSetCommandId()

void SnapshotSetCommandId ( CommandId  curcid)

Definition at line 463 of file snapmgr.c.

464 {
465  if (!FirstSnapshotSet)
466  return;
467 
468  if (CurrentSnapshot)
469  CurrentSnapshot->curcid = curcid;
470  if (SecondarySnapshot)
471  SecondarySnapshot->curcid = curcid;
472  /* Should we do the same with CatalogSnapshot? */
473 }

References SnapshotData::curcid, CurrentSnapshot, FirstSnapshotSet, and SecondarySnapshot.

Referenced by CommandCounterIncrement().

◆ TeardownHistoricSnapshot()

void TeardownHistoricSnapshot ( bool  is_error)

Definition at line 1671 of file snapmgr.c.

1672 {
1673  HistoricSnapshot = NULL;
1674  tuplecid_data = NULL;
1675 }

References HistoricSnapshot, and tuplecid_data.

Referenced by ReorderBufferProcessTXN(), and ReorderBufferQueueMessage().

◆ ThereAreNoPriorRegisteredSnapshots()

bool ThereAreNoPriorRegisteredSnapshots ( void  )

Definition at line 1612 of file snapmgr.c.

1613 {
1616  return true;
1617 
1618  return false;
1619 }

References pairingheap_is_empty, pairingheap_is_singular, and RegisteredSnapshots.

Referenced by CopyFrom().

◆ UnregisterSnapshot()

◆ UnregisterSnapshotFromOwner()

void UnregisterSnapshotFromOwner ( Snapshot  snapshot,
ResourceOwner  owner 
)

Definition at line 856 of file snapmgr.c.

857 {
858  if (snapshot == NULL)
859  return;
860 
861  ResourceOwnerForgetSnapshot(owner, snapshot);
862  UnregisterSnapshotNoOwner(snapshot);
863 }
static void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snap)
Definition: snapmgr.c:189

References ResourceOwnerForgetSnapshot(), and UnregisterSnapshotNoOwner().

Referenced by closeLOfd(), PortalDrop(), PreCommit_Portals(), and UnregisterSnapshot().

◆ UnregisterSnapshotNoOwner()

static void UnregisterSnapshotNoOwner ( Snapshot  snapshot)
static

Definition at line 866 of file snapmgr.c.

867 {
868  Assert(snapshot->regd_count > 0);
870 
871  snapshot->regd_count--;
872  if (snapshot->regd_count == 0)
874 
875  if (snapshot->regd_count == 0 && snapshot->active_count == 0)
876  {
877  FreeSnapshot(snapshot);
879  }
880 }

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

Referenced by ResOwnerReleaseSnapshot(), and UnregisterSnapshotFromOwner().

◆ UpdateActiveSnapshotCommandId()

void UpdateActiveSnapshotCommandId ( void  )

Definition at line 719 of file snapmgr.c.

720 {
721  CommandId save_curcid,
722  curcid;
723 
724  Assert(ActiveSnapshot != NULL);
727 
728  /*
729  * Don't allow modification of the active snapshot during parallel
730  * operation. We share the snapshot to worker backends at the beginning
731  * of parallel operation, so any change to the snapshot can lead to
732  * inconsistencies. We have other defenses against
733  * CommandCounterIncrement, but there are a few places that call this
734  * directly, so we put an additional guard here.
735  */
736  save_curcid = ActiveSnapshot->as_snap->curcid;
737  curcid = GetCurrentCommandId(false);
738  if (IsInParallelMode() && save_curcid != curcid)
739  elog(ERROR, "cannot modify commandid in active snapshot during a parallel operation");
740  ActiveSnapshot->as_snap->curcid = curcid;
741 }
uint32 CommandId
Definition: c.h:655
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:818

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

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

◆ XactHasExportedSnapshots()

bool XactHasExportedSnapshots ( void  )

Definition at line 1560 of file snapmgr.c.

1561 {
1562  return (exportedSnapshots != NIL);
1563 }

References exportedSnapshots, and NIL.

Referenced by PrepareTransaction().

◆ XidInMVCCSnapshot()

bool XidInMVCCSnapshot ( TransactionId  xid,
Snapshot  snapshot 
)

Definition at line 1862 of file snapmgr.c.

1863 {
1864  /*
1865  * Make a quick range check to eliminate most XIDs without looking at the
1866  * xip arrays. Note that this is OK even if we convert a subxact XID to
1867  * its parent below, because a subxact with XID < xmin has surely also got
1868  * a parent with XID < xmin, while one with XID >= xmax must belong to a
1869  * parent that was not yet committed at the time of this snapshot.
1870  */
1871 
1872  /* Any xid < xmin is not in-progress */
1873  if (TransactionIdPrecedes(xid, snapshot->xmin))
1874  return false;
1875  /* Any xid >= xmax is in-progress */
1876  if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
1877  return true;
1878 
1879  /*
1880  * Snapshot information is stored slightly differently in snapshots taken
1881  * during recovery.
1882  */
1883  if (!snapshot->takenDuringRecovery)
1884  {
1885  /*
1886  * If the snapshot contains full subxact data, the fastest way to
1887  * check things is just to compare the given XID against both subxact
1888  * XIDs and top-level XIDs. If the snapshot overflowed, we have to
1889  * use pg_subtrans to convert a subxact XID to its parent XID, but
1890  * then we need only look at top-level XIDs not subxacts.
1891  */
1892  if (!snapshot->suboverflowed)
1893  {
1894  /* we have full data, so search subxip */
1895  if (pg_lfind32(xid, snapshot->subxip, snapshot->subxcnt))
1896  return true;
1897 
1898  /* not there, fall through to search xip[] */
1899  }
1900  else
1901  {
1902  /*
1903  * Snapshot overflowed, so convert xid to top-level. This is safe
1904  * because we eliminated too-old XIDs above.
1905  */
1906  xid = SubTransGetTopmostTransaction(xid);
1907 
1908  /*
1909  * If xid was indeed a subxact, we might now have an xid < xmin,
1910  * so recheck to avoid an array scan. No point in rechecking
1911  * xmax.
1912  */
1913  if (TransactionIdPrecedes(xid, snapshot->xmin))
1914  return false;
1915  }
1916 
1917  if (pg_lfind32(xid, snapshot->xip, snapshot->xcnt))
1918  return true;
1919  }
1920  else
1921  {
1922  /*
1923  * In recovery we store all xids in the subxip array because it is by
1924  * far the bigger array, and we mostly don't know which xids are
1925  * top-level and which are subxacts. The xip array is empty.
1926  *
1927  * We start by searching subtrans, if we overflowed.
1928  */
1929  if (snapshot->suboverflowed)
1930  {
1931  /*
1932  * Snapshot overflowed, so convert xid to top-level. This is safe
1933  * because we eliminated too-old XIDs above.
1934  */
1935  xid = SubTransGetTopmostTransaction(xid);
1936 
1937  /*
1938  * If xid was indeed a subxact, we might now have an xid < xmin,
1939  * so recheck to avoid an array scan. No point in rechecking
1940  * xmax.
1941  */
1942  if (TransactionIdPrecedes(xid, snapshot->xmin))
1943  return false;
1944  }
1945 
1946  /*
1947  * We now have either a top-level xid higher than xmin or an
1948  * indeterminate xid. We don't know whether it's top level or subxact
1949  * but it doesn't matter. If it's present, the xid is visible.
1950  */
1951  if (pg_lfind32(xid, snapshot->subxip, snapshot->subxcnt))
1952  return true;
1953  }
1954 
1955  return false;
1956 }
static bool pg_lfind32(uint32 key, uint32 *base, uint32 nelem)
Definition: pg_lfind.h:90
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:159
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:329

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

Referenced by asyncQueueProcessPageEntries(), find_inheritance_children_extended(), HeapTupleSatisfiesMVCC(), and RelationGetPartitionDesc().

◆ xmin_cmp()

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

Definition at line 887 of file snapmgr.c.

888 {
889  const SnapshotData *asnap = pairingheap_const_container(SnapshotData, ph_node, a);
890  const SnapshotData *bsnap = pairingheap_const_container(SnapshotData, ph_node, b);
891 
892  if (TransactionIdPrecedes(asnap->xmin, bsnap->xmin))
893  return 1;
894  else if (TransactionIdFollows(asnap->xmin, bsnap->xmin))
895  return -1;
896  else
897  return 0;
898 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69
#define pairingheap_const_container(type, membername, ptr)
Definition: pairingheap.h:51
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314

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

Variable Documentation

◆ ActiveSnapshot

◆ CatalogSnapshot

◆ CatalogSnapshotData

SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC}

Definition at line 90 of file snapmgr.c.

Referenced by GetNonHistoricCatalogSnapshot().

◆ CurrentSnapshot

◆ CurrentSnapshotData

SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC}
static

Definition at line 88 of file snapmgr.c.

Referenced by GetTransactionSnapshot(), and SetTransactionSnapshot().

◆ exportedSnapshots

List* exportedSnapshots = NIL
static

Definition at line 162 of file snapmgr.c.

Referenced by AtEOXact_Snapshot(), ExportSnapshot(), and XactHasExportedSnapshots().

◆ FirstSnapshotSet

◆ FirstXactSnapshot

Snapshot FirstXactSnapshot = NULL
static

Definition at line 149 of file snapmgr.c.

Referenced by AtEOXact_Snapshot(), GetTransactionSnapshot(), and SetTransactionSnapshot().

◆ HistoricSnapshot

Snapshot HistoricSnapshot = NULL
static

◆ OldestActiveSnapshot

ActiveSnapshotElt* OldestActiveSnapshot = NULL
static

◆ RecentXmin

◆ RegisteredSnapshots

◆ SecondarySnapshot

Snapshot SecondarySnapshot = NULL
static

◆ SecondarySnapshotData

SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC}
static

Definition at line 89 of file snapmgr.c.

Referenced by GetLatestSnapshot().

◆ snapshot_resowner_desc

const ResourceOwnerDesc snapshot_resowner_desc
static
Initial value:
=
{
.name = "snapshot reference",
.release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
.release_priority = RELEASE_PRIO_SNAPSHOT_REFS,
.ReleaseResource = ResOwnerReleaseSnapshot,
.DebugPrint = NULL
}
#define RELEASE_PRIO_SNAPSHOT_REFS
Definition: resowner.h:75
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition: resowner.h:56
static void ResOwnerReleaseSnapshot(Datum res)
Definition: snapmgr.c:1961

Definition at line 173 of file snapmgr.c.

Referenced by ResourceOwnerForgetSnapshot(), and ResourceOwnerRememberSnapshot().

◆ SnapshotAnyData

SnapshotData SnapshotAnyData = {SNAPSHOT_ANY}

Definition at line 92 of file snapmgr.c.

◆ SnapshotSelfData

SnapshotData SnapshotSelfData = {SNAPSHOT_SELF}

Definition at line 91 of file snapmgr.c.

◆ TransactionXmin

◆ tuplecid_data