PostgreSQL Source Code  git master
vacuum.h File Reference
#include "access/htup.h"
#include "catalog/pg_class.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "parser/parse_node.h"
#include "storage/buf.h"
#include "storage/lock.h"
#include "utils/relcache.h"
Include dependency graph for vacuum.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  VacAttrStats
 
struct  VacuumParams
 

Macros

#define VACUUM_OPTION_NO_PARALLEL   0
 
#define VACUUM_OPTION_PARALLEL_BULKDEL   (1 << 0)
 
#define VACUUM_OPTION_PARALLEL_COND_CLEANUP   (1 << 1)
 
#define VACUUM_OPTION_PARALLEL_CLEANUP   (1 << 2)
 
#define VACUUM_OPTION_MAX_VALID_VALUE   ((1 << 3) - 1)
 
#define VACOPT_VACUUM   0x01 /* do VACUUM */
 
#define VACOPT_ANALYZE   0x02 /* do ANALYZE */
 
#define VACOPT_VERBOSE   0x04 /* print progress info */
 
#define VACOPT_FREEZE   0x08 /* FREEZE option */
 
#define VACOPT_FULL   0x10 /* FULL (non-concurrent) vacuum */
 
#define VACOPT_SKIP_LOCKED   0x20 /* skip if cannot get lock */
 
#define VACOPT_PROCESS_TOAST   0x40 /* process the TOAST table, if any */
 
#define VACOPT_DISABLE_PAGE_SKIPPING   0x80 /* don't skip any pages */
 

Typedefs

typedef struct VacAttrStatsVacAttrStatsP
 
typedef Datum(* AnalyzeAttrFetchFunc) (VacAttrStatsP stats, int rownum, bool *isNull)
 
