Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf587338

Browse files
committed
injection_points: Introduce runtime conditions
This adds a new SQL function injection_points_set_local() that can beused to force injection points to be run only in the process where theyare attached. This is handy for SQL tests to:- Detach automatically injection points when the process exits.- Allow tests with injection points to run concurrently with other testsuites, so as such modules do not have to be marked withNO_INSTALLCHECK.Currently, the only condition that can be registered is for a PID.This could be extended to more kinds later, if required, like databasenames/OIDs, roles, or more concepts I did not consider.Using a single function for SQL scripts is an idea from HeikkiLinnakangas.Reviewed-by: Andrey BorodinDiscussion:https://postgr.es/m/ZfP7IDs9TvrKe49x@paquier.xyz
1 parent705843d commitf587338

File tree

5 files changed

+285
-0
lines changed

5 files changed

+285
-0
lines changed

‎src/test/modules/injection_points/expected/injection_points.out

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,81 @@ NOTICE: notice triggered for injection point TestInjectionLog2
115115

116116
(1 row)
117117

118+
SELECT injection_points_detach('TestInjectionLog2');
119+
injection_points_detach
120+
-------------------------
121+
122+
(1 row)
123+
124+
-- Runtime conditions
125+
SELECT injection_points_attach('TestConditionError', 'error');
126+
injection_points_attach
127+
-------------------------
128+
129+
(1 row)
130+
131+
-- Any follow-up injection point attached will be local to this process.
132+
SELECT injection_points_set_local();
133+
injection_points_set_local
134+
----------------------------
135+
136+
(1 row)
137+
138+
SELECT injection_points_attach('TestConditionLocal1', 'error');
139+
injection_points_attach
140+
-------------------------
141+
142+
(1 row)
143+
144+
SELECT injection_points_attach('TestConditionLocal2', 'notice');
145+
injection_points_attach
146+
-------------------------
147+
148+
(1 row)
149+
150+
SELECT injection_points_run('TestConditionLocal1'); -- error
151+
ERROR: error triggered for injection point TestConditionLocal1
152+
SELECT injection_points_run('TestConditionLocal2'); -- notice
153+
NOTICE: notice triggered for injection point TestConditionLocal2
154+
injection_points_run
155+
----------------------
156+
157+
(1 row)
158+
159+
-- reload, local injection points should be gone.
160+
\c
161+
SELECT injection_points_run('TestConditionLocal1'); -- nothing
162+
injection_points_run
163+
----------------------
164+
165+
(1 row)
166+
167+
SELECT injection_points_run('TestConditionLocal2'); -- nothing
168+
injection_points_run
169+
----------------------
170+
171+
(1 row)
172+
173+
SELECT injection_points_run('TestConditionError'); -- error
174+
ERROR: error triggered for injection point TestConditionError
175+
SELECT injection_points_detach('TestConditionError');
176+
injection_points_detach
177+
-------------------------
178+
179+
(1 row)
180+
181+
-- Attaching injection points that use the same name as one defined locally
182+
-- previously should work.
183+
SELECT injection_points_attach('TestConditionLocal1', 'error');
184+
injection_points_attach
185+
-------------------------
186+
187+
(1 row)
188+
189+
SELECT injection_points_detach('TestConditionLocal1');
190+
injection_points_detach
191+
-------------------------
192+
193+
(1 row)
194+
118195
DROP EXTENSION injection_points;

‎src/test/modules/injection_points/injection_points--1.0.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ RETURNS void
3434
AS'MODULE_PATHNAME','injection_points_wakeup'
3535
LANGUAGE C STRICT PARALLEL UNSAFE;
3636

37+
--
38+
-- injection_points_set_local()
39+
--
40+
-- Trigger switch to link any future injection points attached to the
41+
-- current process, useful to make SQL tests concurrently-safe.
42+
--
43+
CREATEFUNCTIONinjection_points_set_local()
44+
RETURNS void
45+
AS'MODULE_PATHNAME','injection_points_set_local'
46+
LANGUAGE C STRICT PARALLEL UNSAFE;
47+
3748
--
3849
-- injection_points_detach()
3950
--

‎src/test/modules/injection_points/injection_points.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
#include"postgres.h"
1919

2020
#include"fmgr.h"
21+
#include"miscadmin.h"
2122
#include"storage/condition_variable.h"
2223
#include"storage/dsm_registry.h"
24+
#include"storage/ipc.h"
2325
#include"storage/lwlock.h"
2426
#include"storage/shmem.h"
2527
#include"utils/builtins.h"
@@ -31,6 +33,23 @@ PG_MODULE_MAGIC;
3133
/* Maximum number of waits usable in injection points at once */
3234
#defineINJ_MAX_WAIT8
3335
#defineINJ_NAME_MAXLEN64
36+
#defineINJ_MAX_CONDITION4
37+
38+
/*
39+
* Conditions related to injection points. This tracks in shared memory the
40+
* runtime conditions under which an injection point is allowed to run.
41+
*
42+
* If more types of runtime conditions need to be tracked, this structure
43+
* should be expanded.
44+
*/
45+
typedefstructInjectionPointCondition
46+
{
47+
/* Name of the injection point related to this condition */
48+
charname[INJ_NAME_MAXLEN];
49+
50+
/* ID of the process where the injection point is allowed to run */
51+
intpid;
52+
}InjectionPointCondition;
3453

