Age Owner Branch data TLA Line data Source code
1 : : /*--------------------------------------------------------------------------
2 : : *
3 : : * test_custom_rmgrs.c
4 : : * Code for testing custom WAL resource managers.
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : * IDENTIFICATION
10 : : * src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
11 : : *
12 : : * Custom WAL resource manager for records containing a simple textual
13 : : * payload, no-op redo, and no decoding.
14 : : *
15 : : * -------------------------------------------------------------------------
16 : : */
17 : :
18 : : #include "postgres.h"
19 : :
20 : : #include "access/xlog.h"
21 : : #include "access/xlog_internal.h"
22 : : #include "access/xloginsert.h"
23 : : #include "fmgr.h"
24 : : #include "utils/pg_lsn.h"
25 : : #include "varatt.h"
26 : :
516 jdavis@postgresql.or 27 :CBC 15 : PG_MODULE_MAGIC;
28 : :
29 : : /*
30 : : * test_custom_rmgrs WAL record message.
31 : : */
32 : : typedef struct xl_testcustomrmgrs_message
33 : : {
34 : : Size message_size; /* size of the message */
35 : : char message[FLEXIBLE_ARRAY_MEMBER]; /* payload */
36 : : } xl_testcustomrmgrs_message;
37 : :
38 : : #define SizeOfTestCustomRmgrsMessage (offsetof(xl_testcustomrmgrs_message, message))
39 : : #define XLOG_TEST_CUSTOM_RMGRS_MESSAGE 0x00
40 : :
41 : : /*
42 : : * While developing or testing, use RM_EXPERIMENTAL_ID for rmid. For a real
43 : : * extension, reserve a new resource manager ID to avoid conflicting with
44 : : * other extensions; see:
45 : : * https://wiki.postgresql.org/wiki/CustomWALResourceManagers
46 : : */
47 : : #define RM_TESTCUSTOMRMGRS_ID RM_EXPERIMENTAL_ID
48 : : #define TESTCUSTOMRMGRS_NAME "test_custom_rmgrs"
49 : :
50 : : /* RMGR API, see xlog_internal.h */
51 : : void testcustomrmgrs_redo(XLogReaderState *record);
52 : : void testcustomrmgrs_desc(StringInfo buf, XLogReaderState *record);
53 : : const char *testcustomrmgrs_identify(uint8 info);
54 : :
55 : : static const RmgrData testcustomrmgrs_rmgr = {
56 : : .rm_name = TESTCUSTOMRMGRS_NAME,
57 : : .rm_redo = testcustomrmgrs_redo,
58 : : .rm_desc = testcustomrmgrs_desc,
59 : : .rm_identify = testcustomrmgrs_identify
60 : : };
61 : :
62 : : /*
63 : : * Module load callback
64 : : */
65 : : void
66 : 15 : _PG_init(void)
67 : : {
68 : : /*
69 : : * In order to create our own custom resource manager, we have to be
70 : : * loaded via shared_preload_libraries. Otherwise, registration will fail.
71 : : */
72 : 15 : RegisterCustomRmgr(RM_TESTCUSTOMRMGRS_ID, &testcustomrmgrs_rmgr);
73 : 15 : }
74 : :
75 : : /* RMGR API implementation */
76 : :
77 : : /*
78 : : * Redo is just a noop for this module, because we aren't testing recovery of
79 : : * any real structure.
80 : : */
81 : : void
516 jdavis@postgresql.or 82 :UBC 0 : testcustomrmgrs_redo(XLogReaderState *record)
83 : : {
84 : 0 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
85 : :
86 [ # # ]: 0 : if (info != XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
87 [ # # ]: 0 : elog(PANIC, "testcustomrmgrs_redo: unknown op code %u", info);
88 : 0 : }
89 : :
90 : : void
516 jdavis@postgresql.or 91 :CBC 1 : testcustomrmgrs_desc(StringInfo buf, XLogReaderState *record)
92 : : {
93 : 1 : char *rec = XLogRecGetData(record);
94 : 1 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
95 : :
96 [ + - ]: 1 : if (info == XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
97 : : {
98 : 1 : xl_testcustomrmgrs_message *xlrec = (xl_testcustomrmgrs_message *) rec;
99 : :
100 : 1 : appendStringInfo(buf, "payload (%zu bytes): ", xlrec->message_size);
101 : 1 : appendBinaryStringInfo(buf, xlrec->message, xlrec->message_size);
102 : : }
103 : 1 : }
104 : :
105 : : const char *
106 : 1 : testcustomrmgrs_identify(uint8 info)
107 : : {
108 [ + - ]: 1 : if ((info & ~XLR_INFO_MASK) == XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
109 : 1 : return "TEST_CUSTOM_RMGRS_MESSAGE";
110 : :
516 jdavis@postgresql.or 111 :UBC 0 : return NULL;
112 : : }
113 : :
114 : : /*
115 : : * SQL function for writing a simple message into WAL with the help of custom
116 : : * WAL resource manager.
117 : : */
516 jdavis@postgresql.or 118 :CBC 2 : PG_FUNCTION_INFO_V1(test_custom_rmgrs_insert_wal_record);
119 : : Datum
120 : 1 : test_custom_rmgrs_insert_wal_record(PG_FUNCTION_ARGS)
121 : : {
122 : 1 : text *arg = PG_GETARG_TEXT_PP(0);
123 [ - + ]: 1 : char *payload = VARDATA_ANY(arg);
124 [ - + - - : 1 : Size len = VARSIZE_ANY_EXHDR(arg);
- - - - -
+ ]
125 : : XLogRecPtr lsn;
126 : : xl_testcustomrmgrs_message xlrec;
127 : :
128 : 1 : xlrec.message_size = len;
129 : :
130 : 1 : XLogBeginInsert();
131 : 1 : XLogRegisterData((char *) &xlrec, SizeOfTestCustomRmgrsMessage);
132 : 1 : XLogRegisterData((char *) payload, len);
133 : :
134 : : /* Let's mark this record as unimportant, just in case. */
135 : 1 : XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT);
136 : :
137 : 1 : lsn = XLogInsert(RM_TESTCUSTOMRMGRS_ID, XLOG_TEST_CUSTOM_RMGRS_MESSAGE);
138 : :
139 : 1 : PG_RETURN_LSN(lsn);
140 : : }
|