PostgreSQL Source Code  git master
vacuum.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
Include dependency graph for vacuum.c:

Go to the source code of this file.

Functions

static Listexpand_vacuum_rel (VacuumRelation *vrel)
 
static Listget_all_vacuum_rels (void)
 
static void vac_truncate_clog (TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti)
 
static bool vacuum_rel (Oid relid, RangeVar *relation, int options, VacuumParams *params)
 
void ExecVacuum (VacuumStmt *vacstmt, bool isTopLevel)
 
void vacuum (int options, List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel)
 
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)
 
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 vac_update_datfrozenxid (void)
 
void vac_open_indexes (Relation relation, LOCKMODE lockmode, int *nindexes, Relation **Irel)
 
void vac_close_indexes (int nindexes, Relation *Irel, LOCKMODE lockmode)
 
void vacuum_delay_point (void)
 

Variables

int vacuum_freeze_min_age
 
int vacuum_freeze_table_age
 
int vacuum_multixact_freeze_min_age
 
int vacuum_multixact_freeze_table_age
 
static MemoryContext vac_context = NULL
 
static BufferAccessStrategy vac_strategy
 

Function Documentation

◆ ExecVacuum()

void ExecVacuum ( VacuumStmt vacstmt,
bool  isTopLevel 
)

Definition at line 87 of file vacuum.c.

References Assert, ereport, errcode(), errmsg(), ERROR, VacuumParams::freeze_min_age, VacuumParams::freeze_table_age, VacuumParams::is_wraparound, lfirst_node, VacuumParams::log_min_duration, VacuumParams::multixact_freeze_min_age, VacuumParams::multixact_freeze_table_age, NIL, VacuumStmt::options, VacuumStmt::rels, VacuumRelation::va_cols, VACOPT_ANALYZE, VACOPT_FREEZE, VACOPT_FULL, VACOPT_SKIPTOAST, VACOPT_VACUUM, and vacuum().

Referenced by standard_ProcessUtility().

88 {
89  VacuumParams params;
90 
91  /* sanity checks on options */
93  Assert((vacstmt->options & VACOPT_VACUUM) ||
94  !(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE)));
95  Assert(!(vacstmt->options & VACOPT_SKIPTOAST));
96 
97  /*
98  * Make sure VACOPT_ANALYZE is specified if any column lists are present.
99  */
100  if (!(vacstmt->options & VACOPT_ANALYZE))
101  {
102  ListCell *lc;
103 
104  foreach(lc, vacstmt->rels)
105  {
107 
108  if (vrel->va_cols != NIL)
109  ereport(ERROR,
110  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
111  errmsg("ANALYZE option must be specified when a column list is provided")));
112  }
113  }
114 
115  /*
116  * All freeze ages are zero if the FREEZE option is given; otherwise pass
117  * them as -1 which means to use the default values.
118  */
119  if (vacstmt->options & VACOPT_FREEZE)
120  {
121  params.freeze_min_age = 0;
122  params.freeze_table_age = 0;
123  params.multixact_freeze_min_age = 0;
124  params.multixact_freeze_table_age = 0;
125  }
126  else
127  {
128  params.freeze_min_age = -1;
129  params.freeze_table_age = -1;
130  params.multixact_freeze_min_age = -1;
131  params.multixact_freeze_table_age = -1;
132  }
133 
134  /* user-invoked vacuum is never "for wraparound" */
135  params.is_wraparound = false;
136 
137  /* user-invoked vacuum never uses this parameter */
138  params.log_min_duration = -1;
139 
140  /* Now go through the common routine */
141  vacuum(vacstmt->options, vacstmt->rels, &params, NULL, isTopLevel);
142 }
#define NIL
Definition: pg_list.h:69
int multixact_freeze_table_age
Definition: vacuum.h:142
int errcode(int sqlerrcode)
Definition: elog.c:575
int freeze_table_age
Definition: vacuum.h:139
void vacuum(int options, List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel)
Definition: vacuum.c:166
#define ERROR
Definition: elog.h:43
int freeze_min_age
Definition: vacuum.h:138
bool is_wraparound
Definition: vacuum.h:144
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define ereport(elevel, rest)
Definition: elog.h:122
#define Assert(condition)
Definition: c.h:670
int log_min_duration
Definition: vacuum.h:145
int errmsg(const char *fmt,...)
Definition: elog.c:797
int multixact_freeze_min_age
Definition: vacuum.h:140
List * rels
Definition: parsenodes.h:3127

◆ expand_vacuum_rel()

static List * expand_vacuum_rel ( VacuumRelation vrel)
static

Definition at line 426 of file vacuum.c.

References AccessShareLock, elog, ERROR, find_all_inheritors(), GETSTRUCT, HeapTupleIsValid, lappend(), lfirst_oid, makeVacuumRelation(), MemoryContextSwitchTo(), NIL, NoLock, ObjectIdGetDatum, VacuumRelation::oid, OidIsValid, RangeVarGetRelid, VacuumRelation::relation, ReleaseSysCache(), RELKIND_PARTITIONED_TABLE, RELOID, SearchSysCache1(), UnlockRelationOid(), and VacuumRelation::va_cols.

Referenced by vacuum().

427 {
428  List *vacrels = NIL;
429  MemoryContext oldcontext;
430 
431  /* If caller supplied OID, there's nothing we need do here. */
432  if (OidIsValid(vrel->oid))
433  {
434  oldcontext = MemoryContextSwitchTo(vac_context);
435  vacrels = lappend(vacrels, vrel);
436  MemoryContextSwitchTo(oldcontext);
437  }
438  else
439  {
440  /* Process a specific relation, and possibly partitions thereof */
441  Oid relid;
442  HeapTuple tuple;
443  Form_pg_class classForm;
444  bool include_parts;
445 
446  /*
447  * We transiently take AccessShareLock to protect the syscache lookup
448  * below, as well as find_all_inheritors's expectation that the caller
449  * holds some lock on the starting relation.
450  */
451  relid = RangeVarGetRelid(vrel->relation, AccessShareLock, false);
452 
453  /*
454  * Make a returnable VacuumRelation for this rel.
455  */
456  oldcontext = MemoryContextSwitchTo(vac_context);
457  vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
458  relid,
459  vrel->va_cols));
460  MemoryContextSwitchTo(oldcontext);
461 
462  /*
463  * To check whether the relation is a partitioned table, fetch its
464  * syscache entry.
465  */
466  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
467  if (!HeapTupleIsValid(tuple))
468  elog(ERROR, "cache lookup failed for relation %u", relid);
469  classForm = (Form_pg_class) GETSTRUCT(tuple);
470  include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
471  ReleaseSysCache(tuple);
472 
473  /*
474  * If it is, make relation list entries for its partitions. Note that
475  * the list returned by find_all_inheritors() includes the passed-in
476  * OID, so we have to skip that. There's no point in taking locks on
477  * the individual partitions yet, and doing so would just add
478  * unnecessary deadlock risk.
479  */
480  if (include_parts)
481  {
482  List *part_oids = find_all_inheritors(relid, NoLock, NULL);
483  ListCell *part_lc;
484 
485  foreach(part_lc, part_oids)
486  {
487  Oid part_oid = lfirst_oid(part_lc);
488 
489  if (part_oid == relid)
490  continue; /* ignore original table */
491 
492  /*
493  * We omit a RangeVar since it wouldn't be appropriate to
494  * complain about failure to open one of these relations
495  * later.
496  */
497  oldcontext = MemoryContextSwitchTo(vac_context);
498  vacrels = lappend(vacrels, makeVacuumRelation(NULL,
499  part_oid,
500  vrel->va_cols));
501  MemoryContextSwitchTo(oldcontext);
502  }
503  }
504 
505  /*
506  * Release lock again. This means that by the time we actually try to
507  * process the table, it might be gone or renamed. In the former case
508  * we'll silently ignore it; in the latter case we'll process it
509  * anyway, but we must beware that the RangeVar doesn't necessarily
510  * identify it anymore. This isn't ideal, perhaps, but there's little
511  * practical alternative, since we're typically going to commit this
512  * transaction and begin a new one between now and then. Moreover,
513  * holding locks on multiple relations would create significant risk
514  * of deadlock.
515  */
517  }
518 
519  return vacrels;
520 }
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
RangeVar * relation
Definition: parsenodes.h:3118
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
VacuumRelation * makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols)
Definition: makefuncs.c:622
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:53
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
static MemoryContext vac_context
Definition: vacuum.c:66
List * lappend(List *list, void *datum)
Definition: list.c:128
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:167
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ get_all_vacuum_rels()

