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 "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 "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/resowner.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  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 145 of file snapmgr.c.

Typedef Documentation

◆ ActiveSnapshotElt

◆ ExportedSnapshot

◆ SerializedSnapshotData

Function Documentation

◆ ActiveSnapshotSet()

◆ AtEOXact_Snapshot()

void AtEOXact_Snapshot ( bool  isCommit,
bool  resetXmin 
)

Definition at line 995 of file snapmgr.c.

996 {
997  /*
998  * In transaction-snapshot mode we must release our privately-managed
999  * reference to the transaction snapshot. We must remove it from
1000  * RegisteredSnapshots to keep the check below happy. But we don't bother
1001  * to do FreeSnapshot, for two reasons: the memory will go away with
1002  * TopTransactionContext anyway, and if someone has left the snapshot
1003  * stacked as active, we don't want the code below to be chasing through a
1004  * dangling pointer.
1005  */
1006  if (FirstXactSnapshot != NULL)
1007  {
1011  }
1012  FirstXactSnapshot = NULL;
1013 
1014  /*
1015  * If we exported any snapshots, clean them up.
1016  */
1017  if (exportedSnapshots != NIL)
1018  {
1019  ListCell *lc;
1020 
1021  /*
1022  * Get rid of the files. Unlink failure is only a WARNING because (1)
1023  * it's too late to abort the transaction, and (2) leaving a leaked
1024  * file around has little real consequence anyway.
1025  *
1026  * We also need to remove the snapshots from RegisteredSnapshots to
1027  * prevent a warning below.
1028  *
1029  * As with the FirstXactSnapshot, we don't need to free resources of
1030  * the snapshot itself as it will go away with the memory context.
1031  */
1032  foreach(lc, exportedSnapshots)
1033  {
1034  ExportedSnapshot *esnap = (ExportedSnapshot *) lfirst(lc);
1035 
1036  if (unlink(esnap->snapfile))
1037  elog(WARNING, "could not unlink file \"%s\": %m",
1038  esnap->snapfile);
1039 
1041  &esnap->snapshot->ph_node);
1042  }
1043 
1045  }
1046 
1047  /* Drop catalog snapshot if any */
1049 
1050  /* On commit, complain about leftover snapshots */
1051  if (isCommit)
1052  {
1053  ActiveSnapshotElt *active;
1054 
1056  elog(WARNING, "registered snapshots seem to remain after cleanup");
1057 
1058  /* complain about unpopped active snapshots */
1059  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
1060  elog(WARNING, "snapshot %p still active", active);
1061  }
1062 
1063  /*
1064  * And reset our state. We don't need to free the memory explicitly --
1065  * it'll go away with TopTransactionContext.
1066  */
1067  ActiveSnapshot = NULL;
1068  OldestActiveSnapshot = NULL;
1070 
1071  CurrentSnapshot = NULL;
1072  SecondarySnapshot = NULL;
1073 
1074  FirstSnapshotSet = false;
1075 
1076  /*
1077  * During normal commit processing, we call ProcArrayEndTransaction() to
1078  * reset the MyProc->xmin. That call happens prior to the call to
1079  * AtEOXact_Snapshot(), so we need not touch xmin here at all.
1080  */
1081  if (resetXmin)
1083 
1084  Assert(resetXmin || MyProc->xmin == 0);
1085 }
#define Assert(condition)
Definition: c.h:837
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:225
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:142
static Snapshot CurrentSnapshot
Definition: snapmgr.c:88
static Snapshot SecondarySnapshot
Definition: snapmgr.c:89
static List * exportedSnapshots
Definition: snapmgr.c:155
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:132
bool FirstSnapshotSet
Definition: snapmgr.c:135
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:123
static void SnapshotResetXmin(void)
Definition: snapmgr.c:914
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:422
PGPROC * MyProc
Definition: proc.c:66
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:116
char * snapfile
Definition: snapmgr.c:150
Snapshot snapshot
Definition: snapmgr.c:151
TransactionId xmin
Definition: proc.h:177
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 959 of file snapmgr.c.

