1 /*--------------------------------------------------------------------
3 * POSTGRES pluggable background workers implementation
5 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
8 * src/backend/postmaster/bgworker.c
10 *-------------------------------------------------------------------------
15 #include "miscadmin.h"
16 #include "postmaster/bgworker_internals.h"
17 #include "storage/barrier.h"
18 #include "storage/lwlock.h"
19 #include "storage/pmsignal.h"
20 #include "storage/shmem.h"
21 #include "utils/ascii.h"
24 * The postmaster's list of registered background workers, in private memory.
26 slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList);
29 * BackgroundWorkerSlots exist in shared memory and can be accessed (via
30 * the BackgroundWorkerArray) by both the postmaster and by regular backends.
31 * However, the postmaster cannot take locks, even spinlocks, because this
32 * might allow it to crash or become wedged if shared memory gets corrupted.
33 * Such an outcome is intolerable. Therefore, we need a lockless protocol
34 * for coordinating access to this data.
36 * The 'in_use' flag is used to hand off responsibility for the slot between
37 * the postmaster and the rest of the system. When 'in_use' is false,
38 * the postmaster will ignore the slot entirely, except for the 'in_use' flag
39 * itself, which it may read. In this state, regular backends may modify the
40 * slot. Once a backend sets 'in_use' to true, the slot becomes the
41 * responsibility of the postmaster. Regular backends may no longer modify it,
42 * but the postmaster may examine it. Thus, a backend initializing a slot
43 * must fully initialize the slot - and insert a write memory barrier - before
44 * marking it as in use.
46 * In addition to coordinating with the postmaster, backends modifying this
47 * data structure must coordinate with each other. Since they can take locks,
48 * this is straightforward: any backend wishing to manipulate a slot must
49 * take BackgroundWorkerLock in exclusive mode. Backends wishing to read
50 * data that might get concurrently modified by other backends should take
51 * this lock in shared mode. No matter what, backends reading this data
52 * structure must be able to tolerate concurrent modifications by the
55 typedef struct BackgroundWorkerSlot
58 BackgroundWorker worker;
59 } BackgroundWorkerSlot;
61 typedef struct BackgroundWorkerArray
64 BackgroundWorkerSlot slot[FLEXIBLE_ARRAY_MEMBER];
65 } BackgroundWorkerArray;
67 BackgroundWorkerArray *BackgroundWorkerData;
70 * Calculate shared memory needed.
73 BackgroundWorkerShmemSize(void)
77 /* Array of workers is variably sized. */
78 size = offsetof(BackgroundWorkerArray, slot);
79 size = add_size(size, mul_size(max_worker_processes,
80 sizeof(BackgroundWorkerSlot)));
86 * Initialize shared memory.
89 BackgroundWorkerShmemInit(void)
93 BackgroundWorkerData = ShmemInitStruct("Background Worker Data",
94 BackgroundWorkerShmemSize(),
96 if (!IsUnderPostmaster)
101 BackgroundWorkerData->total_slots = max_worker_processes;
104 * Copy contents of worker list into shared memory. Record the
105 * shared memory slot assigned to each worker. This ensures
106 * a 1-to-1 correspondence betwen the postmaster's private list and
107 * the array in shared memory.
109 slist_foreach(siter, &BackgroundWorkerList)
111 BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno];
112 RegisteredBgWorker *rw;
114 rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur);
115 Assert(slotno < max_worker_processes);
117 rw->rw_shmem_slot = slotno;
118 memcpy(&slot->worker, &rw->rw_worker, sizeof(BackgroundWorker));
123 * Mark any remaining slots as not in use.
125 while (slotno < max_worker_processes)
127 BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno];
129 slot->in_use = false;
138 * Search the postmaster's backend-private list of RegisteredBgWorker objects
139 * for the one that maps to the given slot number.
141 static RegisteredBgWorker *
142 FindRegisteredWorkerBySlotNumber(int slotno)
146 slist_foreach(siter, &BackgroundWorkerList)
148 RegisteredBgWorker *rw;
150 rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur);
151 if (rw->rw_shmem_slot == slotno)
159 * Notice changes to shared memory made by other backends. This code
160 * runs in the postmaster, so we must be very careful not to assume that
161 * shared memory contents are sane. Otherwise, a rogue backend could take
162 * out the postmaster.
165 BackgroundWorkerStateChange(void)
170 * The total number of slots stored in shared memory should match our
171 * notion of max_worker_processes. If it does not, something is very
172 * wrong. Further down, we always refer to this value as
173 * max_worker_processes, in case shared memory gets corrupted while
176 if (max_worker_processes != BackgroundWorkerData->total_slots)
179 "inconsistent background worker state (max_worker_processes=%d, total_slots=%d",
180 max_worker_processes,
181 BackgroundWorkerData->total_slots);
186 * Iterate through slots, looking for newly-registered workers or
187 * workers who must die.
189 for (slotno = 0; slotno < max_worker_processes; ++slotno)
191 BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno];
192 RegisteredBgWorker *rw;
198 * Make sure we don't see the in_use flag before the updated slot
204 * See whether we already know about this worker. If not, we need
205 * to update our backend-private BackgroundWorkerList to match shared
208 rw = FindRegisteredWorkerBySlotNumber(slotno);
213 * Copy the registration data into the registered workers list.
215 rw = malloc(sizeof(RegisteredBgWorker));
219 (errcode(ERRCODE_OUT_OF_MEMORY),
220 errmsg("out of memory")));
225 * Copy strings in a paranoid way. If shared memory is corrupted,
226 * the source data might not even be NUL-terminated.
228 ascii_safe_strlcpy(rw->rw_worker.bgw_name,
229 slot->worker.bgw_name, BGW_MAXLEN);
230 ascii_safe_strlcpy(rw->rw_worker.bgw_library_name,
231 slot->worker.bgw_library_name, BGW_MAXLEN);
232 ascii_safe_strlcpy(rw->rw_worker.bgw_function_name,
233 slot->worker.bgw_function_name, BGW_MAXLEN);
236 * Copy remaining fields.
238 * flags, start_time, and restart_time are examined by the
239 * postmaster, but nothing too bad will happen if they are
240 * corrupted. The remaining fields will only be examined by the
241 * child process. It might crash, but we won't.
243 rw->rw_worker.bgw_flags = slot->worker.bgw_flags;
244 rw->rw_worker.bgw_start_time = slot->worker.bgw_start_time;
245 rw->rw_worker.bgw_restart_time = slot->worker.bgw_restart_time;
246 rw->rw_worker.bgw_main = slot->worker.bgw_main;
247 rw->rw_worker.bgw_main_arg = slot->worker.bgw_main_arg;
249 /* Initialize postmaster bookkeeping. */
250 rw->rw_backend = NULL;
252 rw->rw_child_slot = 0;
253 rw->rw_crashed_at = 0;
254 rw->rw_shmem_slot = slotno;
258 (errmsg("registering background worker \"%s\"",
259 rw->rw_worker.bgw_name)));
261 slist_push_head(&BackgroundWorkerList, &rw->rw_lnode);
266 * Forget about a background worker that's no longer needed.
268 * The worker must be identified by passing an slist_mutable_iter that
269 * points to it. This convention allows deletion of workers during
270 * searches of the worker list, and saves having to search the list again.
272 * This function must be invoked only in the postmaster.
275 ForgetBackgroundWorker(slist_mutable_iter *cur)
277 RegisteredBgWorker *rw;
278 BackgroundWorkerSlot *slot;
280 rw = slist_container(RegisteredBgWorker, rw_lnode, cur->cur);
282 Assert(rw->rw_shmem_slot < max_worker_processes);
283 slot = &BackgroundWorkerData->slot[rw->rw_shmem_slot];
284 slot->in_use = false;
287 (errmsg("unregistering background worker \"%s\"",
288 rw->rw_worker.bgw_name)));
290 slist_delete_current(cur);
296 * In EXEC_BACKEND mode, workers use this to retrieve their details from
300 BackgroundWorkerEntry(int slotno)
302 BackgroundWorkerSlot *slot;
304 Assert(slotno < BackgroundWorkerData->total_slots);
305 slot = &BackgroundWorkerData->slot[slotno];
306 Assert(slot->in_use);
307 return &slot->worker; /* can't become free while we're still here */
312 * Complain about the BackgroundWorker definition using error level elevel.
313 * Return true if it looks ok, false if not (unless elevel >= ERROR, in
314 * which case we won't return at all in the not-OK case).
317 SanityCheckBackgroundWorker(BackgroundWorker *worker, int elevel)
319 /* sanity check for flags */
320 if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)
322 if (!(worker->bgw_flags & BGWORKER_SHMEM_ACCESS))
325 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
326 errmsg("background worker \"%s\": must attach to shared memory in order to request a database connection",
331 if (worker->bgw_start_time == BgWorkerStart_PostmasterStart)
334 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
335 errmsg("background worker \"%s\": cannot request database access if starting at postmaster start",
340 /* XXX other checks? */
343 if ((worker->bgw_restart_time < 0 &&
344 worker->bgw_restart_time != BGW_NEVER_RESTART) ||
345 (worker->bgw_restart_time > USECS_PER_DAY / 1000))
348 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
349 errmsg("background worker \"%s\": invalid restart interval",
358 * Register a new background worker while processing shared_preload_libraries.
360 * This can only be called in the _PG_init function of a module library
361 * that's loaded by shared_preload_libraries; otherwise it has no effect.
364 RegisterBackgroundWorker(BackgroundWorker *worker)
366 RegisteredBgWorker *rw;
367 static int numworkers = 0;
369 if (!IsUnderPostmaster)
371 (errmsg("registering background worker \"%s\"", worker->bgw_name)));
373 if (!process_shared_preload_libraries_in_progress)
375 if (!IsUnderPostmaster)
377 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
378 errmsg("background worker \"%s\": must be registered in shared_preload_libraries",
383 if (!SanityCheckBackgroundWorker(worker, LOG))
387 * Enforce maximum number of workers. Note this is overly restrictive: we
388 * could allow more non-shmem-connected workers, because these don't count
389 * towards the MAX_BACKENDS limit elsewhere. For now, it doesn't seem
390 * important to relax this restriction.
392 if (++numworkers > max_worker_processes)
395 (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
396 errmsg("too many background workers"),
397 errdetail_plural("Up to %d background worker can be registered with the current settings.",
398 "Up to %d background workers can be registered with the current settings.",
399 max_worker_processes,
400 max_worker_processes),
401 errhint("Consider increasing the configuration parameter \"max_worker_processes\".")));
406 * Copy the registration data into the registered workers list.
408 rw = malloc(sizeof(RegisteredBgWorker));
412 (errcode(ERRCODE_OUT_OF_MEMORY),
413 errmsg("out of memory")));
417 rw->rw_worker = *worker;
418 rw->rw_backend = NULL;
420 rw->rw_child_slot = 0;
421 rw->rw_crashed_at = 0;
423 slist_push_head(&BackgroundWorkerList, &rw->rw_lnode);
427 * Register a new background worker from a regular backend.
429 * Returns true on success and false on failure. Failure typically indicates
430 * that no background worker slots are currently available.
433 RegisterDynamicBackgroundWorker(BackgroundWorker *worker)
436 bool success = false;
439 * We can't register dynamic background workers from the postmaster.
440 * If this is a standalone backend, we're the only process and can't
441 * start any more. In a multi-process environement, it might be
442 * theoretically possible, but we don't currently support it due to
443 * locking considerations; see comments on the BackgroundWorkerSlot
446 if (!IsUnderPostmaster)
449 if (!SanityCheckBackgroundWorker(worker, ERROR))
452 LWLockAcquire(BackgroundWorkerLock, LW_EXCLUSIVE);
455 * Look for an unused slot. If we find one, grab it.
457 for (slotno = 0; slotno < BackgroundWorkerData->total_slots; ++slotno)
459 BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno];
463 memcpy(&slot->worker, worker, sizeof(BackgroundWorker));
466 * Make sure postmaster doesn't see the slot as in use before
467 * it sees the new contents.
477 LWLockRelease(BackgroundWorkerLock);
479 /* If we found a slot, tell the postmaster to notice the change. */
481 SendPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE);