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 : 27 2 : 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 2 : _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 2 : RegisterCustomRmgr(RM_TESTCUSTOMRMGRS_ID, &testcustomrmgrs_rmgr); 73 2 : } 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 82 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 91 2 : testcustomrmgrs_desc(StringInfo buf, XLogReaderState *record) 92 : { 93 2 : char *rec = XLogRecGetData(record); 94 2 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; 95 : 96 2 : if (info == XLOG_TEST_CUSTOM_RMGRS_MESSAGE) 97 : { 98 2 : xl_testcustomrmgrs_message *xlrec = (xl_testcustomrmgrs_message *) rec; 99 : 100 2 : appendStringInfo(buf, "payload (%zu bytes): ", xlrec->message_size); 101 2 : appendBinaryStringInfo(buf, xlrec->message, xlrec->message_size); 102 : } 103 2 : } 104 : 105 : const char * 106 2 : testcustomrmgrs_identify(uint8 info) 107 : { 108 2 : if ((info & ~XLR_INFO_MASK) == XLOG_TEST_CUSTOM_RMGRS_MESSAGE) 109 2 : return "TEST_CUSTOM_RMGRS_MESSAGE"; 110 : 111 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 : */ 118 4 : PG_FUNCTION_INFO_V1(test_custom_rmgrs_insert_wal_record); 119 : Datum 120 2 : test_custom_rmgrs_insert_wal_record(PG_FUNCTION_ARGS) 121 : { 122 2 : text *arg = PG_GETARG_TEXT_PP(0); 123 2 : char *payload = VARDATA_ANY(arg); 124 2 : Size len = VARSIZE_ANY_EXHDR(arg); 125 : XLogRecPtr lsn; 126 : xl_testcustomrmgrs_message xlrec; 127 : 128 2 : xlrec.message_size = len; 129 : 130 2 : XLogBeginInsert(); 131 2 : XLogRegisterData((char *) &xlrec, SizeOfTestCustomRmgrsMessage); 132 2 : XLogRegisterData((char *) payload, len); 133 : 134 : /* Let's mark this record as unimportant, just in case. */ 135 2 : XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT); 136 : 137 2 : lsn = XLogInsert(RM_TESTCUSTOMRMGRS_ID, XLOG_TEST_CUSTOM_RMGRS_MESSAGE); 138 : 139 2 : PG_RETURN_LSN(lsn); 140 : }