aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2025-03-11 23:28:38 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2025-03-11 23:28:38 +0200
commit043745c3a01fece996e4818945138320d10261bf (patch)
tree4d092bf95eba6a39ad6a183553a3ccc8fb55bf6d /src
parent8076c00592e40e8dbd1fce7a98b20d4bf075e4ba (diff)
downloadpostgresql-043745c3a01fece996e4818945138320d10261bf.tar.gz
postgresql-043745c3a01fece996e4818945138320d10261bf.zip
Improve snapmgr.c comment
Add more details on the different kinds of snapshots, how to use them, and how the active snapshot stack works. Discussion: https://www.postgresql.org/message-id/7c56f180-b9e1-481e-8c1d-efa63de3ecbb@iki.fi
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/time/snapmgr.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 6ed1c93383e..ea35f30f494 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -3,11 +3,70 @@
* snapmgr.c
* PostgreSQL snapshot manager
*
+ * The following functions return an MVCC snapshot that can be used in tuple
+ * visibility checks:
+ *
+ * - GetTransactionSnapshot
+ * - GetLatestSnapshot
+ * - GetCatalogSnapshot
+ * - GetNonHistoricCatalogSnapshot
+ *
+ * Each of these functions returns a reference to a statically allocated
+ * snapshot. The statically allocated snapshot is subject to change on any
+ * snapshot-related function call, and should not be used directly. Instead,
+ * call PushActiveSnapshot() or RegisterSnapshot() to create a longer-lived
+ * copy and use that.
+ *
* We keep track of snapshots in two ways: those "registered" by resowner.c,
* and the "active snapshot" stack. All snapshots in either of them live in
* persistent memory. When a snapshot is no longer in any of these lists
* (tracked by separate refcounts on each snapshot), its memory can be freed.
*
+ * In addition to the above-mentioned MVCC snapshots, there are some special
+ * snapshots like SnapshotSelf, SnapshotAny, and "dirty" snapshots. They can
+ * only be used in limited contexts and cannot be registered or pushed to the
+ * active stack.
+ *
+ * ActiveSnapshot stack
+ * --------------------
+ *
+ * Most visibility checks use the current "active snapshot" returned by
+ * GetActiveSnapshot(). When running normal queries, the active snapshot is
+ * set when query execution begins based on the transaction isolation level.
+ *
+ * The active snapshot is tracked in a stack so that the currently active one
+ * is at the top of the stack. It mirrors the process call stack: whenever we
+ * recurse or switch context to fetch rows from a different portal for
+ * example, the appropriate snapshot is pushed to become the active snapshot,
+ * and popped on return. Once upon a time, ActiveSnapshot was just a global
+ * variable that was saved and restored similar to CurrentMemoryContext, but
+ * nowadays it's managed as a separate data structure so that we can keep
+ * track of which snapshots are in use and reset MyProc->xmin when there is no
+ * active snapshot.
+ *
+ * However, there are a couple of exceptions where the active snapshot stack
+ * does not strictly mirror the call stack:
+ *
+ * - VACUUM and a few other utility commands manage their own transactions,
+ * which take their own snapshots. They are called with an active snapshot
+ * set, like most utility commands, but they pop the active snapshot that
+ * was pushed by the caller. PortalRunUtility knows about the possibility
+ * that the snapshot it pushed is no longer active on return.
+ *
+ * - When COMMIT or ROLLBACK is executed within a procedure or DO-block, the
+ * active snapshot stack is destroyed, and re-established later when
+ * subsequent statements in the procedure are executed. There are many
+ * limitations on when in-procedure COMMIT/ROLLBACK is allowed; one such
+ * limitation is that all the snapshots on the active snapshot stack are
+ * known to portals that are being executed, which makes it safe to reset
+ * the stack. See EnsurePortalSnapshotExists().
+ *
+ * Registered snapshots
+ * --------------------
+ *
+ * In addition to snapshots pushed to the active snapshot stack, a snapshot
+ * can be registered with a resource owner.
+ *
* The FirstXactSnapshot, if any, is treated a bit specially: we increment its
* regd_count and list it in RegisteredSnapshots, but this reference is not
* tracked by a resource owner. We used to use the TopTransactionResourceOwner