Branch data Line data Source code
1 : : /*--------------------------------------------------------------------------
2 : : *
3 : : * test_wait_lsn.c
4 : : * Test support for WAIT FOR LSN.
5 : : *
6 : : * Copyright (c) 2026, PostgreSQL Global Development Group
7 : : *
8 : : * IDENTIFICATION
9 : : * src/test/modules/test_wait_lsn/test_wait_lsn.c
10 : : *
11 : : * -------------------------------------------------------------------------
12 : : */
13 : : #include "postgres.h"
14 : :
15 : : #include "access/xlogwait.h"
16 : : #include "fmgr.h"
17 : : #include "storage/lwlock.h"
18 : : #include "storage/proc.h"
19 : : #include "storage/procarray.h"
20 : : #include "utils/builtins.h"
21 : : #include "utils/pg_lsn.h"
22 : :
23 : 4 : PG_MODULE_MAGIC;
24 : :
25 : 2 : PG_FUNCTION_INFO_V1(test_wait_lsn_wakeup);
26 : 3 : PG_FUNCTION_INFO_V1(test_wait_lsn_waiter_is_registered);
27 : :
28 : : static WaitLSNType
29 : 3 : parse_wait_lsn_type(text *mode_text)
30 : : {
31 : 3 : char *mode = text_to_cstring(mode_text);
32 : : WaitLSNType lsn_type;
33 : :
34 [ - + ]: 3 : if (pg_strcasecmp(mode, "standby_replay") == 0)
35 : 0 : lsn_type = WAIT_LSN_TYPE_STANDBY_REPLAY;
36 [ + - ]: 3 : else if (pg_strcasecmp(mode, "standby_write") == 0)
37 : 3 : lsn_type = WAIT_LSN_TYPE_STANDBY_WRITE;
38 [ # # ]: 0 : else if (pg_strcasecmp(mode, "standby_flush") == 0)
39 : 0 : lsn_type = WAIT_LSN_TYPE_STANDBY_FLUSH;
40 [ # # ]: 0 : else if (pg_strcasecmp(mode, "primary_flush") == 0)
41 : 0 : lsn_type = WAIT_LSN_TYPE_PRIMARY_FLUSH;
42 : : else
43 [ # # ]: 0 : ereport(ERROR,
44 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
45 : : errmsg("unrecognized WAIT FOR LSN mode \"%s\"", mode)));
46 : :
47 : 3 : pfree(mode);
48 : 3 : return lsn_type;
49 : : }
50 : :
51 : : /*
52 : : * Wake all waiters of the supplied type through the supplied LSN without
53 : : * advancing the underlying WAL position.
54 : : */
55 : : Datum
56 : 1 : test_wait_lsn_wakeup(PG_FUNCTION_ARGS)
57 : : {
58 : 1 : WaitLSNType lsn_type = parse_wait_lsn_type(PG_GETARG_TEXT_PP(0));
59 : 1 : XLogRecPtr upto_lsn = PG_GETARG_LSN(1);
60 : :
61 : 1 : WaitLSNWakeup(lsn_type, upto_lsn);
62 : :
63 : 1 : PG_RETURN_VOID();
64 : : }
65 : :
66 : : /*
67 : : * Check whether the backend with the supplied PID is registered for the
68 : : * supplied mode and target. ProcArrayLock stabilizes the PID mapping, while
69 : : * WaitLSNLock protects the registration state.
70 : : */
71 : : Datum
72 : 2 : test_wait_lsn_waiter_is_registered(PG_FUNCTION_ARGS)
73 : : {
74 : 2 : int pid = PG_GETARG_INT32(0);
75 : 2 : WaitLSNType lsn_type = parse_wait_lsn_type(PG_GETARG_TEXT_PP(1));
76 : 2 : XLogRecPtr target_lsn = PG_GETARG_LSN(2);
77 : 2 : bool registered = false;
78 : : PGPROC *proc;
79 : :
80 : 2 : LWLockAcquire(ProcArrayLock, LW_SHARED);
81 : 2 : proc = BackendPidGetProcWithLock(pid);
82 : :
83 [ + - ]: 2 : if (proc != NULL)
84 : : {
85 : 2 : ProcNumber procno = GetNumberFromPGProc(proc);
86 : 2 : WaitLSNProcInfo *proc_info = &waitLSNState->procInfos[procno];
87 : :
88 : 2 : LWLockAcquire(WaitLSNLock, LW_SHARED);
89 : 6 : registered = proc_info->inHeap &&
90 [ + - ]: 2 : proc_info->procno == procno &&
91 [ + - + - ]: 6 : proc_info->lsnType == lsn_type &&
92 [ + - ]: 2 : proc_info->waitLSN == target_lsn;
93 : 2 : LWLockRelease(WaitLSNLock);
94 : : }
95 : :
96 : 2 : LWLockRelease(ProcArrayLock);
97 : :
98 : 2 : PG_RETURN_BOOL(registered);
99 : : }
|