Header And Logo

PostgreSQL
| The world's most advanced open source database.

vacuum.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * vacuum.c
00004  *    The postgres vacuum cleaner.
00005  *
00006  * This file now includes only control and dispatch code for VACUUM and
00007  * ANALYZE commands.  Regular VACUUM is implemented in vacuumlazy.c,
00008  * ANALYZE in analyze.c, and VACUUM FULL is a variant of CLUSTER, handled
00009  * in cluster.c.
00010  *
00011  *
00012  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00013  * Portions Copyright (c) 1994, Regents of the University of California
00014  *
00015  *
00016  * IDENTIFICATION
00017  *    src/backend/commands/vacuum.c
00018  *
00019  *-------------------------------------------------------------------------
00020  */
00021 #include "postgres.h"
00022 
00023 #include <math.h>
00024 
00025 #include "access/clog.h"
00026 #include "access/genam.h"
00027 #include "access/heapam.h"
00028 #include "access/htup_details.h"
00029 #include "access/multixact.h"
00030 #include "access/transam.h"
00031 #include "access/xact.h"
00032 #include "catalog/namespace.h"
00033 #include "catalog/pg_database.h"
00034 #include "catalog/pg_namespace.h"
00035 #include "commands/cluster.h"
00036 #include "commands/vacuum.h"
00037 #include "miscadmin.h"
00038 #include "pgstat.h"
00039 #include "postmaster/autovacuum.h"
00040 #include "storage/bufmgr.h"
00041 #include "storage/lmgr.h"
00042 #include "storage/proc.h"
00043 #include "storage/procarray.h"
00044 #include "utils/acl.h"
00045 #include "utils/fmgroids.h"
00046 #include "utils/guc.h"
00047 #include "utils/memutils.h"
00048 #include "utils/snapmgr.h"
00049 #include "utils/syscache.h"
00050 #include "utils/tqual.h"
00051 
00052 
00053 /*
00054  * GUC parameters
00055  */
00056 int         vacuum_freeze_min_age;
00057 int         vacuum_freeze_table_age;
00058 
00059 
00060 /* A few variables that don't seem worth passing around as parameters */
00061 static MemoryContext vac_context = NULL;
00062 static BufferAccessStrategy vac_strategy;
00063 
00064 
00065 /* non-export function prototypes */
00066 static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
00067 static void vac_truncate_clog(TransactionId frozenXID, MultiXactId frozenMulti);
00068 static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
00069            bool for_wraparound);
00070 
00071 
00072 /*
00073  * Primary entry point for VACUUM and ANALYZE commands.
00074  *
00075  * relid is normally InvalidOid; if it is not, then it provides the relation
00076  * OID to be processed, and vacstmt->relation is ignored.  (The non-invalid
00077  * case is currently only used by autovacuum.)
00078  *
00079  * do_toast is passed as FALSE by autovacuum, because it processes TOAST
00080  * tables separately.
00081  *
00082  * for_wraparound is used by autovacuum to let us know when it's forcing
00083  * a vacuum for wraparound, which should not be auto-canceled.
00084  *
00085  * bstrategy is normally given as NULL, but in autovacuum it can be passed
00086  * in to use the same buffer strategy object across multiple vacuum() calls.
00087  *
00088  * isTopLevel should be passed down from ProcessUtility.
00089  *
00090  * It is the caller's responsibility that vacstmt and bstrategy
00091  * (if given) be allocated in a memory context that won't disappear
00092  * at transaction commit.
00093  */
00094 void
00095 vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
00096        BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
00097 {
00098     const char *stmttype;
00099     volatile bool in_outer_xact,
00100                 use_own_xacts;
00101     List       *relations;
00102 
00103     /* sanity checks on options */
00104     Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE));
00105     Assert((vacstmt->options & VACOPT_VACUUM) ||
00106            !(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE)));
00107     Assert((vacstmt->options & VACOPT_ANALYZE) || vacstmt->va_cols == NIL);
00108 
00109     stmttype = (vacstmt->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
00110 
00111     /*
00112      * We cannot run VACUUM inside a user transaction block; if we were inside
00113      * a transaction, then our commit- and start-transaction-command calls
00114      * would not have the intended effect!  There are numerous other subtle
00115      * dependencies on this, too.
00116      *
00117      * ANALYZE (without VACUUM) can run either way.
00118      */
00119     if (vacstmt->options & VACOPT_VACUUM)
00120     {
00121         PreventTransactionChain(isTopLevel, stmttype);
00122         in_outer_xact = false;
00123     }
00124     else
00125         in_outer_xact = IsInTransactionChain(isTopLevel);
00126 
00127     /*
00128      * Send info about dead objects to the statistics collector, unless we are
00129      * in autovacuum --- autovacuum.c does this for itself.
00130      */
00131     if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
00132         pgstat_vacuum_stat();
00133 
00134     /*
00135      * Create special memory context for cross-transaction storage.
00136      *
00137      * Since it is a child of PortalContext, it will go away eventually even
00138      * if we suffer an error; there's no need for special abort cleanup logic.
00139      */
00140     vac_context = AllocSetContextCreate(PortalContext,
00141                                         "Vacuum",
00142                                         ALLOCSET_DEFAULT_MINSIZE,
00143                                         ALLOCSET_DEFAULT_INITSIZE,
00144                                         ALLOCSET_DEFAULT_MAXSIZE);
00145 
00146     /*
00147      * If caller didn't give us a buffer strategy object, make one in the
00148      * cross-transaction memory context.
00149      */
00150     if (bstrategy == NULL)
00151     {
00152         MemoryContext old_context = MemoryContextSwitchTo(vac_context);
00153 
00154         bstrategy = GetAccessStrategy(BAS_VACUUM);
00155         MemoryContextSwitchTo(old_context);
00156     }
00157     vac_strategy = bstrategy;
00158 
00159     /*
00160      * Build list of relations to process, unless caller gave us one. (If we
00161      * build one, we put it in vac_context for safekeeping.)
00162      */
00163     relations = get_rel_oids(relid, vacstmt->relation);
00164 
00165     /*
00166      * Decide whether we need to start/commit our own transactions.
00167      *
00168      * For VACUUM (with or without ANALYZE): always do so, so that we can
00169      * release locks as soon as possible.  (We could possibly use the outer
00170      * transaction for a one-table VACUUM, but handling TOAST tables would be
00171      * problematic.)
00172      *
00173      * For ANALYZE (no VACUUM): if inside a transaction block, we cannot
00174      * start/commit our own transactions.  Also, there's no need to do so if
00175      * only processing one relation.  For multiple relations when not within a
00176      * transaction block, and also in an autovacuum worker, use own
00177      * transactions so we can release locks sooner.
00178      */
00179     if (vacstmt->options & VACOPT_VACUUM)
00180         use_own_xacts = true;
00181     else
00182     {
00183         Assert(vacstmt->options & VACOPT_ANALYZE);
00184         if (IsAutoVacuumWorkerProcess())
00185             use_own_xacts = true;
00186         else if (in_outer_xact)
00187             use_own_xacts = false;
00188         else if (list_length(relations) > 1)
00189             use_own_xacts = true;
00190         else
00191             use_own_xacts = false;
00192     }
00193 
00194     /*
00195      * vacuum_rel expects to be entered with no transaction active; it will
00196      * start and commit its own transaction.  But we are called by an SQL
00197      * command, and so we are executing inside a transaction already. We
00198      * commit the transaction started in PostgresMain() here, and start
00199      * another one before exiting to match the commit waiting for us back in
00200      * PostgresMain().
00201      */
00202     if (use_own_xacts)
00203     {
00204         /* ActiveSnapshot is not set by autovacuum */
00205         if (ActiveSnapshotSet())
00206             PopActiveSnapshot();
00207 
00208         /* matches the StartTransaction in PostgresMain() */
00209         CommitTransactionCommand();
00210     }
00211 
00212     /* Turn vacuum cost accounting on or off */
00213     PG_TRY();
00214     {
00215         ListCell   *cur;
00216 
00217         VacuumCostActive = (VacuumCostDelay > 0);
00218         VacuumCostBalance = 0;
00219         VacuumPageHit = 0;
00220         VacuumPageMiss = 0;
00221         VacuumPageDirty = 0;
00222 
00223         /*
00224          * Loop to process each selected relation.
00225          */
00226         foreach(cur, relations)
00227         {
00228             Oid         relid = lfirst_oid(cur);
00229 
00230             if (vacstmt->options & VACOPT_VACUUM)
00231             {
00232                 if (!vacuum_rel(relid, vacstmt, do_toast, for_wraparound))
00233                     continue;
00234             }
00235 
00236             if (vacstmt->options & VACOPT_ANALYZE)
00237             {
00238                 /*
00239                  * If using separate xacts, start one for analyze. Otherwise,
00240                  * we can use the outer transaction.
00241                  */
00242                 if (use_own_xacts)
00243                 {
00244                     StartTransactionCommand();
00245                     /* functions in indexes may want a snapshot set */
00246                     PushActiveSnapshot(GetTransactionSnapshot());
00247                 }
00248 
00249                 analyze_rel(relid, vacstmt, vac_strategy);
00250 
00251                 if (use_own_xacts)
00252                 {
00253                     PopActiveSnapshot();
00254                     CommitTransactionCommand();
00255                 }
00256             }
00257         }
00258     }
00259     PG_CATCH();
00260     {
00261         /* Make sure cost accounting is turned off after error */
00262         VacuumCostActive = false;
00263         PG_RE_THROW();
00264     }
00265     PG_END_TRY();
00266 
00267     /* Turn off vacuum cost accounting */
00268     VacuumCostActive = false;
00269 
00270     /*
00271      * Finish up processing.
00272      */
00273     if (use_own_xacts)
00274     {
00275         /* here, we are not in a transaction */
00276 
00277         /*
00278          * This matches the CommitTransaction waiting for us in
00279          * PostgresMain().
00280          */
00281         StartTransactionCommand();
00282     }
00283 
00284     if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
00285     {
00286         /*
00287          * Update pg_database.datfrozenxid, and truncate pg_clog if possible.
00288          * (autovacuum.c does this for itself.)
00289          */
00290         vac_update_datfrozenxid();
00291     }
00292 
00293     /*
00294      * Clean up working storage --- note we must do this after
00295      * StartTransactionCommand, else we might be trying to delete the active
00296      * context!
00297      */
00298     MemoryContextDelete(vac_context);
00299     vac_context = NULL;
00300 }
00301 
00302 /*
00303  * Build a list of Oids for each relation to be processed
00304  *
00305  * The list is built in vac_context so that it will survive across our
00306  * per-relation transactions.
00307  */
00308 static List *
00309 get_rel_oids(Oid relid, const RangeVar *vacrel)
00310 {
00311     List       *oid_list = NIL;
00312     MemoryContext oldcontext;
00313 
00314     /* OID supplied by VACUUM's caller? */
00315     if (OidIsValid(relid))
00316     {
00317         oldcontext = MemoryContextSwitchTo(vac_context);
00318         oid_list = lappend_oid(oid_list, relid);
00319         MemoryContextSwitchTo(oldcontext);
00320     }
00321     else if (vacrel)
00322     {
00323         /* Process a specific relation */
00324         Oid         relid;
00325 
00326         /*
00327          * Since we don't take a lock here, the relation might be gone, or the
00328          * RangeVar might no longer refer to the OID we look up here.  In the
00329          * former case, VACUUM will do nothing; in the latter case, it will
00330          * process the OID we looked up here, rather than the new one.
00331          * Neither is ideal, but there's little practical alternative, since
00332          * we're going to commit this transaction and begin a new one between
00333          * now and then.
00334          */
00335         relid = RangeVarGetRelid(vacrel, NoLock, false);
00336 
00337         /* Make a relation list entry for this guy */
00338         oldcontext = MemoryContextSwitchTo(vac_context);
00339         oid_list = lappend_oid(oid_list, relid);
00340         MemoryContextSwitchTo(oldcontext);
00341     }
00342     else
00343     {
00344         /*
00345          * Process all plain relations and materialized views listed in
00346          * pg_class
00347          */
00348         Relation    pgclass;
00349         HeapScanDesc scan;
00350         HeapTuple   tuple;
00351 
00352         pgclass = heap_open(RelationRelationId, AccessShareLock);
00353 
00354         scan = heap_beginscan(pgclass, SnapshotNow, 0, NULL);
00355 
00356         while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00357         {
00358             Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
00359 
00360             if (classForm->relkind != RELKIND_RELATION &&
00361                 classForm->relkind != RELKIND_MATVIEW)
00362                 continue;
00363 
00364             /* Make a relation list entry for this guy */
00365             oldcontext = MemoryContextSwitchTo(vac_context);
00366             oid_list = lappend_oid(oid_list, HeapTupleGetOid(tuple));
00367             MemoryContextSwitchTo(oldcontext);
00368         }
00369 
00370         heap_endscan(scan);
00371         heap_close(pgclass, AccessShareLock);
00372     }
00373 
00374     return oid_list;
00375 }
00376 
00377 /*
00378  * vacuum_set_xid_limits() -- compute oldest-Xmin and freeze cutoff points
00379  */
00380 void
00381 vacuum_set_xid_limits(int freeze_min_age,
00382                       int freeze_table_age,
00383                       bool sharedRel,
00384                       TransactionId *oldestXmin,
00385                       TransactionId *freezeLimit,
00386                       TransactionId *freezeTableLimit,
00387                       MultiXactId *multiXactFrzLimit)
00388 {
00389     int         freezemin;
00390     TransactionId limit;
00391     TransactionId safeLimit;
00392 
00393     /*
00394      * We can always ignore processes running lazy vacuum.  This is because we
00395      * use these values only for deciding which tuples we must keep in the
00396      * tables.  Since lazy vacuum doesn't write its XID anywhere, it's safe to
00397      * ignore it.  In theory it could be problematic to ignore lazy vacuums in
00398      * a full vacuum, but keep in mind that only one vacuum process can be
00399      * working on a particular table at any time, and that each vacuum is
00400      * always an independent transaction.
00401      */
00402     *oldestXmin = GetOldestXmin(sharedRel, true);
00403 
00404     Assert(TransactionIdIsNormal(*oldestXmin));
00405 
00406     /*
00407      * Determine the minimum freeze age to use: as specified by the caller, or
00408      * vacuum_freeze_min_age, but in any case not more than half
00409      * autovacuum_freeze_max_age, so that autovacuums to prevent XID
00410      * wraparound won't occur too frequently.
00411      */
00412     freezemin = freeze_min_age;
00413     if (freezemin < 0)
00414         freezemin = vacuum_freeze_min_age;
00415     freezemin = Min(freezemin, autovacuum_freeze_max_age / 2);
00416     Assert(freezemin >= 0);
00417 
00418     /*
00419      * Compute the cutoff XID, being careful not to generate a "permanent" XID
00420      */
00421     limit = *oldestXmin - freezemin;
00422     if (!TransactionIdIsNormal(limit))
00423         limit = FirstNormalTransactionId;
00424 
00425     /*
00426      * If oldestXmin is very far back (in practice, more than
00427      * autovacuum_freeze_max_age / 2 XIDs old), complain and force a minimum
00428      * freeze age of zero.
00429      */
00430     safeLimit = ReadNewTransactionId() - autovacuum_freeze_max_age;
00431     if (!TransactionIdIsNormal(safeLimit))
00432         safeLimit = FirstNormalTransactionId;
00433 
00434     if (TransactionIdPrecedes(limit, safeLimit))
00435     {
00436         ereport(WARNING,
00437                 (errmsg("oldest xmin is far in the past"),
00438                  errhint("Close open transactions soon to avoid wraparound problems.")));
00439         limit = *oldestXmin;
00440     }
00441 
00442     *freezeLimit = limit;
00443 
00444     if (freezeTableLimit != NULL)
00445     {
00446         int         freezetable;
00447 
00448         /*
00449          * Determine the table freeze age to use: as specified by the caller,
00450          * or vacuum_freeze_table_age, but in any case not more than
00451          * autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly
00452          * VACUUM schedule, the nightly VACUUM gets a chance to freeze tuples
00453          * before anti-wraparound autovacuum is launched.
00454          */
00455         freezetable = freeze_table_age;
00456         if (freezetable < 0)
00457             freezetable = vacuum_freeze_table_age;
00458         freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95);
00459         Assert(freezetable >= 0);
00460 
00461         /*
00462          * Compute the cutoff XID, being careful not to generate a "permanent"
00463          * XID.
00464          */
00465         limit = ReadNewTransactionId() - freezetable;
00466         if (!TransactionIdIsNormal(limit))
00467             limit = FirstNormalTransactionId;
00468 
00469         *freezeTableLimit = limit;
00470     }
00471 
00472     if (multiXactFrzLimit != NULL)
00473     {
00474         MultiXactId mxLimit;
00475 
00476         /*
00477          * simplistic multixactid freezing: use the same freezing policy as
00478          * for Xids
00479          */
00480         mxLimit = GetOldestMultiXactId() - freezemin;
00481         if (mxLimit < FirstMultiXactId)
00482             mxLimit = FirstMultiXactId;
00483 
00484         *multiXactFrzLimit = mxLimit;
00485     }
00486 }
00487 
00488 /*
00489  * vac_estimate_reltuples() -- estimate the new value for pg_class.reltuples
00490  *
00491  *      If we scanned the whole relation then we should just use the count of
00492  *      live tuples seen; but if we did not, we should not trust the count
00493  *      unreservedly, especially not in VACUUM, which may have scanned a quite
00494  *      nonrandom subset of the table.  When we have only partial information,
00495  *      we take the old value of pg_class.reltuples as a measurement of the
00496  *      tuple density in the unscanned pages.
00497  *
00498  *      This routine is shared by VACUUM and ANALYZE.
00499  */
00500 double
00501 vac_estimate_reltuples(Relation relation, bool is_analyze,
00502                        BlockNumber total_pages,
00503                        BlockNumber scanned_pages,
00504                        double scanned_tuples)
00505 {
00506     BlockNumber old_rel_pages = relation->rd_rel->relpages;
00507     double      old_rel_tuples = relation->rd_rel->reltuples;
00508     double      old_density;
00509     double      new_density;
00510     double      multiplier;
00511     double      updated_density;
00512 
00513     /* If we did scan the whole table, just use the count as-is */
00514     if (scanned_pages >= total_pages)
00515         return scanned_tuples;
00516 
00517     /*
00518      * If scanned_pages is zero but total_pages isn't, keep the existing value
00519      * of reltuples.  (Note: callers should avoid updating the pg_class
00520      * statistics in this situation, since no new information has been
00521      * provided.)
00522      */
00523     if (scanned_pages == 0)
00524         return old_rel_tuples;
00525 
00526     /*
00527      * If old value of relpages is zero, old density is indeterminate; we
00528      * can't do much except scale up scanned_tuples to match total_pages.
00529      */
00530     if (old_rel_pages == 0)
00531         return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
00532 
00533     /*
00534      * Okay, we've covered the corner cases.  The normal calculation is to
00535      * convert the old measurement to a density (tuples per page), then update
00536      * the density using an exponential-moving-average approach, and finally
00537      * compute reltuples as updated_density * total_pages.
00538      *
00539      * For ANALYZE, the moving average multiplier is just the fraction of the
00540      * table's pages we scanned.  This is equivalent to assuming that the
00541      * tuple density in the unscanned pages didn't change.  Of course, it
00542      * probably did, if the new density measurement is different. But over
00543      * repeated cycles, the value of reltuples will converge towards the
00544      * correct value, if repeated measurements show the same new density.
00545      *
00546      * For VACUUM, the situation is a bit different: we have looked at a
00547      * nonrandom sample of pages, but we know for certain that the pages we
00548      * didn't look at are precisely the ones that haven't changed lately.
00549      * Thus, there is a reasonable argument for doing exactly the same thing
00550      * as for the ANALYZE case, that is use the old density measurement as the
00551      * value for the unscanned pages.
00552      *
00553      * This logic could probably use further refinement.
00554      */
00555     old_density = old_rel_tuples / old_rel_pages;
00556     new_density = scanned_tuples / scanned_pages;
00557     multiplier = (double) scanned_pages / (double) total_pages;
00558     updated_density = old_density + (new_density - old_density) * multiplier;
00559     return floor(updated_density * total_pages + 0.5);
00560 }
00561 
00562 
00563 /*
00564  *  vac_update_relstats() -- update statistics for one relation
00565  *
00566  *      Update the whole-relation statistics that are kept in its pg_class
00567  *      row.  There are additional stats that will be updated if we are
00568  *      doing ANALYZE, but we always update these stats.  This routine works
00569  *      for both index and heap relation entries in pg_class.
00570  *
00571  *      We violate transaction semantics here by overwriting the rel's
00572  *      existing pg_class tuple with the new values.  This is reasonably
00573  *      safe since the new values are correct whether or not this transaction
00574  *      commits.  The reason for this is that if we updated these tuples in
00575  *      the usual way, vacuuming pg_class itself wouldn't work very well ---
00576  *      by the time we got done with a vacuum cycle, most of the tuples in
00577  *      pg_class would've been obsoleted.  Of course, this only works for
00578  *      fixed-size never-null columns, but these are.
00579  *
00580  *      Note another assumption: that two VACUUMs/ANALYZEs on a table can't
00581  *      run in parallel, nor can VACUUM/ANALYZE run in parallel with a
00582  *      schema alteration such as adding an index, rule, or trigger.  Otherwise
00583  *      our updates of relhasindex etc might overwrite uncommitted updates.
00584  *
00585  *      Another reason for doing it this way is that when we are in a lazy
00586  *      VACUUM and have PROC_IN_VACUUM set, we mustn't do any updates ---
00587  *      somebody vacuuming pg_class might think they could delete a tuple
00588  *      marked with xmin = our xid.
00589  *
00590  *      This routine is shared by VACUUM and ANALYZE.
00591  */
00592 void
00593 vac_update_relstats(Relation relation,
00594                     BlockNumber num_pages, double num_tuples,
00595                     BlockNumber num_all_visible_pages,
00596                     bool hasindex, TransactionId frozenxid,
00597                     MultiXactId minmulti)
00598 {
00599     Oid         relid = RelationGetRelid(relation);
00600     Relation    rd;
00601     HeapTuple   ctup;
00602     Form_pg_class pgcform;
00603     bool        dirty;
00604 
00605     rd = heap_open(RelationRelationId, RowExclusiveLock);
00606 
00607     /* Fetch a copy of the tuple to scribble on */
00608     ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
00609     if (!HeapTupleIsValid(ctup))
00610         elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
00611              relid);
00612     pgcform = (Form_pg_class) GETSTRUCT(ctup);
00613 
00614     /* Apply required updates, if any, to copied tuple */
00615 
00616     dirty = false;
00617     if (pgcform->relpages != (int32) num_pages)
00618     {
00619         pgcform->relpages = (int32) num_pages;
00620         dirty = true;
00621     }
00622     if (pgcform->reltuples != (float4) num_tuples)
00623     {
00624         pgcform->reltuples = (float4) num_tuples;
00625         dirty = true;
00626     }
00627     if (pgcform->relallvisible != (int32) num_all_visible_pages)
00628     {
00629         pgcform->relallvisible = (int32) num_all_visible_pages;
00630         dirty = true;
00631     }
00632     if (pgcform->relhasindex != hasindex)
00633     {
00634         pgcform->relhasindex = hasindex;
00635         dirty = true;
00636     }
00637 
00638     /*
00639      * If we have discovered that there are no indexes, then there's no
00640      * primary key either.  This could be done more thoroughly...
00641      */
00642     if (pgcform->relhaspkey && !hasindex)
00643     {
00644         pgcform->relhaspkey = false;
00645         dirty = true;
00646     }
00647 
00648     /* We also clear relhasrules and relhastriggers if needed */
00649     if (pgcform->relhasrules && relation->rd_rules == NULL)
00650     {
00651         pgcform->relhasrules = false;
00652         dirty = true;
00653     }
00654     if (pgcform->relhastriggers && relation->trigdesc == NULL)
00655     {
00656         pgcform->relhastriggers = false;
00657         dirty = true;
00658     }
00659 
00660     /*
00661      * relfrozenxid should never go backward.  Caller can pass
00662      * InvalidTransactionId if it has no new data.
00663      */
00664     if (TransactionIdIsNormal(frozenxid) &&
00665         TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid))
00666     {
00667         pgcform->relfrozenxid = frozenxid;
00668         dirty = true;
00669     }
00670 
00671     /* relminmxid must never go backward, either */
00672     if (MultiXactIdIsValid(minmulti) &&
00673         MultiXactIdPrecedes(pgcform->relminmxid, minmulti))
00674     {
00675         pgcform->relminmxid = minmulti;
00676         dirty = true;
00677     }
00678 
00679     /* If anything changed, write out the tuple. */
00680     if (dirty)
00681         heap_inplace_update(rd, ctup);
00682 
00683     heap_close(rd, RowExclusiveLock);
00684 }
00685 
00686 
00687 /*
00688  *  vac_update_datfrozenxid() -- update pg_database.datfrozenxid for our DB
00689  *
00690  *      Update pg_database's datfrozenxid entry for our database to be the
00691  *      minimum of the pg_class.relfrozenxid values.
00692  *
00693  *      Similarly, update our datfrozenmulti to be the minimum of the
00694  *      pg_class.relfrozenmulti values.
00695  *
00696  *      If we are able to advance either pg_database value, also try to
00697  *      truncate pg_clog and pg_multixact.
00698  *
00699  *      We violate transaction semantics here by overwriting the database's
00700  *      existing pg_database tuple with the new value.  This is reasonably
00701  *      safe since the new value is correct whether or not this transaction
00702  *      commits.  As with vac_update_relstats, this avoids leaving dead tuples
00703  *      behind after a VACUUM.
00704  */
00705 void
00706 vac_update_datfrozenxid(void)
00707 {
00708     HeapTuple   tuple;
00709     Form_pg_database dbform;
00710     Relation    relation;
00711     SysScanDesc scan;
00712     HeapTuple   classTup;
00713     TransactionId newFrozenXid;
00714     MultiXactId newFrozenMulti;
00715     bool        dirty = false;
00716 
00717     /*
00718      * Initialize the "min" calculation with GetOldestXmin, which is a
00719      * reasonable approximation to the minimum relfrozenxid for not-yet-
00720      * committed pg_class entries for new tables; see AddNewRelationTuple().
00721      * So we cannot produce a wrong minimum by starting with this.
00722      */
00723     newFrozenXid = GetOldestXmin(true, true);
00724 
00725     /*
00726      * Similarly, initialize the MultiXact "min" with the value that would
00727      * be used on pg_class for new tables.  See AddNewRelationTuple().
00728      */
00729     newFrozenMulti = GetOldestMultiXactId();
00730 
00731     /*
00732      * We must seqscan pg_class to find the minimum Xid, because there is no
00733      * index that can help us here.
00734      */
00735     relation = heap_open(RelationRelationId, AccessShareLock);
00736 
00737     scan = systable_beginscan(relation, InvalidOid, false,
00738                               SnapshotNow, 0, NULL);
00739 
00740     while ((classTup = systable_getnext(scan)) != NULL)
00741     {
00742         Form_pg_class classForm = (Form_pg_class) GETSTRUCT(classTup);
00743 
00744         /*
00745          * Only consider heap and TOAST tables (anything else should have
00746          * InvalidTransactionId in relfrozenxid anyway.)
00747          */
00748         if (classForm->relkind != RELKIND_RELATION &&
00749             classForm->relkind != RELKIND_MATVIEW &&
00750             classForm->relkind != RELKIND_TOASTVALUE)
00751             continue;
00752 
00753         Assert(TransactionIdIsNormal(classForm->relfrozenxid));
00754         Assert(MultiXactIdIsValid(classForm->relminmxid));
00755 
00756         if (TransactionIdPrecedes(classForm->relfrozenxid, newFrozenXid))
00757             newFrozenXid = classForm->relfrozenxid;
00758 
00759         if (MultiXactIdPrecedes(classForm->relminmxid, newFrozenMulti))
00760             newFrozenMulti = classForm->relminmxid;
00761     }
00762 
00763     /* we're done with pg_class */
00764     systable_endscan(scan);
00765     heap_close(relation, AccessShareLock);
00766 
00767     Assert(TransactionIdIsNormal(newFrozenXid));
00768     Assert(MultiXactIdIsValid(newFrozenMulti));
00769 
00770     /* Now fetch the pg_database tuple we need to update. */
00771     relation = heap_open(DatabaseRelationId, RowExclusiveLock);
00772 
00773     /* Fetch a copy of the tuple to scribble on */
00774     tuple = SearchSysCacheCopy1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
00775     if (!HeapTupleIsValid(tuple))
00776         elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
00777     dbform = (Form_pg_database) GETSTRUCT(tuple);
00778 
00779     /*
00780      * Don't allow datfrozenxid to go backward (probably can't happen anyway);
00781      * and detect the common case where it doesn't go forward either.
00782      */
00783     if (TransactionIdPrecedes(dbform->datfrozenxid, newFrozenXid))
00784     {
00785         dbform->datfrozenxid = newFrozenXid;
00786         dirty = true;
00787     }
00788 
00789     /* ditto */
00790     if (MultiXactIdPrecedes(dbform->datminmxid, newFrozenMulti))
00791     {
00792         dbform->datminmxid = newFrozenMulti;
00793         dirty = true;
00794     }
00795 
00796     if (dirty)
00797         heap_inplace_update(relation, tuple);
00798 
00799     heap_freetuple(tuple);
00800     heap_close(relation, RowExclusiveLock);
00801 
00802     /*
00803      * If we were able to advance datfrozenxid, see if we can truncate
00804      * pg_clog. Also do it if the shared XID-wrap-limit info is stale, since
00805      * this action will update that too.
00806      */
00807     if (dirty || ForceTransactionIdLimitUpdate())
00808         vac_truncate_clog(newFrozenXid, newFrozenMulti);
00809 }
00810 
00811 
00812 /*
00813  *  vac_truncate_clog() -- attempt to truncate the commit log
00814  *
00815  *      Scan pg_database to determine the system-wide oldest datfrozenxid,
00816  *      and use it to truncate the transaction commit log (pg_clog).
00817  *      Also update the XID wrap limit info maintained by varsup.c.
00818  *
00819  *      The passed XID is simply the one I just wrote into my pg_database
00820  *      entry.  It's used to initialize the "min" calculation.
00821  *
00822  *      This routine is only invoked when we've managed to change our
00823  *      DB's datfrozenxid entry, or we found that the shared XID-wrap-limit
00824  *      info is stale.
00825  */
00826 static void
00827 vac_truncate_clog(TransactionId frozenXID, MultiXactId frozenMulti)
00828 {
00829     TransactionId myXID = GetCurrentTransactionId();
00830     Relation    relation;
00831     HeapScanDesc scan;
00832     HeapTuple   tuple;
00833     Oid         oldestxid_datoid;
00834     Oid         oldestmulti_datoid;
00835     bool        frozenAlreadyWrapped = false;
00836 
00837     /* init oldest datoids to sync with my frozen values */
00838     oldestxid_datoid = MyDatabaseId;
00839     oldestmulti_datoid = MyDatabaseId;
00840 
00841     /*
00842      * Scan pg_database to compute the minimum datfrozenxid
00843      *
00844      * Note: we need not worry about a race condition with new entries being
00845      * inserted by CREATE DATABASE.  Any such entry will have a copy of some
00846      * existing DB's datfrozenxid, and that source DB cannot be ours because
00847      * of the interlock against copying a DB containing an active backend.
00848      * Hence the new entry will not reduce the minimum.  Also, if two VACUUMs
00849      * concurrently modify the datfrozenxid's of different databases, the
00850      * worst possible outcome is that pg_clog is not truncated as aggressively
00851      * as it could be.
00852      */
00853     relation = heap_open(DatabaseRelationId, AccessShareLock);
00854 
00855     scan = heap_beginscan(relation, SnapshotNow, 0, NULL);
00856 
00857     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00858     {
00859         Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
00860 
00861         Assert(TransactionIdIsNormal(dbform->datfrozenxid));
00862         Assert(MultiXactIdIsValid(dbform->datminmxid));
00863 
00864         if (TransactionIdPrecedes(myXID, dbform->datfrozenxid))
00865             frozenAlreadyWrapped = true;
00866         else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
00867         {
00868             frozenXID = dbform->datfrozenxid;
00869             oldestxid_datoid = HeapTupleGetOid(tuple);
00870         }
00871 
00872         if (MultiXactIdPrecedes(dbform->datminmxid, frozenMulti))
00873         {
00874             frozenMulti = dbform->datminmxid;
00875             oldestmulti_datoid = HeapTupleGetOid(tuple);
00876         }
00877     }
00878 
00879     heap_endscan(scan);
00880 
00881     heap_close(relation, AccessShareLock);
00882 
00883     /*
00884      * Do not truncate CLOG if we seem to have suffered wraparound already;
00885      * the computed minimum XID might be bogus.  This case should now be
00886      * impossible due to the defenses in GetNewTransactionId, but we keep the
00887      * test anyway.
00888      */
00889     if (frozenAlreadyWrapped)
00890     {
00891         ereport(WARNING,
00892                 (errmsg("some databases have not been vacuumed in over 2 billion transactions"),
00893                  errdetail("You might have already suffered transaction-wraparound data loss.")));
00894         return;
00895     }
00896 
00897     /* Truncate CLOG and Multi to the oldest computed value */
00898     TruncateCLOG(frozenXID);
00899     TruncateMultiXact(frozenMulti);
00900 
00901     /*
00902      * Update the wrap limit for GetNewTransactionId and creation of new
00903      * MultiXactIds.  Note: these functions will also signal the postmaster for
00904      * an(other) autovac cycle if needed.   XXX should we avoid possibly
00905      * signalling twice?
00906      */
00907     SetTransactionIdLimit(frozenXID, oldestxid_datoid);
00908     MultiXactAdvanceOldest(frozenMulti, oldestmulti_datoid);
00909 }
00910 
00911 
00912 /*
00913  *  vacuum_rel() -- vacuum one heap relation
00914  *
00915  *      Doing one heap at a time incurs extra overhead, since we need to
00916  *      check that the heap exists again just before we vacuum it.  The
00917  *      reason that we do this is so that vacuuming can be spread across
00918  *      many small transactions.  Otherwise, two-phase locking would require
00919  *      us to lock the entire database during one pass of the vacuum cleaner.
00920  *
00921  *      At entry and exit, we are not inside a transaction.
00922  */
00923 static bool
00924 vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
00925 {
00926     LOCKMODE    lmode;
00927     Relation    onerel;
00928     LockRelId   onerelid;
00929     Oid         toast_relid;
00930     Oid         save_userid;
00931     int         save_sec_context;
00932     int         save_nestlevel;
00933 
00934     /* Begin a transaction for vacuuming this relation */
00935     StartTransactionCommand();
00936 
00937     /*
00938      * Functions in indexes may want a snapshot set.  Also, setting a snapshot
00939      * ensures that RecentGlobalXmin is kept truly recent.
00940      */
00941     PushActiveSnapshot(GetTransactionSnapshot());
00942 
00943     if (!(vacstmt->options & VACOPT_FULL))
00944     {
00945         /*
00946          * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets
00947          * other concurrent VACUUMs know that they can ignore this one while
00948          * determining their OldestXmin.  (The reason we don't set it during a
00949          * full VACUUM is exactly that we may have to run user-defined
00950          * functions for functional indexes, and we want to make sure that if
00951          * they use the snapshot set above, any tuples it requires can't get
00952          * removed from other tables.  An index function that depends on the
00953          * contents of other tables is arguably broken, but we won't break it
00954          * here by violating transaction semantics.)
00955          *
00956          * We also set the VACUUM_FOR_WRAPAROUND flag, which is passed down by
00957          * autovacuum; it's used to avoid canceling a vacuum that was invoked
00958          * in an emergency.
00959          *
00960          * Note: these flags remain set until CommitTransaction or
00961          * AbortTransaction.  We don't want to clear them until we reset
00962          * MyPgXact->xid/xmin, else OldestXmin might appear to go backwards,
00963          * which is probably Not Good.
00964          */
00965         LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
00966         MyPgXact->vacuumFlags |= PROC_IN_VACUUM;
00967         if (for_wraparound)
00968             MyPgXact->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
00969         LWLockRelease(ProcArrayLock);
00970     }
00971 
00972     /*
00973      * Check for user-requested abort.  Note we want this to be inside a
00974      * transaction, so xact.c doesn't issue useless WARNING.
00975      */
00976     CHECK_FOR_INTERRUPTS();
00977 
00978     /*
00979      * Determine the type of lock we want --- hard exclusive lock for a FULL
00980      * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either
00981      * way, we can be sure that no other backend is vacuuming the same table.
00982      */
00983     lmode = (vacstmt->options & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock;
00984 
00985     /*
00986      * Open the relation and get the appropriate lock on it.
00987      *
00988      * There's a race condition here: the rel may have gone away since the
00989      * last time we saw it.  If so, we don't need to vacuum it.
00990      *
00991      * If we've been asked not to wait for the relation lock, acquire it first
00992      * in non-blocking mode, before calling try_relation_open().
00993      */
00994     if (!(vacstmt->options & VACOPT_NOWAIT))
00995         onerel = try_relation_open(relid, lmode);
00996     else if (ConditionalLockRelationOid(relid, lmode))
00997         onerel = try_relation_open(relid, NoLock);
00998     else
00999     {
01000         onerel = NULL;
01001         if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
01002             ereport(LOG,
01003                     (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
01004                    errmsg("skipping vacuum of \"%s\" --- lock not available",
01005                           vacstmt->relation->relname)));
01006     }
01007 
01008     if (!onerel)
01009     {
01010         PopActiveSnapshot();
01011         CommitTransactionCommand();
01012         return false;
01013     }
01014 
01015     /*
01016      * Check permissions.
01017      *
01018      * We allow the user to vacuum a table if he is superuser, the table
01019      * owner, or the database owner (but in the latter case, only if it's not
01020      * a shared relation).  pg_class_ownercheck includes the superuser case.
01021      *
01022      * Note we choose to treat permissions failure as a WARNING and keep
01023      * trying to vacuum the rest of the DB --- is this appropriate?
01024      */
01025     if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
01026           (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared)))
01027     {
01028         if (onerel->rd_rel->relisshared)
01029             ereport(WARNING,
01030                   (errmsg("skipping \"%s\" --- only superuser can vacuum it",
01031                           RelationGetRelationName(onerel))));
01032         else if (onerel->rd_rel->relnamespace == PG_CATALOG_NAMESPACE)
01033             ereport(WARNING,
01034                     (errmsg("skipping \"%s\" --- only superuser or database owner can vacuum it",
01035                             RelationGetRelationName(onerel))));
01036         else
01037             ereport(WARNING,
01038                     (errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
01039                             RelationGetRelationName(onerel))));
01040         relation_close(onerel, lmode);
01041         PopActiveSnapshot();
01042         CommitTransactionCommand();
01043         return false;
01044     }
01045 
01046     /*
01047      * Check that it's a vacuumable table; we used to do this in
01048      * get_rel_oids() but seems safer to check after we've locked the
01049      * relation.
01050      */
01051     if (onerel->rd_rel->relkind != RELKIND_RELATION &&
01052         onerel->rd_rel->relkind != RELKIND_MATVIEW &&
01053         onerel->rd_rel->relkind != RELKIND_TOASTVALUE)
01054     {
01055         ereport(WARNING,
01056                 (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
01057                         RelationGetRelationName(onerel))));
01058         relation_close(onerel, lmode);
01059         PopActiveSnapshot();
01060         CommitTransactionCommand();
01061         return false;
01062     }
01063 
01064     /*
01065      * Silently ignore tables that are temp tables of other backends ---
01066      * trying to vacuum these will lead to great unhappiness, since their
01067      * contents are probably not up-to-date on disk.  (We don't throw a
01068      * warning here; it would just lead to chatter during a database-wide
01069      * VACUUM.)
01070      */
01071     if (RELATION_IS_OTHER_TEMP(onerel))
01072     {
01073         relation_close(onerel, lmode);
01074         PopActiveSnapshot();
01075         CommitTransactionCommand();
01076         return false;
01077     }
01078 
01079     /*
01080      * Get a session-level lock too. This will protect our access to the
01081      * relation across multiple transactions, so that we can vacuum the
01082      * relation's TOAST table (if any) secure in the knowledge that no one is
01083      * deleting the parent relation.
01084      *
01085      * NOTE: this cannot block, even if someone else is waiting for access,
01086      * because the lock manager knows that both lock requests are from the
01087      * same process.
01088      */
01089     onerelid = onerel->rd_lockInfo.lockRelId;
01090     LockRelationIdForSession(&onerelid, lmode);
01091 
01092     /*
01093      * Remember the relation's TOAST relation for later, if the caller asked
01094      * us to process it.  In VACUUM FULL, though, the toast table is
01095      * automatically rebuilt by cluster_rel so we shouldn't recurse to it.
01096      */
01097     if (do_toast && !(vacstmt->options & VACOPT_FULL))
01098         toast_relid = onerel->rd_rel->reltoastrelid;
01099     else
01100         toast_relid = InvalidOid;
01101 
01102     /*
01103      * Switch to the table owner's userid, so that any index functions are run
01104      * as that user.  Also lock down security-restricted operations and
01105      * arrange to make GUC variable changes local to this command. (This is
01106      * unnecessary, but harmless, for lazy VACUUM.)
01107      */
01108     GetUserIdAndSecContext(&save_userid, &save_sec_context);
01109     SetUserIdAndSecContext(onerel->rd_rel->relowner,
01110                            save_sec_context | SECURITY_RESTRICTED_OPERATION);
01111     save_nestlevel = NewGUCNestLevel();
01112 
01113     /*
01114      * Do the actual work --- either FULL or "lazy" vacuum
01115      */
01116     if (vacstmt->options & VACOPT_FULL)
01117     {
01118         /* close relation before vacuuming, but hold lock until commit */
01119         relation_close(onerel, NoLock);
01120         onerel = NULL;
01121 
01122         /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
01123         cluster_rel(relid, InvalidOid, false,
01124                     (vacstmt->options & VACOPT_VERBOSE) != 0,
01125                     vacstmt->freeze_min_age, vacstmt->freeze_table_age);
01126     }
01127     else
01128         lazy_vacuum_rel(onerel, vacstmt, vac_strategy);
01129 
01130     /* Roll back any GUC changes executed by index functions */
01131     AtEOXact_GUC(false, save_nestlevel);
01132 
01133     /* Restore userid and security context */
01134     SetUserIdAndSecContext(save_userid, save_sec_context);
01135 
01136     /* all done with this class, but hold lock until commit */
01137     if (onerel)
01138         relation_close(onerel, NoLock);
01139 
01140     /*
01141      * Complete the transaction and free all temporary memory used.
01142      */
01143     PopActiveSnapshot();
01144     CommitTransactionCommand();
01145 
01146     /*
01147      * If the relation has a secondary toast rel, vacuum that too while we
01148      * still hold the session lock on the master table.  Note however that
01149      * "analyze" will not get done on the toast table.  This is good, because
01150      * the toaster always uses hardcoded index access and statistics are
01151      * totally unimportant for toast relations.
01152      */
01153     if (toast_relid != InvalidOid)
01154         vacuum_rel(toast_relid, vacstmt, false, for_wraparound);
01155 
01156     /*
01157      * Now release the session-level lock on the master table.
01158      */
01159     UnlockRelationIdForSession(&onerelid, lmode);
01160 
01161     /* Report that we really did it. */
01162     return true;
01163 }
01164 
01165 
01166 /*
01167  * Open all the vacuumable indexes of the given relation, obtaining the
01168  * specified kind of lock on each.  Return an array of Relation pointers for
01169  * the indexes into *Irel, and the number of indexes into *nindexes.
01170  *
01171  * We consider an index vacuumable if it is marked insertable (IndexIsReady).
01172  * If it isn't, probably a CREATE INDEX CONCURRENTLY command failed early in
01173  * execution, and what we have is too corrupt to be processable.  We will
01174  * vacuum even if the index isn't indisvalid; this is important because in a
01175  * unique index, uniqueness checks will be performed anyway and had better not
01176  * hit dangling index pointers.
01177  */
01178 void
01179 vac_open_indexes(Relation relation, LOCKMODE lockmode,
01180                  int *nindexes, Relation **Irel)
01181 {
01182     List       *indexoidlist;
01183     ListCell   *indexoidscan;
01184     int         i;
01185 
01186     Assert(lockmode != NoLock);
01187 
01188     indexoidlist = RelationGetIndexList(relation);
01189 
01190     /* allocate enough memory for all indexes */
01191     i = list_length(indexoidlist);
01192 
01193     if (i > 0)
01194         *Irel = (Relation *) palloc(i * sizeof(Relation));
01195     else
01196         *Irel = NULL;
01197 
01198     /* collect just the ready indexes */
01199     i = 0;
01200     foreach(indexoidscan, indexoidlist)
01201     {
01202         Oid         indexoid = lfirst_oid(indexoidscan);
01203         Relation    indrel;
01204 
01205         indrel = index_open(indexoid, lockmode);
01206         if (IndexIsReady(indrel->rd_index))
01207             (*Irel)[i++] = indrel;
01208         else
01209             index_close(indrel, lockmode);
01210     }
01211 
01212     *nindexes = i;
01213 
01214     list_free(indexoidlist);
01215 }
01216 
01217 /*
01218  * Release the resources acquired by vac_open_indexes.  Optionally release
01219  * the locks (say NoLock to keep 'em).
01220  */
01221 void
01222 vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode)
01223 {
01224     if (Irel == NULL)
01225         return;
01226 
01227     while (nindexes--)
01228     {
01229         Relation    ind = Irel[nindexes];
01230 
01231         index_close(ind, lockmode);
01232     }
01233     pfree(Irel);
01234 }
01235 
01236 /*
01237  * vacuum_delay_point --- check for interrupts and cost-based delay.
01238  *
01239  * This should be called in each major loop of VACUUM processing,
01240  * typically once per page processed.
01241  */
01242 void
01243 vacuum_delay_point(void)
01244 {
01245     /* Always check for interrupts */
01246     CHECK_FOR_INTERRUPTS();
01247 
01248     /* Nap if appropriate */
01249     if (VacuumCostActive && !InterruptPending &&
01250         VacuumCostBalance >= VacuumCostLimit)
01251     {
01252         int         msec;
01253 
01254         msec = VacuumCostDelay * VacuumCostBalance / VacuumCostLimit;
01255         if (msec > VacuumCostDelay * 4)
01256             msec = VacuumCostDelay * 4;
01257 
01258         pg_usleep(msec * 1000L);
01259 
01260         VacuumCostBalance = 0;
01261 
01262         /* update balance values for workers */
01263         AutoVacuumUpdateDelay();
01264 
01265         /* Might have gotten an interrupt while sleeping */
01266         CHECK_FOR_INTERRUPTS();
01267     }
01268 }