PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
vacuum.h File Reference
#include "access/htup.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "nodes/parsenodes.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
 

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

Functions

void ExecVacuum (VacuumStmt *vacstmt, bool isTopLevel)
 
void vacuum (int options, RangeVar *relation, Oid relid, VacuumParams *params, List *va_cols, 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, bool is_analyze, 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)
 
void vac_update_datfrozenxid (void)
 
void vacuum_delay_point (void)
 
void lazy_vacuum_rel (Relation onerel, int options, VacuumParams *params, BufferAccessStrategy bstrategy)
 
void analyze_rel (Oid relid, RangeVar *relation, int options, 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
 

Typedef Documentation

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

Definition at line 64 of file vacuum.h.

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

Definition at line 61 of file vacuum.h.

Definition at line 59 of file vacuum.h.

Function Documentation

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

Definition at line 105 of file analyze.c.

References acquire_sample_rows(), FdwRoutine::AnalyzeForeignTable, CHECK_FOR_INTERRUPTS, ConditionalLockRelationOid(), DEBUG2, do_analyze_rel(), elevel, ereport, errcode(), errmsg(), GetFdwRoutineForRelation(), GetUserId(), INFO, IsAutoVacuumWorkerProcess(), LOG, VacuumParams::log_min_duration, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyDatabaseId, MyPgXact, NoLock, NULL, PG_CATALOG_NAMESPACE, pg_class_ownercheck(), pg_database_ownercheck(), PROC_IN_ANALYZE, RelationData::rd_rel, relation_close(), RELATION_IS_OTHER_TEMP, RelationGetNumberOfBlocks, RelationGetRelationName, RelationGetRelid, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RangeVar::relname, ShareUpdateExclusiveLock, StatisticRelationId, try_relation_open(), VACOPT_NOWAIT, VACOPT_VACUUM, VACOPT_VERBOSE, PGXACT::vacuumFlags, and WARNING.

Referenced by vacuum().

108 {
109  Relation onerel;
110  int elevel;
111  AcquireSampleRowsFunc acquirefunc = NULL;
112  BlockNumber relpages = 0;
113 
114  /* Select logging level */
115  if (options & VACOPT_VERBOSE)
116  elevel = INFO;
117  else
118  elevel = DEBUG2;
119 
120  /* Set up static variables */
121  vac_strategy = bstrategy;
122 
123  /*
124  * Check for user-requested abort.
125  */
127 
128  /*
129  * Open the relation, getting ShareUpdateExclusiveLock to ensure that two
130  * ANALYZEs don't run on it concurrently. (This also locks out a
131  * concurrent VACUUM, which doesn't matter much at the moment but might
132  * matter if we ever try to accumulate stats on dead tuples.) If the rel
133  * has been dropped since we last saw it, we don't need to process it.
134  */
135  if (!(options & VACOPT_NOWAIT))
138  onerel = try_relation_open(relid, NoLock);
139  else
140  {
141  onerel = NULL;
142  if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
143  ereport(LOG,
144  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
145  errmsg("skipping analyze of \"%s\" --- lock not available",
146  relation->relname)));
147  }
148  if (!onerel)
149  return;
150 
151  /*
152  * Check permissions --- this should match vacuum's check!
153  */
154  if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
155  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared)))
156  {
157  /* No need for a WARNING if we already complained during VACUUM */
158  if (!(options & VACOPT_VACUUM))
159  {
160  if (onerel->rd_rel->relisshared)
162  (errmsg("skipping \"%s\" --- only superuser can analyze it",
163  RelationGetRelationName(onerel))));
164  else if (onerel->rd_rel->relnamespace == PG_CATALOG_NAMESPACE)
166  (errmsg("skipping \"%s\" --- only superuser or database owner can analyze it",
167  RelationGetRelationName(onerel))));
168  else
170  (errmsg("skipping \"%s\" --- only table or database owner can analyze it",
171  RelationGetRelationName(onerel))));
172  }
174  return;
175  }
176 
177  /*
178  * Silently ignore tables that are temp tables of other backends ---
179  * trying to analyze these is rather pointless, since their contents are
180  * probably not up-to-date on disk. (We don't throw a warning here; it
181  * would just lead to chatter during a database-wide ANALYZE.)
182  */
183  if (RELATION_IS_OTHER_TEMP(onerel))
184  {
186  return;
187  }
188 
189  /*
190  * We can ANALYZE any table except pg_statistic. See update_attstats
191  */
192  if (RelationGetRelid(onerel) == StatisticRelationId)
193  {
195  return;
196  }
197 
198  /*
199  * Check that it's a plain table, materialized view, or foreign table; we
200  * used to do this in get_rel_oids() but seems safer to check after we've
201  * locked the relation.
202  */
203  if (onerel->rd_rel->relkind == RELKIND_RELATION ||
204  onerel->rd_rel->relkind == RELKIND_MATVIEW ||
205  onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
206  {
207  /* Regular table, so we'll use the regular row acquisition function */
208  acquirefunc = acquire_sample_rows;
209  /* Also get regular table's size */
210  relpages = RelationGetNumberOfBlocks(onerel);
211  }
212  else if (onerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
213  {
214  /*
215  * For a foreign table, call the FDW's hook function to see whether it
216  * supports analysis.
217  */
218  FdwRoutine *fdwroutine;
219  bool ok = false;
220 
221  fdwroutine = GetFdwRoutineForRelation(onerel, false);
222 
223  if (fdwroutine->AnalyzeForeignTable != NULL)
224  ok = fdwroutine->AnalyzeForeignTable(onerel,
225  &acquirefunc,
226  &relpages);
227 
228  if (!ok)
229  {
231  (errmsg("skipping \"%s\" --- cannot analyze this foreign table",
232  RelationGetRelationName(onerel))));
234  return;
235  }
236  }
237  else
238  {
239  /* No need for a WARNING if we already complained during VACUUM */
240  if (!(options & VACOPT_VACUUM))
242  (errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables",
243  RelationGetRelationName(onerel))));
245  return;
246  }
247 
248  /*
249  * OK, let's do it. First let other backends know I'm in ANALYZE.
250  */
251  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
253  LWLockRelease(ProcArrayLock);
254 
255  /*
256  * Do the normal non-recursive ANALYZE.
257  */
258  do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
259  false, in_outer_xact, elevel);
260 
261  /*
262  * If there are child tables, do recursive ANALYZE.
263  */
264  if (onerel->rd_rel->relhassubclass)
265  do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
266  true, in_outer_xact, elevel);
267 
268  /*
269  * Close source relation now, but keep lock so that no one deletes it
270  * before we commit. (If someone did, they'd fail to clean up the entries
271  * we made in pg_statistic. Also, releasing the lock before commit would
272  * expose us to concurrent-update failures in update_attstats.)
273  */
274  relation_close(onerel, NoLock);
275 
276  /*
277  * Reset my PGXACT flag. Note: we need this here, and not in vacuum_rel,
278  * because the vacuum flag is cleared by the end-of-xact code.
279  */
280  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
282  LWLockRelease(ProcArrayLock);
283 }
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:138
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1150
Oid GetUserId(void)
Definition: miscinit.c:283
AnalyzeForeignTable_function AnalyzeForeignTable
Definition: fdwapi.h:217
int(* AcquireSampleRowsFunc)(Relation relation, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: fdwapi.h:134
#define RELKIND_MATVIEW
Definition: pg_class.h:167
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
#define INFO
Definition: elog.h:33
static BufferAccessStrategy vac_strategy
Definition: analyze.c:75
uint32 BlockNumber
Definition: block.h:31
#define LOG
Definition: elog.h:26
Form_pg_class rd_rel
Definition: rel.h:113
PGXACT * MyPgXact
Definition: proc.c:68
uint8 vacuumFlags
Definition: proc.h:208
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
char * relname
Definition: primnodes.h:67
#define DEBUG2
Definition: elog.h:24
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:433
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:166
#define PG_CATALOG_NAMESPACE
Definition: pg_namespace.h:71
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:2989
#define ereport(elevel, rest)
Definition: elog.h:122
bool pg_database_ownercheck(Oid db_oid, Oid roleid)
Definition: aclchk.c:4939
#define WARNING
Definition: elog.h:40
static void do_analyze_rel(Relation onerel, int options, VacuumParams *params, List *va_cols, AcquireSampleRowsFunc acquirefunc, BlockNumber relpages, bool inh, bool in_outer_xact, int elevel)
Definition: analyze.c:293
static int elevel
Definition: vacuumlazy.c:136
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define StatisticRelationId
Definition: pg_statistic.h:29
Oid MyDatabaseId
Definition: globals.c:76
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define NULL
Definition: c.h:226
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:530
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4521
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
int log_min_duration
Definition: vacuum.h:145
int errmsg(const char *fmt,...)
Definition: elog.c:797
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:395
#define PROC_IN_ANALYZE
Definition: proc.h:45
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetRelid(relation)
Definition: rel.h:413
static int acquire_sample_rows(Relation onerel, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: analyze.c:977
double anl_get_next_S ( double  t,
int  n,
double *  stateptr 
)

Definition at line 284 of file sampling.c.

285 {
286  double result;
287 
288  oldrs.W = *stateptr;
289  result = reservoir_get_next_S(&oldrs, t, n);
290  *stateptr = oldrs.W;
291  return result;
292 }
static ReservoirStateData oldrs
Definition: sampling.c:259
double reservoir_get_next_S(ReservoirState rs, double t, int n)
Definition: sampling.c:142
double anl_init_selection_state ( int  n)

Definition at line 273 of file sampling.c.

274 {
275  /* initialize if first time through */
276  if (oldrs.randstate[0] == 0)
278 
279  /* Initial value of W (for use when Algorithm Z is first applied) */
280  return exp(-log(sampler_random_fract(oldrs.randstate)) / n);
281 }
void sampler_random_init_state(long seed, SamplerRandomState randstate)
Definition: sampling.c:229
long random(void)
Definition: random.c:22
double sampler_random_fract(SamplerRandomState randstate)
Definition: sampling.c:238
static ReservoirStateData oldrs
Definition: sampling.c:259
SamplerRandomState randstate
Definition: sampling.h:50
double anl_random_fract ( void  )

Definition at line 262 of file sampling.c.

263 {
264  /* initialize if first time through */
265  if (oldrs.randstate[0] == 0)
267 
268  /* and compute a random fraction */
270 }
void sampler_random_init_state(long seed, SamplerRandomState randstate)
Definition: sampling.c:229
long random(void)
Definition: random.c:22
double sampler_random_fract(SamplerRandomState randstate)
Definition: sampling.c:238
static ReservoirStateData oldrs
Definition: sampling.c:259
SamplerRandomState randstate
Definition: sampling.h:50
void ExecVacuum ( VacuumStmt vacstmt,
bool  isTopLevel 
)

Definition at line 84 of file vacuum.c.

References Assert, VacuumParams::freeze_min_age, VacuumParams::freeze_table_age, InvalidOid, VacuumParams::is_wraparound, VacuumParams::log_min_duration, VacuumParams::multixact_freeze_min_age, VacuumParams::multixact_freeze_table_age, NIL, NULL, VacuumStmt::options, VacuumStmt::relation, VacuumStmt::va_cols, VACOPT_ANALYZE, VACOPT_FREEZE, VACOPT_FULL, VACOPT_SKIPTOAST, VACOPT_VACUUM, and vacuum().

Referenced by standard_ProcessUtility().

85 {
86  VacuumParams params;
87 
88  /* sanity checks on options */
90  Assert((vacstmt->options & VACOPT_VACUUM) ||
91  !(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE)));
92  Assert((vacstmt->options & VACOPT_ANALYZE) || vacstmt->va_cols == NIL);
93  Assert(!(vacstmt->options & VACOPT_SKIPTOAST));
94 
95  /*
96  * All freeze ages are zero if the FREEZE option is given; otherwise pass
97  * them as -1 which means to use the default values.
98  */
99  if (vacstmt->options & VACOPT_FREEZE)
100  {
101  params.freeze_min_age = 0;
102  params.freeze_table_age = 0;
103  params.multixact_freeze_min_age = 0;
104  params.multixact_freeze_table_age = 0;
105  }
106  else
107  {
108  params.freeze_min_age = -1;
109  params.freeze_table_age = -1;
110  params.multixact_freeze_min_age = -1;
111  params.multixact_freeze_table_age = -1;
112  }
113 
114  /* user-invoked vacuum is never "for wraparound" */
115  params.is_wraparound = false;
116 
117  /* user-invoked vacuum never uses this parameter */
118  params.log_min_duration = -1;
119 
120  /* Now go through the common routine */
121  vacuum(vacstmt->options, vacstmt->relation, InvalidOid, &params,
122  vacstmt->va_cols, NULL, isTopLevel);
123 }
#define NIL
Definition: pg_list.h:69
int multixact_freeze_table_age
Definition: vacuum.h:142
int freeze_table_age
Definition: vacuum.h:139
int freeze_min_age
Definition: vacuum.h:138
bool is_wraparound
Definition: vacuum.h:144
List * va_cols
Definition: parsenodes.h:2986
#define InvalidOid
Definition: postgres_ext.h:36
void vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, List *va_cols, BufferAccessStrategy bstrategy, bool isTopLevel)
Definition: vacuum.c:148
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
RangeVar * relation
Definition: parsenodes.h:2985
int log_min_duration
Definition: vacuum.h:145
int multixact_freeze_min_age
Definition: vacuum.h:140
void lazy_vacuum_rel ( Relation  onerel,
int  options,
VacuumParams params,
BufferAccessStrategy  bstrategy 
)

