8000 Move various prechecks from vacuum() into ExecVacuum() · postgrespro/postgres@b9b125b · GitHub
[go: up one dir, main page]

Skip to content

Commit b9b125b

Browse files
committed
Move various prechecks from vacuum() into ExecVacuum()
vacuum() is used for both the VACUUM command and for autovacuum. There were many prechecks being done inside vacuum() that were just not relevant to autovacuum. Let's move the bulk of these into ExecVacuum() so that they're only executed when running the VACUUM command. This removes a small amount of overhead when autovacuum vacuums a table. While we are at it, allocate VACUUM's BufferAccessStrategy in ExecVacuum() and pass it into vacuum() instead of expecting vacuum() to make it if it's not already made by the calling function. To make this work, we need to create the vacuum memory context slightly earlier, so we now need to pass that down to vacuum() so that it's available for use in other memory allocations. Author: Melanie Plageman Reviewed-by: David Rowley Discussion: https://postgr.es/m/20230405211534.4skgskbilnxqrmxg@awork3.anarazel.de
1 parent acab1b0 commit b9b125b

File tree

3 files changed

+91
-78
lines changed
  • postmaster
  • include/commands
  • 3 files changed

    +91
    -78
    lines changed

    src/backend/commands/vacuum.c

    Lines changed: 78 additions & 76 deletions
    Original file line numberDiff line numberDiff line change
    @@ -105,6 +105,7 @@ void
    105105
    ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
    106106
    {
    107107
    VacuumParams params;
    108+
    BufferAccessStrategy bstrategy = NULL;
    108109
    bool verbose = false;
    109110
    bool skip_locked = false;
    110111
    bool analyze = false;
    @@ -115,6 +116,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
    115116
    bool process_toast = true;
    116117
    bool skip_database_stats = false;
    117118
    bool only_database_stats = false;
    119+
    MemoryContext vac_context;
    118120
    ListCell *lc;
    119121

    120122
    /* index_cleanup and truncate values unspecified for now */
    @@ -254,6 +256,42 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
    254256
    }
    255257
    }
    256258

    259+
    260+
    /*
    261+
    * Sanity check DISABLE_PAGE_SKIPPING option.
    262+
    */
    263+
    if ((params.options & VACOPT_FULL) != 0 &&
    264+
    (params.options & VACOPT_DISABLE_PAGE_SKIPPING) != 0)
    265+
    ereport(ERROR,
    266+
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    267+
    errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
    268+
    269+
    /* sanity check for PROCESS_TOAST */
    270+
    if ((params.options & VACOPT_FULL) != 0 &&
    271+
    (params.options & VACOPT_PROCESS_TOAST) == 0)
    272+
    ereport(ERROR,
    273+
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    274+
    errmsg("PROCESS_TOAST required with VACUUM FULL")));
    275+
    276+
    /* sanity check for ONLY_DATABASE_STATS */
    277+
    if (params.options & VACOPT_ONLY_DATABASE_STATS)
    278+
    {
    279+
    Assert(params.options & VACOPT_VACUUM);
    280+
    if (vacstmt->rels != NIL)
    281+
    ereport(ERROR,
    282+
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    283+
    errmsg("ONLY_DATABASE_STATS cannot be specified with a list of tables")));
    284+
    /* don't require people to turn off PROCESS_TOAST/MAIN explicitly */
    285+
    if (params.options & ~(VACOPT_VACUUM |
    286+
    VACOPT_VERBOSE |
    287+
    VACOPT_PROCESS_MAIN |
    288+
    VACOPT_PROCESS_TOAST |
    289+
    VACOPT_ONLY_DATABASE_STATS))
    290+
    ereport(ERROR,
    291+
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    292+
    errmsg("ONLY_DATABASE_STATS cannot be specified with other VACUUM options")));
    293+
    }
    294+
    257295
    /*
    258296
    * All freeze ages are zero if the FREEZE option is given; otherwise pass
    259297
    * them as -1 which means to use the default values.
    @@ -279,12 +317,43 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
    279317
    /* user-invoked vacuum uses VACOPT_VERBOSE instead of log_min_duration */
    280318
    params.log_min_duration = -1;
    281319

    320+
    /*
    321+
    * Create special memory context for cross-transaction storage.
    322+
    *
    323+
    * Since it is a child of PortalContext, it will go away eventually even
    324+
    * if we suffer an error; there's no need for special abort cleanup logic.
    325+
    */
    326+
    vac_context = AllocSetContextCreate(PortalContext,
    327+
    "Vacuum",
    328+
    ALLOCSET_DEFAULT_SIZES);
    329+
    330+
    /*
    331+
    * Make a buffer strategy object in the cross-transaction memory context.
    332+
    * We needn't bother making this for VACUUM (FULL) or VACUUM
    333+
    * (ONLY_DATABASE_STATS) as they'll not make use of it. VACUUM (FULL,
    334+
    * ANALYZE) is possible, so we'd better ensure that we make a strategy
    335+
    * when we see ANALYZE.
    336+
    */
    337+
    if ((params.options & (VACOPT_ONLY_DATABASE_STATS |
    338+
    VACOPT_FULL)) == 0 ||
    339+
    (params.options & VACOPT_ANALYZE) != 0)
    340+
    {
    341+
    342+
    MemoryContext old_context = MemoryContextSwitchTo(vac_context);
    343+
    344+
    bstrategy = GetAccessStrategy(BAS_VACUUM);
    345+
    MemoryContextSwitchTo(old_context);
    346+
    }
    347+
    282348
    /* Now go through the common routine */
    283-
    vacuum(vacstmt->rels, &params, NULL, isTopLevel);
    349+
    vacuum(vacstmt->rels, &params, bstrategy, vac_context, isTopLevel);
    350+
    351+
    /* Finally, clean up the vacuum memory context */
    352+
    MemoryContextDelete(vac_context);
    284353
    }
    285354

    286355
    /*
    287-
    * Internal entry point for VACUUM and ANALYZE commands.
    356+
    * Internal entry point for autovacuum and the VACUUM / ANALYZE commands.
    288357
    *
    289358
    * relations, if not NIL, is a list of VacuumRelation to process; otherwise,
    290359
    * we process all relevant tables in the database. For each VacuumRelation,
    @@ -294,21 +363,23 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
    294363
    * params contains a set of parameters that can be used to customize the
    295364
    * behavior.
    296365
    *
    297-
    * bstrategy is normally given as NULL, but in autovacuum it can be passed
    298-
    * in to use the same buffer strategy object across multiple vacuum() calls.
    366+
    * bstrategy may be passed in as NULL when the caller does not want to
    367+
    * restrict the number of shared_buffers that VACUUM / ANALYZE can use,
    368+
    * otherwise, the caller must build a BufferAccessStrategy with the number of
    369+
    * shared_buffers that VACUUM / ANALYZE should try to limit themselves to
    370+
    * using.
    299371
    *
    300372
    * isTopLevel should be passed down from ProcessUtility.
    301373 *
    302374
    * It is the caller's responsibility that all parameters are allocated in a
    303375
    * memory context that will not disappear at transaction commit.
    304376
    */
    305377
    void
    306-
    vacuum(List *relations, VacuumParams *params,
    307-
    BufferAccessStrategy bstrategy, bool isTopLevel)
    378+
    vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
    379+
    MemoryContext vac_context, bool isTopLevel)
    308380
    {
    309381
    static bool in_vacuum = false;
    310382

    311-
    MemoryContext vac_context;
    312383
    const char *stmttype;
    313384
    volatile bool in_outer_xact,
    314385
    use_own_xacts;
    @@ -344,69 +415,6 @@ vacuum(List *relations, VacuumParams *params,
    344415
    errmsg("%s cannot be executed from VACUUM or ANALYZE",
    345416
    stmttype)));
    346417

    347-
    /*
    348-
    * Sanity check DISABLE_PAGE_SKIPPING option.
    349-
    */
    350-
    if ((params->options & VACOPT_FULL) != 0 &&
    351-
    (params->options & VACOPT_DISABLE_PAGE_SKIPPING) != 0)
    352-
    ereport(ERROR,
    353-
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    354-
    errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
    355-
    356-
    /* sanity check for PROCESS_TOAST */
    357-
    if ((params->options & VACOPT_FULL) != 0 &&
    358-
    (params->options & VACOPT_PROCESS_TOAST) == 0)
    359-
    ereport(ERROR,
    360-
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    361-
    errmsg("PROCESS_TOAST required with VACUUM FULL")));
    362-
    363-
    /* sanity check for ONLY_DATABASE_STATS */
    364-
    if (params->options & VACOPT_ONLY_DATABASE_STATS)
    365-
    {
    366-
    Assert(params->options & VACOPT_VACUUM);
    367-
    if (relations != NIL)
    368-
    ereport(ERROR,
    369-
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    370-
    errmsg("ONLY_DATABASE_STATS cannot be specified with a list of tables")));
    371-
    /* don't require people to turn off PROCESS_TOAST/MAIN explicitly */
    372-
    if (params->options & ~(VACOPT_VACUUM |
    373-
    VACOPT_VERBOSE |
    374-
    VACOPT_PROCESS_MAIN |
    375-
    VACOPT_PROCESS_TOAST |
    376-
    VACOPT_ONLY_DATABASE_STATS))
    377-
    ereport(ERROR,
    378-
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    379-
    errmsg("ONLY_DATABASE_STATS cannot be specified with other VACUUM options")));
    380-
    }
    381-
    382-
    /*
    383-
    * Create special memory context for cross-transaction storage.
    384-
    *
    385-
    * Since it is a child of PortalContext, it will go away eventually even
    386-
    * if we suffer an error; there's no need for special abort cleanup logic.
    387-
    */
    388-
    vac_context = AllocSetContextCreate(PortalContext,
    389-
    "Vacuum",
    390-
    ALLOCSET_DEFAULT_SIZES);
    391-
    392-
    /*
    393-
    * If caller didn't give us a buffer strategy object, make one in the
    394-
    * cross-transaction memory context. We needn't bother making this for
    395-
    * VACUUM (FULL) or VACUUM (ONLY_DATABASE_STATS) as they'll not make use
    396-
    * of it. VACUUM (FULL, ANALYZE) is possible, so we'd better ensure that
    397-
    * we make a strategy when we see ANALYZE.
    398-
    */
    399-
    if (bstrategy == NULL &&
    400-
    ((params->options & (VACOPT_ONLY_DATABASE_STATS |
    401-
    VACOPT_FULL)) == 0 ||
    402-
    (params->options & VACOPT_ANALYZE) != 0))
    403-
    {
    404-
    MemoryContext old_context = MemoryContextSwitchTo(vac_context);
    405-
    406-
    bstrategy = GetAccessStrategy(BAS_VACUUM);
    407-
    MemoryContextSwitchTo(old_context);
    408-
    }
    409-
    410418
    /*
    411419
    * Build list of relation(s) to process, putting any new data in
    412420
    * vac_context for safekeeping.
    @@ -578,12 +586,6 @@ vacuum(List *relations, VacuumParams *params,
    578586
    vac_update_datfrozenxid();
    579587
    }
    580588

    581-
    /*
    582-
    * Clean up working storage --- note we must do this after
    583-
    * StartTransactionCommand, else we might be trying to delete the active
    584-
    * context!
    585-
    */
    586-
    MemoryContextDelete(vac_context);
    587589
    }
    588590

    589591
    /*

    src/backend/postmaster/autovacuum.c

    Lines changed: 11 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -3140,13 +3140,17 @@ relation_needs_vacanalyze(Oid relid,
    31403140
    /*
    31413141
    * autovacuum_do_vac_analyze
    31423142
    * Vacuum and/or analyze the specified table
    3143+
    *
    3144+
    * We expect the caller to have switched into a memory context that won't
    3145+
    * disappear at transaction commit.
    31433146
    */
    31443147
    static void
    31453148
    autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
    31463149
    {
    31473150
    RangeVar *rangevar;
    31483151
    VacuumRelation *rel;
    31493152
    List *rel_list;
    3153+
    MemoryContext vac_context;
    31503154

    31513155
    /* Let pgstat know what we're doing */
    31523156
    autovac_report_activity(tab);
    @@ -3156,7 +3160,13 @@ autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
    31563160
    rel = makeVacuumRelation(rangevar, tab->at_relid, NIL);
    31573161
    rel_list = list_make1(rel);
    31583162

    3159-
    vacuum(rel_list, &tab->at_params, bstrategy, true);
    3163+
    vac_context = AllocSetContextCreate(CurrentMemoryContext,
    3164+
    "Vacuum",
    3165+
    ALLOCSET_DEFAULT_SIZES);
    3166+
    3167+
    vacuum(rel_list, &tab->at_params, bstrategy, vac_context, true);
    3168+
    3169+
    MemoryContextDelete(vac_context);
    31603170
    }
    31613171

    31623172
    /*

    src/include/commands/vacuum.h

    Lines changed: 2 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -310,7 +310,8 @@ extern PGDLLIMPORT int VacuumCostBalanceLocal;
    310310
    /* in commands/vacuum.c */
    311311
    extern void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel);
    312312
    extern void vacuum(List *relations, VacuumParams *params,
    313-
    BufferAccessStrategy bstrategy, bool isTopLevel);
    313+
    BufferAccessStrategy bstrategy, MemoryContext vac_context,
    314+
    bool isTopLevel);
    314315
    extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
    315316
    int *nindexes, Relation **Irel);
    316317
    extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode);

    0 commit comments

    Comments
     (0)
    0