static List * get_all_vacuum_rels ( void  )
static

Definition at line 527 of file vacuum.c.

References AccessShareLock, ForwardScanDirection, GETSTRUCT, heap_beginscan_catalog(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, lappend(), makeVacuumRelation(), MemoryContextSwitchTo(), NIL, RelationRelationId, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, and RELKIND_RELATION.

Referenced by vacuum().

528 {
529  List *vacrels = NIL;
530  Relation pgclass;
531  HeapScanDesc scan;
532  HeapTuple tuple;
533 
535 
536  scan = heap_beginscan_catalog(pgclass, 0, NULL);
537 
538  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
539  {
540  Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
541  MemoryContext oldcontext;
542 
543  /*
544  * We include partitioned tables here; depending on which operation is
545  * to be performed, caller will decide whether to process or ignore
546  * them.
547  */
548  if (classForm->relkind != RELKIND_RELATION &&
549  classForm->relkind != RELKIND_MATVIEW &&
550  classForm->relkind != RELKIND_PARTITIONED_TABLE)
551  continue;
552 
553  /*
554  * Build VacuumRelation(s) specifying the table OIDs to be processed.
555  * We omit a RangeVar since it wouldn't be appropriate to complain
556  * about failure to open one of these relations later.
557  */
558  oldcontext = MemoryContextSwitchTo(vac_context);
559  vacrels = lappend(vacrels, makeVacuumRelation(NULL,
560  HeapTupleGetOid(tuple),
561  NIL));
562  MemoryContextSwitchTo(oldcontext);
563  }
564 
565  heap_endscan(scan);
566  heap_close(pgclass, AccessShareLock);
567 
568  return vacrels;
569 }
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1565
VacuumRelation * makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols)
Definition: makefuncs.c:622
#define RelationRelationId
Definition: pg_class.h:29
#define RELKIND_MATVIEW
Definition: pg_class.h:165
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
static MemoryContext vac_context
Definition: vacuum.c:66
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1405
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1808
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45

◆ vac_close_indexes()

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

Definition at line 1637 of file vacuum.c.

References index_close(), and pfree().

Referenced by do_analyze_rel(), and lazy_vacuum_rel().

1638 {
1639  if (Irel == NULL)
1640  return;
1641 
1642  while (nindexes--)
1643  {
1644  Relation ind = Irel[nindexes];
1645 
1646  index_close(ind, lockmode);
1647  }
1648  pfree(Irel);
1649 }
void pfree(void *pointer)
Definition: mcxt.c:949
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176

◆ vac_estimate_reltuples()

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

Definition at line 777 of file vacuum.c.

References RelationData::rd_rel.

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

781 {
782  BlockNumber old_rel_pages = relation->rd_rel->relpages;
783  double old_rel_tuples = relation->rd_rel->reltuples;
784  double old_density;
785  double new_density;
786  double multiplier;
787  double updated_density;
788 
789  /* If we did scan the whole table, just use the count as-is */
790  if (scanned_pages >= total_pages)
791  return scanned_tuples;
792 
793  /*
794  * If scanned_pages is zero but total_pages isn't, keep the existing value
795  * of reltuples. (Note: callers should avoid updating the pg_class
796  * statistics in this situation, since no new information has been
797  * provided.)
798  */
799  if (scanned_pages == 0)
800  return old_rel_tuples;
801 
802  /*
803  * If old value of relpages is zero, old density is indeterminate; we
804  * can't do much except scale up scanned_tuples to match total_pages.
805  */
806  if (old_rel_pages == 0)
807  return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
808 
809  /*
810  * Okay, we've covered the corner cases. The normal calculation is to
811  * convert the old measurement to a density (tuples per page), then update
812  * the density using an exponential-moving-average approach, and finally
813  * compute reltuples as updated_density * total_pages.
814  *
815  * For ANALYZE, the moving average multiplier is just the fraction of the
816  * table's pages we scanned. This is equivalent to assuming that the
817  * tuple density in the unscanned pages didn't change. Of course, it
818  * probably did, if the new density measurement is different. But over
819  * repeated cycles, the value of reltuples will converge towards the
820  * correct value, if repeated measurements show the same new density.
821  *
822  * For VACUUM, the situation is a bit different: we have looked at a
823  * nonrandom sample of pages, but we know for certain that the pages we
824  * didn't look at are precisely the ones that haven't changed lately.
825  * Thus, there is a reasonable argument for doing exactly the same thing
826  * as for the ANALYZE case, that is use the old density measurement as the
827  * value for the unscanned pages.
828  *
829  * This logic could probably use further refinement.
830  */
831  old_density = old_rel_tuples / old_rel_pages;
832  new_density = scanned_tuples / scanned_pages;
833  multiplier = (double) scanned_pages / (double) total_pages;
834  updated_density = old_density + (new_density - old_density) * multiplier;
835  return floor(updated_density * total_pages + 0.5);
836 }
uint32 BlockNumber
Definition: block.h:31
Form_pg_class rd_rel
Definition: rel.h:114

◆ vac_open_indexes()

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

Definition at line 1594 of file vacuum.c.

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

Referenced by do_analyze_rel(), and lazy_vacuum_rel().

1596 {
1597  List *indexoidlist;
1598  ListCell *indexoidscan;
1599  int i;
1600 
1601  Assert(lockmode != NoLock);
1602 
1603  indexoidlist = RelationGetIndexList(relation);
1604 
1605  /* allocate enough memory for all indexes */
1606  i = list_length(indexoidlist);
1607 
1608  if (i > 0)
1609  *Irel = (Relation *) palloc(i * sizeof(Relation));
1610  else
1611  *Irel = NULL;
1612 
1613  /* collect just the ready indexes */
1614  i = 0;
1615  foreach(indexoidscan, indexoidlist)
1616  {
1617  Oid indexoid = lfirst_oid(indexoidscan);
1618  Relation indrel;
1619 
1620  indrel = index_open(indexoid, lockmode);
1621  if (IndexIsReady(indrel->rd_index))
1622  (*Irel)[i++] = indrel;
1623  else
1624  index_close(indrel, lockmode);
1625  }
1626 
1627  *nindexes = i;
1628 
1629  list_free(indexoidlist);
1630 }
#define IndexIsReady(indexForm)
Definition: pg_index.h:108
unsigned int Oid
Definition: postgres_ext.h:31
Form_pg_index rd_index
Definition: rel.h:159
#define NoLock
Definition: lockdefs.h:34
#define Assert(condition)
Definition: c.h:670
static int list_length(const List *l)
Definition: pg_list.h:89
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4360
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
void * palloc(Size size)
Definition: mcxt.c:848
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

◆ vac_truncate_clog()

static void vac_truncate_clog ( TransactionId  frozenXID,
MultiXactId  minMulti,
TransactionId  lastSaneFrozenXid,
MultiXactId  lastSaneMinMulti 
)
static

Definition at line 1178 of file vacuum.c.

