Rationalize vacuuming options and parameters
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 18 Mar 2015 14:52:33 +0000 (11:52 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 18 Mar 2015 14:52:33 +0000 (11:52 -0300)
We were involving the parser too much in setting up initial vacuuming
parameters.  This patch moves that responsibility elsewhere to simplify
code, and also to make future additions easier.  To do this, create a
new struct VacuumParams which is filled just prior to vacuum execution,
instead of at parse time; for user-invoked vacuuming this is set up in a
new function ExecVacuum, while autovacuum sets it up by itself.

While at it, add a new member VACOPT_SKIPTOAST to enum VacuumOption,
only set by autovacuum, which is used to disable vacuuming of the toast
table instead of the old do_toast parameter; this relieves the argument
list of vacuum() and some callees a bit.  This partially makes up for
having added more arguments in an effort to avoid having autovacuum from
constructing a VacuumStmt parse node.

Author: Michael Paquier. Some tweaks by Álvaro
Reviewed by: Robert Haas, Stephen Frost, Álvaro Herrera

src/backend/commands/analyze.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/postmaster/autovacuum.c
src/backend/tcop/utility.c
src/include/commands/vacuum.h
src/include/nodes/parsenodes.h

index d2856a379e77028cf4f766c54729bb4bc807f034..75b45f7cd5de4a22823812d072cc09d69a301d17 100644 (file)
@@ -85,7 +85,7 @@ static MemoryContext anl_context = NULL;
 static BufferAccessStrategy vac_strategy;
 
 
-static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
+static void do_analyze_rel(Relation onerel, int options, List *va_cols,
                           AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
                           bool inh, bool in_outer_xact, int elevel);
 static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
@@ -115,7 +115,7 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
  *     analyze_rel() -- analyze one relation
  */
 void
-analyze_rel(Oid relid, VacuumStmt *vacstmt,
+analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols,
                        bool in_outer_xact, BufferAccessStrategy bstrategy)
 {
        Relation        onerel;
@@ -124,7 +124,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
        BlockNumber relpages = 0;
 
        /* Select logging level */
-       if (vacstmt->options & VACOPT_VERBOSE)
+       if (options & VACOPT_VERBOSE)
                elevel = INFO;
        else
                elevel = DEBUG2;
@@ -144,7 +144,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
         * matter if we ever try to accumulate stats on dead tuples.) If the rel
         * has been dropped since we last saw it, we don't need to process it.
         */
-       if (!(vacstmt->options & VACOPT_NOWAIT))
+       if (!(options & VACOPT_NOWAIT))
                onerel = try_relation_open(relid, ShareUpdateExclusiveLock);
        else if (ConditionalLockRelationOid(relid, ShareUpdateExclusiveLock))
                onerel = try_relation_open(relid, NoLock);
@@ -155,7 +155,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
                        ereport(LOG,
                                        (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                  errmsg("skipping analyze of \"%s\" --- lock not available",
-                                                vacstmt->relation->relname)));
+                                                relation->relname)));
        }
        if (!onerel)
                return;
