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 VacOptTernaryValue VacOptTernaryValue
 
typedef struct VacuumParams VacuumParams
 

Enumerations

enum  VacOptTernaryValue { VACOPT_TERNARY_DEFAULT = 0, VACOPT_TERNARY_DISABLED, VACOPT_TERNARY_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.

◆ VacOptTernaryValue

◆ VacuumParams

typedef struct VacuumParams VacuumParams

Enumeration Type Documentation

◆ VacOptTernaryValue

Enumerator
VACOPT_TERNARY_DEFAULT 
VACOPT_TERNARY_DISABLED 
VACOPT_TERNARY_ENABLED 

Definition at line 193 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:208
#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:503
#define WARNING
Definition: elog.h:40
static int elevel
Definition: vacuumlazy.c:400
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:213
#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:612
int log_min_duration
Definition: vacuum.h:216
#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:619
bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, bits32 options)
Definition: vacuum.c:545
#define RelationGetRelid(relation)
Definition: rel.h:469
static int acquire_sample_rows(Relation onerel, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: analyze.c:1149

◆ 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(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, VacuumParams::freeze_min_age, VacuumParams::freeze_table_age, get_vacopt_ternary_value(), 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(), VacuumStmt::rels, VacuumParams::truncate, VacuumRelation::va_cols, VACOPT_ANALYZE, VACOPT_DISABLE_PAGE_SKIPPING, VACOPT_FREEZE, VACOPT_FULL, VACOPT_PROCESS_TOAST, VACOPT_SKIP_LOCKED, VACOPT_TERNARY_DEFAULT, VACOPT_VACUUM, VACOPT_VERBOSE, 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  /* Set default value */
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)
146  else if (strcmp(opt->defname, "process_toast") == 0)
147  process_toast = defGetBoolean(opt);
148  else if (strcmp(opt->defname, "truncate") == 0)
149  params.truncate = get_vacopt_ternary_value(opt);
150  else if (strcmp(opt->defname, "parallel") == 0)
151  {
152  if (opt->arg == NULL)
153  {
154  ereport(ERROR,
155  (errcode(ERRCODE_SYNTAX_ERROR),
156  errmsg("parallel option requires a value between 0 and %d",
158  parser_errposition(pstate, opt->location)));
159  }
160  else
161  {
162  int nworkers;
163 
164  nworkers = defGetInt32(opt);
165  if (nworkers < 0 || nworkers > MAX_PARALLEL_WORKER_LIMIT)
166  ereport(ERROR,
167  (errcode(ERRCODE_SYNTAX_ERROR),
168  errmsg("parallel vacuum degree must be between 0 and %d",
169  MAX_PARALLEL_WORKER_LIMIT),
170  parser_errposition(pstate, opt->location)));
171 
172  /*
173  * Disable parallel vacuum, if user has specified parallel
174  * degree as zero.
175  */
176  if (nworkers == 0)
177  params.nworkers = -1;
178  else
179  params.nworkers = nworkers;
180  }
181  }
182  else
183  ereport(ERROR,
184  (errcode(ERRCODE_SYNTAX_ERROR),
185  errmsg("unrecognized VACUUM option \"%s\"", opt->defname),
186  parser_errposition(pstate, opt->location)));
187  }
188 
189  /* Set vacuum options */
190  params.options =
191  (vacstmt->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE) |
192  (verbose ? VACOPT_VERBOSE : 0) |
193  (skip_locked ? VACOPT_SKIP_LOCKED : 0) |
194  (analyze ? VACOPT_ANALYZE : 0) |
195  (freeze ? VACOPT_FREEZE : 0) |
196  (full ? VACOPT_FULL : 0) |
197  (disable_page_skipping ? VACOPT_DISABLE_PAGE_SKIPPING : 0) |
198  (process_toast ? VACOPT_PROCESS_TOAST : 0);
199 
200  /* sanity checks on options */
201  Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE));
202  Assert((params.options & VACOPT_VACUUM) ||
203  !(params.options & (VACOPT_FULL | VACOPT_FREEZE)));
204 
205  if ((params.options & VACOPT_FULL) && params.nworkers > 0)
206  ereport(ERROR,
207  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
208  errmsg("VACUUM FULL cannot be performed in parallel")));
209 
210  /*
211  * Make sure VACOPT_ANALYZE is specified if any column lists are present.
212  */
213  if (!(params.options & VACOPT_ANALYZE))
214  {
215  ListCell *lc;
216 
217  foreach(lc, vacstmt->rels)
218  {
220 
221  if (vrel->va_cols != NIL)
222  ereport(ERROR,
223  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
224  errmsg("ANALYZE option must be specified when a column list is provided")));
225  }
226  }
227 
228  /*
229  * All freeze ages are zero if the FREEZE option is given; otherwise pass
230  * them as -1 which means to use the default values.
231  */
232  if (params.options & VACOPT_FREEZE)
233  {
234  params.freeze_min_age = 0;
235  params.freeze_table_age = 0;
236  params.multixact_freeze_min_age = 0;
237  params.multixact_freeze_table_age = 0;
238  }
239  else
240  {
241  params.freeze_min_age = -1;
242  params.freeze_table_age = -1;
243  params.multixact_freeze_min_age = -1;
244  params.multixact_freeze_table_age = -1;
245  }
246 
247  /* user-invoked vacuum is never "for wraparound" */
248  params.is_wraparound = false;
249 
250  /* user-invoked vacuum never uses this parameter */
251  params.log_min_duration = -1;
252 
253  /* Now go through the common routine */
254  vacuum(vacstmt->rels, &params, NULL, isTopLevel);
255 }
#define NIL
Definition: pg_list.h:65
int multixact_freeze_table_age
Definition: vacuum.h:213
void vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel)
Definition: vacuum.c:277
#define VACOPT_DISABLE_PAGE_SKIPPING
Definition: vacuum.h:185
#define VACOPT_ANALYZE
Definition: vacuum.h:179
bool is_vacuumcmd
Definition: parsenodes.h:3327
int32 defGetInt32(DefElem *def)
Definition: define.c:166
int errcode(int sqlerrcode)
Definition: elog.c:698
int freeze_table_age
Definition: vacuum.h:210
#define VACOPT_PROCESS_TOAST
Definition: vacuum.h:184
bool defGetBoolean(DefElem *def)
Definition: define.c:111
bits32 options
Definition: vacuum.h:208
#define ERROR
Definition: elog.h:46
int freeze_min_age
Definition: vacuum.h:209
bool is_wraparound
Definition: vacuum.h:215
#define lfirst_node(type, lc)
Definition: pg_list.h:172
int location
Definition: parsenodes.h:749
#define VACOPT_FREEZE
Definition: vacuum.h:181
VacOptTernaryValue index_cleanup
Definition: vacuum.h:219
Node * arg
Definition: parsenodes.h:747
static int verbose
VacOptTernaryValue truncate
Definition: vacuum.h:221
#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:229
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
int log_min_duration
Definition: vacuum.h:216
#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:3325
char * defname
Definition: parsenodes.h:746
#define MAX_PARALLEL_WORKER_LIMIT
int multixact_freeze_min_age
Definition: vacuum.h:211
static long analyze(struct nfa *nfa)
Definition: regc_nfa.c:2987
List * rels
Definition: parsenodes.h:3326
static VacOptTernaryValue get_vacopt_ternary_value(DefElem *def)
Definition: vacuum.c:2224

