Skip to content

Commit 33ae379

Browse files
author
Oleg Tselebrovskiy
committed
Store GUC variables in local process memory to avoid IPC shenanigans
For more context and reasoning see issue #85
1 parent b79a816 commit 33ae379

File tree

5 files changed

+64
-176
lines changed

5 files changed

+64
-176
lines changed

Diff for: README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ If `pg_wait_sampling.sample_cpu` is set to true then processes that are not
158158
waiting on anything are also sampled. The wait event columns for such processes
159159
will be NULL.
160160

161-
These GUCs are allowed to be changed by superuser. Also, they are placed into
162-
shared memory. Thus, they could be changed from any backend and affects worker
163-
runtime.
161+
Values of these GUC variables can be changed only in config file or with ALTER SYSTEM.
162+
Then you need to reload server's configuration (such as with pg_reload_conf function)
163+
for changes to take effect.
164164

165165
See
166166
[PostgreSQL documentation](http://www.postgresql.org/docs/devel/static/monitoring-stats.html#WAIT-EVENT-TABLE)

Diff for: collector.c

+15-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "funcapi.h"
1717
#include "miscadmin.h"
1818
#include "postmaster/bgworker.h"
19+
#include "postmaster/interrupt.h"
1920
#include "storage/ipc.h"
2021
#include "storage/procarray.h"
2122
#include "storage/procsignal.h"
@@ -151,7 +152,7 @@ probe_waits(History *observations, HTAB *profile_hash,
151152
TimestampTz ts = GetCurrentTimestamp();
152153

153154
/* Realloc waits history if needed */
154-
newSize = pgws_collector_hdr->historySize;
155+
newSize = pg_wait_sampling_historySize;
155156
if (observations->count != newSize)
156157
realloc_history(observations, newSize);
157158

@@ -170,7 +171,7 @@ probe_waits(History *observations, HTAB *profile_hash,
170171
item.pid = proc->pid;
171172
item.wait_event_info = proc->wait_event_info;
172173

173-
if (pgws_collector_hdr->profileQueries)
174+
if (pg_wait_sampling_profileQueries)
174175
item.queryId = pgws_proc_queryids[i];
175176
else
176177
item.queryId = 0;
@@ -289,7 +290,7 @@ make_profile_hash()
289290
hash_ctl.hash = tag_hash;
290291
hash_ctl.hcxt = TopMemoryContext;
291292

292-
if (pgws_collector_hdr->profileQueries)
293+
if (pg_wait_sampling_profileQueries)
293294
hash_ctl.keysize = offsetof(ProfileItem, count);
294295
else
295296
hash_ctl.keysize = offsetof(ProfileItem, queryId);
@@ -346,6 +347,7 @@ pgws_collector_main(Datum main_arg)
346347
* partitipate to the ProcSignal infrastructure.
347348
*/
348349
pqsignal(SIGTERM, handle_sigterm);
350+
pqsignal(SIGHUP, SignalHandlerForConfigReload);
349351
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
350352
BackgroundWorkerUnblockSignals();
351353
InitPostgresCompat(NULL, InvalidOid, NULL, InvalidOid, 0, NULL);
@@ -361,7 +363,7 @@ pgws_collector_main(Datum main_arg)
361363
collector_context = AllocSetContextCreate(TopMemoryContext,
362364
"pg_wait_sampling context", ALLOCSET_DEFAULT_SIZES);
363365
old_context = MemoryContextSwitchTo(collector_context);
364-
alloc_history(&observations, pgws_collector_hdr->historySize);
366+
alloc_history(&observations, pg_wait_sampling_historySize);
365367
MemoryContextSwitchTo(old_context);
366368

367369
ereport(LOG, (errmsg("pg_wait_sampling collector started")));
@@ -383,21 +385,27 @@ pgws_collector_main(Datum main_arg)
383385
/* We need an explicit call for at least ProcSignal notifications. */
384386
CHECK_FOR_INTERRUPTS();
385387

388+
if (ConfigReloadPending)
389+
{
390+
ConfigReloadPending = false;
391+
ProcessConfigFile(PGC_SIGHUP);
392+
}
393+
386394
/* Wait calculate time to next sample for history or profile */
387395
current_ts = GetCurrentTimestamp();
388396

389397
history_diff = millisecs_diff(history_ts, current_ts);
390398
profile_diff = millisecs_diff(profile_ts, current_ts);
391-
history_period = pgws_collector_hdr->historyPeriod;
392-
profile_period = pgws_collector_hdr->profilePeriod;
399+
history_period = pg_wait_sampling_historyPeriod;
400+
profile_period = pg_wait_sampling_profilePeriod;
393401

394402
write_history = (history_diff >= (int64)history_period);
395403
write_profile = (profile_diff >= (int64)profile_period);
396404

397405
if (write_history || write_profile)
398406
{
399407
probe_waits(&observations, profile_hash,
400-
write_history, write_profile, pgws_collector_hdr->profilePid);
408+
write_history, write_profile, pg_wait_sampling_profilePid);
401409

402410
if (write_history)
403411
{

Diff for: compat.h

-16
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,3 @@ InitPostgresCompat(const char *in_dbname, Oid dboid,
5050
flags & INIT_PG_OVERRIDE_ALLOW_CONNS);
5151
#endif
5252
}
53-
54-
static inline void
55-
get_guc_variables_compat(struct config_generic ***vars, int *num_vars)
56-
{
57-
Assert(vars != NULL);
58-
Assert(num_vars != NULL);
59-
60-
#if PG_VERSION_NUM >= 160000
61-
*vars = get_guc_variables(num_vars);
62-
#else
63-
*vars = get_guc_variables();
64-
*num_vars = GetNumConfigOptions();
65-
#endif
66-
}
67-
68-
#endif

Diff for: pg_wait_sampling.c

+38-144
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,17 @@ static const struct config_enum_entry pgws_profile_queries_options[] =
120120
{NULL, 0, false}
121121
};
122122

123+
/* GUC variables */
124+
int pg_wait_sampling_historySize = 5000;
125+
int pg_wait_sampling_historyPeriod = 10;
126+
int pg_wait_sampling_profilePeriod = 10;
127+
bool pg_wait_sampling_profilePid = true;
128+
int pg_wait_sampling_profileQueries = PGWS_PROFILE_QUERIES_TOP;
129+
bool pg_wait_sampling_sampleCpu = true;
130+
123131
#define pgws_enabled(level) \
124-
((pgws_collector_hdr->profileQueries == PGWS_PROFILE_QUERIES_ALL) || \
125-
(pgws_collector_hdr->profileQueries == PGWS_PROFILE_QUERIES_TOP && (level) == 0))
132+
((pg_wait_sampling_profileQueries == PGWS_PROFILE_QUERIES_ALL) || \
133+
(pg_wait_sampling_profileQueries == PGWS_PROFILE_QUERIES_TOP && (level) == 0))
126134

127135
/*
128136
* Calculate max processes count.
@@ -206,30 +214,6 @@ pgws_shmem_size(void)
206214
return size;
207215
}
208216

209-
static bool
210-
shmem_int_guc_check_hook(int *newval, void **extra, GucSource source)
211-
{
212-
if (UsedShmemSegAddr == NULL)
213-
return false;
214-
return true;
215-
}
216-
217-
static bool
218-
shmem_enum_guc_check_hook(int *newval, void **extra, GucSource source)
219-
{
220-
if (UsedShmemSegAddr == NULL)
221-
return false;
222-
return true;
223-
}
224-
225-
static bool
226-
shmem_bool_guc_check_hook(bool *newval, void **extra, GucSource source)
227-
{
228-
if (UsedShmemSegAddr == NULL)
229-
return false;
230-
return true;
231-
}
232-
233217
/*
234218
* This union allows us to mix the numerous different types of structs
235219
* that we are organizing.
@@ -244,117 +228,6 @@ typedef union
244228
struct config_enum _enum;
245229
} mixedStruct;
246230

247-
/*
248-
* Setup new GUCs or modify existsing.
249-
*/
250-
static void
251-
setup_gucs()
252-
{
253-
struct config_generic **guc_vars;
254-
int numOpts,
255-
i;
256-
bool history_size_found = false,
257-
history_period_found = false,
258-
profile_period_found = false,
259-
profile_pid_found = false,
260-
profile_queries_found = false,
261-
sample_cpu_found = false;
262-
263-
get_guc_variables_compat(&guc_vars, &numOpts);
264-
265-
for (i = 0; i < numOpts; i++)
266-
{
267-
mixedStruct *var = (mixedStruct *) guc_vars[i];
268-
const char *name = var->generic.name;
269-
270-
if (var->generic.flags & GUC_CUSTOM_PLACEHOLDER)
271-
continue;
272-
273-
if (!strcmp(name, "pg_wait_sampling.history_size"))
274-
{
275-
history_size_found = true;
276-
var->integer.variable = &pgws_collector_hdr->historySize;
277-
pgws_collector_hdr->historySize = 5000;
278-
}
279-
else if (!strcmp(name, "pg_wait_sampling.history_period"))
280-
{
281-
history_period_found = true;
282-
var->integer.variable = &pgws_collector_hdr->historyPeriod;
283-
pgws_collector_hdr->historyPeriod = 10;
284-
}
285-
else if (!strcmp(name, "pg_wait_sampling.profile_period"))
286-
{
287-
profile_period_found = true;
288-
var->integer.variable = &pgws_collector_hdr->profilePeriod;
289-
pgws_collector_hdr->profilePeriod = 10;
290-
}
291-
else if (!strcmp(name, "pg_wait_sampling.profile_pid"))
292-
{
293-
profile_pid_found = true;
294-
var->_bool.variable = &pgws_collector_hdr->profilePid;
295-
pgws_collector_hdr->profilePid = true;
296-
}
297-
else if (!strcmp(name, "pg_wait_sampling.profile_queries"))
298-
{
299-
profile_queries_found = true;
300-
var->_enum.variable = &pgws_collector_hdr->profileQueries;
301-
pgws_collector_hdr->profileQueries = PGWS_PROFILE_QUERIES_TOP;
302-
}
303-
else if (!strcmp(name, "pg_wait_sampling.sample_cpu"))
304-
{
305-
sample_cpu_found = true;
306-
var->_bool.variable = &pgws_collector_hdr->sampleCpu;
307-
pgws_collector_hdr->sampleCpu = true;
308-
}
309-
}
310-
311-
if (!history_size_found)
312-
DefineCustomIntVariable("pg_wait_sampling.history_size",
313-
"Sets size of waits history.", NULL,
314-
&pgws_collector_hdr->historySize, 5000, 100, INT_MAX,
315-
PGC_SUSET, 0, shmem_int_guc_check_hook, NULL, NULL);
316-
317-
if (!history_period_found)
318-
DefineCustomIntVariable("pg_wait_sampling.history_period",
319-
"Sets period of waits history sampling.", NULL,
320-
&pgws_collector_hdr->historyPeriod, 10, 1, INT_MAX,
321-
PGC_SUSET, 0, shmem_int_guc_check_hook, NULL, NULL);
322-
323-
if (!profile_period_found)
324-
DefineCustomIntVariable("pg_wait_sampling.profile_period",
325-
"Sets period of waits profile sampling.", NULL,
326-
&pgws_collector_hdr->profilePeriod, 10, 1, INT_MAX,
327-
PGC_SUSET, 0, shmem_int_guc_check_hook, NULL, NULL);
328-
329-
if (!profile_pid_found)
330-
DefineCustomBoolVariable("pg_wait_sampling.profile_pid",
331-
"Sets whether profile should be collected per pid.", NULL,
332-
&pgws_collector_hdr->profilePid, true,
333-
PGC_SUSET, 0, shmem_bool_guc_check_hook, NULL, NULL);
334-
335-
if (!profile_queries_found)
336-
DefineCustomEnumVariable("pg_wait_sampling.profile_queries",
337-
"Sets whether profile should be collected per query.", NULL,
338-
&pgws_collector_hdr->profileQueries, PGWS_PROFILE_QUERIES_TOP, pgws_profile_queries_options,
339-
PGC_SUSET, 0, shmem_enum_guc_check_hook, NULL, NULL);
340-
341-
if (!sample_cpu_found)
342-
DefineCustomBoolVariable("pg_wait_sampling.sample_cpu",
343-
"Sets whether not waiting backends should be sampled.", NULL,
344-
&pgws_collector_hdr->sampleCpu, true,
345-
PGC_SUSET, 0, shmem_bool_guc_check_hook, NULL, NULL);
346-
347-
if (history_size_found
348-
|| history_period_found
349-
|| profile_period_found
350-
|| profile_pid_found
351-
|| profile_queries_found
352-
|| sample_cpu_found)
353-
{
354-
ProcessConfigFile(PGC_SIGHUP);
355-
}
356-
}
357-
358231
#if PG_VERSION_NUM >= 150000
359232
/*
360233
* shmem_request hook: request additional shared memory resources.
@@ -391,17 +264,12 @@ pgws_shmem_startup(void)
391264

392265
pgws_collector_hdr = shm_toc_allocate(toc, sizeof(CollectorShmqHeader));
393266
shm_toc_insert(toc, 0, pgws_collector_hdr);
394-
/* needed to please check_GUC_init */
395-
pgws_collector_hdr->profileQueries = PGWS_PROFILE_QUERIES_TOP;
396267
pgws_collector_mq = shm_toc_allocate(toc, COLLECTOR_QUEUE_SIZE);
397268
shm_toc_insert(toc, 1, pgws_collector_mq);
398269
pgws_proc_queryids = shm_toc_allocate(toc,
399270
sizeof(uint64) * get_max_procs_count());
400271
shm_toc_insert(toc, 2, pgws_proc_queryids);
401272
MemSet(pgws_proc_queryids, 0, sizeof(uint64) * get_max_procs_count());
402-
403-
/* Initialize GUC variables in shared memory */
404-
setup_gucs();
405273
}
406274
else
407275
{
@@ -482,6 +350,32 @@ _PG_init(void)
482350
ExecutorEnd_hook = pgws_ExecutorEnd;
483351
prev_ProcessUtility = ProcessUtility_hook;
484352
ProcessUtility_hook = pgws_ProcessUtility;
353+
354+
/* Define GUC variables */
355+
DefineCustomIntVariable("pg_wait_sampling.history_size",
356+
"Sets size of waits history.", NULL,
357+
&pg_wait_sampling_historySize, 5000, 100, INT_MAX,
358+
PGC_SIGHUP, 0, NULL, NULL, NULL);
359+
DefineCustomIntVariable("pg_wait_sampling.history_period",
360+
"Sets period of waits history sampling.", NULL,
361+
&pg_wait_sampling_historyPeriod, 10, 1, INT_MAX,
362+
PGC_SIGHUP, 0, NULL, NULL, NULL);
363+
DefineCustomIntVariable("pg_wait_sampling.profile_period",
364+
"Sets period of waits profile sampling.", NULL,
365+
&pg_wait_sampling_profilePeriod, 10, 1, INT_MAX,
366+
PGC_SIGHUP, 0, NULL, NULL, NULL);
367+
DefineCustomBoolVariable("pg_wait_sampling.profile_pid",
368+
"Sets whether profile should be collected per pid.", NULL,
369+
&pg_wait_sampling_profilePid, true,
370+
PGC_SIGHUP, 0, NULL, NULL, NULL);
371+
DefineCustomEnumVariable("pg_wait_sampling.profile_queries",
372+
"Sets whether profile should be collected per query.", NULL,
373+
&pg_wait_sampling_profileQueries, PGWS_PROFILE_QUERIES_TOP, pgws_profile_queries_options,
374+
PGC_SIGHUP, 0, NULL, NULL, NULL);
375+
DefineCustomBoolVariable("pg_wait_sampling.sample_cpu",
376+
"Sets whether not waiting backends should be sampled.", NULL,
377+
&pg_wait_sampling_sampleCpu, true,
378+
PGC_SIGHUP, 0, NULL, NULL, NULL);
485379
}
486380

487381
/*
@@ -517,7 +411,7 @@ search_proc(int pid)
517411
bool
518412
pgws_should_sample_proc(PGPROC *proc)
519413
{
520-
if (proc->wait_event_info == 0 && !pgws_collector_hdr->sampleCpu)
414+
if (proc->wait_event_info == 0 && !pg_wait_sampling_sampleCpu)
521415
return false;
522416

523417
/*
@@ -829,7 +723,7 @@ pg_wait_sampling_get_profile(PG_FUNCTION_ARGS)
829723
else
830724
nulls[2] = true;
831725

832-
if (pgws_collector_hdr->profileQueries)
726+
if (pg_wait_sampling_profileQueries)
833727
values[3] = UInt64GetDatum(item->queryId);
834728
else
835729
values[3] = (Datum) 0;

Diff for: pg_wait_sampling.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,16 @@ typedef struct
5858
{
5959
Latch *latch;
6060
SHMRequest request;
61-
int historySize;
62-
int historyPeriod;
63-
int profilePeriod;
64-
bool profilePid;
65-
int profileQueries;
66-
bool sampleCpu;
6761
} CollectorShmqHeader;
6862

63+
/* GUC variables */
64+
extern int pg_wait_sampling_historySize;
65+
extern int pg_wait_sampling_historyPeriod;
66+
extern int pg_wait_sampling_profilePeriod;
67+
extern bool pg_wait_sampling_profilePid;
68+
extern int pg_wait_sampling_profileQueries;
69+
extern bool pg_wait_sampling_sampleCpu;
70+
6971
/* pg_wait_sampling.c */
7072
extern CollectorShmqHeader *pgws_collector_hdr;
7173
extern shm_mq *pgws_collector_mq;

0 commit comments

Comments
 (0)