LCOV - code coverage report
Current view: top level - src/backend/access/transam - varsup.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 86 128 67.2 %
Date: 2017-09-29 15:12:54 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * varsup.c
       4             :  *    postgres OID & XID variables support routines
       5             :  *
       6             :  * Copyright (c) 2000-2017, 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/xlog.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 XID for a new transaction or subtransaction.
      39             :  *
      40             :  * The new XID is also stored into MyPgXact before returning.
      41             :  *
      42             :  * Note: when this is called, we are actually already inside a valid
      43             :  * transaction, since XIDs are now not allocated until the transaction
      44             :  * does something.  So it is safe to do a database lookup if we want to
      45             :  * issue a warning about XID wrap.
      46             :  */
      47             : TransactionId
      48       10658 : GetNewTransactionId(bool isSubXact)
      49             : {
      50             :     TransactionId xid;
      51             : 
      52             :     /*
      53             :      * Workers synchronize transaction state at the beginning of each parallel
      54             :      * operation, so we can't account for new XIDs after that point.
      55             :      */
      56       10658 :     if (IsInParallelMode())
      57           0 :         elog(ERROR, "cannot assign TransactionIds during a parallel operation");
      58             : 
      59             :     /*
      60             :      * During bootstrap initialization, we return the special bootstrap
      61             :      * transaction id.
      62             :      */
      63       10658 :     if (IsBootstrapProcessingMode())
      64             :     {
      65           1 :         Assert(!isSubXact);
      66           1 :         MyPgXact->xid = BootstrapTransactionId;
      67           1 :         return BootstrapTransactionId;
      68             :     }
      69             : 
      70             :     /* safety check, we should never get this far in a HS standby */
      71       10657 :     if (RecoveryInProgress())
      72           0 :         elog(ERROR, "cannot assign TransactionIds during recovery");
      73             : 
      74       10657 :     LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
      75             : 
      76       10657 :     xid = ShmemVariableCache->nextXid;
      77             : 
      78             :     /*----------
      79             :      * Check to see if it's safe to assign another XID.  This protects against
      80             :      * catastrophic data loss due to XID wraparound.  The basic rules are:
      81             :      *
      82             :      * If we're past xidVacLimit, start trying to force autovacuum cycles.
      83             :      * If we're past xidWarnLimit, start issuing warnings.
      84             :      * If we're past xidStopLimit, refuse to execute transactions, unless
      85             :      * we are running in single-user mode (which gives an escape hatch
      86             :      * to the DBA who somehow got past the earlier defenses).
      87             :      *
      88             :      * Note that this coding also appears in GetNewMultiXactId.
      89             :      *----------
      90             :      */
      91       10657 :     if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidVacLimit))
      92             :     {
      93             :         /*
      94             :          * For safety's sake, we release XidGenLock while sending signals,
      95             :          * warnings, etc.  This is not so much because we care about
      96             :          * preserving concurrency in this situation, as to avoid any
      97             :          * possibility of deadlock while doing get_database_name(). First,
      98             :          * copy all the shared values we'll need in this path.
      99             :          */
     100           0 :         TransactionId xidWarnLimit = ShmemVariableCache->xidWarnLimit;
     101           0 :         TransactionId xidStopLimit = ShmemVariableCache->xidStopLimit;
     102           0 :         TransactionId xidWrapLimit = ShmemVariableCache->xidWrapLimit;
     103           0 :         Oid         oldest_datoid = ShmemVariableCache->oldestXidDB;
     104             : 
     105           0 :         LWLockRelease(XidGenLock);
     106             : 
     107             :         /*
     108             :          * To avoid swamping the postmaster with signals, we issue the autovac
     109             :          * request only once per 64K transaction starts.  This still gives
     110             :          * plenty of chances before we get into real trouble.
     111             :          */
     112           0 :         if (IsUnderPostmaster && (xid % 65536) == 0)
     113           0 :             SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
     114             : 
     115           0 :         if (IsUnderPostmaster &&
     116           0 :             TransactionIdFollowsOrEquals(xid, xidStopLimit))
     117             :         {
     118           0 :             char       *oldest_datname = get_database_name(oldest_datoid);
     119             : 
     120             :             /* complain even if that DB has disappeared */
     121           0 :             if (oldest_datname)
     122           0 :                 ereport(ERROR,
     123             :                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     124             :                          errmsg("database is not accepting commands to avoid wraparound data loss in database \"%s\"",
     125             :                                 oldest_datname),
     126             :                          errhint("Stop the postmaster and vacuum that database in single-user mode.\n"
     127             :                                  "You might also need to commit or roll back old prepared transactions.")));
     128             :             else
     129           0 :                 ereport(ERROR,
     130             :                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     131             :                          errmsg("database is not accepting commands to avoid wraparound data loss in database with OID %u",
     132             :                                 oldest_datoid),
     133             :                          errhint("Stop the postmaster and vacuum that database in single-user mode.\n"
     134             :                                  "You might also need to commit or roll back old prepared transactions.")));
     135             :         }
     136           0 :         else if (TransactionIdFollowsOrEquals(xid, xidWarnLimit))
     137             :         {
     138           0 :             char       *oldest_datname = get_database_name(oldest_datoid);
     139             : 
     140             :             /* complain even if that DB has disappeared */
     141           0 :             if (oldest_datname)
     142           0 :                 ereport(WARNING,
     143             :                         (errmsg("database \"%s\" must be vacuumed within %u transactions",
     144             :                                 oldest_datname,
     145             :                                 xidWrapLimit - xid),
     146             :                          errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
     147             :                                  "You might also need to commit or roll back old prepared transactions.")));
     148             :             else
     149           0 :                 ereport(WARNING,
     150             :                         (errmsg("database with OID %u must be vacuumed within %u transactions",
     151             :                                 oldest_datoid,
     152             :                                 xidWrapLimit - xid),
     153             :                          errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
     154             :                                  "You might also need to commit or roll back old prepared transactions.")));
     155             :         }
     156             : 
     157             :         /* Re-acquire lock and start over */
     158           0 :         LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
     159           0 :         xid = ShmemVariableCache->nextXid;
     160             :     }
     161             : 
     162             :     /*
     163             :      * If we are allocating the first XID of a new page of the commit log,
     164             :      * zero out that commit-log page before returning. We must do this while
     165             :      * holding XidGenLock, else another xact could acquire and commit a later
     166             :      * XID before we zero the page.  Fortunately, a page of the commit log
     167             :      * holds 32K or more transactions, so we don't have to do this very often.
     168             :      *
     169             :      * Extend pg_subtrans and pg_commit_ts too.
     170             :      */
     171       10657 :     ExtendCLOG(xid);
     172       10657 :     ExtendCommitTs(xid);
     173       10657 :     ExtendSUBTRANS(xid);
     174             : 
     175             :     /*
     176             :      * Now advance the nextXid counter.  This must not happen until after we
     177             :      * have successfully completed ExtendCLOG() --- if that routine fails, we
     178             :      * want the next incoming transaction to try it again.  We cannot assign
     179             :      * more XIDs until there is CLOG space for them.
     180             :      */
     181       10657 :     TransactionIdAdvance(ShmemVariableCache->nextXid);
     182             : 
     183             :     /*
     184             :      * We must store the new XID into the shared ProcArray before releasing
     185             :      * XidGenLock.  This ensures that every active XID older than
     186             :      * latestCompletedXid is present in the ProcArray, which is essential for
     187             :      * correct OldestXmin tracking; see src/backend/access/transam/README.
     188             :      *
     189             :      * XXX by storing xid into MyPgXact without acquiring ProcArrayLock, we
     190             :      * are relying on fetch/store of an xid to be atomic, else other backends
     191             :      * might see a partially-set xid here.  But holding both locks at once
     192             :      * would be a nasty concurrency hit.  So for now, assume atomicity.
     193             :      *
     194             :      * Note that readers of PGXACT xid fields should be careful to fetch the
     195             :      * value only once, rather than assume they can read a value multiple
     196             :      * times and get the same answer each time.
     197             :      *
     198             :      * The same comments apply to the subxact xid count and overflow fields.
     199             :      *
     200             :      * A solution to the atomic-store problem would be to give each PGXACT its
     201             :      * own spinlock used only for fetching/storing that PGXACT's xid and
     202             :      * related fields.
     203             :      *
     204             :      * If there's no room to fit a subtransaction XID into PGPROC, set the
     205             :      * cache-overflowed flag instead.  This forces readers to look in
     206             :      * pg_subtrans to map subtransaction XIDs up to top-level XIDs. There is a
     207             :      * race-condition window, in that the new XID will not appear as running
     208             :      * until its parent link has been placed into pg_subtrans. However, that
     209             :      * will happen before anyone could possibly have a reason to inquire about
     210             :      * the status of the XID, so it seems OK.  (Snapshots taken during this
     211             :      * window *will* include the parent XID, so they will deliver the correct
     212             :      * answer later on when someone does have a reason to inquire.)
     213             :      */
     214             :     {
     215             :         /*
     216             :          * Use volatile pointer to prevent code rearrangement; other backends
     217             :          * could be examining my subxids info concurrently, and we don't want
     218             :          * them to see an invalid intermediate state, such as incrementing
     219             :          * nxids before filling the array entry.  Note we are assuming that
     220             :          * TransactionId and int fetch/store are atomic.
     221             :          */
     222       10657 :         volatile PGPROC *myproc = MyProc;
     223       10657 :         volatile PGXACT *mypgxact = MyPgXact;
     224             : 
     225       10657 :         if (!isSubXact)
     226       10593 :             mypgxact->xid = xid;
     227             :         else
     228             :         {
     229          64 :             int         nxids = mypgxact->nxids;
     230             : 
     231          64 :             if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
     232             :             {
     233          64 :                 myproc->subxids.xids[nxids] = xid;
     234          64 :                 mypgxact->nxids = nxids + 1;
     235             :             }
     236             :             else
     237           0 :                 mypgxact->overflowed = true;
     238             :         }
     239             :     }
     240             : 
     241       10657 :     LWLockRelease(XidGenLock);
     242             : 
     243       10657 :     return xid;
     244             : }
     245             : 
     246             : /*
     247             :  * Read nextXid but don't allocate it.
     248             :  */
     249             : TransactionId
     250        1708 : ReadNewTransactionId(void)
     251             : {
     252             :     TransactionId xid;
     253             : 
     254        1708 :     LWLockAcquire(XidGenLock, LW_SHARED);
     255        1708 :     xid = ShmemVariableCache->nextXid;
     256        1708 :     LWLockRelease(XidGenLock);
     257             : 
     258        1708 :     return xid;
     259             : }
     260             : 
     261             : /*
     262             :  * Advance the cluster-wide value for the oldest valid clog entry.
     263             :  *
     264             :  * We must acquire CLogTruncationLock to advance the oldestClogXid. It's not
     265             :  * necessary to hold the lock during the actual clog truncation, only when we
     266             :  * advance the limit, as code looking up arbitrary xids is required to hold
     267             :  * CLogTruncationLock from when it tests oldestClogXid through to when it
     268             :  * completes the clog lookup.
     269             :  */
     270             : void
     271           4 : AdvanceOldestClogXid(TransactionId oldest_datfrozenxid)
     272             : {
     273           4 :     LWLockAcquire(CLogTruncationLock, LW_EXCLUSIVE);
     274           4 :     if (TransactionIdPrecedes(ShmemVariableCache->oldestClogXid,
     275             :                               oldest_datfrozenxid))
     276             :     {
     277           3 :         ShmemVariableCache->oldestClogXid = oldest_datfrozenxid;
     278             :     }
     279           4 :     LWLockRelease(CLogTruncationLock);
     280           4 : }
     281             : 
     282             : /*
     283             :  * Determine the last safe XID to allocate using the currently oldest
     284             :  * datfrozenxid (ie, the oldest XID that might exist in any database
     285             :  * of our cluster), and the OID of the (or a) database with that value.
     286             :  */
     287             : void
     288           6 : SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
     289             : {
     290             :     TransactionId xidVacLimit;
     291             :     TransactionId xidWarnLimit;
     292             :     TransactionId xidStopLimit;
     293             :     TransactionId xidWrapLimit;
     294             :     TransactionId curXid;
     295             : 
     296           6 :     Assert(TransactionIdIsNormal(oldest_datfrozenxid));
     297             : 
     298             :     /*
     299             :      * The place where we actually get into deep trouble is halfway around
     300             :      * from the oldest potentially-existing XID.  (This calculation is
     301             :      * probably off by one or two counts, because the special XIDs reduce the
     302             :      * size of the loop a little bit.  But we throw in plenty of slop below,
     303             :      * so it doesn't matter.)
     304             :      */
     305           6 :     xidWrapLimit = oldest_datfrozenxid + (MaxTransactionId >> 1);
     306           6 :     if (xidWrapLimit < FirstNormalTransactionId)
     307           0 :         xidWrapLimit += FirstNormalTransactionId;
     308             : 
     309             :     /*
     310             :      * We'll refuse to continue assigning XIDs in interactive mode once we get
     311             :      * within 1M transactions of data loss.  This leaves lots of room for the
     312             :      * DBA to fool around fixing things in a standalone backend, while not
     313             :      * being significant compared to total XID space. (Note that since
     314             :      * vacuuming requires one transaction per table cleaned, we had better be
     315             :      * sure there's lots of XIDs left...)
     316             :      */
     317           6 :     xidStopLimit = xidWrapLimit - 1000000;
     318           6 :     if (xidStopLimit < FirstNormalTransactionId)
     319           0 :         xidStopLimit -= FirstNormalTransactionId;
     320             : 
     321             :     /*
     322             :      * We'll start complaining loudly when we get within 10M transactions of
     323             :      * the stop point.  This is kind of arbitrary, but if you let your gas
     324             :      * gauge get down to 1% of full, would you be looking for the next gas
     325             :      * station?  We need to be fairly liberal about this number because there
     326             :      * are lots of scenarios where most transactions are done by automatic
     327             :      * clients that won't pay attention to warnings. (No, we're not gonna make
     328             :      * this configurable.  If you know enough to configure it, you know enough
     329             :      * to not get in this kind of trouble in the first place.)
     330             :      */
     331           6 :     xidWarnLimit = xidStopLimit - 10000000;
     332           6 :     if (xidWarnLimit < FirstNormalTransactionId)
     333           0 :         xidWarnLimit -= FirstNormalTransactionId;
     334             : 
     335             :     /*
     336             :      * We'll start trying to force autovacuums when oldest_datfrozenxid gets
     337             :      * to be more than autovacuum_freeze_max_age transactions old.
     338             :      *
     339             :      * Note: guc.c ensures that autovacuum_freeze_max_age is in a sane range,
     340             :      * so that xidVacLimit will be well before xidWarnLimit.
     341             :      *
     342             :      * Note: autovacuum_freeze_max_age is a PGC_POSTMASTER parameter so that
     343             :      * we don't have to worry about dealing with on-the-fly changes in its
     344             :      * value.  It doesn't look practical to update shared state from a GUC
     345             :      * assign hook (too many processes would try to execute the hook,
     346             :      * resulting in race conditions as well as crashes of those not connected
     347             :      * to shared memory).  Perhaps this can be improved someday.  See also
     348             :      * SetMultiXactIdLimit.
     349             :      */
     350           6 :     xidVacLimit = oldest_datfrozenxid + autovacuum_freeze_max_age;
     351           6 :     if (xidVacLimit < FirstNormalTransactionId)
     352           0 :         xidVacLimit += FirstNormalTransactionId;
     353             : 
     354             :     /* Grab lock for just long enough to set the new limit values */
     355           6 :     LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
     356           6 :     ShmemVariableCache->oldestXid = oldest_datfrozenxid;
     357           6 :     ShmemVariableCache->xidVacLimit = xidVacLimit;
     358           6 :     ShmemVariableCache->xidWarnLimit = xidWarnLimit;
     359           6 :     ShmemVariableCache->xidStopLimit = xidStopLimit;
     360           6 :     ShmemVariableCache->xidWrapLimit = xidWrapLimit;
     361           6 :     ShmemVariableCache->oldestXidDB = oldest_datoid;
     362           6 :     curXid = ShmemVariableCache->nextXid;
     363           6 :     LWLockRelease(XidGenLock);
     364             : 
     365             :     /* Log the info */
     366           6 :     ereport(DEBUG1,
     367             :             (errmsg("transaction ID wrap limit is %u, limited by database with OID %u",
     368             :                     xidWrapLimit, oldest_datoid)));
     369             : 
     370             :     /*
     371             :      * If past the autovacuum force point, immediately signal an autovac
     372             :      * request.  The reason for this is that autovac only processes one
     373             :      * database per invocation.  Once it's finished cleaning up the oldest
     374             :      * database, it'll call here, and we'll signal the postmaster to start
     375             :      * another iteration immediately if there are still any old databases.
     376             :      */
     377           6 :     if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) &&
     378           0 :         IsUnderPostmaster && !InRecovery)
     379           0 :         SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
     380             : 
     381             :     /* Give an immediate warning if past the wrap warn point */
     382           6 :     if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit) && !InRecovery)
     383             :     {
     384             :         char       *oldest_datname;
     385             : 
     386             :         /*
     387             :          * We can be called when not inside a transaction, for example during
     388             :          * StartupXLOG().  In such a case we cannot do database access, so we
     389             :          * must just report the oldest DB's OID.
     390             :          *
     391             :          * Note: it's also possible that get_database_name fails and returns
     392             :          * NULL, for example because the database just got dropped.  We'll
     393             :          * still warn, even though the warning might now be unnecessary.
     394             :          */
     395           0 :         if (IsTransactionState())
     396           0 :             oldest_datname = get_database_name(oldest_datoid);
     397             :         else
     398           0 :             oldest_datname = NULL;
     399             : 
     400           0 :         if (oldest_datname)
     401           0 :             ereport(WARNING,
     402             :                     (errmsg("database \"%s\" must be vacuumed within %u transactions",
     403             :                             oldest_datname,
     404             :                             xidWrapLimit - curXid),
     405             :                      errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
     406             :                              "You might also need to commit or roll back old prepared transactions.")));
     407             :         else
     408           0 :             ereport(WARNING,
     409             :                     (errmsg("database with OID %u must be vacuumed within %u transactions",
     410             :                             oldest_datoid,
     411             :                             xidWrapLimit - curXid),
     412             :                      errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
     413             :                              "You might also need to commit or roll back old prepared transactions.")));
     414             :     }
     415           6 : }
     416             : 
     417             : 
     418             : /*
     419             :  * ForceTransactionIdLimitUpdate -- does the XID wrap-limit data need updating?
     420             :  *
     421             :  * We primarily check whether oldestXidDB is valid.  The cases we have in
     422             :  * mind are that that database was dropped, or the field was reset to zero
     423             :  * by pg_resetwal.  In either case we should force recalculation of the
     424             :  * wrap limit.  Also do it if oldestXid is old enough to be forcing
     425             :  * autovacuums or other actions; this ensures we update our state as soon
     426             :  * as possible once extra overhead is being incurred.
     427             :  */
     428             : bool
     429          46 : ForceTransactionIdLimitUpdate(void)
     430             : {
     431             :     TransactionId nextXid;
     432             :     TransactionId xidVacLimit;
     433             :     TransactionId oldestXid;
     434             :     Oid         oldestXidDB;
     435             : 
     436             :     /* Locking is probably not really necessary, but let's be careful */
     437          46 :     LWLockAcquire(XidGenLock, LW_SHARED);
     438          46 :     nextXid = ShmemVariableCache->nextXid;
     439          46 :     xidVacLimit = ShmemVariableCache->xidVacLimit;
     440          46 :     oldestXid = ShmemVariableCache->oldestXid;
     441          46 :     oldestXidDB = ShmemVariableCache->oldestXidDB;
     442          46 :     LWLockRelease(XidGenLock);
     443             : 
     444          46 :     if (!TransactionIdIsNormal(oldestXid))
     445           0 :         return true;            /* shouldn't happen, but just in case */
     446          46 :     if (!TransactionIdIsValid(xidVacLimit))
     447           0 :         return true;            /* this shouldn't happen anymore either */
     448          46 :     if (TransactionIdFollowsOrEquals(nextXid, xidVacLimit))
     449           0 :         return true;            /* past VacLimit, don't delay updating */
     450          46 :     if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(oldestXidDB)))
     451           0 :         return true;            /* could happen, per comments above */
     452          46 :     return false;
     453             : }
     454             : 
     455             : 
     456             : /*
     457             :  * GetNewObjectId -- allocate a new OID
     458             :  *
     459             :  * OIDs are generated by a cluster-wide counter.  Since they are only 32 bits
     460             :  * wide, counter wraparound will occur eventually, and therefore it is unwise
     461             :  * to assume they are unique unless precautions are taken to make them so.
     462             :  * Hence, this routine should generally not be used directly.  The only
     463             :  * direct callers should be GetNewOid() and GetNewRelFileNode() in
     464             :  * catalog/catalog.c.
     465             :  */
     466             : Oid
     467       33890 : GetNewObjectId(void)
     468             : {
     469             :     Oid         result;
     470             : 
     471             :     /* safety check, we should never get this far in a HS standby */
     472       33890 :     if (RecoveryInProgress())
     473           0 :         elog(ERROR, "cannot assign OIDs during recovery");
     474             : 
     475       33890 :     LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
     476             : 
     477             :     /*
     478             :      * Check for wraparound of the OID counter.  We *must* not return 0
     479             :      * (InvalidOid); and as long as we have to check that, it seems a good
     480             :      * idea to skip over everything below FirstNormalObjectId too. (This
     481             :      * basically just avoids lots of collisions with bootstrap-assigned OIDs
     482             :      * right after a wrap occurs, so as to avoid a possibly large number of
     483             :      * iterations in GetNewOid.)  Note we are relying on unsigned comparison.
     484             :      *
     485             :      * During initdb, we start the OID generator at FirstBootstrapObjectId, so
     486             :      * we only wrap if before that point when in bootstrap or standalone mode.
     487             :      * The first time through this routine after normal postmaster start, the
     488             :      * counter will be forced up to FirstNormalObjectId.  This mechanism
     489             :      * leaves the OIDs between FirstBootstrapObjectId and FirstNormalObjectId
     490             :      * available for automatic assignment during initdb, while ensuring they
     491             :      * will never conflict with user-assigned OIDs.
     492             :      */
     493       33890 :     if (ShmemVariableCache->nextOid < ((Oid) FirstNormalObjectId))
     494             :     {
     495        2332 :         if (IsPostmasterEnvironment)
     496             :         {
     497             :             /* wraparound, or first post-initdb assignment, in normal mode */
     498           1 :             ShmemVariableCache->nextOid = FirstNormalObjectId;
     499           1 :             ShmemVariableCache->oidCount = 0;
     500             :         }
     501             :         else
     502             :         {
     503             :             /* we may be bootstrapping, so don't enforce the full range */
     504        2331 :             if (ShmemVariableCache->nextOid < ((Oid) FirstBootstrapObjectId))
     505             :             {
     506             :                 /* wraparound in standalone mode (unlikely but possible) */
     507           0 :                 ShmemVariableCache->nextOid = FirstNormalObjectId;
     508           0 :                 ShmemVariableCache->oidCount = 0;
     509             :             }
     510             :         }
     511             :     }
     512             : 
     513             :     /* If we run out of logged for use oids then we must log more */
     514       33890 :     if (ShmemVariableCache->oidCount == 0)
     515             :     {
     516           6 :         XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
     517           6 :         ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
     518             :     }
     519             : 
     520       33890 :     result = ShmemVariableCache->nextOid;
     521             : 
     522       33890 :     (ShmemVariableCache->nextOid)++;
     523       33890 :     (ShmemVariableCache->oidCount)--;
     524             : 
     525       33890 :     LWLockRelease(OidGenLock);
     526             : 
     527       33890 :     return result;
     528             : }

Generated by: LCOV version 1.11