◆ std_typanalyze()

bool std_typanalyze ( VacAttrStats stats)

Definition at line 1872 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().

1873 {
1874  Form_pg_attribute attr = stats->attr;
1875  Oid ltopr;
1876  Oid eqopr;
1877  StdAnalyzeData *mystats;
1878 
1879  /* If the attstattarget column is negative, use the default value */
1880  /* NB: it is okay to scribble on stats->attr since it's a copy */
1881  if (attr->attstattarget < 0)
1882  attr->attstattarget = default_statistics_target;
1883 
1884  /* Look for default "<" and "=" operators for column's type */
1886  false, false, false,
1887  &ltopr, &eqopr, NULL,
1888  NULL);
1889 
1890  /* Save the operator info for compute_stats routines */
1891  mystats = (StdAnalyzeData *) palloc(sizeof(StdAnalyzeData));
1892  mystats->eqopr = eqopr;
1893  mystats->eqfunc = OidIsValid(eqopr) ? get_opcode(eqopr) : InvalidOid;
1894  mystats->ltopr = ltopr;
1895  stats->extra_data = mystats;
1896 
1897  /*
1898  * Determine which standard statistics algorithm to use
1899  */
1900  if (OidIsValid(eqopr) && OidIsValid(ltopr))
1901  {
1902  /* Seems to be a scalar datatype */
1904  /*--------------------
1905  * The following choice of minrows is based on the paper
1906  * "Random sampling for histogram construction: how much is enough?"
1907  * by Surajit Chaudhuri, Rajeev Motwani and Vivek Narasayya, in
1908  * Proceedings of ACM SIGMOD International Conference on Management
1909  * of Data, 1998, Pages 436-447. Their Corollary 1 to Theorem 5
1910  * says that for table size n, histogram size k, maximum relative
1911  * error in bin size f, and error probability gamma, the minimum
1912  * random sample size is
1913  * r = 4 * k * ln(2*n/gamma) / f^2
1914  * Taking f = 0.5, gamma = 0.01, n = 10^6 rows, we obtain
1915  * r = 305.82 * k
1916  * Note that because of the log function, the dependence on n is
1917  * quite weak; even at n = 10^12, a 300*k sample gives <= 0.66
1918  * bin size error with probability 0.99. So there's no real need to
1919  * scale for n, which is a good thing because we don't necessarily
1920  * know it at this point.
1921  *--------------------
1922  */
1923  stats->minrows = 300 * attr->attstattarget;
1924  }
1925  else if (OidIsValid(eqopr))
1926  {
1927  /* We can still recognize distinct values */
1929  /* Might as well use the same minrows as above */
1930  stats->minrows = 300 * attr->attstattarget;
1931  }
1932  else
1933  {
1934  /* Can't do much but the trivial stuff */
1936  /* Might as well use the same minrows as above */
1937  stats->minrows = 300 * attr->attstattarget;
1938  }
1939 
1940  return true;
1941 }
int minrows
Definition: vacuum.h:135
static void compute_scalar_stats(VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
Definition: analyze.c:2385
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:203
static void compute_distinct_stats(VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
Definition: analyze.c:2042
#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:1952
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 2095 of file vacuum.c.

References index_close(), and pfree().

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

2096 {
2097  if (Irel == NULL)
2098  return;
2099 
2100  while (nindexes--)
2101  {
2102  Relation ind = Irel[nindexes];
2103 
2104  index_close(ind, lockmode);
2105  }
2106  pfree(Irel);
2107 }
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 1209 of file vacuum.c.

References RelationData::rd_rel.

Referenced by lazy_scan_heap(), and statapprox_heap().

1213 {
1214  BlockNumber old_rel_pages = relation->rd_rel->relpages;
1215  double old_rel_tuples = relation->rd_rel->reltuples;
1216  double old_density;
1217  double unscanned_pages;
1218  double total_tuples;
1219 
1220  /* If we did scan the whole table, just use the count as-is */
1221  if (scanned_pages >= total_pages)
1222  return scanned_tuples;
1223 
1224  /*
1225  * If scanned_pages is zero but total_pages isn't, keep the existing value
1226  * of reltuples. (Note: we might be returning -1 in this case.)
1227  */
1228  if (scanned_pages == 0)
1229  return old_rel_tuples;
1230 
1231  /*
1232  * If old density is unknown, we can't do much except scale up
1233  * scanned_tuples to match total_pages.
1234  */
1235  if (old_rel_tuples < 0 || old_rel_pages == 0)
1236  return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
1237 
1238  /*
1239  * Okay, we've covered the corner cases. The normal calculation is to
1240  * convert the old measurement to a density (tuples per page), then
1241  * estimate the number of tuples in the unscanned pages using that figure,
1242  * and finally add on the number of tuples in the scanned pages.
1243  */
1244  old_density = old_rel_tuples / old_rel_pages;
1245  unscanned_pages = (double) total_pages - (double) scanned_pages;
1246  total_tuples = old_density * unscanned_pages + scanned_tuples;
1247  return floor(total_tuples + 0.5);
1248 }
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 2052 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().

2054 {
2055  List *indexoidlist;
2056  ListCell *indexoidscan;
2057  int i;
2058 
2059  Assert(lockmode != NoLock);
2060 
2061  indexoidlist = RelationGetIndexList(relation);
2062 
2063  /* allocate enough memory for all indexes */
2064  i = list_length(indexoidlist);
2065 
2066  if (i > 0)
2067  *Irel = (Relation *) palloc(i * sizeof(Relation));
2068  else
2069  *Irel = NULL;
2070 
2071  /* collect just the ready indexes */
2072  i = 0;
2073  foreach(indexoidscan, indexoidlist)
2074  {
2075  Oid indexoid = lfirst_oid(indexoidscan);
2076  Relation indrel;
2077 
2078  indrel = index_open(indexoid, lockmode);
2079  if (indrel->rd_index->indisready)
2080  (*Irel)[i++] = indrel;
2081  else
2082  index_close(indrel, lockmode);
2083  }
2084 
2085  *nindexes = i;
2086 
2087  list_free(indexoidlist);
2088 }
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:4570
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 1419 of file vacuum.c.

References AccessShareLock, Assert, BTEqualStrategyNumber, DatabaseOidIndexId, 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().

1420 {
1421  HeapTuple tuple;
1422  Form_pg_database dbform;
1423  Relation relation;
1424  SysScanDesc scan;
1425  HeapTuple classTup;
1426  TransactionId newFrozenXid;
1427  MultiXactId newMinMulti;
1428  TransactionId lastSaneFrozenXid;
1429  MultiXactId lastSaneMinMulti;
1430  bool bogus = false;
1431  bool dirty = false;
1432  ScanKeyData key[1];
1433 
1434  /*
1435  * Restrict this task to one backend per database. This avoids race
1436  * conditions that would move datfrozenxid or datminmxid backward. It
1437  * avoids calling vac_truncate_clog() with a datfrozenxid preceding a
1438  * datfrozenxid passed to an earlier vac_truncate_clog() call.
1439  */
1441 
1442  /*
1443  * Initialize the "min" calculation with
1444  * GetOldestNonRemovableTransactionId(), which is a reasonable
1445  * approximation to the minimum relfrozenxid for not-yet-committed
1446  * pg_class entries for new tables; see AddNewRelationTuple(). So we
1447  * cannot produce a wrong minimum by starting with this.
1448  */
1449  newFrozenXid = GetOldestNonRemovableTransactionId(NULL);
1450 
1451  /*
1452  * Similarly, initialize the MultiXact "min" with the value that would be
1453  * used on pg_class for new tables. See AddNewRelationTuple().
1454  */
1455  newMinMulti = GetOldestMultiXactId();
1456 
1457  /*
1458  * Identify the latest relfrozenxid and relminmxid values that we could
1459  * validly see during the scan. These are conservative values, but it's
1460  * not really worth trying to be more exact.
1461  */
1462  lastSaneFrozenXid = ReadNextTransactionId();
1463  lastSaneMinMulti = ReadNextMultiXactId();
1464 
1465  /*
1466  * We must seqscan pg_class to find the minimum Xid, because there is no
1467  * index that can help us here.
1468  */
1469  relation = table_open(RelationRelationId, AccessShareLock);
1470 
1471  scan = systable_beginscan(relation, InvalidOid, false,
1472  NULL, 0, NULL);
1473 
1474  while ((classTup = systable_getnext(scan)) != NULL)
1475  {
1476  Form_pg_class classForm = (Form_pg_class) GETSTRUCT(classTup);
1477 
1478  /*
1479  * Only consider relations able to hold unfrozen XIDs (anything else
1480  * should have InvalidTransactionId in relfrozenxid anyway).
1481  */
1482  if (classForm->relkind != RELKIND_RELATION &&
1483  classForm->relkind != RELKIND_MATVIEW &&
1484  classForm->relkind != RELKIND_TOASTVALUE)
1485  {
1486  Assert(!TransactionIdIsValid(classForm->relfrozenxid));
1487  Assert(!MultiXactIdIsValid(classForm->relminmxid));
1488  continue;
1489  }
1490 
1491  /*
1492  * Some table AMs might not need per-relation xid / multixid horizons.
1493  * It therefore seems reasonable to allow relfrozenxid and relminmxid
1494  * to not be set (i.e. set to their respective Invalid*Id)
1495  * independently. Thus validate and compute horizon for each only if
1496  * set.
1497  *
1498  * If things are working properly, no relation should have a
1499  * relfrozenxid or relminmxid that is "in the future". However, such
1500  * cases have been known to arise due to bugs in pg_upgrade. If we
1501  * see any entries that are "in the future", chicken out and don't do
1502  * anything. This ensures we won't truncate clog & multixact SLRUs
1503  * before those relations have been scanned and cleaned up.
1504  */
1505 
1506  if (TransactionIdIsValid(classForm->relfrozenxid))
1507  {
1508  Assert(TransactionIdIsNormal(classForm->relfrozenxid));
1509 
1510  /* check for values in the future */
1511  if (TransactionIdPrecedes(lastSaneFrozenXid, classForm->relfrozenxid))
1512  {
1513  bogus = true;
1514  break;
1515  }
1516 
1517  /* determine new horizon */
1518  if (TransactionIdPrecedes(classForm->relfrozenxid, newFrozenXid))
1519  newFrozenXid = classForm->relfrozenxid;
1520  }
1521 
1522  if (MultiXactIdIsValid(classForm->relminmxid))
1523  {
1524  /* check for values in the future */
1525  if (MultiXactIdPrecedes(lastSaneMinMulti, classForm->relminmxid))
1526  {
1527  bogus = true;
1528  break;
1529  }
1530 
1531  /* determine new horizon */
1532  if (MultiXactIdPrecedes(classForm->relminmxid, newMinMulti))
1533  newMinMulti = classForm->relminmxid;
1534  }
1535  }
1536 
1537  /* we're done with pg_class */
1538  systable_endscan(scan);
1539  table_close(relation, AccessShareLock);
1540 
1541  /* chicken out if bogus data found */
1542  if (bogus)
1543  return;
1544 
1545  Assert(TransactionIdIsNormal(newFrozenXid));
1546  Assert(MultiXactIdIsValid(newMinMulti));
1547 
1548  /* Now fetch the pg_database tuple we need to update. */
1549  relation = table_open(DatabaseRelationId, RowExclusiveLock);
1550 
1551  /*
1552  * Get the pg_database tuple to scribble on. Note that this does not
1553  * directly rely on the syscache to avoid issues with flattened toast
1554  * values for the in-place update.
1555  */
1556  ScanKeyInit(&key[0],
1557  Anum_pg_database_oid,
1558  BTEqualStrategyNumber, F_OIDEQ,
1560 
1561  scan = systable_beginscan(relation, DatabaseOidIndexId, true,
1562  NULL, 1, key);
1563  tuple = systable_getnext(scan);
1564  tuple = heap_copytuple(tuple);
1565  systable_endscan(scan);
1566 
1567  if (!HeapTupleIsValid(tuple))
1568  elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
1569 
1570  dbform = (Form_pg_database) GETSTRUCT(tuple);
1571 
1572  /*
1573  * As in vac_update_relstats(), we ordinarily don't want to let
1574  * datfrozenxid go backward; but if it's "in the future" then it must be
1575  * corrupt and it seems best to overwrite it.
1576  */
1577  if (dbform->datfrozenxid != newFrozenXid &&
1578  (TransactionIdPrecedes(dbform->datfrozenxid, newFrozenXid) ||
1579  TransactionIdPrecedes(lastSaneFrozenXid, dbform->datfrozenxid)))
1580  {
1581  dbform->datfrozenxid = newFrozenXid;
1582  dirty = true;
1583  }
1584  else
1585  newFrozenXid = dbform->datfrozenxid;
1586 
1587  /* Ditto for datminmxid */
1588  if (dbform->datminmxid != newMinMulti &&
1589  (MultiXactIdPrecedes(dbform->datminmxid, newMinMulti) ||
1590  MultiXactIdPrecedes(lastSaneMinMulti, dbform->datminmxid)))
1591  {
1592  dbform->datminmxid = newMinMulti;
1593  dirty = true;
1594  }
1595  else
1596  newMinMulti = dbform->datminmxid;
1597 
1598  if (dirty)
1599  heap_inplace_update(relation, tuple);
1600 
1601  heap_freetuple(tuple);
1602  table_close(relation, RowExclusiveLock);
1603 
1604  /*
1605  * If we were able to advance datfrozenxid or datminmxid, see if we can
1606  * truncate pg_xact and/or pg_multixact. Also do it if the shared
1607  * XID-wrap-limit info is stale, since this action will update that too.
1608  */
1609  if (dirty || ForceTransactionIdLimitUpdate())
1610  vac_truncate_clog(newFrozenXid, newMinMulti,
1611  lastSaneFrozenXid, lastSaneMinMulti);
1612 }
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:308
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:1944
#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
#define DatabaseOidIndexId
Definition: pg_database.h:90
MultiXactId GetOldestMultiXactId(void)
Definition: multixact.c:2503
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:3156
static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti)
Definition: vacuum.c:1633
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:6059
#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 1292 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().

1298 {
1299  Oid relid = RelationGetRelid(relation);
1300  Relation rd;
1301  HeapTuple ctup;
1302  Form_pg_class pgcform;
1303  bool dirty;
1304 
1305  rd = table_open(RelationRelationId, RowExclusiveLock);
1306 
1307  /* Fetch a copy of the tuple to scribble on */
1309  if (!HeapTupleIsValid(ctup))
1310  elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
1311  relid);
1312  pgcform = (Form_pg_class) GETSTRUCT(ctup);
1313 
1314  /* Apply statistical updates, if any, to copied tuple */
1315 
1316  dirty = false;
1317  if (pgcform->relpages != (int32) num_pages)
1318  {
1319  pgcform->relpages = (int32) num_pages;
1320  dirty = true;
1321  }
1322  if (pgcform->reltuples != (float4) num_tuples)
1323  {
1324  pgcform->reltuples = (float4) num_tuples;
1325  dirty = true;
1326  }
1327  if (pgcform->relallvisible != (int32) num_all_visible_pages)
1328  {
1329  pgcform->relallvisible = (int32) num_all_visible_pages;
1330  dirty = true;
1331  }
1332 
1333  /* Apply DDL updates, but not inside an outer transaction (see above) */
1334 
1335  if (!in_outer_xact)
1336  {
1337  /*
1338  * If we didn't find any indexes, reset relhasindex.
1339  */
1340  if (pgcform->relhasindex && !hasindex)
1341  {
1342  pgcform->relhasindex = false;
1343  dirty = true;
1344  }
1345 
1346  /* We also clear relhasrules and relhastriggers if needed */
1347  if (pgcform->relhasrules && relation->rd_rules == NULL)
1348  {
1349  pgcform->relhasrules = false;
1350  dirty = true;
1351  }
1352  if (pgcform->relhastriggers && relation->trigdesc == NULL)
1353  {
1354  pgcform->relhastriggers = false;
1355  dirty = true;
1356  }
1357  }
1358 
1359  /*
1360  * Update relfrozenxid, unless caller passed InvalidTransactionId
1361  * indicating it has no new data.
1362  *
1363  * Ordinarily, we don't let relfrozenxid go backwards: if things are
1364  * working correctly, the only way the new frozenxid could be older would
1365  * be if a previous VACUUM was done with a tighter freeze_min_age, in
1366  * which case we don't want to forget the work it already did. However,
1367  * if the stored relfrozenxid is "in the future", then it must be corrupt
1368  * and it seems best to overwrite it with the cutoff we used this time.
1369  * This should match vac_update_datfrozenxid() concerning what we consider
1370  * to be "in the future".
1371  */
1372  if (TransactionIdIsNormal(frozenxid) &&
1373  pgcform->relfrozenxid != frozenxid &&
1374  (TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid) ||
1376  pgcform->relfrozenxid)))
1377  {
1378  pgcform->relfrozenxid = frozenxid;
1379  dirty = true;
1380  }
1381 
1382  /* Similarly for relminmxid */
1383  if (MultiXactIdIsValid(minmulti) &&
1384  pgcform->relminmxid != minmulti &&
1385  (MultiXactIdPrecedes(pgcform->relminmxid, minmulti) ||
1386  MultiXactIdPrecedes(ReadNextMultiXactId(), pgcform->relminmxid)))
1387  {
1388  pgcform->relminmxid = minmulti;
1389  dirty = true;
1390  }
1391 
1392  /* If anything changed, write out the tuple. */
1393  if (dirty)
1394  heap_inplace_update(rd, ctup);
1395 
1397 }
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:308
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:3156
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:6059
#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:469
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:723

