56 #include "utils/fmgroids.h"
113 bool skip_locked =
false;
117 bool disable_page_skipping =
false;
118 bool process_toast =
true;
119 bool skip_database_stats =
false;
120 bool only_database_stats =
false;
136 if (strcmp(opt->
defname,
"verbose") == 0)
138 else if (strcmp(opt->
defname,
"skip_locked") == 0)
142 (
errcode(ERRCODE_SYNTAX_ERROR),
147 else if (strcmp(opt->
defname,
"analyze") == 0)
149 else if (strcmp(opt->
defname,
"freeze") == 0)
151 else if (strcmp(opt->
defname,
"full") == 0)
153 else if (strcmp(opt->
defname,
"disable_page_skipping") == 0)
155 else if (strcmp(opt->
defname,
"index_cleanup") == 0)
171 else if (strcmp(opt->
defname,
"process_toast") == 0)
173 else if (strcmp(opt->
defname,
"truncate") == 0)
175 else if (strcmp(opt->
defname,
"parallel") == 0)
177 if (opt->
arg == NULL)
180 (
errcode(ERRCODE_SYNTAX_ERROR),
181 errmsg(
"parallel option requires a value between 0 and %d",
192 (
errcode(ERRCODE_SYNTAX_ERROR),
193 errmsg(
"parallel workers for vacuum must be between 0 and %d",
207 else if (strcmp(opt->
defname,
"skip_database_stats") == 0)
209 else if (strcmp(opt->
defname,
"only_database_stats") == 0)
213 (
errcode(ERRCODE_SYNTAX_ERROR),
238 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
239 errmsg(
"VACUUM FULL cannot be performed in parallel")));
246 foreach(lc, vacstmt->
rels)
252 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
253 errmsg(
"ANALYZE option must be specified when a column list is provided")));
283 vacuum(vacstmt->
rels, ¶ms, NULL, isTopLevel);
309 static bool in_vacuum =
false;
311 const char *stmttype;
312 volatile bool in_outer_xact,
330 in_outer_xact =
false;
342 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
343 errmsg(
"%s cannot be executed from VACUUM or ANALYZE",
352 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
353 errmsg(
"VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
359 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
360 errmsg(
"PROCESS_TOAST required with VACUUM FULL")));
366 if (relations !=
NIL)
368 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
369 errmsg(
"ONLY_DATABASE_STATS cannot be specified with a list of tables")));
376 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
377 errmsg(
"ONLY_DATABASE_STATS cannot be specified with other VACUUM options")));
394 if (bstrategy == NULL)
412 else if (relations !=
NIL)
417 foreach(lc, relations)
448 use_own_xacts =
true;
453 use_own_xacts =
true;
454 else if (in_outer_xact)
455 use_own_xacts =
false;
457 use_own_xacts =
true;
459 use_own_xacts =
false;
500 foreach(
cur, relations)
617 (
errmsg(
"permission denied to vacuum \"%s\", skipping it",
630 (
errmsg(
"permission denied to analyze \"%s\", skipping it",
649 bool rel_lock =
true;
686 if (relation == NULL)
707 (
errcode(ERRCODE_LOCK_NOT_AVAILABLE),
708 errmsg(
"skipping vacuum of \"%s\" --- lock not available",
713 errmsg(
"skipping vacuum of \"%s\" --- relation no longer exists",
728 (
errcode(ERRCODE_LOCK_NOT_AVAILABLE),
729 errmsg(
"skipping analyze of \"%s\" --- lock not available",
734 errmsg(
"skipping analyze of \"%s\" --- relation no longer exists",
766 vacrels =
lappend(vacrels, vrel);
803 (
errcode(ERRCODE_LOCK_NOT_AVAILABLE),
804 errmsg(
"skipping vacuum of \"%s\" --- lock not available",
808 (
errcode(ERRCODE_LOCK_NOT_AVAILABLE),
809 errmsg(
"skipping analyze of \"%s\" --- lock not available",
820 elog(
ERROR,
"cache lookup failed for relation %u", relid);
837 include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
854 foreach(part_lc, part_oids)
858 if (part_oid == relid)
911 Oid relid = classForm->oid;
918 if (classForm->relkind != RELKIND_RELATION &&
919 classForm->relkind != RELKIND_MATVIEW &&
920 classForm->relkind != RELKIND_PARTITIONED_TABLE)
962 multixact_freeze_min_age,
964 multixact_freeze_table_age,
965 effective_multixact_freeze_max_age;
971 aggressiveMXIDCutoff;
1002 &limit_xmin, &limit_ts))
1039 safeOldestMxact = nextMXID - effective_multixact_freeze_max_age;
1044 (
errmsg(
"cutoff for removing and freezing tuples is far in the past"),
1045 errhint(
"Close open transactions soon to avoid wraparound problems.\n"
1046 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1049 (
errmsg(
"cutoff for freezing multixacts is far in the past"),
1050 errhint(
"Close open transactions soon to avoid wraparound problems.\n"
1051 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1059 if (freeze_min_age < 0)
1062 Assert(freeze_min_age >= 0);
1078 if (multixact_freeze_min_age < 0)
1080 multixact_freeze_min_age =
Min(multixact_freeze_min_age,
1081 effective_multixact_freeze_max_age / 2);
1082 Assert(multixact_freeze_min_age >= 0);
1101 if (freeze_table_age < 0)
1104 Assert(freeze_table_age >= 0);
1105 aggressiveXIDCutoff = nextXID - freeze_table_age;
1109 aggressiveXIDCutoff))
1120 if (multixact_freeze_table_age < 0)
1122 multixact_freeze_table_age =
1123 Min(multixact_freeze_table_age,
1124 effective_multixact_freeze_max_age * 0.95);
1125 Assert(multixact_freeze_table_age >= 0);
1126 aggressiveMXIDCutoff = nextMXID - multixact_freeze_table_age;
1130 aggressiveMXIDCutoff))
1151 int skip_index_vacuum;
1210 double scanned_tuples)
1213 double old_rel_tuples = relation->
rd_rel->reltuples;
1215 double unscanned_pages;
1216 double total_tuples;
1219 if (scanned_pages >= total_pages)
1220 return scanned_tuples;
1236 if (old_rel_pages == total_pages &&
1237 scanned_pages < (
double) total_pages * 0.02)
1238 return old_rel_tuples;
1239 if (scanned_pages <= 1)
1240 return old_rel_tuples;
1246 if (old_rel_tuples < 0 || old_rel_pages == 0)
1247 return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
1255 old_density = old_rel_tuples / old_rel_pages;
1256 unscanned_pages = (double) total_pages - (
double) scanned_pages;
1257 total_tuples = old_density * unscanned_pages + scanned_tuples;
1258 return floor(total_tuples + 0.5);
1308 bool *frozenxid_updated,
bool *minmulti_updated,
1326 elog(
ERROR,
"pg_class entry for relid %u vanished during vacuuming",
1333 if (pgcform->relpages != (
int32) num_pages)
1335 pgcform->relpages = (
int32) num_pages;
1338 if (pgcform->reltuples != (
float4) num_tuples)
1340 pgcform->reltuples = (
float4) num_tuples;
1343 if (pgcform->relallvisible != (
int32) num_all_visible_pages)
1345 pgcform->relallvisible = (
int32) num_all_visible_pages;
1356 if (pgcform->relhasindex && !hasindex)
1358 pgcform->relhasindex =
false;
1363 if (pgcform->relhasrules && relation->
rd_rules == NULL)
1365 pgcform->relhasrules =
false;
1368 if (pgcform->relhastriggers && relation->
trigdesc == NULL)
1370 pgcform->relhastriggers =
false;
1385 oldfrozenxid = pgcform->relfrozenxid;
1387 if (frozenxid_updated)
1388 *frozenxid_updated =
false;
1391 bool update =
false;
1396 futurexid = update =
true;
1400 pgcform->relfrozenxid = frozenxid;
1402 if (frozenxid_updated)
1403 *frozenxid_updated =
true;
1408 oldminmulti = pgcform->relminmxid;
1410 if (minmulti_updated)
1411 *minmulti_updated =
false;
1414 bool update =
false;
1419 futuremxid = update =
true;
1423 pgcform->relminmxid = minmulti;
1425 if (minmulti_updated)
1426 *minmulti_updated =
true;
1439 errmsg_internal(
"overwrote invalid relfrozenxid value %u with new value %u for table \"%s\"",
1440 oldfrozenxid, frozenxid,
1445 errmsg_internal(
"overwrote invalid relminmxid value %u with new value %u for table \"%s\"",
1446 oldminmulti, minmulti,
1533 if (classForm->relkind != RELKIND_RELATION &&
1534 classForm->relkind != RELKIND_MATVIEW &&
1535 classForm->relkind != RELKIND_TOASTVALUE)
1570 newFrozenXid = classForm->relfrozenxid;
1584 newMinMulti = classForm->relminmxid;
1608 Anum_pg_database_oid,
1628 if (dbform->datfrozenxid != newFrozenXid &&
1632 dbform->datfrozenxid = newFrozenXid;
1636 newFrozenXid = dbform->datfrozenxid;
1639 if (dbform->datminmxid != newMinMulti &&
1643 dbform->datminmxid = newMinMulti;
1647 newMinMulti = dbform->datminmxid;
1662 lastSaneFrozenXid, lastSaneMinMulti);
1693 Oid oldestxid_datoid;
1694 Oid minmulti_datoid;
1696 bool frozenAlreadyWrapped =
false;
1750 frozenAlreadyWrapped =
true;
1754 oldestxid_datoid = dbform->oid;
1760 minmulti_datoid = dbform->oid;
1774 if (frozenAlreadyWrapped)
1777 (
errmsg(
"some databases have not been vacuumed in over 2 billion transactions"),
1778 errdetail(
"You might have already suffered transaction-wraparound data loss.")));
1842 int save_sec_context;
1936 if (rel->
rd_rel->relkind != RELKIND_RELATION &&
1937 rel->
rd_rel->relkind != RELKIND_MATVIEW &&
1938 rel->
rd_rel->relkind != RELKIND_TOASTVALUE &&
1939 rel->
rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1942 (
errmsg(
"skipping \"%s\" --- cannot vacuum non-tables or special system tables",
1970 if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2003 vacuum_index_cleanup =
2012 Assert(vacuum_index_cleanup ==
2038 toast_relid = rel->
rd_rel->reltoastrelid;
2143 foreach(indexoidscan, indexoidlist)
2150 (*Irel)[
i++] = indrel;
2310 (
void *) dead_items);
2313 (
errmsg(
"scanned index \"%s\" to remove %d row versions",
2332 (
errmsg(
"index \"%s\" now contains %.0f row versions in %u pages",
2336 errdetail(
"%.0f index row versions were removed.\n"
2337 "%u index pages were newly deleted.\n"
2338 "%u index pages are currently deleted, of which %u are currently reusable.",
2384 if (item < litem || item > ritem)
2388 (
void *) dead_items->
items,
2393 return (
res != NULL);
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
static uint32 pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
static uint32 pg_atomic_add_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
void AutoVacuumUpdateDelay(void)
int autovacuum_multixact_freeze_max_age
int autovacuum_freeze_max_age
bool IsAutoVacuumWorkerProcess(void)
#define MAX_PARALLEL_WORKER_LIMIT
TransactionId MultiXactId
#define OidIsValid(objectId)
void TruncateCLOG(TransactionId oldestXact, Oid oldestxid_datoid)
void cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params)
void analyze_rel(Oid relid, RangeVar *relation, VacuumParams *params, List *va_cols, bool in_outer_xact, BufferAccessStrategy bstrategy)
void AdvanceOldestCommitTsXid(TransactionId oldestXact)
void TruncateCommitTs(TransactionId oldestXact)
static void PGresult * res
elog(ERROR, "%s: %s", p2, msg)
int32 defGetInt32(DefElem *def)
bool defGetBoolean(DefElem *def)
char * defGetString(DefElem *def)
int errmsg_internal(const char *fmt,...)
int errdetail(const char *fmt,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
void systable_endscan(SysScanDesc sysscan)
HeapTuple systable_getnext(SysScanDesc sysscan)
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
volatile sig_atomic_t InterruptPending
int NewGUCNestLevel(void)
void AtEOXact_GUC(bool isCommit, int nestLevel)
void heap_inplace_update(Relation relation, HeapTuple tuple)
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
HeapTuple heap_copytuple(HeapTuple tuple)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
static int64 itemptr_encode(ItemPointer itemptr)
IndexBulkDeleteResult * index_vacuum_cleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *istat)
void index_close(Relation relation, LOCKMODE lockmode)
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *istat, IndexBulkDeleteCallback callback, void *callback_state)
Relation index_open(Oid relationId, LOCKMODE lockmode)
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
ItemPointerData * ItemPointer
struct ItemPointerData ItemPointerData
void ResetLatch(Latch *latch)
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
#define WL_EXIT_ON_PM_DEATH
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
void list_free(List *list)
List * list_concat(List *list1, const List *list2)
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
void LockDatabaseFrozenIds(LOCKMODE lockmode)
#define AccessExclusiveLock
#define ShareUpdateExclusiveLock
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void LWLockRelease(LWLock *lock)
VacuumRelation * makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols)
void pfree(void *pointer)
void MemoryContextDelete(MemoryContext context)
MemoryContext PortalContext
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define SECURITY_RESTRICTED_OPERATION
#define CHECK_FOR_INTERRUPTS()
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
void SetUserIdAndSecContext(Oid userid, int sec_context)
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
MultiXactId GetOldestMultiXactId(void)
int MultiXactMemberFreezeThreshold(void)
MultiXactId ReadNextMultiXactId(void)
void TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
#define MultiXactIdIsValid(multi)
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
int parser_errposition(ParseState *pstate, int location)
#define ERRCODE_DATA_CORRUPTED
FormData_pg_class * Form_pg_class
TransactionId datfrozenxid
FormData_pg_database * Form_pg_database
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
#define lfirst_node(type, lc)
static int list_length(const List *l)
#define ERRCODE_UNDEFINED_TABLE
int pg_strcasecmp(const char *s1, const char *s2)
static Datum ObjectIdGetDatum(Oid X)
#define PROC_VACUUM_FOR_WRAPAROUND
TransactionId GetOldestNonRemovableTransactionId(Relation rel)
static long analyze(struct nfa *nfa)
#define RelationGetRelid(relation)
#define RelationGetRelationName(relation)
#define RELATION_IS_OTHER_TEMP(relation)
@ STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO
@ STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF
@ STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON
List * RelationGetIndexList(Relation relation)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Snapshot GetTransactionSnapshot(void)
void PushActiveSnapshot(Snapshot snapshot)
bool ActiveSnapshotSet(void)
bool TransactionIdLimitedForOldSnapshots(TransactionId recentXmin, Relation relation, TransactionId *limit_xid, TimestampTz *limit_ts)
void PopActiveSnapshot(void)
void SetOldSnapshotThresholdTimestamp(TimestampTz ts, TransactionId xlimit)
static bool OldSnapshotThresholdActive(void)
void relation_close(Relation relation, LOCKMODE lockmode)
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
#define BTEqualStrategyNumber
BlockNumber pages_deleted
BlockNumber pages_newly_deleted
ItemPointerData items[FLEXIBLE_ARRAY_MEMBER]
TransactionId FreezeLimit
TransactionId relfrozenxid
MultiXactId MultiXactCutoff
int multixact_freeze_min_age
int multixact_freeze_table_age
VacOptValue index_cleanup
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define SearchSysCacheCopy1(cacheId, key1)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
static void table_endscan(TableScanDesc scan)
static void table_relation_vacuum(Relation rel, struct VacuumParams *params, BufferAccessStrategy bstrategy)
bool has_partition_ancestor_privs(Oid relid, Oid userid, AclMode acl)
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
static TransactionId ReadNextTransactionId(void)
#define FirstNormalTransactionId
#define TransactionIdIsValid(xid)
#define TransactionIdIsNormal(xid)
static bool vac_tid_reaped(ItemPointer itemptr, void *state)
IndexBulkDeleteResult * vac_bulkdel_one_index(IndexVacuumInfo *ivinfo, IndexBulkDeleteResult *istat, VacDeadItems *dead_items)
void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
static List * get_all_vacuum_rels(int options)
pg_atomic_uint32 * VacuumActiveNWorkers
static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti)
Size vac_max_items_to_alloc_size(int max_items)
static MemoryContext vac_context
int vacuum_freeze_min_age
static List * expand_vacuum_rel(VacuumRelation *vrel, int options)
static double compute_parallel_delay(void)
static VacOptValue get_vacoptval_from_boolean(DefElem *def)
void vac_open_indexes(Relation relation, LOCKMODE lockmode, int *nindexes, Relation **Irel)
int VacuumCostBalanceLocal
void vac_update_relstats(Relation relation, BlockNumber num_pages, double num_tuples, BlockNumber num_all_visible_pages, bool hasindex, TransactionId frozenxid, MultiXactId minmulti, bool *frozenxid_updated, bool *minmulti_updated, bool in_outer_xact)
void vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel)
int vacuum_multixact_freeze_table_age
static BufferAccessStrategy vac_strategy
int vacuum_freeze_table_age
int vacuum_multixact_failsafe_age
int vacuum_multixact_freeze_min_age
Relation vacuum_open_relation(Oid relid, RangeVar *relation, bits32 options, bool verbose, LOCKMODE lmode)
void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode)
void vacuum_delay_point(void)
void vac_update_datfrozenxid(void)
bool vacuum_get_cutoffs(Relation rel, const VacuumParams *params, struct VacuumCutoffs *cutoffs)
bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs)
pg_atomic_uint32 * VacuumSharedCostBalance
double vac_estimate_reltuples(Relation relation, BlockNumber total_pages, BlockNumber scanned_pages, double scanned_tuples)
static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params, bool skip_privs)
IndexBulkDeleteResult * vac_cleanup_one_index(IndexVacuumInfo *ivinfo, IndexBulkDeleteResult *istat)
static int vac_cmp_itemptr(const void *left, const void *right)
bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple, bits32 options)
#define VACOPT_SKIP_LOCKED
#define MAXDEADITEMS(avail_mem)
#define VACOPT_SKIP_DATABASE_STATS
@ VACOPTVALUE_UNSPECIFIED
#define VACOPT_PROCESS_TOAST
#define VACOPT_DISABLE_PAGE_SKIPPING
#define VACOPT_ONLY_DATABASE_STATS
void SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
bool ForceTransactionIdLimitUpdate(void)
@ WAIT_EVENT_VACUUM_DELAY
bool IsInTransactionBlock(bool isTopLevel)
void CommandCounterIncrement(void)
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
void StartTransactionCommand(void)
void CommitTransactionCommand(void)