LTP GCOV extension - code coverage report
Current view: directory - access/transam - varsup.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 76
Code covered: 80.3 % Executed lines: 61
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * varsup.c
       4                 :  *        postgres OID & XID variables support routines
       5                 :  *
       6                 :  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
       7                 :  *
       8                 :  * IDENTIFICATION
       9                 :  *        $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.80 2007/11/15 21:14:32 momjian Exp $
      10                 :  *
      11                 :  *-------------------------------------------------------------------------
      12                 :  */
      13                 : 
      14                 : #include "postgres.h"
      15                 : 
      16                 : #include "access/clog.h"
      17                 : #include "access/subtrans.h"
      18                 : #include "access/transam.h"
      19                 : #include "miscadmin.h"
      20                 : #include "postmaster/autovacuum.h"
      21                 : #include "storage/pmsignal.h"
      22                 : #include "storage/proc.h"
      23                 : #include "utils/builtins.h"
      24                 : 
      25                 : 
      26                 : /* Number of OIDs to prefetch (preallocate) per XLOG write */
      27                 : #define VAR_OID_PREFETCH                8192
      28                 : 
      29                 : /* pointer to "variable cache" in shared memory (set up by shmem.c) */
      30                 : VariableCache ShmemVariableCache = NULL;
      31                 : 
      32                 : 
      33                 : /*
      34                 :  * Allocate the next XID for my new transaction or subtransaction.
      35                 :  *
      36                 :  * The new XID is also stored into MyProc before returning.
      37                 :  */
      38                 : TransactionId
      39                 : GetNewTransactionId(bool isSubXact)
      40            8671 : {
      41                 :         TransactionId xid;
      42                 : 
      43                 :         /*
      44                 :          * During bootstrap initialization, we return the special bootstrap
      45                 :          * transaction id.
      46                 :          */
      47            8671 :         if (IsBootstrapProcessingMode())
      48                 :         {
      49                 :                 Assert(!isSubXact);
      50            4241 :                 MyProc->xid = BootstrapTransactionId;
      51            4241 :                 return BootstrapTransactionId;
      52                 :         }
      53                 : 
      54            4430 :         LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
      55                 : 
      56            4430 :         xid = ShmemVariableCache->nextXid;
      57                 : 
      58                 :         /*----------
      59                 :          * Check to see if it's safe to assign another XID.  This protects against
      60                 :          * catastrophic data loss due to XID wraparound.  The basic rules are:
      61                 :          *
      62                 :          * If we're past xidVacLimit, start trying to force autovacuum cycles.
      63                 :          * If we're past xidWarnLimit, start issuing warnings.
      64                 :          * If we're past xidStopLimit, refuse to execute transactions, unless
      65                 :          * we are running in a standalone backend (which gives an escape hatch
      66                 :          * to the DBA who somehow got past the earlier defenses).
      67                 :          *
      68                 :          * Test is coded to fall out as fast as possible during normal operation,
      69                 :          * ie, when the vac limit is set and we haven't violated it.
      70                 :          *----------
      71                 :          */
      72            4430 :         if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidVacLimit) &&
      73                 :                 TransactionIdIsValid(ShmemVariableCache->xidVacLimit))
      74                 :         {
      75                 :                 /*
      76                 :                  * To avoid swamping the postmaster with signals, we issue the autovac
      77                 :                  * request only once per 64K transaction starts.  This still gives
      78                 :                  * plenty of chances before we get into real trouble.
      79                 :                  */
      80               0 :                 if (IsUnderPostmaster && (xid % 65536) == 0)
      81               0 :                         SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
      82                 : 
      83               0 :                 if (IsUnderPostmaster &&
      84                 :                  TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidStopLimit))
      85               0 :                         ereport(ERROR,
      86                 :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
      87                 :                                          errmsg("database is not accepting commands to avoid wraparound data loss in database \"%s\"",
      88                 :                                                         NameStr(ShmemVariableCache->limit_datname)),
      89                 :                                          errhint("Stop the postmaster and use a standalone backend to vacuum database \"%s\".",
      90                 :                                                          NameStr(ShmemVariableCache->limit_datname))));
      91               0 :                 else if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidWarnLimit))
      92               0 :                         ereport(WARNING,
      93                 :                         (errmsg("database \"%s\" must be vacuumed within %u transactions",
      94                 :                                         NameStr(ShmemVariableCache->limit_datname),
      95                 :                                         ShmemVariableCache->xidWrapLimit - xid),
      96                 :                          errhint("To avoid a database shutdown, execute a full-database VACUUM in \"%s\".",
      97                 :                                          NameStr(ShmemVariableCache->limit_datname))));
      98                 :         }
      99                 : 
     100                 :         /*
     101                 :          * If we are allocating the first XID of a new page of the commit log,
     102                 :          * zero out that commit-log page before returning. We must do this while
     103                 :          * holding XidGenLock, else another xact could acquire and commit a later
     104                 :          * XID before we zero the page.  Fortunately, a page of the commit log
     105                 :          * holds 32K or more transactions, so we don't have to do this very often.
     106                 :          *
     107                 :          * Extend pg_subtrans too.
     108                 :          */
     109            4430 :         ExtendCLOG(xid);
     110            4430 :         ExtendSUBTRANS(xid);
     111                 : 
     112                 :         /*
     113                 :          * Now advance the nextXid counter.  This must not happen until after we
     114                 :          * have successfully completed ExtendCLOG() --- if that routine fails, we
     115                 :          * want the next incoming transaction to try it again.  We cannot assign
     116                 :          * more XIDs until there is CLOG space for them.
     117                 :          */
     118            4430 :         TransactionIdAdvance(ShmemVariableCache->nextXid);
     119                 : 
     120                 :         /*
     121                 :          * We must store the new XID into the shared ProcArray before releasing
     122                 :          * XidGenLock.  This ensures that every active XID older than
     123                 :          * latestCompletedXid is present in the ProcArray, which is essential for
     124                 :          * correct OldestXmin tracking; see src/backend/access/transam/README.
     125                 :          *
     126                 :          * XXX by storing xid into MyProc without acquiring ProcArrayLock, we are
     127                 :          * relying on fetch/store of an xid to be atomic, else other backends
     128                 :          * might see a partially-set xid here.  But holding both locks at once
     129                 :          * would be a nasty concurrency hit.  So for now, assume atomicity.
     130                 :          *
     131                 :          * Note that readers of PGPROC xid fields should be careful to fetch the
     132                 :          * value only once, rather than assume they can read a value multiple
     133                 :          * times and get the same answer each time.
     134                 :          *
     135                 :          * The same comments apply to the subxact xid count and overflow fields.
     136                 :          *
     137                 :          * A solution to the atomic-store problem would be to give each PGPROC its
     138                 :          * own spinlock used only for fetching/storing that PGPROC's xid and
     139                 :          * related fields.
     140                 :          *
     141                 :          * If there's no room to fit a subtransaction XID into PGPROC, set the
     142                 :          * cache-overflowed flag instead.  This forces readers to look in
     143                 :          * pg_subtrans to map subtransaction XIDs up to top-level XIDs. There is a
     144                 :          * race-condition window, in that the new XID will not appear as running
     145                 :          * until its parent link has been placed into pg_subtrans. However, that
     146                 :          * will happen before anyone could possibly have a reason to inquire about
     147                 :          * the status of the XID, so it seems OK.  (Snapshots taken during this
     148                 :          * window *will* include the parent XID, so they will deliver the correct
     149                 :          * answer later on when someone does have a reason to inquire.)
     150                 :          */
     151                 :         {
     152                 :                 /*
     153                 :                  * Use volatile pointer to prevent code rearrangement; other backends
     154                 :                  * could be examining my subxids info concurrently, and we don't want
     155                 :                  * them to see an invalid intermediate state, such as incrementing
     156                 :                  * nxids before filling the array entry.  Note we are assuming that
     157                 :                  * TransactionId and int fetch/store are atomic.
     158                 :                  */
     159            4430 :                 volatile PGPROC *myproc = MyProc;
     160                 : 
     161            4430 :                 if (!isSubXact)
     162            4390 :                         myproc->xid = xid;
     163                 :                 else
     164                 :                 {
     165              40 :                         int                     nxids = myproc->subxids.nxids;
     166                 : 
     167              40 :                         if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
     168                 :                         {
     169              40 :                                 myproc->subxids.xids[nxids] = xid;
     170              40 :                                 myproc->subxids.nxids = nxids + 1;
     171                 :                         }
     172                 :                         else
     173               0 :                                 myproc->subxids.overflowed = true;
     174                 :                 }
     175                 :         }
     176                 : 
     177            4430 :         LWLockRelease(XidGenLock);
     178                 : 
     179            4430 :         return xid;
     180                 : }
     181                 : 
     182                 : /*
     183                 :  * Read nextXid but don't allocate it.
     184                 :  */
     185                 : TransactionId
     186                 : ReadNewTransactionId(void)
     187             347 : {
     188                 :         TransactionId xid;
     189                 : 
     190             347 :         LWLockAcquire(XidGenLock, LW_SHARED);
     191             347 :         xid = ShmemVariableCache->nextXid;
     192             347 :         LWLockRelease(XidGenLock);
     193                 : 
     194             347 :         return xid;
     195                 : }
     196                 : 
     197                 : /*
     198                 :  * Determine the last safe XID to allocate given the currently oldest
     199                 :  * datfrozenxid (ie, the oldest XID that might exist in any database
     200                 :  * of our cluster).
     201                 :  */
     202                 : void
     203                 : SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
     204                 :                                           Name oldest_datname)
     205              20 : {
     206                 :         TransactionId xidVacLimit;
     207                 :         TransactionId xidWarnLimit;
     208                 :         TransactionId xidStopLimit;
     209                 :         TransactionId xidWrapLimit;
     210                 :         TransactionId curXid;
     211                 : 
     212                 :         Assert(TransactionIdIsNormal(oldest_datfrozenxid));
     213                 : 
     214                 :         /*
     215                 :          * The place where we actually get into deep trouble is halfway around
     216                 :          * from the oldest potentially-existing XID.  (This calculation is
     217                 :          * probably off by one or two counts, because the special XIDs reduce the
     218                 :          * size of the loop a little bit.  But we throw in plenty of slop below,
     219                 :          * so it doesn't matter.)
     220                 :          */
     221              20 :         xidWrapLimit = oldest_datfrozenxid + (MaxTransactionId >> 1);
     222              20 :         if (xidWrapLimit < FirstNormalTransactionId)
     223               0 :                 xidWrapLimit += FirstNormalTransactionId;
     224                 : 
     225                 :         /*
     226                 :          * We'll refuse to continue assigning XIDs in interactive mode once we get
     227                 :          * within 1M transactions of data loss.  This leaves lots of room for the
     228                 :          * DBA to fool around fixing things in a standalone backend, while not
     229                 :          * being significant compared to total XID space. (Note that since
     230                 :          * vacuuming requires one transaction per table cleaned, we had better be
     231                 :          * sure there's lots of XIDs left...)
     232                 :          */
     233              20 :         xidStopLimit = xidWrapLimit - 1000000;
     234              20 :         if (xidStopLimit < FirstNormalTransactionId)
     235               0 :                 xidStopLimit -= FirstNormalTransactionId;
     236                 : 
     237                 :         /*
     238                 :          * We'll start complaining loudly when we get within 10M transactions of
     239                 :          * the stop point.      This is kind of arbitrary, but if you let your gas
     240                 :          * gauge get down to 1% of full, would you be looking for the next gas
     241                 :          * station?  We need to be fairly liberal about this number because there
     242                 :          * are lots of scenarios where most transactions are done by automatic
     243                 :          * clients that won't pay attention to warnings. (No, we're not gonna make
     244                 :          * this configurable.  If you know enough to configure it, you know enough
     245                 :          * to not get in this kind of trouble in the first place.)
     246                 :          */
     247              20 :         xidWarnLimit = xidStopLimit - 10000000;
     248              20 :         if (xidWarnLimit < FirstNormalTransactionId)
     249               0 :                 xidWarnLimit -= FirstNormalTransactionId;
     250                 : 
     251                 :         /*
     252                 :          * We'll start trying to force autovacuums when oldest_datfrozenxid gets
     253                 :          * to be more than autovacuum_freeze_max_age transactions old.
     254                 :          *
     255                 :          * Note: guc.c ensures that autovacuum_freeze_max_age is in a sane range,
     256                 :          * so that xidVacLimit will be well before xidWarnLimit.
     257                 :          *
     258                 :          * Note: autovacuum_freeze_max_age is a PGC_POSTMASTER parameter so that
     259                 :          * we don't have to worry about dealing with on-the-fly changes in its
     260                 :          * value.  It doesn't look practical to update shared state from a GUC
     261                 :          * assign hook (too many processes would try to execute the hook,
     262                 :          * resulting in race conditions as well as crashes of those not connected
     263                 :          * to shared memory).  Perhaps this can be improved someday.
     264                 :          */
     265              20 :         xidVacLimit = oldest_datfrozenxid + autovacuum_freeze_max_age;
     266              20 :         if (xidVacLimit < FirstNormalTransactionId)
     267               0 :                 xidVacLimit += FirstNormalTransactionId;
     268                 : 
     269                 :         /* Grab lock for just long enough to set the new limit values */
     270              20 :         LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
     271              20 :         ShmemVariableCache->oldestXid = oldest_datfrozenxid;
     272              20 :         ShmemVariableCache->xidVacLimit = xidVacLimit;
     273              20 :         ShmemVariableCache->xidWarnLimit = xidWarnLimit;
     274              20 :         ShmemVariableCache->xidStopLimit = xidStopLimit;
     275              20 :         ShmemVariableCache->xidWrapLimit = xidWrapLimit;
     276              20 :         namecpy(&ShmemVariableCache->limit_datname, oldest_datname);
     277              20 :         curXid = ShmemVariableCache->nextXid;
     278              20 :         LWLockRelease(XidGenLock);
     279                 : 
     280                 :         /* Log the info */
     281              20 :         ereport(DEBUG1,
     282                 :            (errmsg("transaction ID wrap limit is %u, limited by database \"%s\"",
     283                 :                            xidWrapLimit, NameStr(*oldest_datname))));
     284                 : 
     285                 :         /*
     286                 :          * If past the autovacuum force point, immediately signal an autovac
     287                 :          * request.  The reason for this is that autovac only processes one
     288                 :          * database per invocation.  Once it's finished cleaning up the oldest
     289                 :          * database, it'll call here, and we'll signal the postmaster to start
     290                 :          * another iteration immediately if there are still any old databases.
     291                 :          */
     292              20 :         if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) &&
     293                 :                 IsUnderPostmaster)
     294               0 :                 SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
     295                 : 
     296                 :         /* Give an immediate warning if past the wrap warn point */
     297              20 :         if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit))
     298               0 :                 ereport(WARNING,
     299                 :                    (errmsg("database \"%s\" must be vacuumed within %u transactions",
     300                 :                                    NameStr(*oldest_datname),
     301                 :                                    xidWrapLimit - curXid),
     302                 :                         errhint("To avoid a database shutdown, execute a full-database VACUUM in \"%s\".",
     303                 :                                         NameStr(*oldest_datname))));
     304              20 : }
     305                 : 
     306                 : 
     307                 : /*
     308                 :  * GetNewObjectId -- allocate a new OID
     309                 :  *
     310                 :  * OIDs are generated by a cluster-wide counter.  Since they are only 32 bits
     311                 :  * wide, counter wraparound will occur eventually, and therefore it is unwise
     312                 :  * to assume they are unique unless precautions are taken to make them so.
     313                 :  * Hence, this routine should generally not be used directly.  The only
     314                 :  * direct callers should be GetNewOid() and GetNewRelFileNode() in
     315                 :  * catalog/catalog.c.
     316                 :  */
     317                 : Oid
     318                 : GetNewObjectId(void)
     319           24891 : {
     320                 :         Oid                     result;
     321                 : 
     322           24891 :         LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
     323                 : 
     324                 :         /*
     325                 :          * Check for wraparound of the OID counter.  We *must* not return 0
     326                 :          * (InvalidOid); and as long as we have to check that, it seems a good
     327                 :          * idea to skip over everything below FirstNormalObjectId too. (This
     328                 :          * basically just avoids lots of collisions with bootstrap-assigned OIDs
     329                 :          * right after a wrap occurs, so as to avoid a possibly large number of
     330                 :          * iterations in GetNewOid.)  Note we are relying on unsigned comparison.
     331                 :          *
     332                 :          * During initdb, we start the OID generator at FirstBootstrapObjectId, so
     333                 :          * we only enforce wrapping to that point when in bootstrap or standalone
     334                 :          * mode.  The first time through this routine after normal postmaster
     335                 :          * start, the counter will be forced up to FirstNormalObjectId. This
     336                 :          * mechanism leaves the OIDs between FirstBootstrapObjectId and
     337                 :          * FirstNormalObjectId available for automatic assignment during initdb,
     338                 :          * while ensuring they will never conflict with user-assigned OIDs.
     339                 :          */
     340           24891 :         if (ShmemVariableCache->nextOid < ((Oid) FirstNormalObjectId))
     341                 :         {
     342            1513 :                 if (IsPostmasterEnvironment)
     343                 :                 {
     344                 :                         /* wraparound in normal environment */
     345               1 :                         ShmemVariableCache->nextOid = FirstNormalObjectId;
     346               1 :                         ShmemVariableCache->oidCount = 0;
     347                 :                 }
     348                 :                 else
     349                 :                 {
     350                 :                         /* we may be bootstrapping, so don't enforce the full range */
     351            1512 :                         if (ShmemVariableCache->nextOid < ((Oid) FirstBootstrapObjectId))
     352                 :                         {
     353                 :                                 /* wraparound in standalone environment? */
     354               0 :                                 ShmemVariableCache->nextOid = FirstBootstrapObjectId;
     355               0 :                                 ShmemVariableCache->oidCount = 0;
     356                 :                         }
     357                 :                 }
     358                 :         }
     359                 : 
     360                 :         /* If we run out of logged for use oids then we must log more */
     361           24891 :         if (ShmemVariableCache->oidCount == 0)
     362                 :         {
     363              12 :                 XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
     364              12 :                 ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
     365                 :         }
     366                 : 
     367           24891 :         result = ShmemVariableCache->nextOid;
     368                 : 
     369           24891 :         (ShmemVariableCache->nextOid)++;
     370           24891 :         (ShmemVariableCache->oidCount)--;
     371                 : 
     372           24891 :         LWLockRelease(OidGenLock);
     373                 : 
     374           24891 :         return result;
     375                 : }

Generated by: LTP GCOV extension version 1.5