Definition at line 182 of file vacuumlazy.c.

References _, appendStringInfo(), Assert, buf, StringInfoData::data, DEBUG2, elevel, ereport, errmsg_internal(), FreeSpaceMapVacuum(), VacuumParams::freeze_min_age, VacuumParams::freeze_table_age, FreezeLimit, LVRelStats::frozenskipped_pages, get_database_name(), get_namespace_name(), GetCurrentTimestamp(), LVRelStats::hasindex, INFO, initStringInfo(), InvalidMultiXactId, InvalidTransactionId, IsAutoVacuumWorkerProcess(), lazy_scan_heap(), lazy_truncate_heap(), LVRelStats::lock_waiter_detected, LOG, VacuumParams::log_min_duration, VacuumParams::multixact_freeze_min_age, VacuumParams::multixact_freeze_table_age, MultiXactCutoff, MultiXactIdPrecedesOrEquals(), MyDatabaseId, LVRelStats::new_dead_tuples, LVRelStats::new_rel_tuples, NoLock, NULL, LVRelStats::num_index_scans, LVRelStats::old_rel_pages, LVRelStats::old_rel_tuples, OldestXmin, LVRelStats::pages_removed, palloc0(), pfree(), pg_rusage_init(), pg_rusage_show(), pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_param(), pgstat_report_vacuum(), LVRelStats::pinskipped_pages, PROGRESS_COMMAND_VACUUM, PROGRESS_VACUUM_PHASE, PROGRESS_VACUUM_PHASE_FINAL_CLEANUP, RelationData::rd_rel, LVRelStats::rel_pages, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, LVRelStats::scanned_pages, should_attempt_truncation(), TimestampDifference(), TimestampDifferenceExceeds(), TransactionIdPrecedesOrEquals(), LVRelStats::tuples_deleted, vac_close_indexes(), vac_open_indexes(), vac_update_relstats(), VACOPT_DISABLE_PAGE_SKIPPING, VACOPT_VERBOSE, vacuum_set_xid_limits(), VacuumPageDirty, VacuumPageHit, VacuumPageMiss, and visibilitymap_count().

Referenced by vacuum_rel().