References AccessShareLock, AdvanceOldestCommitTsXid(), Assert, DatabaseRelationId, ereport, errdetail(), errmsg(), FormData_pg_database, ForwardScanDirection, GETSTRUCT, heap_beginscan_catalog(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, MultiXactIdIsValid, MultiXactIdPrecedes(), MyDatabaseId, ReadNewTransactionId(), SetMultiXactIdLimit(), SetTransactionIdLimit(), TransactionIdIsNormal, TransactionIdPrecedes(), TruncateCLOG(), TruncateCommitTs(), TruncateMultiXact(), and WARNING.

Referenced by vac_update_datfrozenxid().

1182 {
1183  TransactionId nextXID = ReadNewTransactionId();
1184  Relation relation;
1185  HeapScanDesc scan;
1186  HeapTuple tuple;
1187  Oid oldestxid_datoid;
1188  Oid minmulti_datoid;
1189  bool bogus = false;
1190  bool frozenAlreadyWrapped = false;
1191 
1192  /* init oldest datoids to sync with my frozenXID/minMulti values */
1193  oldestxid_datoid = MyDatabaseId;
1194  minmulti_datoid = MyDatabaseId;
1195 
1196  /*
1197  * Scan pg_database to compute the minimum datfrozenxid/datminmxid
1198  *
1199  * Since vac_update_datfrozenxid updates datfrozenxid/datminmxid in-place,
1200  * the values could change while we look at them. Fetch each one just
1201  * once to ensure sane behavior of the comparison logic. (Here, as in
1202  * many other places, we assume that fetching or updating an XID in shared
1203  * storage is atomic.)
1204  *
1205  * Note: we need not worry about a race condition with new entries being
1206  * inserted by CREATE DATABASE. Any such entry will have a copy of some
1207  * existing DB's datfrozenxid, and that source DB cannot be ours because
1208  * of the interlock against copying a DB containing an active backend.
1209  * Hence the new entry will not reduce the minimum. Also, if two VACUUMs
1210  * concurrently modify the datfrozenxid's of different databases, the
1211  * worst possible outcome is that pg_xact is not truncated as aggressively
1212  * as it could be.
1213  */
1215 
1216  scan = heap_beginscan_catalog(relation, 0, NULL);
1217 
1218  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1219  {
1220  volatile FormData_pg_database *dbform = (Form_pg_database) GETSTRUCT(tuple);
1221  TransactionId datfrozenxid = dbform->datfrozenxid;
1222  TransactionId datminmxid = dbform->datminmxid;
1223 
1224  Assert(TransactionIdIsNormal(datfrozenxid));
1225  Assert(MultiXactIdIsValid(datminmxid));
1226 
1227  /*
1228  * If things are working properly, no database should have a
1229  * datfrozenxid or datminmxid that is "in the future". However, such
1230  * cases have been known to arise due to bugs in pg_upgrade. If we
1231  * see any entries that are "in the future", chicken out and don't do
1232  * anything. This ensures we won't truncate clog before those
1233  * databases have been scanned and cleaned up. (We will issue the
1234  * "already wrapped" warning if appropriate, though.)
1235  */
1236  if (TransactionIdPrecedes(lastSaneFrozenXid, datfrozenxid) ||
1237  MultiXactIdPrecedes(lastSaneMinMulti, datminmxid))
1238  bogus = true;
1239 
1240  if (TransactionIdPrecedes(nextXID, datfrozenxid))
1241  frozenAlreadyWrapped = true;
1242  else if (TransactionIdPrecedes(datfrozenxid, frozenXID))
1243  {
1244  frozenXID = datfrozenxid;
1245  oldestxid_datoid = HeapTupleGetOid(tuple);
1246  }
1247 
1248  if (MultiXactIdPrecedes(datminmxid, minMulti))
1249  {
1250  minMulti = datminmxid;
1251  minmulti_datoid = HeapTupleGetOid(tuple);
1252  }
1253  }
1254 
1255  heap_endscan(scan);
1256 
1257  heap_close(relation, AccessShareLock);
1258 
1259  /*
1260  * Do not truncate CLOG if we seem to have suffered wraparound already;
1261  * the computed minimum XID might be bogus. This case should now be
1262  * impossible due to the defenses in GetNewTransactionId, but we keep the
1263  * test anyway.
1264  */
1265  if (frozenAlreadyWrapped)
1266  {
1267  ereport(WARNING,
1268  (errmsg("some databases have not been vacuumed in over 2 billion transactions"),
1269  errdetail("You might have already suffered transaction-wraparound data loss.")));
1270  return;
1271  }
1272 
1273  /* chicken out if data is bogus in any other way */
1274  if (bogus)
1275  return;
1276 
1277  /*
1278  * Advance the oldest value for commit timestamps before truncating, so
1279  * that if a user requests a timestamp for a transaction we're truncating
1280  * away right after this point, they get NULL instead of an ugly "file not
1281  * found" error from slru.c. This doesn't matter for xact/multixact
1282  * because they are not subject to arbitrary lookups from users.
1283  */
1284  AdvanceOldestCommitTsXid(frozenXID);
1285 
1286  /*
1287  * Truncate CLOG, multixact and CommitTs to the oldest computed value.
1288  */
1289  TruncateCLOG(frozenXID, oldestxid_datoid);
1290  TruncateCommitTs(frozenXID);
1291  TruncateMultiXact(minMulti, minmulti_datoid);
1292 
1293  /*
1294  * Update the wrap limit for GetNewTransactionId and creation of new
1295  * MultiXactIds. Note: these functions will also signal the postmaster
1296  * for an(other) autovac cycle if needed. XXX should we avoid possibly
1297  * signalling twice?
1298  */
1299  SetTransactionIdLimit(frozenXID, oldestxid_datoid);
1300  SetMultiXactIdLimit(minMulti, minmulti_datoid, false);
1301 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1565
void TruncateCLOG(TransactionId oldestXact, Oid oldestxid_datoid)
Definition: clog.c:906
uint32 TransactionId
Definition: c.h:445
FormData_pg_database * Form_pg_database
Definition: pg_database.h:57
#define DatabaseRelationId
Definition: pg_database.h:29
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
void AdvanceOldestCommitTsXid(TransactionId oldestXact)
Definition: commit_ts.c:876
int errdetail(const char *fmt,...)
Definition: elog.c:873
TransactionId ReadNewTransactionId(void)
Definition: varsup.c:250
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1405
#define ereport(elevel, rest)
Definition: elog.h:122
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
void TruncateCommitTs(TransactionId oldestXact)
Definition: commit_ts.c:823
#define WARNING
Definition: elog.h:40
Oid MyDatabaseId
Definition: globals.c:77
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1808
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2194
#define Assert(condition)
Definition: c.h:670
void SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
Definition: varsup.c:288
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
int errmsg(const char *fmt,...)
Definition: elog.c:797
FormData_pg_database
Definition: pg_database.h:50
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
void TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
Definition: multixact.c:2933

◆ vac_update_datfrozenxid()

void vac_update_datfrozenxid ( void  )

Definition at line 1014 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, ObjectIdGetDatum, PROCARRAY_FLAGS_VACUUM, 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().

1015 {
1016  HeapTuple tuple;
1017  Form_pg_database dbform;
1018  Relation relation;
1019  SysScanDesc scan;
1020  HeapTuple classTup;
1021  TransactionId newFrozenXid;
1022  MultiXactId newMinMulti;
1023  TransactionId lastSaneFrozenXid;
1024  MultiXactId lastSaneMinMulti;
1025  bool bogus = false;
1026  bool dirty = false;
1027 
1028  /*
1029  * Initialize the "min" calculation with GetOldestXmin, which is a
1030  * reasonable approximation to the minimum relfrozenxid for not-yet-
1031  * committed pg_class entries for new tables; see AddNewRelationTuple().
1032  * So we cannot produce a wrong minimum by starting with this.
1033  */
1034  newFrozenXid = GetOldestXmin(NULL, PROCARRAY_FLAGS_VACUUM);
1035 
1036  /*
1037  * Similarly, initialize the MultiXact "min" with the value that would be
1038  * used on pg_class for new tables. See AddNewRelationTuple().
1039  */
1040  newMinMulti = GetOldestMultiXactId();
1041 
1042  /*
1043  * Identify the latest relfrozenxid and relminmxid values that we could
1044  * validly see during the scan. These are conservative values, but it's
1045  * not really worth trying to be more exact.
1046  */
1047  lastSaneFrozenXid = ReadNewTransactionId();
1048  lastSaneMinMulti = ReadNextMultiXactId();
1049 
1050  /*
1051  * We must seqscan pg_class to find the minimum Xid, because there is no
1052  * index that can help us here.
1053  */
1055 
1056  scan = systable_beginscan(relation, InvalidOid, false,
1057  NULL, 0, NULL);
1058 
1059  while ((classTup = systable_getnext(scan)) != NULL)
1060  {
1061  Form_pg_class classForm = (Form_pg_class) GETSTRUCT(classTup);
1062 
1063  /*
1064  * Only consider relations able to hold unfrozen XIDs (anything else
1065  * should have InvalidTransactionId in relfrozenxid anyway.)
1066  */
1067  if (classForm->relkind != RELKIND_RELATION &&
1068  classForm->relkind != RELKIND_MATVIEW &&
1069  classForm->relkind != RELKIND_TOASTVALUE)
1070  continue;
1071 
1072  Assert(TransactionIdIsNormal(classForm->relfrozenxid));
1073  Assert(MultiXactIdIsValid(classForm->relminmxid));
1074 
1075  /*
1076  * If things are working properly, no relation should have a
1077  * relfrozenxid or relminmxid that is "in the future". However, such
1078  * cases have been known to arise due to bugs in pg_upgrade. If we
1079  * see any entries that are "in the future", chicken out and don't do
1080  * anything. This ensures we won't truncate clog before those
1081  * relations have been scanned and cleaned up.
1082  */
1083  if (TransactionIdPrecedes(lastSaneFrozenXid, classForm->relfrozenxid) ||
1084  MultiXactIdPrecedes(lastSaneMinMulti, classForm->relminmxid))
1085  {
1086  bogus = true;
1087  break;
1088  }
1089 
1090  if (TransactionIdPrecedes(classForm->relfrozenxid, newFrozenXid))
1091  newFrozenXid = classForm->relfrozenxid;
1092 
1093  if (MultiXactIdPrecedes(classForm->relminmxid, newMinMulti))
1094  newMinMulti = classForm->relminmxid;
1095  }
1096 
1097  /* we're done with pg_class */
1098  systable_endscan(scan);
1099  heap_close(relation, AccessShareLock);
1100 
1101  /* chicken out if bogus data found */
1102  if (bogus)
1103  return;
1104 
1105  Assert(TransactionIdIsNormal(newFrozenXid));
1106  Assert(MultiXactIdIsValid(newMinMulti));
1107 
1108  /* Now fetch the pg_database tuple we need to update. */
1110 
1111  /* Fetch a copy of the tuple to scribble on */
1113  if (!HeapTupleIsValid(tuple))
1114  elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
1115  dbform = (Form_pg_database) GETSTRUCT(tuple);
1116 
1117  /*
1118  * As in vac_update_relstats(), we ordinarily don't want to let
1119  * datfrozenxid go backward; but if it's "in the future" then it must be
1120  * corrupt and it seems best to overwrite it.
1121  */
1122  if (dbform->datfrozenxid != newFrozenXid &&
1123  (TransactionIdPrecedes(dbform->datfrozenxid, newFrozenXid) ||
1124  TransactionIdPrecedes(lastSaneFrozenXid, dbform->datfrozenxid)))
1125  {
1126  dbform->datfrozenxid = newFrozenXid;
1127  dirty = true;
1128  }
1129  else
1130  newFrozenXid = dbform->datfrozenxid;
1131 
1132  /* Ditto for datminmxid */
1133  if (dbform->datminmxid != newMinMulti &&
1134  (MultiXactIdPrecedes(dbform->datminmxid, newMinMulti) ||
1135  MultiXactIdPrecedes(lastSaneMinMulti, dbform->datminmxid)))
1136  {
1137  dbform->datminmxid = newMinMulti;
1138  dirty = true;
1139  }
1140  else
1141  newMinMulti = dbform->datminmxid;
1142 
1143  if (dirty)
1144  heap_inplace_update(relation, tuple);
1145 
1146  heap_freetuple(tuple);
1147  heap_close(relation, RowExclusiveLock);
1148 
1149  /*
1150  * If we were able to advance datfrozenxid or datminmxid, see if we can
1151  * truncate pg_xact and/or pg_multixact. Also do it if the shared
1152  * XID-wrap-limit info is stale, since this action will update that too.
1153  */
1154  if (dirty || ForceTransactionIdLimitUpdate())
1155  vac_truncate_clog(newFrozenXid, newMinMulti,
1156  lastSaneFrozenXid, lastSaneMinMulti);
1157 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
uint32 TransactionId
Definition: c.h:445
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:165
#define AccessShareLock
Definition: lockdefs.h:36
#define PROCARRAY_FLAGS_VACUUM
Definition: procarray.h:52
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
bool ForceTransactionIdLimitUpdate(void)
Definition: varsup.c:429
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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:2491
#define RELKIND_TOASTVALUE
Definition: pg_class.h:163
Oid MyDatabaseId
Definition: globals.c:77
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
TransactionId GetOldestXmin(Relation rel, int flags)
Definition: procarray.c:1315
TransactionId MultiXactId
Definition: c.h:455
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:670
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti)
Definition: vacuum.c:1178
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:6248
#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

◆ 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 877 of file vacuum.c.

References elog, ERROR, GETSTRUCT, heap_close, heap_inplace_update(), heap_open(), HeapTupleIsValid, MultiXactIdIsValid, MultiXactIdPrecedes(), 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().

883 {
884  Oid relid = RelationGetRelid(relation);
885  Relation rd;
886  HeapTuple ctup;
887  Form_pg_class pgcform;
888  bool dirty;
889 
891 
892  /* Fetch a copy of the tuple to scribble on */
894  if (!HeapTupleIsValid(ctup))
895  elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
896  relid);
897  pgcform = (Form_pg_class) GETSTRUCT(ctup);
898 
899  /* Apply statistical updates, if any, to copied tuple */
900 
901  dirty = false;
902  if (pgcform->relpages != (int32) num_pages)
903  {
904  pgcform->relpages = (int32) num_pages;
905  dirty = true;
906  }
907  if (pgcform->reltuples != (float4) num_tuples)
908  {
909  pgcform->reltuples = (float4) num_tuples;
910  dirty = true;
911  }
912  if (pgcform->relallvisible != (int32) num_all_visible_pages)
913  {
914  pgcform->relallvisible = (int32) num_all_visible_pages;
915  dirty = true;
916  }
917 
918  /* Apply DDL updates, but not inside an outer transaction (see above) */
919 
920  if (!in_outer_xact)
921  {
922  /*
923  * If we didn't find any indexes, reset relhasindex.
924  */
925  if (pgcform->relhasindex && !hasindex)
926  {
927  pgcform->relhasindex = false;
928  dirty = true;
929  }
930 
931  /*
932  * If we have discovered that there are no indexes, then there's no
933  * primary key either. This could be done more thoroughly...
934  */
935  if (pgcform->relhaspkey && !hasindex)
936  {
937  pgcform->relhaspkey = false;
938  dirty = true;
939  }
940 
941  /* We also clear relhasrules and relhastriggers if needed */
942  if (pgcform->relhasrules && relation->rd_rules == NULL)
943  {
944  pgcform->relhasrules = false;
945  dirty = true;
946  }
947  if (pgcform->relhastriggers && relation->trigdesc == NULL)
948  {
949  pgcform->relhastriggers = false;
950  dirty = true;
951  }
952  }
953 
954  /*
955  * Update relfrozenxid, unless caller passed InvalidTransactionId
956  * indicating it has no new data.
957  *
958  * Ordinarily, we don't let relfrozenxid go backwards: if things are
959  * working correctly, the only way the new frozenxid could be older would
960  * be if a previous VACUUM was done with a tighter freeze_min_age, in
961  * which case we don't want to forget the work it already did. However,
962  * if the stored relfrozenxid is "in the future", then it must be corrupt
963  * and it seems best to overwrite it with the cutoff we used this time.
964  * This should match vac_update_datfrozenxid() concerning what we consider
965  * to be "in the future".
966  */
967  if (TransactionIdIsNormal(frozenxid) &&
968  pgcform->relfrozenxid != frozenxid &&
969  (TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid) ||
971  pgcform->relfrozenxid)))
972  {
973  pgcform->relfrozenxid = frozenxid;
974  dirty = true;
975  }
976 
977  /* Similarly for relminmxid */
978  if (MultiXactIdIsValid(minmulti) &&
979  pgcform->relminmxid != minmulti &&
980  (MultiXactIdPrecedes(pgcform->relminmxid, minmulti) ||
981  MultiXactIdPrecedes(ReadNextMultiXactId(), pgcform->relminmxid)))
982  {
983  pgcform->relminmxid = minmulti;
984  dirty = true;
985  }
986 
987  /* If anything changed, write out the tuple. */
988  if (dirty)
989  heap_inplace_update(rd, ctup);
990 
992 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#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:284
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:120
#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:428
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
RuleLock * rd_rules
Definition: rel.h:118
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
void heap_inplace_update(Relation relation, HeapTuple tuple)
Definition: heapam.c:6248
#define elog
Definition: elog.h:219
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define RelationGetRelid(relation)
Definition: rel.h:425
MultiXactId ReadNextMultiXactId(void)
Definition: multixact.c:721

