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 HaveRegisteredOrActiveSnapshot (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 historic_snapshot, 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
 
PGDLLIMPORT 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:105
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:682

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 149 of file snapmgr.h.

Function Documentation

◆ ActiveSnapshotSet()

◆ AtEOXact_Snapshot()

void AtEOXact_Snapshot ( bool  isCommit,
bool  resetXmin 
)

Definition at line 1025 of file snapmgr.c.

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

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

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

◆ AtSubAbort_Snapshot()

void AtSubAbort_Snapshot ( int  level)

Definition at line 989 of file snapmgr.c.

990 {
991  /* Forget the active snapshots set by this subtransaction */
992  while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
993  {
995 
997 
998  /*
999  * Decrement the snapshot's active count. If it's still registered or
1000  * marked as active by an outer subtransaction, we can't free it yet.
1001  */
1004 
1005  if (ActiveSnapshot->as_snap->active_count == 0 &&
1008 
1009  /* and free the stack element */
1011 
1012  ActiveSnapshot = next;
1013  if (ActiveSnapshot == NULL)
1014  OldestActiveSnapshot = NULL;
1015  }
1016 
1018 }
static int32 next
Definition: blutils.c:219
void pfree(void *pointer)
Definition: mcxt.c:1306
static void FreeSnapshot(Snapshot snapshot)
Definition: snapmgr.c:665
Snapshot as_snap
Definition: snapmgr.c:129
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 968 of file snapmgr.c.

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

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

Referenced by CommitSubTransaction().

◆ DeleteAllExportedSnapshotFiles()

void DeleteAllExportedSnapshotFiles ( void  )

Definition at line 1584 of file snapmgr.c.

1585 {
1586  char buf[MAXPGPATH + sizeof(SNAPSHOT_EXPORT_DIR)];
1587  DIR *s_dir;
1588  struct dirent *s_de;
1589 
1590  /*
1591  * Problems in reading the directory, or unlinking files, are reported at
1592  * LOG level. Since we're running in the startup process, ERROR level
1593  * would prevent database start, and it's not important enough for that.
1594  */
1596 
1597  while ((s_de = ReadDirExtended(s_dir, SNAPSHOT_EXPORT_DIR, LOG)) != NULL)
1598  {
1599  if (strcmp(s_de->d_name, ".") == 0 ||
1600  strcmp(s_de->d_name, "..") == 0)
1601  continue;
1602 
1603  snprintf(buf, sizeof(buf), SNAPSHOT_EXPORT_DIR "/%s", s_de->d_name);
1604 
1605  if (unlink(buf) != 0)
1606  ereport(LOG,
1608  errmsg("could not remove file \"%s\": %m", buf)));
1609  }
1610 
1611  FreeDir(s_dir);
1612 }
int errcode_for_file_access(void)
Definition: elog.c:718
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define LOG
Definition: elog.h:27
#define ereport(elevel,...)
Definition: elog.h:145
int FreeDir(DIR *dir)
Definition: fd.c:2761
struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel)
Definition: fd.c:2724
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2643
#define MAXPGPATH
static char * buf
Definition: pg_test_fsync.c:67
#define snprintf
Definition: port.h:238
#define SNAPSHOT_EXPORT_DIR
Definition: snapmgr.c:160
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 2123 of file snapmgr.c.

2124 {
2125  Size size;
2126 
2127  Assert(snapshot != InvalidSnapshot);
2128  Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
2129 
2130  /* We allocate any XID arrays needed in the same palloc block. */
2131  size = add_size(sizeof(SerializedSnapshotData),
2132  mul_size(snapshot->xcnt, sizeof(TransactionId)));
2133  if (snapshot->subxcnt > 0 &&
2134  (!snapshot->suboverflowed || snapshot->takenDuringRecovery))
2135  size = add_size(size,
2136  mul_size(snapshot->subxcnt, sizeof(TransactionId)));
2137 
2138  return size;
2139 }
uint32 TransactionId
Definition: c.h:588
size_t Size
Definition: c.h:541
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
int32 subxcnt
Definition: snapshot.h:181
uint32 xcnt
Definition: snapshot.h:169
SnapshotType snapshot_type
Definition: snapshot.h:144
bool suboverflowed
Definition: snapshot.h:182
bool takenDuringRecovery
Definition: snapshot.h:184

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

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

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

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

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

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

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

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

◆ GetNonHistoricCatalogSnapshot()

Snapshot GetNonHistoricCatalogSnapshot ( Oid  relid)

Definition at line 409 of file snapmgr.c.

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

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