184 {
185  LVRelStats *vacrelstats;
186  Relation *Irel;
187  int nindexes;
188  PGRUsage ru0;
189  TimestampTz starttime = 0;
190  long secs;
191  int usecs;
192  double read_rate,
193  write_rate;
194  bool aggressive; /* should we scan all unfrozen pages? */
195  bool scanned_all_unfrozen; /* actually scanned all such pages? */
196  TransactionId xidFullScanLimit;
197  MultiXactId mxactFullScanLimit;
198  BlockNumber new_rel_pages;
199  double new_rel_tuples;
200  BlockNumber new_rel_allvisible;
201  double new_live_tuples;
202  TransactionId new_frozen_xid;
203  MultiXactId new_min_multi;
204 
205  Assert(params != NULL);
206 
207  /* measure elapsed time iff autovacuum logging requires it */
208  if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
209  {
210  pg_rusage_init(&ru0);
211  starttime = GetCurrentTimestamp();
212  }
213 
214  if (options & VACOPT_VERBOSE)
215  elevel = INFO;
216  else
217  elevel = DEBUG2;
218 
220  RelationGetRelid(onerel));
221 
222  vac_strategy = bstrategy;
223 
224  vacuum_set_xid_limits(onerel,
225  params->freeze_min_age,
226  params->freeze_table_age,
227  params->multixact_freeze_min_age,
229  &OldestXmin, &FreezeLimit, &xidFullScanLimit,
230  &MultiXactCutoff, &mxactFullScanLimit);
231 
232  /*
233  * We request an aggressive scan if the table's frozen Xid is now older
234  * than or equal to the requested Xid full-table scan limit; or if the
235  * table's minimum MultiXactId is older than or equal to the requested
236  * mxid full-table scan limit; or if DISABLE_PAGE_SKIPPING was specified.
237  */
238  aggressive = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid,
239  xidFullScanLimit);
240  aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid,
241  mxactFullScanLimit);
243  aggressive = true;
244 
245  vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
246 
247  vacrelstats->old_rel_pages = onerel->rd_rel->relpages;
248  vacrelstats->old_rel_tuples = onerel->rd_rel->reltuples;
249  vacrelstats->num_index_scans = 0;
250  vacrelstats->pages_removed = 0;
251  vacrelstats->lock_waiter_detected = false;
252 
253  /* Open all indexes of the relation */
254  vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel);
255  vacrelstats->hasindex = (nindexes > 0);
256 
257  /* Do the vacuuming */
258  lazy_scan_heap(onerel, options, vacrelstats, Irel, nindexes, aggressive);
259 
260  /* Done with indexes */
261  vac_close_indexes(nindexes, Irel, NoLock);
262 
263  /*
264  * Compute whether we actually scanned the all unfrozen pages. If we did,
265  * we can adjust relfrozenxid and relminmxid.
266  *
267  * NB: We need to check this before truncating the relation, because that
268  * will change ->rel_pages.
269  */
270  if ((vacrelstats->scanned_pages + vacrelstats->frozenskipped_pages)
271  < vacrelstats->rel_pages)
272  {
273  Assert(!aggressive);
274  scanned_all_unfrozen = false;
275  }
276  else
277  scanned_all_unfrozen = true;
278 
279  /*
280  * Optionally truncate the relation.
281  */
282  if (should_attempt_truncation(vacrelstats))
283  lazy_truncate_heap(onerel, vacrelstats);
284 
285  /* Report that we are now doing final cleanup */
288 
289  /* Vacuum the Free Space Map */
290  FreeSpaceMapVacuum(onerel);
291 
292  /*
293  * Update statistics in pg_class.
294  *
295  * A corner case here is that if we scanned no pages at all because every
296  * page is all-visible, we should not update relpages/reltuples, because
297  * we have no new information to contribute. In particular this keeps us
298  * from replacing relpages=reltuples=0 (which means "unknown tuple
299  * density") with nonzero relpages and reltuples=0 (which means "zero
300  * tuple density") unless there's some actual evidence for the latter.
301  *
302  * We do update relallvisible even in the corner case, since if the table
303  * is all-visible we'd definitely like to know that. But clamp the value
304  * to be not more than what we're setting relpages to.
305  *
306  * Also, don't change relfrozenxid/relminmxid if we skipped any pages,
307  * since then we don't know for certain that all tuples have a newer xmin.
308  */
309  new_rel_pages = vacrelstats->rel_pages;
310  new_rel_tuples = vacrelstats->new_rel_tuples;
311  if (vacrelstats->scanned_pages == 0 && new_rel_pages > 0)
312  {
313  new_rel_pages = vacrelstats->old_rel_pages;
314  new_rel_tuples = vacrelstats->old_rel_tuples;
315  }
316 
317  visibilitymap_count(onerel, &new_rel_allvisible, NULL);
318  if (new_rel_allvisible > new_rel_pages)
319  new_rel_allvisible = new_rel_pages;
320 
321  new_frozen_xid = scanned_all_unfrozen ? FreezeLimit : InvalidTransactionId;
322  new_min_multi = scanned_all_unfrozen ? MultiXactCutoff : InvalidMultiXactId;
323 
324  vac_update_relstats(onerel,
325  new_rel_pages,
326  new_rel_tuples,
327  new_rel_allvisible,
328  vacrelstats->hasindex,
329  new_frozen_xid,
330  new_min_multi,
331  false);
332 
333  /* report results to the stats collector, too */
334  new_live_tuples = new_rel_tuples - vacrelstats->new_dead_tuples;
335  if (new_live_tuples < 0)
336  new_live_tuples = 0; /* just in case */
337 
339  onerel->rd_rel->relisshared,
340  new_live_tuples,
341  vacrelstats->new_dead_tuples);
343 
344  /* and log the action if appropriate */
345  if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
346  {
347  TimestampTz endtime = GetCurrentTimestamp();
348 
349  if (params->log_min_duration == 0 ||
350  TimestampDifferenceExceeds(starttime, endtime,
351  params->log_min_duration))
352  {
354 
355  TimestampDifference(starttime, endtime, &secs, &usecs);
356 
357  read_rate = 0;
358  write_rate = 0;
359  if ((secs > 0) || (usecs > 0))
360  {
361  read_rate = (double) BLCKSZ *VacuumPageMiss / (1024 * 1024) /
362  (secs + usecs / 1000000.0);
363  write_rate = (double) BLCKSZ *VacuumPageDirty / (1024 * 1024) /
364  (secs + usecs / 1000000.0);
365  }
366 
367  /*
368  * This is pretty messy, but we split it up so that we can skip
369  * emitting individual parts of the message when not applicable.
370  */
371  initStringInfo(&buf);
372  appendStringInfo(&buf, _("automatic vacuum of table \"%s.%s.%s\": index scans: %d\n"),
375  RelationGetRelationName(onerel),
376  vacrelstats->num_index_scans);
377  appendStringInfo(&buf, _("pages: %u removed, %u remain, %u skipped due to pins, %u skipped frozen\n"),
378  vacrelstats->pages_removed,
379  vacrelstats->rel_pages,
380  vacrelstats->pinskipped_pages,
381  vacrelstats->frozenskipped_pages);
382  appendStringInfo(&buf,
383  _("tuples: %.0f removed, %.0f remain, %.0f are dead but not yet removable\n"),
384  vacrelstats->tuples_deleted,
385  vacrelstats->new_rel_tuples,
386  vacrelstats->new_dead_tuples);
387  appendStringInfo(&buf,
388  _("buffer usage: %d hits, %d misses, %d dirtied\n"),
392  appendStringInfo(&buf, _("avg read rate: %.3f MB/s, avg write rate: %.3f MB/s\n"),
393  read_rate, write_rate);
394  appendStringInfo(&buf, _("system usage: %s"), pg_rusage_show(&ru0));
395 
396  ereport(LOG,
397  (errmsg_internal("%s", buf.data)));
398  pfree(buf.data);
399  }
400  }
401 }
double new_rel_tuples
Definition: vacuumlazy.c:119
int multixact_freeze_table_age
Definition: vacuum.h:142
void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode)
Definition: vacuum.c:1494
BlockNumber rel_pages
Definition: vacuumlazy.c:113
uint32 TransactionId
Definition: c.h:394
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
Definition: pgstat.c:2879
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1569
double tuples_deleted
Definition: vacuumlazy.c:122
int64 TimestampTz
Definition: timestamp.h:39
int VacuumPageHit
Definition: globals.c:134
void pgstat_progress_update_param(int index, int64 val)
Definition: pgstat.c:2900
double old_rel_tuples
Definition: vacuumlazy.c:118
static void lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats, Relation *Irel, int nindexes, bool aggressive)
Definition: vacuumlazy.c:453
BlockNumber scanned_pages
Definition: vacuumlazy.c:114
#define INFO
Definition: elog.h:33
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: vacuum.c:471
uint32 BlockNumber
Definition: block.h:31
BlockNumber pinskipped_pages
Definition: vacuumlazy.c:115
void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen)
#define LOG
Definition: elog.h:26
Form_pg_class rd_rel
Definition: rel.h:113
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition: timestamp.c:1648
int freeze_table_age
Definition: vacuum.h:139
void pg_rusage_init(PGRUsage *ru0)
Definition: pg_rusage.c:27
BlockNumber old_rel_pages
Definition: vacuumlazy.c:112
void pfree(void *pointer)
Definition: mcxt.c:992
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
int freeze_min_age
Definition: vacuum.h:138
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2049
#define DEBUG2
Definition: elog.h:24
static TransactionId FreezeLimit
Definition: vacuumlazy.c:139
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
#define NoLock
Definition: lockdefs.h:34
static char * buf
Definition: pg_test_fsync.c:65
#define RowExclusiveLock
Definition: lockdefs.h:38
static MultiXactId MultiXactCutoff
Definition: vacuumlazy.c:140
const char * pg_rusage_show(const PGRUsage *ru0)
Definition: pg_rusage.c:40
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:433
static TransactionId OldestXmin
Definition: vacuumlazy.c:138
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:2989
#define ereport(elevel, rest)
Definition: elog.h:122
void FreeSpaceMapVacuum(Relation rel)
Definition: freespace.c:379
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
void vac_open_indexes(Relation relation, LOCKMODE lockmode, int *nindexes, Relation **Irel)
Definition: vacuum.c:1451
static int elevel
Definition: vacuumlazy.c:136
bool hasindex
Definition: vacuumlazy.c:110
int VacuumPageDirty
Definition: globals.c:136
void * palloc0(Size size)
Definition: mcxt.c:920
void pgstat_progress_end_command(void)
Definition: pgstat.c:2951
Oid MyDatabaseId
Definition: globals.c:76
#define InvalidMultiXactId
Definition: multixact.h:23
static bool should_attempt_truncation(LVRelStats *vacrelstats)
Definition: vacuumlazy.c:1686
#define PROGRESS_VACUUM_PHASE_FINAL_CLEANUP
Definition: progress.h:35
int num_index_scans
Definition: vacuumlazy.c:129
TransactionId MultiXactId
Definition: c.h:404
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
static BufferAccessStrategy vac_strategy
Definition: vacuumlazy.c:142
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
double new_dead_tuples
Definition: vacuumlazy.c:120
#define PROGRESS_VACUUM_PHASE
Definition: progress.h:21
int log_min_duration
Definition: vacuum.h:145
void pgstat_report_vacuum(Oid tableoid, bool shared, PgStat_Counter livetuples, PgStat_Counter deadtuples)
Definition: pgstat.c:1329
BlockNumber pages_removed
Definition: vacuumlazy.c:121
BlockNumber frozenskipped_pages
Definition: vacuumlazy.c:116
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3149
int VacuumPageMiss
Definition: globals.c:135
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1623
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: vacuum.c:755
#define _(x)
Definition: elog.c:84
#define RelationGetRelid(relation)
Definition: rel.h:413
int multixact_freeze_min_age
Definition: vacuum.h:140
static void lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
Definition: vacuumlazy.c:1704
#define RelationGetNamespace(relation)
Definition: rel.h:440
bool lock_waiter_detected
Definition: vacuumlazy.c:131
bool std_typanalyze ( VacAttrStats stats)