typedef void(* AnalyzeAttrComputeStatsFunc) (VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
 
typedef struct VacAttrStats VacAttrStats
 
typedef enum VacOptValue VacOptValue
 
typedef struct VacuumParams VacuumParams
 

Enumerations

enum  VacOptValue { VACOPTVALUE_UNSPECIFIED = 0, VACOPTVALUE_AUTO, VACOPTVALUE_DISABLED, VACOPTVALUE_ENABLED }
 

Functions

void ExecVacuum (ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
 
void vacuum (List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel)
 
void vac_open_indexes (Relation relation, LOCKMODE lockmode, int *nindexes, Relation **Irel)
 
void vac_close_indexes (int nindexes, Relation *Irel, LOCKMODE lockmode)
 
double vac_estimate_reltuples (Relation relation, BlockNumber total_pages, BlockNumber scanned_pages, double scanned_tuples)
 
void vac_update_relstats (Relation relation, BlockNumber num_pages, double num_tuples, BlockNumber num_all_visible_pages, bool hasindex, TransactionId frozenxid, MultiXactId minmulti, bool in_outer_xact)
 
void vacuum_set_xid_limits (Relation rel, int freeze_min_age, int freeze_table_age, int multixact_freeze_min_age, int multixact_freeze_table_age, TransactionId *oldestXmin, TransactionId *freezeLimit, TransactionId *xidFullScanLimit, MultiXactId *multiXactCutoff, MultiXactId *mxactFullScanLimit)
 
bool vacuum_xid_failsafe_check (TransactionId relfrozenxid, MultiXactId relminmxid)
 
void vac_update_datfrozenxid (void)
 
void vacuum_delay_point (void)
 
bool vacuum_is_relation_owner (Oid relid, Form_pg_class reltuple, bits32 options)
 
Relation vacuum_open_relation (Oid relid, RangeVar *relation, bits32 options, bool verbose, LOCKMODE lmode)
 
void analyze_rel (Oid relid, RangeVar *relation, VacuumParams *params, List *va_cols, bool in_outer_xact, BufferAccessStrategy bstrategy)
 
bool std_typanalyze (VacAttrStats *stats)
 
double anl_random_fract (void)
 
double anl_init_selection_state (int n)
 
double anl_get_next_S (double t, int n, double *stateptr)
 

Variables

PGDLLIMPORT int default_statistics_target
 
int vacuum_freeze_min_age
 
int vacuum_freeze_table_age
 
int vacuum_multixact_freeze_min_age
 
int vacuum_multixact_freeze_table_age
 
int vacuum_failsafe_age
 
int vacuum_multixact_failsafe_age
 
pg_atomic_uint32VacuumSharedCostBalance
 
pg_atomic_uint32VacuumActiveNWorkers
 
int VacuumCostBalanceLocal
 

Macro Definition Documentation

◆ VACOPT_ANALYZE

#define VACOPT_ANALYZE   0x02 /* do ANALYZE */

◆ VACOPT_DISABLE_PAGE_SKIPPING

#define VACOPT_DISABLE_PAGE_SKIPPING   0x80 /* don't skip any pages */

Definition at line 185 of file vacuum.h.

Referenced by ExecVacuum(), heap_vacuum_rel(), lazy_scan_heap(), and vacuum().

◆ VACOPT_FREEZE

#define VACOPT_FREEZE   0x08 /* FREEZE option */

Definition at line 181 of file vacuum.h.

Referenced by ExecVacuum().

◆ VACOPT_FULL

#define VACOPT_FULL   0x10 /* FULL (non-concurrent) vacuum */

Definition at line 182 of file vacuum.h.

Referenced by ExecVacuum(), vacuum(), and vacuum_rel().

◆ VACOPT_PROCESS_TOAST

#define VACOPT_PROCESS_TOAST   0x40 /* process the TOAST table, if any */

Definition at line 184 of file vacuum.h.

Referenced by ExecVacuum(), vacuum(), and vacuum_rel().

◆ VACOPT_SKIP_LOCKED

#define VACOPT_SKIP_LOCKED   0x20 /* skip if cannot get lock */

◆ VACOPT_VACUUM

◆ VACOPT_VERBOSE

#define VACOPT_VERBOSE   0x04 /* print progress info */

Definition at line 180 of file vacuum.h.

Referenced by analyze_rel(), ExecVacuum(), heap_vacuum_rel(), and vacuum_rel().

◆ VACUUM_OPTION_MAX_VALID_VALUE

#define VACUUM_OPTION_MAX_VALID_VALUE   ((1 << 3) - 1)

Definition at line 63 of file vacuum.h.

Referenced by begin_parallel_vacuum().

◆ VACUUM_OPTION_NO_PARALLEL

#define VACUUM_OPTION_NO_PARALLEL   0

Definition at line 39 of file vacuum.h.

Referenced by compute_parallel_vacuum_workers(), and dihandler().

◆ VACUUM_OPTION_PARALLEL_BULKDEL

#define VACUUM_OPTION_PARALLEL_BULKDEL   (1 << 0)

◆ VACUUM_OPTION_PARALLEL_CLEANUP

#define VACUUM_OPTION_PARALLEL_CLEANUP   (1 << 2)

◆ VACUUM_OPTION_PARALLEL_COND_CLEANUP

#define VACUUM_OPTION_PARALLEL_COND_CLEANUP   (1 << 1)

Typedef Documentation

◆ AnalyzeAttrComputeStatsFunc

typedef void(* AnalyzeAttrComputeStatsFunc) (VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)

Definition at line 105 of file vacuum.h.

◆ AnalyzeAttrFetchFunc

typedef Datum(* AnalyzeAttrFetchFunc) (VacAttrStatsP stats, int rownum, bool *isNull)

Definition at line 102 of file vacuum.h.

◆ VacAttrStats

typedef struct VacAttrStats VacAttrStats

◆ VacAttrStatsP

typedef struct VacAttrStats* VacAttrStatsP

Definition at line 100 of file vacuum.h.

◆ VacOptValue

typedef enum VacOptValue VacOptValue

◆ VacuumParams

typedef struct VacuumParams VacuumParams

Enumeration Type Documentation

◆ VacOptValue

Enumerator
VACOPTVALUE_UNSPECIFIED 
VACOPTVALUE_AUTO 
VACOPTVALUE_DISABLED 
VACOPTVALUE_ENABLED 

Definition at line 195 of file vacuum.h.

Function Documentation

◆ analyze_rel()

void analyze_rel ( Oid  relid,
RangeVar relation,
VacuumParams params,
List va_cols,
bool  in_outer_xact,
BufferAccessStrategy  bstrategy 
)

Definition at line 120 of file analyze.c.

References acquire_sample_rows(), FdwRoutine::AnalyzeForeignTable, CHECK_FOR_INTERRUPTS, DEBUG2, do_analyze_rel(), elevel, ereport, errmsg(), GetFdwRoutineForRelation(), INFO, VacuumParams::log_min_duration, NoLock, VacuumParams::options, pgstat_progress_end_command(), pgstat_progress_start_command(), PROGRESS_COMMAND_ANALYZE, RelationData::rd_rel, relation_close(), RELATION_IS_OTHER_TEMP, RelationGetNumberOfBlocks, RelationGetRelationName, RelationGetRelid, ShareUpdateExclusiveLock, VACOPT_ANALYZE, VACOPT_VACUUM, VACOPT_VERBOSE, vacuum_is_relation_owner(), vacuum_open_relation(), and WARNING.

Referenced by vacuum().

123 {
124  Relation onerel;
125  int elevel;
126  AcquireSampleRowsFunc acquirefunc = NULL;
127  BlockNumber relpages = 0;
128 
129  /* Select logging level */
130  if (params->options & VACOPT_VERBOSE)
131  elevel = INFO;
132  else
133  elevel = DEBUG2;
134 
135  /* Set up static variables */
136  vac_strategy = bstrategy;
137 
138  /*
139  * Check for user-requested abort.
140  */
142 
143  /*
144  * Open the relation, getting ShareUpdateExclusiveLock to ensure that two
145  * ANALYZEs don't run on it concurrently. (This also locks out a
146  * concurrent VACUUM, which doesn't matter much at the moment but might
147  * matter if we ever try to accumulate stats on dead tuples.) If the rel
148  * has been dropped since we last saw it, we don't need to process it.
149  *
150  * Make sure to generate only logs for ANALYZE in this case.
151  */
152  onerel = vacuum_open_relation(relid, relation, params->options & ~(VACOPT_VACUUM),
153  params->log_min_duration >= 0,
155 
156  /* leave if relation could not be opened or locked */
157  if (!onerel)
158  return;
159 
160  /*
161  * Check if relation needs to be skipped based on ownership. This check
162  * happens also when building the relation list to analyze for a manual
163  * operation, and needs to be done additionally here as ANALYZE could
164  * happen across multiple transactions where relation ownership could have
165  * changed in-between. Make sure to generate only logs for ANALYZE in
166  * this case.
167  */
169  onerel->rd_rel,
170  params->options & VACOPT_ANALYZE))
171  {
173  return;
174  }
175 
176  /*
177  * Silently ignore tables that are temp tables of other backends ---
178  * trying to analyze these is rather pointless, since their contents are
179  * probably not up-to-date on disk. (We don't throw a warning here; it
180  * would just lead to chatter during a database-wide ANALYZE.)
181  */
182  if (RELATION_IS_OTHER_TEMP(onerel))
183  {
185  return;
186  }
187 
188  /*
189  * We can ANALYZE any table except pg_statistic. See update_attstats
190  */
191  if (RelationGetRelid(onerel) == StatisticRelationId)
192  {
194  return;
195  }
196 
197  /*
198  * Check that it's of an analyzable relkind, and set up appropriately.
199  */
200  if (onerel->rd_rel->relkind == RELKIND_RELATION ||
201  onerel->rd_rel->relkind == RELKIND_MATVIEW)
202  {
203  /* Regular table, so we'll use the regular row acquisition function */
204  acquirefunc = acquire_sample_rows;
205  /* Also get regular table's size */
206  relpages = RelationGetNumberOfBlocks(onerel);
207  }
208  else if (onerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
209  {
210  /*
211  * For a foreign table, call the FDW's hook function to see whether it
212  * supports analysis.
213  */
214  FdwRoutine *fdwroutine;
215  bool ok = false;
216 
217  fdwroutine = GetFdwRoutineForRelation(onerel, false);
218 
219  if (fdwroutine->AnalyzeForeignTable != NULL)
220  ok = fdwroutine->AnalyzeForeignTable(onerel,
221  &acquirefunc,
222  &relpages);
223 
224  if (!ok)
225  {
227  (errmsg("skipping \"%s\" --- cannot analyze this foreign table",
228  RelationGetRelationName(onerel))));
230  return;
231  }
232  }
233  else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
234  {
235  /*
236  * For partitioned tables, we want to do the recursive ANALYZE below.
237  */
238  }
239  else
240  {
241  /* No need for a WARNING if we already complained during VACUUM */
242  if (!(params->options & VACOPT_VACUUM))
244  (errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables",
245  RelationGetRelationName(onerel))));
247  return;
248  }
249 
250  /*
251  * OK, let's do it. First, initialize progress reporting.
252  */
254  RelationGetRelid(onerel));
255 
256  /*
257  * Do the normal non-recursive ANALYZE. We can skip this for partitioned
258  * tables, which don't contain any rows.
259  */
260  if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
261  do_analyze_rel(onerel, params, va_cols, acquirefunc,
262  relpages, false, in_outer_xact, elevel);
263 
264  /*
265  * If there are child tables, do recursive ANALYZE.
266  */
267  if (onerel->rd_rel->relhassubclass)
268  do_analyze_rel(onerel, params, va_cols, acquirefunc, relpages,
269  true, in_outer_xact, elevel);
270 
271  /*
272  * Close source relation now, but keep lock so that no one deletes it
273  * before we commit. (If someone did, they'd fail to clean up the entries
274  * we made in pg_statistic. Also, releasing the lock before commit would
275  * expose us to concurrent-update failures in update_attstats.)
276  */
277  relation_close(onerel, NoLock);
278 
280 }
static void do_analyze_rel(Relation onerel, VacuumParams *params, List *va_cols, AcquireSampleRowsFunc acquirefunc, BlockNumber relpages, bool inh, bool in_outer_xact, int elevel)
Definition: analyze.c:290
AnalyzeForeignTable_function AnalyzeForeignTable
Definition: fdwapi.h:257
#define VACOPT_ANALYZE
Definition: vacuum.h:179
#define INFO
Definition: elog.h:33
static BufferAccessStrategy vac_strategy
Definition: analyze.c:86
uint32 BlockNumber
Definition: block.h:31
Form_pg_class rd_rel
Definition: rel.h:109
void pgstat_progress_end_command(void)
bits32 options
Definition: vacuum.h:211
#define DEBUG2
Definition: elog.h:24
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define WARNING
Definition: elog.h:40
static int elevel
Definition: vacuumlazy.c:401
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:212
#define ereport(elevel,...)
Definition: elog.h:157
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define VACOPT_VACUUM
Definition: vacuum.h:178
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:631
int log_min_duration
Definition: vacuum.h:219
#define VACOPT_VERBOSE
Definition: vacuum.h:180
int(* AcquireSampleRowsFunc)(Relation relation, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: fdwapi.h:151
int errmsg(const char *fmt,...)
Definition: elog.c:909
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
Relation vacuum_open_relation(Oid relid, RangeVar *relation, bits32 options, bool verbose, LOCKMODE lmode)
Definition: vacuum.c:633
bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, bits32 options)
Definition: vacuum.c:559
#define RelationGetRelid(relation)
Definition: rel.h:477
static int acquire_sample_rows(Relation onerel, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: analyze.c:1134

◆ anl_get_next_S()

double anl_get_next_S ( double  t,
int  n,
double *  stateptr 
)

Definition at line 288 of file sampling.c.

289 {
290  double result;
291 
292  oldrs.W = *stateptr;
293  result = reservoir_get_next_S(&oldrs, t, n);
294  *stateptr = oldrs.W;
295  return result;
296 }
static ReservoirStateData oldrs
Definition: sampling.c:263
double reservoir_get_next_S(ReservoirState rs, double t, int n)
Definition: sampling.c:146

◆ anl_init_selection_state()

double anl_init_selection_state ( int  n)

Definition at line 277 of file sampling.c.

278 {
279  /* initialize if first time through */
280  if (oldrs.randstate[0] == 0)
282 
283  /* Initial value of W (for use when Algorithm Z is first applied) */
284  return exp(-log(sampler_random_fract(oldrs.randstate)) / n);
285 }
void sampler_random_init_state(long seed, SamplerRandomState randstate)
Definition: sampling.c:233
long random(void)
Definition: random.c:22
double sampler_random_fract(SamplerRandomState randstate)
Definition: sampling.c:242
static ReservoirStateData oldrs
Definition: sampling.c:263
SamplerRandomState randstate
Definition: sampling.h:50

◆ anl_random_fract()

double anl_random_fract ( void  )

Definition at line 266 of file sampling.c.

267 {
268  /* initialize if first time through */
269  if (oldrs.randstate[0] == 0)
271 
272  /* and compute a random fraction */
274 }
void sampler_random_init_state(long seed, SamplerRandomState randstate)
Definition: sampling.c:233
long random(void)
Definition: random.c:22
double sampler_random_fract(SamplerRandomState randstate)
Definition: sampling.c:242
static ReservoirStateData oldrs
Definition: sampling.c:263
SamplerRandomState randstate
Definition: sampling.h:50

◆ ExecVacuum()

void ExecVacuum ( ParseState pstate,
VacuumStmt vacstmt,
bool  isTopLevel 
)

Definition at line 100 of file vacuum.c.

References analyze(), DefElem::arg, Assert, defGetBoolean(), defGetInt32(), defGetString(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, VacuumParams::freeze_min_age, VacuumParams::freeze_table_age, get_vacoptval_from_boolean(), VacuumParams::index_cleanup, VacuumStmt::is_vacuumcmd, VacuumParams::is_wraparound, lfirst, lfirst_node, DefElem::location, VacuumParams::log_min_duration, MAX_PARALLEL_WORKER_LIMIT, VacuumParams::multixact_freeze_min_age, VacuumParams::multixact_freeze_table_age, NIL, VacuumParams::nworkers, VacuumParams::options, VacuumStmt::options, parser_errposition(), pg_strcasecmp(), VacuumStmt::rels, VacuumParams::truncate, VacuumRelation::va_cols, VACOPT_ANALYZE, VACOPT_DISABLE_PAGE_SKIPPING, VACOPT_FREEZE, VACOPT_FULL, VACOPT_PROCESS_TOAST, VACOPT_SKIP_LOCKED, VACOPT_VACUUM, VACOPT_VERBOSE, VACOPTVALUE_AUTO, VACOPTVALUE_UNSPECIFIED, vacuum(), and verbose.

Referenced by standard_ProcessUtility().

101 {
102  VacuumParams params;
103  bool verbose = false;
104  bool skip_locked = false;
105  bool analyze = false;
106  bool freeze = false;
107  bool full = false;
108  bool disable_page_skipping = false;
109  bool process_toast = true;
110  ListCell *lc;
111 
112  /* index_cleanup and truncate values unspecified for now */
115 
116  /* By default parallel vacuum is enabled */
117  params.nworkers = 0;
118 
119  /* Parse options list */
120  foreach(lc, vacstmt->options)
121  {
122  DefElem *opt = (DefElem *) lfirst(lc);
123 
124  /* Parse common options for VACUUM and ANALYZE */
125  if (strcmp(opt->defname, "verbose") == 0)
126  verbose = defGetBoolean(opt);
127  else if (strcmp(opt->defname, "skip_locked") == 0)
128  skip_locked = defGetBoolean(opt);
129  else if (!vacstmt->is_vacuumcmd)
130  ereport(ERROR,
131  (errcode(ERRCODE_SYNTAX_ERROR),
132  errmsg("unrecognized ANALYZE option \"%s\"", opt->defname),
133  parser_errposition(pstate, opt->location)));
134 
135  /* Parse options available on VACUUM */
136  else if (strcmp(opt->defname, "analyze") == 0)
137  analyze = defGetBoolean(opt);
138  else if (strcmp(opt->defname, "freeze") == 0)
139  freeze = defGetBoolean(opt);
140  else if (strcmp(opt->defname, "full") == 0)
141  full = defGetBoolean(opt);
142  else if (strcmp(opt->defname, "disable_page_skipping") == 0)
143  disable_page_skipping = defGetBoolean(opt);
144  else if (strcmp(opt->defname, "index_cleanup") == 0)
145  {
146  /* Interpret no string as the default, which is 'auto' */
147  if (!opt->arg)
149  else
150  {
151  char *sval = defGetString(opt);
152 
153  /* Try matching on 'auto' string, or fall back on boolean */
154  if (pg_strcasecmp(sval, "auto") == 0)
156  else
158  }
159  }
160  else if (strcmp(opt->defname, "process_toast") == 0)
161  process_toast = defGetBoolean(opt);
162  else if (strcmp(opt->defname, "truncate") == 0)
163  params.truncate = get_vacoptval_from_boolean(opt);
164  else if (strcmp(opt->defname, "parallel") == 0)
165  {
166  if (opt->arg == NULL)
167  {
168  ereport(ERROR,
169  (errcode(ERRCODE_SYNTAX_ERROR),
170  errmsg("parallel option requires a value between 0 and %d",
172  parser_errposition(pstate, opt->location)));
173  }
174  else
175  {
176  int nworkers;
177 
178  nworkers = defGetInt32(opt);
179  if (nworkers < 0 || nworkers > MAX_PARALLEL_WORKER_LIMIT)
180  ereport(ERROR,
181  (errcode(ERRCODE_SYNTAX_ERROR),
182  errmsg("parallel workers for vacuum must be between 0 and %d",
183  MAX_PARALLEL_WORKER_LIMIT),
184  parser_errposition(pstate, opt->location)));
185 
186  /*
187  * Disable parallel vacuum, if user has specified parallel
188  * degree as zero.
189  */
190  if (nworkers == 0)
191  params.nworkers = -1;
192  else
193  params.nworkers = nworkers;
194  }
195  }
196  else
197  ereport(ERROR,
198  (errcode(ERRCODE_SYNTAX_ERROR),
199  errmsg("unrecognized VACUUM option \"%s\"", opt->defname),
200  parser_errposition(pstate, opt->location)));
201  }
202 
203  /* Set vacuum options */
204  params.options =
205  (vacstmt->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE) |
206  (verbose ? VACOPT_VERBOSE : 0) |
207  (skip_locked ? VACOPT_SKIP_LOCKED : 0) |
208  (analyze ? VACOPT_ANALYZE : 0) |
209  (freeze ? VACOPT_FREEZE : 0) |
210  (full ? VACOPT_FULL : 0) |
211  (disable_page_skipping ? VACOPT_DISABLE_PAGE_SKIPPING : 0) |
212  (process_toast ? VACOPT_PROCESS_TOAST : 0);
213 
214  /* sanity checks on options */
215  Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE));
216  Assert((params.options & VACOPT_VACUUM) ||
217  !(params.options & (VACOPT_FULL | VACOPT_FREEZE)));
218 
219  if ((params.options & VACOPT_FULL) && params.nworkers > 0)
220  ereport(ERROR,
221  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
222  errmsg("VACUUM FULL cannot be performed in parallel")));
223 
224  /*
225  * Make sure VACOPT_ANALYZE is specified if any column lists are present.
226  */
227  if (!(params.options & VACOPT_ANALYZE))
228  {
229  ListCell *lc;
230 
231  foreach(lc, vacstmt->rels)
232  {
234 
235  if (vrel->va_cols != NIL)
236  ereport(ERROR,
237  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
238  errmsg("ANALYZE option must be specified when a column list is provided")));
239  }
240  }
241 
242  /*
243  * All freeze ages are zero if the FREEZE option is given; otherwise pass
244  * them as -1 which means to use the default values.
245  */
246  if (params.options & VACOPT_FREEZE)
247  {
248  params.freeze_min_age = 0;
249  params.freeze_table_age = 0;
250  params.multixact_freeze_min_age = 0;
251  params.multixact_freeze_table_age = 0;
252  }
253  else
254  {
255  params.freeze_min_age = -1;
256  params.freeze_table_age = -1;
257  params.multixact_freeze_min_age = -1;
258  params.multixact_freeze_table_age = -1;
259  }
260 
261  /* user-invoked vacuum is never "for wraparound" */
262  params.is_wraparound = false;
263 
264  /* user-invoked vacuum never uses this parameter */
265  params.log_min_duration = -1;
266 
267  /* Now go through the common routine */
268  vacuum(vacstmt->rels, &params, NULL, isTopLevel);
269 }
#define NIL
Definition: pg_list.h:65
int multixact_freeze_table_age
Definition: vacuum.h:216
void vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel)
Definition: vacuum.c:291
#define VACOPT_DISABLE_PAGE_SKIPPING
Definition: vacuum.h:185
#define VACOPT_ANALYZE
Definition: vacuum.h:179
bool is_vacuumcmd
Definition: parsenodes.h:3359
int32 defGetInt32(DefElem *def)
Definition: define.c:161
int errcode(int sqlerrcode)
Definition: elog.c:698
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
VacOptValue truncate
Definition: vacuum.h:223
int freeze_table_age
Definition: vacuum.h:213
#define VACOPT_PROCESS_TOAST
Definition: vacuum.h:184
bool defGetBoolean(DefElem *def)
Definition: define.c:106
bits32 options
Definition: vacuum.h:211
#define ERROR
Definition: elog.h:46
int freeze_min_age
Definition: vacuum.h:212
char * defGetString(DefElem *def)
Definition: define.c:49
bool is_wraparound
Definition: vacuum.h:218
#define lfirst_node(type, lc)
Definition: pg_list.h:172
int location
Definition: parsenodes.h:761
#define VACOPT_FREEZE
Definition: vacuum.h:181
static VacOptValue get_vacoptval_from_boolean(DefElem *def)
Definition: vacuum.c:2257
Node * arg
Definition: parsenodes.h:759
static int verbose
VacOptValue index_cleanup
Definition: vacuum.h:222
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define VACOPT_VACUUM
Definition: vacuum.h:178
#define lfirst(lc)
Definition: pg_list.h:169
#define VACOPT_FULL
Definition: vacuum.h:182
int nworkers
Definition: vacuum.h:230
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
int log_min_duration
Definition: vacuum.h:219
#define VACOPT_VERBOSE
Definition: vacuum.h:180
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define VACOPT_SKIP_LOCKED
Definition: vacuum.h:183
List * options
Definition: parsenodes.h:3357
char * defname
Definition: parsenodes.h:758
#define MAX_PARALLEL_WORKER_LIMIT
int multixact_freeze_min_age
Definition: vacuum.h:214
static long analyze(struct nfa *nfa)
Definition: regc_nfa.c:3044
List * rels
Definition: parsenodes.h:3358

