LCOV - differential code coverage report
Current view: top level - src/backend/commands - vacuum.c (source / functions) Coverage Total Hit UNC LBC UBC GBC GNC CBC DUB DCB
Current: ba12a202ce1b5581dc0ed149cf3f637d7897ad5d vs 2866d8c7dbfc9d882a7d80fef93fbbe763709932 Lines: 92.0 % 814 749 3 62 4 32 713 2 20
Current Date: 2026-08-27 14:31:44 +0300 Functions: 100.0 % 22 22 6 16
Baseline: lcov-20260827-baseline Branches: 77.7 % 709 551 6 1 151 3 29 519
Baseline Date: 2026-08-27 14:31:58 +0300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 90.9 % 11 10 1 10
(7,30] days: 91.7 % 24 22 2 22
(30,360] days: 100.0 % 52 52 1 51
(360..) days: 91.5 % 727 665 62 3 662
Function coverage date bins:
(30,360] days: 100.0 % 3 3 3
(360..) days: 100.0 % 19 19 6 13
Branch coverage date bins:
(1,7] days: 93.8 % 16 15 1 15
(7,30] days: 73.7 % 19 14 5 14
(30,360] days: 92.1 % 38 35 3 1 34
(360..) days: 76.6 % 636 487 1 148 2 485

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * vacuum.c
                                  4                 :                :  *    The postgres vacuum cleaner.
                                  5                 :                :  *
                                  6                 :                :  * This file includes (a) control and dispatch code for VACUUM and ANALYZE
                                  7                 :                :  * commands, (b) code to compute various vacuum thresholds, and (c) index
                                  8                 :                :  * vacuum code.
                                  9                 :                :  *
                                 10                 :                :  * VACUUM for heap AM is implemented in vacuumlazy.c, parallel vacuum in
                                 11                 :                :  * vacuumparallel.c, ANALYZE in analyze.c, and VACUUM FULL is a variant of
                                 12                 :                :  * REPACK, handled in repack.c.
                                 13                 :                :  *
                                 14                 :                :  *
                                 15                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                 16                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 17                 :                :  *
                                 18                 :                :  *
                                 19                 :                :  * IDENTIFICATION
                                 20                 :                :  *    src/backend/commands/vacuum.c
                                 21                 :                :  *
                                 22                 :                :  *-------------------------------------------------------------------------
                                 23                 :                :  */
                                 24                 :                : #include "postgres.h"
                                 25                 :                : 
                                 26                 :                : #include <math.h>
                                 27                 :                : 
                                 28                 :                : #include "access/clog.h"
                                 29                 :                : #include "access/commit_ts.h"
                                 30                 :                : #include "access/genam.h"
                                 31                 :                : #include "access/heapam.h"
                                 32                 :                : #include "access/htup_details.h"
                                 33                 :                : #include "access/multixact.h"
                                 34                 :                : #include "access/reloptions.h"
                                 35                 :                : #include "access/tableam.h"
                                 36                 :                : #include "access/transam.h"
                                 37                 :                : #include "access/xact.h"
                                 38                 :                : #include "catalog/namespace.h"
                                 39                 :                : #include "catalog/pg_database.h"
                                 40                 :                : #include "catalog/pg_inherits.h"
                                 41                 :                : #include "commands/async.h"
                                 42                 :                : #include "commands/defrem.h"
                                 43                 :                : #include "commands/progress.h"
                                 44                 :                : #include "commands/repack.h"
                                 45                 :                : #include "commands/vacuum.h"
                                 46                 :                : #include "miscadmin.h"
                                 47                 :                : #include "nodes/makefuncs.h"
                                 48                 :                : #include "pgstat.h"
                                 49                 :                : #include "postmaster/autovacuum.h"
                                 50                 :                : #include "postmaster/bgworker_internals.h"
                                 51                 :                : #include "postmaster/interrupt.h"
                                 52                 :                : #include "storage/bufmgr.h"
                                 53                 :                : #include "storage/lmgr.h"
                                 54                 :                : #include "storage/pmsignal.h"
                                 55                 :                : #include "storage/proc.h"
                                 56                 :                : #include "storage/procarray.h"
                                 57                 :                : #include "utils/acl.h"
                                 58                 :                : #include "utils/fmgroids.h"
                                 59                 :                : #include "utils/guc.h"
                                 60                 :                : #include "utils/guc_hooks.h"
                                 61                 :                : #include "utils/injection_point.h"
                                 62                 :                : #include "utils/memutils.h"
                                 63                 :                : #include "utils/snapmgr.h"
                                 64                 :                : #include "utils/syscache.h"
                                 65                 :                : #include "utils/wait_event.h"
                                 66                 :                : 
                                 67                 :                : /*
                                 68                 :                :  * Minimum interval for cost-based vacuum delay reports from a parallel worker.
                                 69                 :                :  * This aims to avoid sending too many messages and waking up the leader too
                                 70                 :                :  * frequently.
                                 71                 :                :  */
                                 72                 :                : #define PARALLEL_VACUUM_DELAY_REPORT_INTERVAL_NS    (NS_PER_S)
                                 73                 :                : 
                                 74                 :                : /*
                                 75                 :                :  * GUC parameters
                                 76                 :                :  */
                                 77                 :                : int         vacuum_freeze_min_age;
                                 78                 :                : int         vacuum_freeze_table_age;
                                 79                 :                : int         vacuum_multixact_freeze_min_age;
                                 80                 :                : int         vacuum_multixact_freeze_table_age;
                                 81                 :                : int         vacuum_failsafe_age;
                                 82                 :                : int         vacuum_multixact_failsafe_age;
                                 83                 :                : double      vacuum_max_eager_freeze_failure_rate;
                                 84                 :                : bool        track_cost_delay_timing;
                                 85                 :                : bool        vacuum_truncate;
                                 86                 :                : 
                                 87                 :                : /*
                                 88                 :                :  * Variables for cost-based vacuum delay. The defaults differ between
                                 89                 :                :  * autovacuum and vacuum. They should be set with the appropriate GUC value in
                                 90                 :                :  * vacuum code. They are initialized here to the defaults for client backends
                                 91                 :                :  * executing VACUUM or ANALYZE.
                                 92                 :                :  */
                                 93                 :                : double      vacuum_cost_delay = 0;
                                 94                 :                : int         vacuum_cost_limit = 200;
                                 95                 :                : 
                                 96                 :                : /* Variable for reporting cost-based vacuum delay from parallel workers. */
                                 97                 :                : int64       parallel_vacuum_worker_delay_ns = 0;
                                 98                 :                : 
                                 99                 :                : /*
                                100                 :                :  * VacuumFailsafeActive is a defined as a global so that we can determine
                                101                 :                :  * whether or not to re-enable cost-based vacuum delay when vacuuming a table.
                                102                 :                :  * If failsafe mode has been engaged, we will not re-enable cost-based delay
                                103                 :                :  * for the table until after vacuuming has completed, regardless of other
                                104                 :                :  * settings.
                                105                 :                :  *
                                106                 :                :  * Only VACUUM code should inspect this variable and only table access methods
                                107                 :                :  * should set it to true. In Table AM-agnostic VACUUM code, this variable is
                                108                 :                :  * inspected to determine whether or not to allow cost-based delays. Table AMs
                                109                 :                :  * are free to set it if they desire this behavior, but it is false by default
                                110                 :                :  * and reset to false in between vacuuming each relation.
                                111                 :                :  */
                                112                 :                : bool        VacuumFailsafeActive = false;
                                113                 :                : 
                                114                 :                : /*
                                115                 :                :  * Variables for cost-based parallel vacuum.  See comments atop
                                116                 :                :  * compute_parallel_delay to understand how it works.
                                117                 :                :  */
                                118                 :                : pg_atomic_uint32 *VacuumSharedCostBalance = NULL;
                                119                 :                : pg_atomic_uint32 *VacuumActiveNWorkers = NULL;
                                120                 :                : int         VacuumCostBalanceLocal = 0;
                                121                 :                : 
                                122                 :                : /* non-export function prototypes */
                                123                 :                : static List *expand_vacuum_rel(VacuumRelation *vrel,
                                124                 :                :                                MemoryContext vac_context, int options);
                                125                 :                : static List *get_all_vacuum_rels(MemoryContext vac_context, int options);
                                126                 :                : static void vac_truncate_clog(TransactionId frozenXID,
                                127                 :                :                               MultiXactId minMulti,
                                128                 :                :                               TransactionId lastSaneFrozenXid,
                                129                 :                :                               MultiXactId lastSaneMinMulti);
                                130                 :                : static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
                                131                 :                :                        BufferAccessStrategy bstrategy, bool isTopLevel);
                                132                 :                : static double compute_parallel_delay(void);
                                133                 :                : static VacOptValue get_vacoptval_from_boolean(DefElem *def);
                                134                 :                : static bool vac_tid_reaped(ItemPointer itemptr, void *state);
                                135                 :                : 
                                136                 :                : /*
                                137                 :                :  * GUC check function to ensure GUC value specified is within the allowable
                                138                 :                :  * range.
                                139                 :                :  */
                                140                 :                : bool
 1238 drowley@postgresql.o      141                 :CBC        1279 : check_vacuum_buffer_usage_limit(int *newval, void **extra,
                                142                 :                :                                 GucSource source)
                                143                 :                : {
                                144                 :                :     /* Value upper and lower hard limits are inclusive */
                                145   [ +  -  +  - ]:           1279 :     if (*newval == 0 || (*newval >= MIN_BAS_VAC_RING_SIZE_KB &&
                                146         [ +  - ]:           1279 :                          *newval <= MAX_BAS_VAC_RING_SIZE_KB))
                                147                 :           1279 :         return true;
                                148                 :                : 
                                149                 :                :     /* Value does not fall within any allowable range */
  638 alvherre@alvh.no-ip.      150                 :UBC           0 :     GUC_check_errdetail("\"%s\" must be 0 or between %d kB and %d kB.",
                                151                 :                :                         "vacuum_buffer_usage_limit",
                                152                 :                :                         MIN_BAS_VAC_RING_SIZE_KB, MAX_BAS_VAC_RING_SIZE_KB);
                                153                 :                : 
 1238 drowley@postgresql.o      154                 :              0 :     return false;
                                155                 :                : }
                                156                 :                : 
                                157                 :                : /*
                                158                 :                :  * Primary entry point for manual VACUUM and ANALYZE commands
                                159                 :                :  *
                                160                 :                :  * This is mainly a preparation wrapper for the real operations that will
                                161                 :                :  * happen in vacuum().
                                162                 :                :  */
                                163                 :                : void
 2719 rhaas@postgresql.org      164                 :CBC        8726 : ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
                                165                 :                : {
                                166                 :                :     VacuumParams params;
 1239 drowley@postgresql.o      167                 :           8726 :     BufferAccessStrategy bstrategy = NULL;
 2654 tgl@sss.pgh.pa.us         168                 :           8726 :     bool        verbose = false;
                                169                 :           8726 :     bool        skip_locked = false;
                                170                 :           8726 :     bool        analyze = false;
                                171                 :           8726 :     bool        freeze = false;
                                172                 :           8726 :     bool        full = false;
                                173                 :           8726 :     bool        disable_page_skipping = false;
 1270 michael@paquier.xyz       174                 :           8726 :     bool        process_main = true;
 2025                           175                 :           8726 :     bool        process_toast = true;
                                176                 :                :     int         ring_size;
 1329 tgl@sss.pgh.pa.us         177                 :           8726 :     bool        skip_database_stats = false;
                                178                 :           8726 :     bool        only_database_stats = false;
                                179                 :                :     MemoryContext vac_context;
                                180                 :                :     ListCell   *lc;
                                181                 :                : 
                                182                 :                :     /* index_cleanup and truncate values unspecified for now */
 1896 pg@bowt.ie                183                 :           8726 :     params.index_cleanup = VACOPTVALUE_UNSPECIFIED;
                                184                 :           8726 :     params.truncate = VACOPTVALUE_UNSPECIFIED;
                                185                 :                : 
                                186                 :                :     /* By default parallel vacuum is enabled */
 2411 akapila@postgresql.o      187                 :           8726 :     params.nworkers = 0;
                                188                 :                : 
                                189                 :                :     /* Will be set later if we recurse to a TOAST table. */
  897 nathan@postgresql.or      190                 :           8726 :     params.toast_parent = InvalidOid;
    3 nathan@postgresql.or      191                 :GNC        8726 :     params.main_relopts = NULL;
                                192                 :                : 
                                193                 :                :     /*
                                194                 :                :      * Set this to an invalid value so it is clear whether or not a
                                195                 :                :      * BUFFER_USAGE_LIMIT was specified when making the access strategy.
                                196                 :                :      */
 1238 drowley@postgresql.o      197                 :CBC        8726 :     ring_size = -1;
                                198                 :                : 
                                199                 :                :     /* Parse options list */
 2719 rhaas@postgresql.org      200   [ +  +  +  +  :          17812 :     foreach(lc, vacstmt->options)
                                              +  + ]
                                201                 :                :     {
 2654 tgl@sss.pgh.pa.us         202                 :           9110 :         DefElem    *opt = (DefElem *) lfirst(lc);
                                203                 :                : 
                                204                 :                :         /* Parse common options for VACUUM and ANALYZE */
 2719 rhaas@postgresql.org      205         [ +  + ]:           9110 :         if (strcmp(opt->defname, "verbose") == 0)
 2708                           206                 :             32 :             verbose = defGetBoolean(opt);
 2719                           207         [ +  + ]:           9078 :         else if (strcmp(opt->defname, "skip_locked") == 0)
 2708                           208                 :            182 :             skip_locked = defGetBoolean(opt);
 1238 drowley@postgresql.o      209         [ +  + ]:           8896 :         else if (strcmp(opt->defname, "buffer_usage_limit") == 0)
                                210                 :                :         {
                                211                 :                :             const char *hintmsg;
                                212                 :                :             int         result;
                                213                 :                :             char       *vac_buffer_size;
                                214                 :                : 
                                215                 :             36 :             vac_buffer_size = defGetString(opt);
                                216                 :                : 
                                217                 :                :             /*
                                218                 :                :              * Check that the specified value is valid and the size falls
                                219                 :                :              * within the hard upper and lower limits if it is not 0.
                                220                 :                :              */
 1234                           221         [ +  + ]:             36 :             if (!parse_int(vac_buffer_size, &result, GUC_UNIT_KB, &hintmsg) ||
                                222         [ +  + ]:             32 :                 (result != 0 &&
                                223   [ +  +  +  + ]:             24 :                  (result < MIN_BAS_VAC_RING_SIZE_KB || result > MAX_BAS_VAC_RING_SIZE_KB)))
                                224                 :                :             {
 1238                           225   [ +  -  +  + ]:             12 :                 ereport(ERROR,
                                226                 :                :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                227                 :                :                          errmsg("%s option must be 0 or between %d kB and %d kB",
                                228                 :                :                                 "BUFFER_USAGE_LIMIT",
                                229                 :                :                                 MIN_BAS_VAC_RING_SIZE_KB, MAX_BAS_VAC_RING_SIZE_KB),
                                230                 :                :                          hintmsg ? errhint_internal("%s", _(hintmsg)) : 0));
                                231                 :                :             }
                                232                 :                : 
                                233                 :             24 :             ring_size = result;
                                234                 :                :         }
 2719 rhaas@postgresql.org      235         [ +  + ]:           8860 :         else if (!vacstmt->is_vacuumcmd)
                                236         [ +  - ]:              4 :             ereport(ERROR,
                                237                 :                :                     (errcode(ERRCODE_SYNTAX_ERROR),
                                238                 :                :                      errmsg("unrecognized %s option \"%s\"",
                                239                 :                :                             "ANALYZE", opt->defname),
                                240                 :                :                      parser_errposition(pstate, opt->location)));
                                241                 :                : 
                                242                 :                :         /* Parse options available on VACUUM */
                                243         [ +  + ]:           8856 :         else if (strcmp(opt->defname, "analyze") == 0)
 2708                           244                 :           1852 :             analyze = defGetBoolean(opt);
 2719                           245         [ +  + ]:           7004 :         else if (strcmp(opt->defname, "freeze") == 0)
 2708                           246                 :           1679 :             freeze = defGetBoolean(opt);
 2719                           247         [ +  + ]:           5325 :         else if (strcmp(opt->defname, "full") == 0)
 2708                           248                 :            234 :             full = defGetBoolean(opt);
 2719                           249         [ +  + ]:           5091 :         else if (strcmp(opt->defname, "disable_page_skipping") == 0)
 2708                           250                 :            124 :             disable_page_skipping = defGetBoolean(opt);
 2702                           251         [ +  + ]:           4967 :         else if (strcmp(opt->defname, "index_cleanup") == 0)
                                252                 :                :         {
                                253                 :                :             /* Interpret no string as the default, which is 'auto' */
 1896 pg@bowt.ie                254         [ -  + ]:            100 :             if (!opt->arg)
 1896 pg@bowt.ie                255                 :UBC           0 :                 params.index_cleanup = VACOPTVALUE_AUTO;
                                256                 :                :             else
                                257                 :                :             {
 1896 pg@bowt.ie                258                 :CBC         100 :                 char       *sval = defGetString(opt);
                                259                 :                : 
                                260                 :                :                 /* Try matching on 'auto' string, or fall back on boolean */
                                261         [ +  + ]:            100 :                 if (pg_strcasecmp(sval, "auto") == 0)
                                262                 :              4 :                     params.index_cleanup = VACOPTVALUE_AUTO;
                                263                 :                :                 else
                                264                 :             96 :                     params.index_cleanup = get_vacoptval_from_boolean(opt);
                                265                 :                :             }
                                266                 :                :         }
 1270 michael@paquier.xyz       267         [ +  + ]:           4867 :         else if (strcmp(opt->defname, "process_main") == 0)
                                268                 :             85 :             process_main = defGetBoolean(opt);
 2025                           269         [ +  + ]:           4782 :         else if (strcmp(opt->defname, "process_toast") == 0)
                                270                 :             89 :             process_toast = defGetBoolean(opt);
 2668 fujii@postgresql.org      271         [ +  + ]:           4693 :         else if (strcmp(opt->defname, "truncate") == 0)
 1896 pg@bowt.ie                272                 :             88 :             params.truncate = get_vacoptval_from_boolean(opt);
 2411 akapila@postgresql.o      273         [ +  + ]:           4605 :         else if (strcmp(opt->defname, "parallel") == 0)
                                274                 :                :         {
  321 drowley@postgresql.o      275                 :            199 :             int         nworkers = defGetInt32(opt);
                                276                 :                : 
                                277   [ +  +  -  + ]:            195 :             if (nworkers < 0 || nworkers > MAX_PARALLEL_WORKER_LIMIT)
 2411 akapila@postgresql.o      278         [ +  - ]:              4 :                 ereport(ERROR,
                                279                 :                :                         (errcode(ERRCODE_SYNTAX_ERROR),
                                280                 :                :                          errmsg("%s option must be between 0 and %d",
                                281                 :                :                                 "PARALLEL",
                                282                 :                :                                 MAX_PARALLEL_WORKER_LIMIT),
                                283                 :                :                          parser_errposition(pstate, opt->location)));
                                284                 :                : 
                                285                 :                :             /*
                                286                 :                :              * Disable parallel vacuum, if user has specified parallel degree
                                287                 :                :              * as zero.
                                288                 :                :              */
  321 drowley@postgresql.o      289         [ +  + ]:            191 :             if (nworkers == 0)
                                290                 :             86 :                 params.nworkers = -1;
                                291                 :                :             else
                                292                 :            105 :                 params.nworkers = nworkers;
                                293                 :                :         }
 1329 tgl@sss.pgh.pa.us         294         [ +  + ]:           4406 :         else if (strcmp(opt->defname, "skip_database_stats") == 0)
                                295                 :           4331 :             skip_database_stats = defGetBoolean(opt);
                                296         [ +  - ]:             75 :         else if (strcmp(opt->defname, "only_database_stats") == 0)
                                297                 :             75 :             only_database_stats = defGetBoolean(opt);
                                298                 :                :         else
 2719 rhaas@postgresql.org      299         [ #  # ]:UBC           0 :             ereport(ERROR,
                                300                 :                :                     (errcode(ERRCODE_SYNTAX_ERROR),
                                301                 :                :                      errmsg("unrecognized %s option \"%s\"",
                                302                 :                :                             "VACUUM", opt->defname),
                                303                 :                :                      parser_errposition(pstate, opt->location)));
                                304                 :                :     }
                                305                 :                : 
                                306                 :                :     /* Set vacuum options */
 2708 rhaas@postgresql.org      307                 :CBC        8702 :     params.options =
                                308         [ +  + ]:           8702 :         (vacstmt->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE) |
                                309         [ +  + ]:           8702 :         (verbose ? VACOPT_VERBOSE : 0) |
                                310         [ +  + ]:           8702 :         (skip_locked ? VACOPT_SKIP_LOCKED : 0) |
                                311         [ +  + ]:           8702 :         (analyze ? VACOPT_ANALYZE : 0) |
                                312         [ +  + ]:           8702 :         (freeze ? VACOPT_FREEZE : 0) |
                                313         [ +  + ]:           8702 :         (full ? VACOPT_FULL : 0) |
 2025 michael@paquier.xyz       314         [ +  + ]:           8702 :         (disable_page_skipping ? VACOPT_DISABLE_PAGE_SKIPPING : 0) |
 1270                           315         [ +  + ]:           8702 :         (process_main ? VACOPT_PROCESS_MAIN : 0) |
 1329 tgl@sss.pgh.pa.us         316         [ +  + ]:           8702 :         (process_toast ? VACOPT_PROCESS_TOAST : 0) |
                                317         [ +  + ]:           8702 :         (skip_database_stats ? VACOPT_SKIP_DATABASE_STATS : 0) |
                                318         [ +  + ]:           8702 :         (only_database_stats ? VACOPT_ONLY_DATABASE_STATS : 0);
                                319                 :                : 
                                320                 :                :     /* sanity checks on options */
 2719 rhaas@postgresql.org      321         [ -  + ]:           8702 :     Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE));
                                322   [ +  +  -  + ]:           8702 :     Assert((params.options & VACOPT_VACUUM) ||
                                323                 :                :            !(params.options & (VACOPT_FULL | VACOPT_FREEZE)));
                                324                 :                : 
 2324 akapila@postgresql.o      325   [ +  +  +  + ]:           8702 :     if ((params.options & VACOPT_FULL) && params.nworkers > 0)
 2411                           326         [ +  - ]:              4 :         ereport(ERROR,
                                327                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                328                 :                :                  errmsg("VACUUM FULL cannot be performed in parallel")));
                                329                 :                : 
                                330                 :                :     /*
                                331                 :                :      * BUFFER_USAGE_LIMIT does nothing for VACUUM (FULL) so just raise an
                                332                 :                :      * ERROR for that case.  VACUUM (FULL, ANALYZE) does make use of it, so
                                333                 :                :      * we'll permit that.
                                334                 :                :      */
 1238 drowley@postgresql.o      335   [ +  +  +  + ]:           8698 :     if (ring_size != -1 && (params.options & VACOPT_FULL) &&
                                336         [ +  - ]:              4 :         !(params.options & VACOPT_ANALYZE))
                                337         [ +  - ]:              4 :         ereport(ERROR,
                                338                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                339                 :                :                  errmsg("BUFFER_USAGE_LIMIT cannot be specified for VACUUM FULL")));
                                340                 :                : 
                                341                 :                :     /*
                                342                 :                :      * Make sure VACOPT_ANALYZE is specified if any column lists are present.
                                343                 :                :      */
 2719 rhaas@postgresql.org      344         [ +  + ]:           8694 :     if (!(params.options & VACOPT_ANALYZE))
                                345                 :                :     {
 3250 tgl@sss.pgh.pa.us         346   [ +  +  +  +  :           7254 :         foreach(lc, vacstmt->rels)
                                              +  + ]
                                347                 :                :         {
                                348                 :           3575 :             VacuumRelation *vrel = lfirst_node(VacuumRelation, lc);
                                349                 :                : 
                                350         [ +  + ]:           3575 :             if (vrel->va_cols != NIL)
                                351         [ +  - ]:              4 :                 ereport(ERROR,
                                352                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                353                 :                :                          errmsg("ANALYZE option must be specified when a column list is provided")));
                                354                 :                :         }
                                355                 :                :     }
                                356                 :                : 
                                357                 :                :     /*
                                358                 :                :      * Sanity check DISABLE_PAGE_SKIPPING option.
                                359                 :                :      */
 1239 drowley@postgresql.o      360         [ +  + ]:           8690 :     if ((params.options & VACOPT_FULL) != 0 &&
                                361         [ -  + ]:            218 :         (params.options & VACOPT_DISABLE_PAGE_SKIPPING) != 0)
 1239 drowley@postgresql.o      362         [ #  # ]:UBC           0 :         ereport(ERROR,
                                363                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                364                 :                :                  errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
                                365                 :                : 
                                366                 :                :     /* sanity check for PROCESS_TOAST */
 1239 drowley@postgresql.o      367         [ +  + ]:CBC        8690 :     if ((params.options & VACOPT_FULL) != 0 &&
                                368         [ +  + ]:            218 :         (params.options & VACOPT_PROCESS_TOAST) == 0)
                                369         [ +  - ]:              4 :         ereport(ERROR,
                                370                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                371                 :                :                  errmsg("PROCESS_TOAST required with VACUUM FULL")));
                                372                 :                : 
                                373                 :                :     /* sanity check for ONLY_DATABASE_STATS */
                                374         [ +  + ]:           8686 :     if (params.options & VACOPT_ONLY_DATABASE_STATS)
                                375                 :                :     {
                                376         [ -  + ]:             75 :         Assert(params.options & VACOPT_VACUUM);
                                377         [ +  + ]:             75 :         if (vacstmt->rels != NIL)
                                378         [ +  - ]:              4 :             ereport(ERROR,
                                379                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                380                 :                :                      errmsg("ONLY_DATABASE_STATS cannot be specified with a list of tables")));
                                381                 :                :         /* don't require people to turn off PROCESS_TOAST/MAIN explicitly */
                                382         [ -  + ]:             71 :         if (params.options & ~(VACOPT_VACUUM |
                                383                 :                :                                VACOPT_VERBOSE |
                                384                 :                :                                VACOPT_PROCESS_MAIN |
                                385                 :                :                                VACOPT_PROCESS_TOAST |
                                386                 :                :                                VACOPT_ONLY_DATABASE_STATS))
 1239 drowley@postgresql.o      387         [ #  # ]:UBC           0 :             ereport(ERROR,
                                388                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                389                 :                :                      errmsg("ONLY_DATABASE_STATS cannot be specified with other VACUUM options")));
                                390                 :                :     }
                                391                 :                : 
                                392                 :                :     /*
                                393                 :                :      * All freeze ages are zero if the FREEZE option is given; otherwise pass
                                394                 :                :      * them as -1 which means to use the default values.
                                395                 :                :      */
 2719 rhaas@postgresql.org      396         [ +  + ]:CBC        8682 :     if (params.options & VACOPT_FREEZE)
                                397                 :                :     {
 4180 alvherre@alvh.no-ip.      398                 :           1679 :         params.freeze_min_age = 0;
                                399                 :           1679 :         params.freeze_table_age = 0;
                                400                 :           1679 :         params.multixact_freeze_min_age = 0;
                                401                 :           1679 :         params.multixact_freeze_table_age = 0;
                                402                 :                :     }
                                403                 :                :     else
                                404                 :                :     {
                                405                 :           7003 :         params.freeze_min_age = -1;
                                406                 :           7003 :         params.freeze_table_age = -1;
                                407                 :           7003 :         params.multixact_freeze_min_age = -1;
                                408                 :           7003 :         params.multixact_freeze_table_age = -1;
                                409                 :                :     }
                                410                 :                : 
                                411                 :                :     /* user-invoked vacuum is never "for wraparound" */
                                412                 :           8682 :     params.is_wraparound = false;
                                413                 :                : 
                                414                 :                :     /*
                                415                 :                :      * user-invoked vacuum uses VACOPT_VERBOSE instead of
                                416                 :                :      * log_vacuum_min_duration and log_analyze_min_duration
                                417                 :                :      */
  316 peter@eisentraut.org      418                 :           8682 :     params.log_vacuum_min_duration = -1;
                                419                 :           8682 :     params.log_analyze_min_duration = -1;
                                420                 :                : 
                                421                 :                :     /*
                                422                 :                :      * Later, in vacuum_rel(), we check if a reloption override was specified.
                                423                 :                :      */
  562 melanieplageman@gmai      424                 :           8682 :     params.max_eager_freeze_failure_rate = vacuum_max_eager_freeze_failure_rate;
                                425                 :                : 
                                426                 :                :     /*
                                427                 :                :      * Create special memory context for cross-transaction storage.
                                428                 :                :      *
                                429                 :                :      * Since it is a child of PortalContext, it will go away eventually even
                                430                 :                :      * if we suffer an error; there's no need for special abort cleanup logic.
                                431                 :                :      */
 1239 drowley@postgresql.o      432                 :           8682 :     vac_context = AllocSetContextCreate(PortalContext,
                                433                 :                :                                         "Vacuum",
                                434                 :                :                                         ALLOCSET_DEFAULT_SIZES);
                                435                 :                : 
                                436                 :                :     /*
                                437                 :                :      * Make a buffer strategy object in the cross-transaction memory context.
                                438                 :                :      * We needn't bother making this for VACUUM (FULL) or VACUUM
                                439                 :                :      * (ONLY_DATABASE_STATS) as they'll not make use of it.  VACUUM (FULL,
                                440                 :                :      * ANALYZE) is possible, so we'd better ensure that we make a strategy
                                441                 :                :      * when we see ANALYZE.
                                442                 :                :      */
                                443         [ +  + ]:           8682 :     if ((params.options & (VACOPT_ONLY_DATABASE_STATS |
                                444                 :            285 :                            VACOPT_FULL)) == 0 ||
                                445         [ +  + ]:            285 :         (params.options & VACOPT_ANALYZE) != 0)
                                446                 :                :     {
                                447                 :                : 
                                448                 :           8401 :         MemoryContext old_context = MemoryContextSwitchTo(vac_context);
                                449                 :                : 
 1238                           450         [ -  + ]:           8401 :         Assert(ring_size >= -1);
                                451                 :                : 
                                452                 :                :         /*
                                453                 :                :          * If BUFFER_USAGE_LIMIT was specified by the VACUUM or ANALYZE
                                454                 :                :          * command, it overrides the value of VacuumBufferUsageLimit.  Either
                                455                 :                :          * value may be 0, in which case GetAccessStrategyWithSize() will
                                456                 :                :          * return NULL, effectively allowing full use of shared buffers.
                                457                 :                :          */
                                458         [ +  + ]:           8401 :         if (ring_size == -1)
                                459                 :           8381 :             ring_size = VacuumBufferUsageLimit;
                                460                 :                : 
                                461                 :           8401 :         bstrategy = GetAccessStrategyWithSize(BAS_VACUUM, ring_size);
                                462                 :                : 
 1239                           463                 :           8401 :         MemoryContextSwitchTo(old_context);
                                464                 :                :     }
                                465                 :                : 
                                466                 :                :     /* Now go through the common routine */
  149 nathan@postgresql.or      467                 :           8682 :     vacuum(vacstmt->rels, &params, bstrategy, vac_context, isTopLevel);
                                468                 :                : 
                                469                 :                :     /* Finally, clean up the vacuum memory context */
 1239 drowley@postgresql.o      470                 :           8592 :     MemoryContextDelete(vac_context);
 4180 alvherre@alvh.no-ip.      471                 :           8592 : }
                                472                 :                : 
                                473                 :                : /*
                                474                 :                :  * Internal entry point for autovacuum and the VACUUM / ANALYZE commands.
                                475                 :                :  *
                                476                 :                :  * relations, if not NIL, is a list of VacuumRelation to process; otherwise,
                                477                 :                :  * we process all relevant tables in the database.  For each VacuumRelation,
                                478                 :                :  * if a valid OID is supplied, the table with that OID is what to process;
                                479                 :                :  * otherwise, the VacuumRelation's RangeVar indicates what to process.
                                480                 :                :  *
                                481                 :                :  * params contains a set of parameters that can be used to customize the
                                482                 :                :  * behavior.
                                483                 :                :  *
                                484                 :                :  * bstrategy may be passed in as NULL when the caller does not want to
                                485                 :                :  * restrict the number of shared_buffers that VACUUM / ANALYZE can use,
                                486                 :                :  * otherwise, the caller must build a BufferAccessStrategy with the number of
                                487                 :                :  * shared_buffers that VACUUM / ANALYZE should try to limit themselves to
                                488                 :                :  * using.
                                489                 :                :  *
                                490                 :                :  * isTopLevel should be passed down from ProcessUtility.
                                491                 :                :  *
                                492                 :                :  * It is the caller's responsibility that all parameters are allocated in a
                                493                 :                :  * memory context that will not disappear at transaction commit.
                                494                 :                :  */
                                495                 :                : void
  149 nathan@postgresql.or      496                 :           9551 : vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrategy,
                                497                 :                :        MemoryContext vac_context, bool isTopLevel)
                                498                 :                : {
                                499                 :                :     static bool in_vacuum = false;
                                500                 :                : 
                                501                 :                :     const char *stmttype;
                                502                 :                :     volatile bool in_outer_xact,
                                503                 :                :                 use_own_xacts;
                                504                 :                : 
                                505         [ +  + ]:           9551 :     stmttype = (params->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
                                506                 :                : 
                                507                 :                :     /*
                                508                 :                :      * We cannot run VACUUM inside a user transaction block; if we were inside
                                509                 :                :      * a transaction, then our commit- and start-transaction-command calls
                                510                 :                :      * would not have the intended effect!  There are numerous other subtle
                                511                 :                :      * dependencies on this, too.
                                512                 :                :      *
                                513                 :                :      * ANALYZE (without VACUUM) can run either way.
                                514                 :                :      */
                                515         [ +  + ]:           9551 :     if (params->options & VACOPT_VACUUM)
                                516                 :                :     {
 3114 peter_e@gmx.net           517                 :           6001 :         PreventInTransactionBlock(isTopLevel, stmttype);
 8132 tgl@sss.pgh.pa.us         518                 :           5988 :         in_outer_xact = false;
                                519                 :                :     }
                                520                 :                :     else
 3114 peter_e@gmx.net           521                 :           3550 :         in_outer_xact = IsInTransactionBlock(isTopLevel);
                                522                 :                : 
                                523                 :                :     /*
                                524                 :                :      * Check for and disallow recursive calls.  This could happen when VACUUM
                                525                 :                :      * FULL or ANALYZE calls a hostile index expression that itself calls
                                526                 :                :      * ANALYZE.
                                527                 :                :      */
 4250 noah@leadboat.com         528         [ +  + ]:           9538 :     if (in_vacuum)
 4043 tgl@sss.pgh.pa.us         529         [ +  - ]:              8 :         ereport(ERROR,
                                530                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                531                 :                :                  errmsg("%s cannot be executed from VACUUM or ANALYZE",
                                532                 :                :                         stmttype)));
                                533                 :                : 
                                534                 :                :     /*
                                535                 :                :      * Build list of relation(s) to process, putting any new data in
                                536                 :                :      * vac_context for safekeeping.
                                537                 :                :      */
  149 nathan@postgresql.or      538         [ +  + ]:           9530 :     if (params->options & VACOPT_ONLY_DATABASE_STATS)
                                539                 :                :     {
                                540                 :                :         /* We don't process any tables in this case */
 1329 tgl@sss.pgh.pa.us         541         [ -  + ]:             71 :         Assert(relations == NIL);
                                542                 :                :     }
                                543         [ +  + ]:           9459 :     else if (relations != NIL)
                                544                 :                :     {
 3250                           545                 :           9339 :         List       *newrels = NIL;
                                546                 :                :         ListCell   *lc;
                                547                 :                : 
                                548   [ +  -  +  +  :          18763 :         foreach(lc, relations)
                                              +  + ]
                                549                 :                :         {
                                550                 :           9448 :             VacuumRelation *vrel = lfirst_node(VacuumRelation, lc);
                                551                 :                :             List       *sublist;
                                552                 :                :             MemoryContext old_context;
                                553                 :                : 
  149 nathan@postgresql.or      554                 :           9448 :             sublist = expand_vacuum_rel(vrel, vac_context, params->options);
 3250 tgl@sss.pgh.pa.us         555                 :           9424 :             old_context = MemoryContextSwitchTo(vac_context);
                                556                 :           9424 :             newrels = list_concat(newrels, sublist);
                                557                 :           9424 :             MemoryContextSwitchTo(old_context);
                                558                 :                :         }
                                559                 :           9315 :         relations = newrels;
                                560                 :                :     }
                                561                 :                :     else
  149 nathan@postgresql.or      562                 :            120 :         relations = get_all_vacuum_rels(vac_context, params->options);
                                563                 :                : 
                                564                 :                :     /*
                                565                 :                :      * Decide whether we need to start/commit our own transactions.
                                566                 :                :      *
                                567                 :                :      * For VACUUM (with or without ANALYZE): always do so, so that we can
                                568                 :                :      * release locks as soon as possible.  (We could possibly use the outer
                                569                 :                :      * transaction for a one-table VACUUM, but handling TOAST tables would be
                                570                 :                :      * problematic.)
                                571                 :                :      *
                                572                 :                :      * For ANALYZE (no VACUUM): if inside a transaction block, we cannot
                                573                 :                :      * start/commit our own transactions.  Also, there's no need to do so if
                                574                 :                :      * only processing one relation.  For multiple relations when not within a
                                575                 :                :      * transaction block, and also in an autovacuum worker, use own
                                576                 :                :      * transactions so we can release locks sooner.
                                577                 :                :      */
                                578         [ +  + ]:           9506 :     if (params->options & VACOPT_VACUUM)
 8132 tgl@sss.pgh.pa.us         579                 :           5980 :         use_own_xacts = true;
                                580                 :                :     else
                                581                 :                :     {
  149 nathan@postgresql.or      582         [ -  + ]:           3526 :         Assert(params->options & VACOPT_ANALYZE);
  906 heikki.linnakangas@i      583         [ +  + ]:           3526 :         if (AmAutoVacuumWorkerProcess())
 7014 alvherre@alvh.no-ip.      584                 :            391 :             use_own_xacts = true;
                                585         [ +  + ]:           3135 :         else if (in_outer_xact)
 8132 tgl@sss.pgh.pa.us         586                 :            168 :             use_own_xacts = false;
 8128 neilc@samurai.com         587         [ +  + ]:           2967 :         else if (list_length(relations) > 1)
 8132 tgl@sss.pgh.pa.us         588                 :            524 :             use_own_xacts = true;
                                589                 :                :         else
                                590                 :           2443 :             use_own_xacts = false;
                                591                 :                :     }
                                592                 :                : 
                                593                 :                :     /*
                                594                 :                :      * vacuum_rel expects to be entered with no transaction active; it will
                                595                 :                :      * start and commit its own transaction.  But we are called by an SQL
                                596                 :                :      * command, and so we are executing inside a transaction already. We
                                597                 :                :      * commit the transaction started in PostgresMain() here, and start
                                598                 :                :      * another one before exiting to match the commit waiting for us back in
                                599                 :                :      * PostgresMain().
                                600                 :                :      */
                                601         [ +  + ]:           9506 :     if (use_own_xacts)
                                602                 :                :     {
 4319                           603         [ -  + ]:           6895 :         Assert(!in_outer_xact);
                                604                 :                : 
                                605                 :                :         /* ActiveSnapshot is not set by autovacuum */
 6681 alvherre@alvh.no-ip.      606         [ +  + ]:           6895 :         if (ActiveSnapshotSet())
                                607                 :           6026 :             PopActiveSnapshot();
                                608                 :                : 
                                609                 :                :         /* matches the StartTransaction in PostgresMain() */
 8506 tgl@sss.pgh.pa.us         610                 :           6895 :         CommitTransactionCommand();
                                611                 :                :     }
                                612                 :                : 
                                613                 :                :     /* Turn vacuum cost accounting on or off, and set/clear in_vacuum */
 8062                           614         [ +  + ]:           9506 :     PG_TRY();
                                615                 :                :     {
                                616                 :                :         ListCell   *cur;
                                617                 :                : 
 4250 noah@leadboat.com         618                 :           9506 :         in_vacuum = true;
 1238 dgustafsson@postgres      619                 :           9506 :         VacuumFailsafeActive = false;
                                620                 :           9506 :         VacuumUpdateCosts();
 8062 tgl@sss.pgh.pa.us         621                 :           9506 :         VacuumCostBalance = 0;
 2411 akapila@postgresql.o      622                 :           9506 :         VacuumCostBalanceLocal = 0;
                                623                 :           9506 :         VacuumSharedCostBalance = NULL;
                                624                 :           9506 :         VacuumActiveNWorkers = NULL;
                                625                 :                : 
                                626                 :                :         /*
                                627                 :                :          * Loop to process each selected relation.
                                628                 :                :          */
 8062 tgl@sss.pgh.pa.us         629   [ +  +  +  +  :          29366 :         foreach(cur, relations)
                                              +  + ]
                                630                 :                :         {
 3250                           631                 :          19906 :             VacuumRelation *vrel = lfirst_node(VacuumRelation, cur);
                                632                 :                : 
  149 nathan@postgresql.or      633         [ +  + ]:          19906 :             if (params->options & VACOPT_VACUUM)
                                634                 :                :             {
  143 alvherre@kurilemu.de      635         [ +  + ]:          11300 :                 if (!vacuum_rel(vrel->oid, vrel->relation, *params, bstrategy,
                                636                 :                :                                 isTopLevel))
 5680 rhaas@postgresql.org      637                 :             66 :                     continue;
                                638                 :                :             }
                                639                 :                : 
  149 nathan@postgresql.or      640         [ +  + ]:          19834 :             if (params->options & VACOPT_ANALYZE)
                                641                 :                :             {
                                642                 :                :                 /*
                                643                 :                :                  * If using separate xacts, start one for analyze. Otherwise,
                                644                 :                :                  * we can use the outer transaction.
                                645                 :                :                  */
 8062 tgl@sss.pgh.pa.us         646         [ +  + ]:          10860 :                 if (use_own_xacts)
                                647                 :                :                 {
                                648                 :           8261 :                     StartTransactionCommand();
                                649                 :                :                     /* functions in indexes may want a snapshot set */
 6681 alvherre@alvh.no-ip.      650                 :           8261 :                     PushActiveSnapshot(GetTransactionSnapshot());
                                651                 :                :                 }
                                652                 :                : 
 2719 rhaas@postgresql.org      653                 :          10860 :                 analyze_rel(vrel->oid, vrel->relation, params,
                                654                 :                :                             vrel->va_cols, in_outer_xact, bstrategy);
                                655                 :                : 
 8062 tgl@sss.pgh.pa.us         656         [ +  + ]:          10820 :                 if (use_own_xacts)
                                657                 :                :                 {
 6681 alvherre@alvh.no-ip.      658                 :           8236 :                     PopActiveSnapshot();
                                659                 :                :                     /* standard_ProcessUtility() does CCI if !use_own_xacts */
  494 noah@leadboat.com         660                 :           8236 :                     CommandCounterIncrement();
 8062 tgl@sss.pgh.pa.us         661                 :           8236 :                     CommitTransactionCommand();
                                662                 :                :                 }
                                663                 :                :                 else
                                664                 :                :                 {
                                665                 :                :                     /*
                                666                 :                :                      * If we're not using separate xacts, better separate the
                                667                 :                :                      * ANALYZE actions with CCIs.  This avoids trouble if user
                                668                 :                :                      * says "ANALYZE t, t".
                                669                 :                :                      */
 2574                           670                 :           2584 :                     CommandCounterIncrement();
                                671                 :                :                 }
                                672                 :                :             }
                                673                 :                : 
                                674                 :                :             /*
                                675                 :                :              * Ensure VacuumFailsafeActive has been reset before vacuuming the
                                676                 :                :              * next relation.
                                677                 :                :              */
 1238 dgustafsson@postgres      678                 :          19794 :             VacuumFailsafeActive = false;
                                679                 :                :         }
                                680                 :                :     }
 2491 peter@eisentraut.org      681                 :             45 :     PG_FINALLY();
                                682                 :                :     {
 4250 noah@leadboat.com         683                 :           9505 :         in_vacuum = false;
 8062 tgl@sss.pgh.pa.us         684                 :           9505 :         VacuumCostActive = false;
 1238 dgustafsson@postgres      685                 :           9505 :         VacuumFailsafeActive = false;
                                686                 :           9505 :         VacuumCostBalance = 0;
                                687                 :                :     }
 8062 tgl@sss.pgh.pa.us         688         [ +  + ]:           9505 :     PG_END_TRY();
                                689                 :                : 
                                690                 :                :     /*
                                691                 :                :      * Finish up processing.
                                692                 :                :      */
 8132                           693         [ +  + ]:           9460 :     if (use_own_xacts)
                                694                 :                :     {
                                695                 :                :         /* here, we are not in a transaction */
                                696                 :                : 
                                697                 :                :         /*
                                698                 :                :          * This matches the CommitTransaction waiting for us in
                                699                 :                :          * PostgresMain().
                                700                 :                :          */
 8506                           701                 :           6864 :         StartTransactionCommand();
                                702                 :                :     }
                                703                 :                : 
  149 nathan@postgresql.or      704         [ +  + ]:           9460 :     if ((params->options & VACOPT_VACUUM) &&
                                705         [ +  + ]:           5957 :         !(params->options & VACOPT_SKIP_DATABASE_STATS))
                                706                 :                :     {
                                707                 :                :         /*
                                708                 :                :          * Update pg_database.datfrozenxid, and truncate pg_xact if possible.
                                709                 :                :          */
 7235 tgl@sss.pgh.pa.us         710                 :           1150 :         vac_update_datfrozenxid();
                                711                 :                :     }
                                712                 :                : 
11006 scrappy@hub.org           713                 :           9460 : }
                                714                 :                : 
                                715                 :                : /*
                                716                 :                :  * Check if the current user has privileges to vacuum or analyze the relation.
                                717                 :                :  * If not, issue a WARNING log message and return false to let the caller
                                718                 :                :  * decide what to do with this relation.  This routine is used to decide if a
                                719                 :                :  * relation can be processed for VACUUM or ANALYZE.
                                720                 :                :  *
                                721                 :                :  * If missing_ok is true, we silently return false if the relation is
                                722                 :                :  * concurrently dropped.  Callers without a lock on the relation must specify
                                723                 :                :  * missing_ok; all others must hold at least AccessShareLock.
                                724                 :                :  */
                                725                 :                : bool
  897 nathan@postgresql.or      726                 :          47395 : vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
                                727                 :                :                                  uint32 options, bool missing_ok)
                                728                 :                : {
                                729                 :                :     char       *relname;
   24 nathan@postgresql.or      730                 :GNC       47395 :     bool        is_missing = false;
                                731                 :                : 
 2922 michael@paquier.xyz       732         [ -  + ]:CBC       47395 :     Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
   24 nathan@postgresql.or      733   [ +  +  -  + ]:GNC       47395 :     Assert(missing_ok ||
                                734                 :                :            CheckRelationOidLockedByMe(relid, AccessShareLock, true));
                                735                 :                : 
                                736                 :                :     /*----------
                                737                 :                :      * A role has privileges to vacuum or analyze the relation if any of the
                                738                 :                :      * following are true:
                                739                 :                :      *   - the role owns the current database and the relation is not shared
                                740                 :                :      *   - the role has the MAINTAIN privilege on the relation
                                741                 :                :      *----------
                                742                 :                :      */
  897 nathan@postgresql.or      743         [ +  + ]:CBC       47395 :     if ((object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()) &&
                                744   [ +  +  +  + ]:          53098 :          !reltuple->relisshared) ||
   24 nathan@postgresql.or      745         [ +  + ]:GNC        8195 :         pg_class_aclcheck_ext(relid, GetUserId(), ACL_MAINTAIN,
                                746                 :                :                               missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 2922 michael@paquier.xyz       747                 :CBC       45215 :         return true;
                                748                 :                : 
                                749                 :                :     /*
                                750                 :                :      * If the relation was concurrently dropped, nothing to do.  Note that
                                751                 :                :      * this is only reachable when the caller specified missing_ok.
                                752                 :                :      */
   24 nathan@postgresql.or      753         [ -  + ]:GNC        2180 :     if (is_missing)
                                754                 :                :     {
   24 nathan@postgresql.or      755         [ #  # ]:UNC           0 :         Assert(missing_ok);
                                756                 :              0 :         return false;
                                757                 :                :     }
                                758                 :                : 
 2922 michael@paquier.xyz       759                 :CBC        2180 :     relname = NameStr(reltuple->relname);
                                760                 :                : 
                                761         [ +  + ]:           2180 :     if ((options & VACOPT_VACUUM) != 0)
                                762                 :                :     {
 1373 andrew@dunslane.net       763         [ +  - ]:            148 :         ereport(WARNING,
                                764                 :                :                 (errmsg("permission denied to vacuum \"%s\", skipping it",
                                765                 :                :                         relname)));
                                766                 :                : 
                                767                 :                :         /*
                                768                 :                :          * For VACUUM ANALYZE, both logs could show up, but just generate
                                769                 :                :          * information for VACUUM as that would be the first one to be
                                770                 :                :          * processed.
                                771                 :                :          */
 2922 michael@paquier.xyz       772                 :            148 :         return false;
                                773                 :                :     }
                                774                 :                : 
                                775         [ +  - ]:           2032 :     if ((options & VACOPT_ANALYZE) != 0)
 1373 andrew@dunslane.net       776         [ +  - ]:           2032 :         ereport(WARNING,
                                777                 :                :                 (errmsg("permission denied to analyze \"%s\", skipping it",
                                778                 :                :                         relname)));
                                779                 :                : 
 2922 michael@paquier.xyz       780                 :           2032 :     return false;
                                781                 :                : }
                                782                 :                : 
                                783                 :                : 
                                784                 :                : /*
                                785                 :                :  * vacuum_open_relation
                                786                 :                :  *
                                787                 :                :  * This routine is used for attempting to open and lock a relation which
                                788                 :                :  * is going to be vacuumed or analyzed.  If the relation cannot be opened
                                789                 :                :  * or locked, a log is emitted if possible.
                                790                 :                :  */
                                791                 :                : Relation
  150 nathan@postgresql.or      792                 :          27694 : vacuum_open_relation(Oid relid, RangeVar *relation, uint32 options,
                                793                 :                :                      bool verbose, LOCKMODE lmode)
                                794                 :                : {
                                795                 :                :     Relation    rel;
 2886 michael@paquier.xyz       796                 :          27694 :     bool        rel_lock = true;
                                797                 :                :     int         elevel;
                                798                 :                : 
                                799         [ -  + ]:          27694 :     Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
                                800                 :                : 
                                801                 :                :     /*
                                802                 :                :      * Open the relation and get the appropriate lock on it.
                                803                 :                :      *
                                804                 :                :      * There's a race condition here: the relation may have gone away since
                                805                 :                :      * the last time we saw it.  If so, we don't need to vacuum or analyze it.
                                806                 :                :      *
                                807                 :                :      * If we've been asked not to wait for the relation lock, acquire it first
                                808                 :                :      * in non-blocking mode, before calling try_relation_open().
                                809                 :                :      */
                                810         [ +  + ]:          27694 :     if (!(options & VACOPT_SKIP_LOCKED))
 1970 pg@bowt.ie                811                 :          26215 :         rel = try_relation_open(relid, lmode);
 2886 michael@paquier.xyz       812         [ +  + ]:           1479 :     else if (ConditionalLockRelationOid(relid, lmode))
 1970 pg@bowt.ie                813                 :           1464 :         rel = try_relation_open(relid, NoLock);
                                814                 :                :     else
                                815                 :                :     {
                                816                 :             15 :         rel = NULL;
 2886 michael@paquier.xyz       817                 :             15 :         rel_lock = false;
                                818                 :                :     }
                                819                 :                : 
                                820                 :                :     /* if relation is opened, leave */
 1970 pg@bowt.ie                821         [ +  + ]:          27694 :     if (rel)
                                822                 :          27673 :         return rel;
                                823                 :                : 
                                824                 :                :     /*
                                825                 :                :      * Relation could not be opened, hence generate if possible a log
                                826                 :                :      * informing on the situation.
                                827                 :                :      *
                                828                 :                :      * If the RangeVar is not defined, we do not have enough information to
                                829                 :                :      * provide a meaningful log statement.  Chances are that the caller has
                                830                 :                :      * intentionally not provided this information so that this logging is
                                831                 :                :      * skipped, anyway.
                                832                 :                :      */
 2886 michael@paquier.xyz       833         [ +  + ]:             21 :     if (relation == NULL)
                                834                 :              9 :         return NULL;
                                835                 :                : 
                                836                 :                :     /*
                                837                 :                :      * Determine the log level.
                                838                 :                :      *
                                839                 :                :      * For manual VACUUM or ANALYZE, we emit a WARNING to match the log
                                840                 :                :      * statements in the permission checks; otherwise, only log if the caller
                                841                 :                :      * so requested.
                                842                 :                :      */
  906 heikki.linnakangas@i      843         [ +  + ]:             12 :     if (!AmAutoVacuumWorkerProcess())
 2886 michael@paquier.xyz       844                 :              7 :         elevel = WARNING;
 2719 rhaas@postgresql.org      845         [ +  - ]:              5 :     else if (verbose)
 2886 michael@paquier.xyz       846                 :              5 :         elevel = LOG;
                                847                 :                :     else
 2886 michael@paquier.xyz       848                 :UBC           0 :         return NULL;
                                849                 :                : 
 2886 michael@paquier.xyz       850         [ +  + ]:CBC          12 :     if ((options & VACOPT_VACUUM) != 0)
                                851                 :                :     {
                                852         [ +  + ]:              9 :         if (!rel_lock)
                                853         [ +  - ]:              7 :             ereport(elevel,
                                854                 :                :                     (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                855                 :                :                      errmsg("skipping vacuum of \"%s\" --- lock not available",
                                856                 :                :                             relation->relname)));
                                857                 :                :         else
                                858         [ +  - ]:              2 :             ereport(elevel,
                                859                 :                :                     (errcode(ERRCODE_UNDEFINED_TABLE),
                                860                 :                :                      errmsg("skipping vacuum of \"%s\" --- relation no longer exists",
                                861                 :                :                             relation->relname)));
                                862                 :                : 
                                863                 :                :         /*
                                864                 :                :          * For VACUUM ANALYZE, both logs could show up, but just generate
                                865                 :                :          * information for VACUUM as that would be the first one to be
                                866                 :                :          * processed.
                                867                 :                :          */
                                868                 :              9 :         return NULL;
                                869                 :                :     }
                                870                 :                : 
                                871         [ +  - ]:              3 :     if ((options & VACOPT_ANALYZE) != 0)
                                872                 :                :     {
                                873         [ +  + ]:              3 :         if (!rel_lock)
                                874         [ +  - ]:              2 :             ereport(elevel,
                                875                 :                :                     (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                876                 :                :                      errmsg("skipping analyze of \"%s\" --- lock not available",
                                877                 :                :                             relation->relname)));
                                878                 :                :         else
                                879         [ +  - ]:              1 :             ereport(elevel,
                                880                 :                :                     (errcode(ERRCODE_UNDEFINED_TABLE),
                                881                 :                :                      errmsg("skipping analyze of \"%s\" --- relation no longer exists",
                                882                 :                :                             relation->relname)));
                                883                 :                :     }
                                884                 :                : 
                                885                 :              3 :     return NULL;
                                886                 :                : }
                                887                 :                : 
                                888                 :                : 
                                889                 :                : /*
                                890                 :                :  * Given a VacuumRelation, fill in the table OID if it wasn't specified,
                                891                 :                :  * and optionally add VacuumRelations for partitions or inheritance children.
                                892                 :                :  *
                                893                 :                :  * If a VacuumRelation does not have an OID supplied and is a partitioned
                                894                 :                :  * table, an extra entry will be added to the output for each partition.
                                895                 :                :  * Presently, only autovacuum supplies OIDs when calling vacuum(), and
                                896                 :                :  * it does not want us to expand partitioned tables.
                                897                 :                :  *
                                898                 :                :  * We take care not to modify the input data structure, but instead build
                                899                 :                :  * new VacuumRelation(s) to return.  (But note that they will reference
                                900                 :                :  * unmodified parts of the input, eg column lists.)  New data structures
                                901                 :                :  * are made in vac_context.
                                902                 :                :  */
                                903                 :                : static List *
 1242 drowley@postgresql.o      904                 :           9448 : expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
                                905                 :                :                   int options)
                                906                 :                : {
 3250 tgl@sss.pgh.pa.us         907                 :           9448 :     List       *vacrels = NIL;
                                908                 :                :     MemoryContext oldcontext;
                                909                 :                : 
                                910                 :                :     /* If caller supplied OID, there's nothing we need do here. */
                                911         [ +  + ]:           9448 :     if (OidIsValid(vrel->oid))
                                912                 :                :     {
 6657 alvherre@alvh.no-ip.      913                 :            869 :         oldcontext = MemoryContextSwitchTo(vac_context);
 3250 tgl@sss.pgh.pa.us         914                 :            869 :         vacrels = lappend(vacrels, vrel);
 6657 alvherre@alvh.no-ip.      915                 :            869 :         MemoryContextSwitchTo(oldcontext);
                                916                 :                :     }
                                917                 :                :     else
                                918                 :                :     {
                                919                 :                :         /*
                                920                 :                :          * Process a specific relation, and possibly partitions or child
                                921                 :                :          * tables thereof.
                                922                 :                :          */
                                923                 :                :         Oid         relid;
                                924                 :                :         HeapTuple   tuple;
                                925                 :                :         Form_pg_class classForm;
                                926                 :                :         bool        include_children;
                                927                 :                :         bool        is_partitioned_table;
                                928                 :                :         int         rvr_opts;
                                929                 :                : 
                                930                 :                :         /*
                                931                 :                :          * Since autovacuum workers supply OIDs when calling vacuum(), no
                                932                 :                :          * autovacuum worker should reach this code.
                                933                 :                :          */
  906 heikki.linnakangas@i      934         [ -  + ]:           8579 :         Assert(!AmAutoVacuumWorkerProcess());
                                935                 :                : 
                                936                 :                :         /*
                                937                 :                :          * We transiently take AccessShareLock to protect the syscache lookup
                                938                 :                :          * below, as well as find_all_inheritors's expectation that the caller
                                939                 :                :          * holds some lock on the starting relation.
                                940                 :                :          */
 2884 michael@paquier.xyz       941                 :           8579 :         rvr_opts = (options & VACOPT_SKIP_LOCKED) ? RVR_SKIP_LOCKED : 0;
                                942                 :           8579 :         relid = RangeVarGetRelidExtended(vrel->relation,
                                943                 :                :                                          AccessShareLock,
                                944                 :                :                                          rvr_opts,
                                945                 :                :                                          NULL, NULL);
                                946                 :                : 
                                947                 :                :         /*
                                948                 :                :          * If the lock is unavailable, emit the same log statement that
                                949                 :                :          * vacuum_rel() and analyze_rel() would.
                                950                 :                :          */
                                951         [ +  + ]:           8555 :         if (!OidIsValid(relid))
                                952                 :                :         {
                                953         [ +  + ]:              4 :             if (options & VACOPT_VACUUM)
                                954         [ +  - ]:              3 :                 ereport(WARNING,
                                955                 :                :                         (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                956                 :                :                          errmsg("skipping vacuum of \"%s\" --- lock not available",
                                957                 :                :                                 vrel->relation->relname)));
                                958                 :                :             else
                                959         [ +  - ]:              1 :                 ereport(WARNING,
                                960                 :                :                         (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                961                 :                :                          errmsg("skipping analyze of \"%s\" --- lock not available",
                                962                 :                :                                 vrel->relation->relname)));
                                963                 :              4 :             return vacrels;
                                964                 :                :         }
                                965                 :                : 
                                966                 :                :         /*
                                967                 :                :          * To check whether the relation is a partitioned table and its
                                968                 :                :          * ownership, fetch its syscache entry.
                                969                 :                :          */
 3465 rhaas@postgresql.org      970                 :           8551 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
                                971         [ -  + ]:           8551 :         if (!HeapTupleIsValid(tuple))
 3465 rhaas@postgresql.org      972         [ #  # ]:UBC           0 :             elog(ERROR, "cache lookup failed for relation %u", relid);
 3465 rhaas@postgresql.org      973                 :CBC        8551 :         classForm = (Form_pg_class) GETSTRUCT(tuple);
                                974                 :                : 
                                975                 :                :         /*
                                976                 :                :          * Make a returnable VacuumRelation for this rel if the user has the
                                977                 :                :          * required privileges.
                                978                 :                :          */
   24 nathan@postgresql.or      979         [ +  + ]:GNC        8551 :         if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
                                980                 :                :         {
 2922 michael@paquier.xyz       981                 :CBC        8399 :             oldcontext = MemoryContextSwitchTo(vac_context);
                                982                 :           8399 :             vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
                                983                 :                :                                                           relid,
                                984                 :                :                                                           vrel->va_cols));
                                985                 :           8399 :             MemoryContextSwitchTo(oldcontext);
                                986                 :                :         }
                                987                 :                : 
                                988                 :                :         /*
                                989                 :                :          * Vacuuming a partitioned table with ONLY will not do anything since
                                990                 :                :          * the partitioned table itself is empty.  Issue a warning if the user
                                991                 :                :          * requests this.
                                992                 :                :          */
  702 drowley@postgresql.o      993                 :           8551 :         include_children = vrel->relation->inh;
                                994                 :           8551 :         is_partitioned_table = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
                                995   [ +  +  +  +  :           8551 :         if ((options & VACOPT_VACUUM) && is_partitioned_table && !include_children)
                                              +  + ]
                                996         [ +  - ]:              4 :             ereport(WARNING,
                                997                 :                :                     (errmsg("VACUUM ONLY of partitioned table \"%s\" has no effect",
                                998                 :                :                             vrel->relation->relname)));
                                999                 :                : 
 3465 rhaas@postgresql.org     1000                 :           8551 :         ReleaseSysCache(tuple);
                               1001                 :                : 
                               1002                 :                :         /*
                               1003                 :                :          * Unless the user has specified ONLY, make relation list entries for
                               1004                 :                :          * its partitions or inheritance child tables.  Note that the list
                               1005                 :                :          * returned by find_all_inheritors() includes the passed-in OID, so we
                               1006                 :                :          * have to skip that.  There's no point in taking locks on the
                               1007                 :                :          * individual partitions or child tables yet, and doing so would just
                               1008                 :                :          * add unnecessary deadlock risk.  For this last reason, we do not yet
                               1009                 :                :          * check the ownership of the partitions/tables, which get added to
                               1010                 :                :          * the list to process.  Ownership will be checked later on anyway.
                               1011                 :                :          */
  702 drowley@postgresql.o     1012         [ +  + ]:           8551 :         if (include_children)
                               1013                 :                :         {
 3250 tgl@sss.pgh.pa.us        1014                 :           8523 :             List       *part_oids = find_all_inheritors(relid, NoLock, NULL);
                               1015                 :                :             ListCell   *part_lc;
                               1016                 :                : 
                               1017   [ +  -  +  +  :          18501 :             foreach(part_lc, part_oids)
                                              +  + ]
                               1018                 :                :             {
                               1019                 :           9978 :                 Oid         part_oid = lfirst_oid(part_lc);
                               1020                 :                : 
                               1021         [ +  + ]:           9978 :                 if (part_oid == relid)
                               1022                 :           8523 :                     continue;   /* ignore original table */
                               1023                 :                : 
                               1024                 :                :                 /*
                               1025                 :                :                  * We omit a RangeVar since it wouldn't be appropriate to
                               1026                 :                :                  * complain about failure to open one of these relations
                               1027                 :                :                  * later.
                               1028                 :                :                  */
                               1029                 :           1455 :                 oldcontext = MemoryContextSwitchTo(vac_context);
                               1030                 :           1455 :                 vacrels = lappend(vacrels, makeVacuumRelation(NULL,
                               1031                 :                :                                                               part_oid,
                               1032                 :                :                                                               vrel->va_cols));
                               1033                 :           1455 :                 MemoryContextSwitchTo(oldcontext);
                               1034                 :                :             }
                               1035                 :                :         }
                               1036                 :                : 
                               1037                 :                :         /*
                               1038                 :                :          * Release lock again.  This means that by the time we actually try to
                               1039                 :                :          * process the table, it might be gone or renamed.  In the former case
                               1040                 :                :          * we'll silently ignore it; in the latter case we'll process it
                               1041                 :                :          * anyway, but we must beware that the RangeVar doesn't necessarily
                               1042                 :                :          * identify it anymore.  This isn't ideal, perhaps, but there's little
                               1043                 :                :          * practical alternative, since we're typically going to commit this
                               1044                 :                :          * transaction and begin a new one between now and then.  Moreover,
                               1045                 :                :          * holding locks on multiple relations would create significant risk
                               1046                 :                :          * of deadlock.
                               1047                 :                :          */
 3254                          1048                 :           8551 :         UnlockRelationOid(relid, AccessShareLock);
                               1049                 :                :     }
                               1050                 :                : 
 3250                          1051                 :           9420 :     return vacrels;
                               1052                 :                : }
                               1053                 :                : 
                               1054                 :                : /*
                               1055                 :                :  * Construct a list of VacuumRelations for all vacuumable rels in
                               1056                 :                :  * the current database.  The list is built in vac_context.
                               1057                 :                :  */
                               1058                 :                : static List *
 1242 drowley@postgresql.o     1059                 :            120 : get_all_vacuum_rels(MemoryContext vac_context, int options)
                               1060                 :                : {
 3250 tgl@sss.pgh.pa.us        1061                 :            120 :     List       *vacrels = NIL;
                               1062                 :                :     Relation    pgclass;
                               1063                 :                :     TableScanDesc scan;
                               1064                 :                :     HeapTuple   tuple;
                               1065                 :                : 
 2775 andres@anarazel.de       1066                 :            120 :     pgclass = table_open(RelationRelationId, AccessShareLock);
                               1067                 :                : 
 2726                          1068                 :            120 :     scan = table_beginscan_catalog(pgclass, 0, NULL);
                               1069                 :                : 
 3250 tgl@sss.pgh.pa.us        1070         [ +  + ]:          60130 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
                               1071                 :                :     {
                               1072                 :          60010 :         Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
                               1073                 :                :         MemoryContext oldcontext;
 2837 andres@anarazel.de       1074                 :          60010 :         Oid         relid = classForm->oid;
                               1075                 :                : 
                               1076                 :                :         /*
                               1077                 :                :          * We include partitioned tables here; depending on which operation is
                               1078                 :                :          * to be performed, caller will decide whether to process or ignore
                               1079                 :                :          * them.
                               1080                 :                :          */
 3250 tgl@sss.pgh.pa.us        1081         [ +  + ]:          60010 :         if (classForm->relkind != RELKIND_RELATION &&
                               1082         [ +  + ]:          48983 :             classForm->relkind != RELKIND_MATVIEW &&
                               1083         [ +  + ]:          48951 :             classForm->relkind != RELKIND_PARTITIONED_TABLE)
                               1084                 :          48838 :             continue;
                               1085                 :                : 
                               1086                 :                :         /* Skip temp relations belonging to other sessions */
  114 alvherre@kurilemu.de     1087         [ +  + ]:          11172 :         if (classForm->relpersistence == RELPERSISTENCE_TEMP &&
                               1088         [ +  + ]:              9 :             !isTempOrTempToastNamespace(classForm->relnamespace))
                               1089                 :              1 :             continue;
                               1090                 :                : 
                               1091                 :                :         /* check permissions of relation */
   24 nathan@postgresql.or     1092         [ +  + ]:GNC       11171 :         if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 1322 jdavis@postgresql.or     1093                 :CBC        1956 :             continue;
                               1094                 :                : 
                               1095                 :                :         /*
                               1096                 :                :          * Build VacuumRelation(s) specifying the table OIDs to be processed.
                               1097                 :                :          * We omit a RangeVar since it wouldn't be appropriate to complain
                               1098                 :                :          * about failure to open one of these relations later.
                               1099                 :                :          */
 3250 tgl@sss.pgh.pa.us        1100                 :           9215 :         oldcontext = MemoryContextSwitchTo(vac_context);
                               1101                 :           9215 :         vacrels = lappend(vacrels, makeVacuumRelation(NULL,
                               1102                 :                :                                                       relid,
                               1103                 :                :                                                       NIL));
                               1104                 :           9215 :         MemoryContextSwitchTo(oldcontext);
                               1105                 :                :     }
                               1106                 :                : 
 2726 andres@anarazel.de       1107                 :            120 :     table_endscan(scan);
 2775                          1108                 :            120 :     table_close(pgclass, AccessShareLock);
                               1109                 :                : 
 3250 tgl@sss.pgh.pa.us        1110                 :            120 :     return vacrels;
                               1111                 :                : }
                               1112                 :                : 
                               1113                 :                : /*
                               1114                 :                :  * vacuum_get_cutoffs() -- compute OldestXmin and freeze cutoff points
                               1115                 :                :  *
                               1116                 :                :  * The target relation and VACUUM parameters are our inputs.
                               1117                 :                :  *
                               1118                 :                :  * Output parameters are the cutoffs that VACUUM caller should use.
                               1119                 :                :  *
                               1120                 :                :  * Return value indicates if vacuumlazy.c caller should make its VACUUM
                               1121                 :                :  * operation aggressive.  An aggressive VACUUM must advance relfrozenxid up to
                               1122                 :                :  * FreezeLimit (at a minimum), and relminmxid up to MultiXactCutoff (at a
                               1123                 :                :  * minimum).
                               1124                 :                :  */
                               1125                 :                : bool
  149 nathan@postgresql.or     1126                 :          16734 : vacuum_get_cutoffs(Relation rel, const VacuumParams *params,
                               1127                 :                :                    struct VacuumCutoffs *cutoffs)
                               1128                 :                : {
                               1129                 :                :     int         freeze_min_age,
                               1130                 :                :                 multixact_freeze_min_age,
                               1131                 :                :                 freeze_table_age,
                               1132                 :                :                 multixact_freeze_table_age,
                               1133                 :                :                 effective_multixact_freeze_max_age;
                               1134                 :                :     TransactionId nextXID,
                               1135                 :                :                 safeOldestXmin,
                               1136                 :                :                 aggressiveXIDCutoff;
                               1137                 :                :     MultiXactId nextMXID,
                               1138                 :                :                 safeOldestMxact,
                               1139                 :                :                 aggressiveMXIDCutoff;
                               1140                 :                : 
                               1141                 :                :     /* Use mutable copies of freeze age parameters */
                               1142                 :          16734 :     freeze_min_age = params->freeze_min_age;
                               1143                 :          16734 :     multixact_freeze_min_age = params->multixact_freeze_min_age;
                               1144                 :          16734 :     freeze_table_age = params->freeze_table_age;
                               1145                 :          16734 :     multixact_freeze_table_age = params->multixact_freeze_table_age;
                               1146                 :                : 
                               1147                 :                :     /* Set pg_class fields in cutoffs */
 1344 pg@bowt.ie               1148                 :          16734 :     cutoffs->relfrozenxid = rel->rd_rel->relfrozenxid;
                               1149                 :          16734 :     cutoffs->relminmxid = rel->rd_rel->relminmxid;
                               1150                 :                : 
                               1151                 :                :     /*
                               1152                 :                :      * Acquire OldestXmin.
                               1153                 :                :      *
                               1154                 :                :      * We can always ignore processes running lazy vacuum.  This is because we
                               1155                 :                :      * use these values only for deciding which tuples we must keep in the
                               1156                 :                :      * tables.  Since lazy vacuum doesn't write its XID anywhere (usually no
                               1157                 :                :      * XID assigned), it's safe to ignore it.  In theory it could be
                               1158                 :                :      * problematic to ignore lazy vacuums in a full vacuum, but keep in mind
                               1159                 :                :      * that only one vacuum process can be working on a particular table at
                               1160                 :                :      * any time, and that each vacuum is always an independent transaction.
                               1161                 :                :      */
                               1162                 :          16734 :     cutoffs->OldestXmin = GetOldestNonRemovableTransactionId(rel);
                               1163                 :                : 
                               1164         [ -  + ]:          16734 :     Assert(TransactionIdIsNormal(cutoffs->OldestXmin));
                               1165                 :                : 
                               1166                 :                :     /* Acquire OldestMxact */
                               1167                 :          16734 :     cutoffs->OldestMxact = GetOldestMultiXactId();
                               1168         [ -  + ]:          16734 :     Assert(MultiXactIdIsValid(cutoffs->OldestMxact));
                               1169                 :                : 
                               1170                 :                :     /* Acquire next XID/next MXID values used to apply age-based settings */
 1457                          1171                 :          16734 :     nextXID = ReadNextTransactionId();
                               1172                 :          16734 :     nextMXID = ReadNextMultiXactId();
                               1173                 :                : 
                               1174                 :                :     /*
                               1175                 :                :      * Also compute the multixact age for which freezing is urgent.  This is
                               1176                 :                :      * normally autovacuum_multixact_freeze_max_age, but may be less if
                               1177                 :                :      * multixact members are bloated.
                               1178                 :                :      */
 1344                          1179                 :          16734 :     effective_multixact_freeze_max_age = MultiXactMemberFreezeThreshold();
                               1180                 :                : 
                               1181                 :                :     /*
                               1182                 :                :      * Almost ready to set freeze output parameters; check if OldestXmin or
                               1183                 :                :      * OldestMxact are held back to an unsafe degree before we start on that
                               1184                 :                :      */
                               1185                 :          16734 :     safeOldestXmin = nextXID - autovacuum_freeze_max_age;
                               1186         [ -  + ]:          16734 :     if (!TransactionIdIsNormal(safeOldestXmin))
 1344 pg@bowt.ie               1187                 :UBC           0 :         safeOldestXmin = FirstNormalTransactionId;
 1344 pg@bowt.ie               1188                 :CBC       16734 :     safeOldestMxact = nextMXID - effective_multixact_freeze_max_age;
                               1189         [ -  + ]:          16734 :     if (safeOldestMxact < FirstMultiXactId)
 1344 pg@bowt.ie               1190                 :UBC           0 :         safeOldestMxact = FirstMultiXactId;
 1344 pg@bowt.ie               1191         [ -  + ]:CBC       16734 :     if (TransactionIdPrecedes(cutoffs->OldestXmin, safeOldestXmin))
 1344 pg@bowt.ie               1192         [ #  # ]:UBC           0 :         ereport(WARNING,
                               1193                 :                :                 (errmsg("cutoff for removing and freezing tuples is far in the past"),
                               1194                 :                :                  errhint("Close open transactions soon to avoid wraparound problems.\n"
                               1195                 :                :                          "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
 1344 pg@bowt.ie               1196         [ -  + ]:CBC       16734 :     if (MultiXactIdPrecedes(cutoffs->OldestMxact, safeOldestMxact))
 1344 pg@bowt.ie               1197         [ #  # ]:UBC           0 :         ereport(WARNING,
                               1198                 :                :                 (errmsg("cutoff for freezing multixacts is far in the past"),
                               1199                 :                :                  errhint("Close open transactions soon to avoid wraparound problems.\n"
                               1200                 :                :                          "You might also need to commit or roll back old prepared transactions.")));
                               1201                 :                : 
                               1202                 :                :     /*
                               1203                 :                :      * Determine the minimum freeze age to use: as specified by the caller, or
                               1204                 :                :      * vacuum_freeze_min_age, but in any case not more than half
                               1205                 :                :      * autovacuum_freeze_max_age, so that autovacuums to prevent XID
                               1206                 :                :      * wraparound won't occur too frequently.
                               1207                 :                :      */
 1457 pg@bowt.ie               1208         [ +  + ]:CBC       16734 :     if (freeze_min_age < 0)
                               1209                 :           6831 :         freeze_min_age = vacuum_freeze_min_age;
                               1210                 :          16734 :     freeze_min_age = Min(freeze_min_age, autovacuum_freeze_max_age / 2);
                               1211         [ -  + ]:          16734 :     Assert(freeze_min_age >= 0);
                               1212                 :                : 
                               1213                 :                :     /* Compute FreezeLimit, being careful to generate a normal XID */
 1344                          1214                 :          16734 :     cutoffs->FreezeLimit = nextXID - freeze_min_age;
                               1215         [ -  + ]:          16734 :     if (!TransactionIdIsNormal(cutoffs->FreezeLimit))
 1344 pg@bowt.ie               1216                 :UBC           0 :         cutoffs->FreezeLimit = FirstNormalTransactionId;
                               1217                 :                :     /* FreezeLimit must always be <= OldestXmin */
 1344 pg@bowt.ie               1218         [ +  + ]:CBC       16734 :     if (TransactionIdPrecedes(cutoffs->OldestXmin, cutoffs->FreezeLimit))
                               1219                 :            611 :         cutoffs->FreezeLimit = cutoffs->OldestXmin;
                               1220                 :                : 
                               1221                 :                :     /*
                               1222                 :                :      * Determine the minimum multixact freeze age to use: as specified by
                               1223                 :                :      * caller, or vacuum_multixact_freeze_min_age, but in any case not more
                               1224                 :                :      * than half effective_multixact_freeze_max_age, so that autovacuums to
                               1225                 :                :      * prevent MultiXact wraparound won't occur too frequently.
                               1226                 :                :      */
 1457                          1227         [ +  + ]:          16734 :     if (multixact_freeze_min_age < 0)
                               1228                 :           6831 :         multixact_freeze_min_age = vacuum_multixact_freeze_min_age;
                               1229                 :          16734 :     multixact_freeze_min_age = Min(multixact_freeze_min_age,
                               1230                 :                :                                    effective_multixact_freeze_max_age / 2);
                               1231         [ -  + ]:          16734 :     Assert(multixact_freeze_min_age >= 0);
                               1232                 :                : 
                               1233                 :                :     /* Compute MultiXactCutoff, being careful to generate a valid value */
 1344                          1234                 :          16734 :     cutoffs->MultiXactCutoff = nextMXID - multixact_freeze_min_age;
                               1235         [ -  + ]:          16734 :     if (cutoffs->MultiXactCutoff < FirstMultiXactId)
 1344 pg@bowt.ie               1236                 :UBC           0 :         cutoffs->MultiXactCutoff = FirstMultiXactId;
                               1237                 :                :     /* MultiXactCutoff must always be <= OldestMxact */
 1344 pg@bowt.ie               1238         [ +  + ]:CBC       16734 :     if (MultiXactIdPrecedes(cutoffs->OldestMxact, cutoffs->MultiXactCutoff))
                               1239                 :              2 :         cutoffs->MultiXactCutoff = cutoffs->OldestMxact;
                               1240                 :                : 
                               1241                 :                :     /*
                               1242                 :                :      * Finally, figure out if caller needs to do an aggressive VACUUM or not.
                               1243                 :                :      *
                               1244                 :                :      * Determine the table freeze age to use: as specified by the caller, or
                               1245                 :                :      * the value of the vacuum_freeze_table_age GUC, but in any case not more
                               1246                 :                :      * than autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly
                               1247                 :                :      * VACUUM schedule, the nightly VACUUM gets a chance to freeze XIDs before
                               1248                 :                :      * anti-wraparound autovacuum is launched.
                               1249                 :                :      */
 1457                          1250         [ +  + ]:          16734 :     if (freeze_table_age < 0)
                               1251                 :           6831 :         freeze_table_age = vacuum_freeze_table_age;
                               1252         [ +  - ]:          16734 :     freeze_table_age = Min(freeze_table_age, autovacuum_freeze_max_age * 0.95);
                               1253         [ -  + ]:          16734 :     Assert(freeze_table_age >= 0);
                               1254                 :          16734 :     aggressiveXIDCutoff = nextXID - freeze_table_age;
                               1255         [ -  + ]:          16734 :     if (!TransactionIdIsNormal(aggressiveXIDCutoff))
 1457 pg@bowt.ie               1256                 :UBC           0 :         aggressiveXIDCutoff = FirstNormalTransactionId;
  850 noah@leadboat.com        1257         [ +  + ]:CBC       16734 :     if (TransactionIdPrecedesOrEquals(cutoffs->relfrozenxid,
                               1258                 :                :                                       aggressiveXIDCutoff))
 1658 pg@bowt.ie               1259                 :           9460 :         return true;
                               1260                 :                : 
                               1261                 :                :     /*
                               1262                 :                :      * Similar to the above, determine the table freeze age to use for
                               1263                 :                :      * multixacts: as specified by the caller, or the value of the
                               1264                 :                :      * vacuum_multixact_freeze_table_age GUC, but in any case not more than
                               1265                 :                :      * effective_multixact_freeze_max_age * 0.95, so that if you have e.g.
                               1266                 :                :      * nightly VACUUM schedule, the nightly VACUUM gets a chance to freeze
                               1267                 :                :      * multixacts before anti-wraparound autovacuum is launched.
                               1268                 :                :      */
 1457                          1269         [ +  + ]:           7274 :     if (multixact_freeze_table_age < 0)
                               1270                 :           6831 :         multixact_freeze_table_age = vacuum_multixact_freeze_table_age;
                               1271                 :           7274 :     multixact_freeze_table_age =
                               1272         [ +  - ]:           7274 :         Min(multixact_freeze_table_age,
                               1273                 :                :             effective_multixact_freeze_max_age * 0.95);
                               1274         [ -  + ]:           7274 :     Assert(multixact_freeze_table_age >= 0);
                               1275                 :           7274 :     aggressiveMXIDCutoff = nextMXID - multixact_freeze_table_age;
                               1276         [ -  + ]:           7274 :     if (aggressiveMXIDCutoff < FirstMultiXactId)
 1457 pg@bowt.ie               1277                 :UBC           0 :         aggressiveMXIDCutoff = FirstMultiXactId;
  850 noah@leadboat.com        1278         [ -  + ]:CBC        7274 :     if (MultiXactIdPrecedesOrEquals(cutoffs->relminmxid,
                               1279                 :                :                                     aggressiveMXIDCutoff))
 1658 pg@bowt.ie               1280                 :UBC           0 :         return true;
                               1281                 :                : 
                               1282                 :                :     /* Non-aggressive VACUUM */
 1658 pg@bowt.ie               1283                 :CBC        7274 :     return false;
                               1284                 :                : }
                               1285                 :                : 
                               1286                 :                : /*
                               1287                 :                :  * vacuum_xid_failsafe_check() -- Used by VACUUM's wraparound failsafe
                               1288                 :                :  * mechanism to determine if its table's relfrozenxid and relminmxid are now
                               1289                 :                :  * dangerously far in the past.
                               1290                 :                :  *
                               1291                 :                :  * When we return true, VACUUM caller triggers the failsafe.
                               1292                 :                :  */
                               1293                 :                : bool
 1344                          1294                 :          19419 : vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs)
                               1295                 :                : {
                               1296                 :          19419 :     TransactionId relfrozenxid = cutoffs->relfrozenxid;
                               1297                 :          19419 :     MultiXactId relminmxid = cutoffs->relminmxid;
                               1298                 :                :     TransactionId xid_skip_limit;
                               1299                 :                :     MultiXactId multi_skip_limit;
                               1300                 :                :     int         skip_index_vacuum;
                               1301                 :                : 
 1968                          1302         [ -  + ]:          19419 :     Assert(TransactionIdIsNormal(relfrozenxid));
                               1303         [ -  + ]:          19419 :     Assert(MultiXactIdIsValid(relminmxid));
                               1304                 :                : 
                               1305                 :                :     /*
                               1306                 :                :      * Determine the index skipping age to use. In any case no less than
                               1307                 :                :      * autovacuum_freeze_max_age * 1.05.
                               1308                 :                :      */
                               1309         [ +  - ]:          19419 :     skip_index_vacuum = Max(vacuum_failsafe_age, autovacuum_freeze_max_age * 1.05);
                               1310                 :                : 
                               1311                 :          19419 :     xid_skip_limit = ReadNextTransactionId() - skip_index_vacuum;
                               1312         [ -  + ]:          19419 :     if (!TransactionIdIsNormal(xid_skip_limit))
 1968 pg@bowt.ie               1313                 :UBC           0 :         xid_skip_limit = FirstNormalTransactionId;
                               1314                 :                : 
 1968 pg@bowt.ie               1315         [ -  + ]:CBC       19419 :     if (TransactionIdPrecedes(relfrozenxid, xid_skip_limit))
                               1316                 :                :     {
                               1317                 :                :         /* The table's relfrozenxid is too old */
 1968 pg@bowt.ie               1318                 :UBC           0 :         return true;
                               1319                 :                :     }
                               1320                 :                : 
                               1321                 :                :     /*
                               1322                 :                :      * Similar to above, determine the index skipping age to use for
                               1323                 :                :      * multixact. In any case no less than autovacuum_multixact_freeze_max_age *
                               1324                 :                :      * 1.05.
                               1325                 :                :      */
 1968 pg@bowt.ie               1326         [ +  - ]:CBC       19419 :     skip_index_vacuum = Max(vacuum_multixact_failsafe_age,
                               1327                 :                :                             autovacuum_multixact_freeze_max_age * 1.05);
                               1328                 :                : 
                               1329                 :          19419 :     multi_skip_limit = ReadNextMultiXactId() - skip_index_vacuum;
                               1330         [ -  + ]:          19419 :     if (multi_skip_limit < FirstMultiXactId)
 1968 pg@bowt.ie               1331                 :UBC           0 :         multi_skip_limit = FirstMultiXactId;
                               1332                 :                : 
 1968 pg@bowt.ie               1333         [ -  + ]:CBC       19419 :     if (MultiXactIdPrecedes(relminmxid, multi_skip_limit))
                               1334                 :                :     {
                               1335                 :                :         /* The table's relminmxid is too old */
 1968 pg@bowt.ie               1336                 :UBC           0 :         return true;
                               1337                 :                :     }
                               1338                 :                : 
 1968 pg@bowt.ie               1339                 :CBC       19419 :     return false;
                               1340                 :                : }
                               1341                 :                : 
                               1342                 :                : /*
                               1343                 :                :  * vac_estimate_reltuples() -- estimate the new value for pg_class.reltuples
                               1344                 :                :  *
                               1345                 :                :  *      If we scanned the whole relation then we should just use the count of
                               1346                 :                :  *      live tuples seen; but if we did not, we should not blindly extrapolate
                               1347                 :                :  *      from that number, since VACUUM may have scanned a quite nonrandom
                               1348                 :                :  *      subset of the table.  When we have only partial information, we take
                               1349                 :                :  *      the old value of pg_class.reltuples/pg_class.relpages as a measurement
                               1350                 :                :  *      of the tuple density in the unscanned pages.
                               1351                 :                :  *
                               1352                 :                :  *      Note: scanned_tuples should count only *live* tuples, since
                               1353                 :                :  *      pg_class.reltuples is defined that way.
                               1354                 :                :  */
                               1355                 :                : double
 3089 tgl@sss.pgh.pa.us        1356                 :          16327 : vac_estimate_reltuples(Relation relation,
                               1357                 :                :                        BlockNumber total_pages,
                               1358                 :                :                        BlockNumber scanned_pages,
                               1359                 :                :                        double scanned_tuples)
                               1360                 :                : {
 5558 bruce@momjian.us         1361                 :          16327 :     BlockNumber old_rel_pages = relation->rd_rel->relpages;
 5568 tgl@sss.pgh.pa.us        1362                 :          16327 :     double      old_rel_tuples = relation->rd_rel->reltuples;
                               1363                 :                :     double      old_density;
                               1364                 :                :     double      unscanned_pages;
                               1365                 :                :     double      total_tuples;
                               1366                 :                : 
                               1367                 :                :     /* If we did scan the whole table, just use the count as-is */
                               1368         [ +  + ]:          16327 :     if (scanned_pages >= total_pages)
                               1369                 :          15944 :         return scanned_tuples;
                               1370                 :                : 
                               1371                 :                :     /*
                               1372                 :                :      * When successive VACUUM commands scan the same few pages again and
                               1373                 :                :      * again, without anything from the table really changing, there is a risk
                               1374                 :                :      * that our beliefs about tuple density will gradually become distorted.
                               1375                 :                :      * This might be caused by vacuumlazy.c implementation details, such as
                               1376                 :                :      * its tendency to always scan the last heap page.  Handle that here.
                               1377                 :                :      *
                               1378                 :                :      * If the relation is _exactly_ the same size according to the existing
                               1379                 :                :      * pg_class entry, and only a few of its pages (less than 2%) were
                               1380                 :                :      * scanned, keep the existing value of reltuples.  Also keep the existing
                               1381                 :                :      * value when only a subset of rel's pages <= a single page were scanned.
                               1382                 :                :      *
                               1383                 :                :      * (Note: we might be returning -1 here.)
                               1384                 :                :      */
 1653 pg@bowt.ie               1385         [ +  + ]:            383 :     if (old_rel_pages == total_pages &&
                               1386         [ +  + ]:            349 :         scanned_pages < (double) total_pages * 0.02)
                               1387                 :            203 :         return old_rel_tuples;
 1469                          1388         [ +  + ]:            180 :     if (scanned_pages <= 1)
                               1389                 :            101 :         return old_rel_tuples;
                               1390                 :                : 
                               1391                 :                :     /*
                               1392                 :                :      * If old density is unknown, we can't do much except scale up
                               1393                 :                :      * scanned_tuples to match total_pages.
                               1394                 :                :      */
 2188 tgl@sss.pgh.pa.us        1395   [ +  +  -  + ]:             79 :     if (old_rel_tuples < 0 || old_rel_pages == 0)
 5568                          1396                 :              5 :         return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
                               1397                 :                : 
                               1398                 :                :     /*
                               1399                 :                :      * Okay, we've covered the corner cases.  The normal calculation is to
                               1400                 :                :      * convert the old measurement to a density (tuples per page), then
                               1401                 :                :      * estimate the number of tuples in the unscanned pages using that figure,
                               1402                 :                :      * and finally add on the number of tuples in the scanned pages.
                               1403                 :                :      */
                               1404                 :             74 :     old_density = old_rel_tuples / old_rel_pages;
 3089                          1405                 :             74 :     unscanned_pages = (double) total_pages - (double) scanned_pages;
                               1406                 :             74 :     total_tuples = old_density * unscanned_pages + scanned_tuples;
                               1407                 :             74 :     return floor(total_tuples + 0.5);
                               1408                 :                : }
                               1409                 :                : 
                               1410                 :                : 
                               1411                 :                : /*
                               1412                 :                :  *  vac_update_relstats() -- update statistics for one relation
                               1413                 :                :  *
                               1414                 :                :  *      Update the whole-relation statistics that are kept in its pg_class
                               1415                 :                :  *      row.  There are additional stats that will be updated if we are
                               1416                 :                :  *      doing ANALYZE, but we always update these stats.  This routine works
                               1417                 :                :  *      for both index and heap relation entries in pg_class.
                               1418                 :                :  *
                               1419                 :                :  *      We violate transaction semantics here by overwriting the rel's
                               1420                 :                :  *      existing pg_class tuple with the new values.  This is reasonably
                               1421                 :                :  *      safe as long as we're sure that the new values are correct whether or
                               1422                 :                :  *      not this transaction commits.  The reason for doing this is that if
                               1423                 :                :  *      we updated these tuples in the usual way, vacuuming pg_class itself
                               1424                 :                :  *      wouldn't work very well --- by the time we got done with a vacuum
                               1425                 :                :  *      cycle, most of the tuples in pg_class would've been obsoleted.  Of
                               1426                 :                :  *      course, this only works for fixed-size not-null columns, but these are.
                               1427                 :                :  *
                               1428                 :                :  *      Another reason for doing it this way is that when we are in a lazy
                               1429                 :                :  *      VACUUM and have PROC_IN_VACUUM set, we mustn't do any regular updates.
                               1430                 :                :  *      Somebody vacuuming pg_class might think they could delete a tuple
                               1431                 :                :  *      marked with xmin = our xid.
                               1432                 :                :  *
                               1433                 :                :  *      In addition to fundamentally nontransactional statistics such as
                               1434                 :                :  *      relpages and relallvisible, we try to maintain certain lazily-updated
                               1435                 :                :  *      DDL flags such as relhasindex, by clearing them if no longer correct.
                               1436                 :                :  *      It's safe to do this in VACUUM, which can't run in parallel with
                               1437                 :                :  *      CREATE INDEX/RULE/TRIGGER and can't be part of a transaction block.
                               1438                 :                :  *      However, it's *not* safe to do it in an ANALYZE that's within an
                               1439                 :                :  *      outer transaction, because for example the current transaction might
                               1440                 :                :  *      have dropped the last index; then we'd think relhasindex should be
                               1441                 :                :  *      cleared, but if the transaction later rolls back this would be wrong.
                               1442                 :                :  *      So we refrain from updating the DDL flags if we're inside an outer
                               1443                 :                :  *      transaction.  This is OK since postponing the flag maintenance is
                               1444                 :                :  *      always allowable.
                               1445                 :                :  *
                               1446                 :                :  *      Note: num_tuples should count only *live* tuples, since
                               1447                 :                :  *      pg_class.reltuples is defined that way.
                               1448                 :                :  *
                               1449                 :                :  *      This routine is shared by VACUUM and ANALYZE.
                               1450                 :                :  */
                               1451                 :                : void
 6499                          1452                 :          44206 : vac_update_relstats(Relation relation,
                               1453                 :                :                     BlockNumber num_pages, double num_tuples,
                               1454                 :                :                     BlockNumber num_all_visible_pages,
                               1455                 :                :                     BlockNumber num_all_frozen_pages,
                               1456                 :                :                     bool hasindex, TransactionId frozenxid,
                               1457                 :                :                     MultiXactId minmulti,
                               1458                 :                :                     bool *frozenxid_updated, bool *minmulti_updated,
                               1459                 :                :                     bool in_outer_xact)
                               1460                 :                : {
                               1461                 :          44206 :     Oid         relid = RelationGetRelid(relation);
                               1462                 :                :     Relation    rd;
                               1463                 :                :     ScanKeyData key[1];
                               1464                 :                :     HeapTuple   ctup;
                               1465                 :                :     void       *inplace_state;
                               1466                 :                :     Form_pg_class pgcform;
                               1467                 :                :     bool        dirty,
                               1468                 :                :                 futurexid,
                               1469                 :                :                 futuremxid;
                               1470                 :                :     TransactionId oldfrozenxid;
                               1471                 :                :     MultiXactId oldminmulti;
                               1472                 :                : 
 2775 andres@anarazel.de       1473                 :          44206 :     rd = table_open(RelationRelationId, RowExclusiveLock);
                               1474                 :                : 
                               1475                 :                :     /* Fetch a copy of the tuple to scribble on */
  702 noah@leadboat.com        1476                 :          44206 :     ScanKeyInit(&key[0],
                               1477                 :                :                 Anum_pg_class_oid,
                               1478                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                               1479                 :                :                 ObjectIdGetDatum(relid));
                               1480                 :          44206 :     systable_inplace_update_begin(rd, ClassOidIndexId, true,
                               1481                 :                :                                   NULL, 1, key, &ctup, &inplace_state);
 9177 tgl@sss.pgh.pa.us        1482         [ -  + ]:          44206 :     if (!HeapTupleIsValid(ctup))
 9177 tgl@sss.pgh.pa.us        1483         [ #  # ]:UBC           0 :         elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
                               1484                 :                :              relid);
 7414 tgl@sss.pgh.pa.us        1485                 :CBC       44206 :     pgcform = (Form_pg_class) GETSTRUCT(ctup);
                               1486                 :                : 
                               1487                 :                :     /* Apply statistical updates, if any, to copied tuple */
                               1488                 :                : 
                               1489                 :          44206 :     dirty = false;
                               1490         [ +  + ]:          44206 :     if (pgcform->relpages != (int32) num_pages)
                               1491                 :                :     {
                               1492                 :           6160 :         pgcform->relpages = (int32) num_pages;
                               1493                 :           6160 :         dirty = true;
                               1494                 :                :     }
                               1495         [ +  + ]:          44206 :     if (pgcform->reltuples != (float4) num_tuples)
                               1496                 :                :     {
                               1497                 :          13453 :         pgcform->reltuples = (float4) num_tuples;
                               1498                 :          13453 :         dirty = true;
                               1499                 :                :     }
 5431                          1500         [ +  + ]:          44206 :     if (pgcform->relallvisible != (int32) num_all_visible_pages)
                               1501                 :                :     {
                               1502                 :           4130 :         pgcform->relallvisible = (int32) num_all_visible_pages;
                               1503                 :           4130 :         dirty = true;
                               1504                 :                :     }
  542 melanieplageman@gmai     1505         [ +  + ]:          44206 :     if (pgcform->relallfrozen != (int32) num_all_frozen_pages)
                               1506                 :                :     {
                               1507                 :           3447 :         pgcform->relallfrozen = (int32) num_all_frozen_pages;
                               1508                 :           3447 :         dirty = true;
                               1509                 :                :     }
                               1510                 :                : 
                               1511                 :                :     /* Apply DDL updates, but not inside an outer transaction (see above) */
                               1512                 :                : 
 4319 tgl@sss.pgh.pa.us        1513         [ +  + ]:          44206 :     if (!in_outer_xact)
                               1514                 :                :     {
                               1515                 :                :         /*
                               1516                 :                :          * If we didn't find any indexes, reset relhasindex.
                               1517                 :                :          */
 4320                          1518   [ +  +  +  + ]:          43912 :         if (pgcform->relhasindex && !hasindex)
                               1519                 :                :         {
                               1520                 :             21 :             pgcform->relhasindex = false;
                               1521                 :             21 :             dirty = true;
                               1522                 :                :         }
                               1523                 :                : 
                               1524                 :                :         /* We also clear relhasrules and relhastriggers if needed */
                               1525   [ +  +  -  + ]:          43912 :         if (pgcform->relhasrules && relation->rd_rules == NULL)
                               1526                 :                :         {
 4320 tgl@sss.pgh.pa.us        1527                 :UBC           0 :             pgcform->relhasrules = false;
                               1528                 :              0 :             dirty = true;
                               1529                 :                :         }
 4320 tgl@sss.pgh.pa.us        1530   [ +  +  +  + ]:CBC       43912 :         if (pgcform->relhastriggers && relation->trigdesc == NULL)
                               1531                 :                :         {
                               1532                 :              4 :             pgcform->relhastriggers = false;
                               1533                 :              4 :             dirty = true;
                               1534                 :                :         }
                               1535                 :                :     }
                               1536                 :                : 
                               1537                 :                :     /*
                               1538                 :                :      * Update relfrozenxid, unless caller passed InvalidTransactionId
                               1539                 :                :      * indicating it has no new data.
                               1540                 :                :      *
                               1541                 :                :      * Ordinarily, we don't let relfrozenxid go backwards.  However, if the
                               1542                 :                :      * stored relfrozenxid is "in the future" then it seems best to assume
                               1543                 :                :      * it's corrupt, and overwrite with the oldest remaining XID in the table.
                               1544                 :                :      * This should match vac_update_datfrozenxid() concerning what we consider
                               1545                 :                :      * to be "in the future".
                               1546                 :                :      */
 1605 pg@bowt.ie               1547                 :          44206 :     oldfrozenxid = pgcform->relfrozenxid;
                               1548                 :          44206 :     futurexid = false;
 1658                          1549         [ +  + ]:          44206 :     if (frozenxid_updated)
                               1550                 :          16323 :         *frozenxid_updated = false;
 1605                          1551   [ +  +  +  + ]:          44206 :     if (TransactionIdIsNormal(frozenxid) && oldfrozenxid != frozenxid)
                               1552                 :                :     {
 1568 tgl@sss.pgh.pa.us        1553                 :          14354 :         bool        update = false;
                               1554                 :                : 
 1605 pg@bowt.ie               1555         [ +  + ]:          14354 :         if (TransactionIdPrecedes(oldfrozenxid, frozenxid))
                               1556                 :          14275 :             update = true;
                               1557         [ -  + ]:             79 :         else if (TransactionIdPrecedes(ReadNextTransactionId(), oldfrozenxid))
 1605 pg@bowt.ie               1558                 :UBC           0 :             futurexid = update = true;
                               1559                 :                : 
 1605 pg@bowt.ie               1560         [ +  + ]:CBC       14354 :         if (update)
                               1561                 :                :         {
                               1562                 :          14275 :             pgcform->relfrozenxid = frozenxid;
                               1563                 :          14275 :             dirty = true;
                               1564         [ +  - ]:          14275 :             if (frozenxid_updated)
                               1565                 :          14275 :                 *frozenxid_updated = true;
                               1566                 :                :         }
                               1567                 :                :     }
                               1568                 :                : 
                               1569                 :                :     /* Similarly for relminmxid */
                               1570                 :          44206 :     oldminmulti = pgcform->relminmxid;
                               1571                 :          44206 :     futuremxid = false;
 1658                          1572         [ +  + ]:          44206 :     if (minmulti_updated)
                               1573                 :          16323 :         *minmulti_updated = false;
 1605                          1574   [ +  +  +  + ]:          44206 :     if (MultiXactIdIsValid(minmulti) && oldminmulti != minmulti)
                               1575                 :                :     {
 1568 tgl@sss.pgh.pa.us        1576                 :            309 :         bool        update = false;
                               1577                 :                : 
 1605 pg@bowt.ie               1578         [ +  - ]:            309 :         if (MultiXactIdPrecedes(oldminmulti, minmulti))
                               1579                 :            309 :             update = true;
 1605 pg@bowt.ie               1580         [ #  # ]:UBC           0 :         else if (MultiXactIdPrecedes(ReadNextMultiXactId(), oldminmulti))
                               1581                 :              0 :             futuremxid = update = true;
                               1582                 :                : 
 1605 pg@bowt.ie               1583         [ +  - ]:CBC         309 :         if (update)
                               1584                 :                :         {
                               1585                 :            309 :             pgcform->relminmxid = minmulti;
                               1586                 :            309 :             dirty = true;
                               1587         [ +  - ]:            309 :             if (minmulti_updated)
                               1588                 :            309 :                 *minmulti_updated = true;
                               1589                 :                :         }
                               1590                 :                :     }
                               1591                 :                : 
                               1592                 :                :     /* If anything changed, write out the tuple. */
 7414 tgl@sss.pgh.pa.us        1593         [ +  + ]:          44206 :     if (dirty)
  702 noah@leadboat.com        1594                 :          24273 :         systable_inplace_update_finish(inplace_state, ctup);
                               1595                 :                :     else
                               1596                 :          19933 :         systable_inplace_update_cancel(inplace_state);
                               1597                 :                : 
 2775 andres@anarazel.de       1598                 :          44206 :     table_close(rd, RowExclusiveLock);
                               1599                 :                : 
 1605 pg@bowt.ie               1600         [ -  + ]:          44206 :     if (futurexid)
 1605 pg@bowt.ie               1601         [ #  # ]:UBC           0 :         ereport(WARNING,
                               1602                 :                :                 (errcode(ERRCODE_DATA_CORRUPTED),
                               1603                 :                :                  errmsg_internal("overwrote invalid relfrozenxid value %u with new value %u for table \"%s\"",
                               1604                 :                :                                  oldfrozenxid, frozenxid,
                               1605                 :                :                                  RelationGetRelationName(relation))));
 1605 pg@bowt.ie               1606         [ -  + ]:CBC       44206 :     if (futuremxid)
 1605 pg@bowt.ie               1607         [ #  # ]:UBC           0 :         ereport(WARNING,
                               1608                 :                :                 (errcode(ERRCODE_DATA_CORRUPTED),
                               1609                 :                :                  errmsg_internal("overwrote invalid relminmxid value %u with new value %u for table \"%s\"",
                               1610                 :                :                                  oldminmulti, minmulti,
                               1611                 :                :                                  RelationGetRelationName(relation))));
 9177 tgl@sss.pgh.pa.us        1612                 :CBC       44206 : }
                               1613                 :                : 
                               1614                 :                : 
                               1615                 :                : /*
                               1616                 :                :  *  vac_update_datfrozenxid() -- update pg_database.datfrozenxid for our DB
                               1617                 :                :  *
                               1618                 :                :  *      Update pg_database's datfrozenxid entry for our database to be the
                               1619                 :                :  *      minimum of the pg_class.relfrozenxid values.
                               1620                 :                :  *
                               1621                 :                :  *      Similarly, update our datminmxid to be the minimum of the
                               1622                 :                :  *      pg_class.relminmxid values.
                               1623                 :                :  *
                               1624                 :                :  *      If we are able to advance either pg_database value, also try to
                               1625                 :                :  *      truncate pg_xact and pg_multixact.
                               1626                 :                :  *
                               1627                 :                :  *      We violate transaction semantics here by overwriting the database's
                               1628                 :                :  *      existing pg_database tuple with the new values.  This is reasonably
                               1629                 :                :  *      safe since the new values are correct whether or not this transaction
                               1630                 :                :  *      commits.  As with vac_update_relstats, this avoids leaving dead tuples
                               1631                 :                :  *      behind after a VACUUM.
                               1632                 :                :  */
                               1633                 :                : void
 7235                          1634                 :           1304 : vac_update_datfrozenxid(void)
                               1635                 :                : {
                               1636                 :                :     HeapTuple   tuple;
                               1637                 :                :     Form_pg_database dbform;
                               1638                 :                :     Relation    relation;
                               1639                 :                :     SysScanDesc scan;
                               1640                 :                :     HeapTuple   classTup;
                               1641                 :                :     TransactionId newFrozenXid;
                               1642                 :                :     MultiXactId newMinMulti;
                               1643                 :                :     TransactionId lastSaneFrozenXid;
                               1644                 :                :     MultiXactId lastSaneMinMulti;
 4420                          1645                 :           1304 :     bool        bogus = false;
 7353 alvherre@alvh.no-ip.     1646                 :           1304 :     bool        dirty = false;
                               1647                 :                :     ScanKeyData key[1];
                               1648                 :                :     void       *inplace_state;
                               1649                 :                : 
                               1650                 :                :     /*
                               1651                 :                :      * Restrict this task to one backend per database.  This avoids race
                               1652                 :                :      * conditions that would move datfrozenxid or datminmxid backward.  It
                               1653                 :                :      * avoids calling vac_truncate_clog() with a datfrozenxid preceding a
                               1654                 :                :      * datfrozenxid passed to an earlier vac_truncate_clog() call.
                               1655                 :                :      */
 2203 noah@leadboat.com        1656                 :           1304 :     LockDatabaseFrozenIds(ExclusiveLock);
                               1657                 :                : 
                               1658                 :                :     /*
                               1659                 :                :      * Initialize the "min" calculation with
                               1660                 :                :      * GetOldestNonRemovableTransactionId(), which is a reasonable
                               1661                 :                :      * approximation to the minimum relfrozenxid for not-yet-committed
                               1662                 :                :      * pg_class entries for new tables; see AddNewRelationTuple().  So we
                               1663                 :                :      * cannot produce a wrong minimum by starting with this.
                               1664                 :                :      */
 2206 andres@anarazel.de       1665                 :           1304 :     newFrozenXid = GetOldestNonRemovableTransactionId(NULL);
                               1666                 :                : 
                               1667                 :                :     /*
                               1668                 :                :      * Similarly, initialize the MultiXact "min" with the value that would be
                               1669                 :                :      * used on pg_class for new tables.  See AddNewRelationTuple().
                               1670                 :                :      */
 4420 tgl@sss.pgh.pa.us        1671                 :           1304 :     newMinMulti = GetOldestMultiXactId();
                               1672                 :                : 
                               1673                 :                :     /*
                               1674                 :                :      * Identify the latest relfrozenxid and relminmxid values that we could
                               1675                 :                :      * validly see during the scan.  These are conservative values, but it's
                               1676                 :                :      * not really worth trying to be more exact.
                               1677                 :                :      */
 2019 tmunro@postgresql.or     1678                 :           1304 :     lastSaneFrozenXid = ReadNextTransactionId();
 4420 tgl@sss.pgh.pa.us        1679                 :           1304 :     lastSaneMinMulti = ReadNextMultiXactId();
                               1680                 :                : 
                               1681                 :                :     /*
                               1682                 :                :      * We must seqscan pg_class to find the minimum Xid, because there is no
                               1683                 :                :      * index that can help us here.
                               1684                 :                :      *
                               1685                 :                :      * See vac_truncate_clog() for the race condition to prevent.
                               1686                 :                :      */
 2775 andres@anarazel.de       1687                 :           1304 :     relation = table_open(RelationRelationId, AccessShareLock);
                               1688                 :                : 
 7353 alvherre@alvh.no-ip.     1689                 :           1304 :     scan = systable_beginscan(relation, InvalidOid, false,
                               1690                 :                :                               NULL, 0, NULL);
                               1691                 :                : 
                               1692         [ +  + ]:         958650 :     while ((classTup = systable_getnext(scan)) != NULL)
                               1693                 :                :     {
  177 peter@eisentraut.org     1694                 :         957347 :         Form_pg_class classForm = (Form_pg_class) GETSTRUCT(classTup);
                               1695                 :         957347 :         volatile TransactionId *relfrozenxid_p = &classForm->relfrozenxid;
                               1696                 :         957347 :         volatile TransactionId *relminmxid_p = &classForm->relminmxid;
                               1697                 :         957347 :         TransactionId relfrozenxid = *relfrozenxid_p;
                               1698                 :         957347 :         TransactionId relminmxid = *relminmxid_p;
                               1699                 :                : 
                               1700                 :                :         /*
                               1701                 :                :          * Only consider relations able to hold unfrozen XIDs (anything else
                               1702                 :                :          * should have InvalidTransactionId in relfrozenxid anyway).
                               1703                 :                :          */
 7353 alvherre@alvh.no-ip.     1704         [ +  + ]:         957347 :         if (classForm->relkind != RELKIND_RELATION &&
 4925 kgrittn@postgresql.o     1705         [ +  + ]:         718305 :             classForm->relkind != RELKIND_MATVIEW &&
 7353 alvherre@alvh.no-ip.     1706         [ +  + ]:         716537 :             classForm->relkind != RELKIND_TOASTVALUE)
                               1707                 :                :         {
  850 noah@leadboat.com        1708         [ -  + ]:         603358 :             Assert(!TransactionIdIsValid(relfrozenxid));
                               1709         [ -  + ]:         603358 :             Assert(!MultiXactIdIsValid(relminmxid));
 7353 alvherre@alvh.no-ip.     1710                 :         603358 :             continue;
                               1711                 :                :         }
                               1712                 :                : 
                               1713                 :                :         /*
                               1714                 :                :          * Some table AMs might not need per-relation xid / multixid horizons.
                               1715                 :                :          * It therefore seems reasonable to allow relfrozenxid and relminmxid
                               1716                 :                :          * to not be set (i.e. set to their respective Invalid*Id)
                               1717                 :                :          * independently. Thus validate and compute horizon for each only if
                               1718                 :                :          * set.
                               1719                 :                :          *
                               1720                 :                :          * If things are working properly, no relation should have a
                               1721                 :                :          * relfrozenxid or relminmxid that is "in the future".  However, such
                               1722                 :                :          * cases have been known to arise due to bugs in pg_upgrade.  If we
                               1723                 :                :          * see any entries that are "in the future", chicken out and don't do
                               1724                 :                :          * anything.  This ensures we won't truncate clog & multixact SLRUs
                               1725                 :                :          * before those relations have been scanned and cleaned up.
                               1726                 :                :          */
                               1727                 :                : 
  850 noah@leadboat.com        1728         [ +  - ]:         353989 :         if (TransactionIdIsValid(relfrozenxid))
                               1729                 :                :         {
                               1730         [ -  + ]:         353989 :             Assert(TransactionIdIsNormal(relfrozenxid));
                               1731                 :                : 
                               1732                 :                :             /* check for values in the future */
                               1733         [ +  + ]:         353989 :             if (TransactionIdPrecedes(lastSaneFrozenXid, relfrozenxid))
                               1734                 :                :             {
 2683 andres@anarazel.de       1735                 :GBC           1 :                 bogus = true;
                               1736                 :              1 :                 break;
                               1737                 :                :             }
                               1738                 :                : 
                               1739                 :                :             /* determine new horizon */
  850 noah@leadboat.com        1740         [ +  + ]:CBC      353988 :             if (TransactionIdPrecedes(relfrozenxid, newFrozenXid))
                               1741                 :           2106 :                 newFrozenXid = relfrozenxid;
                               1742                 :                :         }
                               1743                 :                : 
                               1744         [ +  - ]:         353988 :         if (MultiXactIdIsValid(relminmxid))
                               1745                 :                :         {
                               1746                 :                :             /* check for values in the future */
                               1747         [ -  + ]:         353988 :             if (MultiXactIdPrecedes(lastSaneMinMulti, relminmxid))
                               1748                 :                :             {
 2683 andres@anarazel.de       1749                 :UBC           0 :                 bogus = true;
                               1750                 :              0 :                 break;
                               1751                 :                :             }
                               1752                 :                : 
                               1753                 :                :             /* determine new horizon */
  850 noah@leadboat.com        1754         [ +  + ]:CBC      353988 :             if (MultiXactIdPrecedes(relminmxid, newMinMulti))
                               1755                 :            274 :                 newMinMulti = relminmxid;
                               1756                 :                :         }
                               1757                 :                :     }
                               1758                 :                : 
                               1759                 :                :     /* we're done with pg_class */
 7353 alvherre@alvh.no-ip.     1760                 :           1304 :     systable_endscan(scan);
 2775 andres@anarazel.de       1761                 :           1304 :     table_close(relation, AccessShareLock);
                               1762                 :                : 
                               1763                 :                :     /* chicken out if bogus data found */
 4420 tgl@sss.pgh.pa.us        1764         [ +  + ]:           1304 :     if (bogus)
 4420 tgl@sss.pgh.pa.us        1765                 :GBC           1 :         return;
                               1766                 :                : 
 7235 tgl@sss.pgh.pa.us        1767         [ -  + ]:CBC        1303 :     Assert(TransactionIdIsNormal(newFrozenXid));
 4728 alvherre@alvh.no-ip.     1768         [ -  + ]:           1303 :     Assert(MultiXactIdIsValid(newMinMulti));
                               1769                 :                : 
                               1770                 :                :     /* Now fetch the pg_database tuple we need to update. */
 2775 andres@anarazel.de       1771                 :           1303 :     relation = table_open(DatabaseRelationId, RowExclusiveLock);
                               1772                 :                : 
                               1773                 :                :     /*
                               1774                 :                :      * Fetch a copy of the tuple to scribble on.  We could check the syscache
                               1775                 :                :      * tuple first.  If that concluded !dirty, we'd avoid waiting on
                               1776                 :                :      * concurrent heap_update() and would avoid exclusive-locking the buffer.
                               1777                 :                :      * For now, don't optimize that.
                               1778                 :                :      */
 2088 michael@paquier.xyz      1779                 :           1303 :     ScanKeyInit(&key[0],
                               1780                 :                :                 Anum_pg_database_oid,
                               1781                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                               1782                 :                :                 ObjectIdGetDatum(MyDatabaseId));
                               1783                 :                : 
  702 noah@leadboat.com        1784                 :           1303 :     systable_inplace_update_begin(relation, DatabaseOidIndexId, true,
                               1785                 :                :                                   NULL, 1, key, &tuple, &inplace_state);
                               1786                 :                : 
 9132 tgl@sss.pgh.pa.us        1787         [ -  + ]:           1303 :     if (!HeapTupleIsValid(tuple))
 7235 tgl@sss.pgh.pa.us        1788         [ #  # ]:UBC           0 :         elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
                               1789                 :                : 
 9132 tgl@sss.pgh.pa.us        1790                 :CBC        1303 :     dbform = (Form_pg_database) GETSTRUCT(tuple);
                               1791                 :                : 
                               1792                 :                :     /*
                               1793                 :                :      * As in vac_update_relstats(), we ordinarily don't want to let
                               1794                 :                :      * datfrozenxid go backward; but if it's "in the future" then it must be
                               1795                 :                :      * corrupt and it seems best to overwrite it.
                               1796                 :                :      */
 4420                          1797   [ +  +  -  + ]:           1415 :     if (dbform->datfrozenxid != newFrozenXid &&
                               1798         [ -  - ]:            112 :         (TransactionIdPrecedes(dbform->datfrozenxid, newFrozenXid) ||
 4420 tgl@sss.pgh.pa.us        1799                 :UBC           0 :          TransactionIdPrecedes(lastSaneFrozenXid, dbform->datfrozenxid)))
                               1800                 :                :     {
 7235 tgl@sss.pgh.pa.us        1801                 :CBC         112 :         dbform->datfrozenxid = newFrozenXid;
 7353 alvherre@alvh.no-ip.     1802                 :            112 :         dirty = true;
                               1803                 :                :     }
                               1804                 :                :     else
 4420 tgl@sss.pgh.pa.us        1805                 :           1191 :         newFrozenXid = dbform->datfrozenxid;
                               1806                 :                : 
                               1807                 :                :     /* Ditto for datminmxid */
                               1808   [ +  +  -  + ]:           1304 :     if (dbform->datminmxid != newMinMulti &&
                               1809         [ -  - ]:              1 :         (MultiXactIdPrecedes(dbform->datminmxid, newMinMulti) ||
 4420 tgl@sss.pgh.pa.us        1810                 :UBC           0 :          MultiXactIdPrecedes(lastSaneMinMulti, dbform->datminmxid)))
                               1811                 :                :     {
 4728 alvherre@alvh.no-ip.     1812                 :CBC           1 :         dbform->datminmxid = newMinMulti;
 4964                          1813                 :              1 :         dirty = true;
                               1814                 :                :     }
                               1815                 :                :     else
 4420 tgl@sss.pgh.pa.us        1816                 :           1302 :         newMinMulti = dbform->datminmxid;
                               1817                 :                : 
 7353 alvherre@alvh.no-ip.     1818         [ +  + ]:           1303 :     if (dirty)
  702 noah@leadboat.com        1819                 :            112 :         systable_inplace_update_finish(inplace_state, tuple);
                               1820                 :                :     else
                               1821                 :           1191 :         systable_inplace_update_cancel(inplace_state);
                               1822                 :                : 
 7353 alvherre@alvh.no-ip.     1823                 :           1303 :     heap_freetuple(tuple);
 2775 andres@anarazel.de       1824                 :           1303 :     table_close(relation, RowExclusiveLock);
                               1825                 :                : 
                               1826                 :                :     /*
                               1827                 :                :      * If we were able to advance datfrozenxid or datminmxid, see if we can
                               1828                 :                :      * truncate pg_xact and/or pg_multixact.  Also do it if the shared
                               1829                 :                :      * XID-wrap-limit info is stale, since this action will update that too.
                               1830                 :                :      */
 6204 tgl@sss.pgh.pa.us        1831   [ +  +  -  + ]:           1303 :     if (dirty || ForceTransactionIdLimitUpdate())
 4420                          1832                 :            112 :         vac_truncate_clog(newFrozenXid, newMinMulti,
                               1833                 :                :                           lastSaneFrozenXid, lastSaneMinMulti);
                               1834                 :                : }
                               1835                 :                : 
                               1836                 :                : 
                               1837                 :                : /*
                               1838                 :                :  *  vac_truncate_clog() -- attempt to truncate the commit log
                               1839                 :                :  *
                               1840                 :                :  *      Scan pg_database to determine the system-wide oldest datfrozenxid,
                               1841                 :                :  *      and use it to truncate the transaction commit log (pg_xact).
                               1842                 :                :  *      Also update the XID wrap limit info maintained by varsup.c.
                               1843                 :                :  *      Likewise for datminmxid.
                               1844                 :                :  *
                               1845                 :                :  *      The passed frozenXID and minMulti are the updated values for my own
                               1846                 :                :  *      pg_database entry. They're used to initialize the "min" calculations.
                               1847                 :                :  *      The caller also passes the "last sane" XID and MXID, since it has
                               1848                 :                :  *      those at hand already.
                               1849                 :                :  *
                               1850                 :                :  *      This routine is only invoked when we've managed to change our
                               1851                 :                :  *      DB's datfrozenxid/datminmxid values, or we found that the shared
                               1852                 :                :  *      XID-wrap-limit info is stale.
                               1853                 :                :  */
                               1854                 :                : static void
                               1855                 :            112 : vac_truncate_clog(TransactionId frozenXID,
                               1856                 :                :                   MultiXactId minMulti,
                               1857                 :                :                   TransactionId lastSaneFrozenXid,
                               1858                 :                :                   MultiXactId lastSaneMinMulti)
                               1859                 :                : {
 2019 tmunro@postgresql.or     1860                 :            112 :     TransactionId nextXID = ReadNextTransactionId();
                               1861                 :                :     Relation    relation;
                               1862                 :                :     TableScanDesc scan;
                               1863                 :                :     HeapTuple   tuple;
                               1864                 :                :     Oid         oldestxid_datoid;
                               1865                 :                :     Oid         minmulti_datoid;
 4420 tgl@sss.pgh.pa.us        1866                 :            112 :     bool        bogus = false;
 7235                          1867                 :            112 :     bool        frozenAlreadyWrapped = false;
                               1868                 :                : 
                               1869                 :                :     /* Restrict task to one backend per cluster; see SimpleLruTruncate(). */
 2203 noah@leadboat.com        1870                 :            112 :     LWLockAcquire(WrapLimitsVacuumLock, LW_EXCLUSIVE);
                               1871                 :                : 
                               1872                 :                :     /* init oldest datoids to sync with my frozenXID/minMulti values */
 4964 alvherre@alvh.no-ip.     1873                 :            112 :     oldestxid_datoid = MyDatabaseId;
 4728                          1874                 :            112 :     minmulti_datoid = MyDatabaseId;
                               1875                 :                : 
                               1876                 :                :     /*
                               1877                 :                :      * Scan pg_database to compute the minimum datfrozenxid/datminmxid
                               1878                 :                :      *
                               1879                 :                :      * Since vac_update_datfrozenxid updates datfrozenxid/datminmxid in-place,
                               1880                 :                :      * the values could change while we look at them.  Fetch each one just
                               1881                 :                :      * once to ensure sane behavior of the comparison logic.  (Here, as in
                               1882                 :                :      * many other places, we assume that fetching or updating an XID in shared
                               1883                 :                :      * storage is atomic.)
                               1884                 :                :      *
                               1885                 :                :      * Note: we need not worry about a race condition with new entries being
                               1886                 :                :      * inserted by CREATE DATABASE.  Any such entry will have a copy of some
                               1887                 :                :      * existing DB's datfrozenxid, and that source DB cannot be ours because
                               1888                 :                :      * of the interlock against copying a DB containing an active backend.
                               1889                 :                :      * Hence the new entry will not reduce the minimum.  Also, if two VACUUMs
                               1890                 :                :      * concurrently modify the datfrozenxid's of different databases, the
                               1891                 :                :      * worst possible outcome is that pg_xact is not truncated as aggressively
                               1892                 :                :      * as it could be.
                               1893                 :                :      */
 2775 andres@anarazel.de       1894                 :            112 :     relation = table_open(DatabaseRelationId, AccessShareLock);
                               1895                 :                : 
 2726                          1896                 :            112 :     scan = table_beginscan_catalog(relation, 0, NULL);
                               1897                 :                : 
 8865 tgl@sss.pgh.pa.us        1898         [ +  + ]:            353 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
                               1899                 :                :     {
  177 peter@eisentraut.org     1900                 :            241 :         Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
                               1901                 :            241 :         volatile TransactionId *datfrozenxid_p = &dbform->datfrozenxid;
                               1902                 :            241 :         volatile TransactionId *datminmxid_p = &dbform->datminmxid;
                               1903                 :            241 :         TransactionId datfrozenxid = *datfrozenxid_p;
                               1904                 :            241 :         TransactionId datminmxid = *datminmxid_p;
                               1905                 :                : 
 3747 tgl@sss.pgh.pa.us        1906         [ -  + ]:            241 :         Assert(TransactionIdIsNormal(datfrozenxid));
                               1907         [ -  + ]:            241 :         Assert(MultiXactIdIsValid(datminmxid));
                               1908                 :                : 
                               1909                 :                :         /*
                               1910                 :                :          * If database is in the process of getting dropped, or has been
                               1911                 :                :          * interrupted while doing so, no connections to it are possible
                               1912                 :                :          * anymore. Therefore we don't need to take it into account here.
                               1913                 :                :          * Which is good, because it can't be processed by autovacuum either.
                               1914                 :                :          */
 1141 andres@anarazel.de       1915         [ +  + ]:            241 :         if (database_is_invalid_form((Form_pg_database) dbform))
                               1916                 :                :         {
                               1917         [ -  + ]:              2 :             elog(DEBUG2,
                               1918                 :                :                  "skipping invalid database \"%s\" while computing relfrozenxid",
                               1919                 :                :                  NameStr(dbform->datname));
                               1920                 :              2 :             continue;
                               1921                 :                :         }
                               1922                 :                : 
                               1923                 :                :         /*
                               1924                 :                :          * If things are working properly, no database should have a
                               1925                 :                :          * datfrozenxid or datminmxid that is "in the future".  However, such
                               1926                 :                :          * cases have been known to arise due to bugs in pg_upgrade.  If we
                               1927                 :                :          * see any entries that are "in the future", chicken out and don't do
                               1928                 :                :          * anything.  This ensures we won't truncate clog before those
                               1929                 :                :          * databases have been scanned and cleaned up.  (We will issue the
                               1930                 :                :          * "already wrapped" warning if appropriate, though.)
                               1931                 :                :          */
 3747 tgl@sss.pgh.pa.us        1932   [ +  -  -  + ]:            478 :         if (TransactionIdPrecedes(lastSaneFrozenXid, datfrozenxid) ||
                               1933                 :            239 :             MultiXactIdPrecedes(lastSaneMinMulti, datminmxid))
 4420 tgl@sss.pgh.pa.us        1934                 :UBC           0 :             bogus = true;
                               1935                 :                : 
 3747 tgl@sss.pgh.pa.us        1936         [ -  + ]:CBC         239 :         if (TransactionIdPrecedes(nextXID, datfrozenxid))
 7235 tgl@sss.pgh.pa.us        1937                 :UBC           0 :             frozenAlreadyWrapped = true;
 3747 tgl@sss.pgh.pa.us        1938         [ +  + ]:CBC         239 :         else if (TransactionIdPrecedes(datfrozenxid, frozenXID))
                               1939                 :                :         {
                               1940                 :             61 :             frozenXID = datfrozenxid;
 2837 andres@anarazel.de       1941                 :             61 :             oldestxid_datoid = dbform->oid;
                               1942                 :                :         }
                               1943                 :                : 
 3747 tgl@sss.pgh.pa.us        1944         [ +  + ]:            239 :         if (MultiXactIdPrecedes(datminmxid, minMulti))
                               1945                 :                :         {
                               1946                 :              2 :             minMulti = datminmxid;
 2837 andres@anarazel.de       1947                 :              2 :             minmulti_datoid = dbform->oid;
                               1948                 :                :         }
                               1949                 :                :     }
                               1950                 :                : 
 2726                          1951                 :            112 :     table_endscan(scan);
                               1952                 :                : 
 2775                          1953                 :            112 :     table_close(relation, AccessShareLock);
                               1954                 :                : 
                               1955                 :                :     /*
                               1956                 :                :      * Do not truncate CLOG if we seem to have suffered wraparound already;
                               1957                 :                :      * the computed minimum XID might be bogus.  This case should now be
                               1958                 :                :      * impossible due to the defenses in GetNewTransactionId, but we keep the
                               1959                 :                :      * test anyway.
                               1960                 :                :      */
 7235 tgl@sss.pgh.pa.us        1961         [ -  + ]:            112 :     if (frozenAlreadyWrapped)
                               1962                 :                :     {
 8439 tgl@sss.pgh.pa.us        1963         [ #  # ]:UBC           0 :         ereport(WARNING,
                               1964                 :                :                 (errmsg("some databases have not been vacuumed in over 2 billion transactions"),
                               1965                 :                :                  errdetail("You might have already suffered transaction-wraparound data loss.")));
 1141 andres@anarazel.de       1966                 :              0 :         LWLockRelease(WrapLimitsVacuumLock);
 8913 tgl@sss.pgh.pa.us        1967                 :              0 :         return;
                               1968                 :                :     }
                               1969                 :                : 
                               1970                 :                :     /* chicken out if data is bogus in any other way */
 4420 tgl@sss.pgh.pa.us        1971         [ -  + ]:CBC         112 :     if (bogus)
                               1972                 :                :     {
 1141 andres@anarazel.de       1973                 :UBC           0 :         LWLockRelease(WrapLimitsVacuumLock);
 4420 tgl@sss.pgh.pa.us        1974                 :              0 :         return;
                               1975                 :                :     }
                               1976                 :                : 
                               1977                 :                :     /*
                               1978                 :                :      * Freeze any old transaction IDs in the async notification queue before
                               1979                 :                :      * CLOG truncation.
                               1980                 :                :      */
  288 heikki.linnakangas@i     1981                 :CBC         112 :     AsyncNotifyFreezeXids(frozenXID);
                               1982                 :                : 
                               1983                 :                :     /*
                               1984                 :                :      * Advance the oldest value for commit timestamps before truncating, so
                               1985                 :                :      * that if a user requests a timestamp for a transaction we're truncating
                               1986                 :                :      * away right after this point, they get NULL instead of an ugly "file not
                               1987                 :                :      * found" error from slru.c.  This doesn't matter for xact/multixact
                               1988                 :                :      * because they are not subject to arbitrary lookups from users.
                               1989                 :                :      */
 3507 alvherre@alvh.no-ip.     1990                 :            112 :     AdvanceOldestCommitTsXid(frozenXID);
                               1991                 :                : 
                               1992                 :                :     /*
                               1993                 :                :      * Truncate CLOG, multixact and CommitTs to the oldest computed value.
                               1994                 :                :      */
 3444 rhaas@postgresql.org     1995                 :            112 :     TruncateCLOG(frozenXID, oldestxid_datoid);
 3957 alvherre@alvh.no-ip.     1996                 :            112 :     TruncateCommitTs(frozenXID);
 3988 andres@anarazel.de       1997                 :            112 :     TruncateMultiXact(minMulti, minmulti_datoid);
                               1998                 :                : 
                               1999                 :                :     /*
                               2000                 :                :      * Update the wrap limit for GetNewTransactionId and creation of new
                               2001                 :                :      * MultiXactIds.  Note: these functions will also signal the postmaster
                               2002                 :                :      * for an(other) autovac cycle if needed.   XXX should we avoid possibly
                               2003                 :                :      * signaling twice?
                               2004                 :                :      */
 4964 alvherre@alvh.no-ip.     2005                 :            112 :     SetTransactionIdLimit(frozenXID, oldestxid_datoid);
  261 heikki.linnakangas@i     2006                 :            112 :     SetMultiXactIdLimit(minMulti, minmulti_datoid);
                               2007                 :                : 
 2203 noah@leadboat.com        2008                 :            112 :     LWLockRelease(WrapLimitsVacuumLock);
                               2009                 :                : }
                               2010                 :                : 
                               2011                 :                : 
                               2012                 :                : /*
                               2013                 :                :  *  vacuum_rel() -- vacuum one heap relation
                               2014                 :                :  *
                               2015                 :                :  *      relid identifies the relation to vacuum.  If relation is supplied,
                               2016                 :                :  *      use the name therein for reporting any failure to open/lock the rel;
                               2017                 :                :  *      do not use it once we've successfully opened the rel, since it might
                               2018                 :                :  *      be stale.
                               2019                 :                :  *
                               2020                 :                :  *      Returns true if it's okay to proceed with a requested ANALYZE
                               2021                 :                :  *      operation on this table.
                               2022                 :                :  *
                               2023                 :                :  *      Doing one heap at a time incurs extra overhead, since we need to
                               2024                 :                :  *      check that the heap exists again just before we vacuum it.  The
                               2025                 :                :  *      reason that we do this is so that vacuuming can be spread across
                               2026                 :                :  *      many small transactions.  Otherwise, two-phase locking would require
                               2027                 :                :  *      us to lock the entire database during one pass of the vacuum cleaner.
                               2028                 :                :  *
                               2029                 :                :  *      At entry and exit, we are not inside a transaction.
                               2030                 :                :  */
                               2031                 :                : static bool
  423 michael@paquier.xyz      2032                 :          16826 : vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
                               2033                 :                :            BufferAccessStrategy bstrategy, bool isTopLevel)
                               2034                 :                : {
                               2035                 :                :     LOCKMODE    lmode;
                               2036                 :                :     Relation    rel;
                               2037                 :                :     LockRelId   lockrelid;
                               2038                 :                :     Oid         priv_relid;
                               2039                 :                :     Oid         toast_relid;
                               2040                 :                :     Oid         save_userid;
                               2041                 :                :     int         save_sec_context;
                               2042                 :                :     int         save_nestlevel;
                               2043                 :                :     VacuumParams toast_vacuum_params;
                               2044                 :                :     StdRdOptions *relopts;
                               2045                 :                :     StdRdOptions relopts_copy;
                               2046                 :                : 
                               2047                 :                :     /*
                               2048                 :                :      * This function scribbles on the parameters, so make a copy early to
                               2049                 :                :      * avoid affecting the TOAST table (if we do end up recursing to it).
                               2050                 :                :      */
                               2051                 :          16826 :     memcpy(&toast_vacuum_params, &params, sizeof(VacuumParams));
                               2052                 :                : 
                               2053                 :                :     /* Begin a transaction for vacuuming this relation */
 8506 tgl@sss.pgh.pa.us        2054                 :          16826 :     StartTransactionCommand();
                               2055                 :                : 
  423 michael@paquier.xyz      2056         [ +  + ]:          16826 :     if (!(params.options & VACOPT_FULL))
                               2057                 :                :     {
                               2058                 :                :         /*
                               2059                 :                :          * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets
                               2060                 :                :          * other concurrent VACUUMs know that they can ignore this one while
                               2061                 :                :          * determining their OldestXmin.  (The reason we don't set it during a
                               2062                 :                :          * full VACUUM is exactly that we may have to run user-defined
                               2063                 :                :          * functions for functional indexes, and we want to make sure that if
                               2064                 :                :          * they use the snapshot set above, any tuples it requires can't get
                               2065                 :                :          * removed from other tables.  An index function that depends on the
                               2066                 :                :          * contents of other tables is arguably broken, but we won't break it
                               2067                 :                :          * here by violating transaction semantics.)
                               2068                 :                :          *
                               2069                 :                :          * We also set the VACUUM_FOR_WRAPAROUND flag, which is passed down by
                               2070                 :                :          * autovacuum; it's used to avoid canceling a vacuum that was invoked
                               2071                 :                :          * in an emergency.
                               2072                 :                :          *
                               2073                 :                :          * Note: these flags remain set until CommitTransaction or
                               2074                 :                :          * AbortTransaction.  We don't want to clear them until we reset
                               2075                 :                :          * MyProc->xid/xmin, otherwise GetOldestNonRemovableTransactionId()
                               2076                 :                :          * might appear to go backwards, which is probably Not Good.  (We also
                               2077                 :                :          * set PROC_IN_VACUUM *before* taking our own snapshot, so that our
                               2078                 :                :          * xmin doesn't become visible ahead of setting the flag.)
                               2079                 :                :          */
 2100 alvherre@alvh.no-ip.     2080                 :          16579 :         LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 2110                          2081                 :          16579 :         MyProc->statusFlags |= PROC_IN_VACUUM;
  423 michael@paquier.xyz      2082         [ -  + ]:          16579 :         if (params.is_wraparound)
 2110 alvherre@alvh.no-ip.     2083                 :UBC           0 :             MyProc->statusFlags |= PROC_VACUUM_FOR_WRAPAROUND;
 2110 alvherre@alvh.no-ip.     2084                 :CBC       16579 :         ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
 6882                          2085                 :          16579 :         LWLockRelease(ProcArrayLock);
                               2086                 :                :     }
                               2087                 :                : 
                               2088                 :                :     /*
                               2089                 :                :      * Need to acquire a snapshot to prevent pg_subtrans from being truncated,
                               2090                 :                :      * cutoff xids in local memory wrapping around, and to have updated xmin
                               2091                 :                :      * horizons.
                               2092                 :                :      */
 2100                          2093                 :          16826 :     PushActiveSnapshot(GetTransactionSnapshot());
                               2094                 :                : 
                               2095                 :                :     /*
                               2096                 :                :      * Check for user-requested abort.  Note we want this to be inside a
                               2097                 :                :      * transaction, so xact.c doesn't issue useless WARNING.
                               2098                 :                :      */
 9356 tgl@sss.pgh.pa.us        2099         [ -  + ]:          16826 :     CHECK_FOR_INTERRUPTS();
                               2100                 :                : 
                               2101                 :                :     /*
                               2102                 :                :      * Determine the type of lock we want --- hard exclusive lock for a FULL
                               2103                 :                :      * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either
                               2104                 :                :      * way, we can be sure that no other backend is vacuuming the same table.
                               2105                 :                :      */
  423 michael@paquier.xyz      2106                 :          33652 :     lmode = (params.options & VACOPT_FULL) ?
 2719 rhaas@postgresql.org     2107         [ +  + ]:          16826 :         AccessExclusiveLock : ShareUpdateExclusiveLock;
                               2108                 :                : 
                               2109                 :                :     /* open the relation and get the appropriate lock on it */
  423 michael@paquier.xyz      2110                 :          16826 :     rel = vacuum_open_relation(relid, relation, params.options,
  316 peter@eisentraut.org     2111                 :          16826 :                                params.log_vacuum_min_duration >= 0, lmode);
                               2112                 :                : 
                               2113                 :                :     /* leave if relation could not be opened or locked */
 1970 pg@bowt.ie               2114         [ +  + ]:          16826 :     if (!rel)
                               2115                 :                :     {
 6559 alvherre@alvh.no-ip.     2116                 :             16 :         PopActiveSnapshot();
 7314 tgl@sss.pgh.pa.us        2117                 :             16 :         CommitTransactionCommand();
 5680 rhaas@postgresql.org     2118                 :             16 :         return false;
                               2119                 :                :     }
                               2120                 :                : 
                               2121                 :                :     /*
                               2122                 :                :      * When recursing to a TOAST table, check privileges on the parent.  NB:
                               2123                 :                :      * This is only safe to do because we hold a session lock on the main
                               2124                 :                :      * relation that prevents concurrent deletion.
                               2125                 :                :      */
  423 michael@paquier.xyz      2126         [ +  + ]:          16810 :     if (OidIsValid(params.toast_parent))
                               2127                 :           5526 :         priv_relid = params.toast_parent;
                               2128                 :                :     else
  897 nathan@postgresql.or     2129                 :          11284 :         priv_relid = RelationGetRelid(rel);
                               2130                 :                : 
                               2131                 :                :     /*
                               2132                 :                :      * Check if relation needs to be skipped based on privileges.  This check
                               2133                 :                :      * happens also when building the relation list to vacuum for a manual
                               2134                 :                :      * operation, and needs to be done additionally here as VACUUM could
                               2135                 :                :      * happen across multiple transactions where privileges could have changed
                               2136                 :                :      * in-between.  Make sure to only generate logs for VACUUM in this case.
                               2137                 :                :      */
                               2138         [ +  + ]:          16810 :     if (!vacuum_is_permitted_for_relation(priv_relid,
                               2139                 :                :                                           rel->rd_rel,
   24 nathan@postgresql.or     2140                 :GNC       16810 :                                           params.options & ~VACOPT_ANALYZE,
                               2141                 :                :                                           false))
                               2142                 :                :     {
 1970 pg@bowt.ie               2143                 :CBC          48 :         relation_close(rel, lmode);
 6559 alvherre@alvh.no-ip.     2144                 :             48 :         PopActiveSnapshot();
 8506 tgl@sss.pgh.pa.us        2145                 :             48 :         CommitTransactionCommand();
 1353 jdavis@postgresql.or     2146                 :             48 :         return false;
                               2147                 :                :     }
                               2148                 :                : 
                               2149                 :                :     /*
                               2150                 :                :      * Check that it's of a vacuumable relkind.
                               2151                 :                :      */
 1970 pg@bowt.ie               2152         [ +  + ]:          16762 :     if (rel->rd_rel->relkind != RELKIND_RELATION &&
                               2153         [ +  + ]:           5663 :         rel->rd_rel->relkind != RELKIND_MATVIEW &&
                               2154         [ +  + ]:           5658 :         rel->rd_rel->relkind != RELKIND_TOASTVALUE &&
                               2155         [ +  + ]:            125 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
                               2156                 :                :     {
 8439 tgl@sss.pgh.pa.us        2157         [ +  - ]:              1 :         ereport(WARNING,
                               2158                 :                :                 (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
                               2159                 :                :                         RelationGetRelationName(rel))));
 1970 pg@bowt.ie               2160                 :              1 :         relation_close(rel, lmode);
 6559 alvherre@alvh.no-ip.     2161                 :              1 :         PopActiveSnapshot();
 8506 tgl@sss.pgh.pa.us        2162                 :              1 :         CommitTransactionCommand();
 5680 rhaas@postgresql.org     2163                 :              1 :         return false;
                               2164                 :                :     }
                               2165                 :                : 
                               2166                 :                :     /*
                               2167                 :                :      * Silently ignore tables that are temp tables of other backends ---
                               2168                 :                :      * trying to vacuum these will lead to great unhappiness, since their
                               2169                 :                :      * contents are probably not up-to-date on disk.  (We don't throw a
                               2170                 :                :      * warning here; it would just lead to chatter during a database-wide
                               2171                 :                :      * VACUUM.)
                               2172                 :                :      */
 1970 pg@bowt.ie               2173   [ +  +  +  + ]:          16761 :     if (RELATION_IS_OTHER_TEMP(rel))
                               2174                 :                :     {
                               2175                 :              1 :         relation_close(rel, lmode);
 6559 alvherre@alvh.no-ip.     2176                 :              1 :         PopActiveSnapshot();
 8506 tgl@sss.pgh.pa.us        2177                 :              1 :         CommitTransactionCommand();
 5680 rhaas@postgresql.org     2178                 :              1 :         return false;
                               2179                 :                :     }
                               2180                 :                : 
                               2181                 :                :     /*
                               2182                 :                :      * Silently ignore partitioned tables as there is no work to be done.  The
                               2183                 :                :      * useful work is on their child partitions, which have been queued up for
                               2184                 :                :      * us separately.
                               2185                 :                :      */
 1970 pg@bowt.ie               2186         [ +  + ]:          16760 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                               2187                 :                :     {
                               2188                 :            124 :         relation_close(rel, lmode);
 3465 rhaas@postgresql.org     2189                 :            124 :         PopActiveSnapshot();
                               2190                 :            124 :         CommitTransactionCommand();
                               2191                 :                :         /* It's OK to proceed with ANALYZE on this table */
                               2192                 :            124 :         return true;
                               2193                 :                :     }
                               2194                 :                : 
                               2195                 :                :     /*
                               2196                 :                :      * Get a session-level lock too. This will protect our access to the
                               2197                 :                :      * relation across multiple transactions, so that we can vacuum the
                               2198                 :                :      * relation's TOAST table (if any) secure in the knowledge that no one is
                               2199                 :                :      * deleting the parent relation.
                               2200                 :                :      *
                               2201                 :                :      * NOTE: this cannot block, even if someone else is waiting for access,
                               2202                 :                :      * because the lock manager knows that both lock requests are from the
                               2203                 :                :      * same process.
                               2204                 :                :      */
 1970 pg@bowt.ie               2205                 :          16636 :     lockrelid = rel->rd_lockInfo.lockRelId;
                               2206                 :          16636 :     LockRelationIdForSession(&lockrelid, lmode);
                               2207                 :                : 
                               2208                 :                :     /*
                               2209                 :                :      * Determine the storage parameters to use.  A TOAST table takes any
                               2210                 :                :      * storage parameter it accepts but does not set from its main table,
                               2211                 :                :      * whose parameters the caller handed down for that purpose.  For anything
                               2212                 :                :      * else, params.main_relopts is NULL, and this just copies our own.
                               2213                 :                :      */
    3 nathan@postgresql.or     2214                 :GNC       16636 :     relopts = merge_toast_reloptions((StdRdOptions *) rel->rd_options,
                               2215                 :                :                                      params.main_relopts);
                               2216                 :                : 
                               2217                 :                :     /*
                               2218                 :                :      * Set index_cleanup option based on index_cleanup reloption if it wasn't
                               2219                 :                :      * specified in VACUUM command, or when running in an autovacuum worker
                               2220                 :                :      */
  423 michael@paquier.xyz      2221         [ +  + ]:CBC       16636 :     if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED)
                               2222                 :                :     {
                               2223                 :                :         StdRdOptIndexCleanup vacuum_index_cleanup;
                               2224                 :                : 
    3 nathan@postgresql.or     2225         [ +  + ]:GNC       16489 :         if (relopts == NULL)
   10                          2226                 :          16110 :             vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_NOT_SET;
                               2227                 :                :         else
    3                          2228                 :            379 :             vacuum_index_cleanup = relopts->vacuum_index_cleanup;
                               2229                 :                : 
   10                          2230   [ +  +  +  +  :          16489 :         switch (vacuum_index_cleanup)
                                                 - ]
                               2231                 :                :         {
                               2232                 :             18 :             case STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON:
                               2233                 :             18 :                 params.index_cleanup = VACOPTVALUE_ENABLED;
                               2234                 :             18 :                 break;
                               2235                 :             20 :             case STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF:
                               2236                 :             20 :                 params.index_cleanup = VACOPTVALUE_DISABLED;
                               2237                 :             20 :                 break;
                               2238                 :             12 :             case STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO:
                               2239                 :             12 :                 params.index_cleanup = VACOPTVALUE_AUTO;
                               2240                 :             12 :                 break;
                               2241                 :          16439 :             case STDRD_OPTION_VACUUM_INDEX_CLEANUP_NOT_SET:
                               2242                 :          16439 :                 params.index_cleanup = VACOPTVALUE_AUTO;
                               2243                 :          16439 :                 break;
                               2244                 :                :         }
                               2245                 :                :     }
                               2246                 :                : 
                               2247                 :                : #ifdef USE_INJECTION_POINTS
  423 michael@paquier.xyz      2248         [ +  + ]:CBC       16636 :     if (params.index_cleanup == VACOPTVALUE_AUTO)
  428                          2249                 :          16455 :         INJECTION_POINT("vacuum-index-cleanup-auto", NULL);
  423                          2250         [ +  + ]:            181 :     else if (params.index_cleanup == VACOPTVALUE_DISABLED)
  428                          2251                 :            150 :         INJECTION_POINT("vacuum-index-cleanup-disabled", NULL);
  423                          2252         [ +  - ]:             31 :     else if (params.index_cleanup == VACOPTVALUE_ENABLED)
  428                          2253                 :             31 :         INJECTION_POINT("vacuum-index-cleanup-enabled", NULL);
                               2254                 :                : #endif
                               2255                 :                : 
                               2256                 :                :     /*
                               2257                 :                :      * Check if the vacuum_max_eager_freeze_failure_rate table storage
                               2258                 :                :      * parameter was specified. This overrides the GUC value.
                               2259                 :                :      */
    3 nathan@postgresql.or     2260   [ +  +  -  + ]:GNC       16636 :     if (relopts != NULL && relopts->vacuum_max_eager_freeze_failure_rate >= 0)
    3 nathan@postgresql.or     2261                 :UNC           0 :         params.max_eager_freeze_failure_rate = relopts->vacuum_max_eager_freeze_failure_rate;
                               2262                 :                : 
                               2263                 :                :     /*
                               2264                 :                :      * Set truncate option based on truncate reloption or GUC if it wasn't
                               2265                 :                :      * specified in VACUUM command, or when running in an autovacuum worker
                               2266                 :                :      */
  423 michael@paquier.xyz      2267         [ +  + ]:CBC       16636 :     if (params.truncate == VACOPTVALUE_UNSPECIFIED)
                               2268                 :                :     {
    3 nathan@postgresql.or     2269   [ +  +  +  + ]:GNC       16497 :         if (relopts && relopts->vacuum_truncate != PG_TERNARY_UNSET)
                               2270                 :                :         {
                               2271         [ +  + ]:             27 :             if (relopts->vacuum_truncate == PG_TERNARY_TRUE)
  423 michael@paquier.xyz      2272                 :CBC          11 :                 params.truncate = VACOPTVALUE_ENABLED;
                               2273                 :                :             else
                               2274                 :             16 :                 params.truncate = VACOPTVALUE_DISABLED;
                               2275                 :                :         }
  525 nathan@postgresql.or     2276         [ +  + ]:          16470 :         else if (vacuum_truncate)
  423 michael@paquier.xyz      2277                 :          16460 :             params.truncate = VACOPTVALUE_ENABLED;
                               2278                 :                :         else
                               2279                 :             10 :             params.truncate = VACOPTVALUE_DISABLED;
                               2280                 :                :     }
                               2281                 :                : 
                               2282                 :                : #ifdef USE_INJECTION_POINTS
                               2283         [ -  + ]:          16636 :     if (params.truncate == VACOPTVALUE_AUTO)
  428 michael@paquier.xyz      2284                 :UBC           0 :         INJECTION_POINT("vacuum-truncate-auto", NULL);
  423 michael@paquier.xyz      2285         [ +  + ]:CBC       16636 :     else if (params.truncate == VACOPTVALUE_DISABLED)
  428                          2286                 :            164 :         INJECTION_POINT("vacuum-truncate-disabled", NULL);
  423                          2287         [ +  - ]:          16472 :     else if (params.truncate == VACOPTVALUE_ENABLED)
  428                          2288                 :          16472 :         INJECTION_POINT("vacuum-truncate-enabled", NULL);
                               2289                 :                : #endif
                               2290                 :                : 
                               2291                 :                :     /*
                               2292                 :                :      * Remember the relation's TOAST relation for later, if the caller asked
                               2293                 :                :      * us to process it.  In VACUUM FULL, though, the toast table is
                               2294                 :                :      * automatically rebuilt by cluster_rel so we shouldn't recurse to it,
                               2295                 :                :      * unless PROCESS_MAIN is disabled.
                               2296                 :                :      */
  423                          2297         [ +  + ]:          16636 :     if ((params.options & VACOPT_PROCESS_TOAST) != 0 &&
                               2298         [ +  + ]:          16081 :         ((params.options & VACOPT_FULL) == 0 ||
                               2299         [ +  + ]:            230 :          (params.options & VACOPT_PROCESS_MAIN) == 0))
 1970 pg@bowt.ie               2300                 :          15855 :         toast_relid = rel->rd_rel->reltoastrelid;
                               2301                 :                :     else
 6588 alvherre@alvh.no-ip.     2302                 :            781 :         toast_relid = InvalidOid;
                               2303                 :                : 
                               2304                 :                :     /*
                               2305                 :                :      * Hand our storage parameters down for the TOAST table to inherit.  Take
                               2306                 :                :      * a copy while we still have the relation open; the relcache entry can go
                               2307                 :                :      * away once we close it.
                               2308                 :                :      */
    3 nathan@postgresql.or     2309   [ +  +  +  + ]:GNC       16636 :     if (OidIsValid(toast_relid) && rel->rd_options)
                               2310                 :                :     {
                               2311                 :            124 :         memcpy(&relopts_copy, rel->rd_options, sizeof(StdRdOptions));
                               2312                 :            124 :         toast_vacuum_params.main_relopts = &relopts_copy;
                               2313                 :                :     }
                               2314                 :                : 
                               2315                 :                :     /*
                               2316                 :                :      * Switch to the table owner's userid, so that any index functions are run
                               2317                 :                :      * as that user.  Also lock down security-restricted operations and
                               2318                 :                :      * arrange to make GUC variable changes local to this command. (This is
                               2319                 :                :      * unnecessary, but harmless, for lazy VACUUM.)
                               2320                 :                :      */
 6105 tgl@sss.pgh.pa.us        2321                 :CBC       16636 :     GetUserIdAndSecContext(&save_userid, &save_sec_context);
 1970 pg@bowt.ie               2322                 :          16636 :     SetUserIdAndSecContext(rel->rd_rel->relowner,
                               2323                 :                :                            save_sec_context | SECURITY_RESTRICTED_OPERATION);
 6105 tgl@sss.pgh.pa.us        2324                 :          16636 :     save_nestlevel = NewGUCNestLevel();
  906 jdavis@postgresql.or     2325                 :          16636 :     RestrictSearchPath();
                               2326                 :                : 
                               2327                 :                :     /*
                               2328                 :                :      * If PROCESS_MAIN is set (the default), it's time to vacuum the main
                               2329                 :                :      * relation.  Otherwise, we can skip this part.  If processing the TOAST
                               2330                 :                :      * table is required (e.g., PROCESS_TOAST is set), we force PROCESS_MAIN
                               2331                 :                :      * to be set when we recurse to the TOAST table.
                               2332                 :                :      */
  423 michael@paquier.xyz      2333         [ +  + ]:          16636 :     if (params.options & VACOPT_PROCESS_MAIN)
                               2334                 :                :     {
                               2335                 :                :         /*
                               2336                 :                :          * Do the actual work --- either FULL or "lazy" vacuum
                               2337                 :                :          */
                               2338         [ +  + ]:          16551 :         if (params.options & VACOPT_FULL)
                               2339                 :                :         {
 1268                          2340                 :            226 :             ClusterParams cluster_params = {0};
                               2341                 :                : 
  423                          2342         [ +  + ]:            226 :             if ((params.options & VACOPT_VERBOSE) != 0)
 1268                          2343                 :              1 :                 cluster_params.options |= CLUOPT_VERBOSE;
                               2344                 :                : 
                               2345                 :                :             /* VACUUM FULL is a variant of REPACK; see repack.c */
  170 alvherre@kurilemu.de     2346                 :            226 :             cluster_rel(REPACK_COMMAND_VACUUMFULL, rel, InvalidOid,
                               2347                 :                :                         &cluster_params, isTopLevel);
                               2348                 :                :             /* cluster_rel closes the relation, but keeps lock */
                               2349                 :                : 
  594 alvherre@alvh.no-ip.     2350                 :            222 :             rel = NULL;
                               2351                 :                :         }
                               2352                 :                :         else
  149 nathan@postgresql.or     2353                 :          16325 :             table_relation_vacuum(rel, &params, bstrategy);
                               2354                 :                :     }
                               2355                 :                : 
                               2356                 :                :     /* Roll back any GUC changes executed by index functions */
 6105 tgl@sss.pgh.pa.us        2357                 :          16630 :     AtEOXact_GUC(false, save_nestlevel);
                               2358                 :                : 
                               2359                 :                :     /* Restore userid and security context */
                               2360                 :          16630 :     SetUserIdAndSecContext(save_userid, save_sec_context);
                               2361                 :                : 
                               2362                 :                :     /* all done with this class, but hold lock until commit */
 1970 pg@bowt.ie               2363         [ +  + ]:          16630 :     if (rel)
                               2364                 :          16408 :         relation_close(rel, NoLock);
                               2365                 :                : 
                               2366                 :                :     /*
                               2367                 :                :      * Complete the transaction and free all temporary memory used.
                               2368                 :                :      */
 6559 alvherre@alvh.no-ip.     2369                 :          16630 :     PopActiveSnapshot();
 8506 tgl@sss.pgh.pa.us        2370                 :          16630 :     CommitTransactionCommand();
                               2371                 :                : 
                               2372                 :                :     /*
                               2373                 :                :      * If the relation has a secondary toast rel, vacuum that too while we
                               2374                 :                :      * still hold the session lock on the main table.  Note however that
                               2375                 :                :      * "analyze" will not get done on the toast table.  This is good, because
                               2376                 :                :      * the toaster always uses hardcoded index access and statistics are
                               2377                 :                :      * totally unimportant for toast relations.
                               2378                 :                :      */
 9177                          2379         [ +  + ]:          16630 :     if (toast_relid != InvalidOid)
                               2380                 :                :     {
                               2381                 :                :         /*
                               2382                 :                :          * Force VACOPT_PROCESS_MAIN so vacuum_rel() processes it.  Likewise,
                               2383                 :                :          * set toast_parent so that the privilege checks are done on the main
                               2384                 :                :          * relation.  NB: This is only safe to do because we hold a session
                               2385                 :                :          * lock on the main relation that prevents concurrent deletion.
                               2386                 :                :          */
 1270 michael@paquier.xyz      2387                 :           5526 :         toast_vacuum_params.options |= VACOPT_PROCESS_MAIN;
  897 nathan@postgresql.or     2388                 :           5526 :         toast_vacuum_params.toast_parent = relid;
                               2389                 :                : 
  143 alvherre@kurilemu.de     2390                 :           5526 :         vacuum_rel(toast_relid, NULL, toast_vacuum_params, bstrategy,
                               2391                 :                :                    isTopLevel);
                               2392                 :                :     }
                               2393                 :                : 
                               2394                 :                :     /*
                               2395                 :                :      * Now release the session-level lock on the main table.
                               2396                 :                :      */
 1970 pg@bowt.ie               2397                 :          16630 :     UnlockRelationIdForSession(&lockrelid, lmode);
                               2398                 :                : 
                               2399                 :                :     /* Report that we really did it. */
 5680 rhaas@postgresql.org     2400                 :          16630 :     return true;
                               2401                 :                : }
                               2402                 :                : 
                               2403                 :                : 
                               2404                 :                : /*
                               2405                 :                :  * Open all the vacuumable indexes of the given relation, obtaining the
                               2406                 :                :  * specified kind of lock on each.  Return an array of Relation pointers for
                               2407                 :                :  * the indexes into *Irel, and the number of indexes into *nindexes.
                               2408                 :                :  *
                               2409                 :                :  * We consider an index vacuumable if it is marked insertable (indisready).
                               2410                 :                :  * If it isn't, probably a CREATE INDEX CONCURRENTLY command failed early in
                               2411                 :                :  * execution, and what we have is too corrupt to be processable.  We will
                               2412                 :                :  * vacuum even if the index isn't indisvalid; this is important because in a
                               2413                 :                :  * unique index, uniqueness checks will be performed anyway and had better not
                               2414                 :                :  * hit dangling index pointers.
                               2415                 :                :  */
                               2416                 :                : void
 6044 tgl@sss.pgh.pa.us        2417                 :          26561 : vac_open_indexes(Relation relation, LOCKMODE lockmode,
                               2418                 :                :                  int *nindexes, Relation **Irel)
                               2419                 :                : {
                               2420                 :                :     List       *indexoidlist;
                               2421                 :                :     ListCell   *indexoidscan;
                               2422                 :                :     int         i;
                               2423                 :                : 
                               2424         [ -  + ]:          26561 :     Assert(lockmode != NoLock);
                               2425                 :                : 
                               2426                 :          26561 :     indexoidlist = RelationGetIndexList(relation);
                               2427                 :                : 
                               2428                 :                :     /* allocate enough memory for all indexes */
 5020                          2429                 :          26561 :     i = list_length(indexoidlist);
                               2430                 :                : 
                               2431         [ +  + ]:          26561 :     if (i > 0)
   10 michael@paquier.xyz      2432                 :GNC       22813 :         *Irel = palloc_array(Relation, i);
                               2433                 :                :     else
 6044 tgl@sss.pgh.pa.us        2434                 :CBC        3748 :         *Irel = NULL;
                               2435                 :                : 
                               2436                 :                :     /* collect just the ready indexes */
                               2437                 :          26561 :     i = 0;
                               2438   [ +  +  +  +  :          65281 :     foreach(indexoidscan, indexoidlist)
                                              +  + ]
                               2439                 :                :     {
                               2440                 :          38720 :         Oid         indexoid = lfirst_oid(indexoidscan);
                               2441                 :                :         Relation    indrel;
                               2442                 :                : 
 5020                          2443                 :          38720 :         indrel = index_open(indexoid, lockmode);
 2800 peter_e@gmx.net          2444         [ +  - ]:          38720 :         if (indrel->rd_index->indisready)
 5020 tgl@sss.pgh.pa.us        2445                 :          38720 :             (*Irel)[i++] = indrel;
                               2446                 :                :         else
 5020 tgl@sss.pgh.pa.us        2447                 :UBC           0 :             index_close(indrel, lockmode);
                               2448                 :                :     }
                               2449                 :                : 
 5020 tgl@sss.pgh.pa.us        2450                 :CBC       26561 :     *nindexes = i;
                               2451                 :                : 
 6044                          2452                 :          26561 :     list_free(indexoidlist);
 9586 bruce@momjian.us         2453                 :          26561 : }
                               2454                 :                : 
                               2455                 :                : /*
                               2456                 :                :  * Release the resources acquired by vac_open_indexes.  Optionally release
                               2457                 :                :  * the locks (say NoLock to keep 'em).
                               2458                 :                :  */
                               2459                 :                : void
 6044 tgl@sss.pgh.pa.us        2460                 :          27155 : vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode)
                               2461                 :                : {
                               2462         [ +  + ]:          27155 :     if (Irel == NULL)
                               2463                 :           4349 :         return;
                               2464                 :                : 
                               2465         [ +  + ]:          61509 :     while (nindexes--)
                               2466                 :                :     {
                               2467                 :          38703 :         Relation    ind = Irel[nindexes];
                               2468                 :                : 
 7332                          2469                 :          38703 :         index_close(ind, lockmode);
                               2470                 :                :     }
10581 bruce@momjian.us         2471                 :          22806 :     pfree(Irel);
                               2472                 :                : }
                               2473                 :                : 
                               2474                 :                : /*
                               2475                 :                :  * vacuum_delay_point --- check for interrupts and cost-based delay.
                               2476                 :                :  *
                               2477                 :                :  * This should be called in each major loop of VACUUM processing,
                               2478                 :                :  * typically once per page processed.
                               2479                 :                :  */
                               2480                 :                : void
  562 nathan@postgresql.or     2481                 :       61917467 : vacuum_delay_point(bool is_analyze)
                               2482                 :                : {
 2411 akapila@postgresql.o     2483                 :       61917467 :     double      msec = 0;
                               2484                 :                : 
                               2485                 :                :     /* Always check for interrupts */
 8234 tgl@sss.pgh.pa.us        2486         [ +  + ]:       61917467 :     CHECK_FOR_INTERRUPTS();
                               2487                 :                : 
  143 msawada@postgresql.o     2488         [ +  + ]:       61917464 :     if (InterruptPending)
  143 msawada@postgresql.o     2489                 :GBC           2 :         return;
                               2490                 :                : 
  143 msawada@postgresql.o     2491         [ +  + ]:CBC    61917462 :     if (IsParallelWorker())
                               2492                 :                :     {
                               2493                 :                :         /*
                               2494                 :                :          * Update cost-based vacuum delay parameters for a parallel autovacuum
                               2495                 :                :          * worker if any changes are detected. It might enable cost-based
                               2496                 :                :          * delay so it needs to be called before VacuumCostActive check.
                               2497                 :                :          */
                               2498                 :            337 :         parallel_vacuum_update_shared_delay_params();
                               2499                 :                :     }
                               2500                 :                : 
                               2501   [ +  +  +  - ]:       61917462 :     if (!VacuumCostActive && !ConfigReloadPending)
 1238 dgustafsson@postgres     2502                 :       46624486 :         return;
                               2503                 :                : 
                               2504                 :                :     /*
                               2505                 :                :      * Autovacuum workers should reload the configuration file if requested.
                               2506                 :                :      * This allows changes to [autovacuum_]vacuum_cost_limit and
                               2507                 :                :      * [autovacuum_]vacuum_cost_delay to take effect while a table is being
                               2508                 :                :      * vacuumed or analyzed.
                               2509                 :                :      */
  906 heikki.linnakangas@i     2510   [ +  +  +  - ]:       15292976 :     if (ConfigReloadPending && AmAutoVacuumWorkerProcess())
                               2511                 :                :     {
 1238 dgustafsson@postgres     2512                 :              1 :         ConfigReloadPending = false;
                               2513                 :              1 :         ProcessConfigFile(PGC_SIGHUP);
                               2514                 :              1 :         VacuumUpdateCosts();
                               2515                 :                : 
                               2516                 :                :         /*
                               2517                 :                :          * Propagate cost-based vacuum delay parameters to shared memory if
                               2518                 :                :          * any of them have changed during the config reload.
                               2519                 :                :          */
  143 msawada@postgresql.o     2520                 :              1 :         parallel_vacuum_propagate_shared_delay_params();
                               2521                 :                :     }
                               2522                 :                : 
                               2523                 :                :     /*
                               2524                 :                :      * If we disabled cost-based delays after reloading the config file,
                               2525                 :                :      * return.
                               2526                 :                :      */
 1238 dgustafsson@postgres     2527         [ -  + ]:       15292976 :     if (!VacuumCostActive)
 2411 akapila@postgresql.o     2528                 :UBC           0 :         return;
                               2529                 :                : 
                               2530                 :                :     /*
                               2531                 :                :      * For parallel vacuum, the delay is computed based on the shared cost
                               2532                 :                :      * balance.  See compute_parallel_delay.
                               2533                 :                :      */
 2411 akapila@postgresql.o     2534         [ +  + ]:CBC    15292976 :     if (VacuumSharedCostBalance != NULL)
                               2535                 :            355 :         msec = compute_parallel_delay();
 1238 dgustafsson@postgres     2536         [ +  + ]:       15292621 :     else if (VacuumCostBalance >= vacuum_cost_limit)
                               2537                 :           2526 :         msec = vacuum_cost_delay * VacuumCostBalance / vacuum_cost_limit;
                               2538                 :                : 
                               2539                 :                :     /* Nap if appropriate */
 2411 akapila@postgresql.o     2540         [ +  + ]:       15292976 :     if (msec > 0)
                               2541                 :                :     {
                               2542                 :                :         instr_time  delay_start;
                               2543                 :                : 
 1238 dgustafsson@postgres     2544         [ +  + ]:           2546 :         if (msec > vacuum_cost_delay * 4)
                               2545                 :             28 :             msec = vacuum_cost_delay * 4;
                               2546                 :                : 
  562 nathan@postgresql.or     2547         [ -  + ]:           2546 :         if (track_cost_delay_timing)
  562 nathan@postgresql.or     2548                 :UBC           0 :             INSTR_TIME_SET_CURRENT(delay_start);
                               2549                 :                : 
 1261 tmunro@postgresql.or     2550                 :CBC        2546 :         pgstat_report_wait_start(WAIT_EVENT_VACUUM_DELAY);
                               2551                 :           2546 :         pg_usleep(msec * 1000);
                               2552                 :           2546 :         pgstat_report_wait_end();
                               2553                 :                : 
  562 nathan@postgresql.or     2554         [ -  + ]:           2546 :         if (track_cost_delay_timing)
                               2555                 :                :         {
                               2556                 :                :             instr_time  delay_end;
                               2557                 :                :             instr_time  delay;
                               2558                 :                : 
  562 nathan@postgresql.or     2559                 :UBC           0 :             INSTR_TIME_SET_CURRENT(delay_end);
                               2560                 :              0 :             INSTR_TIME_SET_ZERO(delay);
                               2561                 :              0 :             INSTR_TIME_ACCUM_DIFF(delay, delay_end, delay_start);
                               2562                 :                : 
                               2563                 :                :             /*
                               2564                 :                :              * For parallel workers, we only report the delay time every once
                               2565                 :                :              * in a while to avoid overloading the leader with messages and
                               2566                 :                :              * interrupts.
                               2567                 :                :              */
                               2568         [ #  # ]:              0 :             if (IsParallelWorker())
                               2569                 :                :             {
                               2570                 :                :                 static instr_time last_report_time;
                               2571                 :                :                 instr_time  time_since_last_report;
                               2572                 :                : 
                               2573         [ #  # ]:              0 :                 Assert(!is_analyze);
                               2574                 :                : 
                               2575                 :                :                 /* Accumulate the delay time */
                               2576                 :              0 :                 parallel_vacuum_worker_delay_ns += INSTR_TIME_GET_NANOSEC(delay);
                               2577                 :                : 
                               2578                 :                :                 /* Calculate interval since last report */
                               2579                 :              0 :                 INSTR_TIME_SET_ZERO(time_since_last_report);
                               2580                 :              0 :                 INSTR_TIME_ACCUM_DIFF(time_since_last_report, delay_end, last_report_time);
                               2581                 :                : 
                               2582                 :                :                 /* If we haven't reported in a while, do so now */
                               2583         [ #  # ]:              0 :                 if (INSTR_TIME_GET_NANOSEC(time_since_last_report) >=
                               2584                 :                :                     PARALLEL_VACUUM_DELAY_REPORT_INTERVAL_NS)
                               2585                 :                :                 {
                               2586                 :              0 :                     pgstat_progress_parallel_incr_param(PROGRESS_VACUUM_DELAY_TIME,
                               2587                 :                :                                                         parallel_vacuum_worker_delay_ns);
                               2588                 :                : 
                               2589                 :                :                     /* Reset variables */
                               2590                 :              0 :                     last_report_time = delay_end;
                               2591                 :              0 :                     parallel_vacuum_worker_delay_ns = 0;
                               2592                 :                :                 }
                               2593                 :                :             }
                               2594         [ #  # ]:              0 :             else if (is_analyze)
                               2595                 :              0 :                 pgstat_progress_incr_param(PROGRESS_ANALYZE_DELAY_TIME,
                               2596                 :                :                                            INSTR_TIME_GET_NANOSEC(delay));
                               2597                 :                :             else
                               2598                 :              0 :                 pgstat_progress_incr_param(PROGRESS_VACUUM_DELAY_TIME,
                               2599                 :                :                                            INSTR_TIME_GET_NANOSEC(delay));
                               2600                 :                :         }
                               2601                 :                : 
                               2602                 :                :         /*
                               2603                 :                :          * We don't want to ignore postmaster death during very long vacuums
                               2604                 :                :          * with vacuum_cost_delay configured.  We can't use the usual
                               2605                 :                :          * WaitLatch() approach here because we want microsecond-based sleep
                               2606                 :                :          * durations above.
                               2607                 :                :          */
 1261 tmunro@postgresql.or     2608   [ +  -  -  + ]:CBC        2546 :         if (IsUnderPostmaster && !PostmasterIsAlive())
 1261 tmunro@postgresql.or     2609                 :UBC           0 :             exit(1);
                               2610                 :                : 
 8234 tgl@sss.pgh.pa.us        2611                 :CBC        2546 :         VacuumCostBalance = 0;
                               2612                 :                : 
                               2613                 :                :         /*
                               2614                 :                :          * Balance and update limit values for autovacuum workers. We must do
                               2615                 :                :          * this periodically, as the number of workers across which we are
                               2616                 :                :          * balancing the limit may have changed.
                               2617                 :                :          *
                               2618                 :                :          * TODO: There may be better criteria for determining when to do this
                               2619                 :                :          * besides "check after napping".
                               2620                 :                :          */
 1238 dgustafsson@postgres     2621                 :           2546 :         AutoVacuumUpdateCostLimit();
                               2622                 :                : 
                               2623                 :                :         /* Might have gotten an interrupt while sleeping */
 8234 tgl@sss.pgh.pa.us        2624         [ -  + ]:           2546 :         CHECK_FOR_INTERRUPTS();
                               2625                 :                :     }
                               2626                 :                : }
                               2627                 :                : 
                               2628                 :                : /*
                               2629                 :                :  * Computes the vacuum delay for parallel workers.
                               2630                 :                :  *
                               2631                 :                :  * The basic idea of a cost-based delay for parallel vacuum is to allow each
                               2632                 :                :  * worker to sleep in proportion to the share of work it's done.  We achieve this
                               2633                 :                :  * by allowing all parallel vacuum workers including the leader process to
                               2634                 :                :  * have a shared view of cost related parameters (mainly VacuumCostBalance).
                               2635                 :                :  * We allow each worker to update it as and when it has incurred any cost and
                               2636                 :                :  * then based on that decide whether it needs to sleep.  We compute the time
                               2637                 :                :  * to sleep for a worker based on the cost it has incurred
                               2638                 :                :  * (VacuumCostBalanceLocal) and then reduce the VacuumSharedCostBalance by
                               2639                 :                :  * that amount.  This avoids putting to sleep those workers which have done less
                               2640                 :                :  * I/O than other workers and therefore ensure that workers
                               2641                 :                :  * which are doing more I/O got throttled more.
                               2642                 :                :  *
                               2643                 :                :  * We allow a worker to sleep only if it has performed I/O above a certain
                               2644                 :                :  * threshold, which is calculated based on the number of active workers
                               2645                 :                :  * (VacuumActiveNWorkers), and the overall cost balance is more than
                               2646                 :                :  * VacuumCostLimit set by the system.  Testing reveals that we achieve
                               2647                 :                :  * the required throttling if we force a worker that has done more than 50%
                               2648                 :                :  * of its share of work to sleep.
                               2649                 :                :  */
                               2650                 :                : static double
 2411 akapila@postgresql.o     2651                 :            355 : compute_parallel_delay(void)
                               2652                 :                : {
                               2653                 :            355 :     double      msec = 0;
                               2654                 :                :     uint32      shared_balance;
                               2655                 :                :     int         nworkers;
                               2656                 :                : 
                               2657                 :                :     /* Parallel vacuum must be active */
                               2658         [ -  + ]:            355 :     Assert(VacuumSharedCostBalance);
                               2659                 :                : 
                               2660                 :            355 :     nworkers = pg_atomic_read_u32(VacuumActiveNWorkers);
                               2661                 :                : 
                               2662                 :                :     /* At least count itself */
                               2663         [ -  + ]:            355 :     Assert(nworkers >= 1);
                               2664                 :                : 
                               2665                 :                :     /* Update the shared cost balance value atomically */
                               2666                 :            355 :     shared_balance = pg_atomic_add_fetch_u32(VacuumSharedCostBalance, VacuumCostBalance);
                               2667                 :                : 
                               2668                 :                :     /* Compute the total local balance for the current worker */
                               2669                 :            355 :     VacuumCostBalanceLocal += VacuumCostBalance;
                               2670                 :                : 
 1238 dgustafsson@postgres     2671         [ +  + ]:            355 :     if ((shared_balance >= vacuum_cost_limit) &&
                               2672         [ +  + ]:             79 :         (VacuumCostBalanceLocal > 0.5 * ((double) vacuum_cost_limit / nworkers)))
                               2673                 :                :     {
                               2674                 :                :         /* Compute sleep time based on the local cost balance */
                               2675                 :             20 :         msec = vacuum_cost_delay * VacuumCostBalanceLocal / vacuum_cost_limit;
 2411 akapila@postgresql.o     2676                 :             20 :         pg_atomic_sub_fetch_u32(VacuumSharedCostBalance, VacuumCostBalanceLocal);
                               2677                 :             20 :         VacuumCostBalanceLocal = 0;
                               2678                 :                :     }
                               2679                 :                : 
                               2680                 :                :     /*
                               2681                 :                :      * Reset the local balance as we accumulated it into the shared value.
                               2682                 :                :      */
                               2683                 :            355 :     VacuumCostBalance = 0;
                               2684                 :                : 
                               2685                 :            355 :     return msec;
                               2686                 :                : }
                               2687                 :                : 
                               2688                 :                : /*
                               2689                 :                :  * A wrapper function of defGetBoolean().
                               2690                 :                :  *
                               2691                 :                :  * This function returns VACOPTVALUE_ENABLED and VACOPTVALUE_DISABLED instead
                               2692                 :                :  * of true and false.
                               2693                 :                :  */
                               2694                 :                : static VacOptValue
 1896 pg@bowt.ie               2695                 :            184 : get_vacoptval_from_boolean(DefElem *def)
                               2696                 :                : {
                               2697         [ +  + ]:            184 :     return defGetBoolean(def) ? VACOPTVALUE_ENABLED : VACOPTVALUE_DISABLED;
                               2698                 :                : }
                               2699                 :                : 
                               2700                 :                : /*
                               2701                 :                :  *  vac_bulkdel_one_index() -- bulk-deletion for index relation.
                               2702                 :                :  *
                               2703                 :                :  * Returns bulk delete stats derived from input stats
                               2704                 :                :  */
                               2705                 :                : IndexBulkDeleteResult *
 1709 akapila@postgresql.o     2706                 :           2086 : vac_bulkdel_one_index(IndexVacuumInfo *ivinfo, IndexBulkDeleteResult *istat,
                               2707                 :                :                       TidStore *dead_items, VacDeadItemsInfo *dead_items_info)
                               2708                 :                : {
                               2709                 :                :     /* Do bulk deletion */
                               2710                 :           2086 :     istat = index_bulk_delete(ivinfo, istat, vac_tid_reaped,
                               2711                 :                :                               dead_items);
                               2712                 :                : 
                               2713         [ +  + ]:           2083 :     ereport(ivinfo->message_level,
                               2714                 :                :             (errmsg("scanned index \"%s\" to remove %" PRId64 " row versions",
                               2715                 :                :                     RelationGetRelationName(ivinfo->index),
                               2716                 :                :                     dead_items_info->num_items)));
                               2717                 :                : 
                               2718                 :           2083 :     return istat;
                               2719                 :                : }
                               2720                 :                : 
                               2721                 :                : /*
                               2722                 :                :  *  vac_cleanup_one_index() -- do post-vacuum cleanup for index relation.
                               2723                 :                :  *
                               2724                 :                :  * Returns bulk delete stats derived from input stats
                               2725                 :                :  */
                               2726                 :                : IndexBulkDeleteResult *
                               2727                 :          23383 : vac_cleanup_one_index(IndexVacuumInfo *ivinfo, IndexBulkDeleteResult *istat)
                               2728                 :                : {
                               2729                 :          23383 :     istat = index_vacuum_cleanup(ivinfo, istat);
                               2730                 :                : 
                               2731         [ +  + ]:          23383 :     if (istat)
                               2732         [ +  + ]:           2277 :         ereport(ivinfo->message_level,
                               2733                 :                :                 (errmsg("index \"%s\" now contains %.0f row versions in %u pages",
                               2734                 :                :                         RelationGetRelationName(ivinfo->index),
                               2735                 :                :                         istat->num_index_tuples,
                               2736                 :                :                         istat->num_pages),
                               2737                 :                :                  errdetail("%.0f index row versions were removed.\n"
                               2738                 :                :                            "%u index pages were newly deleted.\n"
                               2739                 :                :                            "%u index pages are currently deleted, of which %u are currently reusable.",
                               2740                 :                :                            istat->tuples_removed,
                               2741                 :                :                            istat->pages_newly_deleted,
                               2742                 :                :                            istat->pages_deleted, istat->pages_free)));
                               2743                 :                : 
                               2744                 :          23383 :     return istat;
                               2745                 :                : }
                               2746                 :                : 
                               2747                 :                : /*
                               2748                 :                :  *  vac_tid_reaped() -- is a particular tid deletable?
                               2749                 :                :  *
                               2750                 :                :  *      This has the right signature to be an IndexBulkDeleteCallback.
                               2751                 :                :  */
                               2752                 :                : static bool
                               2753                 :        5981066 : vac_tid_reaped(ItemPointer itemptr, void *state)
                               2754                 :                : {
  877 msawada@postgresql.o     2755                 :        5981066 :     TidStore   *dead_items = (TidStore *) state;
                               2756                 :                : 
                               2757                 :        5981066 :     return TidStoreIsMember(dead_items, itemptr);
                               2758                 :                : }
        

Generated by: LCOV version 2.0-1