Definition at line 1714 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, NULL, OidIsValid, and palloc().

Referenced by array_typanalyze(), and examine_attribute().

1715 {
1716  Form_pg_attribute attr = stats->attr;
1717  Oid ltopr;
1718  Oid eqopr;
1719  StdAnalyzeData *mystats;
1720 
1721  /* If the attstattarget column is negative, use the default value */
1722  /* NB: it is okay to scribble on stats->attr since it's a copy */
1723  if (attr->attstattarget < 0)
1724  attr->attstattarget = default_statistics_target;
1725 
1726  /* Look for default "<" and "=" operators for column's type */
1728  false, false, false,
1729  &ltopr, &eqopr, NULL,
1730  NULL);
1731 
1732  /* Save the operator info for compute_stats routines */
1733  mystats = (StdAnalyzeData *) palloc(sizeof(StdAnalyzeData));
1734  mystats->eqopr = eqopr;
1735  mystats->eqfunc = OidIsValid(eqopr) ? get_opcode(eqopr) : InvalidOid;
1736  mystats->ltopr = ltopr;
1737  stats->extra_data = mystats;
1738 
1739  /*
1740  * Determine which standard statistics algorithm to use
1741  */
1742  if (OidIsValid(eqopr) && OidIsValid(ltopr))
1743  {
1744  /* Seems to be a scalar datatype */
1746  /*--------------------
1747  * The following choice of minrows is based on the paper
1748  * "Random sampling for histogram construction: how much is enough?"
1749  * by Surajit Chaudhuri, Rajeev Motwani and Vivek Narasayya, in
1750  * Proceedings of ACM SIGMOD International Conference on Management
1751  * of Data, 1998, Pages 436-447. Their Corollary 1 to Theorem 5
1752  * says that for table size n, histogram size k, maximum relative
1753  * error in bin size f, and error probability gamma, the minimum
1754  * random sample size is
1755  * r = 4 * k * ln(2*n/gamma) / f^2
1756  * Taking f = 0.5, gamma = 0.01, n = 10^6 rows, we obtain
1757  * r = 305.82 * k
1758  * Note that because of the log function, the dependence on n is
1759  * quite weak; even at n = 10^12, a 300*k sample gives <= 0.66
1760  * bin size error with probability 0.99. So there's no real need to
1761  * scale for n, which is a good thing because we don't necessarily
1762  * know it at this point.
1763  *--------------------
1764  */
1765  stats->minrows = 300 * attr->attstattarget;
1766  }
1767  else if (OidIsValid(eqopr))
1768  {
1769  /* We can still recognize distinct values */
1771  /* Might as well use the same minrows as above */
1772  stats->minrows = 300 * attr->attstattarget;
1773  }
1774  else
1775  {
1776  /* Can't do much but the trivial stuff */
1778  /* Might as well use the same minrows as above */
1779  stats->minrows = 300 * attr->attstattarget;
1780  }
1781 
1782  return true;
1783 }
int minrows
Definition: vacuum.h:92
static void compute_scalar_stats(VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
Definition: analyze.c:2236
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
Form_pg_attribute attr
Definition: vacuum.h:81
Oid attrtypid
Definition: vacuum.h:82
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
static void compute_distinct_stats(VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
Definition: analyze.c:1884
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1062
#define NULL
Definition: c.h:226
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:185
static void compute_trivial_stats(VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows)
Definition: analyze.c:1794
void * palloc(Size size)
Definition: mcxt.c:891
AnalyzeAttrComputeStatsFunc compute_stats
Definition: vacuum.h:91
void * extra_data
Definition: vacuum.h:93
int default_statistics_target
Definition: analyze.c:71
void vac_close_indexes ( int  nindexes,
Relation Irel,
LOCKMODE  lockmode 
)

Definition at line 1494 of file vacuum.c.

References index_close(), NULL, and pfree().

Referenced by do_analyze_rel(), and lazy_vacuum_rel().

1495 {
1496  if (Irel == NULL)
1497  return;
1498 
1499  while (nindexes--)
1500  {
1501  Relation ind = Irel[nindexes];
1502 
1503  index_close(ind, lockmode);
1504  }
1505  pfree(Irel);
1506 }
void pfree(void *pointer)
Definition: mcxt.c:992
#define NULL
Definition: c.h:226
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
double vac_estimate_reltuples ( Relation  relation,
bool  is_analyze,
BlockNumber  total_pages,
BlockNumber  scanned_pages,
double  scanned_tuples 
)

Definition at line 655 of file vacuum.c.

References RelationData::rd_rel.

Referenced by acquire_sample_rows(), lazy_scan_heap(), and statapprox_heap().

659 {
660  BlockNumber old_rel_pages = relation->rd_rel->relpages;
661  double old_rel_tuples = relation->rd_rel->reltuples;
662  double old_density;
663  double new_density;
664  double multiplier;
665  double updated_density;
666 
667  /* If we did scan the whole table, just use the count as-is */
668  if (scanned_pages >= total_pages)
669  return scanned_tuples;
670 
671  /*
672  * If scanned_pages is zero but total_pages isn't, keep the existing value
673  * of reltuples. (Note: callers should avoid updating the pg_class
674  * statistics in this situation, since no new information has been
675  * provided.)
676  */
677  if (scanned_pages == 0)
678  return old_rel_tuples;
679 
680  /*
681  * If old value of relpages is zero, old density is indeterminate; we
682  * can't do much except scale up scanned_tuples to match total_pages.
683  */
684  if (old_rel_pages == 0)
685  return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
686 
687  /*
688  * Okay, we've covered the corner cases. The normal calculation is to
689  * convert the old measurement to a density (tuples per page), then update
690  * the density using an exponential-moving-average approach, and finally
691  * compute reltuples as updated_density * total_pages.
692  *
693  * For ANALYZE, the moving average multiplier is just the fraction of the
694  * table's pages we scanned. This is equivalent to assuming that the
695  * tuple density in the unscanned pages didn't change. Of course, it
696  * probably did, if the new density measurement is different. But over
697  * repeated cycles, the value of reltuples will converge towards the
698  * correct value, if repeated measurements show the same new density.
699  *
700  * For VACUUM, the situation is a bit different: we have looked at a
701  * nonrandom sample of pages, but we know for certain that the pages we
702  * didn't look at are precisely the ones that haven't changed lately.
703  * Thus, there is a reasonable argument for doing exactly the same thing
704  * as for the ANALYZE case, that is use the old density measurement as the
705  * value for the unscanned pages.
706  *
707  * This logic could probably use further refinement.
708  */
709  old_density = old_rel_tuples / old_rel_pages;
710  new_density = scanned_tuples / scanned_pages;
711  multiplier = (double) scanned_pages / (double) total_pages;
712  updated_density = old_density + (new_density - old_density) * multiplier;
713  return floor(updated_density * total_pages + 0.5);
714 }
uint32 BlockNumber
Definition: block.h:31
Form_pg_class rd_rel
Definition: rel.h:113
void vac_open_indexes ( Relation  relation,
LOCKMODE  lockmode,
int *  nindexes,
Relation **  Irel 
)

Definition at line 1451 of file vacuum.c.

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

Referenced by do_analyze_rel(), and lazy_vacuum_rel().

1453 {
1454  List *indexoidlist;
1455  ListCell *indexoidscan;
1456  int i;
1457 
1458  Assert(lockmode != NoLock);
1459 
1460  indexoidlist = RelationGetIndexList(relation);
1461 
1462  /* allocate enough memory for all indexes */
1463  i = list_length(indexoidlist);
1464 
1465  if (i > 0)
1466  *Irel = (Relation *) palloc(i * sizeof(Relation));
1467  else
1468  *Irel = NULL;
1469 
1470  /* collect just the ready indexes */
1471  i = 0;
1472  foreach(indexoidscan, indexoidlist)
1473  {
1474  Oid indexoid = lfirst_oid(indexoidscan);
1475  Relation indrel;
1476 
1477  indrel = index_open(indexoid, lockmode);
1478  if (IndexIsReady(indrel->rd_index))
1479  (*Irel)[i++] = indrel;
1480  else
1481  index_close(indrel, lockmode);
1482  }
1483 
1484  *nindexes = i;
1485 
1486  list_free(indexoidlist);
1487 }
#define IndexIsReady(indexForm)
Definition: pg_index.h:108
unsigned int Oid
Definition: postgres_ext.h:31
Form_pg_index rd_index
Definition: rel.h:155
#define NoLock
Definition: lockdefs.h:34
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
static int list_length(const List *l)
Definition: pg_list.h:89
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4336
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
void * palloc(Size size)
Definition: mcxt.c:891
void list_free(List *list)
Definition: list.c:1133
int i
Definition: pg_list.h:45
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
#define lfirst_oid(lc)
Definition: pg_list.h:108
void vac_update_datfrozenxid ( void  )

Definition at line 892 of file vacuum.c.

References AccessShareLock, Assert, DATABASEOID, DatabaseRelationId, elog, ERROR, ForceTransactionIdLimitUpdate(), GetOldestMultiXactId(), GetOldestXmin(), GETSTRUCT, heap_close, heap_freetuple(), heap_inplace_update(), heap_open(), HeapTupleIsValid, InvalidOid, MultiXactIdIsValid, MultiXactIdPrecedes(), MyDatabaseId, NULL, ObjectIdGetDatum, ReadNewTransactionId(), ReadNextMultiXactId(), RelationRelationId, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_TOASTVALUE, RowExclusiveLock, SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), systable_getnext(), TransactionIdIsNormal, TransactionIdPrecedes(), and vac_truncate_clog().

Referenced by do_autovacuum(), and vacuum().

893 {
894  HeapTuple tuple;
895  Form_pg_database dbform;
896  Relation relation;
897  SysScanDesc scan;
898  HeapTuple classTup;
899  TransactionId newFrozenXid;
900  MultiXactId newMinMulti;
901  TransactionId lastSaneFrozenXid;
902  MultiXactId lastSaneMinMulti;
903  bool bogus = false;
904  bool dirty = false;
905 
906  /*
907  * Initialize the "min" calculation with GetOldestXmin, which is a
908  * reasonable approximation to the minimum relfrozenxid for not-yet-
909  * committed pg_class entries for new tables; see AddNewRelationTuple().
910  * So we cannot produce a wrong minimum by starting with this.
911  */
912  newFrozenXid = GetOldestXmin(NULL, true);
913 
914  /*
915  * Similarly, initialize the MultiXact "min" with the value that would be
916  * used on pg_class for new tables. See AddNewRelationTuple().
917  */
918  newMinMulti = GetOldestMultiXactId();
919 
920  /*
921  * Identify the latest relfrozenxid and relminmxid values that we could
922  * validly see during the scan. These are conservative values, but it's
923  * not really worth trying to be more exact.
924  */
925  lastSaneFrozenXid = ReadNewTransactionId();
926  lastSaneMinMulti = ReadNextMultiXactId();
927 
928  /*
929  * We must seqscan pg_class to find the minimum Xid, because there is no
930  * index that can help us here.
931  */
933 
934  scan = systable_beginscan(relation, InvalidOid, false,
935  NULL, 0, NULL);
936 
937  while ((classTup = systable_getnext(scan)) != NULL)
938  {
939  Form_pg_class classForm = (Form_pg_class) GETSTRUCT(classTup);
940 
941  /*
942  * Only consider relations able to hold unfrozen XIDs (anything else
943  * should have InvalidTransactionId in relfrozenxid anyway.)
944  */
945  if (classForm->relkind != RELKIND_RELATION &&
946  classForm->relkind != RELKIND_MATVIEW &&
947  classForm->relkind != RELKIND_TOASTVALUE)
948  continue;
949 
950  Assert(TransactionIdIsNormal(classForm->relfrozenxid));
951  Assert(MultiXactIdIsValid(classForm->relminmxid));
952 
953  /*
954  * If things are working properly, no relation should have a
955  * relfrozenxid or relminmxid that is "in the future". However, such
956  * cases have been known to arise due to bugs in pg_upgrade. If we
957  * see any entries that are "in the future", chicken out and don't do
958  * anything. This ensures we won't truncate clog before those
959  * relations have been scanned and cleaned up.
960  */
961  if (TransactionIdPrecedes(lastSaneFrozenXid, classForm->relfrozenxid) ||
962  MultiXactIdPrecedes(lastSaneMinMulti, classForm->relminmxid))
963  {
964  bogus = true;
965  break;
966  }
967 
968  if (TransactionIdPrecedes(classForm->relfrozenxid, newFrozenXid))
969  newFrozenXid = classForm->relfrozenxid;
970 
971  if (MultiXactIdPrecedes(classForm->relminmxid, newMinMulti))
972  newMinMulti = classForm->relminmxid;
973  }
974 
975  /* we're done with pg_class */
976  systable_endscan(scan);
977  heap_close(relation, AccessShareLock);
978 
979  /* chicken out if bogus data found */
980  if (bogus)
981  return;
982 
983  Assert(TransactionIdIsNormal(newFrozenXid));
984  Assert(MultiXactIdIsValid(newMinMulti));
985 
986  /* Now fetch the pg_database tuple we need to update. */
988 
989  /* Fetch a copy of the tuple to scribble on */
991  if (!HeapTupleIsValid(tuple))
992  elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
993  dbform = (Form_pg_database) GETSTRUCT(tuple);
994 
995  /*
996  * As in vac_update_relstats(), we ordinarily don't want to let
997  * datfrozenxid go backward; but if it's "in the future" then it must be
998  * corrupt and it seems best to overwrite it.
999  */
1000  if (dbform->datfrozenxid != newFrozenXid &&
1001  (TransactionIdPrecedes(dbform->datfrozenxid, newFrozenXid) ||
1002  TransactionIdPrecedes(lastSaneFrozenXid, dbform->datfrozenxid)))
1003  {
1004  dbform->datfrozenxid = newFrozenXid;
1005  dirty = true;
1006  }
1007  else
1008  newFrozenXid = dbform->datfrozenxid;
1009 
1010  /* Ditto for datminmxid */
1011  if (dbform->datminmxid != newMinMulti &&
1012  (MultiXactIdPrecedes(dbform->datminmxid, newMinMulti) ||
1013  MultiXactIdPrecedes(lastSaneMinMulti, dbform->datminmxid)))
1014  {
1015  dbform->datminmxid = newMinMulti;
1016  dirty = true;
1017  }
1018  else
1019  newMinMulti = dbform->datminmxid;
1020 
1021  if (dirty)
1022  heap_inplace_update(relation, tuple);
1023 
1024  heap_freetuple(tuple);
1025  heap_close(relation, RowExclusiveLock);
1026 
1027  /*
1028  * If we were able to advance datfrozenxid or datminmxid, see if we can
1029  * truncate pg_clog and/or pg_multixact. Also do it if the shared
1030  * XID-wrap-limit info is stale, since this action will update that too.
1031  */
1032  if (dirty || ForceTransactionIdLimitUpdate())
1033  vac_truncate_clog(newFrozenXid, newMinMulti,
1034  lastSaneFrozenXid, lastSaneMinMulti);
1035 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
uint32 TransactionId
Definition: c.h:394
FormData_pg_database * Form_pg_database
Definition: pg_database.h:57
#define DatabaseRelationId
Definition: pg_database.h:29
#define RelationRelationId
Definition: pg_class.h:29
#define RELKIND_MATVIEW
Definition: pg_class.h:167
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
bool ForceTransactionIdLimitUpdate(void)
Definition: varsup.c:408
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
TransactionId ReadNewTransactionId(void)
Definition: varsup.c:250
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
MultiXactId GetOldestMultiXactId(void)
Definition: multixact.c:2487
#define RELKIND_TOASTVALUE
Definition: pg_class.h:163
Oid MyDatabaseId
Definition: globals.c:76
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define InvalidOid
Definition: postgres_ext.h:36
TransactionId GetOldestXmin(Relation rel, bool ignoreVacuum)
Definition: procarray.c:1305
TransactionId MultiXactId
Definition: c.h:404
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti)
Definition: vacuum.c:1056
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:158
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:6233
#define elog
Definition: elog.h:219
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define RELKIND_RELATION
Definition: pg_class.h:160
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:721
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 755 of file vacuum.c.

References elog, ERROR, GETSTRUCT, heap_close, heap_inplace_update(), heap_open(), HeapTupleIsValid, MultiXactIdIsValid, MultiXactIdPrecedes(), NULL, ObjectIdGetDatum, RelationData::rd_rules, ReadNewTransactionId(), ReadNextMultiXactId(), RelationGetRelid, RelationRelationId, RELOID, RowExclusiveLock, SearchSysCacheCopy1, TransactionIdIsNormal, TransactionIdPrecedes(), and RelationData::trigdesc.

Referenced by do_analyze_rel(), lazy_cleanup_index(), and lazy_vacuum_rel().

761 {
762  Oid relid = RelationGetRelid(relation);
763  Relation rd;
764  HeapTuple ctup;
765  Form_pg_class pgcform;
766  bool dirty;
767 
769 
770  /* Fetch a copy of the tuple to scribble on */
772  if (!HeapTupleIsValid(ctup))
773  elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
774  relid);
775  pgcform = (Form_pg_class) GETSTRUCT(ctup);
776 
777  /* Apply statistical updates, if any, to copied tuple */
778 
779  dirty = false;
780  if (pgcform->relpages != (int32) num_pages)
781  {
782  pgcform->relpages = (int32) num_pages;
783  dirty = true;
784  }
785  if (pgcform->reltuples != (float4) num_tuples)
786  {
787  pgcform->reltuples = (float4) num_tuples;
788  dirty = true;
789  }
790  if (pgcform->relallvisible != (int32) num_all_visible_pages)
791  {
792  pgcform->relallvisible = (int32) num_all_visible_pages;
793  dirty = true;
794  }
795 
796  /* Apply DDL updates, but not inside an outer transaction (see above) */
797 
798  if (!in_outer_xact)
799  {
800  /*
801  * If we didn't find any indexes, reset relhasindex.
802  */
803  if (pgcform->relhasindex && !hasindex)
804  {
805  pgcform->relhasindex = false;
806  dirty = true;
807  }
808 
809  /*
810  * If we have discovered that there are no indexes, then there's no
811  * primary key either. This could be done more thoroughly...
812  */
813  if (pgcform->relhaspkey && !hasindex)
814  {
815  pgcform->relhaspkey = false;
816  dirty = true;
817  }
818 
819  /* We also clear relhasrules and relhastriggers if needed */
820  if (pgcform->relhasrules && relation->rd_rules == NULL)
821  {
822  pgcform->relhasrules = false;
823  dirty = true;
824  }
825  if (pgcform->relhastriggers && relation->trigdesc == NULL)
826  {
827  pgcform->relhastriggers = false;
828  dirty = true;
829  }
830  }
831 
832  /*
833  * Update relfrozenxid, unless caller passed InvalidTransactionId
834  * indicating it has no new data.
835  *
836  * Ordinarily, we don't let relfrozenxid go backwards: if things are
837  * working correctly, the only way the new frozenxid could be older would
838  * be if a previous VACUUM was done with a tighter freeze_min_age, in
839  * which case we don't want to forget the work it already did. However,
840  * if the stored relfrozenxid is "in the future", then it must be corrupt
841  * and it seems best to overwrite it with the cutoff we used this time.
842  * This should match vac_update_datfrozenxid() concerning what we consider
843  * to be "in the future".
844  */
845  if (TransactionIdIsNormal(frozenxid) &&
846  pgcform->relfrozenxid != frozenxid &&
847  (TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid) ||
849  pgcform->relfrozenxid)))
850  {
851  pgcform->relfrozenxid = frozenxid;
852  dirty = true;
853  }
854 
855  /* Similarly for relminmxid */
856  if (MultiXactIdIsValid(minmulti) &&
857  pgcform->relminmxid != minmulti &&
858  (MultiXactIdPrecedes(pgcform->relminmxid, minmulti) ||
859  MultiXactIdPrecedes(ReadNextMultiXactId(), pgcform->relminmxid)))
860  {
861  pgcform->relminmxid = minmulti;
862  dirty = true;
863  }
864 
865  /* If anything changed, write out the tuple. */
866  if (dirty)
867  heap_inplace_update(rd, ctup);
868 
870 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationRelationId
Definition: pg_class.h:29
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:253
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:119
#define RowExclusiveLock
Definition: lockdefs.h:38
TransactionId ReadNewTransactionId(void)
Definition: varsup.c:250
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
float float4
Definition: c.h:377
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
RuleLock * rd_rules
Definition: rel.h:117
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:158
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:6233
#define elog
Definition: elog.h:219
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define RelationGetRelid(relation)
Definition: rel.h:413
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:721
void vacuum ( int  options,
RangeVar relation,
Oid  relid,
VacuumParams params,
List va_cols,
BufferAccessStrategy  bstrategy,
bool  isTopLevel 
)