◆ vacuum()

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

Definition at line 166 of file vacuum.c.

References ActiveSnapshotSet(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), analyze_rel(), Assert, BAS_VACUUM, CommitTransactionCommand(), cur, ereport, errcode(), errmsg(), ERROR, expand_vacuum_rel(), get_all_vacuum_rels(), GetAccessStrategy(), GetTransactionSnapshot(), IsAutoVacuumWorkerProcess(), IsInTransactionChain(), lfirst_node, list_concat(), list_length(), MemoryContextDelete(), MemoryContextSwitchTo(), NIL, VacuumRelation::oid, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgstat_vacuum_stat(), PopActiveSnapshot(), PortalContext, PreventTransactionChain(), PushActiveSnapshot(), VacuumRelation::relation, StartTransactionCommand(), VacuumRelation::va_cols, 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().

168 {
169  static bool in_vacuum = false;
170 
171  const char *stmttype;
172  volatile bool in_outer_xact,
173  use_own_xacts;
174 
175  Assert(params != NULL);
176 
177  stmttype = (options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
178 
179  /*
180  * We cannot run VACUUM inside a user transaction block; if we were inside
181  * a transaction, then our commit- and start-transaction-command calls
182  * would not have the intended effect! There are numerous other subtle
183  * dependencies on this, too.
184  *
185  * ANALYZE (without VACUUM) can run either way.
186  */
187  if (options & VACOPT_VACUUM)
188  {
189  PreventTransactionChain(isTopLevel, stmttype);
190  in_outer_xact = false;
191  }
192  else
193  in_outer_xact = IsInTransactionChain(isTopLevel);
194 
195  /*
196  * Due to static variables vac_context, anl_context and vac_strategy,
197  * vacuum() is not reentrant. This matters when VACUUM FULL or ANALYZE
198  * calls a hostile index expression that itself calls ANALYZE.
199  */
200  if (in_vacuum)
201  ereport(ERROR,
202  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
203  errmsg("%s cannot be executed from VACUUM or ANALYZE",
204  stmttype)));
205 
206  /*
207  * Sanity check DISABLE_PAGE_SKIPPING option.
208  */
209  if ((options & VACOPT_FULL) != 0 &&
211  ereport(ERROR,
212  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
213  errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
214 
215  /*
216  * Send info about dead objects to the statistics collector, unless we are
217  * in autovacuum --- autovacuum.c does this for itself.
218  */
219  if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
221 
222  /*
223  * Create special memory context for cross-transaction storage.
224  *
225  * Since it is a child of PortalContext, it will go away eventually even
226  * if we suffer an error; there's no need for special abort cleanup logic.
227  */
229  "Vacuum",
231 
232  /*
233  * If caller didn't give us a buffer strategy object, make one in the
234  * cross-transaction memory context.
235  */
236  if (bstrategy == NULL)
237  {
239 
240  bstrategy = GetAccessStrategy(BAS_VACUUM);
241  MemoryContextSwitchTo(old_context);
242  }
243  vac_strategy = bstrategy;
244 
245  /*
246  * Build list of relation(s) to process, putting any new data in
247  * vac_context for safekeeping.
248  */
249  if (relations != NIL)
250  {
251  List *newrels = NIL;
252  ListCell *lc;
253 
254  foreach(lc, relations)
255  {
257  List *sublist;
258  MemoryContext old_context;
259 
260  sublist = expand_vacuum_rel(vrel);
261  old_context = MemoryContextSwitchTo(vac_context);
262  newrels = list_concat(newrels, sublist);
263  MemoryContextSwitchTo(old_context);
264  }
265  relations = newrels;
266  }
267  else
268  relations = get_all_vacuum_rels();
269 
270  /*
271  * Decide whether we need to start/commit our own transactions.
272  *
273  * For VACUUM (with or without ANALYZE): always do so, so that we can
274  * release locks as soon as possible. (We could possibly use the outer
275  * transaction for a one-table VACUUM, but handling TOAST tables would be
276  * problematic.)
277  *
278  * For ANALYZE (no VACUUM): if inside a transaction block, we cannot
279  * start/commit our own transactions. Also, there's no need to do so if
280  * only processing one relation. For multiple relations when not within a
281  * transaction block, and also in an autovacuum worker, use own
282  * transactions so we can release locks sooner.
283  */
284  if (options & VACOPT_VACUUM)
285  use_own_xacts = true;
286  else
287  {
290  use_own_xacts = true;
291  else if (in_outer_xact)
292  use_own_xacts = false;
293  else if (list_length(relations) > 1)
294  use_own_xacts = true;
295  else
296  use_own_xacts = false;
297  }
298 
299  /*
300  * vacuum_rel expects to be entered with no transaction active; it will
301  * start and commit its own transaction. But we are called by an SQL
302  * command, and so we are executing inside a transaction already. We
303  * commit the transaction started in PostgresMain() here, and start
304  * another one before exiting to match the commit waiting for us back in
305  * PostgresMain().
306  */
307  if (use_own_xacts)
308  {
309  Assert(!in_outer_xact);
310 
311  /* ActiveSnapshot is not set by autovacuum */
312  if (ActiveSnapshotSet())
314 
315  /* matches the StartTransaction in PostgresMain() */
317  }
318 
319  /* Turn vacuum cost accounting on or off, and set/clear in_vacuum */
320  PG_TRY();
321  {
322  ListCell *cur;
323 
324  in_vacuum = true;
326  VacuumCostBalance = 0;
327  VacuumPageHit = 0;
328  VacuumPageMiss = 0;
329  VacuumPageDirty = 0;
330 
331  /*
332  * Loop to process each selected relation.
333  */
334  foreach(cur, relations)
335  {
337 
338  if (options & VACOPT_VACUUM)
339  {
340  if (!vacuum_rel(vrel->oid, vrel->relation, options, params))
341  continue;
342  }
343 
344  if (options & VACOPT_ANALYZE)
345  {
346  /*
347  * If using separate xacts, start one for analyze. Otherwise,
348  * we can use the outer transaction.
349  */
350  if (use_own_xacts)
351  {
353  /* functions in indexes may want a snapshot set */
355  }
356 
357  analyze_rel(vrel->oid, vrel->relation, options, params,
358  vrel->va_cols, in_outer_xact, vac_strategy);
359 
360  if (use_own_xacts)
361  {
364  }
365  }
366  }
367  }
368  PG_CATCH();
369  {
370  in_vacuum = false;
371  VacuumCostActive = false;
372  PG_RE_THROW();
373  }
374  PG_END_TRY();
375 
376  in_vacuum = false;
377  VacuumCostActive = false;
378 
379  /*
380  * Finish up processing.
381  */
382  if (use_own_xacts)
383  {
384  /* here, we are not in a transaction */
385 
386  /*
387  * This matches the CommitTransaction waiting for us in
388  * PostgresMain().
389  */
391  }
392 
393  if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
394  {
395  /*
396  * Update pg_database.datfrozenxid, and truncate pg_xact if possible.
397  * (autovacuum.c does this for itself.)
398  */
400  }
401 
402  /*
403  * Clean up working storage --- note we must do this after
404  * StartTransactionCommand, else we might be trying to delete the active
405  * context!
406  */
408  vac_context = NULL;
409 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:542
#define NIL
Definition: pg_list.h:69
static List * get_all_vacuum_rels(void)
Definition: vacuum.c:527
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
int VacuumCostBalance
Definition: globals.c:138
RangeVar * relation
Definition: parsenodes.h:3118
void vac_update_datfrozenxid(void)
Definition: vacuum.c:1014
int VacuumPageHit
Definition: globals.c:134
void CommitTransactionCommand(void)
Definition: xact.c:2744
void analyze_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params, List *va_cols, bool in_outer_xact, BufferAccessStrategy bstrategy)
Definition: analyze.c:115
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static BufferAccessStrategy vac_strategy
Definition: vacuum.c:67
struct cursor * cur
Definition: ecpg.c:28
int errcode(int sqlerrcode)
Definition: elog.c:575
List * list_concat(List *list1, List *list2)
Definition: list.c:321
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
MemoryContext PortalContext
Definition: mcxt.c:52
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:170
static List * expand_vacuum_rel(VacuumRelation *vrel)
Definition: vacuum.c:426
#define lfirst_node(type, lc)
Definition: pg_list.h:109
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
static MemoryContext vac_context
Definition: vacuum.c:66
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:851
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3256
#define ereport(elevel, rest)
Definition: elog.h:122
void pgstat_vacuum_stat(void)
Definition: pgstat.c:1022
int VacuumPageDirty
Definition: globals.c:136
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
int VacuumCostDelay
Definition: globals.c:132
#define PG_CATCH()
Definition: elog.h:293
#define Assert(condition)
Definition: c.h:670
static bool vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
Definition: vacuum.c:1324
void StartTransactionCommand(void)
Definition: xact.c:2673
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
void PreventTransactionChain(bool isTopLevel, const char *stmtType)
Definition: xact.c:3153
bool VacuumCostActive
Definition: globals.c:139

◆ vacuum_delay_point()

void vacuum_delay_point ( void  )

Definition at line 1658 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(), ginVacuumPostingTreeLeaves(), gistbulkdelete(), gistvacuumcleanup(), hashbucketcleanup(), lazy_scan_heap(), lazy_vacuum_heap(), spgprocesspending(), and spgvacuumpage().

1659 {
1660  /* Always check for interrupts */
1662 
1663  /* Nap if appropriate */
1666  {
1667  int msec;
1668 
1670  if (msec > VacuumCostDelay * 4)
1671  msec = VacuumCostDelay * 4;
1672 
1673  pg_usleep(msec * 1000L);
1674 
1675  VacuumCostBalance = 0;
1676 
1677  /* update balance values for workers */
1679 
1680  /* Might have gotten an interrupt while sleeping */
1682  }
1683 }
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:1760
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
bool VacuumCostActive
Definition: globals.c:139

◆ vacuum_rel()

static bool vacuum_rel ( Oid  relid,
RangeVar relation,
int  options,
VacuumParams params 
)
static

Definition at line 1324 of file vacuum.c.

References AccessExclusiveLock, Assert, AtEOXact_GUC(), CHECK_FOR_INTERRUPTS, cluster_rel(), CommitTransactionCommand(), ConditionalLockRelationOid(), ereport, errcode(), errmsg(), GetTransactionSnapshot(), GetUserId(), GetUserIdAndSecContext(), InvalidOid, VacuumParams::is_wraparound, IsAutoVacuumWorkerProcess(), lazy_vacuum_rel(), LockRelationIdForSession(), LockInfoData::lockRelId, LOG, VacuumParams::log_min_duration, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyDatabaseId, MyPgXact, NewGUCNestLevel(), NoLock, PG_CATALOG_NAMESPACE, pg_class_ownercheck(), pg_database_ownercheck(), PopActiveSnapshot(), PROC_IN_VACUUM, PROC_VACUUM_FOR_WRAPAROUND, PushActiveSnapshot(), RelationData::rd_lockInfo, RelationData::rd_rel, relation_close(), RELATION_IS_OTHER_TEMP, RelationGetRelationName, RelationGetRelid, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_TOASTVALUE, RangeVar::relname, SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), ShareUpdateExclusiveLock, StartTransactionCommand(), try_relation_open(), UnlockRelationIdForSession(), VACOPT_FULL, VACOPT_NOWAIT, VACOPT_SKIPTOAST, VACOPT_VERBOSE, PGXACT::vacuumFlags, and WARNING.

Referenced by vacuum().

1325 {
1326  LOCKMODE lmode;
1327  Relation onerel;
1328  LockRelId onerelid;
1329  Oid toast_relid;
1330  Oid save_userid;
1331  int save_sec_context;
1332  int save_nestlevel;
1333 
1334  Assert(params != NULL);
1335 
1336  /* Begin a transaction for vacuuming this relation */
1338 
1339  /*
1340  * Functions in indexes may want a snapshot set. Also, setting a snapshot
1341  * ensures that RecentGlobalXmin is kept truly recent.
1342  */
1344 
1345  if (!(options & VACOPT_FULL))
1346  {
1347  /*
1348  * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets
1349  * other concurrent VACUUMs know that they can ignore this one while
1350  * determining their OldestXmin. (The reason we don't set it during a
1351  * full VACUUM is exactly that we may have to run user-defined
1352  * functions for functional indexes, and we want to make sure that if
1353  * they use the snapshot set above, any tuples it requires can't get
1354  * removed from other tables. An index function that depends on the
1355  * contents of other tables is arguably broken, but we won't break it
1356  * here by violating transaction semantics.)
1357  *
1358  * We also set the VACUUM_FOR_WRAPAROUND flag, which is passed down by
1359  * autovacuum; it's used to avoid canceling a vacuum that was invoked
1360  * in an emergency.
1361  *
1362  * Note: these flags remain set until CommitTransaction or
1363  * AbortTransaction. We don't want to clear them until we reset
1364  * MyPgXact->xid/xmin, else OldestXmin might appear to go backwards,
1365  * which is probably Not Good.
1366  */
1367  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
1369  if (params->is_wraparound)
1371  LWLockRelease(ProcArrayLock);
1372  }
1373 
1374  /*
1375  * Check for user-requested abort. Note we want this to be inside a
1376  * transaction, so xact.c doesn't issue useless WARNING.
1377  */
1379 
1380  /*
1381  * Determine the type of lock we want --- hard exclusive lock for a FULL
1382  * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either
1383  * way, we can be sure that no other backend is vacuuming the same table.
1384  */
1386 
1387  /*
1388  * Open the relation and get the appropriate lock on it.
1389  *
1390  * There's a race condition here: the rel may have gone away since the
1391  * last time we saw it. If so, we don't need to vacuum it.
1392  *
1393  * If we've been asked not to wait for the relation lock, acquire it first
1394  * in non-blocking mode, before calling try_relation_open().
1395  */
1396  if (!(options & VACOPT_NOWAIT))
1397  onerel = try_relation_open(relid, lmode);
1398  else if (ConditionalLockRelationOid(relid, lmode))
1399  onerel = try_relation_open(relid, NoLock);
1400  else
1401  {
1402  onerel = NULL;
1403  if (relation &&
1404  IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
1405  ereport(LOG,
1406  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
1407  errmsg("skipping vacuum of \"%s\" --- lock not available",
1408  relation->relname)));
1409  }
1410 
1411  if (!onerel)
1412  {
1415  return false;
1416  }
1417 
1418  /*
1419  * Check permissions.
1420  *
1421  * We allow the user to vacuum a table if he is superuser, the table
1422  * owner, or the database owner (but in the latter case, only if it's not
1423  * a shared relation). pg_class_ownercheck includes the superuser case.
1424  *
1425  * Note we choose to treat permissions failure as a WARNING and keep
1426  * trying to vacuum the rest of the DB --- is this appropriate?
1427  */
1428  if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
1429  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared)))
1430  {
1431  if (onerel->rd_rel->relisshared)
1432  ereport(WARNING,
1433  (errmsg("skipping \"%s\" --- only superuser can vacuum it",
1434  RelationGetRelationName(onerel))));
1435  else if (onerel->rd_rel->relnamespace == PG_CATALOG_NAMESPACE)
1436  ereport(WARNING,
1437  (errmsg("skipping \"%s\" --- only superuser or database owner can vacuum it",
1438  RelationGetRelationName(onerel))));
1439  else
1440  ereport(WARNING,
1441  (errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
1442  RelationGetRelationName(onerel))));
1443  relation_close(onerel, lmode);
1446  return false;
1447  }
1448 
1449  /*
1450  * Check that it's of a vacuumable relkind.
1451  */
1452  if (onerel->rd_rel->relkind != RELKIND_RELATION &&
1453  onerel->rd_rel->relkind != RELKIND_MATVIEW &&
1454  onerel->rd_rel->relkind != RELKIND_TOASTVALUE &&
1455  onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1456  {
1457  ereport(WARNING,
1458  (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
1459  RelationGetRelationName(onerel))));
1460  relation_close(onerel, lmode);
1463  return false;
1464  }
1465 
1466  /*
1467  * Silently ignore tables that are temp tables of other backends ---
1468  * trying to vacuum these will lead to great unhappiness, since their
1469  * contents are probably not up-to-date on disk. (We don't throw a
1470  * warning here; it would just lead to chatter during a database-wide
1471  * VACUUM.)
1472  */
1473  if (RELATION_IS_OTHER_TEMP(onerel))
1474  {
1475  relation_close(onerel, lmode);
1478  return false;
1479  }
1480 
1481  /*
1482  * Silently ignore partitioned tables as there is no work to be done. The
1483  * useful work is on their child partitions, which have been queued up for
1484  * us separately.
1485  */
1486  if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1487  {
1488  relation_close(onerel, lmode);
1491  /* It's OK to proceed with ANALYZE on this table */
1492  return true;
1493  }
1494 
1495  /*
1496  * Get a session-level lock too. This will protect our access to the
1497  * relation across multiple transactions, so that we can vacuum the
1498  * relation's TOAST table (if any) secure in the knowledge that no one is
1499  * deleting the parent relation.
1500  *
1501  * NOTE: this cannot block, even if someone else is waiting for access,
1502  * because the lock manager knows that both lock requests are from the
1503  * same process.
1504  */
1505  onerelid = onerel->rd_lockInfo.lockRelId;
1506  LockRelationIdForSession(&onerelid, lmode);
1507 
1508  /*
1509  * Remember the relation's TOAST relation for later, if the caller asked
1510  * us to process it. In VACUUM FULL, though, the toast table is
1511  * automatically rebuilt by cluster_rel so we shouldn't recurse to it.
1512  */
1513  if (!(options & VACOPT_SKIPTOAST) && !(options & VACOPT_FULL))
1514  toast_relid = onerel->rd_rel->reltoastrelid;
1515  else
1516  toast_relid = InvalidOid;
1517 
1518  /*
1519  * Switch to the table owner's userid, so that any index functions are run
1520  * as that user. Also lock down security-restricted operations and
1521  * arrange to make GUC variable changes local to this command. (This is
1522  * unnecessary, but harmless, for lazy VACUUM.)
1523  */
1524  GetUserIdAndSecContext(&save_userid, &save_sec_context);
1525  SetUserIdAndSecContext(onerel->rd_rel->relowner,
1526  save_sec_context | SECURITY_RESTRICTED_OPERATION);
1527  save_nestlevel = NewGUCNestLevel();
1528 
1529  /*
1530  * Do the actual work --- either FULL or "lazy" vacuum
1531  */
1532  if (options & VACOPT_FULL)
1533  {
1534  /* close relation before vacuuming, but hold lock until commit */
1535  relation_close(onerel, NoLock);
1536  onerel = NULL;
1537 
1538  /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
1539  cluster_rel(relid, InvalidOid, false,
1540  (options & VACOPT_VERBOSE) != 0);
1541  }
1542  else
1543  lazy_vacuum_rel(onerel, options, params, vac_strategy);
1544 
1545  /* Roll back any GUC changes executed by index functions */
1546  AtEOXact_GUC(false, save_nestlevel);
1547 
1548  /* Restore userid and security context */
1549  SetUserIdAndSecContext(save_userid, save_sec_context);
1550 
1551  /* all done with this class, but hold lock until commit */
1552  if (onerel)
1553  relation_close(onerel, NoLock);
1554 
1555  /*
1556  * Complete the transaction and free all temporary memory used.
1557  */
1560 
1561  /*
1562  * If the relation has a secondary toast rel, vacuum that too while we
1563  * still hold the session lock on the master table. Note however that
1564  * "analyze" will not get done on the toast table. This is good, because
1565  * the toaster always uses hardcoded index access and statistics are
1566  * totally unimportant for toast relations.
1567  */
1568  if (toast_relid != InvalidOid)
1569  vacuum_rel(toast_relid, NULL, options, params);
1570 
1571  /*
1572  * Now release the session-level lock on the master table.
1573  */
1574  UnlockRelationIdForSession(&onerelid, lmode);
1575 
1576  /* Report that we really did it. */
1577  return true;
1578 }
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:138
LockRelId lockRelId
Definition: rel.h:44
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:294
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:396
int LOCKMODE
Definition: lockdefs.h:26
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1153
Oid GetUserId(void)
Definition: miscinit.c:284
void CommitTransactionCommand(void)
Definition: xact.c:2744
#define PROC_VACUUM_FOR_WRAPAROUND
Definition: proc.h:56
#define RELKIND_MATVIEW
Definition: pg_class.h:165
static BufferAccessStrategy vac_strategy
Definition: vacuum.c:67
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
#define LOG
Definition: elog.h:26
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
PGXACT * MyPgXact
Definition: proc.c:68
uint8 vacuumFlags
Definition: proc.h:230
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1721
char * relname
Definition: primnodes.h:68
#define PROC_IN_VACUUM
Definition: proc.h:54
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:312
void cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose)
Definition: cluster.c:260
Definition: rel.h:36
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:299
void lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, BufferAccessStrategy bstrategy)
Definition: vacuumlazy.c:182
bool is_wraparound
Definition: vacuum.h:144
#define NoLock
Definition: lockdefs.h:34
LockInfoData rd_lockInfo
Definition: rel.h:117
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:389
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5098
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define PG_CATALOG_NAMESPACE
Definition: pg_namespace.h:71
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3256
#define ereport(elevel, rest)
Definition: elog.h:122
bool pg_database_ownercheck(Oid db_oid, Oid roleid)
Definition: aclchk.c:4964
#define WARNING
Definition: elog.h:40
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define RELKIND_TOASTVALUE
Definition: pg_class.h:163
Oid MyDatabaseId
Definition: globals.c:77
#define InvalidOid
Definition: postgres_ext.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define Assert(condition)
Definition: c.h:670
static bool vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
Definition: vacuum.c:1324
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:542
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4546
void StartTransactionCommand(void)
Definition: xact.c:2673
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1117
int log_min_duration
Definition: vacuum.h:145
#define AccessExclusiveLock
Definition: lockdefs.h:45
int NewGUCNestLevel(void)
Definition: guc.c:5084
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetRelid(relation)
Definition: rel.h:425

