Rearrange vacuum-related bits in PGPROC as a bitmask, to better support
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 24 Oct 2007 20:55:36 +0000 (20:55 +0000)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 24 Oct 2007 20:55:36 +0000 (20:55 +0000)
having several of them.  Add two more flags: whether the process is
executing an ANALYZE, and whether a vacuum is for Xid wraparound (which
is obviously only set by autovacuum).

Sneakily move the worker's recently-acquired PostAuthDelay to a more useful
place.

src/backend/access/transam/twophase.c
src/backend/commands/analyze.c
src/backend/commands/vacuum.c
src/backend/postmaster/autovacuum.c
src/backend/storage/ipc/procarray.c
src/backend/storage/lmgr/proc.c
src/include/storage/proc.h

index ae2b8dcd6956fcdf2e67271edc1fc05a42e82556..6ce9d1b5864d7a6450333c4f72822f20d0840977 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *     $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.36 2007/09/21 16:32:19 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.37 2007/10/24 20:55:36 alvherre Exp $
  *
  * NOTES
  *     Each global transaction is associated with a global transaction
@@ -283,8 +283,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
    gxact->proc.databaseId = databaseid;
    gxact->proc.roleId = owner;
    gxact->proc.inCommit = false;
-   gxact->proc.inVacuum = false;
-   gxact->proc.isAutovacuum = false;
+   gxact->proc.vacuumFlags = 0;
    gxact->proc.lwWaiting = false;
    gxact->proc.lwExclusive = false;
    gxact->proc.lwWaitLink = NULL;
index 418dbaa1084d69d2362ab4b55ef143b62f60b420..51944c54c2801d96041f270a3ce20495068637de 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.109 2007/09/24 03:12:23 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.110 2007/10/24 20:55:36 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,6 +31,7 @@
 #include "parser/parse_relation.h"
 #include "pgstat.h"
 #include "postmaster/autovacuum.h"
+#include "storage/proc.h"
 #include "utils/acl.h"
 #include "utils/datum.h"
 #include "utils/lsyscache.h"
@@ -201,6 +202,11 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
        return;
    }
 
+   /* let others know what I'm doing */
+   LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+   MyProc->vacuumFlags |= PROC_IN_ANALYZE;
+   LWLockRelease(ProcArrayLock);
+
    /* measure elapsed time iff autovacuum logging requires it */
    if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
    {
@@ -484,6 +490,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
                            RelationGetRelationName(onerel),
                            pg_rusage_show(&ru0))));
    }
+
+   /*
+    * Reset my PGPROC flag.  Note: we need this here, and not in vacuum_rel,
+    * because the vacuum flag is cleared by the end-of-xact code.
+    */
+   LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+   MyProc->vacuumFlags &= ~PROC_IN_ANALYZE;
+   LWLockRelease(ProcArrayLock);
 }
 
 /*
index 5630fc2730d7569ea7690db419e76c999c0a4906..55ce0dbade908797cc6a054a5c2c20d1892779cc 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.359 2007/09/20 17:56:31 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.360 2007/10/24 20:55:36 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -660,9 +660,9 @@ vacuum_set_xid_limits(int freeze_min_age, bool sharedRel,
  *     fixed-size never-null columns, but these are.
  *
  *     Another reason for doing it this way is that when we are in a lazy
- *     VACUUM and have inVacuum set, we mustn't do any updates --- somebody
- *     vacuuming pg_class might think they could delete a tuple marked with
- *     xmin = our xid.
+ *     VACUUM and have PROC_IN_VACUUM set, we mustn't do any updates ---
+ *     somebody vacuuming pg_class might think they could delete a tuple
+ *     marked with xmin = our xid.
  *
  *     This routine is shared by full VACUUM, lazy VACUUM, and stand-alone
  *     ANALYZE.
@@ -987,9 +987,9 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
         * During a lazy VACUUM we do not run any user-supplied functions, and
         * so it should be safe to not create a transaction snapshot.
         *
-        * We can furthermore set the inVacuum flag, which lets other
+        * We can furthermore set the PROC_IN_VACUUM flag, which lets other
         * concurrent VACUUMs know that they can ignore this one while
-        * determining their OldestXmin.  (The reason we don't set inVacuum
+        * determining their OldestXmin.  (The reason we don't set it
         * during a full VACUUM is exactly that we may have to run user-
         * defined functions for functional indexes, and we want to make sure
         * that if they use the snapshot set above, any tuples it requires
@@ -997,12 +997,14 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
         * depends on the contents of other tables is arguably broken, but we
         * won't break it here by violating transaction semantics.)
         *
-        * Note: the inVacuum flag remains set until CommitTransaction or
+        * Note: this flag remains set until CommitTransaction or
         * AbortTransaction.  We don't want to clear it until we reset
         * MyProc->xid/xmin, else OldestXmin might appear to go backwards,
         * which is probably Not Good.
         */