Definition at line 148 of file vacuum.c.

References ActiveSnapshotSet(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), analyze_rel(), Assert, BAS_VACUUM, CommitTransactionCommand(), cur, ereport, errcode(), errmsg(), ERROR, get_rel_oids(), GetAccessStrategy(), GetTransactionSnapshot(), IsAutoVacuumWorkerProcess(), IsInTransactionChain(), lfirst_oid, list_length(), MemoryContextDelete(), MemoryContextSwitchTo(), NULL, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgstat_vacuum_stat(), PopActiveSnapshot(), PortalContext, PreventTransactionChain(), PushActiveSnapshot(), StartTransactionCommand(), vac_update_datfrozenxid(), VACOPT_ANALYZE, VACOPT_DISABLE_PAGE_SKIPPING, VACOPT_FULL, VACOPT_VACUUM, vacuum_rel(), VacuumCostActive, VacuumCostBalance, VacuumCostDelay, VacuumPageDirty, VacuumPageHit, and VacuumPageMiss.

Referenced by autovacuum_do_vac_analyze(), and ExecVacuum().

150 {
151  const char *stmttype;
152  volatile bool in_outer_xact,
153  use_own_xacts;
154  List *relations;
155  static bool in_vacuum = false;
156 
157  Assert(params != NULL);
158 
159  stmttype = (options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
160 
161  /*
162  * We cannot run VACUUM inside a user transaction block; if we were inside
163  * a transaction, then our commit- and start-transaction-command calls
164  * would not have the intended effect! There are numerous other subtle
165  * dependencies on this, too.
166  *
167  * ANALYZE (without VACUUM) can run either way.
168  */
169  if (options & VACOPT_VACUUM)
170  {
171  PreventTransactionChain(isTopLevel, stmttype);
172  in_outer_xact = false;
173  }
174  else
175  in_outer_xact = IsInTransactionChain(isTopLevel);
176 
177  /*
178  * Due to static variables vac_context, anl_context and vac_strategy,
179  * vacuum() is not reentrant. This matters when VACUUM FULL or ANALYZE
180  * calls a hostile index expression that itself calls ANALYZE.
181  */
182  if (in_vacuum)
183  ereport(ERROR,
184  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
185  errmsg("%s cannot be executed from VACUUM or ANALYZE",
186  stmttype)));
187 
188  /*
189  * Sanity check DISABLE_PAGE_SKIPPING option.
190  */
191  if ((options & VACOPT_FULL) != 0 &&
193  ereport(ERROR,
194  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
195  errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
196 
197  /*
198  * Send info about dead objects to the statistics collector, unless we are
199  * in autovacuum --- autovacuum.c does this for itself.
200  */
201  if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
203 
204  /*
205  * Create special memory context for cross-transaction storage.
206  *
207  * Since it is a child of PortalContext, it will go away eventually even
208  * if we suffer an error; there's no need for special abort cleanup logic.
209  */
211  "Vacuum",
213 
214  /*
215  * If caller didn't give us a buffer strategy object, make one in the
216  * cross-transaction memory context.
217  */
218  if (bstrategy == NULL)
219  {
221 
222  bstrategy = GetAccessStrategy(BAS_VACUUM);
223  MemoryContextSwitchTo(old_context);
224  }
225  vac_strategy = bstrategy;
226 
227  /*
228  * Build list of relations to process, unless caller gave us one. (If we
229  * build one, we put it in vac_context for safekeeping.)
230  */
231  relations = get_rel_oids(relid, relation);
232 
233  /*
234  * Decide whether we need to start/commit our own transactions.
235  *
236  * For VACUUM (with or without ANALYZE): always do so, so that we can
237  * release locks as soon as possible. (We could possibly use the outer
238  * transaction for a one-table VACUUM, but handling TOAST tables would be
239  * problematic.)
240  *
241  * For ANALYZE (no VACUUM): if inside a transaction block, we cannot
242  * start/commit our own transactions. Also, there's no need to do so if
243  * only processing one relation. For multiple relations when not within a
244  * transaction block, and also in an autovacuum worker, use own
245  * transactions so we can release locks sooner.
246  */
247  if (options & VACOPT_VACUUM)
248  use_own_xacts = true;
249  else
250  {
253  use_own_xacts = true;
254  else if (in_outer_xact)
255  use_own_xacts = false;
256  else if (list_length(relations) > 1)
257  use_own_xacts = true;
258  else
259  use_own_xacts = false;
260  }
261 
262  /*
263  * vacuum_rel expects to be entered with no transaction active; it will
264  * start and commit its own transaction. But we are called by an SQL
265  * command, and so we are executing inside a transaction already. We
266  * commit the transaction started in PostgresMain() here, and start
267  * another one before exiting to match the commit waiting for us back in
268  * PostgresMain().
269  */
270  if (use_own_xacts)
271  {
272  Assert(!in_outer_xact);
273 
274  /* ActiveSnapshot is not set by autovacuum */
275  if (ActiveSnapshotSet())
277 
278  /* matches the StartTransaction in PostgresMain() */
280  }
281 
282  /* Turn vacuum cost accounting on or off */
283  PG_TRY();
284  {
285  ListCell *cur;
286 
287  in_vacuum = true;
289  VacuumCostBalance = 0;
290  VacuumPageHit = 0;
291  VacuumPageMiss = 0;
292  VacuumPageDirty = 0;
293 
294  /*
295  * Loop to process each selected relation.
296  */
297  foreach(cur, relations)
298  {
299  Oid relid = lfirst_oid(cur);
300 
301  if (options & VACOPT_VACUUM)
302  {
303  if (!vacuum_rel(relid, relation, options, params))
304  continue;
305  }
306 
307  if (options & VACOPT_ANALYZE)
308  {
309  /*
310  * If using separate xacts, start one for analyze. Otherwise,
311  * we can use the outer transaction.
312  */
313  if (use_own_xacts)
314  {
316  /* functions in indexes may want a snapshot set */
318  }
319 
320  analyze_rel(relid, relation, options, params,
321  va_cols, in_outer_xact, vac_strategy);
322 
323  if (use_own_xacts)
324  {
327  }
328  }
329  }
330  }
331  PG_CATCH();
332  {
333  in_vacuum = false;
334  VacuumCostActive = false;
335  PG_RE_THROW();
336  }
337  PG_END_TRY();
338 
339  in_vacuum = false;
340  VacuumCostActive = false;
341 
342  /*
343  * Finish up processing.
344  */
345  if (use_own_xacts)
346  {
347  /* here, we are not in a transaction */
348 
349  /*
350  * This matches the CommitTransaction waiting for us in
351  * PostgresMain().
352  */
354  }
355 
356  if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
357  {
358  /*
359  * Update pg_database.datfrozenxid, and truncate pg_clog if possible.
360  * (autovacuum.c does this for itself.)
361  */
363  }
364 
365  /*
366  * Clean up working storage --- note we must do this after
367  * StartTransactionCommand, else we might be trying to delete the active
368  * context!
369  */
371  vac_context = NULL;
372 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:525
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
int VacuumCostBalance
Definition: globals.c:138
void vac_update_datfrozenxid(void)
Definition: vacuum.c:892
int VacuumPageHit
Definition: globals.c:134
void CommitTransactionCommand(void)
Definition: xact.c:2745
void analyze_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params, List *va_cols, bool in_outer_xact, BufferAccessStrategy bstrategy)
Definition: analyze.c:105
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static BufferAccessStrategy vac_strategy
Definition: vacuum.c:65
struct cursor * cur
Definition: ecpg.c:28
int errcode(int sqlerrcode)
Definition: elog.c:575
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
unsigned int Oid
Definition: postgres_ext.h:31
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
static List * get_rel_oids(Oid relid, const RangeVar *vacrel)
Definition: vacuum.c:381
MemoryContext PortalContext
Definition: mcxt.c:52
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:145
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
static MemoryContext vac_context
Definition: vacuum.c:64
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:846
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:2989
#define ereport(elevel, rest)
Definition: elog.h:122
void pgstat_vacuum_stat(void)
Definition: pgstat.c:946
int VacuumPageDirty
Definition: globals.c:136
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:440
int VacuumCostDelay
Definition: globals.c:132
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
static bool vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
Definition: vacuum.c:1194
void StartTransactionCommand(void)
Definition: xact.c:2675
static int list_length(const List *l)
Definition: pg_list.h:89
#define PG_RE_THROW()
Definition: elog.h:314
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool IsInTransactionChain(bool isTopLevel)
Definition: xact.c:3268
int VacuumPageMiss
Definition: globals.c:135
#define PG_TRY()
Definition: elog.h:284
Definition: pg_list.h:45
#define PG_END_TRY()
Definition: elog.h:300
#define lfirst_oid(lc)
Definition: pg_list.h:108
void PreventTransactionChain(bool isTopLevel, const char *stmtType)
Definition: xact.c:3152
bool VacuumCostActive
Definition: globals.c:139
void vacuum_delay_point ( void  )

Definition at line 1515 of file vacuum.c.

References AutoVacuumUpdateDelay(), CHECK_FOR_INTERRUPTS, InterruptPending, pg_usleep(), VacuumCostActive, VacuumCostBalance, VacuumCostDelay, and VacuumCostLimit.

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(), ginVacuumPostingTree(), gistbulkdelete(), gistvacuumcleanup(), hashbucketcleanup(), lazy_scan_heap(), lazy_vacuum_heap(), spgprocesspending(), and spgvacuumpage().

1516 {
1517  /* Always check for interrupts */
1519 
1520  /* Nap if appropriate */
1523  {
1524  int msec;
1525 
1527  if (msec > VacuumCostDelay * 4)
1528  msec = VacuumCostDelay * 4;
1529 
1530  pg_usleep(msec * 1000L);
1531 
1532  VacuumCostBalance = 0;
1533 
1534  /* update balance values for workers */
1536 
1537  /* Might have gotten an interrupt while sleeping */
1539  }
1540 }
int VacuumCostBalance
Definition: globals.c:138
void pg_usleep(long microsec)
Definition: signal.c:53
int VacuumCostLimit
Definition: globals.c:131
int VacuumCostDelay
Definition: globals.c:132
volatile bool InterruptPending
Definition: globals.c:29
void AutoVacuumUpdateDelay(void)
Definition: autovacuum.c:1714
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
bool VacuumCostActive
Definition: globals.c:139
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 471 of file vacuum.c.

References Assert, autovacuum_freeze_max_age, ereport, errhint(), errmsg(), FirstMultiXactId, FirstNormalTransactionId, GetOldestMultiXactId(), GetOldestXmin(), Min, MultiXactIdPrecedes(), MultiXactMemberFreezeThreshold(), NULL, ReadNewTransactionId(), ReadNextMultiXactId(), 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_heap_data(), and lazy_vacuum_rel().

481 {
482  int freezemin;
483  int mxid_freezemin;
484  int effective_multixact_freeze_max_age;
485  TransactionId limit;
486  TransactionId safeLimit;
487  MultiXactId mxactLimit;
488  MultiXactId safeMxactLimit;
489 
490  /*
491  * We can always ignore processes running lazy vacuum. This is because we
492  * use these values only for deciding which tuples we must keep in the
493  * tables. Since lazy vacuum doesn't write its XID anywhere, it's safe to
494  * ignore it. In theory it could be problematic to ignore lazy vacuums in
495  * a full vacuum, but keep in mind that only one vacuum process can be
496  * working on a particular table at any time, and that each vacuum is
497  * always an independent transaction.
498  */
499  *oldestXmin =
501 
502  Assert(TransactionIdIsNormal(*oldestXmin));
503 
504  /*
505  * Determine the minimum freeze age to use: as specified by the caller, or
506  * vacuum_freeze_min_age, but in any case not more than half
507  * autovacuum_freeze_max_age, so that autovacuums to prevent XID
508  * wraparound won't occur too frequently.
509  */
510  freezemin = freeze_min_age;
511  if (freezemin < 0)
512  freezemin = vacuum_freeze_min_age;
513  freezemin = Min(freezemin, autovacuum_freeze_max_age / 2);
514  Assert(freezemin >= 0);
515 
516  /*
517  * Compute the cutoff XID, being careful not to generate a "permanent" XID
518  */
519  limit = *oldestXmin - freezemin;
520  if (!TransactionIdIsNormal(limit))
521  limit = FirstNormalTransactionId;
522 
523  /*
524  * If oldestXmin is very far back (in practice, more than
525  * autovacuum_freeze_max_age / 2 XIDs old), complain and force a minimum
526  * freeze age of zero.
527  */
529  if (!TransactionIdIsNormal(safeLimit))
530  safeLimit = FirstNormalTransactionId;
531 
532  if (TransactionIdPrecedes(limit, safeLimit))
533  {
535  (errmsg("oldest xmin is far in the past"),
536  errhint("Close open transactions soon to avoid wraparound problems.")));
537  limit = *oldestXmin;
538  }
539 
540  *freezeLimit = limit;
541 
542  /*
543  * Compute the multixact age for which freezing is urgent. This is
544  * normally autovacuum_multixact_freeze_max_age, but may be less if we are
545  * short of multixact member space.
546  */
547  effective_multixact_freeze_max_age = MultiXactMemberFreezeThreshold();
548 
549  /*
550  * Determine the minimum multixact freeze age to use: as specified by
551  * caller, or vacuum_multixact_freeze_min_age, but in any case not more
552  * than half effective_multixact_freeze_max_age, so that autovacuums to
553  * prevent MultiXact wraparound won't occur too frequently.
554  */
555  mxid_freezemin = multixact_freeze_min_age;
556  if (mxid_freezemin < 0)
557  mxid_freezemin = vacuum_multixact_freeze_min_age;
558  mxid_freezemin = Min(mxid_freezemin,
559  effective_multixact_freeze_max_age / 2);
560  Assert(mxid_freezemin >= 0);
561 
562  /* compute the cutoff multi, being careful to generate a valid value */
563  mxactLimit = GetOldestMultiXactId() - mxid_freezemin;
564  if (mxactLimit < FirstMultiXactId)
565  mxactLimit = FirstMultiXactId;
566 
567  safeMxactLimit =
568  ReadNextMultiXactId() - effective_multixact_freeze_max_age;
569  if (safeMxactLimit < FirstMultiXactId)
570  safeMxactLimit = FirstMultiXactId;
571 
572  if (MultiXactIdPrecedes(mxactLimit, safeMxactLimit))
573  {
575  (errmsg("oldest multixact is far in the past"),
576  errhint("Close open transactions with multixacts soon to avoid wraparound problems.")));
577  mxactLimit = safeMxactLimit;
578  }
579 
580  *multiXactCutoff = mxactLimit;
581 
582  if (xidFullScanLimit != NULL)
583  {
584  int freezetable;
585 
586  Assert(mxactFullScanLimit != NULL);
587 
588  /*
589  * Determine the table freeze age to use: as specified by the caller,
590  * or vacuum_freeze_table_age, but in any case not more than
591  * autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly
592  * VACUUM schedule, the nightly VACUUM gets a chance to freeze tuples
593  * before anti-wraparound autovacuum is launched.
594  */
595  freezetable = freeze_table_age;
596  if (freezetable < 0)
597  freezetable = vacuum_freeze_table_age;
598  freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95);
599  Assert(freezetable >= 0);
600 
601  /*
602  * Compute XID limit causing a full-table vacuum, being careful not to
603  * generate a "permanent" XID.
604  */
605  limit = ReadNewTransactionId() - freezetable;
606  if (!TransactionIdIsNormal(limit))
607  limit = FirstNormalTransactionId;
608 
609  *xidFullScanLimit = limit;
610 
611  /*
612  * Similar to the above, determine the table freeze age to use for
613  * multixacts: as specified by the caller, or
614  * vacuum_multixact_freeze_table_age, but in any case not more than
615  * autovacuum_multixact_freeze_table_age * 0.95, so that if you have
616  * e.g. nightly VACUUM schedule, the nightly VACUUM gets a chance to
617  * freeze multixacts before anti-wraparound autovacuum is launched.
618  */
619  freezetable = multixact_freeze_table_age;
620  if (freezetable < 0)
621  freezetable = vacuum_multixact_freeze_table_age;
622  freezetable = Min(freezetable,
623  effective_multixact_freeze_max_age * 0.95);
624  Assert(freezetable >= 0);
625 
626  /*
627  * Compute MultiXact limit causing a full-table vacuum, being careful
628  * to generate a valid MultiXact value.
629  */
630  mxactLimit = ReadNextMultiXactId() - freezetable;
631  if (mxactLimit < FirstMultiXactId)
632  mxactLimit = FirstMultiXactId;
633 
634  *mxactFullScanLimit = mxactLimit;
635  }
636  else
637  {
638  Assert(mxactFullScanLimit == NULL);
639  }
640 }
int errhint(const char *fmt,...)
Definition: elog.c:987
int vacuum_multixact_freeze_table_age
Definition: vacuum.c:60
uint32 TransactionId
Definition: c.h:394
#define Min(x, y)
Definition: c.h:802
TransactionId TransactionIdLimitedForOldSnapshots(TransactionId recentXmin, Relation relation)
Definition: snapmgr.c:1689
#define FirstNormalTransactionId
Definition: transam.h:34
int autovacuum_freeze_max_age
Definition: autovacuum.c:119
int vacuum_multixact_freeze_min_age
Definition: vacuum.c:59
TransactionId ReadNewTransactionId(void)
Definition: varsup.c:250
#define FirstMultiXactId
Definition: multixact.h:24
#define ereport(elevel, rest)
Definition: elog.h:122
int MultiXactMemberFreezeThreshold(void)
Definition: multixact.c:2812
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define WARNING
Definition: elog.h:40
MultiXactId GetOldestMultiXactId(void)
Definition: multixact.c:2487
TransactionId GetOldestXmin(Relation rel, bool ignoreVacuum)
Definition: procarray.c:1305
TransactionId MultiXactId
Definition: c.h:404
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
int vacuum_freeze_min_age
Definition: vacuum.c:57
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
int vacuum_freeze_table_age
Definition: vacuum.c:58
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:721

Variable Documentation

PGDLLIMPORT int default_statistics_target

Definition at line 71 of file analyze.c.

Referenced by range_typanalyze(), std_typanalyze(), and ts_typanalyze().

int vacuum_freeze_min_age

Definition at line 57 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().

int vacuum_freeze_table_age

Definition at line 58 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().

int vacuum_multixact_freeze_min_age

Definition at line 59 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().

int vacuum_multixact_freeze_table_age

Definition at line 60 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().