1/*-------------------------------------------------------------------------
4 * PostgreSQL subtransaction-log manager
6 * The pg_subtrans manager is a pg_xact-like manager that stores the parent
7 * transaction Id for each transaction. It is a fundamental part of the
8 * nested transactions implementation. A main transaction has a parent
9 * of InvalidTransactionId, and each subtransaction has its immediate parent.
10 * The tree can easily be walked from child to parent, but not in the
13 * This code is based on xact.c, but the robustness requirements
14 * are completely different from pg_xact, because we only need to remember
15 * pg_subtrans information for currently-open transactions. Thus, there is
16 * no need to preserve data over a crash and restart.
18 * There are no XLOG interactions since we do not care about preserving
19 * data across crashes. During database startup, we simply force the
20 * currently-active page of SUBTRANS to zeroes.
22 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
23 * Portions Copyright (c) 1994, Regents of the University of California
25 * src/backend/access/transam/subtrans.c
27 *-------------------------------------------------------------------------
41 * Defines for SubTrans page sizes. A page is the same BLCKSZ as is used
42 * everywhere else in Postgres.
44 * Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
45 * SubTrans page numbering also wraps around at
46 * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE, and segment numbering at
47 * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT. We need take no
48 * explicit notice of that fact in this module, except when comparing segment
49 * and page numbers in TruncateSUBTRANS (see SubTransPagePrecedes) and zeroing
50 * them in StartupSUBTRANS.
53/* We need four bytes per xact */
54 #define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(TransactionId))
57 * Although we return an int64 the actual value can't currently exceed
58 * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE.
66 #define TransactionIdToEntry(xid) ((xid) % (TransactionId) SUBTRANS_XACTS_PER_PAGE)
70 * Link to shared-memory data structures for SUBTRANS control
74 #define SubTransCtl (&SubTransCtlData)
81 * Record the parent of a subtransaction in the subtrans log.
103 * It's possible we'll try to set the parent xid multiple times but we
104 * shouldn't ever be changing the xid from one valid xid to another valid
105 * xid, which would corrupt the data structure.
118 * Interrogate the parent of a transaction in the subtrans log.
129 /* Can't ask about stuff that might not be around anymore */
132 /* Bootstrap and frozen XIDs have no parent */
136 /* lock is acquired by SimpleLruReadPage_ReadOnly */
150 * SubTransGetTopmostTransaction
152 * Returns the topmost transaction of the given transaction id.
154 * Because we cannot look back further than TransactionXmin, it is possible
155 * that this function will lie and return an intermediate subtransaction ID
156 * instead of the true topmost parent ID. This is OK, because in practice
157 * we only care about detecting whether the topmost parent is still running
158 * or is part of a current snapshot's list of still-running transactions.
159 * Therefore, any XID before TransactionXmin is as good as any other.
167 /* Can't ask about stuff that might not be around anymore */
172 previousXid = parentXid;
178 * By convention the parent xid gets allocated first, so should always
179 * precede the child xid. Anything else points to a corrupted data
180 * structure that could lead to an infinite loop, so exit.
183 elog(
ERROR,
"pg_subtrans contains invalid entry: xid %u points to parent xid %u",
184 previousXid, parentXid);
193 * Number of shared SUBTRANS buffers.
195 * If asked to autotune, use 2MB for every 1GB of shared buffers, up to 8MB.
196 * Otherwise just cap the configured amount to be between 16 and the maximum
202 /* auto-tune based on shared buffers */
210 * Initialization of shared memory for SUBTRANS
221 /* If auto-tuning is requested, now is the time to do it */
231 * We prefer to report this value's source as PGC_S_DYNAMIC_DEFAULT.
232 * However, if the DBA explicitly set subtransaction_buffers = 0 in
233 * the config file, then PGC_S_DYNAMIC_DEFAULT will fail to override
234 * that and we must force the matter with PGC_S_OVERRIDE.
244 "pg_subtrans", LWTRANCHE_SUBTRANS_BUFFER,
250 * GUC check_hook for subtransaction_buffers
259 * This func must be called ONCE on system install. It creates
260 * the initial SUBTRANS segment. (The SUBTRANS directory is assumed to
261 * have been created by the initdb shell script, and SUBTRANSShmemInit
262 * must have been called already.)
264 * Note: it's not really necessary to create the initial segment now,
265 * since slru.c would create it on first write anyway. But we may as well
266 * do it to be sure the directory is set up correctly.
271 /* Zero the initial page and flush it to disk */
276 * This must be called ONCE during postmaster or standalone-backend startup,
277 * after StartupXLOG has initialized TransamVariables->nextXid.
279 * oldestActiveXID is the oldest XID of any prepared transaction, or nextXid
292 * Since we don't expect pg_subtrans to be valid across crashes, we
293 * initialize the currently-active page(s) to zeroes during startup.
294 * Whenever we advance into a new page, ExtendSUBTRANS will likewise zero
295 * the new page without regard to whatever was previously on disk.
304 if (prevlock != lock)
313 if (startPage == endPage)
317 /* must account for wraparound */
326 * Perform a checkpoint --- either during shutdown, or on-the-fly
332 * Write dirty SUBTRANS pages to disk
334 * This is not actually necessary from a correctness point of view. We do
335 * it merely to improve the odds that writing of dirty pages is done by
336 * the checkpoint process and not by backends.
338 TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_START(
true);
340 TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_DONE(
true);
345 * Make sure that SUBTRANS has room for a newly-allocated XID.
347 * NB: this is called while holding XidGenLock. We want it to be very fast
348 * most of the time; even when it's not so fast, no actual I/O need happen
349 * unless we're forced to write out a dirty subtrans page to make room
359 * No work except at first XID of a page. But beware: just after
360 * wraparound, the first XID of page zero is FirstNormalTransactionId.
379 * Remove all SUBTRANS segments before the one holding the passed transaction ID
381 * oldestXact is the oldest TransactionXmin of any running transaction. This
382 * is called only during checkpoint.
390 * The cutoff point is the start of the segment containing oldestXact. We
391 * pass the *page* containing oldestXact to SimpleLruTruncate. We step
392 * back one transaction to avoid passing a cutoff page that hasn't been
393 * created yet in the rare case that oldestXact would be the first item on
394 * a page and oldestXact == next XID. In that case, if we didn't subtract
395 * one, we'd trigger SimpleLruTruncate's wraparound detection.
405 * Decide whether a SUBTRANS page number is "older" for truncation purposes.
406 * Analogous to CLOGPagePrecedes().
int subtransaction_buffers
void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source)
Assert(PointerIsAligned(start, uint64))
if(TABLE==NULL||TABLE_index==NULL)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void LWLockRelease(LWLock *lock)
static rewind_source * source
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
int SimpleLruAutotuneBuffers(int divisor, int max)
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
void SimpleLruZeroAndWritePage(SlruCtl ctl, int64 pageno)
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Size SimpleLruShmemSize(int nslots, int nlsns)
bool check_slru_buffers(const char *name, int *newval)
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
#define SlruPagePrecedesUnitTests(ctl, per_page)
#define SLRU_MAX_ALLOWED_BUFFERS
TransactionId TransactionXmin
FullTransactionId nextXid
bool check_subtrans_buffers(int *newval, void **extra, GucSource source)
void SUBTRANSShmemInit(void)
void SubTransSetParent(TransactionId xid, TransactionId parent)
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
#define SUBTRANS_XACTS_PER_PAGE
#define TransactionIdToEntry(xid)
static SlruCtlData SubTransCtlData
void ExtendSUBTRANS(TransactionId newestXact)
void StartupSUBTRANS(TransactionId oldestActiveXID)
void CheckPointSUBTRANS(void)
Size SUBTRANSShmemSize(void)
static int SUBTRANSShmemBuffers(void)
TransactionId SubTransGetParent(TransactionId xid)
static bool SubTransPagePrecedes(int64 page1, int64 page2)
static int64 TransactionIdToPage(TransactionId xid)
void BootStrapSUBTRANS(void)
void TruncateSUBTRANS(TransactionId oldestXact)
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
#define TransactionIdRetreat(dest)
#define InvalidTransactionId
#define TransactionIdEquals(id1, id2)
#define XidFromFullTransactionId(x)
#define FirstNormalTransactionId
#define TransactionIdIsValid(xid)
#define TransactionIdIsNormal(xid)
TransamVariablesData * TransamVariables