PostgreSQL Source Code  git master
snapmgr.h File Reference
#include "access/transam.h"
#include "utils/relcache.h"
#include "utils/resowner.h"
#include "utils/snapshot.h"
Include dependency graph for snapmgr.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define OLD_SNAPSHOT_PADDING_ENTRIES   10
 
#define OLD_SNAPSHOT_TIME_MAP_ENTRIES   (old_snapshot_threshold + OLD_SNAPSHOT_PADDING_ENTRIES)
 
#define RelationAllowsEarlyPruning(rel)
 
#define EarlyPruningEnabled(rel)   (old_snapshot_threshold >= 0 && RelationAllowsEarlyPruning(rel))
 
#define SnapshotSelf   (&SnapshotSelfData)
 
#define SnapshotAny   (&SnapshotAnyData)
 
#define InitDirtySnapshot(snapshotdata)    ((snapshotdata).snapshot_type = SNAPSHOT_DIRTY)
 
#define InitNonVacuumableSnapshot(snapshotdata, vistestp)
 
#define InitToastSnapshot(snapshotdata, l, w)
 
#define IsMVCCSnapshot(snapshot)
 

Typedefs

typedef struct GlobalVisState GlobalVisState
 

Functions

Size SnapMgrShmemSize (void)
 
void SnapMgrInit (void)
 
TimestampTz GetSnapshotCurrentTimestamp (void)
 
TimestampTz GetOldSnapshotThresholdTimestamp (void)
 
void SnapshotTooOldMagicForTest (void)
 
static bool OldSnapshotThresholdActive (void)
 
Snapshot GetTransactionSnapshot (void)
 
Snapshot GetLatestSnapshot (void)
 
void SnapshotSetCommandId (CommandId curcid)
 
Snapshot GetOldestSnapshot (void)
 
Snapshot GetCatalogSnapshot (Oid relid)
 
Snapshot GetNonHistoricCatalogSnapshot (Oid relid)
 
void InvalidateCatalogSnapshot (void)
 
void InvalidateCatalogSnapshotConditionally (void)
 
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)
 
void UnregisterSnapshot (Snapshot snapshot)
 
Snapshot RegisterSnapshotOnOwner (Snapshot snapshot, ResourceOwner owner)
 
void UnregisterSnapshotFromOwner (Snapshot snapshot, ResourceOwner owner)
 
void AtSubCommit_Snapshot (int level)
 
void AtSubAbort_Snapshot (int level)
 
void AtEOXact_Snapshot (bool isCommit, bool resetXmin)
 
void ImportSnapshot (const char *idstr)
 
bool XactHasExportedSnapshots (void)
 
void DeleteAllExportedSnapshotFiles (void)
 
void WaitForOlderSnapshots (TransactionId limitXmin, bool progress)
 
bool ThereAreNoPriorRegisteredSnapshots (void)
 
bool TransactionIdLimitedForOldSnapshots (TransactionId recentXmin, Relation relation, TransactionId *limit_xid, TimestampTz *limit_ts)
 
void SetOldSnapshotThresholdTimestamp (TimestampTz ts, TransactionId xlimit)
 
void MaintainOldSnapshotTimeMapping (TimestampTz whenTaken, TransactionId xmin)
 
char * ExportSnapshot (Snapshot snapshot)
 
GlobalVisStateGlobalVisTestFor (Relation rel)
 
bool GlobalVisTestIsRemovableXid (GlobalVisState *state, TransactionId xid)
 
bool GlobalVisTestIsRemovableFullXid (GlobalVisState *state, FullTransactionId fxid)
 
FullTransactionId GlobalVisTestNonRemovableFullHorizon (GlobalVisState *state)
 
TransactionId GlobalVisTestNonRemovableHorizon (GlobalVisState *state)
 
bool GlobalVisCheckRemovableXid (Relation rel, TransactionId xid)
 
bool GlobalVisCheckRemovableFullXid (Relation rel, FullTransactionId fxid)
 
bool XidInMVCCSnapshot (TransactionId xid, Snapshot snapshot)
 
struct HTABHistoricSnapshotGetTupleCids (void)
 
void SetupHistoricSnapshot (Snapshot snapshot_now, struct HTAB *tuplecids)
 
void TeardownHistoricSnapshot (bool is_error)
 
bool HistoricSnapshotActive (void)
 
Size EstimateSnapshotSpace (Snapshot snapshot)
 
void SerializeSnapshot (Snapshot snapshot, char *start_address)
 
Snapshot RestoreSnapshot (char *start_address)
 
void RestoreTransactionSnapshot (Snapshot snapshot, void *source_pgproc)
 

Variables

PGDLLIMPORT int old_snapshot_threshold
 
bool FirstSnapshotSet
 
PGDLLIMPORT TransactionId TransactionXmin
 
PGDLLIMPORT TransactionId RecentXmin
 
PGDLLIMPORT SnapshotData SnapshotSelfData
 
PGDLLIMPORT SnapshotData SnapshotAnyData
 
PGDLLIMPORT SnapshotData CatalogSnapshotData
 

Macro Definition Documentation

◆ EarlyPruningEnabled

#define EarlyPruningEnabled (   rel)    (old_snapshot_threshold >= 0 && RelationAllowsEarlyPruning(rel))

Definition at line 44 of file snapmgr.h.

◆ InitDirtySnapshot

#define InitDirtySnapshot (   snapshotdata)     ((snapshotdata).snapshot_type = SNAPSHOT_DIRTY)

Definition at line 74 of file snapmgr.h.

◆ InitNonVacuumableSnapshot

#define InitNonVacuumableSnapshot (   snapshotdata,
  vistestp 
)
Value:
((snapshotdata).snapshot_type = SNAPSHOT_NON_VACUUMABLE, \
(snapshotdata).vistest = (vistestp))
@ SNAPSHOT_NON_VACUUMABLE
Definition: snapshot.h:118

Definition at line 82 of file snapmgr.h.

◆ InitToastSnapshot

#define InitToastSnapshot (   snapshotdata,
  l,
 
)
Value:
((snapshotdata).snapshot_type = SNAPSHOT_TOAST, \
(snapshotdata).lsn = (l), \
(snapshotdata).whenTaken = (w))
@ SNAPSHOT_TOAST
Definition: snapshot.h:74

Definition at line 90 of file snapmgr.h.

◆ IsMVCCSnapshot

#define IsMVCCSnapshot (   snapshot)
Value:
((snapshot)->snapshot_type == SNAPSHOT_MVCC || \
(snapshot)->snapshot_type == SNAPSHOT_HISTORIC_MVCC)
@ SNAPSHOT_MVCC
Definition: snapshot.h:50
@ SNAPSHOT_HISTORIC_MVCC
Definition: snapshot.h:109

Definition at line 96 of file snapmgr.h.

◆ OLD_SNAPSHOT_PADDING_ENTRIES

#define OLD_SNAPSHOT_PADDING_ENTRIES   10

Definition at line 31 of file snapmgr.h.

◆ OLD_SNAPSHOT_TIME_MAP_ENTRIES

#define OLD_SNAPSHOT_TIME_MAP_ENTRIES   (old_snapshot_threshold + OLD_SNAPSHOT_PADDING_ENTRIES)

Definition at line 32 of file snapmgr.h.

◆ RelationAllowsEarlyPruning

#define RelationAllowsEarlyPruning (   rel)
Value:
( \
RelationIsPermanent(rel) && !IsCatalogRelation(rel) \
)
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:104
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:658

Definition at line 38 of file snapmgr.h.