-       MyProc->inVacuum = true;
+       LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+       MyProc->vacuumFlags |= PROC_IN_VACUUM;
+       LWLockRelease(ProcArrayLock);
    }
 
    /*
index 9e472d02ff6bd20fd22e4c11cf683e522069c6cc..ea586f899a5975f8c0014c5be47c93ec34052234 100644 (file)
@@ -55,7 +55,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.62 2007/10/24 19:08:25 alvherre Exp $
+ *   $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.63 2007/10/24 20:55:36 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -172,6 +172,7 @@ typedef struct autovac_table
    int         at_freeze_min_age;
    int         at_vacuum_cost_delay;
    int         at_vacuum_cost_limit;
+   bool        at_wraparound;
 } autovac_table;
 
 /*-------------
@@ -280,7 +281,7 @@ static autovac_table *table_recheck_autovac(Oid relid);
 static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
                          Form_pg_class classForm,
                          PgStat_StatTabEntry *tabentry, bool *dovacuum,
-                         bool *doanalyze);
+                         bool *doanalyze, bool *wraparound);
 
 static void autovacuum_do_vac_analyze(Oid relid, bool dovacuum,
                          bool doanalyze, int freeze_min_age,
@@ -1440,9 +1441,6 @@ AutoVacWorkerMain(int argc, char *argv[])
    /* Identify myself via ps */
    init_ps_display("autovacuum worker process", "", "", "");
 
-   if (PostAuthDelay)
-       pg_usleep(PostAuthDelay * 1000000L);
-
    SetProcessingMode(InitProcessing);
 
    /*
@@ -1601,6 +1599,9 @@ AutoVacWorkerMain(int argc, char *argv[])
        ereport(DEBUG1,
                (errmsg("autovacuum: processing database \"%s\"", dbname)));
 
+       if (PostAuthDelay)
+           pg_usleep(PostAuthDelay * 1000000L);
+
        /* And do an appropriate amount of work */
        recentXid = ReadNewTransactionId();
        do_autovacuum();
@@ -2085,6 +2086,14 @@ next_worker:
        /* clean up memory before each iteration */
        MemoryContextResetAndDeleteChildren(PortalContext);
 
+       /* set the "vacuum for wraparound" flag in PGPROC */
+       if (tab->at_wraparound)
+       {
+           LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+           MyProc->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
+           LWLockRelease(ProcArrayLock);
+       }
+
        /*
         * We will abort vacuuming the current table if something errors out,
         * and continue with the next one in schedule; in particular, this
@@ -2119,6 +2128,7 @@ next_worker:
                           get_rel_name(tab->at_relid));
            EmitErrorReport();
 
+           /* this resets the PGPROC flags too */
            AbortOutOfAnyTransaction();
            FlushErrorState();
            MemoryContextResetAndDeleteChildren(PortalContext);
@@ -2129,6 +2139,14 @@ next_worker:
        }
        PG_END_TRY();
 
+       /* reset my PGPROC flag */
+       if (tab->at_wraparound)
+       {
+           LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+           MyProc->vacuumFlags &= ~PROC_VACUUM_FOR_WRAPAROUND;
+           LWLockRelease(ProcArrayLock);
+       }
+
        /* be tidy */
        pfree(tab);
 
@@ -2223,9 +2241,10 @@ relation_check_autovac(Oid relid, Form_pg_class classForm,
 {
    bool    dovacuum;
    bool    doanalyze;
+   bool    dummy;
 
    relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
-                             &dovacuum, &doanalyze);
+                             &dovacuum, &doanalyze, &dummy);
 
    if (classForm->relkind == RELKIND_TOASTVALUE)
    {
@@ -2272,6 +2291,8 @@ table_recheck_autovac(Oid relid)
    bool        doit = false;
    PgStat_StatDBEntry *shared;
    PgStat_StatDBEntry *dbentry;
+   bool        wraparound,
+               toast_wraparound = false;
 
    /* use fresh stats */
    autovac_refresh_stats();
@@ -2298,7 +2319,7 @@ table_recheck_autovac(Oid relid)
                                         shared, dbentry);
 
    relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
