Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * delay_execution.c
4 : : * Test module to allow delay between parsing and execution of a query.
5 : : *
6 : : * The delay is implemented by taking and immediately releasing a specified
7 : : * advisory lock. If another process has previously taken that lock, the
8 : : * current process will be blocked until the lock is released; otherwise,
9 : : * there's no effect. This allows an isolationtester script to reliably
10 : : * test behaviors where some specified action happens in another backend
11 : : * between parsing and execution of any desired query.
12 : : *
13 : : * Copyright (c) 2020-2024, PostgreSQL Global Development Group
14 : : *
15 : : * IDENTIFICATION
16 : : * src/test/modules/delay_execution/delay_execution.c
17 : : *
18 : : *-------------------------------------------------------------------------
19 : : */
20 : :
21 : : #include "postgres.h"
22 : :
23 : : #include <limits.h>
24 : :
25 : : #include "optimizer/planner.h"
26 : : #include "utils/builtins.h"
27 : : #include "utils/guc.h"
28 : : #include "utils/inval.h"
29 : :
30 : :
1346 tgl@sss.pgh.pa.us 31 :CBC 2 : PG_MODULE_MAGIC;
32 : :
33 : : /* GUC: advisory lock ID to use. Zero disables the feature. */
34 : : static int post_planning_lock_id = 0;
35 : :
36 : : /* Save previous planner hook user to be a good citizen */
37 : : static planner_hook_type prev_planner_hook = NULL;
38 : :
39 : :
40 : : /* planner_hook function to provide the desired delay */
41 : : static PlannedStmt *
42 : 15 : delay_execution_planner(Query *parse, const char *query_string,
43 : : int cursorOptions, ParamListInfo boundParams)
44 : : {
45 : : PlannedStmt *result;
46 : :
47 : : /* Invoke the planner, possibly via a previous hook user */
48 [ - + ]: 15 : if (prev_planner_hook)
1346 tgl@sss.pgh.pa.us 49 :UBC 0 : result = prev_planner_hook(parse, query_string, cursorOptions,
50 : : boundParams);
51 : : else
1346 tgl@sss.pgh.pa.us 52 :CBC 15 : result = standard_planner(parse, query_string, cursorOptions,
53 : : boundParams);
54 : :
55 : : /* If enabled, delay by taking and releasing the specified lock */
56 [ + - ]: 15 : if (post_planning_lock_id != 0)
57 : : {
58 : 15 : DirectFunctionCall1(pg_advisory_lock_int8,
59 : : Int64GetDatum((int64) post_planning_lock_id));
60 : 15 : DirectFunctionCall1(pg_advisory_unlock_int8,
61 : : Int64GetDatum((int64) post_planning_lock_id));
62 : :
63 : : /*
64 : : * Ensure that we notice any pending invalidations, since the advisory
65 : : * lock functions don't do this.
66 : : */
67 : 15 : AcceptInvalidationMessages();
68 : : }
69 : :
70 : 15 : return result;
71 : : }
72 : :
73 : : /* Module load function */
74 : : void
75 : 2 : _PG_init(void)
76 : : {
77 : : /* Set up the GUC to control which lock is used */
78 : 2 : DefineCustomIntVariable("delay_execution.post_planning_lock_id",
79 : : "Sets the advisory lock ID to be locked/unlocked after planning.",
80 : : "Zero disables the delay.",
81 : : &post_planning_lock_id,
82 : : 0,
83 : : 0, INT_MAX,
84 : : PGC_USERSET,
85 : : 0,
86 : : NULL,
87 : : NULL,
88 : : NULL);
89 : :
783 90 : 2 : MarkGUCPrefixReserved("delay_execution");
91 : :
92 : : /* Install our hook */
1346 93 : 2 : prev_planner_hook = planner_hook;
94 : 2 : planner_hook = delay_execution_planner;
95 : 2 : }
|