55 #include "utils/fmgroids.h"
111 bool skip_locked =
false;
115 bool disable_page_skipping =
false;
116 bool process_toast =
true;
132 if (strcmp(opt->
defname,
"verbose") == 0)
134 else if (strcmp(opt->
defname,
"skip_locked") == 0)
138 (
errcode(ERRCODE_SYNTAX_ERROR),
143 else if (strcmp(opt->
defname,
"analyze") == 0)
145 else if (strcmp(opt->
defname,
"freeze") == 0)
147 else if (strcmp(opt->
defname,
"full") == 0)
149 else if (strcmp(opt->
defname,
"disable_page_skipping") == 0)
151 else if (strcmp(opt->
defname,
"index_cleanup") == 0)
167 else if (strcmp(opt->
defname,
"process_toast") == 0)
169 else if (strcmp(opt->
defname,
"truncate") == 0)
171 else if (strcmp(opt->
defname,
"parallel") == 0)
173 if (opt->
arg == NULL)
176 (
errcode(ERRCODE_SYNTAX_ERROR),
177 errmsg(
"parallel option requires a value between 0 and %d",
188 (
errcode(ERRCODE_SYNTAX_ERROR),
189 errmsg(
"parallel workers for vacuum must be between 0 and %d",
205 (
errcode(ERRCODE_SYNTAX_ERROR),
228 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
229 errmsg(
"VACUUM FULL cannot be performed in parallel")));
238 foreach(lc, vacstmt->
rels)
244 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
245 errmsg(
"ANALYZE option must be specified when a column list is provided")));
275 vacuum(vacstmt->
rels, ¶ms, NULL, isTopLevel);
301 static bool in_vacuum =
false;
303 const char *stmttype;
304 volatile bool in_outer_xact,
322 in_outer_xact =
false;
334 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
335 errmsg(
"%s cannot be executed from VACUUM or ANALYZE",
344 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
345 errmsg(
"VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));
351 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
352 errmsg(
"PROCESS_TOAST required with VACUUM FULL")));
368 if (bstrategy == NULL)
381 if (relations !=
NIL)
386 foreach(lc, relations)
417 use_own_xacts =
true;
422 use_own_xacts =
true;
423 else if (in_outer_xact)
424 use_own_xacts =
false;
426 use_own_xacts =
true;
428 use_own_xacts =
false;
469 foreach(
cur, relations)
584 if (reltuple->relisshared)
586 (
errmsg(
"skipping \"%s\" --- only superuser can vacuum it",
588 else if (reltuple->relnamespace == PG_CATALOG_NAMESPACE)
590 (
errmsg(
"skipping \"%s\" --- only superuser or database owner can vacuum it",
594 (
errmsg(
"skipping \"%s\" --- only table or database owner can vacuum it",
607 if (reltuple->relisshared)
609 (
errmsg(
"skipping \"%s\" --- only superuser can analyze it",
611 else if (reltuple->relnamespace == PG_CATALOG_NAMESPACE)
613 (
errmsg(
"skipping \"%s\" --- only superuser or database owner can analyze it",
617 (
errmsg(
"skipping \"%s\" --- only table or database owner can analyze it",
637 bool rel_lock =
true;
674 if (relation == NULL)
695 (
errcode(ERRCODE_LOCK_NOT_AVAILABLE),
696 errmsg(
"skipping vacuum of \"%s\" --- lock not available",
701 errmsg(
"skipping vacuum of \"%s\" --- relation no longer exists",
716 (
errcode(ERRCODE_LOCK_NOT_AVAILABLE),
717 errmsg(
"skipping analyze of \"%s\" --- lock not available",
722 errmsg(
"skipping analyze of \"%s\" --- relation no longer exists",
754 vacrels =
lappend(vacrels, vrel);
791 (
errcode(ERRCODE_LOCK_NOT_AVAILABLE),
792 errmsg(
"skipping vacuum of \"%s\" --- lock not available",
796 (
errcode(ERRCODE_LOCK_NOT_AVAILABLE),
797 errmsg(
"skipping analyze of \"%s\" --- lock not available",
808 elog(
ERROR,
"cache lookup failed for relation %u", relid);
825 include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
842 foreach(part_lc, part_oids)
846 if (part_oid == relid)
899 Oid relid = classForm->oid;
910 if (classForm->relkind != RELKIND_RELATION &&
911 classForm->relkind != RELKIND_MATVIEW &&
912 classForm->relkind != RELKIND_PARTITIONED_TABLE)
961 int freeze_table_age,
962 int multixact_freeze_min_age,
963 int multixact_freeze_table_age,
971 int effective_multixact_freeze_max_age;
995 &limit_xmin, &limit_ts))
1004 *oldestXmin = limit_xmin;
1016 freezemin = freeze_min_age;
1025 limit = *oldestXmin - freezemin;
1041 (
errmsg(
"oldest xmin is far in the past"),
1042 errhint(
"Close open transactions soon to avoid wraparound problems.\n"
1043 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1044 limit = *oldestXmin;
1047 *freezeLimit = limit;
1062 mxid_freezemin = multixact_freeze_min_age;
1063 if (mxid_freezemin < 0)
1065 mxid_freezemin =
Min(mxid_freezemin,
1066 effective_multixact_freeze_max_age / 2);
1067 Assert(mxid_freezemin >= 0);
1073 mxactLimit = *oldestMxact - mxid_freezemin;
1085 (
errmsg(
"oldest multixact is far in the past"),
1086 errhint(
"Close open transactions with multixacts soon to avoid wraparound problems.")));
1089 mxactLimit = *oldestMxact;
1091 mxactLimit = safeMxactLimit;
1094 *multiXactCutoff = mxactLimit;
1106 freezetable = freeze_table_age;
1107 if (freezetable < 0)
1110 Assert(freezetable >= 0);
1131 freezetable = multixact_freeze_table_age;
1132 if (freezetable < 0)
1134 freezetable =
Min(freezetable,
1135 effective_multixact_freeze_max_age * 0.95);
1136 Assert(freezetable >= 0);
1166 int skip_index_vacuum;
1225 double scanned_tuples)
1228 double old_rel_tuples = relation->
rd_rel->reltuples;
1230 double unscanned_pages;
1231 double total_tuples;
1234 if (scanned_pages >= total_pages)
1235 return scanned_tuples;
1241 if (scanned_pages == 0)
1242 return old_rel_tuples;
1259 if (old_rel_pages == total_pages &&
1260 scanned_pages < (
double) total_pages * 0.02)
1261 return old_rel_tuples;
1267 if (old_rel_tuples < 0 || old_rel_pages == 0)
1268 return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
1276 old_density = old_rel_tuples / old_rel_pages;
1277 unscanned_pages = (double) total_pages - (
double) scanned_pages;
1278 total_tuples = old_density * unscanned_pages + scanned_tuples;
1279 return floor(total_tuples + 0.5);
1329 bool *frozenxid_updated,
bool *minmulti_updated,
1347 elog(
ERROR,
"pg_class entry for relid %u vanished during vacuuming",
1354 if (pgcform->relpages != (
int32) num_pages)
1356 pgcform->relpages = (
int32) num_pages;
1359 if (pgcform->reltuples != (
float4) num_tuples)
1361 pgcform->reltuples = (
float4) num_tuples;
1364 if (pgcform->relallvisible != (
int32) num_all_visible_pages)
1366 pgcform->relallvisible = (
int32) num_all_visible_pages;
1377 if (pgcform->relhasindex && !hasindex)
1379 pgcform->relhasindex =
false;
1384 if (pgcform->relhasrules && relation->
rd_rules == NULL)
1386 pgcform->relhasrules =
false;
1389 if (pgcform->relhastriggers && relation->
trigdesc == NULL)
1391 pgcform->relhastriggers =
false;
1406 oldfrozenxid = pgcform->relfrozenxid;
1408 if (frozenxid_updated)
1409 *frozenxid_updated =
false;
1412 bool update =
false;
1417 futurexid = update =
true;
1421 pgcform->relfrozenxid = frozenxid;
1423 if (frozenxid_updated)
1424 *frozenxid_updated =
true;
1429 oldminmulti = pgcform->relminmxid;
1431 if (minmulti_updated)
1432 *minmulti_updated =
false;
1435 bool update =
false;
1440 futuremxid = update =
true;
1444 pgcform->relminmxid = minmulti;
1446 if (minmulti_updated)
1447 *minmulti_updated =
true;
1460 errmsg_internal(
"overwrote invalid relfrozenxid value %u with new value %u for table \"%s\"",
1461 oldfrozenxid, frozenxid,
1466 errmsg_internal(
"overwrote invalid relminmxid value %u with new value %u for table \"%s\"",
1467 oldminmulti, minmulti,
1554 if (classForm->relkind != RELKIND_RELATION &&
1555 classForm->relkind != RELKIND_MATVIEW &&
1556 classForm->relkind != RELKIND_TOASTVALUE)
1591 newFrozenXid = classForm->relfrozenxid;
1605 newMinMulti = classForm->relminmxid;
1629 Anum_pg_database_oid,
1649 if (dbform->datfrozenxid != newFrozenXid &&
1653 dbform->datfrozenxid = newFrozenXid;
1657 newFrozenXid = dbform->datfrozenxid;
1660 if (dbform->datminmxid != newMinMulti &&
1664 dbform->datminmxid = newMinMulti;
1668 newMinMulti = dbform->datminmxid;
1683 lastSaneFrozenXid, lastSaneMinMulti);
1714 Oid oldestxid_datoid;
1715 Oid minmulti_datoid;
1717 bool frozenAlreadyWrapped =
false;
1771 frozenAlreadyWrapped =
true;
1775 oldestxid_datoid = dbform->oid;
1781 minmulti_datoid = dbform->oid;
1795 if (frozenAlreadyWrapped)
1798 (
errmsg(
"some databases have not been vacuumed in over 2 billion transactions"),
1799 errdetail(
"You might have already suffered transaction-wraparound data loss.")));
1863 int save_sec_context;
1957 if (rel->
rd_rel->relkind != RELKIND_RELATION &&
1958 rel->
rd_rel->relkind != RELKIND_MATVIEW &&
1959 rel->
rd_rel->relkind != RELKIND_TOASTVALUE &&
1960 rel->
rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1963 (
errmsg(
"skipping \"%s\" --- cannot vacuum non-tables or special system tables",
1991 if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2024 vacuum_index_cleanup =
2033 Assert(vacuum_index_cleanup ==
2059 toast_relid = rel->
rd_rel->reltoastrelid;
2164 foreach(indexoidscan, indexoidlist)
2171 (*Irel)[
i++] = indrel;
2331 (
void *) dead_items);
2334 (
errmsg(
"scanned index \"%s\" to remove %d row versions",
2353 (
errmsg(
"index \"%s\" now contains %.0f row versions in %u pages",
2357 errdetail(
"%.0f index row versions were removed.\n"
2358 "%u index pages were newly deleted.\n"
2359 "%u index pages are currently deleted, of which %u are currently reusable.",
2405 if (item < litem || item > ritem)
2409 (
void *) dead_items->
items,
2414 return (
res != NULL);
bool pg_database_ownercheck(Oid db_oid, Oid roleid)
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
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
#define offsetof(type, field)
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
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)
#define ItemPointerGetBlockNumber(pointer)
ItemPointerData * ItemPointer
struct ItemPointerData ItemPointerData
#define ItemPointerGetOffsetNumber(pointer)
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)
#define ObjectIdGetDatum(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)
bool ActiveSnapshotSet(void)
bool TransactionIdLimitedForOldSnapshots(TransactionId recentXmin, Relation relation, TransactionId *limit_xid, TimestampTz *limit_ts)
void PopActiveSnapshot(void)
void PushActiveSnapshot(Snapshot snap)
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]
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 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
bool vacuum_xid_failsafe_check(TransactionId relfrozenxid, MultiXactId relminmxid)
static BufferAccessStrategy vac_strategy
int vacuum_freeze_table_age
static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
int vacuum_multixact_failsafe_age
bool 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, MultiXactId *oldestMxact, TransactionId *freezeLimit, MultiXactId *multiXactCutoff)
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)
bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, bits32 options)
void vac_update_datfrozenxid(void)
pg_atomic_uint32 * VacuumSharedCostBalance
double vac_estimate_reltuples(Relation relation, BlockNumber total_pages, BlockNumber scanned_pages, double scanned_tuples)
IndexBulkDeleteResult * vac_cleanup_one_index(IndexVacuumInfo *ivinfo, IndexBulkDeleteResult *istat)
static int vac_cmp_itemptr(const void *left, const void *right)
#define VACOPT_SKIP_LOCKED
#define MAXDEADITEMS(avail_mem)
@ VACOPTVALUE_UNSPECIFIED
#define VACOPT_PROCESS_TOAST
#define VACOPT_DISABLE_PAGE_SKIPPING
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)