99 #include "utils/fmgroids.h" 100 #include "utils/fmgrprotos.h" 133 #define STATS_READ_DELAY 1000 136 #define MIN_AUTOVAC_SLEEPTIME 100.0 137 #define MAX_AUTOVAC_SLEEPTIME 300 264 #define NUM_WORKITEMS 256 308 static pid_t avlauncher_forkexec(
void);
309 static pid_t avworker_forkexec(
void);
318 struct timeval *nap);
330 int effective_multixact_freeze_max_age);
333 int effective_multixact_freeze_max_age,
334 bool *dovacuum,
bool *doanalyze,
bool *wraparound);
338 int effective_multixact_freeze_max_age,
339 bool *dovacuum,
bool *doanalyze,
bool *wraparound);
351 const char *nspname,
const char *
relname);
368 avlauncher_forkexec(
void)
373 av[ac++] =
"postgres";
374 av[ac++] =
"--forkavlauncher";
380 return postmaster_forkexec(ac, av);
387 AutovacuumLauncherIAm(
void)
403 switch ((AutoVacPID = avlauncher_forkexec()))
410 (
errmsg(
"could not fork autovacuum launcher process: %m")));
438 sigjmp_buf local_sigjmp_buf;
494 "Autovacuum Launcher",
510 if (sigsetjmp(local_sigjmp_buf, 1) != 0)
555 DatabaseListCxt = NULL;
659 (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
757 elog(
WARNING,
"worker took too long to start; canceled");
891 nap->tv_usec = usecs;
910 if (nap->tv_sec == 0 && nap->tv_usec == 0 && !recursing)
1042 foreach(cell, dblist)
1072 int millis_increment;
1084 memcpy(&(dbary[i++]), db,
sizeof(
avl_dbase));
1106 for (i = 0; i < nelems; i++)
1120 if (DatabaseListCxt != NULL)
1123 DatabaseListCxt = newcxt;
1156 bool for_multi_wrap;
1159 bool skipit =
false;
1178 "Start worker tmp cxt",
1228 for_xid_wrap =
false;
1229 for_multi_wrap =
false;
1231 foreach(cell, dblist)
1243 for_xid_wrap =
true;
1246 else if (for_xid_wrap)
1253 for_multi_wrap =
true;
1256 else if (for_multi_wrap)
1425 int save_errno = errno;
1445 avworker_forkexec(
void)
1450 av[ac++] =
"postgres";
1451 av[ac++] =
"--forkavworker";
1457 return postmaster_forkexec(ac, av);
1464 AutovacuumWorkerIAm(
void)
1481 switch ((worker_pid = avworker_forkexec()))
1488 (
errmsg(
"could not fork autovacuum worker process: %m")));
1491 #ifndef EXEC_BACKEND 1503 return (
int) worker_pid;
1516 sigjmp_buf local_sigjmp_buf;
1558 #ifndef EXEC_BACKEND 1575 if (sigsetjmp(local_sigjmp_buf, 1) != 0)
1677 elog(
WARNING,
"autovacuum worker started without a worker entry");
1732 if (MyWorkerInfo != NULL)
1763 MyWorkerInfo = NULL;
1814 if (vac_cost_limit <= 0 || vac_cost_delay <= 0)
1823 if (worker->
wi_proc != NULL &&
1831 if (cost_total <= 0)
1838 cost_avail = (double) vac_cost_limit / vac_cost_delay;
1843 if (worker->
wi_proc != NULL &&
1862 elog(
DEBUG2,
"autovac_balance_cost(pid=%u db=%u, rel=%u, dobalance=%s cost_limit=%d, cost_limit_base=%d, cost_delay=%g)",
1934 dblist =
lappend(dblist, avdb);
1962 HTAB *table_toast_map;
1969 int effective_multixact_freeze_max_age;
1970 bool did_vacuum =
false;
1971 bool found_concurrent_worker =
false;
2017 if (dbForm->datistemplate || !dbForm->datallowconn)
2049 table_toast_map =
hash_create(
"TOAST to main relid map",
2084 if (classForm->relkind != RELKIND_RELATION &&
2085 classForm->relkind != RELKIND_MATVIEW)
2088 relid = classForm->oid;
2094 if (classForm->relpersistence == RELPERSISTENCE_TEMP)
2122 effective_multixact_freeze_max_age,
2123 &dovacuum, &doanalyze, &wraparound);
2126 if (dovacuum || doanalyze)
2140 &classForm->reltoastrelid,
2148 if (relopts != NULL)
2162 Anum_pg_class_relkind,
2180 if (classForm->relpersistence == RELPERSISTENCE_TEMP)
2183 relid = classForm->oid;
2190 if (relopts == NULL)
2205 effective_multixact_freeze_max_age,
2206 &dovacuum, &doanalyze, &wraparound);
2225 foreach(cell, orphan_oids)
2263 if (!((classForm->relkind == RELKIND_RELATION ||
2264 classForm->relkind == RELKIND_MATVIEW) &&
2265 classForm->relpersistence == RELPERSISTENCE_TEMP))
2279 (
errmsg(
"autovacuum: dropping orphan temp table \"%s.%s.%s\"",
2282 NameStr(classForm->relname))));
2284 object.classId = RelationRelationId;
2285 object.objectId = relid;
2286 object.objectSubId = 0;
2315 "Autovacuum Portal",
2321 foreach(cell, table_oids)
2328 double stdVacuumCostDelay;
2329 int stdVacuumCostLimit;
2382 if (worker == MyWorkerInfo)
2392 found_concurrent_worker =
true;
2425 effective_multixact_freeze_max_age);
2508 errcontext(
"automatic vacuum of table \"%s.%s.%s\"",
2511 errcontext(
"automatic analyze of table \"%s.%s.%s\"",
2624 if (did_vacuum || !found_concurrent_worker)
2637 char *cur_datname = NULL;
2638 char *cur_nspname = NULL;
2639 char *cur_relname = NULL;
2656 if (!cur_relname || !cur_nspname || !cur_datname)
2684 elog(
WARNING,
"unrecognized work item found: type %d",
2704 errcontext(
"processing work entry for relation \"%s.%s.%s\"",
2705 cur_datname, cur_nspname, cur_relname);
2751 if (relopts == NULL)
2796 int effective_multixact_freeze_max_age)
2805 static bool reuse_stats =
false;
2818 if (classForm->relkind == RELKIND_TOASTVALUE &&
2819 avopts == NULL && table_toast_map != NULL)
2844 effective_multixact_freeze_max_age,
2845 &dovacuum, &doanalyze, &wraparound);
2848 if (!doanalyze && !dovacuum)
2859 effective_multixact_freeze_max_age,
2860 &dovacuum, &doanalyze, &wraparound);
2863 if (doanalyze || dovacuum)
2866 int freeze_table_age;
2867 int multixact_freeze_min_age;
2868 int multixact_freeze_table_age;
2870 double vac_cost_delay;
2871 int log_min_duration;
2908 multixact_freeze_min_age = (avopts &&
2913 multixact_freeze_table_age = (avopts &&
2955 reuse_stats =
false;
2982 int effective_multixact_freeze_max_age,
2991 if (classForm->relisshared)
3001 effective_multixact_freeze_max_age,
3002 dovacuum, doanalyze, wraparound);
3005 if (classForm->relkind == RELKIND_TOASTVALUE)
3051 int effective_multixact_freeze_max_age,
3062 int vac_base_thresh,
3063 vac_ins_base_thresh,
3066 vac_ins_scale_factor,
3081 int multixact_freeze_max_age;
3126 : effective_multixact_freeze_max_age;
3128 av_enabled = (relopts ? relopts->
enabled :
true);
3131 xidForceLimit =
recentXid - freeze_max_age;
3139 multiForceLimit =
recentMulti - multixact_freeze_max_age;
3145 *wraparound = force_vacuum;
3148 if (!av_enabled && !force_vacuum)
3164 reltuples = classForm->reltuples;
3173 vacthresh = (
float4) vac_base_thresh + vac_scale_factor * reltuples;
3174 vacinsthresh = (
float4) vac_ins_base_thresh + vac_ins_scale_factor * reltuples;
3175 anlthresh = (
float4) anl_base_thresh + anl_scale_factor * reltuples;
3182 if (vac_ins_base_thresh >= 0)
3183 elog(
DEBUG3,
"%s: vac: %.0f (threshold %.0f), ins: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
3185 vactuples, vacthresh, instuples, vacinsthresh, anltuples, anlthresh);
3187 elog(
DEBUG3,
"%s: vac: %.0f (threshold %.0f), ins: (disabled), anl: %.0f (threshold %.0f)",
3189 vactuples, vacthresh, anltuples, anlthresh);
3192 *dovacuum = force_vacuum || (vactuples > vacthresh) ||
3193 (vac_ins_base_thresh >= 0 && instuples > vacinsthresh);
3194 *doanalyze = (anltuples > anlthresh);
3203 *dovacuum = force_vacuum;
3208 if (relid == StatisticRelationId)
3248 #define MAX_AUTOVAC_ACTIV_LEN (NAMEDATALEN * 2 + 56) 3255 "autovacuum: VACUUM%s",
3259 "autovacuum: ANALYZE");
3264 len = strlen(activity);
3282 const char *nspname,
const char *
relname)
3292 "autovacuum: BRIN summarize");
3299 len = strlen(activity);
3307 " %s.%s%s", nspname, relname, blk);
3337 bool result =
false;
3379 (
errmsg(
"autovacuum not started because of misconfiguration"),
3380 errhint(
"Enable the \"track_counts\" option.")));
3448 worker = (
WorkerInfo) ((
char *) AutoVacuumShmem +
3486 last_read = current_time;
AutoVacuumWorkItemType avw_type
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
void ProcessCatchupInterrupt(void)
static bool am_autovacuum_worker
void InitializeTimeouts(void)
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
bool AutoVacuumRequestWork(AutoVacuumWorkItemType type, Oid relationId, BlockNumber blkno)
int multixact_freeze_table_age
static int default_freeze_table_age
void AbortCurrentTransaction(void)
#define pg_attribute_noreturn()
double autovacuum_anl_scale
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
TimestampTz adl_next_worker
struct avw_dbase avw_dbase
void vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel)
void MemoryContextDelete(MemoryContext context)
#define AllocSetContextCreate
volatile sig_atomic_t QueryCancelPending
void table_close(Relation relation, LOCKMODE lockmode)
int errhint(const char *fmt,...)
#define MAX_AUTOVAC_SLEEPTIME
static void autovac_balance_cost(void)
WorkerInfo av_startingWorker
sig_atomic_t av_signal[AutoVacNumSignals]
int vacuum_multixact_freeze_table_age
static bool am_autovacuum_launcher
void ProcessConfigFile(GucContext context)
bool autovacuum_start_daemon
dlist_head av_freeWorkers
int autovacuum_vac_ins_thresh
static AutoVacOpts * extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
void vac_update_datfrozenxid(void)
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
static int default_multixact_freeze_min_age
void InitPostmasterChild(void)
NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn()
#define RelationGetDescr(relation)
static void dlist_push_head(dlist_head *head, dlist_node *node)
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
BackendType MyBackendType
TimestampTz GetCurrentTimestamp(void)
float8 vacuum_scale_factor
void pgstat_report_activity(BackendState state, const char *cmd_str)
static void do_autovacuum(void)
FormData_pg_database * Form_pg_database
VacuumRelation * makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols)
struct WorkerInfoData * WorkerInfo
#define dlist_foreach(iter, lhead)
void AtEOXact_Buffers(bool isCommit)
void SignalHandlerForConfigReload(SIGNAL_ARGS)
char * pstrdup(const char *in)
void CommitTransactionCommand(void)
void ReleaseAuxProcessResources(bool isCommit)
TimestampTz wi_launchtime
static MemoryContext AutovacMemCxt
void ProcessProcSignalBarrier(void)
Oid get_rel_namespace(Oid relid)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
static MultiXactId recentMulti
struct WorkerInfoData WorkerInfoData
struct avl_dbase avl_dbase
int autovacuum_multixact_freeze_max_age
static void autovac_refresh_stats(void)
PgStat_StatDBEntry * pgstat_fetch_stat_dbentry(Oid dbid)
#define SetProcessingMode(mode)
#define MIN_AUTOVAC_SLEEPTIME
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
static TransactionId ReadNextTransactionId(void)
void heap_freetuple(HeapTuple htup)
void SetLatch(Latch *latch)
NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn()
List * lappend_oid(List *list, Oid datum)
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Snapshot GetTransactionSnapshot(void)
void ClosePostmasterPorts(bool am_syslogger)
#define OidIsValid(objectId)
void AbortOutOfAnyTransaction(void)
int autovacuum_vac_cost_limit
void FlushErrorState(void)
void ResetLatch(Latch *latch)
ResourceOwner AuxProcessResourceOwner
void StatementCancelHandler(SIGNAL_ARGS)
void AtEOXact_Files(bool isCommit)
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
double autovacuum_vac_ins_scale
MemoryContext PortalContext
void LWLockRelease(LWLock *lock)
TempNamespaceStatus checkTempNamespaceStatus(Oid namespaceId)
Datum brin_summarize_range(PG_FUNCTION_ARGS)
#define RESUME_INTERRUPTS()
ErrorContextCallback * error_context_stack
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)
void set_ps_display(const char *activity)
PgStat_Counter inserts_since_vacuum
void pg_usleep(long microsec)
static void HandleAutoVacLauncherInterrupts(void)
#define dlist_container(type, membername, ptr)
void pfree(void *pointer)
#define dlist_tail_element(type, membername, lhead)
void disable_all_timeouts(bool keep_indicators)
#define FirstNormalTransactionId
bool AutoVacuumingActive(void)
#define ObjectIdGetDatum(X)
int AutovacuumLauncherPid
struct AutoVacuumWorkItem AutoVacuumWorkItem
int autovacuum_freeze_max_age
int StartAutoVacWorker(void)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
int vacuum_multixact_freeze_min_age
PgStat_Counter n_dead_tuples
#define ALLOCSET_DEFAULT_SIZES
char * get_database_name(Oid dbid)
AutoVacuumWorkItem av_workItems[NUM_WORKITEMS]
TimestampTz last_autovac_time
double autovacuum_vac_cost_delay
char * get_namespace_name(Oid nspid)
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source)
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
int autovacuum_vac_thresh
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
static void autovac_report_workitem(AutoVacuumWorkItem *workitem, const char *nspname, const char *relname)
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
static void perform_work_item(AutoVacuumWorkItem *workitem)
#define MultiXactIdIsValid(multi)
static void pgstat_report_wait_end(void)
MemoryContext CurrentMemoryContext
static WorkerInfo MyWorkerInfo
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 dlist_delete(dlist_node *node)
Datum Int64GetDatum(int64 X)
static dlist_head DatabaseList
bool IsAutoVacuumWorkerProcess(void)
void pgstat_vacuum_stat(void)
int MultiXactMemberFreezeThreshold(void)
#define AssertArg(condition)
MemoryContext TopMemoryContext
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
volatile sig_atomic_t ShutdownRequestPending
VacOptTernaryValue index_cleanup
List * lappend(List *list, void *datum)
void SignalHandlerForShutdownRequest(SIGNAL_ARGS)
static void avl_sigusr2_handler(SIGNAL_ARGS)
static void launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval *nap)
TransactionId adw_frozenxid
#define DLIST_STATIC_INIT(name)
static int db_comparator(const void *a, const void *b)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define MemoryContextResetAndDeleteChildren(ctx)
static void autovac_report_activity(autovac_table *tab)
int multixact_freeze_table_age
Size mul_size(Size s1, Size s2)
PgStat_StatDBEntry * adw_entry
void ReleaseSysCache(HeapTuple tuple)
Size add_size(Size s1, Size s2)
double at_vacuum_cost_delay
struct autovac_table autovac_table
#define MAX_AUTOVAC_ACTIV_LEN
Size AutoVacuumShmemSize(void)
BlockNumber avw_blockNumber
static TransactionId recentXid
void EmitErrorReport(void)
PgStat_Counter changes_since_analyze
bytea * extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, amoptions_function amoptions)
int autovacuum_max_workers
VacOptTernaryValue truncate
static PgStat_StatTabEntry * get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared, PgStat_StatDBEntry *dbentry)
#define TimestampTzPlusMilliseconds(tz, ms)
static void dlist_init(dlist_head *head)
double autovacuum_vac_scale
#define ereport(elevel,...)
void InitPostgres(const char *in_dbname, Oid dboid, const char *username, Oid useroid, char *out_dbname, bool override_allow_connections)
#define BlockNumberIsValid(blockNumber)
pqsigfunc pqsignal(int signum, pqsigfunc handler)
static volatile sig_atomic_t got_SIGUSR2
float8 analyze_scale_factor
TransactionId MultiXactId
int errmsg_internal(const char *fmt,...)
bool IsAutoVacuumLauncherProcess(void)
#define HeapTupleIsValid(tuple)
#define Assert(condition)
#define PERFORM_DELETION_QUIETLY
volatile sig_atomic_t ProcSignalBarrierPending
int multixact_freeze_min_age
void StartTransactionCommand(void)
static bool dlist_is_empty(dlist_head *head)
void pgstat_clear_snapshot(void)
static void FreeWorkerInfo(int code, Datum arg)
static AutoVacuumShmemStruct * AutoVacuumShmem
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
int vacuum_freeze_min_age
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
void * hash_seq_search(HASH_SEQ_STATUS *status)
void AutoVacWorkerFailed(void)
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
int vacuum_freeze_table_age
sigjmp_buf * PG_exception_stack
static List * get_database_list(void)
int StartAutoVacLauncher(void)
static void dlist_move_head(dlist_head *head, dlist_node *node)
static void rebuild_database_list(Oid newdb)
int Log_autovacuum_min_duration
static void table_endscan(TableScanDesc scan)
FormData_pg_class * Form_pg_class
#define SearchSysCacheCopy1(cacheId, key1)
AutoVacOpts ar_reloptions
#define AccessExclusiveLock
static void autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
void SetCurrentStatementStartTimestamp(void)
static void AutoVacLauncherShutdown(void)
int errmsg(const char *fmt,...)
#define VACOPT_SKIP_LOCKED
static dlist_node * dlist_pop_head_node(dlist_head *head)
#define HOLD_INTERRUPTS()
static MemoryContext DatabaseListCxt
volatile sig_atomic_t ConfigReloadPending
void FloatExceptionHandler(SIGNAL_ARGS)
struct av_relation av_relation
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
int multixact_freeze_max_age
void AutoVacuumUpdateDelay(void)
#define CHECK_FOR_INTERRUPTS()
static void launch_worker(TimestampTz now)
float8 vacuum_ins_scale_factor
void SendPostmasterSignal(PMSignalReason reason)
static autovac_table * table_recheck_autovac(Oid relid, HTAB *table_toast_map, TupleDesc pg_class_desc, int effective_multixact_freeze_max_age)
void init_ps_display(const char *fixed_part)
void LWLockReleaseAll(void)
#define qsort(a, b, c, d)
void procsignal_sigusr1_handler(SIGNAL_ARGS)
void AtEOXact_HashTables(bool isCommit)
void AutoVacuumShmemInit(void)
dlist_head av_runningWorkers
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
#define TransactionIdIsNormal(xid)
Relation table_open(Oid relationId, LOCKMODE lockmode)
#define PERFORM_DELETION_SKIP_EXTENSIONS
char * get_rel_name(Oid relid)
#define PointerIsValid(pointer)
static int default_multixact_freeze_table_age
void pgstat_report_autovac(Oid dboid)
static Oid do_start_worker(void)
int multixact_freeze_min_age
#define dlist_reverse_foreach(iter, lhead)
static int default_freeze_min_age
Datum now(PG_FUNCTION_ARGS)
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
#define DirectFunctionCall2(func, arg1, arg2)
#define BTEqualStrategyNumber
#define WL_EXIT_ON_PM_DEATH
#define PERFORM_DELETION_INTERNAL
int autovacuum_anl_thresh
MultiXactId ReadNextMultiXactId(void)