◆ std_typanalyze()

bool std_typanalyze ( VacAttrStats stats)

Definition at line 1857 of file analyze.c.

References VacAttrStats::attr, VacAttrStats::attrtypid, compute_distinct_stats(), compute_scalar_stats(), VacAttrStats::compute_stats, compute_trivial_stats(), default_statistics_target, StdAnalyzeData::eqfunc, StdAnalyzeData::eqopr, VacAttrStats::extra_data, get_opcode(), get_sort_group_operators(), InvalidOid, StdAnalyzeData::ltopr, VacAttrStats::minrows, OidIsValid, and palloc().

Referenced by array_typanalyze(), examine_attribute(), and examine_expression().

1858 {
1859  Form_pg_attribute attr = stats->attr;
1860  Oid ltopr;
1861  Oid eqopr;
1862  StdAnalyzeData *mystats;
1863 
1864  /* If the attstattarget column is negative, use the default value */
1865  /* NB: it is okay to scribble on stats->attr since it's a copy */
1866  if (attr->attstattarget < 0)
1867  attr->attstattarget = default_statistics_target;
1868 
1869  /* Look for default "<" and "=" operators for column's type */
1871  false, false, false,
1872  &ltopr, &eqopr, NULL,
1873  NULL);
1874 
1875  /* Save the operator info for compute_stats routines */
1876  mystats = (StdAnalyzeData *) palloc(sizeof(StdAnalyzeData));
1877  mystats->eqopr = eqopr;
1878  mystats->eqfunc = OidIsValid(eqopr) ? get_opcode(eqopr) : InvalidOid;
1879  mystats->ltopr = ltopr;
1880  stats->extra_data = mystats;
1881 
1882  /*
1883  * Determine which standard statistics algorithm to use
1884  */
1885  if (OidIsValid(eqopr) && OidIsValid(ltopr))
1886  {
1887  /* Seems to be a scalar datatype */
1889  /*--------------------
1890  * The following choice of minrows is based on the paper
1891  * "Random sampling for histogram construction: how much is enough?"
1892  * by Surajit Chaudhuri, Rajeev Motwani and Vivek Narasayya, in
1893  * Proceedings of ACM SIGMOD International Conference on Management
1894  * of Data, 1998, Pages 436-447. Their Corollary 1 to Theorem 5
1895  * says that for table size n, histogram size k, maximum relative
1896  * error in bin size f, and error probability gamma, the minimum
1897  * random sample size is
1898  * r = 4 * k * ln(2*n/gamma) / f^2
1899  * Taking f = 0.5, gamma = 0.01, n = 10^6 rows, we obtain
1900  * r = 305.82 * k
1901  * Note that because of the log function, the dependence on n is
1902  * quite weak; even at n = 10^12, a 300*k sample gives <= 0.66
1903  * bin size error with probability 0.99. So there's no real need to
1904  * scale for n, which is a good thing because we don't necessarily
1905  * know it at this point.
1906  *--------------------
1907  */
1908  stats->minrows = 300 * attr->attstattarget;
1909  }
1910  else if (OidIsValid(eqopr))
1911  {
1912  /* We can still recognize distinct values */
1914  /* Might as well use the same minrows as above */
1915  stats->minrows = 300 * attr->attstattarget;
1916  }
1917  else
1918  {
1919  /* Can't do much but the trivial stuff */
1921  /* Might as well use the same minrows as above */
1922  stats->minrows = 300 * attr->attstattarget;
1923  }
1924 
1925  return true;
1926 }
int minrows
Definition: vacuum.h:135
static void compute_scalar_stats(VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
Definition: analyze.c:2370
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
Form_pg_attribute attr
Definition: vacuum.h:123
Oid attrtypid
Definition: vacuum.h:124
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
static void compute_distinct_stats(VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
Definition: analyze.c:2027
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1256
void get_sort_group_operators(Oid argtype, bool needLT, bool needEQ, bool needGT, Oid *ltOpr, Oid *eqOpr, Oid *gtOpr, bool *isHashable)
Definition: parse_oper.c:192
static void compute_trivial_stats(VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
Definition: analyze.c:1937
void * palloc(Size size)
Definition: mcxt.c:1062
AnalyzeAttrComputeStatsFunc compute_stats
Definition: vacuum.h:134
void * extra_data
Definition: vacuum.h:136
int default_statistics_target
Definition: analyze.c:82

◆ vac_close_indexes()

void vac_close_indexes ( int  nindexes,
Relation Irel,
LOCKMODE  lockmode 
)

Definition at line 2128 of file vacuum.c.

References index_close(), and pfree().

Referenced by do_analyze_rel(), heap_vacuum_rel(), and parallel_vacuum_main().

2129 {
2130  if (Irel == NULL)
2131  return;
2132 
2133  while (nindexes--)
2134  {
2135  Relation ind = Irel[nindexes];
2136 
2137  index_close(ind, lockmode);
2138  }
2139  pfree(Irel);
2140 }
void pfree(void *pointer)
Definition: mcxt.c:1169
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158

◆ vac_estimate_reltuples()

double vac_estimate_reltuples ( Relation  relation,
BlockNumber  total_pages,
BlockNumber  scanned_pages,
double  scanned_tuples 
)

Definition at line 1223 of file vacuum.c.

References RelationData::rd_rel.

Referenced by lazy_scan_heap(), and statapprox_heap().

1227 {
1228  BlockNumber old_rel_pages = relation->rd_rel->relpages;
1229  double old_rel_tuples = relation->rd_rel->reltuples;
1230  double old_density;
1231  double unscanned_pages;
1232  double total_tuples;
1233 
1234  /* If we did scan the whole table, just use the count as-is */
1235  if (scanned_pages >= total_pages)
1236  return scanned_tuples;
1237 
1238  /*
1239  * If scanned_pages is zero but total_pages isn't, keep the existing value
1240  * of reltuples. (Note: we might be returning -1 in this case.)
1241  */
1242  if (scanned_pages == 0)
1243  return old_rel_tuples;
1244 
1245  /*
1246  * If old density is unknown, we can't do much except scale up
1247  * scanned_tuples to match total_pages.
1248  */
1249  if (old_rel_tuples < 0 || old_rel_pages == 0)
1250  return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
1251 
1252  /*
1253  * Okay, we've covered the corner cases. The normal calculation is to
1254  * convert the old measurement to a density (tuples per page), then
1255  * estimate the number of tuples in the unscanned pages using that figure,
1256  * and finally add on the number of tuples in the scanned pages.
1257  */
1258  old_density = old_rel_tuples / old_rel_pages;
1259  unscanned_pages = (double) total_pages - (double) scanned_pages;
1260  total_tuples = old_density * unscanned_pages + scanned_tuples;
1261  return floor(total_tuples + 0.5);
1262 }
uint32 BlockNumber
Definition: block.h:31
Form_pg_class rd_rel
Definition: rel.h:109

◆ vac_open_indexes()

void vac_open_indexes ( Relation  relation,
LOCKMODE  lockmode,
int *  nindexes,
Relation **  Irel 
)

Definition at line 2085 of file vacuum.c.

References Assert, i, index_close(), index_open(), lfirst_oid, list_free(), list_length(), NoLock, palloc(), RelationData::rd_index, and RelationGetIndexList().

Referenced by do_analyze_rel(), heap_vacuum_rel(), and parallel_vacuum_main().

2087 {
2088  List *indexoidlist;
2089  ListCell *indexoidscan;
2090  int i;
2091 
2092  Assert(lockmode != NoLock);
2093 
2094  indexoidlist = RelationGetIndexList(relation);
2095 
2096  /* allocate enough memory for all indexes */
2097  i = list_length(indexoidlist);
2098 
2099  if (i > 0)
2100  *Irel = (Relation *) palloc(i * sizeof(Relation));
2101  else
2102  *Irel = NULL;
2103 
2104  /* collect just the ready indexes */
2105  i = 0;
2106  foreach(indexoidscan, indexoidlist)
2107  {
2108  Oid indexoid = lfirst_oid(indexoidscan);
2109  Relation indrel;
2110 
2111  indrel = index_open(indexoid, lockmode);
2112  if (indrel->rd_index->indisready)
2113  (*Irel)[i++] = indrel;
2114  else
2115  index_close(indrel, lockmode);
2116  }
2117 
2118  *nindexes = i;
2119 
2120  list_free(indexoidlist);
2121 }
unsigned int Oid
Definition: postgres_ext.h:31
Form_pg_index rd_index
Definition: rel.h:187
#define NoLock
Definition: lockdefs.h:34
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4676
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
void * palloc(Size size)
Definition: mcxt.c:1062
void list_free(List *list)
Definition: list.c:1391
int i
Definition: pg_list.h:50
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ vac_update_datfrozenxid()

void vac_update_datfrozenxid ( void  )

Definition at line 1433 of file vacuum.c.

References AccessShareLock, Assert, BTEqualStrategyNumber, elog, ERROR, ExclusiveLock, ForceTransactionIdLimitUpdate(), GetOldestMultiXactId(), GetOldestNonRemovableTransactionId(), GETSTRUCT, heap_copytuple(), heap_freetuple(), heap_inplace_update(), HeapTupleIsValid, InvalidOid, sort-test::key, LockDatabaseFrozenIds(), MultiXactIdIsValid, MultiXactIdPrecedes(), MyDatabaseId, ObjectIdGetDatum, ReadNextMultiXactId(), ReadNextTransactionId(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), and vac_truncate_clog().

Referenced by do_autovacuum(), and vacuum().

1434 {
1435  HeapTuple tuple;
1436  Form_pg_database dbform;
1437  Relation relation;
1438  SysScanDesc scan;
1439  HeapTuple classTup;
1440  TransactionId newFrozenXid;
1441  MultiXactId newMinMulti;
1442  TransactionId lastSaneFrozenXid;
1443  MultiXactId lastSaneMinMulti;
1444  bool bogus = false;
1445  bool dirty = false;
1446  ScanKeyData key[1];
1447 
1448  /*
1449  * Restrict this task to one backend per database. This avoids race
1450  * conditions that would move datfrozenxid or datminmxid backward. It
1451  * avoids calling vac_truncate_clog() with a datfrozenxid preceding a
1452  * datfrozenxid passed to an earlier vac_truncate_clog() call.
1453  */
1455 
1456  /*
1457  * Initialize the "min" calculation with
1458  * GetOldestNonRemovableTransactionId(), which is a reasonable
1459  * approximation to the minimum relfrozenxid for not-yet-committed
1460  * pg_class entries for new tables; see AddNewRelationTuple(). So we
1461  * cannot produce a wrong minimum by starting with this.
1462  */
1463  newFrozenXid = GetOldestNonRemovableTransactionId(NULL);
1464 
1465  /*
1466  * Similarly, initialize the MultiXact "min" with the value that would be
1467  * used on pg_class for new tables. See AddNewRelationTuple().
1468  */
1469  newMinMulti = GetOldestMultiXactId();
1470 
1471  /*
1472  * Identify the latest relfrozenxid and relminmxid values that we could
1473  * validly see during the scan. These are conservative values, but it's
1474  * not really worth trying to be more exact.
1475  */
1476  lastSaneFrozenXid = ReadNextTransactionId();
1477  lastSaneMinMulti = ReadNextMultiXactId();
1478 
1479  /*
1480  * We must seqscan pg_class to find the minimum Xid, because there is no
1481  * index that can help us here.
1482  */
1483  relation = table_open(RelationRelationId, AccessShareLock);
1484 
1485  scan = systable_beginscan(relation, InvalidOid, false,
1486  NULL, 0, NULL);
1487 
1488  while ((classTup = systable_getnext(scan)) != NULL)
1489  {
1490  Form_pg_class classForm = (Form_pg_class) GETSTRUCT(classTup);
1491 
1492  /*
1493  * Only consider relations able to hold unfrozen XIDs (anything else
1494  * should have InvalidTransactionId in relfrozenxid anyway).
1495  */
1496  if (classForm->relkind != RELKIND_RELATION &&
1497  classForm->relkind != RELKIND_MATVIEW &&
1498  classForm->relkind != RELKIND_TOASTVALUE)
1499  {
1500  Assert(!TransactionIdIsValid(classForm->relfrozenxid));
1501  Assert(!MultiXactIdIsValid(classForm->relminmxid));
1502  continue;
1503  }
1504 
1505  /*
1506  * Some table AMs might not need per-relation xid / multixid horizons.
1507  * It therefore seems reasonable to allow relfrozenxid and relminmxid
1508  * to not be set (i.e. set to their respective Invalid*Id)
1509  * independently. Thus validate and compute horizon for each only if
1510  * set.
1511  *
1512  * If things are working properly, no relation should have a
1513  * relfrozenxid or relminmxid that is "in the future". However, such
1514  * cases have been known to arise due to bugs in pg_upgrade. If we
1515  * see any entries that are "in the future", chicken out and don't do
1516  * anything. This ensures we won't truncate clog & multixact SLRUs
1517  * before those relations have been scanned and cleaned up.
1518  */
1519 
1520  if (TransactionIdIsValid(classForm->relfrozenxid))
1521  {
1522  Assert(TransactionIdIsNormal(classForm->relfrozenxid));
1523 
1524  /* check for values in the future */
1525  if (TransactionIdPrecedes(lastSaneFrozenXid, classForm->relfrozenxid))
1526  {
1527  bogus = true;
1528  break;
1529  }
1530 
1531  /* determine new horizon */
1532  if (TransactionIdPrecedes(classForm->relfrozenxid, newFrozenXid))
1533  newFrozenXid = classForm->relfrozenxid;
1534  }
1535 
1536  if (MultiXactIdIsValid(classForm->relminmxid))
1537  {
1538  /* check for values in the future */
1539  if (MultiXactIdPrecedes(lastSaneMinMulti, classForm->relminmxid))
1540  {
1541  bogus = true;
1542  break;
1543  }
1544 
1545  /* determine new horizon */
1546  if (MultiXactIdPrecedes(classForm->relminmxid, newMinMulti))
1547  newMinMulti = classForm->relminmxid;
1548  }
1549  }
1550 
1551  /* we're done with pg_class */
1552  systable_endscan(scan);
1553  table_close(relation, AccessShareLock);
1554 
1555  /* chicken out if bogus data found */
1556  if (bogus)
1557  return;
1558 
1559  Assert(TransactionIdIsNormal(newFrozenXid));
1560  Assert(MultiXactIdIsValid(newMinMulti));
1561 
1562  /* Now fetch the pg_database tuple we need to update. */
1563  relation = table_open(DatabaseRelationId, RowExclusiveLock);
1564 
1565  /*
1566  * Get the pg_database tuple to scribble on. Note that this does not
1567  * directly rely on the syscache to avoid issues with flattened toast
1568  * values for the in-place update.
1569  */
1570  ScanKeyInit(&key[0],
1571  Anum_pg_database_oid,
1572  BTEqualStrategyNumber, F_OIDEQ,
1574 
1575  scan = systable_beginscan(relation, DatabaseOidIndexId, true,
1576  NULL, 1, key);
1577  tuple = systable_getnext(scan);
1578  tuple = heap_copytuple(tuple);
1579  systable_endscan(scan);
1580 
1581  if (!HeapTupleIsValid(tuple))
1582  elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
1583 
1584  dbform = (Form_pg_database) GETSTRUCT(tuple);
1585 
1586  /*
1587  * As in vac_update_relstats(), we ordinarily don't want to let
1588  * datfrozenxid go backward; but if it's "in the future" then it must be
1589  * corrupt and it seems best to overwrite it.
1590  */
1591  if (dbform->datfrozenxid != newFrozenXid &&
1592  (TransactionIdPrecedes(dbform->datfrozenxid, newFrozenXid) ||
1593  TransactionIdPrecedes(lastSaneFrozenXid, dbform->datfrozenxid)))
1594  {
1595  dbform->datfrozenxid = newFrozenXid;
1596  dirty = true;
1597  }
1598  else
1599  newFrozenXid = dbform->datfrozenxid;
1600 
1601  /* Ditto for datminmxid */
1602  if (dbform->datminmxid != newMinMulti &&
1603  (MultiXactIdPrecedes(dbform->datminmxid, newMinMulti) ||
1604  MultiXactIdPrecedes(lastSaneMinMulti, dbform->datminmxid)))
1605  {
1606  dbform->datminmxid = newMinMulti;
1607  dirty = true;
1608  }
1609  else
1610  newMinMulti = dbform->datminmxid;
1611 
1612  if (dirty)
1613  heap_inplace_update(relation, tuple);
1614 
1615  heap_freetuple(tuple);
1616  table_close(relation, RowExclusiveLock);
1617 
1618  /*
1619  * If we were able to advance datfrozenxid or datminmxid, see if we can
1620  * truncate pg_xact and/or pg_multixact. Also do it if the shared
1621  * XID-wrap-limit info is stale, since this action will update that too.
1622  */
1623  if (dirty || ForceTransactionIdLimitUpdate())
1624  vac_truncate_clog(newFrozenXid, newMinMulti,
1625  lastSaneFrozenXid, lastSaneMinMulti);
1626 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
uint32 TransactionId
Definition: c.h:587
FormData_pg_database * Form_pg_database
Definition: pg_database.h:81
#define ExclusiveLock
Definition: lockdefs.h:44
void LockDatabaseFrozenIds(LOCKMODE lockmode)
Definition: lmgr.c:470
#define AccessShareLock
Definition: lockdefs.h:36
static TransactionId ReadNextTransactionId(void)
Definition: transam.h:316
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
bool ForceTransactionIdLimitUpdate(void)
Definition: varsup.c:490
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
TransactionId GetOldestNonRemovableTransactionId(Relation rel)
Definition: procarray.c:2005
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define RowExclusiveLock
Definition: lockdefs.h:38
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
MultiXactId GetOldestMultiXactId(void)
Definition: multixact.c:2506
Oid MyDatabaseId
Definition: globals.c:88
#define InvalidOid
Definition: postgres_ext.h:36
TransactionId MultiXactId
Definition: c.h:597
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3159
static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti)
Definition: vacuum.c:1647
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:5991
#define elog(elevel,...)
Definition: elog.h:232
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:723

◆ vac_update_relstats()

void vac_update_relstats ( Relation  relation,
BlockNumber  num_pages,
double  num_tuples,
BlockNumber  num_all_visible_pages,
bool  hasindex,
TransactionId  frozenxid,
MultiXactId  minmulti,
bool  in_outer_xact 
)

Definition at line 1306 of file vacuum.c.

References elog, ERROR, GETSTRUCT, heap_inplace_update(), HeapTupleIsValid, MultiXactIdIsValid, MultiXactIdPrecedes(), ObjectIdGetDatum, RelationData::rd_rules, ReadNextMultiXactId(), ReadNextTransactionId(), RelationGetRelid, RELOID, RowExclusiveLock, SearchSysCacheCopy1, table_close(), table_open(), TransactionIdIsNormal, TransactionIdPrecedes(), and RelationData::trigdesc.

Referenced by do_analyze_rel(), heap_vacuum_rel(), and update_index_statistics().

1312 {
1313  Oid relid = RelationGetRelid(relation);
1314  Relation rd;
1315  HeapTuple ctup;
1316  Form_pg_class pgcform;
1317  bool dirty;
1318 
1319  rd = table_open(RelationRelationId, RowExclusiveLock);
1320 
1321  /* Fetch a copy of the tuple to scribble on */
1323  if (!HeapTupleIsValid(ctup))
1324  elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
1325  relid);
1326  pgcform = (Form_pg_class) GETSTRUCT(ctup);
1327 
1328  /* Apply statistical updates, if any, to copied tuple */
1329 
1330  dirty = false;
1331  if (pgcform->relpages != (int32) num_pages)
1332  {
1333  pgcform->relpages = (int32) num_pages;
1334  dirty = true;
1335  }
1336  if (pgcform->reltuples != (float4) num_tuples)
1337  {
1338  pgcform->reltuples = (float4) num_tuples;
1339  dirty = true;
1340  }
1341  if (pgcform->relallvisible != (int32) num_all_visible_pages)
1342  {
1343  pgcform->relallvisible = (int32) num_all_visible_pages;
1344  dirty = true;
1345  }
1346 
1347  /* Apply DDL updates, but not inside an outer transaction (see above) */
1348 
1349  if (!in_outer_xact)
1350  {
1351  /*
1352  * If we didn't find any indexes, reset relhasindex.
1353  */
1354  if (pgcform->relhasindex && !hasindex)
1355  {
1356  pgcform->relhasindex = false;
1357  dirty = true;
1358  }
1359 
1360  /* We also clear relhasrules and relhastriggers if needed */
1361  if (pgcform->relhasrules && relation->rd_rules == NULL)
1362  {
1363  pgcform->relhasrules = false;
1364  dirty = true;
1365  }
1366  if (pgcform->relhastriggers && relation->trigdesc == NULL)
1367  {
1368  pgcform->relhastriggers = false;
1369  dirty = true;
1370  }
1371  }
1372 
1373  /*
1374  * Update relfrozenxid, unless caller passed InvalidTransactionId
1375  * indicating it has no new data.
1376  *
1377  * Ordinarily, we don't let relfrozenxid go backwards: if things are
1378  * working correctly, the only way the new frozenxid could be older would
1379  * be if a previous VACUUM was done with a tighter freeze_min_age, in
1380  * which case we don't want to forget the work it already did. However,
1381  * if the stored relfrozenxid is "in the future", then it must be corrupt
1382  * and it seems best to overwrite it with the cutoff we used this time.
1383  * This should match vac_update_datfrozenxid() concerning what we consider
1384  * to be "in the future".
1385  */
1386  if (TransactionIdIsNormal(frozenxid) &&
1387  pgcform->relfrozenxid != frozenxid &&
1388  (TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid) ||
1390  pgcform->relfrozenxid)))
1391  {
1392  pgcform->relfrozenxid = frozenxid;
1393  dirty = true;
1394  }
1395 
1396  /* Similarly for relminmxid */
1397  if (MultiXactIdIsValid(minmulti) &&
1398  pgcform->relminmxid != minmulti &&
1399  (MultiXactIdPrecedes(pgcform->relminmxid, minmulti) ||
1400  MultiXactIdPrecedes(ReadNextMultiXactId(), pgcform->relminmxid)))
1401  {
1402  pgcform->relminmxid = minmulti;
1403  dirty = true;
1404  }
1405 
1406  /* If anything changed, write out the tuple. */
1407  if (dirty)
1408  heap_inplace_update(rd, ctup);
1409 
1411 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
static TransactionId ReadNextTransactionId(void)
Definition: transam.h:316
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:429
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
TriggerDesc * trigdesc
Definition: rel.h:115
#define RowExclusiveLock
Definition: lockdefs.h:38
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
float float4
Definition: c.h:564
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
RuleLock * rd_rules
Definition: rel.h:113
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3159
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:5991
#define elog(elevel,...)
Definition: elog.h:232
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:477
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:723

◆ vacuum()

void vacuum ( List relations,
VacuumParams params,
BufferAccessStrategy  bstrategy,
bool  isTopLevel 
)

Definition at line 291 of file vacuum.c.

References ActiveSnapshotSet(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, analyze_rel(), Assert, BAS_VACUUM, CommandCounterIncrement(), CommitTransactionCommand(), cur, ereport, errcode(), errmsg(), ERROR, expand_vacuum_rel(), get_all_vacuum_rels(), GetAccessStrategy(), GetTransactionSnapshot(), IsAutoVacuumWorkerProcess(), IsInTransactionBlock(), lfirst_node, list_concat(), list_length(), MemoryContextDelete(), MemoryContextSwitchTo(), NIL, VacuumRelation::oid, VacuumParams::options, PG_END_TRY, PG_FINALLY, PG_TRY, pgstat_vacuum_stat(), PopActiveSnapshot(), PortalContext, PreventInTransactionBlock(), PushActiveSnapshot(), VacuumRelation::relation, StartTransactionCommand(), VacuumRelation::va_cols, vac_update_datfrozenxid(), VACOPT_ANALYZE, VACOPT_DISABLE_PAGE_SKIPPING, VACOPT_FULL, VACOPT_PROCESS_TOAST, VACOPT_VACUUM, vacuum_rel(), VacuumCostActive, VacuumCostBalance, VacuumCostBalanceLocal, VacuumCostDelay, VacuumPageDirty, VacuumPageHit, and VacuumPageMiss.

Referenced by autovacuum_do_vac_analyze(), and ExecVacuum().

293 {
294  static bool in_vacuum = false;
295 
296  const char *stmttype;
297  volatile bool in_outer_xact,
298  use_own_xacts;
299 
300  Assert(params != NULL);
301 
302  stmttype = (params->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
303 
304  /*
305  * We cannot run VACUUM inside a user transaction block; if we were inside
306  * a transaction, then our commit- and start-transaction-command calls
307  * would not have the intended effect! There are numerous other subtle
308  * dependencies on this, too.
309  *
310  * ANALYZE (without VACUUM) can run either way.
311  */
312  if (params->options & VACOPT_VACUUM)
313  {
314  PreventInTransactionBlock(isTopLevel, stmttype);
315  in_outer_xact = false;
316  }
317  else
318  in_outer_xact = IsInTransactionBlock(isTopLevel);
319 
320  /*
321  * Due to static variables vac_context, anl_context and vac_strategy,
322  * vacuum() is not reentrant. This matters when VACUUM FULL or ANALYZE
323  * calls a hostile index expression that itself calls ANALYZE.
324  */
325  if (in_vacuum)
326  ereport(ERROR,
327  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
328  errmsg("%s cannot be executed from VACUUM or ANALYZE",
329  stmttype)));
330 
331  /*
332  * Sanity check DISABLE_PAGE_SKIPPING option.
333  */
334  if ((params->options & VACOPT_FULL) != 0 &&
335  (params->options & VACOPT_DISABLE_PAGE_SKIPPING) != 0)
336  ereport(ERROR,
337  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
338  errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
339 
340  /* sanity check for PROCESS_TOAST */
341  if ((params->options & VACOPT_FULL) != 0 &&
342  (params->options & VACOPT_PROCESS_TOAST) == 0)
343  ereport(ERROR,
344  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
345  errmsg("PROCESS_TOAST required with VACUUM FULL")));
346 
347  /*
348  * Send info about dead objects to the statistics collector, unless we are
349  * in autovacuum --- autovacuum.c does this for itself.
350  */
351  if ((params->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
353 
354  /*
355  * Create special memory context for cross-transaction storage.
356  *
357  * Since it is a child of PortalContext, it will go away eventually even
358  * if we suffer an error; there's no need for special abort cleanup logic.
359  */
361  "Vacuum",
363 
364  /*
365  * If caller didn't give us a buffer strategy object, make one in the
366  * cross-transaction memory context.
367  */
368  if (bstrategy == NULL)
369  {
371 
372  bstrategy = GetAccessStrategy(BAS_VACUUM);
373  MemoryContextSwitchTo(old_context);
374  }
375  vac_strategy = bstrategy;
376 
377  /*
378  * Build list of relation(s) to process, putting any new data in
379  * vac_context for safekeeping.
380  */
381  if (relations != NIL)
382  {
383  List *newrels = NIL;
384  ListCell *lc;
385 
386  foreach(lc, relations)
387  {
389  List *sublist;
390  MemoryContext old_context;
391 
392  sublist = expand_vacuum_rel(vrel, params->options);
393  old_context = MemoryContextSwitchTo(vac_context);
394  newrels = list_concat(newrels, sublist);
395  MemoryContextSwitchTo(old_context);
396  }
397  relations = newrels;
398  }
399  else
400  relations = get_all_vacuum_rels(params->options);
401 
402  /*
403  * Decide whether we need to start/commit our own transactions.
404  *
405  * For VACUUM (with or without ANALYZE): always do so, so that we can
406  * release locks as soon as possible. (We could possibly use the outer
407  * transaction for a one-table VACUUM, but handling TOAST tables would be
408  * problematic.)
409  *
410  * For ANALYZE (no VACUUM): if inside a transaction block, we cannot
411  * start/commit our own transactions. Also, there's no need to do so if
412  * only processing one relation. For multiple relations when not within a
413  * transaction block, and also in an autovacuum worker, use own
414  * transactions so we can release locks sooner.
415  */
416  if (params->options & VACOPT_VACUUM)
417  use_own_xacts = true;
418  else
419  {
420  Assert(params->options & VACOPT_ANALYZE);
422  use_own_xacts = true;
423  else if (in_outer_xact)
424  use_own_xacts = false;
425  else if (list_length(relations) > 1)
426  use_own_xacts = true;
427  else
428  use_own_xacts = false;
429  }
430 
431  /*
432  * vacuum_rel expects to be entered with no transaction active; it will
433  * start and commit its own transaction. But we are called by an SQL
434  * command, and so we are executing inside a transaction already. We
435  * commit the transaction started in PostgresMain() here, and start
436  * another one before exiting to match the commit waiting for us back in
437  * PostgresMain().
438  */
439  if (use_own_xacts)
440  {
441  Assert(!in_outer_xact);
442 
443  /* ActiveSnapshot is not set by autovacuum */
444  if (ActiveSnapshotSet())
446 
447  /* matches the StartTransaction in PostgresMain() */
449  }
450 
451  /* Turn vacuum cost accounting on or off, and set/clear in_vacuum */
452  PG_TRY();
453  {
454  ListCell *cur;
455 
456  in_vacuum = true;
458  VacuumCostBalance = 0;
459  VacuumPageHit = 0;
460  VacuumPageMiss = 0;
461  VacuumPageDirty = 0;
464  VacuumActiveNWorkers = NULL;
465 
466  /*
467  * Loop to process each selected relation.
468  */
469  foreach(cur, relations)
470  {
472 
473  if (params->options & VACOPT_VACUUM)
474  {
475  if (!vacuum_rel(vrel->oid, vrel->relation, params))
476  continue;
477  }
478 
479  if (params->options & VACOPT_ANALYZE)
480  {
481  /*
482  * If using separate xacts, start one for analyze. Otherwise,
483  * we can use the outer transaction.
484  */
485  if (use_own_xacts)
486  {
488  /* functions in indexes may want a snapshot set */
490  }
491 
492  analyze_rel(vrel->oid, vrel->relation, params,
493  vrel->va_cols, in_outer_xact, vac_strategy);
494 
495  if (use_own_xacts)
496  {
499  }
500  else
501  {
502  /*
503  * If we're not using separate xacts, better separate the
504  * ANALYZE actions with CCIs. This avoids trouble if user
505  * says "ANALYZE t, t".
506  */
508  }
509  }
510  }
511  }
512  PG_FINALLY();
513  {
514  in_vacuum = false;
515  VacuumCostActive = false;
516  }
517  PG_END_TRY();
518 
519  /*
520  * Finish up processing.
521  */
522  if (use_own_xacts)
523  {
524  /* here, we are not in a transaction */
525 
526  /*
527  * This matches the CommitTransaction waiting for us in
528  * PostgresMain().
529  */
531  }
532 
533  if ((params->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
534  {
535  /*
536  * Update pg_database.datfrozenxid, and truncate pg_xact if possible.
537  * (autovacuum.c does this for itself.)
538  */
540  }
541 
542  /*
543  * Clean up working storage --- note we must do this after
544  * StartTransactionCommand, else we might be trying to delete the active
545  * context!
546  */
548  vac_context = NULL;
549 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:542
#define NIL
Definition: pg_list.h:65
void analyze_rel(Oid relid, RangeVar *relation, VacuumParams *params, List *va_cols, bool in_outer_xact, BufferAccessStrategy bstrategy)
Definition: analyze.c:120
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
#define AllocSetContextCreate
Definition: memutils.h:173
int64 VacuumPageMiss
Definition: globals.c:148
pg_atomic_uint32 * VacuumActiveNWorkers
Definition: vacuum.c:79
int VacuumCostBalance
Definition: globals.c:151
#define VACOPT_DISABLE_PAGE_SKIPPING
Definition: vacuum.h:185
static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
Definition: vacuum.c:1798
RangeVar * relation
Definition: parsenodes.h:3372
void vac_update_datfrozenxid(void)
Definition: vacuum.c:1433
#define VACOPT_ANALYZE
Definition: vacuum.h:179
void CommitTransactionCommand(void)
Definition: xact.c:2959
int64 VacuumPageHit
Definition: globals.c:147
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static BufferAccessStrategy vac_strategy
Definition: vacuum.c:71
struct cursor * cur
Definition: ecpg.c:28
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
int errcode(int sqlerrcode)
Definition: elog.c:698
int64 VacuumPageDirty
Definition: globals.c:149
void PopActiveSnapshot(void)
Definition: snapmgr.c:774
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
static List * expand_vacuum_rel(VacuumRelation *vrel, int options)
Definition: vacuum.c:745
#define VACOPT_PROCESS_TOAST
Definition: vacuum.h:184
MemoryContext PortalContext
Definition: mcxt.c:57
bits32 options
Definition: vacuum.h:211
#define ERROR
Definition: elog.h:46
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
#define lfirst_node(type, lc)
Definition: pg_list.h:172
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680
static MemoryContext vac_context
Definition: vacuum.c:70
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3399
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:813
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3410
void pgstat_vacuum_stat(void)
Definition: pgstat.c:1118
bool IsInTransactionBlock(bool isTopLevel)
Definition: xact.c:3512
int VacuumCostBalanceLocal
Definition: vacuum.c:80
pg_atomic_uint32 * VacuumSharedCostBalance
Definition: vacuum.c:78
#define PG_FINALLY()
Definition: elog.h:330
void CommandCounterIncrement(void)
Definition: xact.c:1022
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define VACOPT_VACUUM
Definition: vacuum.h:178
#define VACOPT_FULL
Definition: vacuum.h:182
void StartTransactionCommand(void)
Definition: xact.c:2858
static int list_length(const List *l)
Definition: pg_list.h:149
int errmsg(const char *fmt,...)
Definition: elog.c:909
double VacuumCostDelay
Definition: globals.c:145
#define PG_TRY()
Definition: elog.h:313
Definition: pg_list.h:50
#define PG_END_TRY()
Definition: elog.h:338
bool VacuumCostActive
Definition: globals.c:152
static List * get_all_vacuum_rels(int options)
Definition: vacuum.c:884

◆ vacuum_delay_point()

void vacuum_delay_point ( void  )

Definition at line 2149 of file vacuum.c.

References AutoVacuumUpdateDelay(), CHECK_FOR_INTERRUPTS, compute_parallel_delay(), InterruptPending, MyLatch, ResetLatch(), VacuumCostActive, VacuumCostBalance, VacuumCostDelay, VacuumCostLimit, WAIT_EVENT_VACUUM_DELAY, WaitLatch(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, and WL_TIMEOUT.

Referenced by acquire_sample_rows(), blbulkdelete(), blvacuumcleanup(), btvacuumpage(), compute_array_stats(), compute_distinct_stats(), compute_index_stats(), compute_range_stats(), compute_scalar_stats(), compute_trivial_stats(), compute_tsvector_stats(), file_acquire_sample_rows(), ginbulkdelete(), ginInsertCleanup(), ginvacuumcleanup(), gistvacuumpage(), hashbucketcleanup(), lazy_scan_heap(), lazy_vacuum_heap_rel(), spgprocesspending(), and spgvacuumpage().

2150 {
2151  double msec = 0;
2152 
2153  /* Always check for interrupts */
2155 
2157  return;
2158 
2159  /*
2160  * For parallel vacuum, the delay is computed based on the shared cost
2161  * balance. See compute_parallel_delay.
2162  */
2163  if (VacuumSharedCostBalance != NULL)
2164  msec = compute_parallel_delay();
2165  else if (VacuumCostBalance >= VacuumCostLimit)
2167 
2168  /* Nap if appropriate */
2169  if (msec > 0)
2170  {
2171  if (msec > VacuumCostDelay * 4)
2172  msec = VacuumCostDelay * 4;
2173 
2174  (void) WaitLatch(MyLatch,
2176  msec,
2179 
2180  VacuumCostBalance = 0;
2181 
2182  /* update balance values for workers */
2184 
2185  /* Might have gotten an interrupt while sleeping */
2187  }
2188 }
static double compute_parallel_delay(void)
Definition: vacuum.c:2213
int VacuumCostBalance
Definition: globals.c:151
#define WL_TIMEOUT
Definition: latch.h:128
void ResetLatch(Latch *latch)
Definition: latch.c:660
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:452
int VacuumCostLimit
Definition: globals.c:144
pg_atomic_uint32 * VacuumSharedCostBalance
Definition: vacuum.c:78
volatile sig_atomic_t InterruptPending
Definition: globals.c:30
double VacuumCostDelay
Definition: globals.c:145
void AutoVacuumUpdateDelay(void)
Definition: autovacuum.c:1783
struct Latch * MyLatch
Definition: globals.c:57
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
#define WL_LATCH_SET
Definition: latch.h:125
#define WL_EXIT_ON_PM_DEATH
Definition: latch.h:130
bool VacuumCostActive
Definition: globals.c:152

◆ vacuum_is_relation_owner()

bool vacuum_is_relation_owner ( Oid  relid,
Form_pg_class  reltuple,
bits32  options 
)

Definition at line 559 of file vacuum.c.

References Assert, ereport, errmsg(), GetUserId(), MyDatabaseId, NameStr, pg_class_ownercheck(), pg_database_ownercheck(), relname, VACOPT_ANALYZE, VACOPT_VACUUM, and WARNING.

Referenced by analyze_rel(), expand_vacuum_rel(), get_all_vacuum_rels(), and vacuum_rel().

560 {
561  char *relname;
562 
564 
565  /*
566  * Check permissions.
567  *
568  * We allow the user to vacuum or analyze a table if he is superuser, the
569  * table owner, or the database owner (but in the latter case, only if
570  * it's not a shared relation). pg_class_ownercheck includes the
571  * superuser case.
572  *
573  * Note we choose to treat permissions failure as a WARNING and keep
574  * trying to vacuum or analyze the rest of the DB --- is this appropriate?
575  */
576  if (pg_class_ownercheck(relid, GetUserId()) ||
577  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !reltuple->relisshared))
578  return true;
579 
580  relname = NameStr(reltuple->relname);
581 
582  if ((options & VACOPT_VACUUM) != 0)
583  {
584  if (reltuple->relisshared)
586  (errmsg("skipping \"%s\" --- only superuser can vacuum it",
587  relname)));
588  else if (reltuple->relnamespace == PG_CATALOG_NAMESPACE)
590  (errmsg("skipping \"%s\" --- only superuser or database owner can vacuum it",
591  relname)));
592  else
594  (errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
595  relname)));
596 
597  /*
598  * For VACUUM ANALYZE, both logs could show up, but just generate
599  * information for VACUUM as that would be the first one to be
600  * processed.
601  */
602  return false;
603  }
604 
605  if ((options & VACOPT_ANALYZE) != 0)
606  {
607  if (reltuple->relisshared)
609  (errmsg("skipping \"%s\" --- only superuser can analyze it",
610  relname)));
611  else if (reltuple->relnamespace == PG_CATALOG_NAMESPACE)
613  (errmsg("skipping \"%s\" --- only superuser or database owner can analyze it",
614  relname)));
615  else
617  (errmsg("skipping \"%s\" --- only table or database owner can analyze it",
618  relname)));
619  }
620 
621  return false;
622 }
Oid GetUserId(void)
Definition: miscinit.c:495
#define VACOPT_ANALYZE
Definition: vacuum.h:179
NameData relname
Definition: pg_class.h:38
bool pg_database_ownercheck(Oid db_oid, Oid roleid)
Definition: aclchk.c:5236
#define WARNING
Definition: elog.h:40
Oid MyDatabaseId
Definition: globals.c:88
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define VACOPT_VACUUM
Definition: vacuum.h:178
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4818
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define NameStr(name)
Definition: c.h:681

◆ vacuum_open_relation()

Relation vacuum_open_relation ( Oid  relid,
RangeVar relation,
bits32  options,
bool  verbose,
LOCKMODE  lmode 
)

Definition at line 633 of file vacuum.c.

References Assert, ConditionalLockRelationOid(), elevel, ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), IsAutoVacuumWorkerProcess(), LOG, NoLock, RangeVar::relname, try_relation_open(), VACOPT_ANALYZE, VACOPT_SKIP_LOCKED, VACOPT_VACUUM, and WARNING.

Referenced by analyze_rel(), and vacuum_rel().

635 {
636  Relation rel;
637  bool rel_lock = true;
638  int elevel;
639 
641 
642  /*
643  * Open the relation and get the appropriate lock on it.
644  *
645  * There's a race condition here: the relation may have gone away since
646  * the last time we saw it. If so, we don't need to vacuum or analyze it.
647  *
648  * If we've been asked not to wait for the relation lock, acquire it first
649  * in non-blocking mode, before calling try_relation_open().
650  */
651  if (!(options & VACOPT_SKIP_LOCKED))
652  rel = try_relation_open(relid, lmode);
653  else if (ConditionalLockRelationOid(relid, lmode))
654  rel = try_relation_open(relid, NoLock);
655  else
656  {
657  rel = NULL;
658  rel_lock = false;
659  }
660 
661  /* if relation is opened, leave */
662  if (rel)
663  return rel;
664 
665  /*
666  * Relation could not be opened, hence generate if possible a log
667  * informing on the situation.
668  *
669  * If the RangeVar is not defined, we do not have enough information to
670  * provide a meaningful log statement. Chances are that the caller has
671  * intentionally not provided this information so that this logging is
672  * skipped, anyway.
673  */
674  if (relation == NULL)
675  return NULL;
676 
677  /*
678  * Determine the log level.
679  *
680  * For manual VACUUM or ANALYZE, we emit a WARNING to match the log
681  * statements in the permission checks; otherwise, only log if the caller
682  * so requested.
683  */
685  elevel = WARNING;
686  else if (verbose)
687  elevel = LOG;
688  else
689  return NULL;
690 
691  if ((options & VACOPT_VACUUM) != 0)
692  {
693  if (!rel_lock)
694  ereport(elevel,
695  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
696  errmsg("skipping vacuum of \"%s\" --- lock not available",
697  relation->relname)));
698  else
699  ereport(elevel,
701  errmsg("skipping vacuum of \"%s\" --- relation no longer exists",
702  relation->relname)));
703 
704  /*
705  * For VACUUM ANALYZE, both logs could show up, but just generate
706  * information for VACUUM as that would be the first one to be
707  * processed.
708  */
709  return NULL;
710  }
711 
712  if ((options & VACOPT_ANALYZE) != 0)
713  {
714  if (!rel_lock)
715  ereport(elevel,
716  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
717  errmsg("skipping analyze of \"%s\" --- lock not available",
718  relation->relname)));
719  else
720  ereport(elevel,
722  errmsg("skipping analyze of \"%s\" --- relation no longer exists",
723  relation->relname)));
724  }
725 
726  return NULL;
727 }
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:152
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
#define VACOPT_ANALYZE
Definition: vacuum.h:179
int errcode(int sqlerrcode)
Definition: elog.c:698
#define LOG
Definition: elog.h:26
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
char * relname
Definition: primnodes.h:68
#define NoLock
Definition: lockdefs.h:34
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3410
static int verbose
#define WARNING
Definition: elog.h:40
static int elevel
Definition: vacuumlazy.c:401
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define VACOPT_VACUUM
Definition: vacuum.h:178
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define VACOPT_SKIP_LOCKED
Definition: vacuum.h:183

