|
|
@ -139,6 +139,18 @@ int Log_autovacuum_min_duration = 600000;
|
|
|
|
static bool am_autovacuum_launcher = false;
|
|
|
|
static bool am_autovacuum_launcher = false;
|
|
|
|
static bool am_autovacuum_worker = false;
|
|
|
|
static bool am_autovacuum_worker = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Variables to save the cost-related storage parameters for the current
|
|
|
|
|
|
|
|
* relation being vacuumed by this autovacuum worker. Using these, we can
|
|
|
|
|
|
|
|
* ensure we don't overwrite the values of vacuum_cost_delay and
|
|
|
|
|
|
|
|
* vacuum_cost_limit after reloading the configuration file. They are
|
|
|
|
|
|
|
|
* initialized to "invalid" values to indicate that no cost-related storage
|
|
|
|
|
|
|
|
* parameters were specified and will be set in do_autovacuum() after checking
|
|
|
|
|
|
|
|
* the storage parameters in table_recheck_autovac().
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static double av_storage_param_cost_delay = -1;
|
|
|
|
|
|
|
|
static int av_storage_param_cost_limit = -1;
|
|
|
|
|
|
|
|
|
|
|
|
/* Flags set by signal handlers */
|
|
|
|
/* Flags set by signal handlers */
|
|
|
|
static volatile sig_atomic_t got_SIGUSR2 = false;
|
|
|
|
static volatile sig_atomic_t got_SIGUSR2 = false;
|
|
|
|
|
|
|
|
|
|
|
@ -189,8 +201,8 @@ typedef struct autovac_table
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Oid at_relid;
|
|
|
|
Oid at_relid;
|
|
|
|
VacuumParams at_params;
|
|
|
|
VacuumParams at_params;
|
|
|
|
double at_vacuum_cost_delay;
|
|
|
|
double at_storage_param_vac_cost_delay;
|
|
|
|
int at_vacuum_cost_limit;
|
|
|
|
int at_storage_param_vac_cost_limit;
|
|
|
|
bool at_dobalance;
|
|
|
|
bool at_dobalance;
|
|
|
|
bool at_sharedrel;
|
|
|
|
bool at_sharedrel;
|
|
|
|
char *at_relname;
|
|
|
|
char *at_relname;
|
|
|
@ -209,7 +221,7 @@ typedef struct autovac_table
|
|
|
|
* wi_sharedrel flag indicating whether table is marked relisshared
|
|
|
|
* wi_sharedrel flag indicating whether table is marked relisshared
|
|
|
|
* wi_proc pointer to PGPROC of the running worker, NULL if not started
|
|
|
|
* wi_proc pointer to PGPROC of the running worker, NULL if not started
|
|
|
|
* wi_launchtime Time at which this worker was launched
|
|
|
|
* wi_launchtime Time at which this worker was launched
|
|
|
|
* wi_cost_* Vacuum cost-based delay parameters current in this worker
|
|
|
|
* wi_dobalance Whether this worker should be included in balance calculations
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* All fields are protected by AutovacuumLock, except for wi_tableoid and
|
|
|
|
* All fields are protected by AutovacuumLock, except for wi_tableoid and
|
|
|
|
* wi_sharedrel which are protected by AutovacuumScheduleLock (note these
|
|
|
|
* wi_sharedrel which are protected by AutovacuumScheduleLock (note these
|
|
|
@ -223,11 +235,8 @@ typedef struct WorkerInfoData
|
|
|
|
Oid wi_tableoid;
|
|
|
|
Oid wi_tableoid;
|
|
|
|
PGPROC *wi_proc;
|
|
|
|
PGPROC *wi_proc;
|
|
|
|
TimestampTz wi_launchtime;
|
|
|
|
TimestampTz wi_launchtime;
|
|
|
|
bool wi_dobalance;
|
|
|
|
pg_atomic_flag wi_dobalance;
|
|
|
|
bool wi_sharedrel;
|
|
|
|
bool wi_sharedrel;
|
|
|
|
double wi_cost_delay;
|
|
|
|
|
|
|
|
int wi_cost_limit;
|
|
|
|
|
|
|
|
int wi_cost_limit_base;
|
|
|
|
|
|
|
|
} WorkerInfoData;
|
|
|
|
} WorkerInfoData;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct WorkerInfoData *WorkerInfo;
|
|
|
|
typedef struct WorkerInfoData *WorkerInfo;
|
|
|
@ -273,6 +282,8 @@ typedef struct AutoVacuumWorkItem
|
|
|
|
* av_startingWorker pointer to WorkerInfo currently being started (cleared by
|
|
|
|
* av_startingWorker pointer to WorkerInfo currently being started (cleared by
|
|
|
|
* the worker itself as soon as it's up and running)
|
|
|
|
* the worker itself as soon as it's up and running)
|
|
|
|
* av_workItems work item array
|
|
|
|
* av_workItems work item array
|
|
|
|
|
|
|
|
* av_nworkersForBalance the number of autovacuum workers to use when
|
|
|
|
|
|
|
|
* calculating the per worker cost limit
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This struct is protected by AutovacuumLock, except for av_signal and parts
|
|
|
|
* This struct is protected by AutovacuumLock, except for av_signal and parts
|
|
|
|
* of the worker list (see above).
|
|
|
|
* of the worker list (see above).
|
|
|
@ -286,6 +297,7 @@ typedef struct
|
|
|
|
dlist_head av_runningWorkers;
|
|
|
|
dlist_head av_runningWorkers;
|
|
|
|
WorkerInfo av_startingWorker;
|
|
|
|
WorkerInfo av_startingWorker;
|
|
|
|
AutoVacuumWorkItem av_workItems[NUM_WORKITEMS];
|
|
|
|
AutoVacuumWorkItem av_workItems[NUM_WORKITEMS];
|
|
|
|
|
|
|
|
pg_atomic_uint32 av_nworkersForBalance;
|
|
|
|
} AutoVacuumShmemStruct;
|
|
|
|
} AutoVacuumShmemStruct;
|
|
|
|
|
|
|
|
|
|
|
|
static AutoVacuumShmemStruct *AutoVacuumShmem;
|
|
|
|
static AutoVacuumShmemStruct *AutoVacuumShmem;
|
|
|
@ -319,7 +331,7 @@ static void launch_worker(TimestampTz now);
|
|
|
|
static List *get_database_list(void);
|
|
|
|
static List *get_database_list(void);
|
|
|
|
static void rebuild_database_list(Oid newdb);
|
|
|
|
static void rebuild_database_list(Oid newdb);
|
|
|
|
static int db_comparator(const void *a, const void *b);
|
|
|
|
static int db_comparator(const void *a, const void *b);
|
|
|
|
static void autovac_balance_cost(void);
|
|
|
|
static void autovac_recalculate_workers_for_balance(void);
|
|
|
|
|
|
|
|
|
|
|
|
static void do_autovacuum(void);
|
|
|
|
static void do_autovacuum(void);
|
|
|
|
static void FreeWorkerInfo(int code, Datum arg);
|
|
|
|
static void FreeWorkerInfo(int code, Datum arg);
|
|
|
@ -669,7 +681,7 @@ AutoVacLauncherMain(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
{
|
|
|
|
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
|
|
|
|
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
|
|
|
|
AutoVacuumShmem->av_signal[AutoVacRebalance] = false;
|
|
|
|
AutoVacuumShmem->av_signal[AutoVacRebalance] = false;
|
|
|
|
autovac_balance_cost();
|
|
|
|
autovac_recalculate_workers_for_balance();
|
|
|
|
LWLockRelease(AutovacuumLock);
|
|
|
|
LWLockRelease(AutovacuumLock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -818,11 +830,6 @@ HandleAutoVacLauncherInterrupts(void)
|
|
|
|
if (!AutoVacuumingActive())
|
|
|
|
if (!AutoVacuumingActive())
|
|
|
|
AutoVacLauncherShutdown();
|
|
|
|
AutoVacLauncherShutdown();
|
|
|
|
|
|
|
|
|
|
|
|
/* rebalance in case the default cost parameters changed */
|
|
|
|
|
|
|
|
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
|
|
|
|
|
|
|
|
autovac_balance_cost();
|
|
|
|
|
|
|
|
LWLockRelease(AutovacuumLock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* rebuild the list in case the naptime changed */
|
|
|
|
/* rebuild the list in case the naptime changed */
|
|
|
|
rebuild_database_list(InvalidOid);
|
|
|
|
rebuild_database_list(InvalidOid);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1754,10 +1761,7 @@ FreeWorkerInfo(int code, Datum arg)
|
|
|
|
MyWorkerInfo->wi_sharedrel = false;
|
|
|
|
MyWorkerInfo->wi_sharedrel = false;
|
|
|
|
MyWorkerInfo->wi_proc = NULL;
|
|
|
|
MyWorkerInfo->wi_proc = NULL;
|
|
|
|
MyWorkerInfo->wi_launchtime = 0;
|
|
|
|
MyWorkerInfo->wi_launchtime = 0;
|
|
|
|
MyWorkerInfo->wi_dobalance = false;
|
|
|
|
pg_atomic_clear_flag(&MyWorkerInfo->wi_dobalance);
|
|
|
|
MyWorkerInfo->wi_cost_delay = 0;
|
|
|
|
|
|
|
|
MyWorkerInfo->wi_cost_limit = 0;
|
|
|
|
|
|
|
|
MyWorkerInfo->wi_cost_limit_base = 0;
|
|
|
|
|
|
|
|
dlist_push_head(&AutoVacuumShmem->av_freeWorkers,
|
|
|
|
dlist_push_head(&AutoVacuumShmem->av_freeWorkers,
|
|
|
|
&MyWorkerInfo->wi_links);
|
|
|
|
&MyWorkerInfo->wi_links);
|
|
|
|
/* not mine anymore */
|
|
|
|
/* not mine anymore */
|
|
|
@ -1781,10 +1785,20 @@ FreeWorkerInfo(int code, Datum arg)
|
|
|
|
void
|
|
|
|
void
|
|
|
|
VacuumUpdateCosts(void)
|
|
|
|
VacuumUpdateCosts(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
double original_cost_delay = vacuum_cost_delay;
|
|
|
|
|
|
|
|
int original_cost_limit = vacuum_cost_limit;
|
|
|
|
|
|
|
|
|
|
|
|
if (MyWorkerInfo)
|
|
|
|
if (MyWorkerInfo)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
vacuum_cost_delay = MyWorkerInfo->wi_cost_delay;
|
|
|
|
if (av_storage_param_cost_delay >= 0)
|
|
|
|
vacuum_cost_limit = MyWorkerInfo->wi_cost_limit;
|
|
|
|
vacuum_cost_delay = av_storage_param_cost_delay;
|
|
|
|
|
|
|
|
else if (autovacuum_vac_cost_delay >= 0)
|
|
|
|
|
|
|
|
vacuum_cost_delay = autovacuum_vac_cost_delay;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
/* fall back to VacuumCostDelay */
|
|
|
|
|
|
|
|
vacuum_cost_delay = VacuumCostDelay;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AutoVacuumUpdateCostLimit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -1792,88 +1806,128 @@ VacuumUpdateCosts(void)
|
|
|
|
vacuum_cost_delay = VacuumCostDelay;
|
|
|
|
vacuum_cost_delay = VacuumCostDelay;
|
|
|
|
vacuum_cost_limit = VacuumCostLimit;
|
|
|
|
vacuum_cost_limit = VacuumCostLimit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* If configuration changes are allowed to impact VacuumCostActive, make
|
|
|
|
|
|
|
|
* sure it is updated.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (VacuumFailsafeActive)
|
|
|
|
|
|
|
|
Assert(!VacuumCostActive);
|
|
|
|
|
|
|
|
else if (vacuum_cost_delay > 0)
|
|
|
|
|
|
|
|
VacuumCostActive = true;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
VacuumCostActive = false;
|
|
|
|
|
|
|
|
VacuumCostBalance = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MyWorkerInfo)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Oid dboid,
|
|
|
|
|
|
|
|
tableoid;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Only log updates to cost-related variables */
|
|
|
|
|
|
|
|
if (vacuum_cost_delay == original_cost_delay &&
|
|
|
|
|
|
|
|
vacuum_cost_limit == original_cost_limit)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert(!LWLockHeldByMe(AutovacuumLock));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LWLockAcquire(AutovacuumLock, LW_SHARED);
|
|
|
|
|
|
|
|
dboid = MyWorkerInfo->wi_dboid;
|
|
|
|
|
|
|
|
tableoid = MyWorkerInfo->wi_tableoid;
|
|
|
|
|
|
|
|
LWLockRelease(AutovacuumLock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elog(DEBUG2,
|
|
|
|
|
|
|
|
"Autovacuum VacuumUpdateCosts(db=%u, rel=%u, dobalance=%s, cost_limit=%d, cost_delay=%g active=%s failsafe=%s)",
|
|
|
|
|
|
|
|
dboid, tableoid, pg_atomic_unlocked_test_flag(&MyWorkerInfo->wi_dobalance) ? "no" : "yes",
|
|
|
|
|
|
|
|
vacuum_cost_limit, vacuum_cost_delay,
|
|
|
|
|
|
|
|
vacuum_cost_delay > 0 ? "yes" : "no",
|
|
|
|
|
|
|
|
VacuumFailsafeActive ? "yes" : "no");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* autovac_balance_cost
|
|
|
|
* Update vacuum_cost_limit with the correct value for an autovacuum worker,
|
|
|
|
* Recalculate the cost limit setting for each active worker.
|
|
|
|
* given the value of other relevant cost limit parameters and the number of
|
|
|
|
*
|
|
|
|
* workers across which the limit must be balanced. Autovacuum workers must
|
|
|
|
* Caller must hold the AutovacuumLock in exclusive mode.
|
|
|
|
* call this regularly in case av_nworkersForBalance has been updated by
|
|
|
|
|
|
|
|
* another worker or by the autovacuum launcher. They must also call it after a
|
|
|
|
|
|
|
|
* config reload.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
void
|
|
|
|
autovac_balance_cost(void)
|
|
|
|
AutoVacuumUpdateCostLimit(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!MyWorkerInfo)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* The idea here is that we ration out I/O equally. The amount of I/O
|
|
|
|
|
|
|
|
* that a worker can consume is determined by cost_limit/cost_delay, so we
|
|
|
|
|
|
|
|
* try to equalize those ratios rather than the raw limit settings.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* note: in cost_limit, zero also means use value from elsewhere, because
|
|
|
|
* note: in cost_limit, zero also means use value from elsewhere, because
|
|
|
|
* zero is not a valid value.
|
|
|
|
* zero is not a valid value.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
int vac_cost_limit = (autovacuum_vac_cost_limit > 0 ?
|
|
|
|
|
|
|
|
autovacuum_vac_cost_limit : VacuumCostLimit);
|
|
|
|
if (av_storage_param_cost_limit > 0)
|
|
|
|
double vac_cost_delay = (autovacuum_vac_cost_delay >= 0 ?
|
|
|
|
vacuum_cost_limit = av_storage_param_cost_limit;
|
|
|
|
autovacuum_vac_cost_delay : VacuumCostDelay);
|
|
|
|
else
|
|
|
|
double cost_total;
|
|
|
|
{
|
|
|
|
double cost_avail;
|
|
|
|
int nworkers_for_balance;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (autovacuum_vac_cost_limit > 0)
|
|
|
|
|
|
|
|
vacuum_cost_limit = autovacuum_vac_cost_limit;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
vacuum_cost_limit = VacuumCostLimit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Only balance limit if no cost-related storage parameters specified */
|
|
|
|
|
|
|
|
if (pg_atomic_unlocked_test_flag(&MyWorkerInfo->wi_dobalance))
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert(vacuum_cost_limit > 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nworkers_for_balance = pg_atomic_read_u32(&AutoVacuumShmem->av_nworkersForBalance);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* There is at least 1 autovac worker (this worker) */
|
|
|
|
|
|
|
|
if (nworkers_for_balance <= 0)
|
|
|
|
|
|
|
|
elog(ERROR, "nworkers_for_balance must be > 0");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vacuum_cost_limit = Max(vacuum_cost_limit / nworkers_for_balance, 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* autovac_recalculate_workers_for_balance
|
|
|
|
|
|
|
|
* Recalculate the number of workers to consider, given cost-related
|
|
|
|
|
|
|
|
* storage parameters and the current number of active workers.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Caller must hold the AutovacuumLock in at least shared mode to access
|
|
|
|
|
|
|
|
* worker->wi_proc.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
|
|
autovac_recalculate_workers_for_balance(void)
|
|
|
|
|
|
|
|
{
|
|
|
|
dlist_iter iter;
|
|
|
|
dlist_iter iter;
|
|
|
|
|
|
|
|
int orig_nworkers_for_balance;
|
|
|
|
|
|
|
|
int nworkers_for_balance = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/* not set? nothing to do */
|
|
|
|
Assert(LWLockHeldByMe(AutovacuumLock));
|
|
|
|
if (vac_cost_limit <= 0 || vac_cost_delay <= 0)
|
|
|
|
|
|
|
|
return;
|
|
|
|
orig_nworkers_for_balance =
|
|
|
|
|
|
|
|
pg_atomic_read_u32(&AutoVacuumShmem->av_nworkersForBalance);
|
|
|
|
|
|
|
|
|
|
|
|
/* calculate the total base cost limit of participating active workers */
|
|
|
|
|
|
|
|
cost_total = 0.0;
|
|
|
|
|
|
|
|
dlist_foreach(iter, &AutoVacuumShmem->av_runningWorkers)
|
|
|
|
dlist_foreach(iter, &AutoVacuumShmem->av_runningWorkers)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
WorkerInfo worker = dlist_container(WorkerInfoData, wi_links, iter.cur);
|
|
|
|
WorkerInfo worker = dlist_container(WorkerInfoData, wi_links, iter.cur);
|
|
|
|
|
|
|
|
|
|
|
|
if (worker->wi_proc != NULL &&
|
|
|
|
if (worker->wi_proc == NULL ||
|
|
|
|
worker->wi_dobalance &&
|
|
|
|
pg_atomic_unlocked_test_flag(&worker->wi_dobalance))
|
|
|
|
worker->wi_cost_limit_base > 0 && worker->wi_cost_delay > 0)
|
|
|
|
continue;
|
|
|
|
cost_total +=
|
|
|
|
|
|
|
|
(double) worker->wi_cost_limit_base / worker->wi_cost_delay;
|
|
|
|
nworkers_for_balance++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* there are no cost limits -- nothing to do */
|
|
|
|
if (nworkers_for_balance != orig_nworkers_for_balance)
|
|
|
|
if (cost_total <= 0)
|
|
|
|
pg_atomic_write_u32(&AutoVacuumShmem->av_nworkersForBalance,
|
|
|
|
return;
|
|
|
|
nworkers_for_balance);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Adjust cost limit of each active worker to balance the total of cost
|
|
|
|
|
|
|
|
* limit to autovacuum_vacuum_cost_limit.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
cost_avail = (double) vac_cost_limit / vac_cost_delay;
|
|
|
|
|
|
|
|
dlist_foreach(iter, &AutoVacuumShmem->av_runningWorkers)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
WorkerInfo worker = dlist_container(WorkerInfoData, wi_links, iter.cur);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (worker->wi_proc != NULL &&
|
|
|
|
|
|
|
|
worker->wi_dobalance &&
|
|
|
|
|
|
|
|
worker->wi_cost_limit_base > 0 && worker->wi_cost_delay > 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int limit = (int)
|
|
|
|
|
|
|
|
(cost_avail * worker->wi_cost_limit_base / cost_total);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* We put a lower bound of 1 on the cost_limit, to avoid division-
|
|
|
|
|
|
|
|
* by-zero in the vacuum code. Also, in case of roundoff trouble
|
|
|
|
|
|
|
|
* in these calculations, let's be sure we don't ever set
|
|
|
|
|
|
|
|
* cost_limit to more than the base value.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
worker->wi_cost_limit = Max(Min(limit,
|
|
|
|
|
|
|
|
worker->wi_cost_limit_base),
|
|
|
|
|
|
|
|
1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (worker->wi_proc != NULL)
|
|
|
|
|
|
|
|
elog(DEBUG2, "autovac_balance_cost(pid=%d db=%u, rel=%u, dobalance=%s cost_limit=%d, cost_limit_base=%d, cost_delay=%g)",
|
|
|
|
|
|
|
|
worker->wi_proc->pid, worker->wi_dboid, worker->wi_tableoid,
|
|
|
|
|
|
|
|
worker->wi_dobalance ? "yes" : "no",
|
|
|
|
|
|
|
|
worker->wi_cost_limit, worker->wi_cost_limit_base,
|
|
|
|
|
|
|
|
worker->wi_cost_delay);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
@ -2421,23 +2475,34 @@ do_autovacuum(void)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Must hold AutovacuumLock while mucking with cost balance info */
|
|
|
|
/*
|
|
|
|
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
|
|
|
|
* Save the cost-related storage parameter values in global variables
|
|
|
|
|
|
|
|
* for reference when updating vacuum_cost_delay and vacuum_cost_limit
|
|
|
|
|
|
|
|
* during vacuuming this table.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
av_storage_param_cost_delay = tab->at_storage_param_vac_cost_delay;
|
|
|
|
|
|
|
|
av_storage_param_cost_limit = tab->at_storage_param_vac_cost_limit;
|
|
|
|
|
|
|
|
|
|
|
|
/* advertise my cost delay parameters for the balancing algorithm */
|
|
|
|
/*
|
|
|
|
MyWorkerInfo->wi_dobalance = tab->at_dobalance;
|
|
|
|
* We only expect this worker to ever set the flag, so don't bother
|
|
|
|
MyWorkerInfo->wi_cost_delay = tab->at_vacuum_cost_delay;
|
|
|
|
* checking the return value. We shouldn't have to retry.
|
|
|
|
MyWorkerInfo->wi_cost_limit = tab->at_vacuum_cost_limit;
|
|
|
|
*/
|
|
|
|
MyWorkerInfo->wi_cost_limit_base = tab->at_vacuum_cost_limit;
|
|
|
|
if (tab->at_dobalance)
|
|
|
|
|
|
|
|
pg_atomic_test_set_flag(&MyWorkerInfo->wi_dobalance);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
pg_atomic_clear_flag(&MyWorkerInfo->wi_dobalance);
|
|
|
|
|
|
|
|
|
|
|
|
/* do a balance */
|
|
|
|
LWLockAcquire(AutovacuumLock, LW_SHARED);
|
|
|
|
autovac_balance_cost();
|
|
|
|
autovac_recalculate_workers_for_balance();
|
|
|
|
|
|
|
|
LWLockRelease(AutovacuumLock);
|
|
|
|
|
|
|
|
|
|
|
|
/* set the active cost parameters from the result of that */
|
|
|
|
/*
|
|
|
|
|
|
|
|
* We wait until this point to update cost delay and cost limit
|
|
|
|
|
|
|
|
* values, even though we reloaded the configuration file above, so
|
|
|
|
|
|
|
|
* that we can take into account the cost-related storage parameters.
|
|
|
|
|
|
|
|
*/
|
|
|
|
VacuumUpdateCosts();
|
|
|
|
VacuumUpdateCosts();
|
|
|
|
|
|
|
|
|
|
|
|
/* done */
|
|
|
|
|
|
|
|
LWLockRelease(AutovacuumLock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* clean up memory before each iteration */
|
|
|
|
/* clean up memory before each iteration */
|
|
|
|
MemoryContextResetAndDeleteChildren(PortalContext);
|
|
|
|
MemoryContextResetAndDeleteChildren(PortalContext);
|
|
|
@ -2521,16 +2586,17 @@ deleted:
|
|
|
|
pfree(tab);
|
|
|
|
pfree(tab);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Remove my info from shared memory. We could, but intentionally
|
|
|
|
* Remove my info from shared memory. We set wi_dobalance on the
|
|
|
|
* don't, clear wi_cost_limit and friends --- this is on the
|
|
|
|
* assumption that we are more likely than not to vacuum a table with
|
|
|
|
* assumption that we probably have more to do with similar cost
|
|
|
|
* no cost-related storage parameters next, so we want to claim our
|
|
|
|
* settings, so we don't want to give up our share of I/O for a very
|
|
|
|
* share of I/O as soon as possible to avoid thrashing the global
|
|
|
|
* short interval and thereby thrash the global balance.
|
|
|
|
* balance.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
LWLockAcquire(AutovacuumScheduleLock, LW_EXCLUSIVE);
|
|
|
|
LWLockAcquire(AutovacuumScheduleLock, LW_EXCLUSIVE);
|
|
|
|
MyWorkerInfo->wi_tableoid = InvalidOid;
|
|
|
|
MyWorkerInfo->wi_tableoid = InvalidOid;
|
|
|
|
MyWorkerInfo->wi_sharedrel = false;
|
|
|
|
MyWorkerInfo->wi_sharedrel = false;
|
|
|
|
LWLockRelease(AutovacuumScheduleLock);
|
|
|
|
LWLockRelease(AutovacuumScheduleLock);
|
|
|
|
|
|
|
|
pg_atomic_test_set_flag(&MyWorkerInfo->wi_dobalance);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
@ -2562,6 +2628,7 @@ deleted:
|
|
|
|
{
|
|
|
|
{
|
|
|
|
ConfigReloadPending = false;
|
|
|
|
ConfigReloadPending = false;
|
|
|
|
ProcessConfigFile(PGC_SIGHUP);
|
|
|
|
ProcessConfigFile(PGC_SIGHUP);
|
|
|
|
|
|
|
|
VacuumUpdateCosts();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
|
|
|
|
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
|
|
|
@ -2797,8 +2864,6 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
|
|
|
|
int freeze_table_age;
|
|
|
|
int freeze_table_age;
|
|
|
|
int multixact_freeze_min_age;
|
|
|
|
int multixact_freeze_min_age;
|
|
|
|
int multixact_freeze_table_age;
|
|
|
|
int multixact_freeze_table_age;
|
|
|
|
int vac_cost_limit;
|
|
|
|
|
|
|
|
double vac_cost_delay;
|
|
|
|
|
|
|
|
int log_min_duration;
|
|
|
|
int log_min_duration;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
@ -2808,20 +2873,6 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
|
|
|
|
* defaults, autovacuum's own first and plain vacuum second.
|
|
|
|
* defaults, autovacuum's own first and plain vacuum second.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* -1 in autovac setting means use plain vacuum_cost_delay */
|
|
|
|
|
|
|
|
vac_cost_delay = (avopts && avopts->vacuum_cost_delay >= 0)
|
|
|
|
|
|
|
|
? avopts->vacuum_cost_delay
|
|
|
|
|
|
|
|
: (autovacuum_vac_cost_delay >= 0)
|
|
|
|
|
|
|
|
? autovacuum_vac_cost_delay
|
|
|
|
|
|
|
|
: VacuumCostDelay;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 0 or -1 in autovac setting means use plain vacuum_cost_limit */
|
|
|
|
|
|
|
|
vac_cost_limit = (avopts && avopts->vacuum_cost_limit > 0)
|
|
|
|
|
|
|
|
? avopts->vacuum_cost_limit
|
|
|
|
|
|
|
|
: (autovacuum_vac_cost_limit > 0)
|
|
|
|
|
|
|
|
? autovacuum_vac_cost_limit
|
|
|
|
|
|
|
|
: VacuumCostLimit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -1 in autovac setting means use log_autovacuum_min_duration */
|
|
|
|
/* -1 in autovac setting means use log_autovacuum_min_duration */
|
|
|
|
log_min_duration = (avopts && avopts->log_min_duration >= 0)
|
|
|
|
log_min_duration = (avopts && avopts->log_min_duration >= 0)
|
|
|
|
? avopts->log_min_duration
|
|
|
|
? avopts->log_min_duration
|
|
|
@ -2877,8 +2928,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
|
|
|
|
tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age;
|
|
|
|
tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age;
|
|
|
|
tab->at_params.is_wraparound = wraparound;
|
|
|
|
tab->at_params.is_wraparound = wraparound;
|
|
|
|
tab->at_params.log_min_duration = log_min_duration;
|
|
|
|
tab->at_params.log_min_duration = log_min_duration;
|
|
|
|
tab->at_vacuum_cost_limit = vac_cost_limit;
|
|
|
|
tab->at_storage_param_vac_cost_limit = avopts ?
|
|
|
|
tab->at_vacuum_cost_delay = vac_cost_delay;
|
|
|
|
avopts->vacuum_cost_limit : 0;
|
|
|
|
|
|
|
|
tab->at_storage_param_vac_cost_delay = avopts ?
|
|
|
|
|
|
|
|
avopts->vacuum_cost_delay : -1;
|
|
|
|
tab->at_relname = NULL;
|
|
|
|
tab->at_relname = NULL;
|
|
|
|
tab->at_nspname = NULL;
|
|
|
|
tab->at_nspname = NULL;
|
|
|
|
tab->at_datname = NULL;
|
|
|
|
tab->at_datname = NULL;
|
|
|
@ -3382,8 +3435,14 @@ AutoVacuumShmemInit(void)
|
|
|
|
|
|
|
|
|
|
|
|
/* initialize the WorkerInfo free list */
|
|
|
|
/* initialize the WorkerInfo free list */
|
|
|
|
for (i = 0; i < autovacuum_max_workers; i++)
|
|
|
|
for (i = 0; i < autovacuum_max_workers; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
dlist_push_head(&AutoVacuumShmem->av_freeWorkers,
|
|
|
|
dlist_push_head(&AutoVacuumShmem->av_freeWorkers,
|
|
|
|
&worker[i].wi_links);
|
|
|
|
&worker[i].wi_links);
|
|
|
|
|
|
|
|
pg_atomic_init_flag(&worker[i].wi_dobalance);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pg_atomic_init_u32(&AutoVacuumShmem->av_nworkersForBalance, 0);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
Assert(found);
|
|
|
|
Assert(found);
|
|
|
|