step1-permanent_process.diff
text/x-diff
Filename: step1-permanent_process.diff
Type: text/x-diff
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/access/transam/varsup.c | 11 | 3 |
| src/backend/postmaster/autovacuum.c | 319 | 194 |
| src/backend/postmaster/postmaster.c | 6 | 34 |
| src/backend/storage/ipc/imsg.c | 11 | 0 |
| src/backend/storage/lmgr/proc.c | 3 | 7 |
| src/backend/utils/misc/guc.c | 19 | 2 |
| src/backend/utils/misc/postgresql.conf.sample | 15 | 3 |
| src/include/postmaster/autovacuum.h | 5 | 11 |
| src/include/storage/imsg.h | 14 | 0 |
| src/include/storage/pmsignal.h | 0 | 1 |
*** src/backend/access/transam/varsup.c 58aea89cb33fe0ee2cb3e10c0a714cd0057a8bdb
--- src/backend/access/transam/varsup.c 058cb2f268e956e37724f1d05d98946d1cc56ab4
*************** GetNewTransactionId(bool isSubXact)
*** 46,51 ****
--- 46,52 ----
GetNewTransactionId(bool isSubXact)
{
TransactionId xid;
+ IMessage *msg;
/*
* During bootstrap initialization, we return the special bootstrap
*************** GetNewTransactionId(bool isSubXact)
*** 94,105 ****
LWLockRelease(XidGenLock);
/*
! * To avoid swamping the postmaster with signals, we issue the autovac
* request only once per 64K transaction starts. This still gives
* plenty of chances before we get into real trouble.
*/
if (IsUnderPostmaster && (xid % 65536) == 0)
! SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
if (IsUnderPostmaster &&
TransactionIdFollowsOrEquals(xid, xidStopLimit))
--- 95,109 ----
LWLockRelease(XidGenLock);
/*
! * To avoid swamping the coordinator with signals, we issue the autovac
* request only once per 64K transaction starts. This still gives
* plenty of chances before we get into real trouble.
*/
if (IsUnderPostmaster && (xid % 65536) == 0)
! {
! msg = IMessageCreate(IMSGT_FORCE_VACUUM, 0);
! IMessageActivate(msg, GetAutovacuumLauncherId());
! }
if (IsUnderPostmaster &&
TransactionIdFollowsOrEquals(xid, xidStopLimit))
*************** SetTransactionIdLimit(TransactionId olde
*** 258,263 ****
--- 262,268 ----
TransactionId xidStopLimit;
TransactionId xidWrapLimit;
TransactionId curXid;
+ IMessage *msg;
Assert(TransactionIdIsNormal(oldest_datfrozenxid));
*************** SetTransactionIdLimit(TransactionId olde
*** 341,347 ****
*/
if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) &&
IsUnderPostmaster && !InRecovery)
! SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
/* Give an immediate warning if past the wrap warn point */
if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit) && !InRecovery)
--- 346,355 ----
*/
if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) &&
IsUnderPostmaster && !InRecovery)
! {
! msg = IMessageCreate(IMSGT_FORCE_VACUUM, 0);
! IMessageActivate(msg, GetAutovacuumLauncherId());
! }
/* Give an immediate warning if past the wrap warn point */
if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit) && !InRecovery)
============================================================
*** src/backend/postmaster/postmaster.c 13da26f5fb9a09c47a8dc3b30f0bbfdb1da0420c
--- src/backend/postmaster/postmaster.c e6a455be46eee967cafa76cef125cedef4ba986f
*************** bool redirection_done = false; /* stder
*** 294,301 ****
bool redirection_done = false; /* stderr redirected for syslogger? */
- /* received START_AUTOVAC_LAUNCHER signal */
- static volatile sig_atomic_t start_autovac_launcher = false;
/* the launcher needs to be signalled to communicate some condition */
static volatile bool avlauncher_needs_signal = false;
--- 294,299 ----
*************** ServerLoop(void)
*** 1463,1476 ****
WalWriterPID = StartWalWriter();
/* If we have lost the autovacuum launcher, try to start a new one */
! if (AutoVacPID == 0 &&
! (AutoVacuumingActive() || start_autovac_launcher) &&
! pmState == PM_RUN)
! {
AutoVacPID = StartAutoVacLauncher();
- if (AutoVacPID != 0)
- start_autovac_launcher = false; /* signal processed */
- }
/* If we have lost the archiver, try to start a new one */
if (XLogArchivingActive() && PgArchPID == 0 && pmState == PM_RUN)
--- 1461,1468 ----
WalWriterPID = StartWalWriter();
/* If we have lost the autovacuum launcher, try to start a new one */
! if (AutoVacPID == 0 && pmState == PM_RUN)
AutoVacPID = StartAutoVacLauncher();
/* If we have lost the archiver, try to start a new one */
if (XLogArchivingActive() && PgArchPID == 0 && pmState == PM_RUN)
*************** reaper(SIGNAL_ARGS)
*** 2390,2396 ****
*/
if (WalWriterPID == 0)
WalWriterPID = StartWalWriter();
! if (AutoVacuumingActive() && AutoVacPID == 0)
AutoVacPID = StartAutoVacLauncher();
if (XLogArchivingActive() && PgArchPID == 0)
PgArchPID = pgarch_start();
--- 2382,2388 ----
*/
if (WalWriterPID == 0)
WalWriterPID = StartWalWriter();
! if (AutoVacPID == 0)
AutoVacPID = StartAutoVacLauncher();
if (XLogArchivingActive() && PgArchPID == 0)
PgArchPID = pgarch_start();
*************** sigusr1_handler(SIGNAL_ARGS)
*** 4198,4217 ****
signal_child(SysLoggerPID, SIGUSR1);
}
- if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER))
- {
- /*
- * Start one iteration of the autovacuum daemon, even if autovacuuming
- * is nominally not enabled. This is so we can have an active defense
- * against transaction ID wraparound. We set a flag for the main loop
- * to do it rather than trying to do it here --- this is because the
- * autovac process itself may send the signal, and we want to handle
- * that by launching another iteration as soon as the current one
- * completes.
- */
- start_autovac_launcher = true;
- }
-
if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER))
{
/* The autovacuum launcher wants us to start a worker process. */
--- 4190,4195 ----
*************** StartAutovacuumWorker(void)
*** 4518,4536 ****
}
/*
! * Report the failure to the launcher, if it's running. (If it's not, we
! * might not even be connected to shared memory, so don't try to call
! * AutoVacWorkerFailed.) Note that we also need to signal it so that it
! * responds to the condition, but we don't do that here, instead waiting
! * for ServerLoop to do it. This way we avoid a ping-pong signalling in
! * quick succession between the autovac launcher and postmaster in case
! * things get ugly.
*/
if (AutoVacPID != 0)
- {
- AutoVacWorkerFailed();
avlauncher_needs_signal = true;
- }
}
/*
--- 4496,4508 ----
}
/*
! * Report the failure to the coordinator, if it's running. Note that we
! * wait for the ServerLoop to actually trigger the signal. This way we
! * avoid a ping-pong signalling in quick succession between coordinator
! * and postmaster in case things get ugly.
*/
if (AutoVacPID != 0)
avlauncher_needs_signal = true;
}
/*
============================================================
*** src/backend/storage/lmgr/proc.c 410c53ed63ba8902d9747e9ad91a639e21195411
--- src/backend/storage/lmgr/proc.c bbd84c0cdc85587bd4e04f1b69ead6ea11bb08dd
*************** InitProcess(void)
*** 263,276 ****
set_spins_per_delay(procglobal->spins_per_delay);
! if (IsAnyAutoVacuumProcess())
MyProc = procglobal->autovacFreeProcs;
else
MyProc = procglobal->freeProcs;
if (MyProc != NULL)
{
! if (IsAnyAutoVacuumProcess())
procglobal->autovacFreeProcs = (PGPROC *) MyProc->links.next;
else
procglobal->freeProcs = (PGPROC *) MyProc->links.next;
--- 263,276 ----
set_spins_per_delay(procglobal->spins_per_delay);
! if (IsAutoVacuumLauncherProcess() || IsAutoVacuumWorkerProcess())
MyProc = procglobal->autovacFreeProcs;
else
MyProc = procglobal->freeProcs;
if (MyProc != NULL)
{
! if (IsAutoVacuumLauncherProcess() || IsAutoVacuumWorkerProcess())
procglobal->autovacFreeProcs = (PGPROC *) MyProc->links.next;
else
procglobal->freeProcs = (PGPROC *) MyProc->links.next;
*************** ProcKill(int code, Datum arg)
*** 682,688 ****
SpinLockAcquire(ProcStructLock);
/* Return PGPROC structure (and semaphore) to appropriate freelist */
! if (IsAnyAutoVacuumProcess())
{
MyProc->links.next = (SHM_QUEUE *) procglobal->autovacFreeProcs;
procglobal->autovacFreeProcs = MyProc;
--- 682,688 ----
SpinLockAcquire(ProcStructLock);
/* Return PGPROC structure (and semaphore) to appropriate freelist */
! if (IsAutoVacuumLauncherProcess() || IsAutoVacuumWorkerProcess())
{
MyProc->links.next = (SHM_QUEUE *) procglobal->autovacFreeProcs;
procglobal->autovacFreeProcs = MyProc;
*************** ProcKill(int code, Datum arg)
*** 708,717 ****
*/
if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess())
MarkPostmasterChildInactive();
-
- /* wake autovac launcher if needed -- see comments in FreeWorkerInfo */
- if (AutovacuumLauncherPid != 0)
- kill(AutovacuumLauncherPid, SIGUSR2);
}
/*
--- 708,713 ----
============================================================
*** src/backend/utils/misc/guc.c 0d02c70862077335d5f009dc9f295b2dc7071c52
--- src/backend/utils/misc/guc.c b1a0bdd9b727094182159680278763a09f3ded9c
*************** static struct config_bool ConfigureNames
*** 935,944 ****
{
{"autovacuum", PGC_SIGHUP, AUTOVACUUM,
! gettext_noop("Starts the autovacuum subprocess."),
NULL
},
! &autovacuum_start_daemon,
true, NULL, NULL
},
--- 935,944 ----
{
{"autovacuum", PGC_SIGHUP, AUTOVACUUM,
! gettext_noop("Enable automatic vacuuming."),
NULL
},
! &autovacuum_enabled,
true, NULL, NULL
},
*************** static struct config_int ConfigureNamesI
*** 1941,1946 ****
--- 1941,1963 ----
},
{
+ {"min_spare_background_workers", PGC_POSTMASTER, AUTOVACUUM,
+ gettext_noop("Sets the maximum number of simultaneously running autovacuum worker processes."),
+ NULL
+ },
+ &min_spare_background_workers,
+ 0, 0, INT_MAX / 4, NULL, NULL
+ },
+ {
+ {"max_spare_background_workers", PGC_POSTMASTER, AUTOVACUUM,
+ gettext_noop("Sets the maximum number of simultaneously running autovacuum worker processes."),
+ NULL
+ },
+ &max_spare_background_workers,
+ 0, 0, INT_MAX / 4, NULL, NULL
+ },
+
+ {
{"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
gettext_noop("Time to sleep between autovacuum runs."),
NULL,
============================================================
*** src/backend/utils/misc/postgresql.conf.sample 3b137fa18da4ec43ae76dc954fd19449556fbdce
--- src/backend/utils/misc/postgresql.conf.sample 14a99f6b70482f481ccd82dad86e31a9421c9336
***************
*** 404,419 ****
#------------------------------------------------------------------------------
# AUTOVACUUM PARAMETERS
#------------------------------------------------------------------------------
! #autovacuum = on # Enable autovacuum subprocess? 'on'
! # requires track_counts to also be on.
#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
- #autovacuum_max_workers = 3 # max number of autovacuum subprocesses
#autovacuum_naptime = 1min # time between autovacuum runs
#autovacuum_vacuum_threshold = 50 # min number of row updates before
# vacuum
--- 404,431 ----
#------------------------------------------------------------------------------
+ # BACKGROUND WORKER PARAMETERS (including autovacuum)
+ #------------------------------------------------------------------------------
+
+ #autovacuum_max_workers = 3 # max number of background helper
+ # subprocesses (for all databases)
+
+ #min_spare_background_helpers = 0 # min spare workers to prefork and
+ # keep waiting for jobs, per database
+ #max_spare_background_helpers = 0 # max spare helpers per database
+
+
+
+ #------------------------------------------------------------------------------
# AUTOVACUUM PARAMETERS
#------------------------------------------------------------------------------
! #autovacuum = on # Enable autovacuum? 'on' requires
! # track_counts to also be on.
#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
#autovacuum_naptime = 1min # time between autovacuum runs
#autovacuum_vacuum_threshold = 50 # min number of row updates before
# vacuum
============================================================
*** src/include/storage/pmsignal.h 517450db2bab1f2a3dd7320a273b8e7320c29bac
--- src/include/storage/pmsignal.h c8113d31e2e76fc64ad82209ff2fb8aea91f68b3
*************** typedef enum
*** 26,32 ****
PMSIGNAL_BEGIN_HOT_STANDBY, /* begin Hot Standby */
PMSIGNAL_WAKEN_ARCHIVER, /* send a NOTIFY signal to xlog archiver */
PMSIGNAL_ROTATE_LOGFILE, /* send SIGUSR1 to syslogger to rotate logfile */
- PMSIGNAL_START_AUTOVAC_LAUNCHER, /* start an autovacuum launcher */
PMSIGNAL_START_AUTOVAC_WORKER, /* start an autovacuum worker */
PMSIGNAL_START_WALRECEIVER, /* start a walreceiver */
--- 26,31 ----
============================================================
*** src/backend/postmaster/autovacuum.c e0cb7d340f41ac1fd6f3d6709cb9ab42052a31ab
--- src/backend/postmaster/autovacuum.c 3b9cbe9ba0d576b32d490f21969b073a7ec55b98
***************
*** 101,108 ****
/*
* GUC parameters
*/
! bool autovacuum_start_daemon = false;
int autovacuum_max_workers;
int autovacuum_naptime;
int autovacuum_vac_thresh;
double autovacuum_vac_scale;
--- 101,110 ----
/*
* GUC parameters
*/
! bool autovacuum_enabled = false;
int autovacuum_max_workers;
+ int min_spare_background_workers;
+ int max_spare_background_workers;
int autovacuum_naptime;
int autovacuum_vac_thresh;
double autovacuum_vac_scale;
*************** typedef struct autovac_table
*** 188,199 ****
* an array of these in shared memory, sized according to
* autovacuum_max_workers.
*
! * wi_links entry into free list or running list
! * wi_dboid OID of the database this worker is supposed to work on
! * wi_tableoid OID of the table currently being vacuumed
! * wi_proc pointer to PGPROC of the running worker, NULL if not started
! * wi_launchtime Time at which this worker was launched
! * wi_cost_* Vacuum cost-based delay parameters current in this worker
*
* All fields are protected by AutovacuumLock, except for wi_tableoid which is
* protected by AutovacuumScheduleLock (which is read-only for everyone except
--- 190,201 ----
* an array of these in shared memory, sized according to
* autovacuum_max_workers.
*
! * wi_links entry into free list or running list
! * wi_dboid OID of the database this worker is supposed to work on
! * wi_tableoid OID of the table currently being vacuumed
! * wi_backend_id id of the running worker backend, NULL if not started
! * wi_launchtime Time at which this worker was launched
! * wi_cost_* Vacuum cost-based delay parameters current in this worker
*
* All fields are protected by AutovacuumLock, except for wi_tableoid which is
* protected by AutovacuumScheduleLock (which is read-only for everyone except
*************** typedef struct WorkerInfoData
*** 205,211 ****
SHM_QUEUE wi_links;
Oid wi_dboid;
Oid wi_tableoid;
! PGPROC *wi_proc;
TimestampTz wi_launchtime;
int wi_cost_delay;
int wi_cost_limit;
--- 207,213 ----
SHM_QUEUE wi_links;
Oid wi_dboid;
Oid wi_tableoid;
! BackendId wi_backend_id;
TimestampTz wi_launchtime;
int wi_cost_delay;
int wi_cost_limit;
*************** typedef struct WorkerInfoData *WorkerInf
*** 214,250 ****
typedef struct WorkerInfoData *WorkerInfo;
- /*
- * Possible signals received by the launcher from remote processes. These are
- * stored atomically in shared memory so that other processes can set them
- * without locking.
- */
- typedef enum
- {
- AutoVacForkFailed, /* failed trying to start a worker */
- AutoVacRebalance, /* rebalance the cost limits */
- AutoVacNumSignals /* must be last */
- } AutoVacuumSignal;
-
/*-------------
* The main autovacuum shmem struct. On shared memory we store this main
* struct and the array of WorkerInfo structs. This struct keeps:
*
! * av_signal set by other processes to indicate various conditions
! * av_launcherpid the PID of the autovacuum launcher
* av_freeWorkers the WorkerInfo freelist
* av_runningWorkers the WorkerInfo non-free queue
* av_startingWorker pointer to WorkerInfo currently being started (cleared by
* the worker itself as soon as it's up and running)
*
! * This struct is protected by AutovacuumLock, except for av_signal and parts
! * of the worker list (see above).
*-------------
*/
typedef struct
{
! sig_atomic_t av_signal[AutoVacNumSignals];
! pid_t av_launcherpid;
WorkerInfo av_freeWorkers;
SHM_QUEUE av_runningWorkers;
WorkerInfo av_startingWorker;
--- 216,238 ----
typedef struct WorkerInfoData *WorkerInfo;
/*-------------
* The main autovacuum shmem struct. On shared memory we store this main
* struct and the array of WorkerInfo structs. This struct keeps:
*
! * av_launcherid the BackendId of the autovacuum launcher
* av_freeWorkers the WorkerInfo freelist
* av_runningWorkers the WorkerInfo non-free queue
* av_startingWorker pointer to WorkerInfo currently being started (cleared by
* the worker itself as soon as it's up and running)
*
! * This struct is protected by AutovacuumLock, except for parts of the worker
! * list (see above).
*-------------
*/
typedef struct
{
! BackendId av_launcherid;
WorkerInfo av_freeWorkers;
SHM_QUEUE av_runningWorkers;
WorkerInfo av_startingWorker;
*************** static WorkerInfo MyWorkerInfo = NULL;
*** 259,277 ****
/* Pointer to my own WorkerInfo, valid on each worker */
static WorkerInfo MyWorkerInfo = NULL;
- /* PID of launcher, valid only in worker while shutting down */
- int AutovacuumLauncherPid = 0;
#ifdef EXEC_BACKEND
static pid_t avlauncher_forkexec(void);
static pid_t avworker_forkexec(void);
#endif
NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]);
NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]);
! static Oid do_start_worker(void);
! static void launcher_determine_sleep(bool canlaunch, bool recursing,
! struct timeval * nap);
static void launch_worker(TimestampTz now);
static List *get_database_list(void);
static void rebuild_database_list(Oid newdb);
--- 247,267 ----
/* Pointer to my own WorkerInfo, valid on each worker */
static WorkerInfo MyWorkerInfo = NULL;
#ifdef EXEC_BACKEND
static pid_t avlauncher_forkexec(void);
static pid_t avworker_forkexec(void);
#endif
NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]);
+ static void handle_imessage(IMessage *msg);
NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]);
! static void CoordinatorMaybeTriggerAutoVacuum(void);
!
! static void do_start_worker(avw_dbase *avdb);
! static Oid do_start_autovacuum_worker(void);
! static void launcher_determine_sleep(bool can_launch, bool recursing,
! struct timeval *nap);
static void launch_worker(TimestampTz now);
static List *get_database_list(void);
static void rebuild_database_list(Oid newdb);
*************** AutoVacLauncherMain(int argc, char *argv
*** 386,391 ****
--- 376,382 ----
AutoVacLauncherMain(int argc, char *argv[])
{
sigjmp_buf local_sigjmp_buf;
+ IMessage *msg = NULL;
/* we are a postmaster subprocess now */
IsUnderPostmaster = true;
*************** AutoVacLauncherMain(int argc, char *argv
*** 526,540 ****
/* must unblock signals before calling rebuild_database_list */
PG_SETMASK(&UnBlockSig);
! /* in emergency mode, just start a worker and go away */
! if (!AutoVacuumingActive())
! {
! do_start_worker();
! proc_exit(0); /* done */
! }
- AutoVacuumShmem->av_launcherpid = MyProcPid;
-
/*
* Create the initial database list. The invariant we want this list to
* keep is that it's ordered by decreasing next_time. As soon as an entry
--- 517,524 ----
/* must unblock signals before calling rebuild_database_list */
PG_SETMASK(&UnBlockSig);
! AutoVacuumShmem->av_launcherid = MyBackendId;
/*
* Create the initial database list. The invariant we want this list to
* keep is that it's ordered by decreasing next_time. As soon as an entry
*************** AutoVacLauncherMain(int argc, char *argv
*** 547,555 ****
for (;;)
{
struct timeval nap;
- TimestampTz current_time = 0;
- bool can_launch;
- Dlelem *elem;
/*
* Emergency bailout if postmaster has died. This is to avoid the
--- 531,536 ----
*************** AutoVacLauncherMain(int argc, char *argv
*** 595,601 ****
if (!PostmasterIsAlive(true))
proc_exit(1);
! if (got_SIGTERM || got_SIGHUP || got_SIGUSR2)
break;
}
--- 576,583 ----
if (!PostmasterIsAlive(true))
proc_exit(1);
! msg = IMessageCheck();
! if (got_SIGTERM || got_SIGHUP || got_SIGUSR2 || msg)
break;
}
*************** AutoVacLauncherMain(int argc, char *argv
*** 607,619 ****
if (got_SIGHUP)
{
got_SIGHUP = false;
ProcessConfigFile(PGC_SIGHUP);
- /* shutdown requested in config file? */
- if (!AutoVacuumingActive())
- break;
-
/* rebalance in case the default cost parameters changed */
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
autovac_balance_cost();
--- 589,601 ----
if (got_SIGHUP)
{
+ #ifdef COORDINATOR_DEBUG
+ elog(DEBUG5, "Coordinator: got SIGHUP");
+ #endif
+
got_SIGHUP = false;
ProcessConfigFile(PGC_SIGHUP);
/* rebalance in case the default cost parameters changed */
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
autovac_balance_cost();
*************** AutoVacLauncherMain(int argc, char *argv
*** 624,647 ****
}
/*
! * a worker finished, or postmaster signalled failure to start a
! * worker
*/
if (got_SIGUSR2)
{
got_SIGUSR2 = false;
! /* rebalance cost limits, if needed */
! if (AutoVacuumShmem->av_signal[AutoVacRebalance])
{
- LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
- AutoVacuumShmem->av_signal[AutoVacRebalance] = false;
- autovac_balance_cost();
- LWLockRelease(AutovacuumLock);
- }
- if (AutoVacuumShmem->av_signal[AutoVacForkFailed])
- {
/*
* If the postmaster failed to start a new worker, we sleep
* for a little while and resend the signal. The new worker's
--- 606,624 ----
}
/*
! * postmaster signalled failure to start a worker
*/
if (got_SIGUSR2)
{
+ #ifdef COORDINATOR_DEBUG
+ elog(DEBUG5, "Coordinator: got SIGUSR2");
+ #endif
+
got_SIGUSR2 = false;
! /* FIXME: fix indentation after merging */
{
/*
* If the postmaster failed to start a new worker, we sleep
* for a little while and resend the signal. The new worker's
*************** AutoVacLauncherMain(int argc, char *argv
*** 651,665 ****
* XXX should we put a limit to the number of times we retry?
* I don't think it makes much sense, because a future start
* of a worker will continue to fail in the same way.
*/
- AutoVacuumShmem->av_signal[AutoVacForkFailed] = false;
pg_usleep(1000000L); /* 1s */
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
continue;
}
}
/*
* There are some conditions that we need to check before trying to
* start a launcher. First, we need to make sure that there is a
* launcher slot available. Second, we need to make sure that no
--- 628,740 ----
* XXX should we put a limit to the number of times we retry?
* I don't think it makes much sense, because a future start
* of a worker will continue to fail in the same way.
+ *
+ * FIXME: for the autovac launcher, it might have been okay
+ * to just sleep. But the coordinator needs to remain
+ * as responsive as possible, even if the postmaster
+ * is currently unable to fork new workers.
*/
pg_usleep(1000000L); /* 1s */
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
continue;
}
}
+ /* handle pending imessages */
+ while (msg != NULL)
+ {
+ handle_imessage(msg);
+ msg = IMessageCheck();
+ }
+
/*
+ * Periodically check and trigger autovacuum workers, if autovacuum
+ * is enabled.
+ */
+ if (autovacuum_enabled)
+ CoordinatorMaybeTriggerAutoVacuum();
+ }
+
+ /* Normal exit from the autovac launcher is here */
+ ereport(LOG,
+ (errmsg("autovacuum launcher shutting down")));
+ AutoVacuumShmem->av_launcherid = InvalidBackendId;
+
+ proc_exit(0); /* done */
+ }
+
+ void
+ handle_imessage(IMessage *msg)
+ {
+ IMessageType msg_type;
+ BackendId msg_sender;
+
+ msg_type = msg->type;
+ msg_sender = msg->sender;
+
+ #ifdef COORDINATOR_DEBUG
+ elog(DEBUG3, "Coordinator: received %s from pid %d",
+ decode_imessage_type(msg->type), msg->sender);
+ #endif
+
+ switch (msg->type)
+ {
+ /*
+ * Standard messages from background worker processes
+ */
+ case IMSGT_REGISTER_WORKER:
+ case IMSGT_READY:
+ /* consume the message */
+ IMessageRemove(msg);
+
+ /*
+ * default to immediately command the new background
+ * worker to perform an autovacuum step.
+ */
+ if (IMSGT_REGISTER_WORKER)
+ {
+ msg = IMessageCreate(IMSGT_PERFORM_VACUUM, 0);
+ IMessageActivate(msg, msg_sender);
+ }
+
+ /*
+ * Rebalance cost limits, as the worker has already reported its
+ * startup to the stats collector. However, that needs to be
+ * removed, so there's probably no point in rebalancing here.
+ * So: FIXME.
+ */
+ LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
+ autovac_balance_cost();
+ LWLockRelease(AutovacuumLock);
+
+ break;
+
+ case IMSGT_FORCE_VACUUM:
+ /* consume the message */
+ IMessageRemove(msg);
+
+ /* trigger an autovacuum worker */
+ do_start_autovacuum_worker();
+
+ break;
+
+ default:
+ elog(WARNING, "Unknown message type: %c, ignored!", msg->type);
+ IMessageRemove(msg);
+ }
+ }
+
+ static void
+ CoordinatorMaybeTriggerAutoVacuum()
+ {
+ TimestampTz current_time = 0;
+ bool can_launch;
+ Dlelem *elem;
+
+ /* FIXME: indentation */
+ {
+
+ /*
* There are some conditions that we need to check before trying to
* start a launcher. First, we need to make sure that there is a
* launcher slot available. Second, we need to make sure that no
*************** AutoVacLauncherMain(int argc, char *argv
*** 676,681 ****
--- 751,760 ----
int waittime;
WorkerInfo worker = AutoVacuumShmem->av_startingWorker;
+ #ifdef COORDINATOR_DEBUG
+ elog(DEBUG5, "Coordinator: another worker is starting...");
+ #endif
+
/*
* We can't launch another worker when another one is still
* starting up (or failed while doing so), so just sleep for a bit
*************** AutoVacLauncherMain(int argc, char *argv
*** 709,715 ****
worker = AutoVacuumShmem->av_startingWorker;
worker->wi_dboid = InvalidOid;
worker->wi_tableoid = InvalidOid;
! worker->wi_proc = NULL;
worker->wi_launchtime = 0;
worker->wi_links.next = (SHM_QUEUE *) AutoVacuumShmem->av_freeWorkers;
AutoVacuumShmem->av_freeWorkers = worker;
--- 788,794 ----
worker = AutoVacuumShmem->av_startingWorker;
worker->wi_dboid = InvalidOid;
worker->wi_tableoid = InvalidOid;
! worker->wi_backend_id = InvalidBackendId;
worker->wi_launchtime = 0;
worker->wi_links.next = (SHM_QUEUE *) AutoVacuumShmem->av_freeWorkers;
AutoVacuumShmem->av_freeWorkers = worker;
*************** AutoVacLauncherMain(int argc, char *argv
*** 722,730 ****
}
LWLockRelease(AutovacuumLock); /* either shared or exclusive */
! /* if we can't do anything, just go back to sleep */
if (!can_launch)
! continue;
/* We're OK to start a new worker */
--- 801,809 ----
}
LWLockRelease(AutovacuumLock); /* either shared or exclusive */
! /* if we can't do anything, just return. */
if (!can_launch)
! return;
/* We're OK to start a new worker */
*************** AutoVacLauncherMain(int argc, char *argv
*** 754,777 ****
launch_worker(current_time);
}
}
-
- /* Normal exit from the autovac launcher is here */
- ereport(LOG,
- (errmsg("autovacuum launcher shutting down")));
- AutoVacuumShmem->av_launcherpid = 0;
-
- proc_exit(0); /* done */
}
/*
* Determine the time to sleep, based on the database list.
*
! * The "canlaunch" parameter indicates whether we can start a worker right now,
* for example due to the workers being all busy. If this is false, we will
* cause a long sleep, which will be interrupted when a worker exits.
*/
static void
! launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval * nap)
{
Dlelem *elem;
--- 833,849 ----
launch_worker(current_time);
}
}
}
/*
* Determine the time to sleep, based on the database list.
*
! * The "can_launch" parameter indicates whether we can start a worker right now,
* for example due to the workers being all busy. If this is false, we will
* cause a long sleep, which will be interrupted when a worker exits.
*/
static void
! launcher_determine_sleep(bool can_launch, bool recursing, struct timeval *nap)
{
Dlelem *elem;
*************** launcher_determine_sleep(bool canlaunch,
*** 781,787 ****
* in the past; if the first entry has too close a next_worker value, or a
* time in the past, we will sleep a small nominal time.
*/
! if (!canlaunch)
{
nap->tv_sec = autovacuum_naptime;
nap->tv_usec = 0;
--- 853,859 ----
* in the past; if the first entry has too close a next_worker value, or a
* time in the past, we will sleep a small nominal time.
*/
! if (!can_launch)
{
nap->tv_sec = autovacuum_naptime;
nap->tv_usec = 0;
*************** launcher_determine_sleep(bool canlaunch,
*** 820,826 ****
if (nap->tv_sec == 0 && nap->tv_usec == 0 && !recursing)
{
rebuild_database_list(InvalidOid);
! launcher_determine_sleep(canlaunch, true, nap);
return;
}
--- 892,898 ----
if (nap->tv_sec == 0 && nap->tv_usec == 0 && !recursing)
{
rebuild_database_list(InvalidOid);
! launcher_determine_sleep(can_launch, true, nap);
return;
}
*************** db_comparator(const void *a, const void
*** 1052,1058 ****
/*
* do_start_worker
*
! * Bare-bones procedure for starting an autovacuum worker from the launcher.
* It determines what database to work on, sets up shared memory stuff and
* signals postmaster to start the worker. It fails gracefully if invoked when
* autovacuum_workers are already active.
--- 1124,1170 ----
/*
* do_start_worker
*
! * Bare-bones procedure for starting an autovacuum worker from the
! * coordinator. It sets up shared memory stuff and signals the postmaster to
! * start a worker.
! */
! void
! do_start_worker(avw_dbase *avdb)
! {
! WorkerInfo worker;
!
! #ifdef COORDINATOR_DEBUG
! elog(DEBUG5, "Coordinator: requesting worker for database %s",
! avdb->adw_name);
! #endif
!
! LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
!
! /*
! * Get a worker entry from the freelist. We checked above, so there
! * really should be a free slot -- complain very loudly if there
! * isn't.
! */
! worker = AutoVacuumShmem->av_freeWorkers;
! if (worker == NULL)
! elog(FATAL, "no free worker found");
!
! AutoVacuumShmem->av_freeWorkers = (WorkerInfo) worker->wi_links.next;
!
! worker->wi_dboid = avdb->adw_datid;
! worker->wi_backend_id = InvalidBackendId;
! worker->wi_launchtime = GetCurrentTimestamp();
!
! AutoVacuumShmem->av_startingWorker = worker;
!
! LWLockRelease(AutovacuumLock);
!
! SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
! }
!
! /*
! * do_start_autovacuum_worker
! *
* It determines what database to work on, sets up shared memory stuff and
* signals postmaster to start the worker. It fails gracefully if invoked when
* autovacuum_workers are already active.
*************** static Oid
*** 1061,1067 ****
* or InvalidOid if no worker was actually started.
*/
static Oid
! do_start_worker(void)
{
List *dblist;
ListCell *cell;
--- 1173,1179 ----
* or InvalidOid if no worker was actually started.
*/
static Oid
! do_start_autovacuum_worker(void)
{
List *dblist;
ListCell *cell;
*************** do_start_worker(void)
*** 1206,1236 ****
/* Found a database -- process it */
if (avdb != NULL)
{
! WorkerInfo worker;
!
! LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
!
! /*
! * Get a worker entry from the freelist. We checked above, so there
! * really should be a free slot -- complain very loudly if there
! * isn't.
! */
! worker = AutoVacuumShmem->av_freeWorkers;
! if (worker == NULL)
! elog(FATAL, "no free worker found");
!
! AutoVacuumShmem->av_freeWorkers = (WorkerInfo) worker->wi_links.next;
!
! worker->wi_dboid = avdb->adw_datid;
! worker->wi_proc = NULL;
! worker->wi_launchtime = GetCurrentTimestamp();
!
! AutoVacuumShmem->av_startingWorker = worker;
!
! LWLockRelease(AutovacuumLock);
!
! SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
!
retval = avdb->adw_datid;
}
else if (skipit)
--- 1318,1324 ----
/* Found a database -- process it */
if (avdb != NULL)
{
! do_start_worker(avdb);
retval = avdb->adw_datid;
}
else if (skipit)
*************** do_start_worker(void)
*** 1254,1260 ****
* Wrapper for starting a worker from the launcher. Besides actually starting
* it, update the database list to reflect the next time that another one will
* need to be started on the selected database. The actual database choice is
! * left to do_start_worker.
*
* This routine is also expected to insert an entry into the database list if
* the selected database was previously absent from the list.
--- 1342,1348 ----
* Wrapper for starting a worker from the launcher. Besides actually starting
* it, update the database list to reflect the next time that another one will
* need to be started on the selected database. The actual database choice is
! * left to do_start_autovacuum_worker.
*
* This routine is also expected to insert an entry into the database list if
* the selected database was previously absent from the list.
*************** launch_worker(TimestampTz now)
*** 1265,1271 ****
Oid dbid;
Dlelem *elem;
! dbid = do_start_worker();
if (OidIsValid(dbid))
{
/*
--- 1353,1359 ----
Oid dbid;
Dlelem *elem;
! dbid = do_start_autovacuum_worker();
if (OidIsValid(dbid))
{
/*
*************** launch_worker(TimestampTz now)
*** 1304,1320 ****
}
}
- /*
- * Called from postmaster to signal a failure to fork a process to become
- * worker. The postmaster should kill(SIGUSR2) the launcher shortly
- * after calling this function.
- */
- void
- AutoVacWorkerFailed(void)
- {
- AutoVacuumShmem->av_signal[AutoVacForkFailed] = true;
- }
-
/* SIGHUP: set flag to re-read config file at next convenient time */
static void
avl_sighup_handler(SIGNAL_ARGS)
--- 1392,1397 ----
*************** avl_sighup_handler(SIGNAL_ARGS)
*** 1322,1328 ****
got_SIGHUP = true;
}
! /* SIGUSR2: a worker is up and running, or just finished, or failed to fork */
static void
avl_sigusr2_handler(SIGNAL_ARGS)
{
--- 1399,1405 ----
got_SIGHUP = true;
}
! /* SIGUSR2: postmaster failed to fork a worker for us */
static void
avl_sigusr2_handler(SIGNAL_ARGS)
{
*************** AutoVacWorkerMain(int argc, char *argv[]
*** 1421,1427 ****
--- 1498,1508 ----
AutoVacWorkerMain(int argc, char *argv[])
{
sigjmp_buf local_sigjmp_buf;
+ BackendId coordinator_id;
+ IMessage *msg;
Oid dbid;
+ char dbname[NAMEDATALEN];
+ bool terminate_worker = false;
/* we are a postmaster subprocess now */
IsUnderPostmaster = true;
*************** AutoVacWorkerMain(int argc, char *argv[]
*** 1537,1548 ****
* launcher might have decided to remove it from the queue and start
* again.
*/
! if (AutoVacuumShmem->av_startingWorker != NULL)
{
! MyWorkerInfo = AutoVacuumShmem->av_startingWorker;
! dbid = MyWorkerInfo->wi_dboid;
! MyWorkerInfo->wi_proc = MyProc;
/* insert into the running list */
SHMQueueInsertBefore(&AutoVacuumShmem->av_runningWorkers,
&MyWorkerInfo->wi_links);
--- 1618,1637 ----
* launcher might have decided to remove it from the queue and start
* again.
*/
! if (AutoVacuumShmem->av_startingWorker == NULL)
{
! /* no worker entry for me, go away */
! elog(WARNING, "autovacuum worker started without a worker entry");
! LWLockRelease(AutovacuumLock);
! proc_exit(0);
! }
+ MyWorkerInfo = AutoVacuumShmem->av_startingWorker;
+ dbid = MyWorkerInfo->wi_dboid;
+
+ /* FIXME: indentation */
+ {
+
/* insert into the running list */
SHMQueueInsertBefore(&AutoVacuumShmem->av_runningWorkers,
&MyWorkerInfo->wi_links);
*************** AutoVacWorkerMain(int argc, char *argv[]
*** 1552,1576 ****
* a new worker if required
*/
AutoVacuumShmem->av_startingWorker = NULL;
- LWLockRelease(AutovacuumLock);
! on_shmem_exit(FreeWorkerInfo, 0);
!
! /* wake up the launcher */
! if (AutoVacuumShmem->av_launcherpid != 0)
! kill(AutoVacuumShmem->av_launcherpid, SIGUSR2);
! }
! else
! {
! /* no worker entry for me, go away */
! elog(WARNING, "autovacuum worker started without a worker entry");
! dbid = InvalidOid;
LWLockRelease(AutovacuumLock);
- }
! if (OidIsValid(dbid))
! {
! char dbname[NAMEDATALEN];
/*
* Report autovac startup to the stats collector. We deliberately do
--- 1641,1651 ----
* a new worker if required
*/
AutoVacuumShmem->av_startingWorker = NULL;
! coordinator_id = AutoVacuumShmem->av_launcherid;
LWLockRelease(AutovacuumLock);
! on_shmem_exit(FreeWorkerInfo, 0);
/*
* Report autovac startup to the stats collector. We deliberately do
*************** AutoVacWorkerMain(int argc, char *argv[]
*** 1593,1613 ****
set_ps_display(dbname, false);
ereport(DEBUG1,
(errmsg("autovacuum: processing database \"%s\"", dbname)));
! if (PostAuthDelay)
! pg_usleep(PostAuthDelay * 1000000L);
! /* And do an appropriate amount of work */
! recentXid = ReadNewTransactionId();
! do_autovacuum();
}
! /*
! * The launcher will be notified of my death in ProcKill, *if* we managed
! * to get a worker slot at all
! */
/* All done, go away */
proc_exit(0);
}
--- 1668,1765 ----
set_ps_display(dbname, false);
ereport(DEBUG1,
(errmsg("autovacuum: processing database \"%s\"", dbname)));
+ }
! MyWorkerInfo->wi_backend_id = MyBackendId;
! /* register with the coordinator */
! if (coordinator_id != InvalidBackendId)
! {
! msg = IMessageCreate(IMSGT_REGISTER_WORKER, 0);
! IMessageActivate(msg, coordinator_id);
}
! if (PostAuthDelay)
! pg_usleep(PostAuthDelay * 1000000L);
+ while (!terminate_worker)
+ {
+ CHECK_FOR_INTERRUPTS();
+
+ ImmediateInterruptOK = true;
+ pg_usleep(1000000L);
+ ImmediateInterruptOK = false;
+
+ while ((msg = IMessageCheck()) && !terminate_worker)
+ {
+ #ifdef COORDINATOR_DEBUG
+ ereport(DEBUG3,
+ (errmsg("bg worker [%d/%d]: received message %s of size %d "
+ "from backend id %d, db %d",
+ MyProcPid, MyBackendId,
+ decode_imessage_type(msg->type),
+ msg->size, msg->sender,
+ MyDatabaseId)));
+ #endif
+
+ /*
+ * StartTransactionCommand and CommitTransactionCommand will
+ * automatically switch to other contexts. None the less we need
+ * this one for other book-keeping of the various background
+ * jobs across transactions, for example to keep the list of
+ * relations to vacuum.
+ */
+ AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
+ "Background Worker",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ MemoryContextSwitchTo(AutovacMemCxt);
+
+ switch (msg->type)
+ {
+ case IMSGT_PERFORM_VACUUM:
+ /* immediately remove the message to free shared memory */
+ IMessageRemove(msg);
+
+ /* do an appropriate amount of work */
+ do_autovacuum();
+
+
+ /*
+ * send an IMSGT_READY to inform the coordinator that we
+ * finished vacuuming.
+ */
+ msg = IMessageCreate(IMSGT_READY, 0);
+ IMessageActivate(msg, GetAutovacuumLauncherId());
+
+ /*
+ * for now, we always terminate the worker after an
+ * autovacuum job.
+ */
+ terminate_worker = true;
+ break;
+
+ default:
+ ereport(WARNING,
+ (errmsg("bg worker [%d]: invalid message type "
+ "'%c' ignored",
+ MyProcPid, msg->type)));
+
+ /* keep shared memory clean */
+ IMessageRemove(msg);
+ }
+
+ MemoryContextSwitchTo(TopMemoryContext);
+ MemoryContextDelete(AutovacMemCxt);
+
+ CHECK_FOR_INTERRUPTS();
+ }
+ }
+
/* All done, go away */
+ ereport(DEBUG1, (errmsg("bg worker [%d/%d]: terminating",
+ MyProcPid, MyBackendId)));
proc_exit(0);
}
*************** FreeWorkerInfo(int code, Datum arg)
*** 1621,1645 ****
{
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
- /*
- * Wake the launcher up so that he can launch a new worker immediately
- * if required. We only save the launcher's PID in local memory here;
- * the actual signal will be sent when the PGPROC is recycled. Note
- * that we always do this, so that the launcher can rebalance the cost
- * limit setting of the remaining workers.
- *
- * We somewhat ignore the risk that the launcher changes its PID
- * between we reading it and the actual kill; we expect ProcKill to be
- * called shortly after us, and we assume that PIDs are not reused too
- * quickly after a process exits.
- */
- AutovacuumLauncherPid = AutoVacuumShmem->av_launcherpid;
-
SHMQueueDelete(&MyWorkerInfo->wi_links);
MyWorkerInfo->wi_links.next = (SHM_QUEUE *) AutoVacuumShmem->av_freeWorkers;
MyWorkerInfo->wi_dboid = InvalidOid;
MyWorkerInfo->wi_tableoid = InvalidOid;
! MyWorkerInfo->wi_proc = NULL;
MyWorkerInfo->wi_launchtime = 0;
MyWorkerInfo->wi_cost_delay = 0;
MyWorkerInfo->wi_cost_limit = 0;
--- 1773,1783 ----
{
LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
SHMQueueDelete(&MyWorkerInfo->wi_links);
MyWorkerInfo->wi_links.next = (SHM_QUEUE *) AutoVacuumShmem->av_freeWorkers;
MyWorkerInfo->wi_dboid = InvalidOid;
MyWorkerInfo->wi_tableoid = InvalidOid;
! MyWorkerInfo->wi_backend_id = InvalidBackendId;
MyWorkerInfo->wi_launchtime = 0;
MyWorkerInfo->wi_cost_delay = 0;
MyWorkerInfo->wi_cost_limit = 0;
*************** FreeWorkerInfo(int code, Datum arg)
*** 1648,1658 ****
/* not mine anymore */
MyWorkerInfo = NULL;
- /*
- * now that we're inactive, cause a rebalancing of the surviving
- * workers
- */
- AutoVacuumShmem->av_signal[AutoVacRebalance] = true;
LWLockRelease(AutovacuumLock);
}
}
--- 1786,1791 ----
*************** autovac_balance_cost(void)
*** 1704,1710 ****
offsetof(WorkerInfoData, wi_links));
while (worker)
{
! if (worker->wi_proc != NULL &&
worker->wi_cost_limit_base > 0 && worker->wi_cost_delay > 0)
cost_total +=
(double) worker->wi_cost_limit_base / worker->wi_cost_delay;
--- 1837,1843 ----
offsetof(WorkerInfoData, wi_links));
while (worker)
{
! if (worker->wi_backend_id != InvalidBackendId &&
worker->wi_cost_limit_base > 0 && worker->wi_cost_delay > 0)
cost_total +=
(double) worker->wi_cost_limit_base / worker->wi_cost_delay;
*************** autovac_balance_cost(void)
*** 1727,1733 ****
offsetof(WorkerInfoData, wi_links));
while (worker)
{
! if (worker->wi_proc != NULL &&
worker->wi_cost_limit_base > 0 && worker->wi_cost_delay > 0)
{
int limit = (int)
--- 1860,1866 ----
offsetof(WorkerInfoData, wi_links));
while (worker)
{
! if (worker->wi_backend_id != InvalidBackendId &&
worker->wi_cost_limit_base > 0 && worker->wi_cost_delay > 0)
{
int limit = (int)
*************** autovac_balance_cost(void)
*** 1739,1746 ****
*/
worker->wi_cost_limit = Max(Min(limit, worker->wi_cost_limit_base), 1);
! elog(DEBUG2, "autovac_balance_cost(pid=%u db=%u, rel=%u, cost_limit=%d, cost_delay=%d)",
! worker->wi_proc->pid, worker->wi_dboid,
worker->wi_tableoid, worker->wi_cost_limit, worker->wi_cost_delay);
}
--- 1872,1879 ----
*/
worker->wi_cost_limit = Max(Min(limit, worker->wi_cost_limit_base), 1);
! elog(DEBUG2, "autovac_balance_cost(backend_id=%u db=%u, rel=%u, cost_limit=%d, cost_delay=%d)",
! worker->wi_backend_id, worker->wi_dboid,
worker->wi_tableoid, worker->wi_cost_limit, worker->wi_cost_delay);
}
*************** do_autovacuum(void)
*** 1830,1846 ****
ScanKeyData key;
TupleDesc pg_class_desc;
! /*
! * StartTransactionCommand and CommitTransactionCommand will automatically
! * switch to other contexts. We need this one to keep the list of
! * relations to vacuum/analyze across transactions.
! */
! AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
! "AV worker",
! ALLOCSET_DEFAULT_MINSIZE,
! ALLOCSET_DEFAULT_INITSIZE,
! ALLOCSET_DEFAULT_MAXSIZE);
! MemoryContextSwitchTo(AutovacMemCxt);
/*
* may be NULL if we couldn't find an entry (only happens if we are
--- 1963,1969 ----
ScanKeyData key;
TupleDesc pg_class_desc;
! recentXid = ReadNewTransactionId();
/*
* may be NULL if we couldn't find an entry (only happens if we are
*************** autovac_report_activity(autovac_table *t
*** 2694,2712 ****
}
/*
- * AutoVacuumingActive
- * Check GUC vars and report whether the autovacuum process should be
- * running.
- */
- bool
- AutoVacuumingActive(void)
- {
- if (!autovacuum_start_daemon || !pgstat_track_counts)
- return false;
- return true;
- }
-
- /*
* autovac_init
* This is called at postmaster initialization.
*
--- 2817,2822 ----
*************** autovac_init(void)
*** 2715,2723 ****
void
autovac_init(void)
{
! if (autovacuum_start_daemon && !pgstat_track_counts)
ereport(WARNING,
! (errmsg("autovacuum not started because of misconfiguration"),
errhint("Enable the \"track_counts\" option.")));
}
--- 2825,2833 ----
void
autovac_init(void)
{
! if (autovacuum_enabled && !pgstat_track_counts)
ereport(WARNING,
! (errmsg("autovacuum disabled because of misconfiguration"),
errhint("Enable the \"track_counts\" option.")));
}
*************** IsAutoVacuumWorkerProcess(void)
*** 2738,2744 ****
--- 2848,2869 ----
return am_autovacuum_worker;
}
+ /*
+ * GetAutovacuumLauncherId
+ * Returns the backendId of the currently active coordinator process.
+ */
+ BackendId
+ GetAutovacuumLauncherId(void)
+ {
+ BackendId AutovacuumLauncherId;
+ LWLockAcquire(AutovacuumLock, LW_SHARED);
+ AutovacuumLauncherId = AutoVacuumShmem->av_launcherid;
+ LWLockRelease(AutovacuumLock);
+
+ return AutovacuumLauncherId;
+ }
+
/*
* AutoVacuumShmemSize
* Compute space needed for autovacuum-related shared memory
*************** AutoVacuumShmemInit(void)
*** 2779,2785 ****
Assert(!found);
! AutoVacuumShmem->av_launcherpid = 0;
AutoVacuumShmem->av_freeWorkers = NULL;
SHMQueueInit(&AutoVacuumShmem->av_runningWorkers);
AutoVacuumShmem->av_startingWorker = NULL;
--- 2904,2910 ----
Assert(!found);
! AutoVacuumShmem->av_launcherid = InvalidBackendId;
AutoVacuumShmem->av_freeWorkers = NULL;
SHMQueueInit(&AutoVacuumShmem->av_runningWorkers);
AutoVacuumShmem->av_startingWorker = NULL;
============================================================
*** src/include/postmaster/autovacuum.h 0bae2233087c757cad1e627118530e452ba166e7
--- src/include/postmaster/autovacuum.h 9d1ae53662236fcc871f84a9b1036619931bffe6
***************
*** 14,24 ****
#ifndef AUTOVACUUM_H
#define AUTOVACUUM_H
#include "storage/lock.h"
/* GUC variables */
! extern bool autovacuum_start_daemon;
extern int autovacuum_max_workers;
extern int autovacuum_naptime;
extern int autovacuum_vac_thresh;
extern double autovacuum_vac_scale;
--- 14,27 ----
#ifndef AUTOVACUUM_H
#define AUTOVACUUM_H
+ #include "storage/imsg.h"
#include "storage/lock.h"
/* GUC variables */
! extern bool autovacuum_enabled;
extern int autovacuum_max_workers;
+ extern int min_spare_background_workers;
+ extern int max_spare_background_workers;
extern int autovacuum_naptime;
extern int autovacuum_vac_thresh;
extern double autovacuum_vac_scale;
*************** extern int autovacuum_vac_cost_limit;
*** 28,54 ****
extern int autovacuum_vac_cost_delay;
extern int autovacuum_vac_cost_limit;
- /* autovacuum launcher PID, only valid when worker is shutting down */
- extern int AutovacuumLauncherPid;
-
extern int Log_autovacuum_min_duration;
/* Status inquiry functions */
- extern bool AutoVacuumingActive(void);
extern bool IsAutoVacuumLauncherProcess(void);
extern bool IsAutoVacuumWorkerProcess(void);
- #define IsAnyAutoVacuumProcess() \
- (IsAutoVacuumLauncherProcess() || IsAutoVacuumWorkerProcess())
-
/* Functions to start autovacuum process, called from postmaster */
extern void autovac_init(void);
extern int StartAutoVacLauncher(void);
extern int StartAutoVacWorker(void);
- /* called from postmaster when a worker could not be forked */
- extern void AutoVacWorkerFailed(void);
-
/* autovacuum cost-delay balancer */
extern void AutoVacuumUpdateDelay(void);
--- 31,48 ----
extern int autovacuum_vac_cost_delay;
extern int autovacuum_vac_cost_limit;
extern int Log_autovacuum_min_duration;
/* Status inquiry functions */
extern bool IsAutoVacuumLauncherProcess(void);
extern bool IsAutoVacuumWorkerProcess(void);
+ extern BackendId GetAutovacuumLauncherId(void);
/* Functions to start autovacuum process, called from postmaster */
extern void autovac_init(void);
extern int StartAutoVacLauncher(void);
extern int StartAutoVacWorker(void);
/* autovacuum cost-delay balancer */
extern void AutoVacuumUpdateDelay(void);
============================================================
*** src/backend/storage/ipc/imsg.c dc149eef487eafb43409a78b8a33c70e7d3c2bfa
--- src/backend/storage/ipc/imsg.c 81f58ac6067b9e4ebfaaf1e8ada1df68a20e8493
*************** decode_imessage_type(const IMessageType
*** 79,84 ****
--- 79,95 ----
{
case IMSGT_TEST:
return "IMSGT_TEST";
+
+ case IMSGT_REGISTER_WORKER:
+ return "IMSGT_REGISTER_WORKER";
+ case IMSGT_READY:
+ return "IMSGT_READY";
+
+ case IMSGT_PERFORM_VACUUM:
+ return "IMSGT_PERFORM_VACUUM";
+ case IMSGT_FORCE_VACUUM:
+ return "IMSGT_FORCE_VACUUM";
+
default:
return "unknown message type";
}
============================================================
*** src/include/storage/imsg.h d7d3960f42396bef49eb598411c215271570330e
--- src/include/storage/imsg.h 33f7d6772ba8d599a4eed0b882ccfa474a5cf258
*************** typedef enum
*** 28,33 ****
--- 28,47 ----
*/
typedef enum
{
+ /*
+ * messages from worker to coordinator, for background worker
+ * registration and job management.
+ */
+ IMSGT_REGISTER_WORKER = 'W',
+ IMSGT_READY = 'r',
+
+ /* inform the coordinator about a database that needs vacuuming to
+ * prevent transaction wrap around, from backends to coordinator */
+ IMSGT_FORCE_VACUUM = 'v',
+
+ /* messages from coordinator to worker */
+ IMSGT_PERFORM_VACUUM = 'V',
+
IMSGT_TEST = 'T' /* test message type */
} IMessageType;