PostgreSQL Source Code git master
Loading...
Searching...
No Matches
subtrans.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * subtrans.c
4 * PostgreSQL subtransaction-log manager
5 *
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
11 * opposite direction.
12 *
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.
17 *
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.
21 *
22 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
23 * Portions Copyright (c) 1994, Regents of the University of California
24 *
25 * src/backend/access/transam/subtrans.c
26 *
27 *-------------------------------------------------------------------------
28 */
29#include "postgres.h"
30
31#include "access/slru.h"
32#include "access/subtrans.h"
33#include "access/transam.h"
34#include "miscadmin.h"
35#include "pg_trace.h"
36#include "utils/guc_hooks.h"
37#include "utils/snapmgr.h"
38
39
40/*
41 * Defines for SubTrans page sizes. A page is the same BLCKSZ as is used
42 * everywhere else in Postgres.
43 *
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.
51 */
52
53/* We need four bytes per xact */
54#define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(TransactionId))
55
56/*
57 * Although we return an int64 the actual value can't currently exceed
58 * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE.
59 */
60static inline int64
65
66#define TransactionIdToEntry(xid) ((xid) % (TransactionId) SUBTRANS_XACTS_PER_PAGE)
67
68
69/*
70 * Link to shared-memory data structures for SUBTRANS control
71 */
73
74#define SubTransCtl (&SubTransCtlData)
75
76
78static int subtrans_errdetail_for_io_error(const void *opaque_data);
79
80
81/*
82 * Record the parent of a subtransaction in the subtrans log.
83 */
84void
86{
87 int64 pageno = TransactionIdToPage(xid);
89 int slotno;
90 LWLock *lock;
91 TransactionId *ptr;
92
94 Assert(TransactionIdFollows(xid, parent));
95
96 lock = SimpleLruGetBankLock(SubTransCtl, pageno);
98
99 slotno = SimpleLruReadPage(SubTransCtl, pageno, true, &xid);
100 ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
101 ptr += entryno;
102
103 /*
104 * It's possible we'll try to set the parent xid multiple times but we
105 * shouldn't ever be changing the xid from one valid xid to another valid
106 * xid, which would corrupt the data structure.
107 */
108 if (*ptr != parent)
109 {
111 *ptr = parent;
112 SubTransCtl->shared->page_dirty[slotno] = true;
113 }
114
115 LWLockRelease(lock);
116}
117
118/*
119 * Interrogate the parent of a transaction in the subtrans log.
120 */
123{
124 int64 pageno = TransactionIdToPage(xid);
125 int entryno = TransactionIdToEntry(xid);
126 int slotno;
127 TransactionId *ptr;
128 TransactionId parent;
129
130 /* Can't ask about stuff that might not be around anymore */
132
133 /* Bootstrap and frozen XIDs have no parent */
134 if (!TransactionIdIsNormal(xid))
136
137 /* lock is acquired by SimpleLruReadPage_ReadOnly */
138
140 ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
141 ptr += entryno;
142
143 parent = *ptr;
144
146
147 return parent;
148}
149
150/*
151 * SubTransGetTopmostTransaction
152 *
153 * Returns the topmost transaction of the given transaction id.
154 *
155 * Because we cannot look back further than TransactionXmin, it is possible
156 * that this function will lie and return an intermediate subtransaction ID
157 * instead of the true topmost parent ID. This is OK, because in practice
158 * we only care about detecting whether the topmost parent is still running
159 * or is part of a current snapshot's list of still-running transactions.
160 * Therefore, any XID before TransactionXmin is as good as any other.
161 */
164{
166 previousXid = xid;
167
168 /* Can't ask about stuff that might not be around anymore */
170
172 {
175 break;
177
178 /*
179 * By convention the parent xid gets allocated first, so should always
180 * precede the child xid. Anything else points to a corrupted data
181 * structure that could lead to an infinite loop, so exit.
182 */
184 elog(ERROR, "pg_subtrans contains invalid entry: xid %u points to parent xid %u",
186 }
187
189
190 return previousXid;
191}
192
193/*
194 * Number of shared SUBTRANS buffers.
195 *
196 * If asked to autotune, use 2MB for every 1GB of shared buffers, up to 8MB.
197 * Otherwise just cap the configured amount to be between 16 and the maximum
198 * allowed.
199 */
200static int
202{
203 /* auto-tune based on shared buffers */
204 if (subtransaction_buffers == 0)
205 return SimpleLruAutotuneBuffers(512, 1024);
206
208}
209
210/*
211 * Initialization of shared memory for SUBTRANS
212 */
213Size
218
219void
221{
222 /* If auto-tuning is requested, now is the time to do it */
223 if (subtransaction_buffers == 0)
224 {
225 char buf[32];
226
227 snprintf(buf, sizeof(buf), "%d", SUBTRANSShmemBuffers());
228 SetConfigOption("subtransaction_buffers", buf, PGC_POSTMASTER,
230
231 /*
232 * We prefer to report this value's source as PGC_S_DYNAMIC_DEFAULT.
233 * However, if the DBA explicitly set subtransaction_buffers = 0 in
234 * the config file, then PGC_S_DYNAMIC_DEFAULT will fail to override
235 * that and we must force the matter with PGC_S_OVERRIDE.
236 */
237 if (subtransaction_buffers == 0) /* failed to apply it? */
238 SetConfigOption("subtransaction_buffers", buf, PGC_POSTMASTER,
240 }
242
243 SubTransCtl->PagePrecedes = SubTransPagePrecedes;
244 SubTransCtl->errdetail_for_io_error = subtrans_errdetail_for_io_error;
245 SimpleLruInit(SubTransCtl, "subtransaction", SUBTRANSShmemBuffers(), 0,
246 "pg_subtrans", LWTRANCHE_SUBTRANS_BUFFER,
249}
250
251/*
252 * GUC check_hook for subtransaction_buffers
253 */
254bool
256{
257 return check_slru_buffers("subtransaction_buffers", newval);
258}
259
260/*
261 * This func must be called ONCE on system install. It creates
262 * the initial SUBTRANS segment. (The SUBTRANS directory is assumed to
263 * have been created by the initdb shell script, and SUBTRANSShmemInit
264 * must have been called already.)
265 *
266 * Note: it's not really necessary to create the initial segment now,
267 * since slru.c would create it on first write anyway. But we may as well
268 * do it to be sure the directory is set up correctly.
269 */
270void
272{
273 /* Zero the initial page and flush it to disk */
275}
276
277/*
278 * This must be called ONCE during postmaster or standalone-backend startup,
279 * after StartupXLOG has initialized TransamVariables->nextXid.
280 *
281 * oldestActiveXID is the oldest XID of any prepared transaction, or nextXid
282 * if there are none.
283 */
284void
286{
287 FullTransactionId nextXid;
291 LWLock *lock;
292
293 /*
294 * Since we don't expect pg_subtrans to be valid across crashes, we
295 * initialize the currently-active page(s) to zeroes during startup.
296 * Whenever we advance into a new page, ExtendSUBTRANS will likewise zero
297 * the new page without regard to whatever was previously on disk.
298 */
300 nextXid = TransamVariables->nextXid;
302
303 for (;;)
304 {
306 if (prevlock != lock)
307 {
308 if (prevlock)
311 prevlock = lock;
312 }
313
315 if (startPage == endPage)
316 break;
317
318 startPage++;
319 /* must account for wraparound */
321 startPage = 0;
322 }
323
324 LWLockRelease(lock);
325}
326
327/*
328 * Perform a checkpoint --- either during shutdown, or on-the-fly
329 */
330void
332{
333 /*
334 * Write dirty SUBTRANS pages to disk
335 *
336 * This is not actually necessary from a correctness point of view. We do
337 * it merely to improve the odds that writing of dirty pages is done by
338 * the checkpoint process and not by backends.
339 */
343}
344
345
346/*
347 * Make sure that SUBTRANS has room for a newly-allocated XID.
348 *
349 * NB: this is called while holding XidGenLock. We want it to be very fast
350 * most of the time; even when it's not so fast, no actual I/O need happen
351 * unless we're forced to write out a dirty subtrans page to make room
352 * in shared memory.
353 */
354void
356{
357 int64 pageno;
358 LWLock *lock;
359
360 /*
361 * No work except at first XID of a page. But beware: just after
362 * wraparound, the first XID of page zero is FirstNormalTransactionId.
363 */
366 return;
367
369
370 lock = SimpleLruGetBankLock(SubTransCtl, pageno);
372
373 /* Zero the page */
375
376 LWLockRelease(lock);
377}
378
379
380/*
381 * Remove all SUBTRANS segments before the one holding the passed transaction ID
382 *
383 * oldestXact is the oldest TransactionXmin of any running transaction. This
384 * is called only during checkpoint.
385 */
386void
388{
390
391 /*
392 * The cutoff point is the start of the segment containing oldestXact. We
393 * pass the *page* containing oldestXact to SimpleLruTruncate. We step
394 * back one transaction to avoid passing a cutoff page that hasn't been
395 * created yet in the rare case that oldestXact would be the first item on
396 * a page and oldestXact == next XID. In that case, if we didn't subtract
397 * one, we'd trigger SimpleLruTruncate's wraparound detection.
398 */
399 TransactionIdRetreat(oldestXact);
400 cutoffPage = TransactionIdToPage(oldestXact);
401
403}
404
405
406/*
407 * Decide whether a SUBTRANS page number is "older" for truncation purposes.
408 * Analogous to CLOGPagePrecedes().
409 */
410static bool
424
425static int
427{
428 TransactionId xid = *(const TransactionId *) opaque_data;
429
430 return errdetail("Could not access subtransaction status of transaction %u.", xid);
431}
#define Min(x, y)
Definition c.h:1093
#define Max(x, y)
Definition c.h:1087
#define Assert(condition)
Definition c.h:945
int64_t int64
Definition c.h:615
uint32 TransactionId
Definition c.h:738
size_t Size
Definition c.h:691
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
int subtransaction_buffers
Definition globals.c:166
void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source)
Definition guc.c:4228
#define newval
GucSource
Definition guc.h:112
@ PGC_S_DYNAMIC_DEFAULT
Definition guc.h:114
@ PGC_S_OVERRIDE
Definition guc.h:123
@ PGC_POSTMASTER
Definition guc.h:74
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1177
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1794
@ LW_EXCLUSIVE
Definition lwlock.h:112
static rewind_source * source
Definition pg_rewind.c:89
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define snprintf
Definition port.h:260
static int fb(int x)
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)
Definition slru.c:254
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition slru.c:1355
int SimpleLruAutotuneBuffers(int divisor, int max)
Definition slru.c:233
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, const void *opaque_data)
Definition slru.c:533
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition slru.c:380
void SimpleLruZeroAndWritePage(SlruCtl ctl, int64 pageno)
Definition slru.c:449
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition slru.c:1441
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, const void *opaque_data)
Definition slru.c:637
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition slru.c:200
bool check_slru_buffers(const char *name, int *newval)
Definition slru.c:360
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition slru.h:171
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition slru.h:196
#define SLRU_MAX_ALLOWED_BUFFERS
Definition slru.h:25
TransactionId TransactionXmin
Definition snapmgr.c:159
FullTransactionId nextXid
Definition transam.h:220
static int subtrans_errdetail_for_io_error(const void *opaque_data)
Definition subtrans.c:426
bool check_subtrans_buffers(int *newval, void **extra, GucSource source)
Definition subtrans.c:255
void SUBTRANSShmemInit(void)
Definition subtrans.c:220
void SubTransSetParent(TransactionId xid, TransactionId parent)
Definition subtrans.c:85
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition subtrans.c:163
#define SUBTRANS_XACTS_PER_PAGE
Definition subtrans.c:54
#define TransactionIdToEntry(xid)
Definition subtrans.c:66
static SlruCtlData SubTransCtlData
Definition subtrans.c:72
void ExtendSUBTRANS(TransactionId newestXact)
Definition subtrans.c:355
void StartupSUBTRANS(TransactionId oldestActiveXID)
Definition subtrans.c:285
void CheckPointSUBTRANS(void)
Definition subtrans.c:331
Size SUBTRANSShmemSize(void)
Definition subtrans.c:214
static int SUBTRANSShmemBuffers(void)
Definition subtrans.c:201
TransactionId SubTransGetParent(TransactionId xid)
Definition subtrans.c:122
static bool SubTransPagePrecedes(int64 page1, int64 page2)
Definition subtrans.c:411
static int64 TransactionIdToPage(TransactionId xid)
Definition subtrans.c:61
#define SubTransCtl
Definition subtrans.c:74
void BootStrapSUBTRANS(void)
Definition subtrans.c:271
void TruncateSUBTRANS(TransactionId oldestXact)
Definition subtrans.c:387
@ SYNC_HANDLER_NONE
Definition sync.h:42
static bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition transam.h:297
#define TransactionIdRetreat(dest)
Definition transam.h:141
#define InvalidTransactionId
Definition transam.h:31
static bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition transam.h:312
#define TransactionIdEquals(id1, id2)
Definition transam.h:43
#define XidFromFullTransactionId(x)
Definition transam.h:48
#define FirstNormalTransactionId
Definition transam.h:34
#define TransactionIdIsValid(xid)
Definition transam.h:41
#define TransactionIdIsNormal(xid)
Definition transam.h:42
#define MaxTransactionId
Definition transam.h:35
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
TransamVariablesData * TransamVariables
Definition varsup.c:34