Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * varsup.c
4 : : * postgres OID & XID variables support routines
5 : : *
6 : : * Copyright (c) 2000-2024, PostgreSQL Global Development Group
7 : : *
8 : : * IDENTIFICATION
9 : : * src/backend/access/transam/varsup.c
10 : : *
11 : : *-------------------------------------------------------------------------
12 : : */
13 : :
14 : : #include "postgres.h"
15 : :
16 : : #include "access/clog.h"
17 : : #include "access/commit_ts.h"
18 : : #include "access/subtrans.h"
19 : : #include "access/transam.h"
20 : : #include "access/xact.h"
21 : : #include "access/xlogutils.h"
22 : : #include "commands/dbcommands.h"
23 : : #include "miscadmin.h"
24 : : #include "postmaster/autovacuum.h"
25 : : #include "storage/pmsignal.h"
26 : : #include "storage/proc.h"
27 : : #include "utils/syscache.h"
28 : :
29 : :
30 : : /* Number of OIDs to prefetch (preallocate) per XLOG write */
31 : : #define VAR_OID_PREFETCH 8192
32 : :
33 : : /* pointer to variables struct in shared memory */
34 : : TransamVariablesData *TransamVariables = NULL;
35 : :
36 : :
37 : : /*
38 : : * Initialization of shared memory for TransamVariables.
39 : : */
40 : : Size
128 heikki.linnakangas@i 41 :GNC 1679 : VarsupShmemSize(void)
42 : : {
43 : 1679 : return sizeof(TransamVariablesData);
44 : : }
45 : :
46 : : void
47 : 898 : VarsupShmemInit(void)
48 : : {
49 : : bool found;
50 : :
51 : : /* Initialize our shared state struct */
52 : 898 : TransamVariables = ShmemInitStruct("TransamVariables",
53 : : sizeof(TransamVariablesData),
54 : : &found);
55 [ + - ]: 898 : if (!IsUnderPostmaster)
56 : : {
57 [ - + ]: 898 : Assert(!found);
58 : 898 : memset(TransamVariables, 0, sizeof(TransamVariablesData));
59 : : }
60 : : else
128 heikki.linnakangas@i 61 [ # # ]:UNC 0 : Assert(found);
128 heikki.linnakangas@i 62 :GNC 898 : }
63 : :
64 : : /*
65 : : * Allocate the next FullTransactionId for a new transaction or
66 : : * subtransaction.
67 : : *
68 : : * The new XID is also stored into MyProc->xid/ProcGlobal->xids[] before
69 : : * returning.
70 : : *
71 : : * Note: when this is called, we are actually already inside a valid
72 : : * transaction, since XIDs are now not allocated until the transaction
73 : : * does something. So it is safe to do a database lookup if we want to
74 : : * issue a warning about XID wrap.
75 : : */
76 : : FullTransactionId
7227 tgl@sss.pgh.pa.us 77 :CBC 24481574 : GetNewTransactionId(bool isSubXact)
78 : : {
79 : : FullTransactionId full_xid;
80 : : TransactionId xid;
81 : :
82 : : /*
83 : : * Workers synchronize transaction state at the beginning of each parallel
84 : : * operation, so we can't account for new XIDs after that point.
85 : : */
3272 rhaas@postgresql.org 86 [ - + ]: 24481574 : if (IsInParallelMode())
3272 rhaas@postgresql.org 87 [ # # ]:UBC 0 : elog(ERROR, "cannot assign TransactionIds during a parallel operation");
88 : :
89 : : /*
90 : : * During bootstrap initialization, we return the special bootstrap
91 : : * transaction id.
92 : : */
6993 tgl@sss.pgh.pa.us 93 [ + + ]:CBC 24481574 : if (IsBootstrapProcessingMode())
94 : : {
6063 95 [ - + ]: 39 : Assert(!isSubXact);
1339 andres@anarazel.de 96 : 39 : MyProc->xid = BootstrapTransactionId;
97 : 39 : ProcGlobal->xids[MyProc->pgxactoff] = BootstrapTransactionId;
1844 tmunro@postgresql.or 98 : 39 : return FullTransactionIdFromEpochAndXid(0, BootstrapTransactionId);
99 : : }
100 : :
101 : : /* safety check, we should never get this far in a HS standby */
5167 tgl@sss.pgh.pa.us 102 [ - + ]: 24481535 : if (RecoveryInProgress())
5167 tgl@sss.pgh.pa.us 103 [ # # ]:UBC 0 : elog(ERROR, "cannot assign TransactionIds during recovery");
104 : :
8233 tgl@sss.pgh.pa.us 105 :CBC 24481535 : LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
106 : :
128 heikki.linnakangas@i 107 :GNC 24481535 : full_xid = TransamVariables->nextXid;
1844 tmunro@postgresql.or 108 :CBC 24481535 : xid = XidFromFullTransactionId(full_xid);
109 : :
110 : : /*----------
111 : : * Check to see if it's safe to assign another XID. This protects against
112 : : * catastrophic data loss due to XID wraparound. The basic rules are:
113 : : *
114 : : * If we're past xidVacLimit, start trying to force autovacuum cycles.
115 : : * If we're past xidWarnLimit, start issuing warnings.
116 : : * If we're past xidStopLimit, refuse to execute transactions, unless
117 : : * we are running in single-user mode (which gives an escape hatch
118 : : * to the DBA who somehow got past the earlier defenses).
119 : : *
120 : : * Note that this coding also appears in GetNewMultiXactId.
121 : : *----------
122 : : */
128 heikki.linnakangas@i 123 [ + + ]:GNC 24481535 : if (TransactionIdFollowsOrEquals(xid, TransamVariables->xidVacLimit))
124 : : {
125 : : /*
126 : : * For safety's sake, we release XidGenLock while sending signals,
127 : : * warnings, etc. This is not so much because we care about
128 : : * preserving concurrency in this situation, as to avoid any
129 : : * possibility of deadlock while doing get_database_name(). First,
130 : : * copy all the shared values we'll need in this path.
131 : : */
132 : 9909264 : TransactionId xidWarnLimit = TransamVariables->xidWarnLimit;
133 : 9909264 : TransactionId xidStopLimit = TransamVariables->xidStopLimit;
134 : 9909264 : TransactionId xidWrapLimit = TransamVariables->xidWrapLimit;
135 : 9909264 : Oid oldest_datoid = TransamVariables->oldestXidDB;
136 : :
5340 tgl@sss.pgh.pa.us 137 :GBC 9909264 : LWLockRelease(XidGenLock);
138 : :
139 : : /*
140 : : * To avoid swamping the postmaster with signals, we issue the autovac
141 : : * request only once per 64K transaction starts. This still gives
142 : : * plenty of chances before we get into real trouble.
143 : : */
6370 144 [ + - + + ]: 9909264 : if (IsUnderPostmaster && (xid % 65536) == 0)
6268 alvherre@alvh.no-ip. 145 : 88242 : SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
146 : :
6993 tgl@sss.pgh.pa.us 147 [ + - + + ]: 19818528 : if (IsUnderPostmaster &&
5340 148 : 9909264 : TransactionIdFollowsOrEquals(xid, xidStopLimit))
149 : : {
5161 bruce@momjian.us 150 : 4 : char *oldest_datname = get_database_name(oldest_datoid);
151 : :
152 : : /* complain even if that DB has disappeared */
5340 tgl@sss.pgh.pa.us 153 [ + - ]: 4 : if (oldest_datname)
154 [ + - ]: 4 : ereport(ERROR,
155 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
156 : : errmsg("database is not accepting commands that assign new XIDs to avoid wraparound data loss in database \"%s\"",
157 : : oldest_datname),
158 : : errhint("Execute a database-wide VACUUM in that database.\n"
159 : : "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
160 : : else
5340 tgl@sss.pgh.pa.us 161 [ # # ]:UBC 0 : ereport(ERROR,
162 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
163 : : errmsg("database is not accepting commands that assign new XIDs to avoid wraparound data loss in database with OID %u",
164 : : oldest_datoid),
165 : : errhint("Execute a database-wide VACUUM in that database.\n"
166 : : "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
167 : : }
5340 tgl@sss.pgh.pa.us 168 [ + + ]:GBC 9909260 : else if (TransactionIdFollowsOrEquals(xid, xidWarnLimit))
169 : : {
5161 bruce@momjian.us 170 : 64938 : char *oldest_datname = get_database_name(oldest_datoid);
171 : :
172 : : /* complain even if that DB has disappeared */
5340 tgl@sss.pgh.pa.us 173 [ + - ]: 64938 : if (oldest_datname)
174 [ + - ]: 64938 : ereport(WARNING,
175 : : (errmsg("database \"%s\" must be vacuumed within %u transactions",
176 : : oldest_datname,
177 : : xidWrapLimit - xid),
178 : : errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
179 : : "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
180 : : else
5340 tgl@sss.pgh.pa.us 181 [ # # ]:UBC 0 : ereport(WARNING,
182 : : (errmsg("database with OID %u must be vacuumed within %u transactions",
183 : : oldest_datoid,
184 : : xidWrapLimit - xid),
185 : : errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
186 : : "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
187 : : }
188 : :
189 : : /* Re-acquire lock and start over */
5340 tgl@sss.pgh.pa.us 190 :GBC 9909260 : LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
128 heikki.linnakangas@i 191 :GNC 9909260 : full_xid = TransamVariables->nextXid;
1829 tmunro@postgresql.or 192 :GBC 9909260 : xid = XidFromFullTransactionId(full_xid);
193 : : }
194 : :
195 : : /*
196 : : * If we are allocating the first XID of a new page of the commit log,
197 : : * zero out that commit-log page before returning. We must do this while
198 : : * holding XidGenLock, else another xact could acquire and commit a later
199 : : * XID before we zero the page. Fortunately, a page of the commit log
200 : : * holds 32K or more transactions, so we don't have to do this very often.
201 : : *
202 : : * Extend pg_subtrans and pg_commit_ts too.
203 : : */
8268 tgl@sss.pgh.pa.us 204 :CBC 24481531 : ExtendCLOG(xid);
3420 alvherre@alvh.no-ip. 205 : 24481531 : ExtendCommitTs(xid);
7227 tgl@sss.pgh.pa.us 206 : 24481531 : ExtendSUBTRANS(xid);
207 : :
208 : : /*
209 : : * Now advance the nextXid counter. This must not happen until after we
210 : : * have successfully completed ExtendCLOG() --- if that routine fails, we
211 : : * want the next incoming transaction to try it again. We cannot assign
212 : : * more XIDs until there is CLOG space for them.
213 : : */
128 heikki.linnakangas@i 214 :GNC 24481531 : FullTransactionIdAdvance(&TransamVariables->nextXid);
215 : :
216 : : /*
217 : : * We must store the new XID into the shared ProcArray before releasing
218 : : * XidGenLock. This ensures that every active XID older than
219 : : * latestCompletedXid is present in the ProcArray, which is essential for
220 : : * correct OldestXmin tracking; see src/backend/access/transam/README.
221 : : *
222 : : * Note that readers of ProcGlobal->xids/PGPROC->xid should be careful to
223 : : * fetch the value for each proc only once, rather than assume they can
224 : : * read a value multiple times and get the same answer each time. Note we
225 : : * are assuming that TransactionId and int fetch/store are atomic.
226 : : *
227 : : * The same comments apply to the subxact xid count and overflow fields.
228 : : *
229 : : * Use of a write barrier prevents dangerous code rearrangement in this
230 : : * function; other backends could otherwise e.g. be examining my subxids
231 : : * info concurrently, and we don't want them to see an invalid
232 : : * intermediate state, such as an incremented nxids before the array entry
233 : : * is filled.
234 : : *
235 : : * Other processes that read nxids should do so before reading xids
236 : : * elements with a pg_read_barrier() in between, so that they can be sure
237 : : * not to read an uninitialized array element; see
238 : : * src/backend/storage/lmgr/README.barrier.
239 : : *
240 : : * If there's no room to fit a subtransaction XID into PGPROC, set the
241 : : * cache-overflowed flag instead. This forces readers to look in
242 : : * pg_subtrans to map subtransaction XIDs up to top-level XIDs. There is a
243 : : * race-condition window, in that the new XID will not appear as running
244 : : * until its parent link has been placed into pg_subtrans. However, that
245 : : * will happen before anyone could possibly have a reason to inquire about
246 : : * the status of the XID, so it seems OK. (Snapshots taken during this
247 : : * window *will* include the parent XID, so they will deliver the correct
248 : : * answer later on when someone does have a reason to inquire.)
249 : : */
1983 andres@anarazel.de 250 [ + + ]:CBC 24481531 : if (!isSubXact)
251 : : {
1339 252 [ - + ]: 113580 : Assert(ProcGlobal->subxidStates[MyProc->pgxactoff].count == 0);
253 [ - + ]: 113580 : Assert(!ProcGlobal->subxidStates[MyProc->pgxactoff].overflowed);
254 [ - + ]: 113580 : Assert(MyProc->subxidStatus.count == 0);
255 [ - + ]: 113580 : Assert(!MyProc->subxidStatus.overflowed);
256 : :
257 : : /* LWLockRelease acts as barrier */
258 : 113580 : MyProc->xid = xid;
259 : 113580 : ProcGlobal->xids[MyProc->pgxactoff] = xid;
260 : : }
261 : : else
262 : : {
263 : 24367951 : XidCacheStatus *substat = &ProcGlobal->subxidStates[MyProc->pgxactoff];
264 : 24367951 : int nxids = MyProc->subxidStatus.count;
265 : :
266 [ - + ]: 24367951 : Assert(substat->count == MyProc->subxidStatus.count);
267 [ - + ]: 24367951 : Assert(substat->overflowed == MyProc->subxidStatus.overflowed);
268 : :
1983 269 [ + + ]: 24367951 : if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
270 : : {
271 : 9468 : MyProc->subxids.xids[nxids] = xid;
272 : 9468 : pg_write_barrier();
1339 273 : 9468 : MyProc->subxidStatus.count = substat->count = nxids + 1;
274 : : }
275 : : else
276 : 24358483 : MyProc->subxidStatus.overflowed = substat->overflowed = true;
277 : : }
278 : :
8233 tgl@sss.pgh.pa.us 279 : 24481531 : LWLockRelease(XidGenLock);
280 : :
1844 tmunro@postgresql.or 281 : 24481531 : return full_xid;
282 : : }
283 : :
284 : : /*
285 : : * Read nextXid but don't allocate it.
286 : : */
287 : : FullTransactionId
288 : 250965 : ReadNextFullTransactionId(void)
289 : : {
290 : : FullTransactionId fullXid;
291 : :
8233 tgl@sss.pgh.pa.us 292 : 250965 : LWLockAcquire(XidGenLock, LW_SHARED);
128 heikki.linnakangas@i 293 :GNC 250965 : fullXid = TransamVariables->nextXid;
8233 tgl@sss.pgh.pa.us 294 :CBC 250965 : LWLockRelease(XidGenLock);
295 : :
1844 tmunro@postgresql.or 296 : 250965 : return fullXid;
297 : : }
298 : :
299 : : /*
300 : : * Advance nextXid to the value after a given xid. The epoch is inferred.
301 : : * This must only be called during recovery or from two-phase start-up code.
302 : : */
303 : : void
304 : 3028300 : AdvanceNextFullTransactionIdPastXid(TransactionId xid)
305 : : {
306 : : FullTransactionId newNextFullXid;
307 : : TransactionId next_xid;
308 : : uint32 epoch;
309 : :
310 : : /*
311 : : * It is safe to read nextXid without a lock, because this is only called
312 : : * from the startup process or single-process mode, meaning that no other
313 : : * process can modify it.
314 : : */
315 [ + + - + ]: 3028300 : Assert(AmStartupProcess() || !IsUnderPostmaster);
316 : :
317 : : /* Fast return if this isn't an xid high enough to move the needle. */
128 heikki.linnakangas@i 318 :GNC 3028300 : next_xid = XidFromFullTransactionId(TransamVariables->nextXid);
1844 tmunro@postgresql.or 319 [ + + ]:CBC 3028300 : if (!TransactionIdFollowsOrEquals(xid, next_xid))
320 : 3003645 : return;
321 : :
322 : : /*
323 : : * Compute the FullTransactionId that comes after the given xid. To do
324 : : * this, we preserve the existing epoch, but detect when we've wrapped
325 : : * into a new epoch. This is necessary because WAL records and 2PC state
326 : : * currently contain 32 bit xids. The wrap logic is safe in those cases
327 : : * because the span of active xids cannot exceed one epoch at any given
328 : : * point in the WAL stream.
329 : : */
330 [ - + ]: 24655 : TransactionIdAdvance(xid);
128 heikki.linnakangas@i 331 :GNC 24655 : epoch = EpochFromFullTransactionId(TransamVariables->nextXid);
1844 tmunro@postgresql.or 332 [ - + ]:CBC 24655 : if (unlikely(xid < next_xid))
1844 tmunro@postgresql.or 333 :UBC 0 : ++epoch;
1844 tmunro@postgresql.or 334 :CBC 24655 : newNextFullXid = FullTransactionIdFromEpochAndXid(epoch, xid);
335 : :
336 : : /*
337 : : * We still need to take a lock to modify the value when there are
338 : : * concurrent readers.
339 : : */
340 : 24655 : LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
128 heikki.linnakangas@i 341 :GNC 24655 : TransamVariables->nextXid = newNextFullXid;
1844 tmunro@postgresql.or 342 :CBC 24655 : LWLockRelease(XidGenLock);
343 : : }
344 : :
345 : : /*
346 : : * Advance the cluster-wide value for the oldest valid clog entry.
347 : : *
348 : : * We must acquire XactTruncationLock to advance the oldestClogXid. It's not
349 : : * necessary to hold the lock during the actual clog truncation, only when we
350 : : * advance the limit, as code looking up arbitrary xids is required to hold
351 : : * XactTruncationLock from when it tests oldestClogXid through to when it
352 : : * completes the clog lookup.
353 : : */
354 : : void
2579 rhaas@postgresql.org 355 : 913 : AdvanceOldestClogXid(TransactionId oldest_datfrozenxid)
356 : : {
1430 tgl@sss.pgh.pa.us 357 : 913 : LWLockAcquire(XactTruncationLock, LW_EXCLUSIVE);
128 heikki.linnakangas@i 358 [ + + ]:GNC 913 : if (TransactionIdPrecedes(TransamVariables->oldestClogXid,
359 : : oldest_datfrozenxid))
360 : : {
361 : 874 : TransamVariables->oldestClogXid = oldest_datfrozenxid;
362 : : }
1430 tgl@sss.pgh.pa.us 363 :CBC 913 : LWLockRelease(XactTruncationLock);
2579 rhaas@postgresql.org 364 : 913 : }
365 : :
366 : : /*
367 : : * Determine the last safe XID to allocate using the currently oldest
368 : : * datfrozenxid (ie, the oldest XID that might exist in any database
369 : : * of our cluster), and the OID of the (or a) database with that value.
370 : : */
371 : : void
5340 tgl@sss.pgh.pa.us 372 : 1650 : SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
373 : : {
374 : : TransactionId xidVacLimit;
375 : : TransactionId xidWarnLimit;
376 : : TransactionId xidStopLimit;
377 : : TransactionId xidWrapLimit;
378 : : TransactionId curXid;
379 : :
6370 380 [ - + ]: 1650 : Assert(TransactionIdIsNormal(oldest_datfrozenxid));
381 : :
382 : : /*
383 : : * The place where we actually get into deep trouble is halfway around
384 : : * from the oldest potentially-existing XID. (This calculation is
385 : : * probably off by one or two counts, because the special XIDs reduce the
386 : : * size of the loop a little bit. But we throw in plenty of slop below,
387 : : * so it doesn't matter.)
388 : : */
389 : 1650 : xidWrapLimit = oldest_datfrozenxid + (MaxTransactionId >> 1);
6993 390 [ - + ]: 1650 : if (xidWrapLimit < FirstNormalTransactionId)
6993 tgl@sss.pgh.pa.us 391 :UBC 0 : xidWrapLimit += FirstNormalTransactionId;
392 : :
393 : : /*
394 : : * We'll refuse to continue assigning XIDs in interactive mode once we get
395 : : * within 3M transactions of data loss. This leaves lots of room for the
396 : : * DBA to fool around fixing things in a standalone backend, while not
397 : : * being significant compared to total XID space. (VACUUM requires an XID
398 : : * if it truncates at wal_level!=minimal. "VACUUM (ANALYZE)", which a DBA
399 : : * might do by reflex, assigns an XID. Hence, we had better be sure
400 : : * there's lots of XIDs left...) Also, at default BLCKSZ, this leaves two
401 : : * completely-idle segments. In the event of edge-case bugs involving
402 : : * page or segment arithmetic, idle segments render the bugs unreachable
403 : : * outside of single-user mode.
404 : : */
1352 noah@leadboat.com 405 :CBC 1650 : xidStopLimit = xidWrapLimit - 3000000;
6993 tgl@sss.pgh.pa.us 406 [ - + ]: 1650 : if (xidStopLimit < FirstNormalTransactionId)
6993 tgl@sss.pgh.pa.us 407 :UBC 0 : xidStopLimit -= FirstNormalTransactionId;
408 : :
409 : : /*
410 : : * We'll start complaining loudly when we get within 40M transactions of
411 : : * data loss. This is kind of arbitrary, but if you let your gas gauge
412 : : * get down to 2% of full, would you be looking for the next gas station?
413 : : * We need to be fairly liberal about this number because there are lots
414 : : * of scenarios where most transactions are done by automatic clients that
415 : : * won't pay attention to warnings. (No, we're not gonna make this
416 : : * configurable. If you know enough to configure it, you know enough to
417 : : * not get in this kind of trouble in the first place.)
418 : : */
1352 noah@leadboat.com 419 :CBC 1650 : xidWarnLimit = xidWrapLimit - 40000000;
6993 tgl@sss.pgh.pa.us 420 [ - + ]: 1650 : if (xidWarnLimit < FirstNormalTransactionId)
6993 tgl@sss.pgh.pa.us 421 :UBC 0 : xidWarnLimit -= FirstNormalTransactionId;
422 : :
423 : : /*
424 : : * We'll start trying to force autovacuums when oldest_datfrozenxid gets
425 : : * to be more than autovacuum_freeze_max_age transactions old.
426 : : *
427 : : * Note: guc.c ensures that autovacuum_freeze_max_age is in a sane range,
428 : : * so that xidVacLimit will be well before xidWarnLimit.
429 : : *
430 : : * Note: autovacuum_freeze_max_age is a PGC_POSTMASTER parameter so that
431 : : * we don't have to worry about dealing with on-the-fly changes in its
432 : : * value. It doesn't look practical to update shared state from a GUC
433 : : * assign hook (too many processes would try to execute the hook,
434 : : * resulting in race conditions as well as crashes of those not connected
435 : : * to shared memory). Perhaps this can be improved someday. See also
436 : : * SetMultiXactIdLimit.
437 : : */
6370 tgl@sss.pgh.pa.us 438 :CBC 1650 : xidVacLimit = oldest_datfrozenxid + autovacuum_freeze_max_age;
439 [ - + ]: 1650 : if (xidVacLimit < FirstNormalTransactionId)
6370 tgl@sss.pgh.pa.us 440 :UBC 0 : xidVacLimit += FirstNormalTransactionId;
441 : :
442 : : /* Grab lock for just long enough to set the new limit values */
6993 tgl@sss.pgh.pa.us 443 :CBC 1650 : LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
128 heikki.linnakangas@i 444 :GNC 1650 : TransamVariables->oldestXid = oldest_datfrozenxid;
445 : 1650 : TransamVariables->xidVacLimit = xidVacLimit;
446 : 1650 : TransamVariables->xidWarnLimit = xidWarnLimit;
447 : 1650 : TransamVariables->xidStopLimit = xidStopLimit;
448 : 1650 : TransamVariables->xidWrapLimit = xidWrapLimit;
449 : 1650 : TransamVariables->oldestXidDB = oldest_datoid;
450 : 1650 : curXid = XidFromFullTransactionId(TransamVariables->nextXid);
6993 tgl@sss.pgh.pa.us 451 :CBC 1650 : LWLockRelease(XidGenLock);
452 : :
453 : : /* Log the info */
6410 alvherre@alvh.no-ip. 454 [ + + ]: 1650 : ereport(DEBUG1,
455 : : (errmsg_internal("transaction ID wrap limit is %u, limited by database with OID %u",
456 : : xidWrapLimit, oldest_datoid)));
457 : :
458 : : /*
459 : : * If past the autovacuum force point, immediately signal an autovac
460 : : * request. The reason for this is that autovac only processes one
461 : : * database per invocation. Once it's finished cleaning up the oldest
462 : : * database, it'll call here, and we'll signal the postmaster to start
463 : : * another iteration immediately if there are still any old databases.
464 : : */
6370 tgl@sss.pgh.pa.us 465 [ + + + - ]: 1650 : if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) &&
5170 tgl@sss.pgh.pa.us 466 [ + - ]:GBC 625 : IsUnderPostmaster && !InRecovery)
6268 alvherre@alvh.no-ip. 467 : 625 : SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
468 : :
469 : : /* Give an immediate warning if past the wrap warn point */
5170 tgl@sss.pgh.pa.us 470 [ + + + - ]:CBC 1650 : if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit) && !InRecovery)
471 : : {
472 : : char *oldest_datname;
473 : :
474 : : /*
475 : : * We can be called when not inside a transaction, for example during
476 : : * StartupXLOG(). In such a case we cannot do database access, so we
477 : : * must just report the oldest DB's OID.
478 : : *
479 : : * Note: it's also possible that get_database_name fails and returns
480 : : * NULL, for example because the database just got dropped. We'll
481 : : * still warn, even though the warning might now be unnecessary.
482 : : */
4925 tgl@sss.pgh.pa.us 483 [ + - ]:GBC 53 : if (IsTransactionState())
484 : 53 : oldest_datname = get_database_name(oldest_datoid);
485 : : else
4925 tgl@sss.pgh.pa.us 486 :UBC 0 : oldest_datname = NULL;
487 : :
5340 tgl@sss.pgh.pa.us 488 [ + - ]:GBC 53 : if (oldest_datname)
489 [ + - ]: 53 : ereport(WARNING,
490 : : (errmsg("database \"%s\" must be vacuumed within %u transactions",
491 : : oldest_datname,
492 : : xidWrapLimit - curXid),
493 : : errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
494 : : "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
495 : : else
5340 tgl@sss.pgh.pa.us 496 [ # # ]:UBC 0 : ereport(WARNING,
497 : : (errmsg("database with OID %u must be vacuumed within %u transactions",
498 : : oldest_datoid,
499 : : xidWrapLimit - curXid),
500 : : errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
501 : : "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
502 : : }
5340 tgl@sss.pgh.pa.us 503 :CBC 1650 : }
504 : :
505 : :
506 : : /*
507 : : * ForceTransactionIdLimitUpdate -- does the XID wrap-limit data need updating?
508 : : *
509 : : * We primarily check whether oldestXidDB is valid. The cases we have in
510 : : * mind are that that database was dropped, or the field was reset to zero
511 : : * by pg_resetwal. In either case we should force recalculation of the
512 : : * wrap limit. Also do it if oldestXid is old enough to be forcing
513 : : * autovacuums or other actions; this ensures we update our state as soon
514 : : * as possible once extra overhead is being incurred.
515 : : */
516 : : bool
5339 517 : 1271 : ForceTransactionIdLimitUpdate(void)
518 : : {
519 : : TransactionId nextXid;
520 : : TransactionId xidVacLimit;
521 : : TransactionId oldestXid;
522 : : Oid oldestXidDB;
523 : :
524 : : /* Locking is probably not really necessary, but let's be careful */
5340 525 : 1271 : LWLockAcquire(XidGenLock, LW_SHARED);
128 heikki.linnakangas@i 526 :GNC 1271 : nextXid = XidFromFullTransactionId(TransamVariables->nextXid);
527 : 1271 : xidVacLimit = TransamVariables->xidVacLimit;
528 : 1271 : oldestXid = TransamVariables->oldestXid;
529 : 1271 : oldestXidDB = TransamVariables->oldestXidDB;
5340 tgl@sss.pgh.pa.us 530 :CBC 1271 : LWLockRelease(XidGenLock);
531 : :
532 [ - + ]: 1271 : if (!TransactionIdIsNormal(oldestXid))
5339 tgl@sss.pgh.pa.us 533 :UBC 0 : return true; /* shouldn't happen, but just in case */
5170 tgl@sss.pgh.pa.us 534 [ - + ]:CBC 1271 : if (!TransactionIdIsValid(xidVacLimit))
5170 tgl@sss.pgh.pa.us 535 :UBC 0 : return true; /* this shouldn't happen anymore either */
5170 tgl@sss.pgh.pa.us 536 [ + + ]:CBC 1271 : if (TransactionIdFollowsOrEquals(nextXid, xidVacLimit))
1700 michael@paquier.xyz 537 :GBC 517 : return true; /* past xidVacLimit, don't delay updating */
5173 rhaas@postgresql.org 538 [ + + ]:CBC 754 : if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(oldestXidDB)))
5339 tgl@sss.pgh.pa.us 539 :GBC 1 : return true; /* could happen, per comments above */
5339 tgl@sss.pgh.pa.us 540 :CBC 753 : return false;
541 : : }
542 : :
543 : :
544 : : /*
545 : : * GetNewObjectId -- allocate a new OID
546 : : *
547 : : * OIDs are generated by a cluster-wide counter. Since they are only 32 bits
548 : : * wide, counter wraparound will occur eventually, and therefore it is unwise
549 : : * to assume they are unique unless precautions are taken to make them so.
550 : : * Hence, this routine should generally not be used directly. The only direct
551 : : * callers should be GetNewOidWithIndex() and GetNewRelFileNumber() in
552 : : * catalog/catalog.c.
553 : : */
554 : : Oid
8283 555 : 471938 : GetNewObjectId(void)
556 : : {
557 : : Oid result;
558 : :
559 : : /* safety check, we should never get this far in a HS standby */
5167 560 [ - + ]: 471938 : if (RecoveryInProgress())
5167 tgl@sss.pgh.pa.us 561 [ # # ]:UBC 0 : elog(ERROR, "cannot assign OIDs during recovery");
562 : :
8233 tgl@sss.pgh.pa.us 563 :CBC 471938 : LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
564 : :
565 : : /*
566 : : * Check for wraparound of the OID counter. We *must* not return 0
567 : : * (InvalidOid), and in normal operation we mustn't return anything below
568 : : * FirstNormalObjectId since that range is reserved for initdb (see
569 : : * IsCatalogRelationOid()). Note we are relying on unsigned comparison.
570 : : *
571 : : * During initdb, we start the OID generator at FirstGenbkiObjectId, so we
572 : : * only wrap if before that point when in bootstrap or standalone mode.
573 : : * The first time through this routine after normal postmaster start, the
574 : : * counter will be forced up to FirstNormalObjectId. This mechanism
575 : : * leaves the OIDs between FirstGenbkiObjectId and FirstNormalObjectId
576 : : * available for automatic assignment during initdb, while ensuring they
577 : : * will never conflict with user-assigned OIDs.
578 : : */
128 heikki.linnakangas@i 579 [ + + ]:GNC 471938 : if (TransamVariables->nextOid < ((Oid) FirstNormalObjectId))
580 : : {
6941 tgl@sss.pgh.pa.us 581 [ + + ]:CBC 91447 : if (IsPostmasterEnvironment)
582 : : {
583 : : /* wraparound, or first post-initdb assignment, in normal mode */
128 heikki.linnakangas@i 584 :GNC 308 : TransamVariables->nextOid = FirstNormalObjectId;
585 : 308 : TransamVariables->oidCount = 0;
586 : : }
587 : : else
588 : : {
589 : : /* we may be bootstrapping, so don't enforce the full range */
590 [ - + ]: 91139 : if (TransamVariables->nextOid < ((Oid) FirstGenbkiObjectId))
591 : : {
592 : : /* wraparound in standalone mode (unlikely but possible) */
128 heikki.linnakangas@i 593 :UNC 0 : TransamVariables->nextOid = FirstNormalObjectId;
594 : 0 : TransamVariables->oidCount = 0;
595 : : }
596 : : }
597 : : }
598 : :
599 : : /* If we run out of logged for use oids then we must log more */
128 heikki.linnakangas@i 600 [ + + ]:GNC 471938 : if (TransamVariables->oidCount == 0)
601 : : {
602 : 505 : XLogPutNextOid(TransamVariables->nextOid + VAR_OID_PREFETCH);
603 : 505 : TransamVariables->oidCount = VAR_OID_PREFETCH;
604 : : }
605 : :
606 : 471938 : result = TransamVariables->nextOid;
607 : :
608 : 471938 : (TransamVariables->nextOid)++;
609 : 471938 : (TransamVariables->oidCount)--;
610 : :
8233 tgl@sss.pgh.pa.us 611 :CBC 471938 : LWLockRelease(OidGenLock);
612 : :
8283 613 : 471938 : return result;
614 : : }
615 : :
616 : : /*
617 : : * SetNextObjectId
618 : : *
619 : : * This may only be called during initdb; it advances the OID counter
620 : : * to the specified value.
621 : : */
622 : : static void
1004 623 : 37 : SetNextObjectId(Oid nextOid)
624 : : {
625 : : /* Safety check, this is only allowable during initdb */
626 [ - + ]: 37 : if (IsPostmasterEnvironment)
1004 tgl@sss.pgh.pa.us 627 [ # # ]:UBC 0 : elog(ERROR, "cannot advance OID counter anymore");
628 : :
629 : : /* Taking the lock is, therefore, just pro forma; but do it anyway */
1004 tgl@sss.pgh.pa.us 630 :CBC 37 : LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
631 : :
128 heikki.linnakangas@i 632 [ - + ]:GNC 37 : if (TransamVariables->nextOid > nextOid)
1004 tgl@sss.pgh.pa.us 633 [ # # ]:UBC 0 : elog(ERROR, "too late to advance OID counter to %u, it is now %u",
634 : : nextOid, TransamVariables->nextOid);
635 : :
128 heikki.linnakangas@i 636 :GNC 37 : TransamVariables->nextOid = nextOid;
637 : 37 : TransamVariables->oidCount = 0;
638 : :
1004 tgl@sss.pgh.pa.us 639 :CBC 37 : LWLockRelease(OidGenLock);
640 : 37 : }
641 : :
642 : : /*
643 : : * StopGeneratingPinnedObjectIds
644 : : *
645 : : * This is called once during initdb to force the OID counter up to
646 : : * FirstUnpinnedObjectId. This supports letting initdb's post-bootstrap
647 : : * processing create some pinned objects early on. Once it's done doing
648 : : * so, it calls this (via pg_stop_making_pinned_objects()) so that the
649 : : * remaining objects it makes will be considered un-pinned.
650 : : */
651 : : void
652 : 37 : StopGeneratingPinnedObjectIds(void)
653 : : {
654 : 37 : SetNextObjectId(FirstUnpinnedObjectId);
655 : 37 : }
656 : :
657 : :
658 : : #ifdef USE_ASSERT_CHECKING
659 : :
660 : : /*
661 : : * Assert that xid is between [oldestXid, nextXid], which is the range we
662 : : * expect XIDs coming from tables etc to be in.
663 : : *
664 : : * As TransamVariables->oldestXid could change just after this call without
665 : : * further precautions, and as a wrapped-around xid could again fall within
666 : : * the valid range, this assertion can only detect if something is definitely
667 : : * wrong, but not establish correctness.
668 : : *
669 : : * This intentionally does not expose a return value, to avoid code being
670 : : * introduced that depends on the return value.
671 : : */
672 : : void
1342 andres@anarazel.de 673 : 11457016 : AssertTransactionIdInAllowableRange(TransactionId xid)
674 : : {
675 : : TransactionId oldest_xid;
676 : : TransactionId next_xid;
677 : :
678 [ - + ]: 11457016 : Assert(TransactionIdIsValid(xid));
679 : :
680 : : /* we may see bootstrap / frozen */
681 [ - + ]: 11457016 : if (!TransactionIdIsNormal(xid))
1342 andres@anarazel.de 682 :UBC 0 : return;
683 : :
684 : : /*
685 : : * We can't acquire XidGenLock, as this may be called with XidGenLock
686 : : * already held (or with other locks that don't allow XidGenLock to be
687 : : * nested). That's ok for our purposes though, since we already rely on
688 : : * 32bit reads to be atomic. While nextXid is 64 bit, we only look at the
689 : : * lower 32bit, so a skewed read doesn't hurt.
690 : : *
691 : : * There's no increased danger of falling outside [oldest, next] by
692 : : * accessing them without a lock. xid needs to have been created with
693 : : * GetNewTransactionId() in the originating session, and the locks there
694 : : * pair with the memory barrier below. We do however accept xid to be <=
695 : : * to next_xid, instead of just <, as xid could be from the procarray,
696 : : * before we see the updated nextXid value.
697 : : */
1342 andres@anarazel.de 698 :CBC 11457016 : pg_memory_barrier();
128 heikki.linnakangas@i 699 :GNC 11457016 : oldest_xid = TransamVariables->oldestXid;
700 : 11457016 : next_xid = XidFromFullTransactionId(TransamVariables->nextXid);
701 : :
1342 andres@anarazel.de 702 [ - + - - ]:CBC 11457016 : Assert(TransactionIdFollowsOrEquals(xid, oldest_xid) ||
703 : : TransactionIdPrecedesOrEquals(xid, next_xid));
704 : : }
705 : : #endif
|