Age Owner 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-2023, 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 :
145 jdavis 27 GNC 1 : 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 1 : _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 1 : RegisterCustomRmgr(RM_TESTCUSTOMRMGRS_ID, &testcustomrmgrs_rmgr);
73 1 : }
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
145 jdavis 82 UNC 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
145 jdavis 91 GNC 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 :
145 jdavis 111 UNC 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 : */
145 jdavis 118 GNC 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 : }
|