-                             &dovacuum, &doanalyze);
+                             &dovacuum, &doanalyze, &wraparound);
 
    /* OK, it needs vacuum by itself */
    if (dovacuum)
@@ -2316,6 +2337,7 @@ table_recheck_autovac(Oid relid)
        {
            bool            toast_dovacuum;
            bool            toast_doanalyze;
+           bool            toast_wraparound;
            Form_pg_class   toastClassForm;
            PgStat_StatTabEntry *toasttabentry;
 
@@ -2325,9 +2347,10 @@ table_recheck_autovac(Oid relid)
                                                      shared, dbentry);
 
            /* note we use the pg_autovacuum entry for the main table */
-           relation_needs_vacanalyze(toastrelid, avForm, toastClassForm,
-                                     toasttabentry, &toast_dovacuum,
-                                     &toast_doanalyze);
+           relation_needs_vacanalyze(toastrelid, avForm,
+                                     toastClassForm, toasttabentry,
+                                     &toast_dovacuum, &toast_doanalyze,
+                                     &toast_wraparound);
            /* we only consider VACUUM for toast tables */
            if (toast_dovacuum)
            {
@@ -2389,6 +2412,7 @@ table_recheck_autovac(Oid relid)
        tab->at_freeze_min_age = freeze_min_age;
        tab->at_vacuum_cost_limit = vac_cost_limit;
        tab->at_vacuum_cost_delay = vac_cost_delay;
+       tab->at_wraparound = wraparound || toast_wraparound;
    }
 
    heap_close(avRel, AccessShareLock);
@@ -2403,7 +2427,8 @@ table_recheck_autovac(Oid relid)
  * relation_needs_vacanalyze
  *
  * Check whether a relation needs to be vacuumed or analyzed; return each into
- * "dovacuum" and "doanalyze", respectively.  avForm and tabentry can be NULL,
+ * "dovacuum" and "doanalyze", respectively.  Also return whether the vacuum is
+ * being forced because of Xid wraparound.  avForm and tabentry can be NULL,
  * classForm shouldn't.
  *
  * A table needs to be vacuumed if the number of dead tuples exceeds a