◆ SnapshotAny

#define SnapshotAny   (&SnapshotAnyData)

Definition at line 67 of file snapmgr.h.

◆ SnapshotSelf

#define SnapshotSelf   (&SnapshotSelfData)

Definition at line 66 of file snapmgr.h.

Typedef Documentation

◆ GlobalVisState

Definition at line 146 of file snapmgr.h.

Function Documentation

◆ ActiveSnapshotSet()

◆ AtEOXact_Snapshot()

void AtEOXact_Snapshot ( bool  isCommit,
bool  resetXmin 
)

Definition at line 1021 of file snapmgr.c.

1022 {
1023  /*
1024  * In transaction-snapshot mode we must release our privately-managed
1025  * reference to the transaction snapshot. We must remove it from
1026  * RegisteredSnapshots to keep the check below happy. But we don't bother
1027  * to do FreeSnapshot, for two reasons: the memory will go away with
1028  * TopTransactionContext anyway, and if someone has left the snapshot
1029  * stacked as active, we don't want the code below to be chasing through a
1030  * dangling pointer.
1031  */
1032  if (FirstXactSnapshot != NULL)
1033  {
1037  }
1038  FirstXactSnapshot = NULL;
1039 
1040  /*
1041  * If we exported any snapshots, clean them up.
1042  */
1043  if (exportedSnapshots != NIL)
1044  {
1045  ListCell *lc;
1046 
1047  /*
1048  * Get rid of the files. Unlink failure is only a WARNING because (1)
1049  * it's too late to abort the transaction, and (2) leaving a leaked
1050  * file around has little real consequence anyway.
1051  *
1052  * We also need to remove the snapshots from RegisteredSnapshots to
1053  * prevent a warning below.
1054  *
1055  * As with the FirstXactSnapshot, we don't need to free resources of
1056  * the snapshot itself as it will go away with the memory context.
1057  */
1058  foreach(lc, exportedSnapshots)
1059  {
1060  ExportedSnapshot *esnap = (ExportedSnapshot *) lfirst(lc);
1061 
1062  if (unlink(esnap->snapfile))
1063  elog(WARNING, "could not unlink file \"%s\": %m",
1064  esnap->snapfile);
1065 
1067  &esnap->snapshot->ph_node);
1068  }
1069 
1071  }
1072 
1073  /* Drop catalog snapshot if any */
1075 
1076  /* On commit, complain about leftover snapshots */
1077  if (isCommit)
1078  {
1079  ActiveSnapshotElt *active;
1080 
1082  elog(WARNING, "registered snapshots seem to remain after cleanup");
1083 
1084  /* complain about unpopped active snapshots */
1085  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
1086  elog(WARNING, "snapshot %p still active", active);
1087  }
1088 
1089  /*
1090  * And reset our state. We don't need to free the memory explicitly --
1091  * it'll go away with TopTransactionContext.
1092  */
1093  ActiveSnapshot = NULL;
1094  OldestActiveSnapshot = NULL;
1096 
1097  CurrentSnapshot = NULL;
1098  SecondarySnapshot = NULL;
1099 
1100  FirstSnapshotSet = false;
1101 
1102  /*
1103  * During normal commit processing, we call ProcArrayEndTransaction() to
1104  * reset the MyProc->xmin. That call happens prior to the call to
1105  * AtEOXact_Snapshot(), so we need not touch xmin here at all.
1106  */
1107  if (resetXmin)
1109 
1110  Assert(resetXmin || MyProc->xmin == 0);
1111 }
#define WARNING
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:218
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:169
#define NIL
Definition: pg_list.h:65
static Snapshot FirstXactSnapshot
Definition: snapmgr.c:156
static Snapshot CurrentSnapshot
Definition: snapmgr.c:102
static Snapshot SecondarySnapshot
Definition: snapmgr.c:103
static List * exportedSnapshots
Definition: snapmgr.c:169
static pairingheap RegisteredSnapshots
Definition: snapmgr.c:146
bool FirstSnapshotSet
Definition: snapmgr.c:149
static ActiveSnapshotElt * OldestActiveSnapshot
Definition: snapmgr.c:137
static void SnapshotResetXmin(void)
Definition: snapmgr.c:940
void InvalidateCatalogSnapshot(void)
Definition: snapmgr.c:456
PGPROC * MyProc
Definition: proc.c:68
struct ActiveSnapshotElt * as_next
Definition: snapmgr.c:130
char * snapfile
Definition: snapmgr.c:164
Snapshot snapshot
Definition: snapmgr.c:165
TransactionId xmin
Definition: proc.h:141
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 985 of file snapmgr.c.

986 {
987  /* Forget the active snapshots set by this subtransaction */
988  while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
989  {
991 
993 
994  /*
995  * Decrement the snapshot's active count. If it's still registered or
996  * marked as active by an outer subtransaction, we can't free it yet.
997  */
1000 
1001  if (ActiveSnapshot->as_snap->active_count == 0 &&
1004 
1005  /* and free the stack element */
1007 
1008  ActiveSnapshot = next;
1009  if (ActiveSnapshot == NULL)
1010  OldestActiveSnapshot = NULL;
1011  }
1012 
1014 }
static int32 next
Definition: blutils.c:219
void pfree(void *pointer)
Definition: mcxt.c:1169
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:662
Snapshot as_snap
Definition: snapmgr.c:128
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 964 of file snapmgr.c.

965 {
966  ActiveSnapshotElt *active;
967 
968  /*
969  * Relabel the active snapshots set in this subtransaction as though they
970  * are owned by the parent subxact.
971  */
972  for (active = ActiveSnapshot; active != NULL; active = active->as_next)
973  {
974  if (active->as_level < level)
975  break;
976  active->as_level = level - 1;
977  }
978 }

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

Referenced by CommitSubTransaction().

◆ DeleteAllExportedSnapshotFiles()

void DeleteAllExportedSnapshotFiles ( void  )

Definition at line 1580 of file snapmgr.c.

1581 {
1582  char buf[MAXPGPATH + sizeof(SNAPSHOT_EXPORT_DIR)];
1583  DIR *s_dir;
1584  struct dirent *s_de;
1585 
1586  /*
1587  * Problems in reading the directory, or unlinking files, are reported at
1588  * LOG level. Since we're running in the startup process, ERROR level
1589  * would prevent database start, and it's not important enough for that.
1590  */
1592 
1593  while ((s_de = ReadDirExtended(s_dir, SNAPSHOT_EXPORT_DIR, LOG)) != NULL)
1594  {
1595  if (strcmp(s_de->d_name, ".") == 0 ||
1596  strcmp(s_de->d_name, "..") == 0)
1597  continue;
1598 
1599  snprintf(buf, sizeof(buf), SNAPSHOT_EXPORT_DIR "/%s", s_de->d_name);
1600 
1601  if (unlink(buf) != 0)
1602  ereport(LOG,
1604  errmsg("could not remove file \"%s\": %m", buf)));
1605  }
1606 
1607  FreeDir(s_dir);
1608 }
int errcode_for_file_access(void)
Definition: elog.c:721
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define LOG
Definition: elog.h:25
#define ereport(elevel,...)
Definition: elog.h:143
int FreeDir(DIR *dir)
Definition: fd.c:2840
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2803
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2722
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:70
#define snprintf
Definition: port.h:222
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:159
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 2093 of file snapmgr.c.