960 {
961  /* Forget the active snapshots set by this subtransaction */
962  while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
963  {
965 
967 
968  /*
969  * Decrement the snapshot's active count. If it's still registered or
970  * marked as active by an outer subtransaction, we can't free it yet.
971  */
974 
975  if (ActiveSnapshot->as_snap->active_count == 0 &&
978 
979  /* and free the stack element */
981 
983  if (ActiveSnapshot == NULL)
984  OldestActiveSnapshot = NULL;
985  }
986 
988 }
static int32 next
Definition: blutils.c:219
void pfree(void *pointer)
Definition: mcxt.c:1521
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:630
Snapshot as_snap
Definition: snapmgr.c:114
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 938 of file snapmgr.c.

939 {
940  ActiveSnapshotElt *active;
941 
942  /*
943  * Relabel the active snapshots set in this subtransaction as though they
944  * are owned by the parent subxact.
945  */
946  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
947  {
948  if (active->as_level < level)
949  break;
950  active->as_level = level - 1;
951  }
952 }

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

Referenced by CommitSubTransaction().

◆ CopySnapshot()

static Snapshot CopySnapshot ( Snapshot  snapshot)
static

Definition at line 574 of file snapmgr.c.

575 {
576  Snapshot newsnap;
577  Size subxipoff;
578  Size size;
579 
580  Assert(snapshot != InvalidSnapshot);
581 
582  /* We allocate any XID arrays needed in the same palloc block. */
583  size = subxipoff = sizeof(SnapshotData) +
584  snapshot->xcnt * sizeof(TransactionId);
585  if (snapshot->subxcnt > 0)
586  size += snapshot->subxcnt * sizeof(TransactionId);
587 
589  memcpy(newsnap, snapshot, sizeof(SnapshotData));
590 
591  newsnap->regd_count = 0;
592  newsnap->active_count = 0;
593  newsnap->copied = true;
594  newsnap->snapXactCompletionCount = 0;
595 
596  /* setup XID array */
597  if (snapshot->xcnt > 0)
598  {
599  newsnap->xip = (TransactionId *) (newsnap + 1);
600  memcpy(newsnap->xip, snapshot->xip,
601  snapshot->xcnt * sizeof(TransactionId));
602  }
603  else
604  newsnap->xip = NULL;
605 
606  /*
607  * Setup subXID array. Don't bother to copy it if it had overflowed,
608  * though, because it's not used anywhere in that case. Except if it's a
609  * snapshot taken during recovery; all the top-level XIDs are in subxip as
610  * well in that case, so we mustn't lose them.
611  */
612  if (snapshot->subxcnt > 0 &&
613  (!snapshot->suboverflowed || snapshot->takenDuringRecovery))
614  {
615  newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);
616  memcpy(newsnap->subxip, snapshot->subxip,
617  snapshot->subxcnt * sizeof(TransactionId));
618  }
619  else
620  newsnap->subxip = NULL;
621 
622  return newsnap;
623 }
uint32 TransactionId
Definition: c.h:631
size_t Size
Definition: c.h:584
MemoryContext TopTransactionContext
Definition: mcxt.c:154
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
static pg_noinline void Size size
Definition: slab.c:607
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, size, 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 1567 of file snapmgr.c.

1568 {
1569  char buf[MAXPGPATH + sizeof(SNAPSHOT_EXPORT_DIR)];
1570  DIR *s_dir;
1571  struct dirent *s_de;
1572 
1573  /*
1574  * Problems in reading the directory, or unlinking files, are reported at
1575  * LOG level. Since we're running in the startup process, ERROR level
1576  * would prevent database start, and it's not important enough for that.
1577  */
1579 
1580  while ((s_de = ReadDirExtended(s_dir, SNAPSHOT_EXPORT_DIR, LOG)) != NULL)
1581  {
1582  if (strcmp(s_de->d_name, ".") == 0 ||
1583  strcmp(s_de->d_name, "..") == 0)
1584  continue;
1585 
1586  snprintf(buf, sizeof(buf), SNAPSHOT_EXPORT_DIR "/%s", s_de->d_name);
1587 
1588  if (unlink(buf) != 0)
1589  ereport(LOG,
1591  errmsg("could not remove file \"%s\": %m", buf)));
1592  }
1593 
1594  FreeDir(s_dir);
1595 }
int errcode_for_file_access(void)
Definition: elog.c:876
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
int FreeDir(DIR *dir)
Definition: fd.c:2983
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2946
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2865
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:72
#define snprintf
Definition: port.h:238
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:145
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 1692 of file snapmgr.c.

