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