2094 {
2095  Size size;
2096 
2097  Assert(snap != InvalidSnapshot);
2098  Assert(snap->snapshot_type == SNAPSHOT_MVCC);
2099 
2100  /* We allocate any XID arrays needed in the same palloc block. */
2101  size = add_size(sizeof(SerializedSnapshotData),
2102  mul_size(snap->xcnt, sizeof(TransactionId)));
2103  if (snap->subxcnt > 0 &&
2104  (!snap->suboverflowed || snap->takenDuringRecovery))
2105  size = add_size(size,
2106  mul_size(snap->subxcnt, sizeof(TransactionId)));
2107 
2108  return size;
2109 }
uint32 TransactionId
Definition: c.h:587
size_t Size
Definition: c.h:540
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
#define InvalidSnapshot
Definition: snapshot.h:123

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

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

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

◆ GetActiveSnapshot()

◆ GetCatalogSnapshot()

Snapshot GetCatalogSnapshot ( Oid  relid)

Definition at line 386 of file snapmgr.c.

387 {
388  /*
389  * Return historic snapshot while we're doing logical decoding, so we can
390  * see the appropriate state of the catalog.
391  *
392  * This is the primary reason for needing to reset the system caches after
393  * finishing decoding.
394  */
396  return HistoricSnapshot;
397 
398  return GetNonHistoricCatalogSnapshot(relid);
399 }
static Snapshot HistoricSnapshot
Definition: snapmgr.c:105
bool HistoricSnapshotActive(void)
Definition: snapmgr.c:2073
Snapshot GetNonHistoricCatalogSnapshot(Oid relid)
Definition: snapmgr.c:408

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

326 {
327  /*
328  * We might be able to relax this, but nothing that could otherwise work
329  * needs it.
330  */
331  if (IsInParallelMode())
332  elog(ERROR,
333  "cannot update SecondarySnapshot during a parallel operation");
334 
335  /*
336  * So far there are no cases requiring support for GetLatestSnapshot()
337  * during logical decoding, but it wouldn't be hard to add if required.
338  */
340 
341  /* If first call in transaction, go ahead and set the xact snapshot */
342  if (!FirstSnapshotSet)
343  return GetTransactionSnapshot();
344 
346 
347  return SecondarySnapshot;
348 }
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:2206
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
static SnapshotData SecondarySnapshotData
Definition: snapmgr.c:96
bool IsInParallelMode(void)
Definition: xact.c:1064

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

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

◆ GetNonHistoricCatalogSnapshot()

Snapshot GetNonHistoricCatalogSnapshot ( Oid  relid)

Definition at line 408 of file snapmgr.c.

409 {
410  /*
411  * If the caller is trying to scan a relation that has no syscache, no
412  * catcache invalidations will be sent when it is updated. For a few key
413  * relations, snapshot invalidations are sent instead. If we're trying to
414  * scan a relation for which neither catcache nor snapshot invalidations
415  * are sent, we must refresh the snapshot every time.
416  */
417  if (CatalogSnapshot &&
419  !RelationHasSysCache(relid))
421 
422  if (CatalogSnapshot == NULL)
423  {
424  /* Get new snapshot. */
426 
427  /*
428  * Make sure the catalog snapshot will be accounted for in decisions
429  * about advancing PGPROC->xmin. We could apply RegisterSnapshot, but
430  * that would result in making a physical copy, which is overkill; and
431  * it would also create a dependency on some resource owner, which we
432  * do not want for reasons explained at the head of this file. Instead
433  * just shove the CatalogSnapshot into the pairing heap manually. This
434  * has to be reversed in InvalidateCatalogSnapshot, of course.
435  *
436  * NB: it had better be impossible for this to throw error, since the
437  * CatalogSnapshot pointer is already valid.
438  */
440  }
441 
442  return CatalogSnapshot;
443 }
SnapshotData CatalogSnapshotData
Definition: snapmgr.c:97
static Snapshot CatalogSnapshot
Definition: snapmgr.c:104
bool RelationHasSysCache(Oid relid)
Definition: syscache.c:1530
bool RelationInvalidatesSnapshotsOnly(Oid relid)
Definition: syscache.c:1507

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