1693 {
1694  Size size;
1695 
1696  Assert(snapshot != InvalidSnapshot);
1697  Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
1698 
1699  /* We allocate any XID arrays needed in the same palloc block. */
1701  mul_size(snapshot->xcnt, sizeof(TransactionId)));
1702  if (snapshot->subxcnt > 0 &&
1703  (!snapshot->suboverflowed || snapshot->takenDuringRecovery))
1704  size = add_size(size,
1705  mul_size(snapshot->subxcnt, sizeof(TransactionId)));
1706 
1707  return size;
1708 }
Size add_size(Size s1, Size s2)
Definition: shmem.c:488
Size mul_size(Size s1, Size s2)
Definition: shmem.c:505
@ SNAPSHOT_MVCC
Definition: snapshot.h:50
SnapshotType snapshot_type
Definition: snapshot.h:144

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

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

◆ ExportSnapshot()

char* ExportSnapshot ( Snapshot  snapshot)

Definition at line 1095 of file snapmgr.c.

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

References AllocateFile(), appendStringInfo(), appendStringInfoString(), 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, PGPROC::procNumber, pstrdup(), SnapshotData::regd_count, RegisteredSnapshots, ExportedSnapshot::snapfile, ExportedSnapshot::snapshot, SNAPSHOT_EXPORT_DIR, snprintf, SnapshotData::suboverflowed, SnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TopTransactionContext, TransactionIdIsValid, TransactionIdPrecedes(), PGPROC::vxid, 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 630 of file snapmgr.c.

631 {
632  Assert(snapshot->regd_count == 0);
633  Assert(snapshot->active_count == 0);
634  Assert(snapshot->copied);
635 
636  pfree(snapshot);
637 }

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 352 of file snapmgr.c.

353 {
354  /*
355  * Return historic snapshot while we're doing logical decoding, so we can
356  * see the appropriate state of the catalog.
357  *
358  * This is the primary reason for needing to reset the system caches after
359  * finishing decoding.
360  */
362  return HistoricSnapshot;
363 
364  return GetNonHistoricCatalogSnapshot(relid);
365 }
static Snapshot HistoricSnapshot
Definition: snapmgr.c:91
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:1672
Snapshot GetNonHistoricCatalogSnapshot(Oid relid)
Definition: snapmgr.c:374

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 291 of file snapmgr.c.

292 {
293  /*
294  * We might be able to relax this, but nothing that could otherwise work
295  * needs it.
296  */
297  if (IsInParallelMode())
298  elog(ERROR,
299  "cannot update SecondarySnapshot during a parallel operation");
300 
301  /*
302  * So far there are no cases requiring support for GetLatestSnapshot()
303  * during logical decoding, but it wouldn't be hard to add if required.
304  */
306 
307  /* If first call in transaction, go ahead and set the xact snapshot */
308  if (!FirstSnapshotSet)
309  return GetTransactionSnapshot();
310 
312 
313  return SecondarySnapshot;
314 }
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:2177
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
static SnapshotData SecondarySnapshotData
Definition: snapmgr.c:82
bool IsInParallelMode(void)
Definition: xact.c:1088

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