@@ -2437,7 +2462,8 @@ relation_needs_vacanalyze(Oid relid,
                          PgStat_StatTabEntry *tabentry,
                          /* output params below */
                          bool *dovacuum,
-                         bool *doanalyze)
+                         bool *doanalyze,
+                         bool *wraparound)
 {
    bool        force_vacuum;
    float4      reltuples;      /* pg_class.reltuples */
@@ -2499,6 +2525,7 @@ relation_needs_vacanalyze(Oid relid,
    force_vacuum = (TransactionIdIsNormal(classForm->relfrozenxid) &&
                    TransactionIdPrecedes(classForm->relfrozenxid,
                                          xidForceLimit));
+   *wraparound = force_vacuum;
 
    /* User disabled it in pg_autovacuum?  (But ignore if at risk) */
    if (avForm && !avForm->enabled && !force_vacuum)
index 90ba09d5a881d87b9b4fcb238c4f72014166c805..c455c89f998c20fbea2795d1e716de9a1bf42d49 100644 (file)
@@ -23,7 +23,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.35 2007/09/23 18:50:38 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.36 2007/10/24 20:55:36 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -242,7 +242,8 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
        proc->xid = InvalidTransactionId;
        proc->lxid = InvalidLocalTransactionId;
        proc->xmin = InvalidTransactionId;
-       proc->inVacuum = false;         /* must be cleared with xid/xmin */
+       /* must be cleared with xid/xmin: */
+       proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
        proc->inCommit = false;         /* be sure this is cleared in abort */
 
        /* Clear the subtransaction-XID cache too while holding the lock */
@@ -267,7 +268,8 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
 
        proc->lxid = InvalidLocalTransactionId;
        proc->xmin = InvalidTransactionId;
-       proc->inVacuum = false;         /* must be cleared with xid/xmin */
+       /* must be cleared with xid/xmin: */
+       proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
        proc->inCommit = false;         /* be sure this is cleared in abort */
 
        Assert(proc->subxids.nxids == 0);
@@ -296,8 +298,10 @@ ProcArrayClearTransaction(PGPROC *proc)
    proc->xid = InvalidTransactionId;
    proc->lxid = InvalidLocalTransactionId;
    proc->xmin = InvalidTransactionId;
-   proc->inVacuum = false;         /* redundant, but just in case */
-   proc->inCommit = false;         /* ditto */
+
+   /* redundant, but just in case */
+   proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
+   proc->inCommit = false;
 
    /* Clear the subtransaction-XID cache too */
    proc->subxids.nxids = 0;
@@ -546,7 +550,8 @@ TransactionIdIsActive(TransactionId xid)
  * If allDbs is TRUE then all backends are considered; if allDbs is FALSE
  * then only backends running in my own database are considered.
  *
- * If ignoreVacuum is TRUE then backends with inVacuum set are ignored.
+ * If ignoreVacuum is TRUE then backends with the PROC_IN_VACUUM flag set are
+ * ignored.
  *
  * This is used by VACUUM to decide which deleted tuples must be preserved
  * in a table. allDbs = TRUE is needed for shared relations, but allDbs =
@@ -586,7 +591,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
    {
        volatile PGPROC    *proc = arrayP->procs[index];
 
-       if (ignoreVacuum && proc->inVacuum)
+       if (ignoreVacuum && (proc->vacuumFlags & PROC_IN_VACUUM))
            continue;
 
        if (allDbs || proc->databaseId == MyDatabaseId)
@@ -723,7 +728,7 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
        TransactionId xid;
 
        /* Ignore procs running LAZY VACUUM */
-       if (proc->inVacuum)
+       if (proc->vacuumFlags & PROC_IN_VACUUM)
            continue;
 
        /* Update globalxmin to be the smallest valid xmin */
@@ -1193,7 +1198,7 @@ CheckOtherDBBackends(Oid databaseId)
 
            found = true;
 
-           if (proc->isAutovacuum)
+           if (proc->vacuumFlags & PROC_IS_AUTOVACUUM)
            {
                /* an autovacuum --- send it SIGTERM before sleeping */
                int     autopid = proc->pid;
index ddebdcc5e2ad5221ad304166df86d5b09b6c26a7..fdf089f836c39dc8dc707f551913d47ba2101d8b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.194 2007/09/08 20:31:15 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.195 2007/10/24 20:55:36 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -291,8 +291,9 @@ InitProcess(void)
    MyProc->databaseId = InvalidOid;
    MyProc->roleId = InvalidOid;
    MyProc->inCommit = false;
-   MyProc->inVacuum = false;
-   MyProc->isAutovacuum = IsAutoVacuumWorkerProcess();
+   MyProc->vacuumFlags = 0;
+   if (IsAutoVacuumWorkerProcess())
+       MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM;
    MyProc->lwWaiting = false;
    MyProc->lwExclusive = false;
    MyProc->lwWaitLink = NULL;
@@ -429,8 +430,8 @@ InitAuxiliaryProcess(void)
    MyProc->databaseId = InvalidOid;
    MyProc->roleId = InvalidOid;
    MyProc->inCommit = false;
-   MyProc->inVacuum = false;
-   MyProc->isAutovacuum = IsAutoVacuumLauncherProcess(); /* is this needed? */
+   /* we don't set the "is autovacuum" flag in the launcher */
+   MyProc->vacuumFlags = 0;
    MyProc->lwWaiting = false;
    MyProc->lwExclusive = false;
    MyProc->lwWaitLink = NULL;
index 9fefa0a5a93e5bd2dfe4505caca7935e8d8cc222..4ffb51b43451751ec4323ec7224a53a638a42599 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.100 2007/09/05 18:10:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.101 2007/10/24 20:55:36 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,6 +38,15 @@ struct XidCache
    TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS];
 };
 
+/* Flags for PGPROC->vacuumFlags */
+#define        PROC_IS_AUTOVACUUM  0x01    /* is it an autovac worker? */
+#define        PROC_IN_VACUUM      0x02    /* currently running lazy vacuum */
+#define        PROC_IN_ANALYZE     0x04    /* currently running analyze */
+#define        PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */
+
+/* flags reset at EOXact */
+#define        PROC_VACUUM_STATE_MASK (0x0E)
+
 /*
  * Each backend has a PGPROC struct in shared memory.  There is also a list of
  * currently-unused PGPROC structs that will be reallocated to new backends.
@@ -82,8 +91,7 @@ struct PGPROC
 
    bool        inCommit;       /* true if within commit critical section */
 
-   bool        inVacuum;       /* true if current xact is a LAZY VACUUM */
-   bool        isAutovacuum;   /* true if it's autovacuum */
+   uint8       vacuumFlags;    /* vacuum-related flags, see above */
 
    /* Info about LWLock the process is currently waiting for, if any. */
    bool        lwWaiting;      /* true if waiting for an LW lock */