◆ vacuum_set_xid_limits()

void vacuum_set_xid_limits ( Relation  rel,
int  freeze_min_age,
int  freeze_table_age,
int  multixact_freeze_min_age,
int  multixact_freeze_table_age,
TransactionId oldestXmin,
TransactionId freezeLimit,
TransactionId xidFullScanLimit,
MultiXactId multiXactCutoff,
MultiXactId mxactFullScanLimit 
)

Definition at line 957 of file vacuum.c.

References Assert, autovacuum_freeze_max_age, ereport, errhint(), errmsg(), FirstMultiXactId, FirstNormalTransactionId, GetOldestMultiXactId(), GetOldestNonRemovableTransactionId(), Min, MultiXactIdPrecedes(), MultiXactMemberFreezeThreshold(), OldSnapshotThresholdActive(), ReadNextMultiXactId(), ReadNextTransactionId(), SetOldSnapshotThresholdTimestamp(), TransactionIdIsNormal, TransactionIdLimitedForOldSnapshots(), TransactionIdPrecedes(), vacuum_freeze_min_age, vacuum_freeze_table_age, vacuum_multixact_freeze_min_age, vacuum_multixact_freeze_table_age, and WARNING.

Referenced by copy_table_data(), and heap_vacuum_rel().

967 {
968  int freezemin;
969  int mxid_freezemin;
970  int effective_multixact_freeze_max_age;
971  TransactionId limit;
972  TransactionId safeLimit;
973  MultiXactId oldestMxact;
974  MultiXactId mxactLimit;
975  MultiXactId safeMxactLimit;
976 
977  /*
978  * We can always ignore processes running lazy vacuum. This is because we
979  * use these values only for deciding which tuples we must keep in the
980  * tables. Since lazy vacuum doesn't write its XID anywhere (usually no
981  * XID assigned), it's safe to ignore it. In theory it could be
982  * problematic to ignore lazy vacuums in a full vacuum, but keep in mind
983  * that only one vacuum process can be working on a particular table at
984  * any time, and that each vacuum is always an independent transaction.
985  */
986  *oldestXmin = GetOldestNonRemovableTransactionId(rel);
987 
989  {
990  TransactionId limit_xmin;
991  TimestampTz limit_ts;
992 
993  if (TransactionIdLimitedForOldSnapshots(*oldestXmin, rel,
994  &limit_xmin, &limit_ts))
995  {
996  /*
997  * TODO: We should only set the threshold if we are pruning on the
998  * basis of the increased limits. Not as crucial here as it is
999  * for opportunistic pruning (which often happens at a much higher
1000  * frequency), but would still be a significant improvement.
1001  */
1002  SetOldSnapshotThresholdTimestamp(limit_ts, limit_xmin);
1003  *oldestXmin = limit_xmin;
1004  }
1005  }
1006 
1007  Assert(TransactionIdIsNormal(*oldestXmin));
1008 
1009  /*
1010  * Determine the minimum freeze age to use: as specified by the caller, or
1011  * vacuum_freeze_min_age, but in any case not more than half
1012  * autovacuum_freeze_max_age, so that autovacuums to prevent XID
1013  * wraparound won't occur too frequently.
1014  */
1015  freezemin = freeze_min_age;
1016  if (freezemin < 0)
1017  freezemin = vacuum_freeze_min_age;
1018  freezemin = Min(freezemin, autovacuum_freeze_max_age / 2);
1019  Assert(freezemin >= 0);
1020 
1021  /*
1022  * Compute the cutoff XID, being careful not to generate a "permanent" XID
1023  */
1024  limit = *oldestXmin - freezemin;
1025  if (!TransactionIdIsNormal(limit))
1026  limit = FirstNormalTransactionId;
1027 
1028  /*
1029  * If oldestXmin is very far back (in practice, more than
1030  * autovacuum_freeze_max_age / 2 XIDs old), complain and force a minimum
1031  * freeze age of zero.
1032  */
1034  if (!TransactionIdIsNormal(safeLimit))
1035  safeLimit = FirstNormalTransactionId;
1036 
1037  if (TransactionIdPrecedes(limit, safeLimit))
1038  {
1039  ereport(WARNING,
1040  (errmsg("oldest xmin is far in the past"),
1041  errhint("Close open transactions soon to avoid wraparound problems.\n"
1042  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1043  limit = *oldestXmin;
1044  }
1045 
1046  *freezeLimit = limit;
1047 
1048  /*
1049  * Compute the multixact age for which freezing is urgent. This is
1050  * normally autovacuum_multixact_freeze_max_age, but may be less if we are
1051  * short of multixact member space.
1052  */
1053  effective_multixact_freeze_max_age = MultiXactMemberFreezeThreshold();
1054 
1055  /*
1056  * Determine the minimum multixact freeze age to use: as specified by
1057  * caller, or vacuum_multixact_freeze_min_age, but in any case not more
1058  * than half effective_multixact_freeze_max_age, so that autovacuums to
1059  * prevent MultiXact wraparound won't occur too frequently.
1060  */
1061  mxid_freezemin = multixact_freeze_min_age;
1062  if (mxid_freezemin < 0)
1063  mxid_freezemin = vacuum_multixact_freeze_min_age;
1064  mxid_freezemin = Min(mxid_freezemin,
1065  effective_multixact_freeze_max_age / 2);
1066  Assert(mxid_freezemin >= 0);
1067 
1068  /* compute the cutoff multi, being careful to generate a valid value */
1069  oldestMxact = GetOldestMultiXactId();
1070  mxactLimit = oldestMxact - mxid_freezemin;
1071  if (mxactLimit < FirstMultiXactId)
1072  mxactLimit = FirstMultiXactId;
1073 
1074  safeMxactLimit =
1075  ReadNextMultiXactId() - effective_multixact_freeze_max_age;
1076  if (safeMxactLimit < FirstMultiXactId)
1077  safeMxactLimit = FirstMultiXactId;
1078 
1079  if (MultiXactIdPrecedes(mxactLimit, safeMxactLimit))
1080  {
1081  ereport(WARNING,
1082  (errmsg("oldest multixact is far in the past"),
1083  errhint("Close open transactions with multixacts soon to avoid wraparound problems.")));
1084  /* Use the safe limit, unless an older mxact is still running */
1085  if (MultiXactIdPrecedes(oldestMxact, safeMxactLimit))
1086  mxactLimit = oldestMxact;
1087  else
1088  mxactLimit = safeMxactLimit;
1089  }
1090 
1091  *multiXactCutoff = mxactLimit;
1092 
1093  if (xidFullScanLimit != NULL)
1094  {
1095  int freezetable;
1096 
1097  Assert(mxactFullScanLimit != NULL);
1098 
1099  /*
1100  * Determine the table freeze age to use: as specified by the caller,
1101  * or vacuum_freeze_table_age, but in any case not more than
1102  * autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly
1103  * VACUUM schedule, the nightly VACUUM gets a chance to freeze tuples
1104  * before anti-wraparound autovacuum is launched.
1105  */
1106  freezetable = freeze_table_age;
1107  if (freezetable < 0)
1108  freezetable = vacuum_freeze_table_age;
1109  freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95);
1110  Assert(freezetable >= 0);
1111 
1112  /*
1113  * Compute XID limit causing a full-table vacuum, being careful not to
1114  * generate a "permanent" XID.
1115  */
1116  limit = ReadNextTransactionId() - freezetable;
1117  if (!TransactionIdIsNormal(limit))
1118  limit = FirstNormalTransactionId;
1119 
1120  *xidFullScanLimit = limit;
1121 
1122  /*
1123  * Similar to the above, determine the table freeze age to use for
1124  * multixacts: as specified by the caller, or
1125  * vacuum_multixact_freeze_table_age, but in any case not more than
1126  * autovacuum_multixact_freeze_table_age * 0.95, so that if you have
1127  * e.g. nightly VACUUM schedule, the nightly VACUUM gets a chance to
1128  * freeze multixacts before anti-wraparound autovacuum is launched.
1129  */
1130  freezetable = multixact_freeze_table_age;
1131  if (freezetable < 0)
1132  freezetable = vacuum_multixact_freeze_table_age;
1133  freezetable = Min(freezetable,
1134  effective_multixact_freeze_max_age * 0.95);
1135  Assert(freezetable >= 0);
1136 
1137  /*
1138  * Compute MultiXact limit causing a full-table vacuum, being careful
1139  * to generate a valid MultiXact value.
1140  */
1141  mxactLimit = ReadNextMultiXactId() - freezetable;
1142  if (mxactLimit < FirstMultiXactId)
1143  mxactLimit = FirstMultiXactId;
1144 
1145  *mxactFullScanLimit = mxactLimit;
1146  }
1147  else
1148  {
1149  Assert(mxactFullScanLimit == NULL);
1150  }
1151 }
int errhint(const char *fmt,...)
Definition: elog.c:1156
int vacuum_multixact_freeze_table_age
Definition: vacuum.c:64
uint32 TransactionId
Definition: c.h:587
int64 TimestampTz
Definition: timestamp.h:39
static bool OldSnapshotThresholdActive(void)
Definition: snapmgr.h:101
#define Min(x, y)
Definition: c.h:986
static TransactionId ReadNextTransactionId(void)
Definition: transam.h:316
bool TransactionIdLimitedForOldSnapshots(TransactionId recentXmin, Relation relation, TransactionId *limit_xid, TimestampTz *limit_ts)
Definition: snapmgr.c:1766
void SetOldSnapshotThresholdTimestamp(TimestampTz ts, TransactionId xlimit)
Definition: snapmgr.c:1687
TransactionId GetOldestNonRemovableTransactionId(Relation rel)
Definition: procarray.c:2005
#define FirstNormalTransactionId
Definition: transam.h:34
int autovacuum_freeze_max_age
Definition: autovacuum.c:124
int vacuum_multixact_freeze_min_age
Definition: vacuum.c:63
#define FirstMultiXactId
Definition: multixact.h:25
int MultiXactMemberFreezeThreshold(void)
Definition: multixact.c:2828
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define WARNING
Definition: elog.h:40
MultiXactId GetOldestMultiXactId(void)
Definition: multixact.c:2506
#define ereport(elevel,...)
Definition: elog.h:157
TransactionId MultiXactId
Definition: c.h:597
#define Assert(condition)
Definition: c.h:804
int vacuum_freeze_min_age
Definition: vacuum.c:61
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3159
int vacuum_freeze_table_age
Definition: vacuum.c:62
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:723

◆ vacuum_xid_failsafe_check()

bool vacuum_xid_failsafe_check ( TransactionId  relfrozenxid,
MultiXactId  relminmxid 
)

Definition at line 1163 of file vacuum.c.

References Assert, autovacuum_freeze_max_age, autovacuum_multixact_freeze_max_age, FirstMultiXactId, FirstNormalTransactionId, Max, MultiXactIdIsValid, MultiXactIdPrecedes(), ReadNextMultiXactId(), ReadNextTransactionId(), TransactionIdIsNormal, TransactionIdPrecedes(), vacuum_failsafe_age, and vacuum_multixact_failsafe_age.

Referenced by lazy_check_wraparound_failsafe().

1164 {
1165  TransactionId xid_skip_limit;
1166  MultiXactId multi_skip_limit;
1167  int skip_index_vacuum;
1168 
1169  Assert(TransactionIdIsNormal(relfrozenxid));
1170  Assert(MultiXactIdIsValid(relminmxid));
1171 
1172  /*
1173  * Determine the index skipping age to use. In any case no less than
1174  * autovacuum_freeze_max_age * 1.05.
1175  */
1176  skip_index_vacuum = Max(vacuum_failsafe_age, autovacuum_freeze_max_age * 1.05);
1177 
1178  xid_skip_limit = ReadNextTransactionId() - skip_index_vacuum;
1179  if (!TransactionIdIsNormal(xid_skip_limit))
1180  xid_skip_limit = FirstNormalTransactionId;
1181 
1182  if (TransactionIdPrecedes(relfrozenxid, xid_skip_limit))
1183  {
1184  /* The table's relfrozenxid is too old */
1185  return true;
1186  }
1187 
1188  /*
1189  * Similar to above, determine the index skipping age to use for
1190  * multixact. In any case no less than autovacuum_multixact_freeze_max_age *
1191  * 1.05.
1192  */
1193  skip_index_vacuum = Max(vacuum_multixact_failsafe_age,
1195 
1196  multi_skip_limit = ReadNextMultiXactId() - skip_index_vacuum;
1197  if (multi_skip_limit < FirstMultiXactId)
1198  multi_skip_limit = FirstMultiXactId;
1199 
1200  if (MultiXactIdPrecedes(relminmxid, multi_skip_limit))
1201  {
1202  /* The table's relminmxid is too old */
1203  return true;
1204  }
1205 
1206  return false;
1207 }
uint32 TransactionId
Definition: c.h:587
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:125
static TransactionId ReadNextTransactionId(void)
Definition: transam.h:316
#define FirstNormalTransactionId
Definition: transam.h:34
int autovacuum_freeze_max_age
Definition: autovacuum.c:124
int vacuum_failsafe_age
Definition: vacuum.c:65
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define FirstMultiXactId
Definition: multixact.h:25
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
int vacuum_multixact_failsafe_age
Definition: vacuum.c:66
TransactionId MultiXactId
Definition: c.h:597
#define Max(x, y)
Definition: c.h:980
#define Assert(condition)
Definition: c.h:804
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3159
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:723

Variable Documentation

◆ default_statistics_target

PGDLLIMPORT int default_statistics_target

◆ vacuum_failsafe_age

int vacuum_failsafe_age

Definition at line 65 of file vacuum.c.

Referenced by vacuum_xid_failsafe_check().

◆ vacuum_freeze_min_age

int vacuum_freeze_min_age

Definition at line 61 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().

◆ vacuum_freeze_table_age

int vacuum_freeze_table_age

Definition at line 62 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().

◆ vacuum_multixact_failsafe_age

int vacuum_multixact_failsafe_age

Definition at line 66 of file vacuum.c.

Referenced by vacuum_xid_failsafe_check().

◆ vacuum_multixact_freeze_min_age

int vacuum_multixact_freeze_min_age

Definition at line 63 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().

◆ vacuum_multixact_freeze_table_age

int vacuum_multixact_freeze_table_age

Definition at line 64 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().

◆ VacuumActiveNWorkers

◆ VacuumCostBalanceLocal

int VacuumCostBalanceLocal

◆ VacuumSharedCostBalance

pg_atomic_uint32* VacuumSharedCostBalance

Definition at line 78 of file vacuum.c.

Referenced by do_parallel_vacuum_or_cleanup(), and parallel_vacuum_main().