◆ 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 593 of file vacuum.c.

References Assert, autovacuum_freeze_max_age, ereport, errhint(), errmsg(), FirstMultiXactId, FirstNormalTransactionId, GetOldestMultiXactId(), GetOldestXmin(), Min, MultiXactIdPrecedes(), MultiXactMemberFreezeThreshold(), PROCARRAY_FLAGS_VACUUM, 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().

603 {
604  int freezemin;
605  int mxid_freezemin;
606  int effective_multixact_freeze_max_age;
607  TransactionId limit;
608  TransactionId safeLimit;
609  MultiXactId mxactLimit;
610  MultiXactId safeMxactLimit;
611 
612  /*
613  * We can always ignore processes running lazy vacuum. This is because we
614  * use these values only for deciding which tuples we must keep in the
615  * tables. Since lazy vacuum doesn't write its XID anywhere, it's safe to
616  * ignore it. In theory it could be problematic to ignore lazy vacuums in
617  * a full vacuum, but keep in mind that only one vacuum process can be
618  * working on a particular table at any time, and that each vacuum is
619  * always an independent transaction.
620  */
621  *oldestXmin =
623 
624  Assert(TransactionIdIsNormal(*oldestXmin));
625 
626  /*
627  * Determine the minimum freeze age to use: as specified by the caller, or
628  * vacuum_freeze_min_age, but in any case not more than half
629  * autovacuum_freeze_max_age, so that autovacuums to prevent XID
630  * wraparound won't occur too frequently.
631  */
632  freezemin = freeze_min_age;
633  if (freezemin < 0)
634  freezemin = vacuum_freeze_min_age;
635  freezemin = Min(freezemin, autovacuum_freeze_max_age / 2);
636  Assert(freezemin >= 0);
637 
638  /*
639  * Compute the cutoff XID, being careful not to generate a "permanent" XID
640  */
641  limit = *oldestXmin - freezemin;
642  if (!TransactionIdIsNormal(limit))
643  limit = FirstNormalTransactionId;
644 
645  /*
646  * If oldestXmin is very far back (in practice, more than
647  * autovacuum_freeze_max_age / 2 XIDs old), complain and force a minimum
648  * freeze age of zero.
649  */
651  if (!TransactionIdIsNormal(safeLimit))
652  safeLimit = FirstNormalTransactionId;
653 
654  if (TransactionIdPrecedes(limit, safeLimit))
655  {
657  (errmsg("oldest xmin is far in the past"),
658  errhint("Close open transactions soon to avoid wraparound problems.")));
659  limit = *oldestXmin;
660  }
661 
662  *freezeLimit = limit;
663 
664  /*
665  * Compute the multixact age for which freezing is urgent. This is
666  * normally autovacuum_multixact_freeze_max_age, but may be less if we are
667  * short of multixact member space.
668  */
669  effective_multixact_freeze_max_age = MultiXactMemberFreezeThreshold();
670 
671  /*
672  * Determine the minimum multixact freeze age to use: as specified by
673  * caller, or vacuum_multixact_freeze_min_age, but in any case not more
674  * than half effective_multixact_freeze_max_age, so that autovacuums to
675  * prevent MultiXact wraparound won't occur too frequently.
676  */
677  mxid_freezemin = multixact_freeze_min_age;
678  if (mxid_freezemin < 0)
679  mxid_freezemin = vacuum_multixact_freeze_min_age;
680  mxid_freezemin = Min(mxid_freezemin,
681  effective_multixact_freeze_max_age / 2);
682  Assert(mxid_freezemin >= 0);
683 
684  /* compute the cutoff multi, being careful to generate a valid value */
685  mxactLimit = GetOldestMultiXactId() - mxid_freezemin;
686  if (mxactLimit < FirstMultiXactId)
687  mxactLimit = FirstMultiXactId;
688 
689  safeMxactLimit =
690  ReadNextMultiXactId() - effective_multixact_freeze_max_age;
691  if (safeMxactLimit < FirstMultiXactId)
692  safeMxactLimit = FirstMultiXactId;
693 
694  if (MultiXactIdPrecedes(mxactLimit, safeMxactLimit))
695  {
697  (errmsg("oldest multixact is far in the past"),
698  errhint("Close open transactions with multixacts soon to avoid wraparound problems.")));
699  mxactLimit = safeMxactLimit;
700  }
701 
702  *multiXactCutoff = mxactLimit;
703 
704  if (xidFullScanLimit != NULL)
705  {
706  int freezetable;
707 
708  Assert(mxactFullScanLimit != NULL);
709 
710  /*
711  * Determine the table freeze age to use: as specified by the caller,
712  * or vacuum_freeze_table_age, but in any case not more than
713  * autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly
714  * VACUUM schedule, the nightly VACUUM gets a chance to freeze tuples
715  * before anti-wraparound autovacuum is launched.
716  */
717  freezetable = freeze_table_age;
718  if (freezetable < 0)
719  freezetable = vacuum_freeze_table_age;
720  freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95);
721  Assert(freezetable >= 0);
722 
723  /*
724  * Compute XID limit causing a full-table vacuum, being careful not to
725  * generate a "permanent" XID.
726  */
727  limit = ReadNewTransactionId() - freezetable;
728  if (!TransactionIdIsNormal(limit))
729  limit = FirstNormalTransactionId;
730 
731  *xidFullScanLimit = limit;
732 
733  /*
734  * Similar to the above, determine the table freeze age to use for
735  * multixacts: as specified by the caller, or
736  * vacuum_multixact_freeze_table_age, but in any case not more than
737  * autovacuum_multixact_freeze_table_age * 0.95, so that if you have
738  * e.g. nightly VACUUM schedule, the nightly VACUUM gets a chance to
739  * freeze multixacts before anti-wraparound autovacuum is launched.
740  */
741  freezetable = multixact_freeze_table_age;
742  if (freezetable < 0)
743  freezetable = vacuum_multixact_freeze_table_age;
744  freezetable = Min(freezetable,
745  effective_multixact_freeze_max_age * 0.95);
746  Assert(freezetable >= 0);
747 
748  /*
749  * Compute MultiXact limit causing a full-table vacuum, being careful
750  * to generate a valid MultiXact value.
751  */
752  mxactLimit = ReadNextMultiXactId() - freezetable;
753  if (mxactLimit < FirstMultiXactId)
754  mxactLimit = FirstMultiXactId;
755 
756  *mxactFullScanLimit = mxactLimit;
757  }
758  else
759  {
760  Assert(mxactFullScanLimit == NULL);
761  }
762 }
int errhint(const char *fmt,...)
Definition: elog.c:987
int vacuum_multixact_freeze_table_age
Definition: vacuum.c:62
uint32 TransactionId
Definition: c.h:445
#define Min(x, y)
Definition: c.h:802
TransactionId TransactionIdLimitedForOldSnapshots(TransactionId recentXmin, Relation relation)
Definition: snapmgr.c:1743
#define PROCARRAY_FLAGS_VACUUM
Definition: procarray.h:52
#define FirstNormalTransactionId
Definition: transam.h:34
int autovacuum_freeze_max_age
Definition: autovacuum.c:122
int vacuum_multixact_freeze_min_age
Definition: vacuum.c:61
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:2817
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define WARNING
Definition: elog.h:40
MultiXactId GetOldestMultiXactId(void)
Definition: multixact.c:2491
TransactionId GetOldestXmin(Relation rel, int flags)
Definition: procarray.c:1315
TransactionId MultiXactId
Definition: c.h:455
#define Assert(condition)
Definition: c.h:670
int vacuum_freeze_min_age
Definition: vacuum.c:59
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
int vacuum_freeze_table_age
Definition: vacuum.c:60
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

◆ vac_context

MemoryContext vac_context = NULL
static

Definition at line 66 of file vacuum.c.

◆ vac_strategy

BufferAccessStrategy vac_strategy
static

Definition at line 67 of file vacuum.c.

◆ vacuum_freeze_min_age

int vacuum_freeze_min_age

Definition at line 59 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 60 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().

◆ vacuum_multixact_freeze_min_age

int vacuum_multixact_freeze_min_age

Definition at line 61 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 62 of file vacuum.c.

Referenced by do_autovacuum(), and vacuum_set_xid_limits().