PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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_clog-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 clog.c, but the robustness requirements
14  * are completely different from pg_clog, 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-2017, 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 "pg_trace.h"
35 #include "utils/snapmgr.h"
36 
37 
38 /*
39  * Defines for SubTrans page sizes. A page is the same BLCKSZ as is used
40  * everywhere else in Postgres.
41  *
42  * Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
43  * SubTrans page numbering also wraps around at
44  * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE, and segment numbering at
45  * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT. We need take no
46  * explicit notice of that fact in this module, except when comparing segment
47  * and page numbers in TruncateSUBTRANS (see SubTransPagePrecedes) and zeroing
48  * them in StartupSUBTRANS.
49  */
50 
51 /* We need four bytes per xact */
52 #define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(TransactionId))
53 
54 #define TransactionIdToPage(xid) ((xid) / (TransactionId) SUBTRANS_XACTS_PER_PAGE)
55 #define TransactionIdToEntry(xid) ((xid) % (TransactionId) SUBTRANS_XACTS_PER_PAGE)
56 
57 
58 /*
59  * Link to shared-memory data structures for SUBTRANS control
60  */
62 
63 #define SubTransCtl (&SubTransCtlData)
64 
65 
66 static int ZeroSUBTRANSPage(int pageno);
67 static bool SubTransPagePrecedes(int page1, int page2);
68 
69 
70 /*
71  * Record the parent of a subtransaction in the subtrans log.
72  *
73  * In some cases we may need to overwrite an existing value.
74  */
75 void
76 SubTransSetParent(TransactionId xid, TransactionId parent, bool overwriteOK)
77 {
78  int pageno = TransactionIdToPage(xid);
79  int entryno = TransactionIdToEntry(xid);
80  int slotno;
81  TransactionId *ptr;
82 
84 
85  LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
86 
87  slotno = SimpleLruReadPage(SubTransCtl, pageno, true, xid);
88  ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
89  ptr += entryno;
90 
91  /* Current state should be 0 */
92  Assert(*ptr == InvalidTransactionId ||
93  (*ptr == parent && overwriteOK));
94 
95  *ptr = parent;
96 
97  SubTransCtl->shared->page_dirty[slotno] = true;
98 
99  LWLockRelease(SubtransControlLock);
100 }
101 
102 /*
103  * Interrogate the parent of a transaction in the subtrans log.
104  */
107 {
108  int pageno = TransactionIdToPage(xid);
109  int entryno = TransactionIdToEntry(xid);
110  int slotno;
111  TransactionId *ptr;
112  TransactionId parent;
113 
114  /* Can't ask about stuff that might not be around anymore */
116 
117  /* Bootstrap and frozen XIDs have no parent */
118  if (!TransactionIdIsNormal(xid))
119  return InvalidTransactionId;
120 
121  /* lock is acquired by SimpleLruReadPage_ReadOnly */
122 
123  slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
124  ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
125  ptr += entryno;
126 
127  parent = *ptr;
128 
129  LWLockRelease(SubtransControlLock);
130 
131  return parent;
132 }
133 
134 /*
135  * SubTransGetTopmostTransaction
136  *
137  * Returns the topmost transaction of the given transaction id.
138  *
139  * Because we cannot look back further than TransactionXmin, it is possible
140  * that this function will lie and return an intermediate subtransaction ID
141  * instead of the true topmost parent ID. This is OK, because in practice
142  * we only care about detecting whether the topmost parent is still running
143  * or is part of a current snapshot's list of still-running transactions.
144  * Therefore, any XID before TransactionXmin is as good as any other.
145  */
148 {
149  TransactionId parentXid = xid,
150  previousXid = xid;
151 
152  /* Can't ask about stuff that might not be around anymore */
154 
155  while (TransactionIdIsValid(parentXid))
156  {
157  previousXid = parentXid;
158  if (TransactionIdPrecedes(parentXid, TransactionXmin))
159  break;
160  parentXid = SubTransGetParent(parentXid);
161  }
162 
163  Assert(TransactionIdIsValid(previousXid));
164 
165  return previousXid;
166 }
167 
168 
169 /*
170  * Initialization of shared memory for SUBTRANS
171  */
172 Size
174 {
176 }
177 
178 void
180 {
181  SubTransCtl->PagePrecedes = SubTransPagePrecedes;
183  SubtransControlLock, "pg_subtrans",
185  /* Override default assumption that writes should be fsync'd */
186  SubTransCtl->do_fsync = false;
187 }
188 
189 /*
190  * This func must be called ONCE on system install. It creates
191  * the initial SUBTRANS segment. (The SUBTRANS directory is assumed to
192  * have been created by the initdb shell script, and SUBTRANSShmemInit
193  * must have been called already.)
194  *
195  * Note: it's not really necessary to create the initial segment now,
196  * since slru.c would create it on first write anyway. But we may as well
197  * do it to be sure the directory is set up correctly.
198  */
199 void
201 {
202  int slotno;
203 
204  LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
205 
206  /* Create and zero the first page of the subtrans log */
207  slotno = ZeroSUBTRANSPage(0);
208 
209  /* Make sure it's written out */
211  Assert(!SubTransCtl->shared->page_dirty[slotno]);
212 
213  LWLockRelease(SubtransControlLock);
214 }
215 
216 /*
217  * Initialize (or reinitialize) a page of SUBTRANS to zeroes.
218  *
219  * The page is not actually written, just set up in shared memory.
220  * The slot number of the new page is returned.
221  *
222  * Control lock must be held at entry, and will be held at exit.
223  */
224 static int
225 ZeroSUBTRANSPage(int pageno)
226 {
227  return SimpleLruZeroPage(SubTransCtl, pageno);
228 }
229 
230 /*
231  * This must be called ONCE during postmaster or standalone-backend startup,
232  * after StartupXLOG has initialized ShmemVariableCache->nextXid.
233  *
234  * oldestActiveXID is the oldest XID of any prepared transaction, or nextXid
235  * if there are none.
236  */
237 void
239 {
240  int startPage;
241  int endPage;
242 
243  /*
244  * Since we don't expect pg_subtrans to be valid across crashes, we
245  * initialize the currently-active page(s) to zeroes during startup.
246  * Whenever we advance into a new page, ExtendSUBTRANS will likewise zero
247  * the new page without regard to whatever was previously on disk.
248  */
249  LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
250 
251  startPage = TransactionIdToPage(oldestActiveXID);
253 
254  while (startPage != endPage)
255  {
256  (void) ZeroSUBTRANSPage(startPage);
257  startPage++;
258  /* must account for wraparound */
259  if (startPage > TransactionIdToPage(MaxTransactionId))
260  startPage = 0;
261  }
262  (void) ZeroSUBTRANSPage(startPage);
263 
264  LWLockRelease(SubtransControlLock);
265 }
266 
267 /*
268  * This must be called ONCE during postmaster or standalone-backend shutdown
269  */
270 void
272 {
273  /*
274  * Flush dirty SUBTRANS pages to disk
275  *
276  * This is not actually necessary from a correctness point of view. We do
277  * it merely as a debugging aid.
278  */
279  TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_START(false);
280  SimpleLruFlush(SubTransCtl, false);
281  TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_DONE(false);
282 }
283 
284 /*
285  * Perform a checkpoint --- either during shutdown, or on-the-fly
286  */
287 void
289 {
290  /*
291  * Flush dirty SUBTRANS pages to disk
292  *
293  * This is not actually necessary from a correctness point of view. We do
294  * it merely to improve the odds that writing of dirty pages is done by
295  * the checkpoint process and not by backends.
296  */
297  TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_START(true);
299  TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_DONE(true);
300 }
301 
302 
303 /*
304  * Make sure that SUBTRANS has room for a newly-allocated XID.
305  *
306  * NB: this is called while holding XidGenLock. We want it to be very fast
307  * most of the time; even when it's not so fast, no actual I/O need happen
308  * unless we're forced to write out a dirty subtrans page to make room
309  * in shared memory.
310  */
311 void
313 {
314  int pageno;
315 
316  /*
317  * No work except at first XID of a page. But beware: just after
318  * wraparound, the first XID of page zero is FirstNormalTransactionId.
319  */
320  if (TransactionIdToEntry(newestXact) != 0 &&
322  return;
323 
324  pageno = TransactionIdToPage(newestXact);
325 
326  LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
327 
328  /* Zero the page */
329  ZeroSUBTRANSPage(pageno);
330 
331  LWLockRelease(SubtransControlLock);
332 }
333 
334 
335 /*
336  * Remove all SUBTRANS segments before the one holding the passed transaction ID
337  *
338  * This is normally called during checkpoint, with oldestXact being the
339  * oldest TransactionXmin of any running transaction.
340  */
341 void
343 {
344  int cutoffPage;
345 
346  /*
347  * The cutoff point is the start of the segment containing oldestXact. We
348  * pass the *page* containing oldestXact to SimpleLruTruncate. We step
349  * back one transaction to avoid passing a cutoff page that hasn't been
350  * created yet in the rare case that oldestXact would be the first item on
351  * a page and oldestXact == next XID. In that case, if we didn't subtract
352  * one, we'd trigger SimpleLruTruncate's wraparound detection.
353  */
354  TransactionIdRetreat(oldestXact);
355  cutoffPage = TransactionIdToPage(oldestXact);
356 
357  SimpleLruTruncate(SubTransCtl, cutoffPage);
358 }
359 
360 
361 /*
362  * Decide which of two SUBTRANS page numbers is "older" for truncation purposes.
363  *
364  * We need to use comparison of TransactionIds here in order to do the right
365  * thing with wraparound XID arithmetic. However, if we are asked about
366  * page number zero, we don't want to hand InvalidTransactionId to
367  * TransactionIdPrecedes: it'll get weird about permanent xact IDs. So,
368  * offset both xids by FirstNormalTransactionId to avoid that.
369  */
370 static bool
371 SubTransPagePrecedes(int page1, int page2)
372 {
373  TransactionId xid1;
374  TransactionId xid2;
375 
376  xid1 = ((TransactionId) page1) * SUBTRANS_XACTS_PER_PAGE;
377  xid1 += FirstNormalTransactionId;
378  xid2 = ((TransactionId) page2) * SUBTRANS_XACTS_PER_PAGE;
379  xid2 += FirstNormalTransactionId;
380 
381  return TransactionIdPrecedes(xid1, xid2);
382 }
static int ZeroSUBTRANSPage(int pageno)
Definition: subtrans.c:225
#define TransactionIdToEntry(xid)
Definition: subtrans.c:55
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
void ShutdownSUBTRANS(void)
Definition: subtrans.c:271
uint32 TransactionId
Definition: c.h:394
void SUBTRANSShmemInit(void)
Definition: subtrans.c:179
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:147
TransactionId SubTransGetParent(TransactionId xid)
Definition: subtrans.c:106
void SubTransSetParent(TransactionId xid, TransactionId parent, bool overwriteOK)
Definition: subtrans.c:76
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1153
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
void TruncateSUBTRANS(TransactionId oldestXact)
Definition: subtrans.c:342
#define TransactionIdRetreat(dest)
Definition: transam.h:56
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:144
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1090
TransactionId TransactionXmin
Definition: snapmgr.c:164
#define SubTransCtl
Definition: subtrans.c:63
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
void BootStrapSUBTRANS(void)
Definition: subtrans.c:200
#define FirstNormalTransactionId
Definition: transam.h:34
void ExtendSUBTRANS(TransactionId newestXact)
Definition: subtrans.c:312
TransactionId nextXid
Definition: transam.h:117
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:370
VariableCache ShmemVariableCache
Definition: varsup.c:34
#define InvalidTransactionId
Definition: transam.h:31
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:573
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define MaxTransactionId
Definition: transam.h:35
static bool SubTransPagePrecedes(int page1, int page2)
Definition: subtrans.c:371
#define TransactionIdToPage(xid)
Definition: subtrans.c:54
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:462
#define NUM_SUBTRANS_BUFFERS
Definition: subtrans.h:15
void StartupSUBTRANS(TransactionId oldestActiveXID)
Definition: subtrans.c:238
#define Assert(condition)
Definition: c.h:671
size_t Size
Definition: c.h:353
void CheckPointSUBTRANS(void)
Definition: subtrans.c:288
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
Size SUBTRANSShmemSize(void)
Definition: subtrans.c:173
#define SUBTRANS_XACTS_PER_PAGE
Definition: subtrans.c:52
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:258
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id)
Definition: slru.c:164
static SlruCtlData SubTransCtlData
Definition: subtrans.c:61