359 {
360  Snapshot OldestRegisteredSnapshot = NULL;
361  XLogRecPtr RegisteredLSN = InvalidXLogRecPtr;
362 
364  {
365  OldestRegisteredSnapshot = pairingheap_container(SnapshotData, ph_node,
367  RegisteredLSN = OldestRegisteredSnapshot->lsn;
368  }
369 
370  if (OldestActiveSnapshot != NULL)
371  {
373 
374  if (XLogRecPtrIsInvalid(RegisteredLSN) || RegisteredLSN > ActiveLSN)
376  }
377 
378  return OldestRegisteredSnapshot;
379 }
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 1705 of file snapmgr.c.

1706 {
1707  TimestampTz threshold_timestamp;
1708 
1710  threshold_timestamp = oldSnapshotControl->threshold_timestamp;
1712 
1713  return threshold_timestamp;
1714 }
int64 TimestampTz
Definition: timestamp.h:39
volatile OldSnapshotControlData * oldSnapshotControl
Definition: snapmgr.c:81
#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 1680 of file snapmgr.c.

1681 {
1683 
1684  /*
1685  * Don't let time move backward; if it hasn't advanced, use the old value.
1686  */
1688  if (now <= oldSnapshotControl->current_timestamp)
1690  else
1693 
1694  return now;
1695 }
Datum current_timestamp(PG_FUNCTION_ARGS)
Definition: timestamp.c:1591
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1573
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1537
TimestampTz current_timestamp
Definition: old_snapshot.h:31

References current_timestamp(), 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 251 of file snapmgr.c.

252 {
253  /*
254  * Return historic snapshot if doing logical decoding. We'll never need a
255  * non-historic transaction snapshot in this (sub-)transaction, so there's
256  * no need to be careful to set one up for later calls to
257  * GetTransactionSnapshot().
258  */
260  {
262  return HistoricSnapshot;
263  }
264 
265  /* First call in transaction? */
266  if (!FirstSnapshotSet)
267  {
268  /*
269  * Don't allow catalog snapshot to be older than xact snapshot. Must
270  * do this first to allow the empty-heap Assert to succeed.
271  */
273 
275  Assert(FirstXactSnapshot == NULL);
276 
277  if (IsInParallelMode())
278  elog(ERROR,
279  "cannot take query snapshot during a parallel operation");
280 
281  /*
282  * In transaction-snapshot mode, the first snapshot must live until
283  * end of xact regardless of what the caller does with it, so we must
284  * make a copy of it rather than returning CurrentSnapshotData
285  * directly. Furthermore, if we're running in serializable mode,
286  * predicate.c needs to wrap the snapshot fetch in its own processing.
287  */
289  {
290  /* First, create the snapshot in CurrentSnapshotData */
293  else
295  /* Make a saved copy */
298  /* Mark it as "registered" in FirstXactSnapshot */
301  }
302  else
304 
305  FirstSnapshotSet = true;
306  return CurrentSnapshot;
307  }
308 
310  return CurrentSnapshot;
311 
312  /* Don't allow catalog snapshot to be older than xact snapshot. */
314 
316 
317  return CurrentSnapshot;
318 }
Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot)
Definition: predicate.c:1681
static SnapshotData CurrentSnapshotData
Definition: snapmgr.c:96
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
#define IsolationIsSerializable()
Definition: xact.h:52

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

Referenced by _bt_begin_parallel(), _SPI_execute_plan(), AfterTriggerFireDeferred(), AfterTriggerSetState(), begin_replication_step(), bt_check_every_level(), BuildCachedPlan(), CheckTargetForConflictsIn(), cluster_multiple_rels(), DefineIndex(), EnsurePortalSnapshotExists(), 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(), RemoveTempRelationsCallback(), RevalidateCachedQuery(), ri_PerformCheck(), SPI_cursor_open_internal(), vacuum(), vacuum_rel(), verify_heapam(), and XidIsConcurrent().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4275 of file procarray.c.