3554
/* Shared state information for injection points. */
3655
typedefstructInjectionPointSharedState
@@ -46,6 +65,9 @@ typedef struct InjectionPointSharedState
4665

4766
/* Condition variable used for waits and wakeups */
4867
ConditionVariablewait_point;
68+
69+
/* Conditions to run an injection point */
70+
InjectionPointConditionconditions[INJ_MAX_CONDITION];
4971
}InjectionPointSharedState;
5072

5173
/* Pointer to shared-memory state. */
@@ -55,6 +77,8 @@ extern PGDLLEXPORT void injection_error(const char *name);
5577
externPGDLLEXPORTvoidinjection_notice(constchar*name);
5678
externPGDLLEXPORTvoidinjection_wait(constchar*name);
5779

80+
/* track if injection points attached in this process are linked to it */
81+
staticboolinjection_point_local= false;
5882

5983
/*
6084
* Callback for shared memory area initialization.
@@ -67,6 +91,7 @@ injection_point_init_state(void *ptr)
6791
SpinLockInit(&state->lock);
6892
memset(state->wait_counts,0,sizeof(state->wait_counts));
6993
memset(state->name,0,sizeof(state->name));
94+
memset(state->conditions,0,sizeof(state->conditions));
7095
ConditionVariableInit(&state->wait_point);
7196
}
7297

@@ -87,16 +112,92 @@ injection_init_shmem(void)
87112
&found);
88113
}
89114

115+
/*
116+
* Check runtime conditions associated to an injection point.
117+
*
118+
* Returns true if the named injection point is allowed to run, and false
119+
* otherwise. Multiple conditions can be associated to a single injection
120+
* point, so check them all.
121+
*/
122+
staticbool
123+
injection_point_allowed(constchar*name)
124+
{
125+
boolresult= true;
126+
127+
if (inj_state==NULL)
128+
injection_init_shmem();
129+
130+
SpinLockAcquire(&inj_state->lock);
131+
132+
for (inti=0;i<INJ_MAX_CONDITION;i++)
133+
{
134+
InjectionPointCondition*condition=&inj_state->conditions[i];
135+
136+
if (strcmp(condition->name,name)==0)
137+
{
138+
/*
139+
* Check if this injection point is allowed to run in this
140+
* process.
141+
*/
142+
if (MyProcPid!=condition->pid)
143+
{
144+
result= false;
145+
break;
146+
}
147+
}
148+
}
149+
150+
SpinLockRelease(&inj_state->lock);
151+
152+
returnresult;
153+
}
154+
155+
/*
156+
* before_shmem_exit callback to remove injection points linked to a
157+
* specific process.
158+
*/
159+
staticvoid
160+
injection_points_cleanup(intcode,Datumarg)
161+
{
162+
/* Leave if nothing is tracked locally */
163+
if (!injection_point_local)
164+
return;
165+
166+
SpinLockAcquire(&inj_state->lock);
167+
for (inti=0;i<INJ_MAX_CONDITION;i++)
168+
{
169+
InjectionPointCondition*condition=&inj_state->conditions[i];
170+
171+
if (condition->name[0]=='\0')
172+
continue;
173+
174+
if (condition->pid!=MyProcPid)
175+
continue;
176+
177+
/* Detach the injection point and unregister condition */
178+
InjectionPointDetach(condition->name);
179+
condition->name[0]='\0';
180+
condition->pid=0;
181+
}
182+
SpinLockRelease(&inj_state->lock);
183+
}
184+
90185
/* Set of callbacks available to be attached to an injection point. */
91186
void
92187
injection_error(constchar*name)
93188
{
189+
if (!injection_point_allowed(name))
190+
return;
191+
94192
elog(ERROR,"error triggered for injection point %s",name);
95193
}
96194

97195
void
98196
injection_notice(constchar*name)
99197
{
198+
if (!injection_point_allowed(name))
199+
return;
200+
100201
elog(NOTICE,"notice triggered for injection point %s",name);
101202
}
102203

@@ -111,6 +212,9 @@ injection_wait(const char *name)
111212
if (inj_state==NULL)
112213
injection_init_shmem();
113214

