Skip to content

Commit e7e27f5

Browse files
committed
Add 'contrib/pg_query_state/' from commit '016b4ab49608a679c7c9c965391e2368bb679736'
git-subtree-dir: contrib/pg_query_state git-subtree-mainline: e1996df git-subtree-split: 016b4ab
2 parents e1996df + 016b4ab commit e7e27f5

15 files changed

+2714
-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: 284 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
2+
index 0abde43..961d267 100644
3+
--- a/src/backend/storage/ipc/procsignal.c
4+
+++ b/src/backend/storage/ipc/procsignal.c
5+
@@ -67,12 +67,17 @@ typedef struct
6+
*/
7+
bool set_latch_on_sigusr1;
8+
9+
+static bool CustomSignalPendings[NUM_CUSTOM_PROCSIGNALS];
10+
+static ProcSignalHandler_type CustomHandlers[NUM_CUSTOM_PROCSIGNALS];
11+
+
12+
static ProcSignalSlot *ProcSignalSlots = NULL;
13+
static volatile ProcSignalSlot *MyProcSignalSlot = NULL;
14+
15+
static bool CheckProcSignal(ProcSignalReason reason);
16+
static void CleanupProcSignalState(int status, Datum arg);
17+
18+
+static void CustomSignalInterrupt(ProcSignalReason reason);
19+
+
20+
/*
21+
* ProcSignalShmemSize
22+
* Compute space needed for procsignal's shared memory
23+
@@ -173,6 +178,57 @@ CleanupProcSignalState(int status, Datum arg)
24+
}
25+
26+
/*
27+
+ * RegisterCustomProcSignalHandler
28+
+ * Assign specific handler of custom process signal with new ProcSignalReason key.
29+
+ * Return INVALID_PROCSIGNAL if all custom signals have been assigned.
30+
+ */
31+
+ProcSignalReason
32+
+RegisterCustomProcSignalHandler(ProcSignalHandler_type handler)
33+
+{
34+
+ ProcSignalReason reason;
35+
+
36+
+ /* iterate through custom signal keys to find free spot */
37+
+ for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++)
38+
+ if (!CustomHandlers[reason - PROCSIG_CUSTOM_1])
39+
+ {
40+
+ CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler;
41+
+ return reason;
42+
+ }
43+
+ return INVALID_PROCSIGNAL;
44+
+}
45+
+
46+
+/*
47+
+ * AssignCustomProcSignalHandler
48+
+ * Assign handler of custom process signal with specific ProcSignalReason key.
49+
+ * Return old ProcSignal handler.
50+
+ * Assume incoming reason is one of custom ProcSignals.
51+
+ */
52+
+ProcSignalHandler_type
53+
+AssignCustomProcSignalHandler(ProcSignalReason reason, ProcSignalHandler_type handler)
54+
+{
55+
+ ProcSignalHandler_type old;
56+
+
57+
+ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N);
58+
+
59+
+ old = CustomHandlers[reason - PROCSIG_CUSTOM_1];
60+
+ CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler;
61+
+ return old;
62+
+}
63+
+
64+
+/*
65+
+ * GetCustomProcSignalHandler
66+
+ * Get handler of custom process signal.
67+
+ * Assume incoming reason is one of custom ProcSignals.
68+
+ */
69+
+ProcSignalHandler_type
70+
+GetCustomProcSignalHandler(ProcSignalReason reason)
71+
+{
72+
+ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N);
73+
+
74+
+ return CustomHandlers[reason - PROCSIG_CUSTOM_1];
75+
+}
76+
+
77+
+/*
78+
* SendProcSignal
79+
* Send a signal to a Postgres process
80+
*
81+
@@ -267,7 +323,8 @@ CheckProcSignal(ProcSignalReason reason)
82+
void
83+
procsignal_sigusr1_handler(SIGNAL_ARGS)
84+
{
85+
- int save_errno = errno;
86+
+ int save_errno = errno;
87+
+ ProcSignalReason reason;
88+
89+
if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
90+
HandleCatchupInterrupt();
91+
@@ -296,6 +353,10 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
92+
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
93+
RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
94+
95+
+ for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++)
96+
+ if (CheckProcSignal(reason))
97+
+ CustomSignalInterrupt(reason);
98+
+
99+
if (set_latch_on_sigusr1)
100+
SetLatch(MyLatch);
101+
102+
@@ -303,3 +364,45 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
103+
104+
errno = save_errno;
105+
}
106+
+
107+
+/*
108+
+ * Handle receipt of an interrupt indicating a custom process signal.
109+
+ */
110+
+static void
111+
+CustomSignalInterrupt(ProcSignalReason reason)
112+
+{
113+
+ int save_errno = errno;
114+
+
115+
+ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N);
116+
+
117+
+ /* set interrupt flags */
118+
+ InterruptPending = true;
119+
+ CustomSignalPendings[reason - PROCSIG_CUSTOM_1] = true;
120+
+
121+
+ /* make sure the event is processed in due course */
122+
+ SetLatch(MyLatch);
123+
+
124+
+ errno = save_errno;
125+
+}
126+
+
127+
+/*
128+
+ * CheckAndHandleCustomSignals
129+
+ * Check custom signal flags and call handler assigned to that signal if it is not NULL.
130+
+ * This function is called within CHECK_FOR_INTERRUPTS if interrupt have been occurred.
131+
+ */
132+
+void
133+
+CheckAndHandleCustomSignals(void)
134+
+{
135+
+ int i;
136+
+
137+
+ for (i = 0; i < NUM_CUSTOM_PROCSIGNALS; i++)
138+
+ if (CustomSignalPendings[i])
139+
+ {
140+
+ ProcSignalHandler_type handler;
141+
+
142+
+ CustomSignalPendings[i] = false;
143+
+ handler = CustomHandlers[i];
144+
+ if (handler)
145+
+ handler();
146+
+ }
147+
+}
148+
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
149+
index f78321d..9ef7dd8 100644
150+
--- a/src/backend/tcop/postgres.c
151+
+++ b/src/backend/tcop/postgres.c
152+
@@ -3006,6 +3006,8 @@ ProcessInterrupts(void)
153+
154+
if (ParallelMessagePending)
155+
HandleParallelMessages();
156+
+
157+
+ CheckAndHandleCustomSignals();
158+
}
159+
160+
161+
diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h
162+
index af1a0cd..507a63c 100644
163+
--- a/src/include/storage/procsignal.h
164+
+++ b/src/include/storage/procsignal.h
165+
@@ -17,6 +17,8 @@
166+
#include "storage/backendid.h"
167+
168+
169+
+#define NUM_CUSTOM_PROCSIGNALS 64
170+
+
171+
/*
172+
* Reasons for signalling a Postgres child process (a backend or an auxiliary
173+
* process, like checkpointer). We can cope with concurrent signals for different
174+
@@ -29,6 +31,8 @@
175+
*/
176+
typedef enum
177+
{
178+
+ INVALID_PROCSIGNAL = -1, /* Must be first */
179+
+
180+
PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */
181+
PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */
182+
PROCSIG_PARALLEL_MESSAGE, /* message from cooperating parallel backend */
183+
@@ -41,9 +45,20 @@ typedef enum
184+
PROCSIG_RECOVERY_CONFLICT_BUFFERPIN,
185+
PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK,
186+
187+
+ PROCSIG_CUSTOM_1,
188+
+ /*
189+
+ * PROCSIG_CUSTOM_2,
190+
+ * ...,
191+
+ * PROCSIG_CUSTOM_N-1,
192+
+ */
193+
+ PROCSIG_CUSTOM_N = PROCSIG_CUSTOM_1 + NUM_CUSTOM_PROCSIGNALS - 1,
194+
+
195+
NUM_PROCSIGNALS /* Must be last! */
196+
} ProcSignalReason;
197+
198+
+/* Handler of custom process signal */
199+
+typedef void (*ProcSignalHandler_type) (void);
200+
+
201+
/*
202+
* prototypes for functions in procsignal.c
203+
*/
204+
@@ -51,9 +66,15 @@ extern Size ProcSignalShmemSize(void);
205+
extern void ProcSignalShmemInit(void);
206+
207+
extern void ProcSignalInit(int pss_idx);
208+
+extern ProcSignalReason RegisterCustomProcSignalHandler(ProcSignalHandler_type handler);
209+
+extern ProcSignalHandler_type AssignCustomProcSignalHandler(ProcSignalReason reason,
210+
+ ProcSignalHandler_type handler);
211+
+extern ProcSignalHandler_type GetCustomProcSignalHandler(ProcSignalReason reason);
212+
extern int SendProcSignal(pid_t pid, ProcSignalReason reason,
213+
BackendId backendId);
214+
215+
+extern void CheckAndHandleCustomSignals(void);
216+
+
217+
extern void procsignal_sigusr1_handler(SIGNAL_ARGS);
218+
extern PGDLLIMPORT bool set_latch_on_sigusr1;
219+
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
2+
index 03c2feb..a33e645c 100644
3+
--- a/src/backend/executor/execProcnode.c
4+
+++ b/src/backend/executor/execProcnode.c
5+
@@ -115,7 +115,6 @@
6+
#include "executor/nodeWorktablescan.h"
7+
#include "miscadmin.h"
8+
9+
-
10+
/* ------------------------------------------------------------------------
11+
* ExecInitNode
12+
*
13+
@@ -356,6 +355,9 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
14+
return result;
15+
}
16+
17+
+/* Hooks for plugins to pre/post process ExecProcNode */
18+
+PreExecProcNode_hook_type preExecProcNode_hook = NULL;
19+
+PostExecProcNode_hook_type postExecProcNode_hook = NULL;
20+
21+
/* ----------------------------------------------------------------
22+
* ExecProcNode
23+
@@ -374,7 +376,12 @@ ExecProcNode(PlanState *node)
24+
ExecReScan(node); /* let ReScan handle this */
25+
26+
if (node->instrument)
27+
+ {
28+
+ if (preExecProcNode_hook)
29+
+ preExecProcNode_hook(node);
30+
+
31+
InstrStartNode(node->instrument);
32+
+ }
33+
34+
switch (nodeTag(node))
35+
{
36+
@@ -527,8 +534,13 @@ ExecProcNode(PlanState *node)
37+
}
38+
39+
if (node->instrument)
40+
+ {
41+
InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
42+
43+
+ if (postExecProcNode_hook)
44+
+ postExecProcNode_hook(node, result);
45+
+ }
46+
+
47+
return result;
48+
}
49+
50+
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
51+
index 110bc93..8801419 100644
52+
--- a/src/include/executor/executor.h
53+
+++ b/src/include/executor/executor.h
54+
@@ -95,6 +95,12 @@ extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook;
55+
typedef bool (*ExecutorCheckPerms_hook_type) (List *, bool);
56+
extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook;
57+
58+
+/* Hook for plugins to pre/post process ExecProcNode() */
59+
+typedef void (*PreExecProcNode_hook_type) (PlanState *node);
60+
+typedef void (*PostExecProcNode_hook_type) (PlanState *node, TupleTableSlot *result);
61+
+extern PGDLLIMPORT PreExecProcNode_hook_type preExecProcNode_hook;
62+
+extern PGDLLIMPORT PostExecProcNode_hook_type postExecProcNode_hook;
63+
+
64+
65+
/*
66+
* prototypes from functions in execAmi.c
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

0 commit comments

Comments
 (0)