◆ vacuum()

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

Definition at line 277 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().

279 {
280  static bool in_vacuum = false;
281 
282  const char *stmttype;
283  volatile bool in_outer_xact,
284  use_own_xacts;
285 
286  Assert(params != NULL);
287 
288  stmttype = (params->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
289 
290  /*
291  * We cannot run VACUUM inside a user transaction block; if we were inside
292  * a transaction, then our commit- and start-transaction-command calls
293  * would not have the intended effect! There are numerous other subtle
294  * dependencies on this, too.
295  *
296  * ANALYZE (without VACUUM) can run either way.
297  */
298  if (params->options & VACOPT_VACUUM)
299  {
300  PreventInTransactionBlock(isTopLevel, stmttype);
301  in_outer_xact = false;
302  }
303  else
304  in_outer_xact = IsInTransactionBlock(isTopLevel);
305 
306  /*
307  * Due to static variables vac_context, anl_context and vac_strategy,
308  * vacuum() is not reentrant. This matters when VACUUM FULL or ANALYZE
309  * calls a hostile index expression that itself calls ANALYZE.
310  */
311  if (in_vacuum)
312  ereport(ERROR,
313  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
314  errmsg("%s cannot be executed from VACUUM or ANALYZE",
315  stmttype)));
316 
317  /*
318  * Sanity check DISABLE_PAGE_SKIPPING option.
319  */
320  if ((params->options & VACOPT_FULL) != 0 &&
321  (params->options & VACOPT_DISABLE_PAGE_SKIPPING) != 0)
322  ereport(ERROR,
323  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
324  errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
325 
326  /* sanity check for PROCESS_TOAST */
327  if ((params->options & VACOPT_FULL) != 0 &&
328  (params->options & VACOPT_PROCESS_TOAST) == 0)
329  ereport(ERROR,
330  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
331  errmsg("PROCESS_TOAST required with VACUUM FULL")));
332 
333  /*
334  * Send info about dead objects to the statistics collector, unless we are
335  * in autovacuum --- autovacuum.c does this for itself.
336  */
337  if ((params->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
339 
340  /*
341  * Create special memory context for cross-transaction storage.
342  *
343  * Since it is a child of PortalContext, it will go away eventually even
344  * if we suffer an error; there's no need for special abort cleanup logic.
345  */
347  "Vacuum",
349 
350  /*
351  * If caller didn't give us a buffer strategy object, make one in the
352  * cross-transaction memory context.
353  */
354  if (bstrategy == NULL)
355  {
357 
358  bstrategy = GetAccessStrategy(BAS_VACUUM);
359  MemoryContextSwitchTo(old_context);
360  }
361  vac_strategy = bstrategy;
362 
363  /*
364  * Build list of relation(s) to process, putting any new data in
365  * vac_context for safekeeping.
366  */
367  if (relations != NIL)
368  {
369  List *newrels = NIL;
370  ListCell *lc;
371 
372  foreach(lc, relations)
373  {
375  List *sublist;
376  MemoryContext old_context;
377 
378  sublist = expand_vacuum_rel(vrel, params->options);
379  old_context = MemoryContextSwitchTo(vac_context);
380  newrels = list_concat(newrels, sublist);
381  MemoryContextSwitchTo(old_context);
382  }
383  relations = newrels;
384  }
385  else
386  relations = get_all_vacuum_rels(params->options);
387 
388  /*
389  * Decide whether we need to start/commit our own transactions.
390  *
391  * For VACUUM (with or without ANALYZE): always do so, so that we can
392  * release locks as soon as possible. (We could possibly use the outer
393  * transaction for a one-table VACUUM, but handling TOAST tables would be
394  * problematic.)
395  *
396  * For ANALYZE (no VACUUM): if inside a transaction block, we cannot
397  * start/commit our own transactions. Also, there's no need to do so if
398  * only processing one relation. For multiple relations when not within a
399  * transaction block, and also in an autovacuum worker, use own
400  * transactions so we can release locks sooner.
401  */
402  if (params->options & VACOPT_VACUUM)
403  use_own_xacts = true;
404  else
405  {
406  Assert(params->options & VACOPT_ANALYZE);
408  use_own_xacts = true;
409  else if (in_outer_xact)
410  use_own_xacts = false;
411  else if (list_length(relations) > 1)
412  use_own_xacts = true;
413  else
414  use_own_xacts = false;
415  }
416 
417  /*
418  * vacuum_rel expects to be entered with no transaction active; it will
419  * start and commit its own transaction. But we are called by an SQL
420  * command, and so we are executing inside a transaction already. We
421  * commit the transaction started in PostgresMain() here, and start
422  * another one before exiting to match the commit waiting for us back in
423  * PostgresMain().
424  */
425  if (use_own_xacts)
426  {
427  Assert(!in_outer_xact);
428 
429  /* ActiveSnapshot is not set by autovacuum */
430  if (ActiveSnapshotSet())
432 
433  /* matches the StartTransaction in PostgresMain() */
435  }
436 
437  /* Turn vacuum cost accounting on or off, and set/clear in_vacuum */
438  PG_TRY();
439  {
440  ListCell *cur;
441 
442  in_vacuum = true;
444  VacuumCostBalance = 0;
445  VacuumPageHit = 0;
446  VacuumPageMiss = 0;
447  VacuumPageDirty = 0;
450  VacuumActiveNWorkers = NULL;
451 
452  /*
453  * Loop to process each selected relation.
454  */
455  foreach(cur, relations)
456  {
458 
459  if (params->options & VACOPT_VACUUM)
460  {
461  if (!vacuum_rel(vrel->oid, vrel->relation, params))
462  continue;
463  }
464 
465  if (params->options & VACOPT_ANALYZE)
466  {
467  /*
468  * If using separate xacts, start one for analyze. Otherwise,
469  * we can use the outer transaction.
470  */
471  if (use_own_xacts)
472  {
474  /* functions in indexes may want a snapshot set */
476  }
477 
478  analyze_rel(vrel->oid, vrel->relation, params,
479  vrel->va_cols, in_outer_xact, vac_strategy);
480 
481  if (use_own_xacts)
482  {
485  }
486  else
487  {
488  /*
489  * If we're not using separate xacts, better separate the
490  * ANALYZE actions with CCIs. This avoids trouble if user
491  * says "ANALYZE t, t".
492  */
494  }
495  }
496  }
497  }
498  PG_FINALLY();
499  {
500  in_vacuum = false;
501  VacuumCostActive = false;
502  }
503  PG_END_TRY();
504 
505  /*
506  * Finish up processing.
507  */
508  if (use_own_xacts)
509  {
510  /* here, we are not in a transaction */
511 
512  /*
513  * This matches the CommitTransaction waiting for us in
514  * PostgresMain().
515  */
517  }
518 
519  if ((params->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
520  {
521  /*
522  * Update pg_database.datfrozenxid, and truncate pg_xact if possible.
523  * (autovacuum.c does this for itself.)
524  */
526  }
527 
528  /*
529  * Clean up working storage --- note we must do this after
530  * StartTransactionCommand, else we might be trying to delete the active
531  * context!
532  */
534  vac_context = NULL;
535 }
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:1784
RangeVar * relation
Definition: parsenodes.h:3340
void vac_update_datfrozenxid(void)
Definition: vacuum.c:1419
#define VACOPT_ANALYZE
Definition: vacuum.h:179
void CommitTransactionCommand(void)
Definition: xact.c:2939
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:759
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
static List * expand_vacuum_rel(VacuumRelation *vrel, int options)
Definition: vacuum.c:731
#define VACOPT_PROCESS_TOAST
Definition: vacuum.h:184
MemoryContext PortalContext
Definition: mcxt.c:57
bits32 options
Definition: vacuum.h:208
#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:3379
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:798
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3448
void pgstat_vacuum_stat(void)
Definition: pgstat.c:1064
bool IsInTransactionBlock(bool isTopLevel)
Definition: xact.c:3492
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:1021
#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:2838
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:870

◆ vacuum_delay_point()

void vacuum_delay_point ( void  )

Definition at line 2116 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().

2117 {
2118  double msec = 0;
2119 
2120  /* Always check for interrupts */
2122 
2124  return;
2125 
2126  /*
2127  * For parallel vacuum, the delay is computed based on the shared cost
2128  * balance. See compute_parallel_delay.
2129  */
2130  if (VacuumSharedCostBalance != NULL)
2131  msec = compute_parallel_delay();
2132  else if (VacuumCostBalance >= VacuumCostLimit)
2134 
2135  /* Nap if appropriate */
2136  if (msec > 0)
2137  {
2138  if (msec > VacuumCostDelay * 4)
2139  msec = VacuumCostDelay * 4;
2140 
2141  (void) WaitLatch(MyLatch,
2143  msec,
2146 
2147  VacuumCostBalance = 0;
2148 
2149  /* update balance values for workers */
2151 
2152  /* Might have gotten an interrupt while sleeping */
2154  }
2155 }
static double compute_parallel_delay(void)
Definition: vacuum.c:2180
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:1780
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 545 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().

546 {
547  char *relname;
548 
550 
551  /*
552  * Check permissions.
553  *
554  * We allow the user to vacuum or analyze a table if he is superuser, the
555  * table owner, or the database owner (but in the latter case, only if
556  * it's not a shared relation). pg_class_ownercheck includes the
557  * superuser case.
558  *
559  * Note we choose to treat permissions failure as a WARNING and keep
560  * trying to vacuum or analyze the rest of the DB --- is this appropriate?
561  */
562  if (pg_class_ownercheck(relid, GetUserId()) ||
563  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !reltuple->relisshared))
564  return true;
565 
566  relname = NameStr(reltuple->relname);
567 
568  if ((options & VACOPT_VACUUM) != 0)
569  {
570  if (reltuple->relisshared)
572  (errmsg("skipping \"%s\" --- only superuser can vacuum it",
573  relname)));
574  else if (reltuple->relnamespace == PG_CATALOG_NAMESPACE)
576  (errmsg("skipping \"%s\" --- only superuser or database owner can vacuum it",
577  relname)));
578  else
580  (errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
581  relname)));
582 
583  /*
584  * For VACUUM ANALYZE, both logs could show up, but just generate
585  * information for VACUUM as that would be the first one to be
586  * processed.
587  */
588  return false;
589  }
590 
591  if ((options & VACOPT_ANALYZE) != 0)
592  {
593  if (reltuple->relisshared)
595  (errmsg("skipping \"%s\" --- only superuser can analyze it",
596  relname)));
597  else if (reltuple->relnamespace == PG_CATALOG_NAMESPACE)
599  (errmsg("skipping \"%s\" --- only superuser or database owner can analyze it",
600  relname)));
601  else
603  (errmsg("skipping \"%s\" --- only table or database owner can analyze it",
604  relname)));
605  }
606 
607  return false;
608 }
Oid GetUserId(void)
Definition: miscinit.c:478
#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:5241
#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:4823
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 619 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().