Referenced by asyncQueueReadAllNotifications(), ATRewriteTable(), check_default_partition_contents(), currtid_internal(), FindConflictTuple(), IndexCheckExclusion(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RI_Initial_Check(), RI_PartitionRemove_Check(), ri_PerformCheck(), ScanSourceDatabasePgClass(), validateDomainCheckConstraint(), validateDomainNotNullConstraint(), and validateForeignKeyConstraint().

◆ GetNonHistoricCatalogSnapshot()

Snapshot GetNonHistoricCatalogSnapshot ( Oid  relid)

Definition at line 374 of file snapmgr.c.

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

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 323 of file snapmgr.c.

324 {
325  Snapshot OldestRegisteredSnapshot = NULL;
326  XLogRecPtr RegisteredLSN = InvalidXLogRecPtr;
327 
329  {
330  OldestRegisteredSnapshot = pairingheap_container(SnapshotData, ph_node,
332  RegisteredLSN = OldestRegisteredSnapshot->lsn;
333  }
334 
335  if (OldestActiveSnapshot != NULL)
336  {
338 
339  if (XLogRecPtrIsInvalid(RegisteredLSN) || RegisteredLSN > ActiveLSN)
341  }
342 
343  return OldestRegisteredSnapshot;
344 }
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 216 of file snapmgr.c.

217 {
218  /*
219  * Return historic snapshot if doing logical decoding. We'll never need a
220  * non-historic transaction snapshot in this (sub-)transaction, so there's
221  * no need to be careful to set one up for later calls to
222  * GetTransactionSnapshot().
223  */
225  {
227  return HistoricSnapshot;
228  }
229 
230  /* First call in transaction? */
231  if (!FirstSnapshotSet)
232  {
233  /*
234  * Don't allow catalog snapshot to be older than xact snapshot. Must
235  * do this first to allow the empty-heap Assert to succeed.
236  */
238 
240  Assert(FirstXactSnapshot == NULL);
241 
242  if (IsInParallelMode())
243  elog(ERROR,
244  "cannot take query snapshot during a parallel operation");
245 
246  /*
247  * In transaction-snapshot mode, the first snapshot must live until
248  * end of xact regardless of what the caller does with it, so we must
249  * make a copy of it rather than returning CurrentSnapshotData
250  * directly. Furthermore, if we're running in serializable mode,
251  * predicate.c needs to wrap the snapshot fetch in its own processing.
252  */
254  {
255  /* First, create the snapshot in CurrentSnapshotData */
258  else
260  /* Make a saved copy */
263  /* Mark it as "registered" in FirstXactSnapshot */
266  }
267  else
269 
270  FirstSnapshotSet = true;
271  return CurrentSnapshot;
272  }
273 
275  return CurrentSnapshot;
276 
277  /* Don't allow catalog snapshot to be older than xact snapshot. */
279 
281 
282  return CurrentSnapshot;
283 }
Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot)
Definition: predicate.c:1672
static SnapshotData CurrentSnapshotData
Definition: snapmgr.c:81
#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 _brin_begin_parallel(), _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(), index_drop(), 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 1624 of file snapmgr.c.

1625 {
1626  if (ActiveSnapshot != NULL)
1627  return true;
1628 
1629  /*
1630  * The catalog snapshot is in RegisteredSnapshots when valid, but can be
1631  * removed at any time due to invalidation processing. If explicitly
1632  * registered more than one snapshot has to be in RegisteredSnapshots.
1633  */
1634  if (CatalogSnapshot != NULL &&
1636  return false;
1637 
1639 }
#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 1678 of file snapmgr.c.

1679 {
1681  return tuplecid_data;
1682 }
static HTAB * tuplecid_data
Definition: snapmgr.c:102

References Assert, HistoricSnapshotActive(), and tuplecid_data.

Referenced by HeapTupleSatisfiesHistoricMVCC().

◆ ImportSnapshot()

void ImportSnapshot ( const char *  idstr)

Definition at line 1367 of file snapmgr.c.

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

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

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 1337 of file snapmgr.c.

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

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

Referenced by ImportSnapshot().

◆ parseXidFromText()

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

Definition at line 1312 of file snapmgr.c.

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

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

Referenced by ImportSnapshot().

◆ pg_export_snapshot()

Datum pg_export_snapshot ( PG_FUNCTION_ARGS  )

Definition at line 1272 of file snapmgr.c.

1273 {
1274  char *snapshotName;
1275 
1276  snapshotName = ExportSnapshot(GetActiveSnapshot());
1277  PG_RETURN_TEXT_P(cstring_to_text(snapshotName));
1278 }
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
char * ExportSnapshot(Snapshot snapshot)
Definition: snapmgr.c:1095
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:770
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 743 of file snapmgr.c.

744 {
745  ActiveSnapshotElt *newstack;
746 
747  newstack = ActiveSnapshot->as_next;
748 
750 
752 
753  if (ActiveSnapshot->as_snap->active_count == 0 &&
756 
758  ActiveSnapshot = newstack;
759  if (ActiveSnapshot == NULL)
760  OldestActiveSnapshot = NULL;
761 
763 }

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(), FindConflictTuple(), 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 662 of file snapmgr.c.

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

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 700 of file snapmgr.c.

701 {
702  PushActiveSnapshot(CopySnapshot(snapshot));
703 }
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:648

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 807 of file snapmgr.c.

808 {
809  Snapshot snap;
810 
811  if (snapshot == InvalidSnapshot)
812  return InvalidSnapshot;
813 
814  /* Static snapshot? Create a persistent copy */
815  snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
816 
817  /* and tell resowner.c about it */
818  ResourceOwnerEnlarge(owner);
819  snap->regd_count++;
820  ResourceOwnerRememberSnapshot(owner, snap);
821 
822  if (snap->regd_count == 1)
824 
825  return snap;
826 }
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:442
static void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snap)
Definition: snapmgr.c:177

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 182 of file snapmgr.c.

183 {
185 }
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:554
static const ResourceOwnerDesc snapshot_resowner_desc
Definition: snapmgr.c:166

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

Referenced by UnregisterSnapshotFromOwner().

◆ ResourceOwnerRememberSnapshot()

static void ResourceOwnerRememberSnapshot ( ResourceOwner  owner,
Snapshot  snap 
)
inlinestatic

Definition at line 177 of file snapmgr.c.

178 {
180 }
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:514

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

Referenced by RegisterSnapshotOnOwner().

◆ ResOwnerReleaseSnapshot()

static void ResOwnerReleaseSnapshot ( Datum  res)
static

Definition at line 1955 of file snapmgr.c.

1956 {
1958 }
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static void UnregisterSnapshotNoOwner(Snapshot snapshot)
Definition: snapmgr.c:859

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

◆ RestoreSnapshot()

Snapshot RestoreSnapshot ( char *  start_address)

Definition at line 1775 of file snapmgr.c.

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

◆ RestoreTransactionSnapshot()

void RestoreTransactionSnapshot ( Snapshot  snapshot,
void *  source_pgproc 
)

Definition at line 1840 of file snapmgr.c.

1841 {
1842  SetTransactionSnapshot(snapshot, NULL, InvalidPid, source_pgproc);
1843 }
#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 1716 of file snapmgr.c.

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

◆ SetTransactionSnapshot()

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

Definition at line 477 of file snapmgr.c.

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

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 1649 of file snapmgr.c.

1650 {
1651  Assert(historic_snapshot != NULL);
1652 
1653  /* setup the timetravel snapshot */
1654  HistoricSnapshot = historic_snapshot;
1655 
1656  /* setup (cmin, cmax) lookup hash */
1657  tuplecid_data = tuplecids;
1658 }

References Assert, HistoricSnapshot, and tuplecid_data.

Referenced by ReorderBufferProcessTXN(), and ReorderBufferQueueMessage().

◆ SnapshotResetXmin()

static void SnapshotResetXmin ( void  )
static

Definition at line 914 of file snapmgr.c.

915 {
916  Snapshot minSnapshot;
917 
918  if (ActiveSnapshot != NULL)
919  return;
920 
922  {
924  return;
925  }
926 
927  minSnapshot = pairingheap_container(SnapshotData, ph_node,
929 
930  if (TransactionIdPrecedes(MyProc->xmin, minSnapshot->xmin))
931  MyProc->xmin = minSnapshot->xmin;
932 }

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 456 of file snapmgr.c.

457 {
458  if (!FirstSnapshotSet)
459  return;
460 
461  if (CurrentSnapshot)
462  CurrentSnapshot->curcid = curcid;
463  if (SecondarySnapshot)
464  SecondarySnapshot->curcid = curcid;
465  /* Should we do the same with CatalogSnapshot? */
466 }

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

Referenced by CommandCounterIncrement().

◆ TeardownHistoricSnapshot()

void TeardownHistoricSnapshot ( bool  is_error)

Definition at line 1665 of file snapmgr.c.

1666 {
1667  HistoricSnapshot = NULL;
1668  tuplecid_data = NULL;
1669 }

References HistoricSnapshot, and tuplecid_data.

Referenced by ReorderBufferProcessTXN(), and ReorderBufferQueueMessage().

◆ ThereAreNoPriorRegisteredSnapshots()

bool ThereAreNoPriorRegisteredSnapshots ( void  )

Definition at line 1606 of file snapmgr.c.

1607 {
1610  return true;
1611 
1612  return false;
1613 }

References pairingheap_is_empty, pairingheap_is_singular, and RegisteredSnapshots.

Referenced by CopyFrom().

◆ UnregisterSnapshot()

◆ UnregisterSnapshotFromOwner()

void UnregisterSnapshotFromOwner ( Snapshot  snapshot,
ResourceOwner  owner 
)

Definition at line 849 of file snapmgr.c.

850 {
851  if (snapshot == NULL)
852  return;
853 
854  ResourceOwnerForgetSnapshot(owner, snapshot);
855  UnregisterSnapshotNoOwner(snapshot);
856 }
static void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snap)
Definition: snapmgr.c:182

References ResourceOwnerForgetSnapshot(), and UnregisterSnapshotNoOwner().

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

◆ UnregisterSnapshotNoOwner()

static void UnregisterSnapshotNoOwner ( Snapshot  snapshot)
static

Definition at line 859 of file snapmgr.c.

860 {
861  Assert(snapshot->regd_count > 0);
863 
864  snapshot->regd_count--;
865  if (snapshot->regd_count == 0)
867 
868  if (snapshot->regd_count == 0 && snapshot->active_count == 0)
869  {
870  FreeSnapshot(snapshot);
872  }
873 }

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 712 of file snapmgr.c.

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

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 1554 of file snapmgr.c.

1555 {
1556  return (exportedSnapshots != NIL);
1557 }

References exportedSnapshots, and NIL.

Referenced by PrepareTransaction().

◆ XidInMVCCSnapshot()

bool XidInMVCCSnapshot ( TransactionId  xid,
Snapshot  snapshot 
)

Definition at line 1856 of file snapmgr.c.

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

881 {
882  const SnapshotData *asnap = pairingheap_const_container(SnapshotData, ph_node, a);
883  const SnapshotData *bsnap = pairingheap_const_container(SnapshotData, ph_node, b);
884 
885  if (TransactionIdPrecedes(asnap->xmin, bsnap->xmin))
886  return 1;
887  else if (TransactionIdFollows(asnap->xmin, bsnap->xmin))
888  return -1;
889  else
890  return 0;
891 }
int b
Definition: isn.c:69
int a
Definition: isn.c:68
#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 83 of file snapmgr.c.

Referenced by GetNonHistoricCatalogSnapshot().

◆ CurrentSnapshot

◆ CurrentSnapshotData

SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC}
static

Definition at line 81 of file snapmgr.c.

Referenced by GetTransactionSnapshot(), and SetTransactionSnapshot().

◆ exportedSnapshots

List* exportedSnapshots = NIL
static

Definition at line 155 of file snapmgr.c.

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

◆ FirstSnapshotSet

◆ FirstXactSnapshot

Snapshot FirstXactSnapshot = NULL
static

Definition at line 142 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 82 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:1955

Definition at line 166 of file snapmgr.c.

Referenced by ResourceOwnerForgetSnapshot(), and ResourceOwnerRememberSnapshot().

◆ SnapshotAnyData

SnapshotData SnapshotAnyData = {SNAPSHOT_ANY}

Definition at line 85 of file snapmgr.c.

◆ SnapshotSelfData

SnapshotData SnapshotSelfData = {SNAPSHOT_SELF}

Definition at line 84 of file snapmgr.c.

◆ TransactionXmin

◆ tuplecid_data