358 {
359  Snapshot OldestRegisteredSnapshot = NULL;
360  XLogRecPtr RegisteredLSN = InvalidXLogRecPtr;
361 
363  {
364  OldestRegisteredSnapshot = pairingheap_container(SnapshotData, ph_node,
366  RegisteredLSN = OldestRegisteredSnapshot->lsn;
367  }
368 
369  if (OldestActiveSnapshot != NULL)
370  {
372 
373  if (XLogRecPtrIsInvalid(RegisteredLSN) || RegisteredLSN > ActiveLSN)
375  }
376 
377  return OldestRegisteredSnapshot;
378 }
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().

◆ GetOldSnapshotThresholdTimestamp()

TimestampTz GetOldSnapshotThresholdTimestamp ( void  )

Definition at line 1675 of file snapmgr.c.

1676 {
1677  TimestampTz threshold_timestamp;
1678 
1680  threshold_timestamp = oldSnapshotControl->threshold_timestamp;
1682 
1683  return threshold_timestamp;
1684 }
int64 TimestampTz
Definition: timestamp.h:39
volatile OldSnapshotControlData * oldSnapshotControl
Definition: snapmgr.c:80
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
TimestampTz threshold_timestamp
Definition: old_snapshot.h:36

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

Referenced by TestForOldSnapshot_impl().

◆ GetSnapshotCurrentTimestamp()

TimestampTz GetSnapshotCurrentTimestamp ( void  )

Definition at line 1650 of file snapmgr.c.

1651 {
1653 
1654  /*
1655  * Don't let time move backward; if it hasn't advanced, use the old value.
1656  */
1658  if (now <= oldSnapshotControl->current_timestamp)
1660  else
1663 
1664  return now;
1665 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1580
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1544
TimestampTz current_timestamp
Definition: old_snapshot.h:31

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

Referenced by GetSnapshotDataInitOldSnapshot(), SnapshotTooOldMagicForTest(), and TransactionIdLimitedForOldSnapshots().

◆ GetTransactionSnapshot()

Snapshot GetTransactionSnapshot ( void  )

Definition at line 250 of file snapmgr.c.

251 {
252  /*
253  * Return historic snapshot if doing logical decoding. We'll never need a
254  * non-historic transaction snapshot in this (sub-)transaction, so there's
255  * no need to be careful to set one up for later calls to
256  * GetTransactionSnapshot().
257  */
259  {
261  return HistoricSnapshot;
262  }
263 
264  /* First call in transaction? */
265  if (!FirstSnapshotSet)
266  {
267  /*
268  * Don't allow catalog snapshot to be older than xact snapshot. Must
269  * do this first to allow the empty-heap Assert to succeed.
270  */
272 
274  Assert(FirstXactSnapshot == NULL);
275 
276  if (IsInParallelMode())
277  elog(ERROR,
278  "cannot take query snapshot during a parallel operation");
279 
280  /*
281  * In transaction-snapshot mode, the first snapshot must live until
282  * end of xact regardless of what the caller does with it, so we must
283  * make a copy of it rather than returning CurrentSnapshotData
284  * directly. Furthermore, if we're running in serializable mode,
285  * predicate.c needs to wrap the snapshot fetch in its own processing.
286  */
288  {
289  /* First, create the snapshot in CurrentSnapshotData */
292  else
294  /* Make a saved copy */
297  /* Mark it as "registered" in FirstXactSnapshot */
300  }
301  else
303 
304  FirstSnapshotSet = true;
305  return CurrentSnapshot;
306  }
307 
309  return CurrentSnapshot;
310 
311  /* Don't allow catalog snapshot to be older than xact snapshot. */
313 
315 
316  return CurrentSnapshot;
317 }
Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot)
Definition: predicate.c:1680
static SnapshotData CurrentSnapshotData
Definition: snapmgr.c:95
#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(), DefineIndex(), EnsurePortalSnapshotExists(), 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(), ReindexMultipleInternal(), ReindexRelationConcurrently(), RevalidateCachedQuery(), ri_PerformCheck(), SPI_cursor_open_internal(), vacuum(), vacuum_rel(), verify_heapam(), and XidIsConcurrent().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4251 of file procarray.c.

4252 {
4254 
4255  state = GlobalVisTestFor(rel);
4256 
4257  return GlobalVisTestIsRemovableFullXid(state, fxid);
4258 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4157
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4042
Definition: regguts.h:318

References GlobalVisTestFor(), and GlobalVisTestIsRemovableFullXid().

Referenced by _bt_pendingfsm_finalize(), BTPageIsRecyclable(), and gistPageRecyclable().

◆ GlobalVisCheckRemovableXid()

bool GlobalVisCheckRemovableXid ( Relation  rel,
TransactionId  xid 
)

Definition at line 4265 of file procarray.c.

4266 {
4268 
4269  state = GlobalVisTestFor(rel);
4270 
4271  return GlobalVisTestIsRemovableXid(state, xid);
4272 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4199

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisTestFor()

GlobalVisState* GlobalVisTestFor ( Relation  rel)

Definition at line 4042 of file procarray.c.

4043 {
4044  GlobalVisState *state = NULL;
4045 
4046  /* XXX: we should assert that a snapshot is pushed or registered */
4047  Assert(RecentXmin);
4048 
4049  switch (GlobalVisHorizonKindForRel(rel))
4050  {
4051  case VISHORIZON_SHARED:
4053  break;
4054  case VISHORIZON_CATALOG:
4056  break;
4057  case VISHORIZON_DATA:
4059  break;
4060  case VISHORIZON_TEMP:
4062  break;
4063  }
4064 
4065  Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4066  FullTransactionIdIsValid(state->maybe_needed));
4067 
4068  return state;
4069 }
static GlobalVisState GlobalVisDataRels
Definition: procarray.c:286
static GlobalVisState GlobalVisSharedRels
Definition: procarray.c:284
static GlobalVisState GlobalVisCatalogRels
Definition: procarray.c:285
static GlobalVisState GlobalVisTempRels
Definition: procarray.c:287
@ VISHORIZON_SHARED
Definition: procarray.c:254
@ VISHORIZON_DATA
Definition: procarray.c:256
@ VISHORIZON_CATALOG
Definition: procarray.c:255
@ VISHORIZON_TEMP
Definition: procarray.c:257
static GlobalVisHorizonKind GlobalVisHorizonKindForRel(Relation rel)
Definition: procarray.c:1971
TransactionId RecentXmin
Definition: snapmgr.c:113
#define FullTransactionIdIsValid(x)
Definition: transam.h:55

References Assert(), FullTransactionIdIsValid, GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisHorizonKindForRel(), GlobalVisSharedRels, GlobalVisTempRels, RecentXmin, VISHORIZON_CATALOG, VISHORIZON_DATA, VISHORIZON_SHARED, and VISHORIZON_TEMP.

Referenced by get_actual_variable_endpoint(), GlobalVisCheckRemovableFullXid(), GlobalVisCheckRemovableXid(), heap_hot_search_buffer(), heap_index_delete_tuples(), heap_page_prune_opt(), lazy_scan_heap(), and vacuumRedirectAndPlaceholder().

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4157 of file procarray.c.

4159 {
4160  /*
4161  * If fxid is older than maybe_needed bound, it definitely is visible to
4162  * everyone.
4163  */
4164  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4165  return true;
4166 
4167  /*
4168  * If fxid is >= definitely_needed bound, it is very likely to still be
4169  * considered running.
4170  */
4171  if (FullTransactionIdFollowsOrEquals(fxid, state->definitely_needed))
4172  return false;
4173 
4174  /*
4175  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4176  * might not exist a snapshot considering fxid running. If it makes sense,
4177  * update boundaries and recheck.
4178  */
4180  {
4181  GlobalVisUpdate();
4182 
4183  Assert(FullTransactionIdPrecedes(fxid, state->definitely_needed));
4184 
4185  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4186  }
4187  else
4188  return false;
4189 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4082
static void GlobalVisUpdate(void)
Definition: procarray.c:4140
#define FullTransactionIdFollowsOrEquals(a, b)
Definition: transam.h:54
#define FullTransactionIdPrecedes(a, b)
Definition: transam.h:51

References Assert(), FullTransactionIdFollowsOrEquals, FullTransactionIdPrecedes, GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisCheckRemovableFullXid(), and GlobalVisTestIsRemovableXid().

◆ GlobalVisTestIsRemovableXid()

bool GlobalVisTestIsRemovableXid ( GlobalVisState state,
TransactionId  xid 
)

Definition at line 4199 of file procarray.c.

4200 {
4201  FullTransactionId fxid;
4202 
4203  /*
4204  * Convert 32 bit argument to FullTransactionId. We can do so safely
4205  * because we know the xid has to, at the very least, be between
4206  * [oldestXid, nextFullXid), i.e. within 2 billion of xid. To avoid taking
4207  * a lock to determine either, we can just compare with
4208  * state->definitely_needed, which was based on those value at the time
4209  * the current snapshot was built.
4210  */
4211  fxid = FullXidRelativeTo(state->definitely_needed, xid);
4212 
4213  return GlobalVisTestIsRemovableFullXid(state, fxid);
4214 }
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4286

References FullXidRelativeTo(), and GlobalVisTestIsRemovableFullXid().

Referenced by GlobalVisCheckRemovableXid(), heap_page_prune_opt(), heap_prune_satisfies_vacuum(), HeapTupleIsSurelyDead(), HeapTupleSatisfiesNonVacuumable(), and vacuumRedirectAndPlaceholder().

◆ GlobalVisTestNonRemovableFullHorizon()

FullTransactionId GlobalVisTestNonRemovableFullHorizon ( GlobalVisState state)

Definition at line 4226 of file procarray.c.

4227 {
4228  /* acquire accurate horizon if not already done */
4230  GlobalVisUpdate();
4231 
4232  return state->maybe_needed;
4233 }

References GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisTestNonRemovableHorizon().

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4237 of file procarray.c.

4238 {
4239  FullTransactionId cutoff;
4240 
4242 
4243  return XidFromFullTransactionId(cutoff);
4244 }
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4226
#define XidFromFullTransactionId(x)
Definition: transam.h:48

References GlobalVisTestNonRemovableFullHorizon(), and XidFromFullTransactionId.

Referenced by heap_page_prune_opt(), and heap_prune_satisfies_vacuum().

◆ HistoricSnapshotActive()

◆ HistoricSnapshotGetTupleCids()

struct HTAB* HistoricSnapshotGetTupleCids ( void  )

Definition at line 2079 of file snapmgr.c.

2080 {
2082  return tuplecid_data;
2083 }
static HTAB * tuplecid_data
Definition: snapmgr.c:116

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

Referenced by HeapTupleSatisfiesHistoricMVCC().

◆ ImportSnapshot()

void ImportSnapshot ( const char *  idstr)

Definition at line 1392 of file snapmgr.c.

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

References AllocateFile(), elog, ereport, errcode(), 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  )

Definition at line 477 of file snapmgr.c.

478 {
479  if (CatalogSnapshot &&
480  ActiveSnapshot == NULL &&
483 }
#define pairingheap_is_singular(h)
Definition: pairingheap.h:99

References ActiveSnapshot, CatalogSnapshot, InvalidateCatalogSnapshot(), pairingheap_is_singular, and RegisteredSnapshots.

Referenced by PostgresMain().

◆ MaintainOldSnapshotTimeMapping()

void MaintainOldSnapshotTimeMapping ( TimestampTz  whenTaken,
TransactionId  xmin 
)

Definition at line 1873 of file snapmgr.c.

1874 {
1875  TimestampTz ts;
1876  TransactionId latest_xmin;
1877  TimestampTz update_ts;
1878  bool map_update_required = false;
1879 
1880  /* Never call this function when old snapshot checking is disabled. */
1882 
1883  ts = AlignTimestampToMinuteBoundary(whenTaken);
1884 
1885  /*
1886  * Keep track of the latest xmin seen by any process. Update mapping with
1887  * a new value when we have crossed a bucket boundary.
1888  */
1890  latest_xmin = oldSnapshotControl->latest_xmin;
1891  update_ts = oldSnapshotControl->next_map_update;
1892  if (ts > update_ts)
1893  {
1895  map_update_required = true;
1896  }
1897  if (TransactionIdFollows(xmin, latest_xmin))
1900 
1901  /* We only needed to update the most recent xmin value. */
1902  if (!map_update_required)
1903  return;
1904 
1905  /* No further tracking needed for 0 (used for testing). */
1906  if (old_snapshot_threshold == 0)
1907  return;
1908 
1909  /*
1910  * We don't want to do something stupid with unusual values, but we don't
1911  * want to litter the log with warnings or break otherwise normal
1912  * processing for this feature; so if something seems unreasonable, just
1913  * log at DEBUG level and return without doing anything.
1914  */
1915  if (whenTaken < 0)
1916  {
1917  elog(DEBUG1,
1918  "MaintainOldSnapshotTimeMapping called with negative whenTaken = %ld",
1919  (long) whenTaken);
1920  return;
1921  }
1922  if (!TransactionIdIsNormal(xmin))
1923  {
1924  elog(DEBUG1,
1925  "MaintainOldSnapshotTimeMapping called with xmin = %lu",
1926  (unsigned long) xmin);
1927  return;
1928  }
1929 
1930  LWLockAcquire(OldSnapshotTimeMapLock, LW_EXCLUSIVE);
1931 
1937 
1938  if (oldSnapshotControl->count_used == 0)
1939  {
1940  /* set up first entry for empty mapping */
1944  oldSnapshotControl->xid_by_minute[0] = xmin;
1945  }
1946  else if (ts < oldSnapshotControl->head_timestamp)
1947  {
1948  /* old ts; log it at DEBUG */
1949  LWLockRelease(OldSnapshotTimeMapLock);
1950  elog(DEBUG1,
1951  "MaintainOldSnapshotTimeMapping called with old whenTaken = %ld",
1952  (long) whenTaken);
1953  return;
1954  }
1955  else if (ts <= (oldSnapshotControl->head_timestamp +
1957  * USECS_PER_MINUTE)))
1958  {
1959  /* existing mapping; advance xid if possible */
1960  int bucket = (oldSnapshotControl->head_offset
1962  / USECS_PER_MINUTE))
1964 
1966  oldSnapshotControl->xid_by_minute[bucket] = xmin;
1967  }
1968  else
1969  {
1970  /* We need a new bucket, but it might not be the very next one. */
1971  int distance_to_new_tail;
1972  int distance_to_current_tail;
1973  int advance;
1974 
1975  /*
1976  * Our goal is for the new "tail" of the mapping, that is, the entry
1977  * which is newest and thus furthest from the "head" entry, to
1978  * correspond to "ts". Since there's one entry per minute, the
1979  * distance between the current head and the new tail is just the
1980  * number of minutes of difference between ts and the current
1981  * head_timestamp.
1982  *
1983  * The distance from the current head to the current tail is one less
1984  * than the number of entries in the mapping, because the entry at the
1985  * head_offset is for 0 minutes after head_timestamp.
1986  *
1987  * The difference between these two values is the number of minutes by
1988  * which we need to advance the mapping, either adding new entries or
1989  * rotating old ones out.
1990  */
1991  distance_to_new_tail =
1993  distance_to_current_tail =
1995  advance = distance_to_new_tail - distance_to_current_tail;
1996  Assert(advance > 0);
1997 
1998  if (advance >= OLD_SNAPSHOT_TIME_MAP_ENTRIES)
1999  {
2000  /* Advance is so far that all old data is junk; start over. */
2003  oldSnapshotControl->xid_by_minute[0] = xmin;
2005  }
2006  else
2007  {
2008  /* Store the new value in one or more buckets. */
2009  int i;
2010 
2011  for (i = 0; i < advance; i++)
2012  {
2014  {
2015  /* Map full and new value replaces old head. */
2016  int old_head = oldSnapshotControl->head_offset;
2017 
2018  if (old_head == (OLD_SNAPSHOT_TIME_MAP_ENTRIES - 1))
2020  else
2021  oldSnapshotControl->head_offset = old_head + 1;
2022  oldSnapshotControl->xid_by_minute[old_head] = xmin;
2024  }
2025  else
2026  {
2027  /* Extend map to unused entry. */
2028  int new_tail = (oldSnapshotControl->head_offset
2031 
2033  oldSnapshotControl->xid_by_minute[new_tail] = xmin;
2034  }
2035  }
2036  }
2037  }
2038 
2039  LWLockRelease(OldSnapshotTimeMapLock);
2040 }
#define USECS_PER_MINUTE
Definition: timestamp.h:93
#define DEBUG1
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
@ LW_EXCLUSIVE
Definition: lwlock.h:104
static TimestampTz AlignTimestampToMinuteBoundary(TimestampTz ts)
Definition: snapmgr.c:1636
int old_snapshot_threshold
Definition: snapmgr.c:78
#define OLD_SNAPSHOT_TIME_MAP_ENTRIES
Definition: snapmgr.h:32
TimestampTz next_map_update
Definition: old_snapshot.h:34
TransactionId latest_xmin
Definition: old_snapshot.h:33
TimestampTz head_timestamp
Definition: old_snapshot.h:68
TransactionId xid_by_minute[FLEXIBLE_ARRAY_MEMBER]
Definition: old_snapshot.h:70
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334

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

Referenced by GetSnapshotDataInitOldSnapshot().

◆ OldSnapshotThresholdActive()

static bool OldSnapshotThresholdActive ( void  )
inlinestatic

Definition at line 101 of file snapmgr.h.

102 {
103  return old_snapshot_threshold >= 0;
104 }
PGDLLIMPORT int old_snapshot_threshold
Definition: snapmgr.c:78

References old_snapshot_threshold.

Referenced by GetSnapshotDataInitOldSnapshot(), heap_page_prune_opt(), heap_prune_satisfies_vacuum(), TransactionIdLimitedForOldSnapshots(), and vacuum_set_xid_limits().

◆ PopActiveSnapshot()

void PopActiveSnapshot ( void  )

Definition at line 774 of file snapmgr.c.

775 {
776  ActiveSnapshotElt *newstack;
777 
778  newstack = ActiveSnapshot->as_next;
779 
781 
783 
784  if (ActiveSnapshot->as_snap->active_count == 0 &&
787 
789  ActiveSnapshot = newstack;
790  if (ActiveSnapshot == NULL)
791  OldestActiveSnapshot = NULL;
792 
794 }

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(), DefineIndex(), DoPortalRewind(), end_replication_step(), EndCopyTo(), 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(), refresh_matview_datafill(), ReindexMultipleInternal(), ReindexRelationConcurrently(), RelationFindReplTupleByIndex(), RelationFindReplTupleSeq(), RevalidateCachedQuery(), ShutdownSQLFunction(), vacuum(), and vacuum_rel().

◆ PushActiveSnapshot()

◆ PushActiveSnapshotWithLevel()

void PushActiveSnapshotWithLevel ( Snapshot  snapshot,
int  snap_level 
)

Definition at line 694 of file snapmgr.c.

695 {
696  ActiveSnapshotElt *newactive;
697 
698  Assert(snap != InvalidSnapshot);
699  Assert(ActiveSnapshot == NULL || snap_level >= ActiveSnapshot->as_level);
700 
702 
703  /*
704  * Checking SecondarySnapshot is probably useless here, but it seems
705  * better to be sure.
706  */
707  if (snap == CurrentSnapshot || snap == SecondarySnapshot || !snap->copied)
708  newactive->as_snap = CopySnapshot(snap);
709  else
710  newactive->as_snap = snap;
711 
712  newactive->as_next = ActiveSnapshot;
713  newactive->as_level = snap_level;
714 
715  newactive->as_snap->active_count++;
716 
717  ActiveSnapshot = newactive;
718  if (OldestActiveSnapshot == NULL)
720 }
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
bool copied
Definition: snapshot.h:185

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

732 {
733  PushActiveSnapshot(CopySnapshot(snapshot));
734 }
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680

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

839 {
840  Snapshot snap;
841 
842  if (snapshot == InvalidSnapshot)
843  return InvalidSnapshot;
844 
845  /* Static snapshot? Create a persistent copy */
846  snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
847 
848  /* and tell resowner.c about it */
850  snap->regd_count++;
851  ResourceOwnerRememberSnapshot(owner, snap);
852 
853  if (snap->regd_count == 1)
855 
856  return snap;
857 }
void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1251
void ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
Definition: resowner.c:1240

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

Referenced by be_lo_open(), and RegisterSnapshot().

◆ RestoreSnapshot()

Snapshot RestoreSnapshot ( char *  start_address)

Definition at line 2176 of file snapmgr.c.

2177 {
2178  SerializedSnapshotData serialized_snapshot;
2179  Size size;
2180  Snapshot snapshot;
2181  TransactionId *serialized_xids;
2182 
2183  memcpy(&serialized_snapshot, start_address,
2184  sizeof(SerializedSnapshotData));
2185  serialized_xids = (TransactionId *)
2186  (start_address + sizeof(SerializedSnapshotData));
2187 
2188  /* We allocate any XID arrays needed in the same palloc block. */
2189  size = sizeof(SnapshotData)
2190  + serialized_snapshot.xcnt * sizeof(TransactionId)
2191  + serialized_snapshot.subxcnt * sizeof(TransactionId);
2192 
2193  /* Copy all required fields */
2195  snapshot->snapshot_type = SNAPSHOT_MVCC;
2196  snapshot->xmin = serialized_snapshot.xmin;
2197  snapshot->xmax = serialized_snapshot.xmax;
2198  snapshot->xip = NULL;
2199  snapshot->xcnt = serialized_snapshot.xcnt;
2200  snapshot->subxip = NULL;
2201  snapshot->subxcnt = serialized_snapshot.subxcnt;
2202  snapshot->suboverflowed = serialized_snapshot.suboverflowed;
2203  snapshot->takenDuringRecovery = serialized_snapshot.takenDuringRecovery;
2204  snapshot->curcid = serialized_snapshot.curcid;
2205  snapshot->whenTaken = serialized_snapshot.whenTaken;
2206  snapshot->lsn = serialized_snapshot.lsn;
2207  snapshot->snapXactCompletionCount = 0;
2208 
2209  /* Copy XIDs, if present. */
2210  if (serialized_snapshot.xcnt > 0)
2211  {
2212  snapshot->xip = (TransactionId *) (snapshot + 1);
2213  memcpy(snapshot->xip, serialized_xids,
2214  serialized_snapshot.xcnt * sizeof(TransactionId));
2215  }
2216 
2217  /* Copy SubXIDs, if present. */
2218  if (serialized_snapshot.subxcnt > 0)
2219  {
2220  snapshot->subxip = ((TransactionId *) (snapshot + 1)) +
2221  serialized_snapshot.xcnt;
2222  memcpy(snapshot->subxip, serialized_xids + serialized_snapshot.xcnt,
2223  serialized_snapshot.subxcnt * sizeof(TransactionId));
2224  }
2225 
2226  /* Set the copied flag so that the caller will set refcounts correctly. */
2227  snapshot->regd_count = 0;
2228  snapshot->active_count = 0;
2229  snapshot->copied = true;
2230 
2231  return snapshot;
2232 }
struct SnapshotData * Snapshot
Definition: snapshot.h:121
struct SnapshotData SnapshotData
TransactionId xmax
Definition: snapmgr.c:186
TimestampTz whenTaken
Definition: snapmgr.c:192
TransactionId xmin
Definition: snapmgr.c:185
CommandId curcid
Definition: snapshot.h:187
TimestampTz whenTaken
Definition: snapshot.h:208
uint64 snapXactCompletionCount
Definition: snapshot.h:216

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

2242 {
2243  SetTransactionSnapshot(snapshot, NULL, InvalidPid, source_pgproc);
2244 }
#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 2117 of file snapmgr.c.

2118 {
2119  SerializedSnapshotData serialized_snapshot;
2120 
2121  Assert(snapshot->subxcnt >= 0);
2122 
2123  /* Copy all required fields */
2124  serialized_snapshot.xmin = snapshot->xmin;
2125  serialized_snapshot.xmax = snapshot->xmax;
2126  serialized_snapshot.xcnt = snapshot->xcnt;
2127  serialized_snapshot.subxcnt = snapshot->subxcnt;
2128  serialized_snapshot.suboverflowed = snapshot->suboverflowed;
2129  serialized_snapshot.takenDuringRecovery = snapshot->takenDuringRecovery;
2130  serialized_snapshot.curcid = snapshot->curcid;
2131  serialized_snapshot.whenTaken = snapshot->whenTaken;
2132  serialized_snapshot.lsn = snapshot->lsn;
2133 
2134  /*
2135  * Ignore the SubXID array if it has overflowed, unless the snapshot was
2136  * taken during recovery - in that case, top-level XIDs are in subxip as
2137  * well, and we mustn't lose them.
2138  */
2139  if (serialized_snapshot.suboverflowed && !snapshot->takenDuringRecovery)
2140  serialized_snapshot.subxcnt = 0;
2141 
2142  /* Copy struct to possibly-unaligned buffer */
2143  memcpy(start_address,
2144  &serialized_snapshot, sizeof(SerializedSnapshotData));
2145 
2146  /* Copy XID array */
2147  if (snapshot->xcnt > 0)
2148  memcpy((TransactionId *) (start_address +
2149  sizeof(SerializedSnapshotData)),
2150  snapshot->xip, snapshot->xcnt * sizeof(TransactionId));
2151 
2152  /*
2153  * Copy SubXID array. Don't bother to copy it if it had overflowed,
2154  * though, because it's not used anywhere in that case. Except if it's a
2155  * snapshot taken during recovery; all the top-level XIDs are in subxip as
2156  * well in that case, so we mustn't lose them.
2157  */
2158  if (serialized_snapshot.subxcnt > 0)
2159  {
2160  Size subxipoff = sizeof(SerializedSnapshotData) +
2161  snapshot->xcnt * sizeof(TransactionId);
2162 
2163  memcpy((TransactionId *) (start_address + subxipoff),
2164  snapshot->subxip, snapshot->subxcnt * sizeof(TransactionId));
2165  }
2166 }
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().

◆ SetOldSnapshotThresholdTimestamp()

◆ SetupHistoricSnapshot()

void SetupHistoricSnapshot ( Snapshot  snapshot_now,
struct HTAB tuplecids 
)

Definition at line 2050 of file snapmgr.c.

2051 {
2052  Assert(historic_snapshot != NULL);
2053 
2054  /* setup the timetravel snapshot */
2055  HistoricSnapshot = historic_snapshot;
2056 
2057  /* setup (cmin, cmax) lookup hash */
2058  tuplecid_data = tuplecids;
2059 }

References Assert(), HistoricSnapshot, and tuplecid_data.

Referenced by ReorderBufferProcessTXN(), and ReorderBufferQueueMessage().

◆ SnapMgrInit()

void SnapMgrInit ( void  )

Definition at line 213 of file snapmgr.c.

214 {
215  bool found;
216 
217  /*
218  * Create or attach to the OldSnapshotControlData structure.
219  */
221  ShmemInitStruct("OldSnapshotControlData",
222  SnapMgrShmemSize(), &found);
223 
224  if (!found)
225  {
237  }
238 }
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
Size SnapMgrShmemSize(void)
Definition: snapmgr.c:197
#define SpinLockInit(lock)
Definition: spin.h:60

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

Referenced by CreateSharedMemoryAndSemaphores().

◆ SnapMgrShmemSize()

Size SnapMgrShmemSize ( void  )

Definition at line 197 of file snapmgr.c.

198 {
199  Size size;
200 
201  size = offsetof(OldSnapshotControlData, xid_by_minute);
202  if (old_snapshot_threshold > 0)
203  size = add_size(size, mul_size(sizeof(TransactionId),
205 
206  return size;
207 }
#define offsetof(type, field)
Definition: c.h:727

References add_size(), mul_size(), offsetof, old_snapshot_threshold, and OLD_SNAPSHOT_TIME_MAP_ENTRIES.

Referenced by CalculateShmemSize(), and SnapMgrInit().

◆ SnapshotSetCommandId()

void SnapshotSetCommandId ( CommandId  curcid)

Definition at line 490 of file snapmgr.c.

491 {
492  if (!FirstSnapshotSet)
493  return;
494 
495  if (CurrentSnapshot)
496  CurrentSnapshot->curcid = curcid;
497  if (SecondarySnapshot)
498  SecondarySnapshot->curcid = curcid;
499  /* Should we do the same with CatalogSnapshot? */
500 }

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

Referenced by CommandCounterIncrement().

◆ SnapshotTooOldMagicForTest()

void SnapshotTooOldMagicForTest ( void  )

◆ TeardownHistoricSnapshot()

void TeardownHistoricSnapshot ( bool  is_error)

Definition at line 2066 of file snapmgr.c.

2067 {
2068  HistoricSnapshot = NULL;
2069  tuplecid_data = NULL;
2070 }

References HistoricSnapshot, and tuplecid_data.

Referenced by ReorderBufferProcessTXN(), and ReorderBufferQueueMessage().

◆ ThereAreNoPriorRegisteredSnapshots()

bool ThereAreNoPriorRegisteredSnapshots ( void  )

Definition at line 1619 of file snapmgr.c.

1620 {
1623  return true;
1624 
1625  return false;
1626 }

References pairingheap_is_empty, pairingheap_is_singular, and RegisteredSnapshots.

Referenced by CopyFrom().

◆ TransactionIdLimitedForOldSnapshots()

bool TransactionIdLimitedForOldSnapshots ( TransactionId  recentXmin,
Relation  relation,
TransactionId limit_xid,
TimestampTz limit_ts 
)

Definition at line 1766 of file snapmgr.c.

1770 {
1771  TimestampTz ts;
1772  TransactionId xlimit = recentXmin;
1773  TransactionId latest_xmin;
1774  TimestampTz next_map_update_ts;
1775  TransactionId threshold_timestamp;
1776  TransactionId threshold_xid;
1777 
1778  Assert(TransactionIdIsNormal(recentXmin));
1780  Assert(limit_ts != NULL && limit_xid != NULL);
1781 
1782  /*
1783  * TestForOldSnapshot() assumes early pruning advances the page LSN, so we
1784  * can't prune early when skipping WAL.
1785  */
1786  if (!RelationAllowsEarlyPruning(relation) || !RelationNeedsWAL(relation))
1787  return false;
1788 
1790 
1792  latest_xmin = oldSnapshotControl->latest_xmin;
1793  next_map_update_ts = oldSnapshotControl->next_map_update;
1795 
1796  /*
1797  * Zero threshold always overrides to latest xmin, if valid. Without some
1798  * heuristic it will find its own snapshot too old on, for example, a
1799  * simple UPDATE -- which would make it useless for most testing, but
1800  * there is no principled way to ensure that it doesn't fail in this way.
1801  * Use a five-second delay to try to get useful testing behavior, but this
1802  * may need adjustment.
1803  */
1804  if (old_snapshot_threshold == 0)
1805  {
1806  if (TransactionIdPrecedes(latest_xmin, MyProc->xmin)
1807  && TransactionIdFollows(latest_xmin, xlimit))
1808  xlimit = latest_xmin;
1809 
1810  ts -= 5 * USECS_PER_SEC;
1811  }
1812  else
1813  {
1816 
1817  /* Check for fast exit without LW locking. */
1819  threshold_timestamp = oldSnapshotControl->threshold_timestamp;
1820  threshold_xid = oldSnapshotControl->threshold_xid;
1822 
1823  if (ts == threshold_timestamp)
1824  {
1825  /*
1826  * Current timestamp is in same bucket as the last limit that was
1827  * applied. Reuse.
1828  */
1829  xlimit = threshold_xid;
1830  }
1831  else if (ts == next_map_update_ts)
1832  {
1833  /*
1834  * FIXME: This branch is super iffy - but that should probably
1835  * fixed separately.
1836  */
1837  xlimit = latest_xmin;
1838  }
1839  else if (GetOldSnapshotFromTimeMapping(ts, &xlimit))
1840  {
1841  }
1842 
1843  /*
1844  * Failsafe protection against vacuuming work of active transaction.
1845  *
1846  * This is not an assertion because we avoid the spinlock for
1847  * performance, leaving open the possibility that xlimit could advance
1848  * and be more current; but it seems prudent to apply this limit. It
1849  * might make pruning a tiny bit less aggressive than it could be, but
1850  * protects against data loss bugs.
1851  */
1852  if (TransactionIdIsNormal(latest_xmin)
1853  && TransactionIdPrecedes(latest_xmin, xlimit))
1854  xlimit = latest_xmin;
1855  }
1856 
1857  if (TransactionIdIsValid(xlimit) &&
1858  TransactionIdFollowsOrEquals(xlimit, recentXmin))
1859  {
1860  *limit_ts = ts;
1861  *limit_xid = xlimit;
1862 
1863  return true;
1864  }
1865 
1866  return false;
1867 }
#define RelationNeedsWAL(relation)
Definition: rel.h:602
static bool GetOldSnapshotFromTimeMapping(TimestampTz ts, TransactionId *xlimitp)
Definition: snapmgr.c:1722
#define RelationAllowsEarlyPruning(rel)
Definition: snapmgr.h:38
static bool OldSnapshotThresholdActive(void)
Definition: snapmgr.h:101
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349

References AlignTimestampToMinuteBoundary(), Assert(), GetOldSnapshotFromTimeMapping(), GetSnapshotCurrentTimestamp(), OldSnapshotControlData::latest_xmin, OldSnapshotControlData::mutex_latest_xmin, OldSnapshotControlData::mutex_threshold, MyProc, OldSnapshotControlData::next_map_update, old_snapshot_threshold, oldSnapshotControl, OldSnapshotThresholdActive(), RelationAllowsEarlyPruning, RelationNeedsWAL, SpinLockAcquire, SpinLockRelease, OldSnapshotControlData::threshold_timestamp, OldSnapshotControlData::threshold_xid, TransactionIdFollows(), TransactionIdFollowsOrEquals(), TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), USECS_PER_MINUTE, USECS_PER_SEC, and PGPROC::xmin.

Referenced by heap_page_prune_opt(), heap_prune_satisfies_vacuum(), and vacuum_set_xid_limits().

◆ UnregisterSnapshot()

◆ UnregisterSnapshotFromOwner()

void UnregisterSnapshotFromOwner ( Snapshot  snapshot,
ResourceOwner  owner 
)

Definition at line 880 of file snapmgr.c.

881 {
882  if (snapshot == NULL)
883  return;
884 
885  Assert(snapshot->regd_count > 0);
887 
888  ResourceOwnerForgetSnapshot(owner, snapshot);
889 
890  snapshot->regd_count--;
891  if (snapshot->regd_count == 0)
893 
894  if (snapshot->regd_count == 0 && snapshot->active_count == 0)
895  {
896  FreeSnapshot(snapshot);
898  }
899 }
void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1260

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

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

◆ UpdateActiveSnapshotCommandId()

void UpdateActiveSnapshotCommandId ( void  )

Definition at line 743 of file snapmgr.c.

744 {
745  CommandId save_curcid,
746  curcid;
747 
748  Assert(ActiveSnapshot != NULL);
751 
752  /*
753  * Don't allow modification of the active snapshot during parallel
754  * operation. We share the snapshot to worker backends at the beginning
755  * of parallel operation, so any change to the snapshot can lead to
756  * inconsistencies. We have other defenses against
757  * CommandCounterIncrement, but there are a few places that call this
758  * directly, so we put an additional guard here.
759  */
760  save_curcid = ActiveSnapshot->as_snap->curcid;
761  curcid = GetCurrentCommandId(false);
762  if (IsInParallelMode() && save_curcid != curcid)
763  elog(ERROR, "cannot modify commandid in active snapshot during a parallel operation");
764  ActiveSnapshot->as_snap->curcid = curcid;
765 }
uint32 CommandId
Definition: c.h:601
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:813

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

◆ WaitForOlderSnapshots()

void WaitForOlderSnapshots ( TransactionId  limitXmin,
bool  progress 
)

Definition at line 414 of file indexcmds.c.

415 {
416  int n_old_snapshots;
417  int i;
418  VirtualTransactionId *old_snapshots;
419 
420  old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
422  | PROC_IN_SAFE_IC,
423  &n_old_snapshots);
424  if (progress)
426 
427  for (i = 0; i < n_old_snapshots; i++)
428  {
429  if (!VirtualTransactionIdIsValid(old_snapshots[i]))
430  continue; /* found uninteresting in previous cycle */
431 
432  if (i > 0)
433  {
434  /* see if anything's changed ... */
435  VirtualTransactionId *newer_snapshots;
436  int n_newer_snapshots;
437  int j;
438  int k;
439 
440  newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
441  true, false,
443  | PROC_IN_SAFE_IC,
444  &n_newer_snapshots);
445  for (j = i; j < n_old_snapshots; j++)
446  {
447  if (!VirtualTransactionIdIsValid(old_snapshots[j]))
448  continue; /* found uninteresting in previous cycle */
449  for (k = 0; k < n_newer_snapshots; k++)
450  {
451  if (VirtualTransactionIdEquals(old_snapshots[j],
452  newer_snapshots[k]))
453  break;
454  }
455  if (k >= n_newer_snapshots) /* not there anymore */
456  SetInvalidVirtualTransactionId(old_snapshots[j]);
457  }
458  pfree(newer_snapshots);
459  }
460 
461  if (VirtualTransactionIdIsValid(old_snapshots[i]))
462  {
463  /* If requested, publish who we're going to wait for. */
464  if (progress)
465  {
466  PGPROC *holder = BackendIdGetProc(old_snapshots[i].backendId);
467 
468  if (holder)
470  holder->pid);
471  }
472  VirtualXactLock(old_snapshots[i], true);
473  }
474 
475  if (progress)
477  }
478 }
void pgstat_progress_update_param(int index, int64 val)
int j
Definition: isn.c:74
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition: lock.c:4599
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:76
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:79
int progress
Definition: pgbench.c:272
#define PROC_IN_SAFE_IC
Definition: proc.h:56
#define PROC_IN_VACUUM
Definition: proc.h:55
#define PROC_IS_AUTOVACUUM
Definition: proc.h:54
VirtualTransactionId * GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
Definition: procarray.c:3274
#define PROGRESS_WAITFOR_DONE
Definition: progress.h:115
#define PROGRESS_WAITFOR_TOTAL
Definition: progress.h:114
#define PROGRESS_WAITFOR_CURRENT_PID
Definition: progress.h:116
PGPROC * BackendIdGetProc(int backendID)
Definition: sinvaladt.c:376
Definition: proc.h:125
int pid
Definition: proc.h:149

References BackendIdGetProc(), GetCurrentVirtualXIDs(), i, j, pfree(), pgstat_progress_update_param(), PGPROC::pid, PROC_IN_SAFE_IC, PROC_IN_VACUUM, PROC_IS_AUTOVACUUM, progress, PROGRESS_WAITFOR_CURRENT_PID, PROGRESS_WAITFOR_DONE, PROGRESS_WAITFOR_TOTAL, SetInvalidVirtualTransactionId, VirtualTransactionIdEquals, VirtualTransactionIdIsValid, and VirtualXactLock().

Referenced by ATExecDetachPartitionFinalize(), DefineIndex(), and ReindexRelationConcurrently().

◆ XactHasExportedSnapshots()

bool XactHasExportedSnapshots ( void  )

Definition at line 1567 of file snapmgr.c.

1568 {
1569  return (exportedSnapshots != NIL);
1570 }

References exportedSnapshots, and NIL.

Referenced by PrepareTransaction().

◆ XidInMVCCSnapshot()

bool XidInMVCCSnapshot ( TransactionId  xid,
Snapshot  snapshot 
)

Definition at line 2257 of file snapmgr.c.

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

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

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

Variable Documentation

◆ CatalogSnapshotData

PGDLLIMPORT SnapshotData CatalogSnapshotData
extern

Definition at line 97 of file snapmgr.c.

Referenced by GetNonHistoricCatalogSnapshot().

◆ FirstSnapshotSet

◆ old_snapshot_threshold

◆ RecentXmin

◆ SnapshotAnyData

PGDLLIMPORT SnapshotData SnapshotAnyData
extern

Definition at line 99 of file snapmgr.c.

◆ SnapshotSelfData

PGDLLIMPORT SnapshotData SnapshotSelfData
extern

Definition at line 98 of file snapmgr.c.

◆ TransactionXmin