215+
if (!injection_point_allowed(name))
216+
return;
217+
114218
/*
115219
* Use the injection point name for this custom wait event. Note that
116220
* this custom wait event name is not released, but we don't care much for
@@ -182,6 +286,35 @@ injection_points_attach(PG_FUNCTION_ARGS)
182286

183287
InjectionPointAttach(name,"injection_points",function);
184288

289+
if (injection_point_local)
290+
{
291+
intindex=-1;
292+
293+
/*
294+
* Register runtime condition to link this injection point to the
295+
* current process.
296+
*/
297+
SpinLockAcquire(&inj_state->lock);
298+
for (inti=0;i<INJ_MAX_CONDITION;i++)
299+
{
300+
InjectionPointCondition*condition=&inj_state->conditions[i];
301+
302+
if (condition->name[0]=='\0')
303+
{
304+
index=i;
305+
strlcpy(condition->name,name,INJ_NAME_MAXLEN);
306+
condition->pid=MyProcPid;
307+
break;
308+
}
309+
}
310+
SpinLockRelease(&inj_state->lock);
311+
312+
if (index<0)
313+
elog(FATAL,
314+
"could not find free slot for condition of injection point %s",
315+
name);
316+
}
317+
185318
PG_RETURN_VOID();
186319
}
187320

@@ -235,6 +368,32 @@ injection_points_wakeup(PG_FUNCTION_ARGS)
235368
PG_RETURN_VOID();
236369
}
237370

371+
/*
372+
* injection_points_set_local
373+
*
374+
* Track if any injection point created in this process ought to run only
375+
* in this process. Such injection points are detached automatically when
376+
* this process exits. This is useful to make test suites concurrent-safe.
377+
*/
378+
PG_FUNCTION_INFO_V1(injection_points_set_local);
379+
Datum
380+
injection_points_set_local(PG_FUNCTION_ARGS)
381+
{
382+
/* Enable flag to add a runtime condition based on this process ID */
383+
injection_point_local= true;
384+
385+
if (inj_state==NULL)
386+
injection_init_shmem();
387+
388+
/*
389+
* Register a before_shmem_exit callback to remove any injection points
390+
* linked to this process.
391+
*/
392+
before_shmem_exit(injection_points_cleanup, (Datum)0);
393+
394+
PG_RETURN_VOID();
395+
}
396+
238397
/*
239398
* SQL function for dropping an injection point.
240399
*/
@@ -246,5 +405,22 @@ injection_points_detach(PG_FUNCTION_ARGS)
246405

247406
InjectionPointDetach(name);
248407

408+
if (inj_state==NULL)
409+
injection_init_shmem();
410+
411+
/* Clean up any conditions associated to this injection point */
412+
SpinLockAcquire(&inj_state->lock);
413+
for (inti=0;i<INJ_MAX_CONDITION;i++)
414+
{
415+
InjectionPointCondition*condition=&inj_state->conditions[i];
416+
417+
if (strcmp(condition->name,name)==0)
418+
{
419+
condition->pid=0;
420+
condition->name[0]='\0';
421+
}
422+
}
423+
SpinLockRelease(&inj_state->lock);
424+
249425
PG_RETURN_VOID();
250426
}

‎src/test/modules/injection_points/sql/injection_points.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,25 @@ SELECT injection_points_run('TestInjectionLog2'); -- notice
3030
SELECT injection_points_detach('TestInjectionLog');-- fails
3131

3232
SELECT injection_points_run('TestInjectionLog2');-- notice
33+
SELECT injection_points_detach('TestInjectionLog2');
34+
35+
-- Runtime conditions
36+
SELECT injection_points_attach('TestConditionError','error');
37+
-- Any follow-up injection point attached will be local to this process.
38+
SELECT injection_points_set_local();
39+
SELECT injection_points_attach('TestConditionLocal1','error');
40+
SELECT injection_points_attach('TestConditionLocal2','notice');
41+
SELECT injection_points_run('TestConditionLocal1');-- error
42+
SELECT injection_points_run('TestConditionLocal2');-- notice
43+
-- reload, local injection points should be gone.
44+
\c
45+
SELECT injection_points_run('TestConditionLocal1');-- nothing
46+
SELECT injection_points_run('TestConditionLocal2');-- nothing
47+
SELECT injection_points_run('TestConditionError');-- error
48+
SELECT injection_points_detach('TestConditionError');
49+
-- Attaching injection points that use the same name as one defined locally
50+
-- previously should work.
51+
SELECT injection_points_attach('TestConditionLocal1','error');
52+
SELECT injection_points_detach('TestConditionLocal1');
3353

3454
DROP EXTENSION injection_points;

‎src/tools/pgindent/typedefs.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,7 @@ InitSampleScan_function
12191219
InitializeDSMForeignScan_function
12201220
InitializeWorkerForeignScan_function
12211221
InjectionPointCacheEntry
1222+
InjectionPointCondition
12221223
InjectionPointEntry
12231224
InjectionPointSharedState
12241225
InlineCodeBlock

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp