Skip to content

Commit bbd0b14

Browse files
author
Maksim Milyutin
committed
Add contrib sources
1 parent a0c217f commit bbd0b14

14 files changed

+2870
-0
lines changed

contrib/pg_query_state/Makefile

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# contrib/pg_query_state/Makefile
2+
3+
MODULE_big = pg_query_state
4+
OBJS = pg_query_state.o signal_handler.o $(WIN32RES)
5+
EXTENSION = pg_query_state
6+
EXTVERSION = 1.0
7+
DATA = $(EXTENSION)--$(EXTVERSION).sql
8+
PGFILEDESC = "pg_query_state - facility to track progress of plan execution"
9+
10+
EXTRA_CLEAN = ./isolation_output
11+
12+
ifdef USE_PGXS
13+
PG_CONFIG = pg_config
14+
PGXS := $(shell $(PG_CONFIG) --pgxs)
15+
include $(PGXS)
16+
else
17+
subdir = contrib/pg_query_state
18+
top_builddir = ../..
19+
include $(top_builddir)/src/Makefile.global
20+
include $(top_srcdir)/contrib/contrib-global.mk
21+
endif
22+
23+
check: isolationcheck
24+
25+
ISOLATIONCHECKS=corner_cases
26+
27+
submake-isolation:
28+
$(MAKE) -C $(top_builddir)/src/test/isolation all
29+
30+
isolationcheck: | submake-isolation temp-install
31+
$(MKDIR_P) isolation_output
32+
$(pg_isolation_regress_check) \
33+
--temp-config $(top_srcdir)/contrib/pg_query_state/test.conf \
34+
--outputdir=isolation_output \
35+
$(ISOLATIONCHECKS)
36+
37+
isolationcheck-install-force: all | submake-isolation temp-install
38+
$(MKDIR_P) isolation_output
39+
$(pg_isolation_regress_installcheck) \
40+
--outputdir=isolation_output \
41+
$(ISOLATIONCHECKS)
42+
43+
.PHONY: isolationcheck isolationcheck-install-force check
44+
45+
temp-install: EXTRA_INSTALL=contrib/pg_query_state

contrib/pg_query_state/README.md

Lines changed: 291 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
2+
index a3d6ac5..60732a6 100644
3+
--- a/src/backend/storage/ipc/procsignal.c
4+
+++ b/src/backend/storage/ipc/procsignal.c
5+
@@ -26,6 +26,7 @@
6+
#include "storage/shmem.h"
7+
#include "storage/sinval.h"
8+
#include "tcop/tcopprot.h"
9+
+#include "utils/memutils.h"
10+
11+
12+
/*
13+
@@ -59,12 +60,17 @@ typedef struct
14+
*/
15+
#define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES)
16+
17+
+static bool CustomSignalPendings[NUM_CUSTOM_PROCSIGNALS];
18+
+static ProcSignalHandler_type CustomHandlers[NUM_CUSTOM_PROCSIGNALS];
19+
+
20+
static ProcSignalSlot *ProcSignalSlots = NULL;
21+
static volatile ProcSignalSlot *MyProcSignalSlot = NULL;
22+
23+
static bool CheckProcSignal(ProcSignalReason reason);
24+
static void CleanupProcSignalState(int status, Datum arg);
25+
26+
+static void CustomSignalInterrupt(ProcSignalReason reason);
27+
+
28+
/*
29+
* ProcSignalShmemSize
30+
* Compute space needed for procsignal's shared memory
31+
@@ -165,6 +171,57 @@ CleanupProcSignalState(int status, Datum arg)
32+
}
33+
34+
/*
35+
+ * RegisterCustomProcSignalHandler
36+
+ * Assign specific handler of custom process signal with new ProcSignalReason key.
37+
+ * Return INVALID_PROCSIGNAL if all custom signals have been assigned.
38+
+ */
39+
+ProcSignalReason
40+
+RegisterCustomProcSignalHandler(ProcSignalHandler_type handler)
41+
+{
42+
+ ProcSignalReason reason;
43+
+
44+
+ /* iterate through custom signal keys to find free spot */
45+
+ for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++)
46+
+ if (!CustomHandlers[reason - PROCSIG_CUSTOM_1])
47+
+ {
48+
+ CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler;
49+
+ return reason;
50+
+ }
51+
+ return INVALID_PROCSIGNAL;
52+
+}
53+
+
54+
+/*
55+
+ * AssignCustomProcSignalHandler
56+
+ * Assign handler of custom process signal with specific ProcSignalReason key.
57+
+ * Return old ProcSignal handler.
58+
+ * Assume incoming reason is one of custom ProcSignals.
59+
+ */
60+
+ProcSignalHandler_type
61+
+AssignCustomProcSignalHandler(ProcSignalReason reason, ProcSignalHandler_type handler)
62+
+{
63+
+ ProcSignalHandler_type old;
64+
+
65+
+ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N);
66+
+
67+
+ old = CustomHandlers[reason - PROCSIG_CUSTOM_1];
68+
+ CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler;
69+
+ return old;
70+
+}
71+
+
72+
+/*
73+
+ * GetCustomProcSignalHandler
74+
+ * Get handler of custom process signal.
75+
+ * Assume incoming reason is one of custom ProcSignals.
76+
+ */
77+
+ProcSignalHandler_type
78+
+GetCustomProcSignalHandler(ProcSignalReason reason)
79+
+{
80+
+ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N);
81+
+
82+
+ return CustomHandlers[reason - PROCSIG_CUSTOM_1];
83+
+}
84+
+
85+
+/*
86+
* SendProcSignal
87+
* Send a signal to a Postgres process
88+
*
89+
@@ -259,7 +316,8 @@ CheckProcSignal(ProcSignalReason reason)
90+
void
91+
procsignal_sigusr1_handler(SIGNAL_ARGS)
92+
{
93+
- int save_errno = errno;
94+
+ int save_errno = errno;
95+
+ ProcSignalReason reason;
96+
97+
if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
98+
HandleCatchupInterrupt();
99+
@@ -288,9 +346,88 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
100+
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
101+
RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
102+
103+
+ for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++)
104+
+ if (CheckProcSignal(reason))
105+
+ CustomSignalInterrupt(reason);
106+
+
107+
SetLatch(MyLatch);
108+
109+
latch_sigusr1_handler();
110+
111+
errno = save_errno;
112+
}
113+
+
114+
+/*
115+
+ * Handle receipt of an interrupt indicating a custom process signal.
116+
+ */
117+
+static void
118+
+CustomSignalInterrupt(ProcSignalReason reason)
119+
+{
120+
+ int save_errno = errno;
121+
+
122+
+ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N);
123+
+
124+
+ /* set interrupt flags */
125+
+ InterruptPending = true;
126+
+ CustomSignalPendings[reason - PROCSIG_CUSTOM_1] = true;
127+
+
128+
+ /* make sure the event is processed in due course */
129+
+ SetLatch(MyLatch);
130+
+
131+
+ errno = save_errno;
132+
+}
133+
+
134+
+/*
135+
+ * CheckAndHandleCustomSignals
136+
+ * Check custom signal flags and call handler assigned to that signal if it is not NULL.
137+
+ * This function is called within CHECK_FOR_INTERRUPTS if interrupt have been occurred.
138+
+ */
139+
+void
140+
+CheckAndHandleCustomSignals(void)
141+
+{
142+
+ int i;
143+
+ MemoryContext oldcontext;
144+
+
145+
+ static MemoryContext hcs_context = NULL;
146+
+
147+
+ /*
148+
+ * This is invoked from ProcessInterrupts(), and since some of the
149+
+ * functions it calls contain CHECK_FOR_INTERRUPTS(), there is a potential
150+
+ * for recursive calls if more signals are received while this runs. It's
151+
+ * unclear that recursive entry would be safe, and it doesn't seem useful
152+
+ * even if it is safe, so let's block interrupts until done.
153+
+ */
154+
+ HOLD_INTERRUPTS();
155+
+
156+
+ /*
157+
+ * Moreover, CurrentMemoryContext might be pointing almost anywhere. We
158+
+ * don't want to risk leaking data into long-lived contexts, so let's do
159+
+ * our work here in a private context that we can reset on each use.
160+
+ */
161+
+ if (hcs_context == NULL) /* first time through? */
162+
+ hcs_context = AllocSetContextCreate(TopMemoryContext,
163+
+ "HandleCustomSignals",
164+
+ ALLOCSET_DEFAULT_SIZES);
165+
+ else
166+
+ MemoryContextReset(hcs_context);
167+
+
168+
+ oldcontext = MemoryContextSwitchTo(hcs_context);
169+
+
170+
+ for (i = 0; i < NUM_CUSTOM_PROCSIGNALS; i++)
171+
+ if (CustomSignalPendings[i])
172+
+ {
173+
+ ProcSignalHandler_type handler;
174+
+
175+
+ CustomSignalPendings[i] = false;
176+
+ handler = CustomHandlers[i];
177+
+ if (handler)
178+
+ handler();
179+
+ }
180+
+
181+
+ MemoryContextSwitchTo(oldcontext);
182+
+
183+
+ /* Might as well clear the context on our way out */
184+
+ MemoryContextReset(hcs_context);
185+
+
186+
+ RESUME_INTERRUPTS();
187+
+}
188+
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
189+
index 98ccbbb..c5d649c 100644
190+
--- a/src/backend/tcop/postgres.c
191+
+++ b/src/backend/tcop/postgres.c
192+
@@ -3005,6 +3005,8 @@ ProcessInterrupts(void)
193+
194+
if (ParallelMessagePending)
195+
HandleParallelMessages();
196+
+
197+
+ CheckAndHandleCustomSignals();
198+
}
199+
200+
201+
diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h
202+
index f67b982..e941dcb 100644
203+
--- a/src/include/storage/procsignal.h
204+
+++ b/src/include/storage/procsignal.h
205+
@@ -17,6 +17,8 @@
206+
#include "storage/backendid.h"
207+
208+
209+
+#define NUM_CUSTOM_PROCSIGNALS 64
210+
+
211+
/*
212+
* Reasons for signalling a Postgres child process (a backend or an auxiliary
213+
* process, like checkpointer). We can cope with concurrent signals for different
214+
@@ -29,6 +31,8 @@
215+
*/
216+
typedef enum
217+
{
218+
+ INVALID_PROCSIGNAL = -1, /* Must be first */
219+
+
220+
PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */
221+
PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */
222+
PROCSIG_PARALLEL_MESSAGE, /* message from cooperating parallel backend */
223+
@@ -41,9 +45,20 @@ typedef enum
224+
PROCSIG_RECOVERY_CONFLICT_BUFFERPIN,
225+
PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK,
226+
227+
+ PROCSIG_CUSTOM_1,
228+
+ /*
229+
+ * PROCSIG_CUSTOM_2,
230+
+ * ...,
231+
+ * PROCSIG_CUSTOM_N-1,
232+
+ */
233+
+ PROCSIG_CUSTOM_N = PROCSIG_CUSTOM_1 + NUM_CUSTOM_PROCSIGNALS - 1,
234+
+
235+
NUM_PROCSIGNALS /* Must be last! */
236+
} ProcSignalReason;
237+
238+
+/* Handler of custom process signal */
239+
+typedef void (*ProcSignalHandler_type) (void);
240+
+
241+
/*
242+
* prototypes for functions in procsignal.c
243+
*/
244+
@@ -51,9 +66,15 @@ extern Size ProcSignalShmemSize(void);
245+
extern void ProcSignalShmemInit(void);
246+
247+
extern void ProcSignalInit(int pss_idx);
248+
+extern ProcSignalReason RegisterCustomProcSignalHandler(ProcSignalHandler_type handler);
249+
+extern ProcSignalHandler_type AssignCustomProcSignalHandler(ProcSignalReason reason,
250+
+ ProcSignalHandler_type handler);
251+
+extern ProcSignalHandler_type GetCustomProcSignalHandler(ProcSignalReason reason);
252+
extern int SendProcSignal(pid_t pid, ProcSignalReason reason,
253+
BackendId backendId);
254+
255+
+extern void CheckAndHandleCustomSignals(void);
256+
+
257+
extern void procsignal_sigusr1_handler(SIGNAL_ARGS);
258+
259+
#endif /* PROCSIGNAL_H */
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
Parsed test spec with 2 sessions
2+
3+
starting permutation: s1_pg_qs_1
4+
step s1_pg_qs_1: select pg_query_state(1);
5+
ERROR: backend with pid=1 not found
6+
7+
starting permutation: s1_pg_qs_2
8+
step s1_pg_qs_2: select pg_query_state(pg_backend_pid());
9+
ERROR: attempt to extract state of current process
10+
11+
starting permutation: s1_save_pid s2_pg_qs_counterpart
12+
step s1_save_pid: select save_own_pid(0);
13+
save_own_pid
14+
15+
16+
INFO: state of backend is idle
17+
step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0));
18+
pg_query_state
19+
20+
21+
starting permutation: s1_save_pid s1_disable_pg_qs s2_pg_qs_counterpart
22+
step s1_save_pid: select save_own_pid(0);
23+
save_own_pid
24+
25+
26+
step s1_disable_pg_qs: set pg_query_state.enable to off;
27+
INFO: query execution statistics disabled
28+
step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0));
29+
pg_query_state
30+
31+
32+
starting permutation: s1_set_bob s2_set_bob s1_save_pid s2_pg_qs_counterpart
33+
step s1_set_bob: set role bob;
34+
step s2_set_bob: set role bob;
35+
step s1_save_pid: select save_own_pid(0);
36+
save_own_pid
37+
38+
39+
INFO: state of backend is idle
40+
step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0));
41+
pg_query_state
42+
43+
44+
starting permutation: s1_set_bob s2_set_su s1_save_pid s2_pg_qs_counterpart
45+
step s1_set_bob: set role bob;
46+
step s2_set_su: set role super;
47+
step s1_save_pid: select save_own_pid(0);
48+
save_own_pid
49+
50+
51+
INFO: state of backend is idle
52+
step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0));
53+
pg_query_state
54+
55+
56+
starting permutation: s1_set_bob s2_set_alice s1_save_pid s2_pg_qs_counterpart
57+
step s1_set_bob: set role bob;
58+
step s2_set_alice: set role alice;
59+
step s1_save_pid: select save_own_pid(0);
60+
save_own_pid
61+
62+
63+
step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0));
64+
ERROR: permission denied
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
2+
\echo Use "CREATE EXTENSION pg_query_state" to load this file. \quit
3+
4+
CREATE FUNCTION pg_query_state(pid integer
5+
, verbose boolean = FALSE
6+
, costs boolean = FALSE
7+
, timing boolean = FALSE
8+
, buffers boolean = FALSE
9+
, triggers boolean = FALSE
10+
, format text = 'text')
11+
RETURNS TABLE (pid integer
12+
, frame_number integer
13+
, query_text text
14+
, plan text
15+
, leader_pid integer)
16+
AS 'MODULE_PATHNAME'
17+
LANGUAGE C STRICT VOLATILE;

0 commit comments

Comments
 (0)