4276 {
4278 
4279  state = GlobalVisTestFor(rel);
4280 
4281  return GlobalVisTestIsRemovableFullXid(state, fxid);
4282 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4181
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4066
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 4289 of file procarray.c.

4290 {
4292 
4293  state = GlobalVisTestFor(rel);
4294 
4295  return GlobalVisTestIsRemovableXid(state, xid);
4296 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4223

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisTestFor()

GlobalVisState* GlobalVisTestFor ( Relation  rel)

Definition at line 4066 of file procarray.c.

4067 {
4068  GlobalVisState *state = NULL;
4069 
4070  /* XXX: we should assert that a snapshot is pushed or registered */
4071  Assert(RecentXmin);
4072 
4073  switch (GlobalVisHorizonKindForRel(rel))
4074  {
4075  case VISHORIZON_SHARED:
4077  break;
4078  case VISHORIZON_CATALOG:
4080  break;
4081  case VISHORIZON_DATA:
4083  break;
4084  case VISHORIZON_TEMP:
4086  break;
4087  }
4088 
4089  Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4090  FullTransactionIdIsValid(state->maybe_needed));
4091 
4092  return state;
4093 }
static GlobalVisState GlobalVisDataRels
Definition: procarray.c:302
static GlobalVisState GlobalVisSharedRels
Definition: procarray.c:300
static GlobalVisState GlobalVisCatalogRels
Definition: procarray.c:301
static GlobalVisState GlobalVisTempRels
Definition: procarray.c:303
@ 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:1979
TransactionId RecentXmin
Definition: snapmgr.c:114
#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(), heap_vacuum_rel(), and vacuumRedirectAndPlaceholder().

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4181 of file procarray.c.

4183 {
4184  /*
4185  * If fxid is older than maybe_needed bound, it definitely is visible to
4186  * everyone.
4187  */
4188  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4189  return true;
4190 
4191  /*
4192  * If fxid is >= definitely_needed bound, it is very likely to still be
4193  * considered running.
4194  */
4195  if (FullTransactionIdFollowsOrEquals(fxid, state->definitely_needed))
4196  return false;
4197 
4198  /*
4199  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4200  * might not exist a snapshot considering fxid running. If it makes sense,
4201  * update boundaries and recheck.
4202  */
4204  {
4205  GlobalVisUpdate();
4206 
4207  Assert(FullTransactionIdPrecedes(fxid, state->definitely_needed));
4208 
4209  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4210  }
4211  else
4212  return false;
4213 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4106
static void GlobalVisUpdate(void)
Definition: procarray.c:4164
#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 4223 of file procarray.c.

4224 {
4225  FullTransactionId fxid;
4226 
4227  /*
4228  * Convert 32 bit argument to FullTransactionId. We can do so safely
4229  * because we know the xid has to, at the very least, be between
4230  * [oldestXid, nextXid), i.e. within 2 billion of xid. To avoid taking a
4231  * lock to determine either, we can just compare with
4232  * state->definitely_needed, which was based on those value at the time
4233  * the current snapshot was built.
4234  */
4235  fxid = FullXidRelativeTo(state->definitely_needed, xid);
4236 
4237  return GlobalVisTestIsRemovableFullXid(state, fxid);
4238 }
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4310

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 4250 of file procarray.c.

4251 {
4252  /* acquire accurate horizon if not already done */
4254  GlobalVisUpdate();
4255 
4256  return state->maybe_needed;
4257 }

References GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisTestNonRemovableHorizon().

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4261 of file procarray.c.

4262 {
4263  FullTransactionId cutoff;
4264 
4266 
4267  return XidFromFullTransactionId(cutoff);
4268 }
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4250
#define XidFromFullTransactionId(x)
Definition: transam.h:48

References GlobalVisTestNonRemovableFullHorizon(), and XidFromFullTransactionId.

Referenced by heap_page_prune_opt(), and heap_prune_satisfies_vacuum().

◆ HaveRegisteredOrActiveSnapshot()

bool HaveRegisteredOrActiveSnapshot ( void  )

Definition at line 1641 of file snapmgr.c.

1642 {
1643  if (ActiveSnapshot != NULL)
1644  return true;
1645 
1646  /*
1647  * The catalog snapshot is in RegisteredSnapshots when valid, but can be
1648  * removed at any time due to invalidation processing. If explicitly
1649  * registered more than one snapshot has to be in RegisteredSnapshots.
1650  */
1651  if (CatalogSnapshot != NULL &&
1653  return false;
1654 
1656 }
#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()

struct HTAB* HistoricSnapshotGetTupleCids ( void  )

Definition at line 2109 of file snapmgr.c.

2110 {
2112  return tuplecid_data;
2113 }
static HTAB * tuplecid_data
Definition: snapmgr.c:117

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

Referenced by HeapTupleSatisfiesHistoricMVCC().

◆ ImportSnapshot()

void ImportSnapshot ( const char *  idstr)

Definition at line 1396 of file snapmgr.c.

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

◆ MaintainOldSnapshotTimeMapping()

void MaintainOldSnapshotTimeMapping ( TimestampTz  whenTaken,
TransactionId  xmin 
)

Definition at line 1903 of file snapmgr.c.

1904 {
1905  TimestampTz ts;
1906  TransactionId latest_xmin;
1907  TimestampTz update_ts;
1908  bool map_update_required = false;
1909 
1910  /* Never call this function when old snapshot checking is disabled. */
1912 
1913  ts = AlignTimestampToMinuteBoundary(whenTaken);
1914 
1915  /*
1916  * Keep track of the latest xmin seen by any process. Update mapping with
1917  * a new value when we have crossed a bucket boundary.
1918  */
1920  latest_xmin = oldSnapshotControl->latest_xmin;
1921  update_ts = oldSnapshotControl->next_map_update;
1922  if (ts > update_ts)
1923  {
1925  map_update_required = true;
1926  }
1927  if (TransactionIdFollows(xmin, latest_xmin))
1930 
1931  /* We only needed to update the most recent xmin value. */
1932  if (!map_update_required)
1933  return;
1934 
1935  /* No further tracking needed for 0 (used for testing). */
1936  if (old_snapshot_threshold == 0)
1937  return;
1938 
1939  /*
1940  * We don't want to do something stupid with unusual values, but we don't
1941  * want to litter the log with warnings or break otherwise normal
1942  * processing for this feature; so if something seems unreasonable, just
1943  * log at DEBUG level and return without doing anything.
1944  */
1945  if (whenTaken < 0)
1946  {
1947  elog(DEBUG1,
1948  "MaintainOldSnapshotTimeMapping called with negative whenTaken = %ld",
1949  (long) whenTaken);
1950  return;
1951  }
1952  if (!TransactionIdIsNormal(xmin))
1953  {
1954  elog(DEBUG1,
1955  "MaintainOldSnapshotTimeMapping called with xmin = %lu",
1956  (unsigned long) xmin);
1957  return;
1958  }
1959 
1960  LWLockAcquire(OldSnapshotTimeMapLock, LW_EXCLUSIVE);
1961 
1967 
1968  if (oldSnapshotControl->count_used == 0)
1969  {
1970  /* set up first entry for empty mapping */
1974  oldSnapshotControl->xid_by_minute[0] = xmin;
1975  }
1976  else if (ts < oldSnapshotControl->head_timestamp)
1977  {
1978  /* old ts; log it at DEBUG */
1979  LWLockRelease(OldSnapshotTimeMapLock);
1980  elog(DEBUG1,
1981  "MaintainOldSnapshotTimeMapping called with old whenTaken = %ld",
1982  (long) whenTaken);
1983  return;
1984  }
1985  else if (ts <= (oldSnapshotControl->head_timestamp +
1987  * USECS_PER_MINUTE)))
1988  {
1989  /* existing mapping; advance xid if possible */
1990  int bucket = (oldSnapshotControl->head_offset
1992  / USECS_PER_MINUTE))
1994 
1996  oldSnapshotControl->xid_by_minute[bucket] = xmin;
1997  }
1998  else
1999  {
2000  /* We need a new bucket, but it might not be the very next one. */
2001  int distance_to_new_tail;
2002  int distance_to_current_tail;
2003  int advance;
2004 
2005  /*
2006  * Our goal is for the new "tail" of the mapping, that is, the entry
2007  * which is newest and thus furthest from the "head" entry, to
2008  * correspond to "ts". Since there's one entry per minute, the
2009  * distance between the current head and the new tail is just the
2010  * number of minutes of difference between ts and the current
2011  * head_timestamp.
2012  *
2013  * The distance from the current head to the current tail is one less
2014  * than the number of entries in the mapping, because the entry at the
2015  * head_offset is for 0 minutes after head_timestamp.
2016  *
2017  * The difference between these two values is the number of minutes by
2018  * which we need to advance the mapping, either adding new entries or
2019  * rotating old ones out.
2020  */
2021  distance_to_new_tail =
2023  distance_to_current_tail =
2025  advance = distance_to_new_tail - distance_to_current_tail;
2026  Assert(advance > 0);
2027 
2028  if (advance >= OLD_SNAPSHOT_TIME_MAP_ENTRIES)
2029  {
2030  /* Advance is so far that all old data is junk; start over. */
2033  oldSnapshotControl->xid_by_minute[0] = xmin;
2035  }
2036  else
2037  {
2038  /* Store the new value in one or more buckets. */
2039  int i;
2040 
2041  for (i = 0; i < advance; i++)
2042  {
2044  {
2045  /* Map full and new value replaces old head. */
2046  int old_head = oldSnapshotControl->head_offset;
2047 
2048  if (old_head == (OLD_SNAPSHOT_TIME_MAP_ENTRIES - 1))
2050  else
2051  oldSnapshotControl->head_offset = old_head + 1;
2052  oldSnapshotControl->xid_by_minute[old_head] = xmin;
2054  }
2055  else
2056  {
2057  /* Extend map to unused entry. */
2058  int new_tail = (oldSnapshotControl->head_offset
2061 
2063  oldSnapshotControl->xid_by_minute[new_tail] = xmin;
2064  }
2065  }
2066  }
2067  }
2068 
2069  LWLockRelease(OldSnapshotTimeMapLock);
2070 }
#define USECS_PER_MINUTE
Definition: timestamp.h:132
#define DEBUG1
Definition: elog.h:26
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1194
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1802
@ LW_EXCLUSIVE
Definition: lwlock.h:112
static TimestampTz AlignTimestampToMinuteBoundary(TimestampTz ts)
Definition: snapmgr.c:1666
int old_snapshot_threshold
Definition: snapmgr.c:79
#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:307

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 102 of file snapmgr.h.

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

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

779 {
780  ActiveSnapshotElt *newstack;
781 
782  newstack = ActiveSnapshot->as_next;
783 
785 
787 
788  if (ActiveSnapshot->as_snap->active_count == 0 &&
791 
793  ActiveSnapshot = newstack;
794  if (ActiveSnapshot == NULL)
795  OldestActiveSnapshot = NULL;
796 
798 }

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(), 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(), RemoveTempRelationsCallback(), RevalidateCachedQuery(), ShutdownSQLFunction(), vacuum(), and vacuum_rel().

◆ PushActiveSnapshot()

◆ PushActiveSnapshotWithLevel()

void PushActiveSnapshotWithLevel ( Snapshot  snapshot,
int  snap_level 
)

Definition at line 697 of file snapmgr.c.

698 {
699  ActiveSnapshotElt *newactive;
700 
701  Assert(snapshot != InvalidSnapshot);
702  Assert(ActiveSnapshot == NULL || snap_level >= ActiveSnapshot->as_level);
703 
705 
706  /*
707  * Checking SecondarySnapshot is probably useless here, but it seems
708  * better to be sure.
709  */
710  if (snapshot == CurrentSnapshot || snapshot == SecondarySnapshot ||
711  !snapshot->copied)
712  newactive->as_snap = CopySnapshot(snapshot);
713  else
714  newactive->as_snap = snapshot;
715 
716  newactive->as_next = ActiveSnapshot;
717  newactive->as_level = snap_level;
718 
719  newactive->as_snap->active_count++;
720 
721  ActiveSnapshot = newactive;
722  if (OldestActiveSnapshot == NULL)
724 }
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:994
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 735 of file snapmgr.c.

736 {
737  PushActiveSnapshot(CopySnapshot(snapshot));
738 }
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:683

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

843 {
844  Snapshot snap;
845 
846  if (snapshot == InvalidSnapshot)
847  return InvalidSnapshot;
848 
849  /* Static snapshot? Create a persistent copy */
850  snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
851 
852  /* and tell resowner.c about it */
854  snap->regd_count++;
855  ResourceOwnerRememberSnapshot(owner, snap);
856 
857  if (snap->regd_count == 1)
859 
860  return snap;
861 }
void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1255
void ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
Definition: resowner.c:1244

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

2207 {
2208  SerializedSnapshotData serialized_snapshot;
2209  Size size;
2210  Snapshot snapshot;
2211  TransactionId *serialized_xids;
2212 
2213  memcpy(&serialized_snapshot, start_address,
2214  sizeof(SerializedSnapshotData));
2215  serialized_xids = (TransactionId *)
2216  (start_address + sizeof(SerializedSnapshotData));
2217 
2218  /* We allocate any XID arrays needed in the same palloc block. */
2219  size = sizeof(SnapshotData)
2220  + serialized_snapshot.xcnt * sizeof(TransactionId)
2221  + serialized_snapshot.subxcnt * sizeof(TransactionId);
2222 
2223  /* Copy all required fields */
2225  snapshot->snapshot_type = SNAPSHOT_MVCC;
2226  snapshot->xmin = serialized_snapshot.xmin;
2227  snapshot->xmax = serialized_snapshot.xmax;
2228  snapshot->xip = NULL;
2229  snapshot->xcnt = serialized_snapshot.xcnt;
2230  snapshot->subxip = NULL;
2231  snapshot->subxcnt = serialized_snapshot.subxcnt;
2232  snapshot->suboverflowed = serialized_snapshot.suboverflowed;
2233  snapshot->takenDuringRecovery = serialized_snapshot.takenDuringRecovery;
2234  snapshot->curcid = serialized_snapshot.curcid;
2235  snapshot->whenTaken = serialized_snapshot.whenTaken;
2236  snapshot->lsn = serialized_snapshot.lsn;
2237  snapshot->snapXactCompletionCount = 0;
2238 
2239  /* Copy XIDs, if present. */
2240  if (serialized_snapshot.xcnt > 0)
2241  {
2242  snapshot->xip = (TransactionId *) (snapshot + 1);
2243  memcpy(snapshot->xip, serialized_xids,
2244  serialized_snapshot.xcnt * sizeof(TransactionId));
2245  }
2246 
2247  /* Copy SubXIDs, if present. */
2248  if (serialized_snapshot.subxcnt > 0)
2249  {
2250  snapshot->subxip = ((TransactionId *) (snapshot + 1)) +
2251  serialized_snapshot.xcnt;
2252  memcpy(snapshot->subxip, serialized_xids + serialized_snapshot.xcnt,
2253  serialized_snapshot.subxcnt * sizeof(TransactionId));
2254  }
2255 
2256  /* Set the copied flag so that the caller will set refcounts correctly. */
2257  snapshot->regd_count = 0;
2258  snapshot->active_count = 0;
2259  snapshot->copied = true;
2260 
2261  return snapshot;
2262 }
struct SnapshotData * Snapshot
Definition: snapshot.h:121
struct SnapshotData SnapshotData
TransactionId xmax
Definition: snapmgr.c:187
TimestampTz whenTaken
Definition: snapmgr.c:193
TransactionId xmin
Definition: snapmgr.c:186
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 2271 of file snapmgr.c.

2272 {
2273  SetTransactionSnapshot(snapshot, NULL, InvalidPid, source_pgproc);
2274 }
#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 2147 of file snapmgr.c.

2148 {
2149  SerializedSnapshotData serialized_snapshot;
2150 
2151  Assert(snapshot->subxcnt >= 0);
2152 
2153  /* Copy all required fields */
2154  serialized_snapshot.xmin = snapshot->xmin;
2155  serialized_snapshot.xmax = snapshot->xmax;
2156  serialized_snapshot.xcnt = snapshot->xcnt;
2157  serialized_snapshot.subxcnt = snapshot->subxcnt;
2158  serialized_snapshot.suboverflowed = snapshot->suboverflowed;
2159  serialized_snapshot.takenDuringRecovery = snapshot->takenDuringRecovery;
2160  serialized_snapshot.curcid = snapshot->curcid;
2161  serialized_snapshot.whenTaken = snapshot->whenTaken;
2162  serialized_snapshot.lsn = snapshot->lsn;
2163 
2164  /*
2165  * Ignore the SubXID array if it has overflowed, unless the snapshot was
2166  * taken during recovery - in that case, top-level XIDs are in subxip as
2167  * well, and we mustn't lose them.
2168  */
2169  if (serialized_snapshot.suboverflowed && !snapshot->takenDuringRecovery)
2170  serialized_snapshot.subxcnt = 0;
2171 
2172  /* Copy struct to possibly-unaligned buffer */
2173  memcpy(start_address,
2174  &serialized_snapshot, sizeof(SerializedSnapshotData));
2175 
2176  /* Copy XID array */
2177  if (snapshot->xcnt > 0)
2178  memcpy((TransactionId *) (start_address +
2179  sizeof(SerializedSnapshotData)),
2180  snapshot->xip, snapshot->xcnt * sizeof(TransactionId));
2181 
2182  /*
2183  * Copy SubXID array. Don't bother to copy it if it had overflowed,
2184  * though, because it's not used anywhere in that case. Except if it's a
2185  * snapshot taken during recovery; all the top-level XIDs are in subxip as
2186  * well in that case, so we mustn't lose them.
2187  */
2188  if (serialized_snapshot.subxcnt > 0)
2189  {
2190  Size subxipoff = sizeof(SerializedSnapshotData) +
2191  snapshot->xcnt * sizeof(TransactionId);
2192 
2193  memcpy((TransactionId *) (start_address + subxipoff),
2194  snapshot->subxip, snapshot->subxcnt * sizeof(TransactionId));
2195  }
2196 }
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  historic_snapshot,
struct HTAB tuplecids 
)

Definition at line 2080 of file snapmgr.c.

2081 {
2082  Assert(historic_snapshot != NULL);
2083 
2084  /* setup the timetravel snapshot */
2085  HistoricSnapshot = historic_snapshot;
2086 
2087  /* setup (cmin, cmax) lookup hash */
2088  tuplecid_data = tuplecids;
2089 }

References Assert(), HistoricSnapshot, and tuplecid_data.

Referenced by ReorderBufferProcessTXN(), and ReorderBufferQueueMessage().

◆ SnapMgrInit()

void SnapMgrInit ( void  )

Definition at line 214 of file snapmgr.c.

215 {
216  bool found;
217 
218  /*
219  * Create or attach to the OldSnapshotControlData structure.
220  */
222  ShmemInitStruct("OldSnapshotControlData",
223  SnapMgrShmemSize(), &found);
224 
225  if (!found)
226  {
238  }
239 }
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
Size SnapMgrShmemSize(void)
Definition: snapmgr.c:198
#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 198 of file snapmgr.c.

199 {
200  Size size;
201 
202  size = offsetof(OldSnapshotControlData, xid_by_minute);
203  if (old_snapshot_threshold > 0)
204  size = add_size(size, mul_size(sizeof(TransactionId),
206 
207  return size;
208 }

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

Referenced by CalculateShmemSize(), and SnapMgrInit().

◆ SnapshotSetCommandId()

void SnapshotSetCommandId ( CommandId  curcid)

Definition at line 491 of file snapmgr.c.

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

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

Referenced by CommandCounterIncrement().

◆ SnapshotTooOldMagicForTest()

void SnapshotTooOldMagicForTest ( void  )

◆ TeardownHistoricSnapshot()

void TeardownHistoricSnapshot ( bool  is_error)

Definition at line 2096 of file snapmgr.c.

2097 {
2098  HistoricSnapshot = NULL;
2099  tuplecid_data = NULL;
2100 }

References HistoricSnapshot, and tuplecid_data.

Referenced by ReorderBufferProcessTXN(), and ReorderBufferQueueMessage().

◆ ThereAreNoPriorRegisteredSnapshots()

bool ThereAreNoPriorRegisteredSnapshots ( void  )

Definition at line 1623 of file snapmgr.c.

1624 {
1627  return true;
1628 
1629  return false;
1630 }

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

1800 {
1801  TimestampTz ts;
1802  TransactionId xlimit = recentXmin;
1803  TransactionId latest_xmin;
1804  TimestampTz next_map_update_ts;
1805  TransactionId threshold_timestamp;
1806  TransactionId threshold_xid;
1807 
1808  Assert(TransactionIdIsNormal(recentXmin));
1810  Assert(limit_ts != NULL && limit_xid != NULL);
1811 
1812  /*
1813  * TestForOldSnapshot() assumes early pruning advances the page LSN, so we
1814  * can't prune early when skipping WAL.
1815  */
1816  if (!RelationAllowsEarlyPruning(relation) || !RelationNeedsWAL(relation))
1817  return false;
1818 
1820 
1822  latest_xmin = oldSnapshotControl->latest_xmin;
1823  next_map_update_ts = oldSnapshotControl->next_map_update;
1825 
1826  /*
1827  * Zero threshold always overrides to latest xmin, if valid. Without some
1828  * heuristic it will find its own snapshot too old on, for example, a
1829  * simple UPDATE -- which would make it useless for most testing, but
1830  * there is no principled way to ensure that it doesn't fail in this way.
1831  * Use a five-second delay to try to get useful testing behavior, but this
1832  * may need adjustment.
1833  */
1834  if (old_snapshot_threshold == 0)
1835  {
1836  if (TransactionIdPrecedes(latest_xmin, MyProc->xmin)
1837  && TransactionIdFollows(latest_xmin, xlimit))
1838  xlimit = latest_xmin;
1839 
1840  ts -= 5 * USECS_PER_SEC;
1841  }
1842  else
1843  {
1846 
1847  /* Check for fast exit without LW locking. */
1849  threshold_timestamp = oldSnapshotControl->threshold_timestamp;
1850  threshold_xid = oldSnapshotControl->threshold_xid;
1852 
1853  if (ts == threshold_timestamp)
1854  {
1855  /*
1856  * Current timestamp is in same bucket as the last limit that was
1857  * applied. Reuse.
1858  */
1859  xlimit = threshold_xid;
1860  }
1861  else if (ts == next_map_update_ts)
1862  {
1863  /*
1864  * FIXME: This branch is super iffy - but that should probably
1865  * fixed separately.
1866  */
1867  xlimit = latest_xmin;
1868  }
1869  else if (GetOldSnapshotFromTimeMapping(ts, &xlimit))
1870  {
1871  }
1872 
1873  /*
1874  * Failsafe protection against vacuuming work of active transaction.
1875  *
1876  * This is not an assertion because we avoid the spinlock for
1877  * performance, leaving open the possibility that xlimit could advance
1878  * and be more current; but it seems prudent to apply this limit. It
1879  * might make pruning a tiny bit less aggressive than it could be, but
1880  * protects against data loss bugs.
1881  */
1882  if (TransactionIdIsNormal(latest_xmin)
1883  && TransactionIdPrecedes(latest_xmin, xlimit))
1884  xlimit = latest_xmin;
1885  }
1886 
1887  if (TransactionIdIsValid(xlimit) &&
1888  TransactionIdFollowsOrEquals(xlimit, recentXmin))
1889  {
1890  *limit_ts = ts;
1891  *limit_xid = xlimit;
1892 
1893  return true;
1894  }
1895 
1896  return false;
1897 }
#define RelationNeedsWAL(relation)
Definition: rel.h:626
static bool GetOldSnapshotFromTimeMapping(TimestampTz ts, TransactionId *xlimitp)
Definition: snapmgr.c:1752
#define RelationAllowsEarlyPruning(rel)
Definition: snapmgr.h:38
static bool OldSnapshotThresholdActive(void)
Definition: snapmgr.h:102
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:322

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

885 {
886  if (snapshot == NULL)
887  return;
888 
889  Assert(snapshot->regd_count > 0);
891 
892  ResourceOwnerForgetSnapshot(owner, snapshot);
893 
894  snapshot->regd_count--;
895  if (snapshot->regd_count == 0)
897 
898  if (snapshot->regd_count == 0 && snapshot->active_count == 0)
899  {
900  FreeSnapshot(snapshot);
902  }
903 }
void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1264

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

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

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 419 of file indexcmds.c.

420 {
421  int n_old_snapshots;
422  int i;
423  VirtualTransactionId *old_snapshots;
424 
425  old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
427  | PROC_IN_SAFE_IC,
428  &n_old_snapshots);
429  if (progress)
431 
432  for (i = 0; i < n_old_snapshots; i++)
433  {
434  if (!VirtualTransactionIdIsValid(old_snapshots[i]))
435  continue; /* found uninteresting in previous cycle */
436 
437  if (i > 0)
438  {
439  /* see if anything's changed ... */
440  VirtualTransactionId *newer_snapshots;
441  int n_newer_snapshots;
442  int j;
443  int k;
444 
445  newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
446  true, false,
448  | PROC_IN_SAFE_IC,
449  &n_newer_snapshots);
450  for (j = i; j < n_old_snapshots; j++)
451  {
452  if (!VirtualTransactionIdIsValid(old_snapshots[j]))
453  continue; /* found uninteresting in previous cycle */
454  for (k = 0; k < n_newer_snapshots; k++)
455  {
456  if (VirtualTransactionIdEquals(old_snapshots[j],
457  newer_snapshots[k]))
458  break;
459  }
460  if (k >= n_newer_snapshots) /* not there anymore */
461  SetInvalidVirtualTransactionId(old_snapshots[j]);
462  }
463  pfree(newer_snapshots);
464  }
465 
466  if (VirtualTransactionIdIsValid(old_snapshots[i]))
467  {
468  /* If requested, publish who we're going to wait for. */
469  if (progress)
470  {
471  PGPROC *holder = BackendIdGetProc(old_snapshots[i].backendId);
472 
473  if (holder)
475  holder->pid);
476  }
477  VirtualXactLock(old_snapshots[i], true);
478  }
479 
480  if (progress)
482  }
483 }
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:270
#define PROC_IN_SAFE_IC
Definition: proc.h:58
#define PROC_IN_VACUUM
Definition: proc.h:57
#define PROC_IS_AUTOVACUUM
Definition: proc.h:56
VirtualTransactionId * GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
Definition: procarray.c:3290
#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:385
Definition: proc.h:162
int pid
Definition: proc.h:186

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

1572 {
1573  return (exportedSnapshots != NIL);
1574 }

References exportedSnapshots, and NIL.

Referenced by PrepareTransaction().

◆ XidInMVCCSnapshot()

bool XidInMVCCSnapshot ( TransactionId  xid,
Snapshot  snapshot 
)

Definition at line 2287 of file snapmgr.c.

2288 {
2289  /*
2290  * Make a quick range check to eliminate most XIDs without looking at the
2291  * xip arrays. Note that this is OK even if we convert a subxact XID to
2292  * its parent below, because a subxact with XID < xmin has surely also got
2293  * a parent with XID < xmin, while one with XID >= xmax must belong to a
2294  * parent that was not yet committed at the time of this snapshot.
2295  */
2296 
2297  /* Any xid < xmin is not in-progress */
2298  if (TransactionIdPrecedes(xid, snapshot->xmin))
2299  return false;
2300  /* Any xid >= xmax is in-progress */
2301  if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
2302  return true;
2303 
2304  /*
2305  * Snapshot information is stored slightly differently in snapshots taken
2306  * during recovery.
2307  */
2308  if (!snapshot->takenDuringRecovery)
2309  {
2310  /*
2311  * If the snapshot contains full subxact data, the fastest way to
2312  * check things is just to compare the given XID against both subxact
2313  * XIDs and top-level XIDs. If the snapshot overflowed, we have to
2314  * use pg_subtrans to convert a subxact XID to its parent XID, but
2315  * then we need only look at top-level XIDs not subxacts.
2316  */
2317  if (!snapshot->suboverflowed)
2318  {
2319  /* we have full data, so search subxip */
2320  if (pg_lfind32(xid, snapshot->subxip, snapshot->subxcnt))
2321  return true;
2322 
2323  /* not there, fall through to search xip[] */
2324  }
2325  else
2326  {
2327  /*
2328  * Snapshot overflowed, so convert xid to top-level. This is safe
2329  * because we eliminated too-old XIDs above.
2330  */
2331  xid = SubTransGetTopmostTransaction(xid);
2332 
2333  /*
2334  * If xid was indeed a subxact, we might now have an xid < xmin,
2335  * so recheck to avoid an array scan. No point in rechecking
2336  * xmax.
2337  */
2338  if (TransactionIdPrecedes(xid, snapshot->xmin))
2339  return false;
2340  }
2341 
2342  if (pg_lfind32(xid, snapshot->xip, snapshot->xcnt))
2343  return true;
2344  }
2345  else
2346  {
2347  /*
2348  * In recovery we store all xids in the subxip array because it is by
2349  * far the bigger array, and we mostly don't know which xids are
2350  * top-level and which are subxacts. The xip array is empty.
2351  *
2352  * We start by searching subtrans, if we overflowed.
2353  */
2354  if (snapshot->suboverflowed)
2355  {
2356  /*
2357  * Snapshot overflowed, so convert xid to top-level. This is safe
2358  * because we eliminated too-old XIDs above.
2359  */
2360  xid = SubTransGetTopmostTransaction(xid);
2361 
2362  /*
2363  * If xid was indeed a subxact, we might now have an xid < xmin,
2364  * so recheck to avoid an array scan. No point in rechecking
2365  * xmax.
2366  */
2367  if (TransactionIdPrecedes(xid, snapshot->xmin))
2368  return false;
2369  }
2370 
2371  /*
2372  * We now have either a top-level xid higher than xmin or an
2373  * indeterminate xid. We don't know whether it's top level or subxact
2374  * but it doesn't matter. If it's present, the xid is visible.
2375  */
2376  if (pg_lfind32(xid, snapshot->subxip, snapshot->subxcnt))
2377  return true;
2378  }
2379 
2380  return false;
2381 }
static bool pg_lfind32(uint32 key, uint32 *base, uint32 nelem)
Definition: pg_lfind.h:90
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:150

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

Variable Documentation

◆ CatalogSnapshotData

PGDLLIMPORT SnapshotData CatalogSnapshotData
extern

Definition at line 98 of file snapmgr.c.

Referenced by GetNonHistoricCatalogSnapshot().

◆ FirstSnapshotSet

◆ old_snapshot_threshold

◆ RecentXmin

◆ SnapshotAnyData

PGDLLIMPORT SnapshotData SnapshotAnyData
extern

Definition at line 100 of file snapmgr.c.

◆ SnapshotSelfData

PGDLLIMPORT SnapshotData SnapshotSelfData
extern

Definition at line 99 of file snapmgr.c.

◆ TransactionXmin