100 #include "utils/fmgroids.h"
101 #include "utils/fmgrprotos.h"
135 #define MIN_AUTOVAC_SLEEPTIME 100.0
136 #define MAX_AUTOVAC_SLEEPTIME 300
263 #define NUM_WORKITEMS 256
307 static pid_t avlauncher_forkexec(
void);
308 static pid_t avworker_forkexec(
void);
317 struct timeval *nap);
329 int effective_multixact_freeze_max_age);
332 int effective_multixact_freeze_max_age,
333 bool *dovacuum,
bool *doanalyze,
bool *wraparound);
337 int effective_multixact_freeze_max_age,
338 bool *dovacuum,
bool *doanalyze,
bool *wraparound);
347 const char *nspname,
const char *
relname);
363 avlauncher_forkexec(
void)
368 av[ac++] =
"postgres";
369 av[ac++] =
"--forkavlauncher";
375 return postmaster_forkexec(ac,
av);
382 AutovacuumLauncherIAm(
void)
405 (
errmsg(
"could not fork autovacuum launcher process: %m")));
433 sigjmp_buf local_sigjmp_buf;
489 "Autovacuum Launcher",
505 if (sigsetjmp(local_sigjmp_buf, 1) != 0)
654 (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
753 errmsg(
"autovacuum worker took too long to start; canceled"));
891 nap->tv_usec = usecs;
910 if (nap->tv_sec == 0 && nap->tv_usec == 0 && !recursing)
962 "Autovacuum database list",
965 "Autovacuum database list (tmp)",
988 dbhash =
hash_create(
"autovacuum db hash", 20, &hctl,
1070 int millis_increment;
1082 memcpy(&(dbary[
i++]), db,
sizeof(
avl_dbase));
1104 for (
i = 0;
i < nelems;
i++)
1154 bool for_multi_wrap;
1157 bool skipit =
false;
1176 "Autovacuum start worker (tmp)",
1223 for_xid_wrap =
false;
1224 for_multi_wrap =
false;
1238 for_xid_wrap =
true;
1241 else if (for_xid_wrap)
1248 for_multi_wrap =
true;
1251 else if (for_multi_wrap)
1420 int save_errno = errno;
1440 avworker_forkexec(
void)
1445 av[ac++] =
"postgres";
1446 av[ac++] =
"--forkavworker";
1452 return postmaster_forkexec(ac,
av);
1459 AutovacuumWorkerIAm(
void)
1476 switch ((worker_pid = avworker_forkexec()))
1483 (
errmsg(
"could not fork autovacuum worker process: %m")));
1486 #ifndef EXEC_BACKEND
1498 return (
int) worker_pid;
1511 sigjmp_buf local_sigjmp_buf;
1550 #ifndef EXEC_BACKEND
1570 if (sigsetjmp(local_sigjmp_buf, 1) != 0)
1678 elog(
WARNING,
"autovacuum worker started without a worker entry");
1816 if (vac_cost_limit <= 0 || vac_cost_delay <= 0)
1825 if (worker->
wi_proc != NULL &&
1833 if (cost_total <= 0)
1840 cost_avail = (double) vac_cost_limit / vac_cost_delay;
1845 if (worker->
wi_proc != NULL &&
1864 elog(
DEBUG2,
"autovac_balance_cost(pid=%d db=%u, rel=%u, dobalance=%s cost_limit=%d, cost_limit_base=%d, cost_delay=%g)",
1967 HTAB *table_toast_map;
1972 int effective_multixact_freeze_max_age;
1973 bool did_vacuum =
false;
1974 bool found_concurrent_worker =
false;
1983 "Autovacuum worker",
2007 if (dbForm->datistemplate || !dbForm->datallowconn)
2036 table_toast_map =
hash_create(
"TOAST to main relid map",
2071 if (classForm->relkind != RELKIND_RELATION &&
2072 classForm->relkind != RELKIND_MATVIEW)
2075 relid = classForm->oid;
2081 if (classForm->relpersistence == RELPERSISTENCE_TEMP)
2109 effective_multixact_freeze_max_age,
2110 &dovacuum, &doanalyze, &wraparound);
2113 if (dovacuum || doanalyze)
2127 &classForm->reltoastrelid,
2135 if (relopts != NULL)
2149 Anum_pg_class_relkind,
2167 if (classForm->relpersistence == RELPERSISTENCE_TEMP)
2170 relid = classForm->oid;
2177 if (relopts == NULL)
2192 effective_multixact_freeze_max_age,
2193 &dovacuum, &doanalyze, &wraparound);
2212 foreach(cell, orphan_oids)
2250 if (!((classForm->relkind == RELKIND_RELATION ||
2251 classForm->relkind == RELKIND_MATVIEW) &&
2252 classForm->relpersistence == RELPERSISTENCE_TEMP))
2266 (
errmsg(
"autovacuum: dropping orphan temp table \"%s.%s.%s\"",
2269 NameStr(classForm->relname))));
2271 object.classId = RelationRelationId;
2272 object.objectId = relid;
2273 object.objectSubId = 0;
2302 "Autovacuum Portal",
2308 foreach(cell, table_oids)
2315 double stdVacuumCostDelay;
2316 int stdVacuumCostLimit;
2379 found_concurrent_worker =
true;
2408 effective_multixact_freeze_max_age);
2491 errcontext(
"automatic vacuum of table \"%s.%s.%s\"",
2494 errcontext(
"automatic analyze of table \"%s.%s.%s\"",
2607 if (did_vacuum || !found_concurrent_worker)
2620 char *cur_datname = NULL;
2621 char *cur_nspname = NULL;
2622 char *cur_relname = NULL;
2639 if (!cur_relname || !cur_nspname || !cur_datname)
2667 elog(
WARNING,
"unrecognized work item found: type %d",
2687 errcontext(
"processing work entry for relation \"%s.%s.%s\"",
2688 cur_datname, cur_nspname, cur_relname);
2739 if (relopts == NULL)
2761 int effective_multixact_freeze_max_age)
2782 if (classForm->relkind == RELKIND_TOASTVALUE &&
2783 avopts == NULL && table_toast_map != NULL)
2794 effective_multixact_freeze_max_age,
2795 &dovacuum, &doanalyze, &wraparound);
2798 if (doanalyze || dovacuum)
2801 int freeze_table_age;
2802 int multixact_freeze_min_age;
2803 int multixact_freeze_table_age;
2805 double vac_cost_delay;
2806 int log_min_duration;
2843 multixact_freeze_min_age = (avopts &&
2848 multixact_freeze_table_age = (avopts &&
2915 int effective_multixact_freeze_max_age,
2927 effective_multixact_freeze_max_age,
2928 dovacuum, doanalyze, wraparound);
2931 if (classForm->relkind == RELKIND_TOASTVALUE)
2977 int effective_multixact_freeze_max_age,
2988 int vac_base_thresh,
2989 vac_ins_base_thresh,
2992 vac_ins_scale_factor,
3007 int multixact_freeze_max_age;
3011 Assert(classForm != NULL);
3052 : effective_multixact_freeze_max_age;
3054 av_enabled = (relopts ? relopts->
enabled :
true);
3057 xidForceLimit =
recentXid - freeze_max_age;
3065 multiForceLimit =
recentMulti - multixact_freeze_max_age;
3071 *wraparound = force_vacuum;
3074 if (!av_enabled && !force_vacuum)
3090 reltuples = classForm->reltuples;
3099 vacthresh = (
float4) vac_base_thresh + vac_scale_factor * reltuples;
3100 vacinsthresh = (
float4) vac_ins_base_thresh + vac_ins_scale_factor * reltuples;
3101 anlthresh = (
float4) anl_base_thresh + anl_scale_factor * reltuples;
3108 if (vac_ins_base_thresh >= 0)
3109 elog(
DEBUG3,
"%s: vac: %.0f (threshold %.0f), ins: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
3111 vactuples, vacthresh, instuples, vacinsthresh, anltuples, anlthresh);
3113 elog(
DEBUG3,
"%s: vac: %.0f (threshold %.0f), ins: (disabled), anl: %.0f (threshold %.0f)",
3115 vactuples, vacthresh, anltuples, anlthresh);
3118 *dovacuum = force_vacuum || (vactuples > vacthresh) ||
3119 (vac_ins_base_thresh >= 0 && instuples > vacinsthresh);
3120 *doanalyze = (anltuples > anlthresh);
3129 *dovacuum = force_vacuum;
3134 if (relid == StatisticRelationId)
3174 #define MAX_AUTOVAC_ACTIV_LEN (NAMEDATALEN * 2 + 56)
3181 "autovacuum: VACUUM%s",
3185 "autovacuum: ANALYZE");
3190 len = strlen(activity);
3208 const char *nspname,
const char *
relname)
3218 "autovacuum: BRIN summarize");
3225 len = strlen(activity);
3233 " %s.%s%s", nspname,
relname, blk);
3263 bool result =
false;
3305 (
errmsg(
"autovacuum not started because of misconfiguration"),
3306 errhint(
"Enable the \"track_counts\" option.")));
int StartAutoVacWorker(void)
void AutoVacuumUpdateDelay(void)
static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts, Form_pg_class classForm, PgStat_StatTabEntry *tabentry, int effective_multixact_freeze_max_age, bool *dovacuum, bool *doanalyze, bool *wraparound)
static void autovac_balance_cost(void)
static Oid do_start_worker(void)
static void launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval *nap)
static autovac_table * table_recheck_autovac(Oid relid, HTAB *table_toast_map, TupleDesc pg_class_desc, int effective_multixact_freeze_max_age)
static volatile sig_atomic_t got_SIGUSR2
static void avl_sigusr2_handler(SIGNAL_ARGS)
NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn()
int autovacuum_multixact_freeze_max_age
static int default_multixact_freeze_table_age
static void HandleAutoVacLauncherInterrupts(void)
double autovacuum_vac_scale
static bool am_autovacuum_launcher
static void FreeWorkerInfo(int code, Datum arg)
int AutovacuumLauncherPid
int Log_autovacuum_min_duration
int autovacuum_anl_thresh
struct av_relation av_relation
static TransactionId recentXid
struct AutoVacuumWorkItem AutoVacuumWorkItem
Size AutoVacuumShmemSize(void)
struct autovac_table autovac_table
void AutoVacuumShmemInit(void)
bool check_autovacuum_work_mem(int *newval, void **extra, GucSource source)
static void autovac_report_activity(autovac_table *tab)
static int default_multixact_freeze_min_age
static AutoVacOpts * extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
static void do_autovacuum(void)
int autovacuum_vac_cost_limit
bool AutoVacuumRequestWork(AutoVacuumWorkItemType type, Oid relationId, BlockNumber blkno)
bool AutoVacuumingActive(void)
int autovacuum_max_workers
int autovacuum_freeze_max_age
static int db_comparator(const void *a, const void *b)
double autovacuum_vac_cost_delay
static void AutoVacLauncherShutdown(void)
NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn()
struct avl_dbase avl_dbase
int autovacuum_vac_thresh
struct avw_dbase avw_dbase
static void launch_worker(TimestampTz now)
struct WorkerInfoData WorkerInfoData
static dlist_head DatabaseList
static void rebuild_database_list(Oid newdb)
static AutoVacuumShmemStruct * AutoVacuumShmem
bool IsAutoVacuumLauncherProcess(void)
#define MIN_AUTOVAC_SLEEPTIME
#define MAX_AUTOVAC_ACTIV_LEN
double autovacuum_anl_scale
int autovacuum_vac_ins_thresh
#define MAX_AUTOVAC_SLEEPTIME
static MemoryContext DatabaseListCxt
void AutoVacWorkerFailed(void)
struct WorkerInfoData * WorkerInfo
static List * get_database_list(void)
bool autovacuum_start_daemon
static void perform_work_item(AutoVacuumWorkItem *workitem)
double autovacuum_vac_ins_scale
static MultiXactId recentMulti
static int default_freeze_min_age
bool IsAutoVacuumWorkerProcess(void)
static bool am_autovacuum_worker
static WorkerInfo MyWorkerInfo
static void autovac_report_workitem(AutoVacuumWorkItem *workitem, const char *nspname, const char *relname)
static void recheck_relation_needs_vacanalyze(Oid relid, AutoVacOpts *avopts, Form_pg_class classForm, int effective_multixact_freeze_max_age, bool *dovacuum, bool *doanalyze, bool *wraparound)
static MemoryContext AutovacMemCxt
static int default_freeze_table_age
static void autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
int StartAutoVacLauncher(void)
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
TimestampTz GetCurrentTimestamp(void)
Datum now(PG_FUNCTION_ARGS)
void pgstat_report_activity(BackendState state, const char *cmd_str)
static bool BlockNumberIsValid(BlockNumber blockNumber)
Datum brin_summarize_range(PG_FUNCTION_ARGS)
void AtEOXact_Buffers(bool isCommit)
#define pg_attribute_noreturn()
TransactionId MultiXactId
#define PointerIsValid(pointer)
#define OidIsValid(objectId)
Datum current_time(PG_FUNCTION_ARGS)
char * get_database_name(Oid dbid)
elog(ERROR, "%s: %s", p2, msg)
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
#define PERFORM_DELETION_SKIP_EXTENSIONS
#define PERFORM_DELETION_QUIETLY
#define PERFORM_DELETION_INTERNAL
void AtEOXact_HashTables(bool isCommit)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
void * hash_seq_search(HASH_SEQ_STATUS *status)
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
int errmsg_internal(const char *fmt,...)
void EmitErrorReport(void)
ErrorContextCallback * error_context_stack
void FlushErrorState(void)
int errhint(const char *fmt,...)
int errmsg(const char *fmt,...)
sigjmp_buf * PG_exception_stack
#define ereport(elevel,...)
void AtEOXact_Files(bool isCommit)
Datum Int64GetDatum(int64 X)
#define DirectFunctionCall2(func, arg1, arg2)
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
volatile sig_atomic_t LogMemoryContextPending
volatile sig_atomic_t ProcSignalBarrierPending
volatile sig_atomic_t QueryCancelPending
void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source)
void ProcessConfigFile(GucContext context)
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
#define dlist_foreach(iter, lhead)
static void dlist_init(dlist_head *head)
static void dlist_delete(dlist_node *node)
#define dlist_reverse_foreach(iter, lhead)
static dlist_node * dlist_pop_head_node(dlist_head *head)
#define dlist_tail_element(type, membername, lhead)
static void dlist_push_head(dlist_head *head, dlist_node *node)
static bool dlist_is_empty(const dlist_head *head)
static void dlist_move_head(dlist_head *head, dlist_node *node)
#define DLIST_STATIC_INIT(name)
#define dlist_container(type, membername, ptr)
void SignalHandlerForShutdownRequest(SIGNAL_ARGS)
volatile sig_atomic_t ShutdownRequestPending
volatile sig_atomic_t ConfigReloadPending
void SignalHandlerForConfigReload(SIGNAL_ARGS)
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
void SetLatch(Latch *latch)
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)
List * lappend_oid(List *list, Oid datum)
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
#define AccessExclusiveLock
char * get_namespace_name(Oid nspid)
Oid get_rel_namespace(Oid relid)
char * get_rel_name(Oid relid)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void LWLockRelease(LWLock *lock)
void LWLockReleaseAll(void)
VacuumRelation * makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols)
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
char * pstrdup(const char *in)
void pfree(void *pointer)
MemoryContext TopMemoryContext
MemoryContext CurrentMemoryContext
void ProcessLogMemoryContextInterrupt(void)
void MemoryContextDelete(MemoryContext context)
MemoryContext PortalContext
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define MemoryContextResetAndDeleteChildren(ctx)
#define RESUME_INTERRUPTS()
#define CHECK_FOR_INTERRUPTS()
#define HOLD_INTERRUPTS()
#define SetProcessingMode(mode)
void InitPostmasterChild(void)
BackendType MyBackendType
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
int MultiXactMemberFreezeThreshold(void)
MultiXactId ReadNextMultiXactId(void)
#define MultiXactIdIsValid(multi)
TempNamespaceStatus checkTempNamespaceStatus(Oid namespaceId)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
FormData_pg_class * Form_pg_class
FormData_pg_database * Form_pg_database
static rewind_source * source
void pgstat_report_autovac(Oid dboid)
PgStat_StatDBEntry * pgstat_fetch_stat_dbentry(Oid dboid)
PgStat_StatTabEntry * pgstat_fetch_stat_tabentry_ext(bool shared, Oid reloid)
void SendPostmasterSignal(PMSignalReason reason)
@ PMSIGNAL_START_AUTOVAC_WORKER
pqsigfunc pqsignal(int signo, pqsigfunc func)
#define qsort(a, b, c, d)
void FloatExceptionHandler(SIGNAL_ARGS)
void StatementCancelHandler(SIGNAL_ARGS)
static Datum ObjectIdGetDatum(Oid X)
static Datum CharGetDatum(char X)
void InitPostgres(const char *in_dbname, Oid dboid, const char *username, Oid useroid, bool load_session_libraries, bool override_allow_connections, char *out_dbname)
void ClosePostmasterPorts(bool am_syslogger)
void ProcessProcSignalBarrier(void)
void procsignal_sigusr1_handler(SIGNAL_ARGS)
void init_ps_display(const char *fixed_part)
static void set_ps_display(const char *activity)
#define RelationGetDescr(relation)
bytea * extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions)
void ReleaseAuxProcessResources(bool isCommit)
ResourceOwner AuxProcessResourceOwner
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Size add_size(Size s1, Size s2)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Size mul_size(Size s1, Size s2)
void pg_usleep(long microsec)
void ProcessCatchupInterrupt(void)
Snapshot GetTransactionSnapshot(void)
#define BTEqualStrategyNumber
int multixact_freeze_max_age
float8 vacuum_scale_factor
float8 vacuum_ins_scale_factor
int multixact_freeze_table_age
int multixact_freeze_min_age
float8 analyze_scale_factor
dlist_head av_freeWorkers
WorkerInfo av_startingWorker
sig_atomic_t av_signal[AutoVacNumSignals]
AutoVacuumWorkItem av_workItems[NUM_WORKITEMS]
dlist_head av_runningWorkers
BlockNumber avw_blockNumber
AutoVacuumWorkItemType avw_type
TimestampTz last_autovac_time
PgStat_Counter ins_since_vacuum
PgStat_Counter mod_since_analyze
PgStat_Counter dead_tuples
int multixact_freeze_min_age
int multixact_freeze_table_age
VacOptValue index_cleanup
TimestampTz wi_launchtime
double at_vacuum_cost_delay
AutoVacOpts ar_reloptions
TimestampTz adl_next_worker
PgStat_StatDBEntry * adw_entry
TransactionId adw_frozenxid
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)
void disable_all_timeouts(bool keep_indicators)
void InitializeTimeouts(void)
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
static TransactionId ReadNextTransactionId(void)
#define FirstNormalTransactionId
#define TransactionIdIsNormal(xid)
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
#define TimestampTzPlusMilliseconds(tz, ms)
int vacuum_freeze_min_age
void vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel)
int vacuum_multixact_freeze_table_age
int vacuum_freeze_table_age
int vacuum_multixact_freeze_min_age
void vac_update_datfrozenxid(void)
#define VACOPT_SKIP_LOCKED
#define VACOPT_SKIP_DATABASE_STATS
@ VACOPTVALUE_UNSPECIFIED
#define VACOPT_PROCESS_MAIN
@ WAIT_EVENT_AUTOVACUUM_MAIN
static void pgstat_report_wait_end(void)
void StartTransactionCommand(void)
void SetCurrentStatementStartTimestamp(void)
void CommitTransactionCommand(void)
void AbortOutOfAnyTransaction(void)
void AbortCurrentTransaction(void)
@ SYNCHRONOUS_COMMIT_LOCAL_FLUSH