@@ -167,7 +167,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
                  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared)))
        {
                /* No need for a WARNING if we already complained during VACUUM */
-               if (!(vacstmt->options & VACOPT_VACUUM))
+               if (!(options & VACOPT_VACUUM))
                {
                        if (onerel->rd_rel->relisshared)
                                ereport(WARNING,
@@ -248,7 +248,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
        else
        {
                /* No need for a WARNING if we already complained during VACUUM */
-               if (!(vacstmt->options & VACOPT_VACUUM))
+               if (!(options & VACOPT_VACUUM))
                        ereport(WARNING,
                                        (errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables",
                                                        RelationGetRelationName(onerel))));
@@ -266,14 +266,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
        /*
         * Do the normal non-recursive ANALYZE.
         */
-       do_analyze_rel(onerel, vacstmt, acquirefunc, relpages,
+       do_analyze_rel(onerel, options, va_cols, acquirefunc, relpages,
                                   false, in_outer_xact, elevel);
 
        /*
         * If there are child tables, do recursive ANALYZE.
         */
        if (onerel->rd_rel->relhassubclass)
-               do_analyze_rel(onerel, vacstmt, acquirefunc, relpages,
+               do_analyze_rel(onerel, options, va_cols, acquirefunc, relpages,
                                           true, in_outer_xact, elevel);
 
        /*
@@ -302,7 +302,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt,
  * acquirefunc for each child table.
  */
 static void
-do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
+do_analyze_rel(Relation onerel, int options, List *va_cols,
                           AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
                           bool inh, bool in_outer_xact, int elevel)
 {
@@ -372,14 +372,14 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
         *
         * Note that system attributes are never analyzed.
         */
-       if (vacstmt->va_cols != NIL)
+       if (va_cols != NIL)
        {
                ListCell   *le;
 
-               vacattrstats = (VacAttrStats **) palloc(list_length(vacstmt->va_cols) *
+               vacattrstats = (VacAttrStats **) palloc(list_length(va_cols) *
                                                                                                sizeof(VacAttrStats *));
                tcnt = 0;
-               foreach(le, vacstmt->va_cols)
+               foreach(le, va_cols)
                {
                        char       *col = strVal(lfirst(le));
 
@@ -436,7 +436,7 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
 
                        thisdata->indexInfo = indexInfo = BuildIndexInfo(Irel[ind]);
                        thisdata->tupleFract = 1.0; /* fix later if partial */
-                       if (indexInfo->ii_Expressions != NIL && vacstmt->va_cols == NIL)
+                       if (indexInfo->ii_Expressions != NIL && va_cols == NIL)
                        {
                                ListCell   *indexpr_item = list_head(indexInfo->ii_Expressions);
 
@@ -595,7 +595,7 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
         * VACUUM ANALYZE, don't overwrite the accurate count already inserted by
         * VACUUM.
         */
-       if (!inh && !(vacstmt->options & VACOPT_VACUUM))
+       if (!inh && !(options & VACOPT_VACUUM))
        {
                for (ind = 0; ind < nindexes; ind++)
                {
@@ -623,7 +623,7 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
                pgstat_report_analyze(onerel, totalrows, totaldeadrows);
 
        /* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup */
-       if (!(vacstmt->options & VACOPT_VACUUM))
+       if (!(options & VACOPT_VACUUM))
        {
                for (ind = 0; ind < nindexes; ind++)
                {
index 74475684fc2baa359e37919ae461ae52428ec4ed..bd57b683d836511fd8b3d086a23ff75e85fc3479 100644 (file)
@@ -71,35 +71,79 @@ static void vac_truncate_clog(TransactionId frozenXID,
                                  MultiXactId minMulti,
                                  TransactionId lastSaneFrozenXid,
                                  MultiXactId lastSaneMinMulti);
-static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
-                  bool for_wraparound);
+static bool vacuum_rel(Oid relid, RangeVar *relation, int options,
+                  VacuumParams *params);
 
+/*
+ * Primary entry point for manual VACUUM and ANALYZE commands
+ *
+ * This is mainly a preparation wrapper for the real operations that will
+ * happen in vacuum().
+ */
+void
+ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel)
+{
+       VacuumParams    params;
+
+       /* sanity checks on options */
+       Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE));
+       Assert((vacstmt->options & VACOPT_VACUUM) ||
+                  !(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE)));
+       Assert((vacstmt->options & VACOPT_ANALYZE) || vacstmt->va_cols == NIL);
+       Assert(!(vacstmt->options & VACOPT_SKIPTOAST));
+
+       /*
+        * All freeze ages are zero if the FREEZE option is given; otherwise pass
+        * them as -1 which means to use the default values.
+        */
+       if (vacstmt->options & VACOPT_FREEZE)
+       {
+               params.freeze_min_age = 0;
+               params.freeze_table_age = 0;
+               params.multixact_freeze_min_age = 0;
+               params.multixact_freeze_table_age = 0;
+       }
+       else
+       {
+               params.freeze_min_age = -1;
+               params.freeze_table_age = -1;
+               params.multixact_freeze_min_age = -1;
+               params.multixact_freeze_table_age = -1;
+       }
+
+       /* user-invoked vacuum is never "for wraparound" */
+       params.is_wraparound = false;
+
+       /* Now go through the common routine */
+       vacuum(vacstmt->options, vacstmt->relation, InvalidOid, &params,
+                  vacstmt->va_cols, NULL, isTopLevel);
+}
 
 /*
  * Primary entry point for VACUUM and ANALYZE commands.
  *
- * relid is normally InvalidOid; if it is not, then it provides the relation
- * OID to be processed, and vacstmt->relation is ignored.  (The non-invalid
- * case is currently only used by autovacuum.)
+ * options is a bitmask of VacuumOption flags, indicating what to do.
  *
- * do_toast is passed as FALSE by autovacuum, because it processes TOAST
- * tables separately.
+ * relid, if not InvalidOid, indicate the relation to process; otherwise,
+ * the RangeVar is used.  (The latter must always be passed, because it's
+ * used for error messages.)
  *
- * for_wraparound is used by autovacuum to let us know when it's forcing
- * a vacuum for wraparound, which should not be auto-canceled.
+ * params contains a set of parameters that can be used to customize the
+ * behavior.
+ *
+ * va_cols is a list of columns to analyze, or NIL to process them all.
  *
  * bstrategy is normally given as NULL, but in autovacuum it can be passed
  * in to use the same buffer strategy object across multiple vacuum() calls.
  *
  * isTopLevel should be passed down from ProcessUtility.
  *
- * It is the caller's responsibility that vacstmt and bstrategy
- * (if given) be allocated in a memory context that won't disappear
- * at transaction commit.
+ * It is the caller's responsibility that all parameters are allocated in a
+ * memory context that will not disappear at transaction commit.
  */
 void
-vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
-          BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
+vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
+          List *va_cols, BufferAccessStrategy bstrategy, bool isTopLevel)
 {
        const char *stmttype;
        volatile bool in_outer_xact,
@@ -107,13 +151,9 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
        List       *relations;
        static bool in_vacuum = false;
 
-       /* sanity checks on options */
-       Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE));
-       Assert((vacstmt->options & VACOPT_VACUUM) ||
-                  !(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE)));
-       Assert((vacstmt->options & VACOPT_ANALYZE) || vacstmt->va_cols == NIL);
+       Assert(params != NULL);
 
-       stmttype = (vacstmt->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
+       stmttype = (options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
 
        /*
         * We cannot run VACUUM inside a user transaction block; if we were inside
@@ -123,7 +163,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
         *
         * ANALYZE (without VACUUM) can run either way.
         */
-       if (vacstmt->options & VACOPT_VACUUM)
+       if (options & VACOPT_VACUUM)
        {
                PreventTransactionChain(isTopLevel, stmttype);
                in_outer_xact = false;
@@ -143,7 +183,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
         * Send info about dead objects to the statistics collector, unless we are
         * in autovacuum --- autovacuum.c does this for itself.
         */
-       if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
+       if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
                pgstat_vacuum_stat();
 
        /*
@@ -175,7 +215,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
         * Build list of relations to process, unless caller gave us one. (If we
         * build one, we put it in vac_context for safekeeping.)
         */
-       relations = get_rel_oids(relid, vacstmt->relation);
+       relations = get_rel_oids(relid, relation);
 
        /*
         * Decide whether we need to start/commit our own transactions.
@@ -191,11 +231,11 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
         * transaction block, and also in an autovacuum worker, use own
         * transactions so we can release locks sooner.
         */
-       if (vacstmt->options & VACOPT_VACUUM)
+       if (options & VACOPT_VACUUM)
                use_own_xacts = true;
        else
        {
-               Assert(vacstmt->options & VACOPT_ANALYZE);
+               Assert(options & VACOPT_ANALYZE);
                if (IsAutoVacuumWorkerProcess())
                        use_own_xacts = true;
                else if (in_outer_xact)
@@ -245,13 +285,13 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
                {
                        Oid                     relid = lfirst_oid(cur);
 
-                       if (vacstmt->options & VACOPT_VACUUM)
+                       if (options & VACOPT_VACUUM)
                        {
-                               if (!vacuum_rel(relid, vacstmt, do_toast, for_wraparound))
+                               if (!vacuum_rel(relid, relation, options, params))
                                        continue;
                        }
 
-                       if (vacstmt->options & VACOPT_ANALYZE)
+                       if (options & VACOPT_ANALYZE)
                        {
                                /*
                                 * If using separate xacts, start one for analyze. Otherwise,
@@ -264,7 +304,8 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
                                        PushActiveSnapshot(GetTransactionSnapshot());
                                }
 
-                               analyze_rel(relid, vacstmt, in_outer_xact, vac_strategy);
+                               analyze_rel(relid, relation, options,
+                                                       va_cols, in_outer_xact, vac_strategy);
 
                                if (use_own_xacts)
                                {
@@ -299,7 +340,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
                StartTransactionCommand();
        }
 
-       if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
+       if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
        {
                /*
                 * Update pg_database.datfrozenxid, and truncate pg_clog if possible.
@@ -1113,7 +1154,7 @@ vac_truncate_clog(TransactionId frozenXID,
  *             At entry and exit, we are not inside a transaction.
  */
 static bool
-vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
+vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
 {
        LOCKMODE        lmode;
        Relation        onerel;
@@ -1123,6 +1164,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
        int                     save_sec_context;
        int                     save_nestlevel;
 
+       Assert(params != NULL);
+
        /* Begin a transaction for vacuuming this relation */
        StartTransactionCommand();
 
@@ -1132,7 +1175,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
         */
        PushActiveSnapshot(GetTransactionSnapshot());
 
-       if (!(vacstmt->options & VACOPT_FULL))
+       if (!(options & VACOPT_FULL))
        {
                /*
                 * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets
@@ -1156,7 +1199,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
                 */
                LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
                MyPgXact->vacuumFlags |= PROC_IN_VACUUM;
-               if (for_wraparound)
+               if (params->is_wraparound)
                        MyPgXact->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
                LWLockRelease(ProcArrayLock);
        }
@@ -1172,7 +1215,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
         * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either
         * way, we can be sure that no other backend is vacuuming the same table.
         */
-       lmode = (vacstmt->options & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock;
+       lmode = (options & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock;
 
        /*
         * Open the relation and get the appropriate lock on it.
@@ -1183,7 +1226,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
         * If we've been asked not to wait for the relation lock, acquire it first
         * in non-blocking mode, before calling try_relation_open().
         */
-       if (!(vacstmt->options & VACOPT_NOWAIT))
+       if (!(options & VACOPT_NOWAIT))
                onerel = try_relation_open(relid, lmode);
        else if (ConditionalLockRelationOid(relid, lmode))
                onerel = try_relation_open(relid, NoLock);
@@ -1194,7 +1237,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
                        ereport(LOG,
                                        (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                   errmsg("skipping vacuum of \"%s\" --- lock not available",
-                                                 vacstmt->relation->relname)));
+                                                 relation->relname)));
        }
 
        if (!onerel)
@@ -1286,7 +1329,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
         * us to process it.  In VACUUM FULL, though, the toast table is
         * automatically rebuilt by cluster_rel so we shouldn't recurse to it.
         */
-       if (do_toast && !(vacstmt->options & VACOPT_FULL))
+       if (!(options & VACOPT_SKIPTOAST) && !(options & VACOPT_FULL))
                toast_relid = onerel->rd_rel->reltoastrelid;
        else
                toast_relid = InvalidOid;
@@ -1305,7 +1348,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
        /*
         * Do the actual work --- either FULL or "lazy" vacuum
         */
-       if (vacstmt->options & VACOPT_FULL)
+       if (options & VACOPT_FULL)
        {
                /* close relation before vacuuming, but hold lock until commit */
                relation_close(onerel, NoLock);
@@ -1313,10 +1356,10 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 
                /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
                cluster_rel(relid, InvalidOid, false,
-                                       (vacstmt->options & VACOPT_VERBOSE) != 0);
+                                       (options & VACOPT_VERBOSE) != 0);
        }
        else
-               lazy_vacuum_rel(onerel, vacstmt, vac_strategy);
+               lazy_vacuum_rel(onerel, options, params, vac_strategy);
 
        /* Roll back any GUC changes executed by index functions */
        AtEOXact_GUC(false, save_nestlevel);
@@ -1342,7 +1385,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
         * totally unimportant for toast relations.
         */
        if (toast_relid != InvalidOid)
-               vacuum_rel(toast_relid, vacstmt, false, for_wraparound);
+               vacuum_rel(toast_relid, relation, options, params);
 
        /*
         * Now release the session-level lock on the master table.
index 7d9e49eb330d6bc849443222efd818975fb51dd4..cd5ca4c2f9735e3917b4292680609875484b50a7 100644 (file)
@@ -169,7 +169,7 @@ static bool heap_page_is_all_visible(Relation rel, Buffer buf,
  *             and locked the relation.
  */
 void
-lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
+lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
                                BufferAccessStrategy bstrategy)
 {
        LVRelStats *vacrelstats;
@@ -193,6 +193,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
        TransactionId new_frozen_xid;
        MultiXactId new_min_multi;
 
+       Assert(params != NULL);
+
        /* measure elapsed time iff autovacuum logging requires it */
        if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
        {
@@ -200,7 +202,7 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
                starttime = GetCurrentTimestamp();
        }
 
-       if (vacstmt->options & VACOPT_VERBOSE)
+       if (options & VACOPT_VERBOSE)
                elevel = INFO;
        else
                elevel = DEBUG2;
@@ -208,9 +210,10 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
        vac_strategy = bstrategy;
 
        vacuum_set_xid_limits(onerel,
-                                                 vacstmt->freeze_min_age, vacstmt->freeze_table_age,
-                                                 vacstmt->multixact_freeze_min_age,
-                                                 vacstmt->multixact_freeze_table_age,
+                                                 params->freeze_min_age,
+                                                 params->freeze_table_age,
+                                                 params->multixact_freeze_min_age,
+                                                 params->multixact_freeze_table_age,
                                                  &OldestXmin, &FreezeLimit, &xidFullScanLimit,
                                                  &MultiXactCutoff, &mxactFullScanLimit);
 
index 3c6a964a6599b585f969df4eba716b27af7787b3..029761e74f8d7cbfebb4edbdad53e9f9ad0c508e 100644 (file)
@@ -3300,10 +3300,6 @@ _copyVacuumStmt(const VacuumStmt *from)
        VacuumStmt *newnode = makeNode(VacuumStmt);
 
        COPY_SCALAR_FIELD(options);
-       COPY_SCALAR_FIELD(freeze_min_age);
-       COPY_SCALAR_FIELD(freeze_table_age);
-       COPY_SCALAR_FIELD(multixact_freeze_min_age);
-       COPY_SCALAR_FIELD(multixact_freeze_table_age);
        COPY_NODE_FIELD(relation);
        COPY_NODE_FIELD(va_cols);
 
index fcd58ada3d0066071f2b55a84580ebe00125c327..190e50ab8c6909d62a7dbb4b40b0c6f53ff48e34 100644 (file)
@@ -1503,10 +1503,6 @@ static bool
 _equalVacuumStmt(const VacuumStmt *a, const VacuumStmt *b)
 {
        COMPARE_SCALAR_FIELD(options);
-       COMPARE_SCALAR_FIELD(freeze_min_age);
-       COMPARE_SCALAR_FIELD(freeze_table_age);
-       COMPARE_SCALAR_FIELD(multixact_freeze_min_age);
-       COMPARE_SCALAR_FIELD(multixact_freeze_table_age);
        COMPARE_NODE_FIELD(relation);
        COMPARE_NODE_FIELD(va_cols);
 
index 149962035dc12d6326a6310c5df99d050270673f..82405b9d26f5b8c9325132eb9ba59a72cad29bd0 100644 (file)
@@ -9034,12 +9034,10 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose
                                        n->options = VACOPT_VACUUM;
                                        if ($2)
                                                n->options |= VACOPT_FULL;
+                                       if ($3)
+                                               n->options |= VACOPT_FREEZE;
                                        if ($4)
                                                n->options |= VACOPT_VERBOSE;
-                                       n->freeze_min_age = $3 ? 0 : -1;
-                                       n->freeze_table_age = $3 ? 0 : -1;
-                                       n->multixact_freeze_min_age = $3 ? 0 : -1;
-                                       n->multixact_freeze_table_age = $3 ? 0 : -1;
                                        n->relation = NULL;
                                        n->va_cols = NIL;
                                        $$ = (Node *)n;
@@ -9050,12 +9048,10 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose
                                        n->options = VACOPT_VACUUM;
                                        if ($2)
                                                n->options |= VACOPT_FULL;
+                                       if ($3)
+                                               n->options |= VACOPT_FREEZE;
                                        if ($4)
                                                n->options |= VACOPT_VERBOSE;
-                                       n->freeze_min_age = $3 ? 0 : -1;
-                                       n->freeze_table_age = $3 ? 0 : -1;
-                                       n->multixact_freeze_min_age = $3 ? 0 : -1;
-                                       n->multixact_freeze_table_age = $3 ? 0 : -1;
                                        n->relation = $5;
                                        n->va_cols = NIL;
                                        $$ = (Node *)n;
@@ -9066,30 +9062,16 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose
                                        n->options |= VACOPT_VACUUM;
                                        if ($2)
                                                n->options |= VACOPT_FULL;
+                                       if ($3)
+                                               n->options |= VACOPT_FREEZE;
                                        if ($4)
                                                n->options |= VACOPT_VERBOSE;
-                                       n->freeze_min_age = $3 ? 0 : -1;
-                                       n->freeze_table_age = $3 ? 0 : -1;
-                                       n->multixact_freeze_min_age = $3 ? 0 : -1;
-                                       n->multixact_freeze_table_age = $3 ? 0 : -1;
                                        $$ = (Node *)n;
                                }
                        | VACUUM '(' vacuum_option_list ')'
                                {
                                        VacuumStmt *n = makeNode(VacuumStmt);
                                        n->options = VACOPT_VACUUM | $3;
-                                       if (n->options & VACOPT_FREEZE)
-                                       {
-                                               n->freeze_min_age = n->freeze_table_age = 0;
-                                               n->multixact_freeze_min_age = 0;
-                                               n->multixact_freeze_table_age = 0;
-                                       }
-                                       else
-                                       {
-                                               n->freeze_min_age = n->freeze_table_age = -1;
-                                               n->multixact_freeze_min_age = -1;
-                                               n->multixact_freeze_table_age = -1;
-                                       }
                                        n->relation = NULL;
                                        n->va_cols = NIL;
                                        $$ = (Node *) n;
@@ -9098,18 +9080,6 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose
                                {
                                        VacuumStmt *n = makeNode(VacuumStmt);
                                        n->options = VACOPT_VACUUM | $3;
-                                       if (n->options & VACOPT_FREEZE)
-                                       {
-                                               n->freeze_min_age = n->freeze_table_age = 0;
-                                               n->multixact_freeze_min_age = 0;
-                                               n->multixact_freeze_table_age = 0;
-                                       }
-                                       else
-                                       {
-                                               n->freeze_min_age = n->freeze_table_age = -1;
-                                               n->multixact_freeze_min_age = -1;
-                                               n->multixact_freeze_table_age = -1;
-                                       }
                                        n->relation = $5;
                                        n->va_cols = $6;
                                        if (n->va_cols != NIL)  /* implies analyze */
@@ -9137,10 +9107,6 @@ AnalyzeStmt:
                                        n->options = VACOPT_ANALYZE;
                                        if ($2)
                                                n->options |= VACOPT_VERBOSE;
-                                       n->freeze_min_age = -1;
-                                       n->freeze_table_age = -1;
-                                       n->multixact_freeze_min_age = -1;
-                                       n->multixact_freeze_table_age = -1;
                                        n->relation = NULL;
                                        n->va_cols = NIL;
                                        $$ = (Node *)n;
@@ -9151,10 +9117,6 @@ AnalyzeStmt:
                                        n->options = VACOPT_ANALYZE;
                                        if ($2)
                                                n->options |= VACOPT_VERBOSE;
-                                       n->freeze_min_age = -1;
-                                       n->freeze_table_age = -1;
-                                       n->multixact_freeze_min_age = -1;
-                                       n->multixact_freeze_table_age = -1;
                                        n->relation = $3;
                                        n->va_cols = $4;
                                        $$ = (Node *)n;
index ee556f3600d8016b4e0763104367ac96c34870b4..5ccae24b25c9b31f699f70171edac6c26a14c755 100644 (file)
@@ -184,16 +184,11 @@ typedef struct av_relation
 typedef struct autovac_table
 {
        Oid                     at_relid;
-       bool            at_dovacuum;
-       bool            at_doanalyze;
-       int                     at_freeze_min_age;
-       int                     at_freeze_table_age;
-       int                     at_multixact_freeze_min_age;
-       int                     at_multixact_freeze_table_age;
+       int                     at_vacoptions;  /* bitmask of VacuumOption */
+       VacuumParams at_params;
        int                     at_vacuum_cost_delay;
        int                     at_vacuum_cost_limit;
        bool            at_dobalance;
-       bool            at_wraparound;
        char       *at_relname;
        char       *at_nspname;
        char       *at_datname;
@@ -2301,7 +2296,7 @@ do_autovacuum(void)
                         * next table in our list.
                         */
                        HOLD_INTERRUPTS();
-                       if (tab->at_dovacuum)
+                       if (tab->at_vacoptions & VACOPT_VACUUM)
                                errcontext("automatic vacuum of table \"%s.%s.%s\"",
                                                   tab->at_datname, tab->at_nspname, tab->at_relname);
                        else
@@ -2528,15 +2523,17 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
 
                tab = palloc(sizeof(autovac_table));
                tab->at_relid = relid;
-               tab->at_dovacuum = dovacuum;
-               tab->at_doanalyze = doanalyze;
-               tab->at_freeze_min_age = freeze_min_age;
-               tab->at_freeze_table_age = freeze_table_age;
-               tab->at_multixact_freeze_min_age = multixact_freeze_min_age;
-               tab->at_multixact_freeze_table_age = multixact_freeze_table_age;
+               tab->at_vacoptions = VACOPT_SKIPTOAST |
+                       (dovacuum ? VACOPT_VACUUM : 0) |
+                       (doanalyze ? VACOPT_ANALYZE : 0) |
+                       (wraparound ? VACOPT_NOWAIT : 0);
+               tab->at_params.freeze_min_age = freeze_min_age;
+               tab->at_params.freeze_table_age = freeze_table_age;
+               tab->at_params.multixact_freeze_min_age = multixact_freeze_min_age;
+               tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age;
+               tab->at_params.is_wraparound = wraparound;
                tab->at_vacuum_cost_limit = vac_cost_limit;
                tab->at_vacuum_cost_delay = vac_cost_delay;
-               tab->at_wraparound = wraparound;
                tab->at_relname = NULL;
                tab->at_nspname = NULL;
                tab->at_datname = NULL;
@@ -2737,39 +2734,22 @@ relation_needs_vacanalyze(Oid relid,
  *             Vacuum and/or analyze the specified table
  */
 static void
-autovacuum_do_vac_analyze(autovac_table *tab,
-                                                 BufferAccessStrategy bstrategy)
+autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
 {
-       VacuumStmt      vacstmt;
-       RangeVar        rangevar;
+       RangeVar                rangevar;
 
        /* Set up command parameters --- use local variables instead of palloc */
-       MemSet(&vacstmt, 0, sizeof(vacstmt));
        MemSet(&rangevar, 0, sizeof(rangevar));
 
        rangevar.schemaname = tab->at_nspname;
        rangevar.relname = tab->at_relname;
        rangevar.location = -1;
 
-       vacstmt.type = T_VacuumStmt;
-       if (!tab->at_wraparound)
-               vacstmt.options = VACOPT_NOWAIT;
-       if (tab->at_dovacuum)
-               vacstmt.options |= VACOPT_VACUUM;
-       if (tab->at_doanalyze)
-               vacstmt.options |= VACOPT_ANALYZE;
-       vacstmt.freeze_min_age = tab->at_freeze_min_age;
-       vacstmt.freeze_table_age = tab->at_freeze_table_age;
-       vacstmt.multixact_freeze_min_age = tab->at_multixact_freeze_min_age;
-       vacstmt.multixact_freeze_table_age = tab->at_multixact_freeze_table_age;
-       /* we pass the OID, but might need this anyway for an error message */
-       vacstmt.relation = &rangevar;
-       vacstmt.va_cols = NIL;
-
        /* Let pgstat know what we're doing */
        autovac_report_activity(tab);
 
-       vacuum(&vacstmt, tab->at_relid, false, bstrategy, tab->at_wraparound, true);
+       vacuum(tab->at_vacoptions, &rangevar, tab->at_relid, &tab->at_params, NIL,
+                  bstrategy, true);
 }
 
 /*
@@ -2791,10 +2771,10 @@ autovac_report_activity(autovac_table *tab)
        int                     len;
 
        /* Report the command and possible options */
-       if (tab->at_dovacuum)
+       if (tab->at_vacoptions & VACOPT_VACUUM)
                snprintf(activity, MAX_AUTOVAC_ACTIV_LEN,
                                 "autovacuum: VACUUM%s",
-                                tab->at_doanalyze ? " ANALYZE" : "");
+                                tab->at_vacoptions & VACOPT_ANALYZE ? " ANALYZE" : "");
        else
                snprintf(activity, MAX_AUTOVAC_ACTIV_LEN,
                                 "autovacuum: ANALYZE");
@@ -2806,7 +2786,7 @@ autovac_report_activity(autovac_table *tab)
 
        snprintf(activity + len, MAX_AUTOVAC_ACTIV_LEN - len,
                         " %s.%s%s", tab->at_nspname, tab->at_relname,
-                        tab->at_wraparound ? " (to prevent wraparound)" : "");
+                        tab->at_params.is_wraparound ? " (to prevent wraparound)" : "");
 
        /* Set statement_timestamp() to current time for pg_stat_activity */
        SetCurrentStatementStartTimestamp();
index 065475dda2a0ba75736e6935a82b17bf0ff54b13..d9443b1496ad7c372ee8669f9195b85576e363fe 100644 (file)
@@ -627,7 +627,7 @@ standard_ProcessUtility(Node *parsetree,
                                /* we choose to allow this during "read only" transactions */
                                PreventCommandDuringRecovery((stmt->options & VACOPT_VACUUM) ?
                                                                                         "VACUUM" : "ANALYZE");
-                               vacuum(stmt, InvalidOid, true, NULL, false, isTopLevel);
+                               ExecVacuum(stmt, isTopLevel);
                        }
                        break;
 
index 4275484349dd46a25f9753695e03d1f0b98e8840..9fd2516923051c8a15cc84cd036e2b72a2a658f9 100644 (file)
@@ -130,6 +130,19 @@ typedef struct VacAttrStats
        int                     rowstride;
 } VacAttrStats;
 
+/*
+ * Parameters customizing behavior of VACUUM and ANALYZE.
+ */
+typedef struct VacuumParams
+{
+       int             freeze_min_age;         /* min freeze age, -1 to use default */
+       int             freeze_table_age;       /* age at which to scan whole table */
+       int             multixact_freeze_min_age;       /* min multixact freeze age,
+                                                                                * -1 to use default */
+       int             multixact_freeze_table_age;     /* multixact age at which to
+                                                                                * scan whole table */
+       bool    is_wraparound;          /* force a for-wraparound vacuum */
+} VacuumParams;
 
 /* GUC parameters */
 extern PGDLLIMPORT int default_statistics_target;              /* PGDLLIMPORT for
@@ -141,8 +154,10 @@ extern int vacuum_multixact_freeze_table_age;
 
 
 /* in commands/vacuum.c */
-extern void vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
-          BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel);
+extern void ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel);
+extern void vacuum(int options, RangeVar *relation, Oid relid,
+          VacuumParams *params, List *va_cols,
+          BufferAccessStrategy bstrategy, bool isTopLevel);
 extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
                                 int *nindexes, Relation **Irel);
 extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode);
@@ -171,12 +186,13 @@ extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(void);
 
 /* in commands/vacuumlazy.c */
-extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
-                               BufferAccessStrategy bstrategy);
+extern void lazy_vacuum_rel(Relation onerel, int options,
+                               VacuumParams *params, BufferAccessStrategy bstrategy);
 
 /* in commands/analyze.c */
-extern void analyze_rel(Oid relid, VacuumStmt *vacstmt,
-                       bool in_outer_xact, BufferAccessStrategy bstrategy);
+extern void analyze_rel(Oid relid, RangeVar *relation, int options,
+                       List *va_cols, bool in_outer_xact,
+                       BufferAccessStrategy bstrategy);
 extern bool std_typanalyze(VacAttrStats *stats);
 extern double anl_random_fract(void);
 extern double anl_init_selection_state(int n);
index a5753539a30bea6e64bec313c926d5ad750ea81d..ec0d0eaa4ac2dda4abf96bee56e854755d70d542 100644 (file)
@@ -2608,9 +2608,7 @@ typedef struct ClusterStmt
  *
  * Even though these are nominally two statements, it's convenient to use
  * just one node type for both.  Note that at least one of VACOPT_VACUUM
- * and VACOPT_ANALYZE must be set in options.  VACOPT_FREEZE is an internal
- * convenience for the grammar and is not examined at runtime --- the
- * freeze_min_age and freeze_table_age fields are what matter.
+ * and VACOPT_ANALYZE must be set in options.
  * ----------------------
  */
 typedef enum VacuumOption
@@ -2620,19 +2618,14 @@ typedef enum VacuumOption
        VACOPT_VERBOSE = 1 << 2,        /* print progress info */
        VACOPT_FREEZE = 1 << 3,         /* FREEZE option */
        VACOPT_FULL = 1 << 4,           /* FULL (non-concurrent) vacuum */
-       VACOPT_NOWAIT = 1 << 5          /* don't wait to get lock (autovacuum only) */
+       VACOPT_NOWAIT = 1 << 5,         /* don't wait to get lock (autovacuum only) */
+       VACOPT_SKIPTOAST = 1 << 6       /* don't process the TOAST table, if any */
 } VacuumOption;
 
 typedef struct VacuumStmt
 {
        NodeTag         type;
        int                     options;                /* OR of VacuumOption flags */
-       int                     freeze_min_age; /* min freeze age, or -1 to use default */
-       int                     freeze_table_age;               /* age at which to scan whole table */
-       int                     multixact_freeze_min_age;               /* min multixact freeze age,
-                                                                                                * or -1 to use default */
-       int                     multixact_freeze_table_age;             /* multixact age at which to
-                                                                                                * scan whole table */
        RangeVar   *relation;           /* single table to process, or NULL */
        List       *va_cols;            /* list of column names, or NIL for all */
 } VacuumStmt;