621 {
622  Relation rel;
623  bool rel_lock = true;
624  int elevel;
625 
627 
628  /*
629  * Open the relation and get the appropriate lock on it.
630  *
631  * There's a race condition here: the relation may have gone away since
632  * the last time we saw it. If so, we don't need to vacuum or analyze it.
633  *
634  * If we've been asked not to wait for the relation lock, acquire it first
635  * in non-blocking mode, before calling try_relation_open().
636  */
637  if (!(options & VACOPT_SKIP_LOCKED))
638  rel = try_relation_open(relid, lmode);
639  else if (ConditionalLockRelationOid(relid, lmode))
640  rel = try_relation_open(relid, NoLock);
641  else
642  {
643  rel = NULL;
644  rel_lock = false;
645  }
646 
647  /* if relation is opened, leave */
648  if (rel)
649  return rel;
650 
651  /*
652  * Relation could not be opened, hence generate if possible a log
653  * informing on the situation.
654  *
655  * If the RangeVar is not defined, we do not have enough information to
656  * provide a meaningful log statement. Chances are that the caller has
657  * intentionally not provided this information so that this logging is
658  * skipped, anyway.
659  */
660  if (relation == NULL)
661  return NULL;
662 
663  /*
664  * Determine the log level.
665  *
666  * For manual VACUUM or ANALYZE, we emit a WARNING to match the log
667  * statements in the permission checks; otherwise, only log if the caller
668  * so requested.
669  */
671  elevel = WARNING;
672  else if (verbose)
673  elevel = LOG;
674  else
675  return NULL;
676 
677  if ((options & VACOPT_VACUUM) != 0)
678  {
679  if (!rel_lock)
680  ereport(elevel,
681  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
682  errmsg("skipping vacuum of \"%s\" --- lock not available",
683  relation->relname)));
684  else
685  ereport(elevel,
687  errmsg("skipping vacuum of \"%s\" --- relation no longer exists",
688  relation->relname)));
689 
690  /*
691  * For VACUUM ANALYZE, both logs could show up, but just generate
692  * information for VACUUM as that would be the first one to be
693  * processed.
694  */
695  return NULL;
696  }
697 
698  if ((options & VACOPT_ANALYZE) != 0)
699  {
700  if (!rel_lock)
701  ereport(elevel,
702  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
703  errmsg("skipping analyze of \"%s\" --- lock not available",
704  relation->relname)));
705  else
706  ereport(elevel,
708  errmsg("skipping analyze of \"%s\" --- relation no longer exists",
709  relation->relname)));
710  }
711 
712  return NULL;
713 }
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:152
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:76
#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:3448
static int verbose
#define WARNING
Definition: elog.h:40
static int elevel
Definition: vacuumlazy.c:400
#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 943 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().

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

1150 {
1151  TransactionId xid_skip_limit;
1152  MultiXactId multi_skip_limit;
1153  int skip_index_vacuum;
1154 
1155  Assert(TransactionIdIsNormal(relfrozenxid));
1156  Assert(MultiXactIdIsValid(relminmxid));
1157 
1158  /*
1159  * Determine the index skipping age to use. In any case no less than
1160  * autovacuum_freeze_max_age * 1.05.
1161  */
1162  skip_index_vacuum = Max(vacuum_failsafe_age, autovacuum_freeze_max_age * 1.05);
1163 
1164  xid_skip_limit = ReadNextTransactionId() - skip_index_vacuum;
1165  if (!TransactionIdIsNormal(xid_skip_limit))
1166  xid_skip_limit = FirstNormalTransactionId;
1167 
1168  if (TransactionIdPrecedes(relfrozenxid, xid_skip_limit))
1169  {
1170  /* The table's relfrozenxid is too old */
1171  return true;
1172  }
1173 
1174  /*
1175  * Similar to above, determine the index skipping age to use for
1176  * multixact. In any case no less than autovacuum_multixact_freeze_max_age *
1177  * 1.05.
1178  */
1179  skip_index_vacuum = Max(vacuum_multixact_failsafe_age,
1181 
1182  multi_skip_limit = ReadNextMultiXactId() - skip_index_vacuum;
1183  if (multi_skip_limit < FirstMultiXactId)
1184  multi_skip_limit = FirstMultiXactId;
1185 
1186  if (MultiXactIdPrecedes(relminmxid, multi_skip_limit))
1187  {
1188  /* The table's relminmxid is too old */
1189  return true;
1190  }
1191 
1192  return false;
1193 }
uint32 TransactionId
Definition: c.h:587
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:126
static TransactionId ReadNextTransactionId(void)
Definition: transam.h:308
#define FirstNormalTransactionId
Definition: transam.h:34
int autovacuum_freeze_max_age
Definition: autovacuum.c:125
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:3156
#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().