aboutsummaryrefslogtreecommitdiff
path: root/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
blob: 85038f549db496b356fe0fc5a97124e81b5c017c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*--------------------------------------------------------------------------
 *
 * test_custom_rmgrs.c
 *		Code for testing custom WAL resource managers.
 *
 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *		src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
 *
 * Custom WAL resource manager for records containing a simple textual
 * payload, no-op redo, and no decoding.
 *
 * -------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/xlog.h"
#include "access/xlog_internal.h"
#include "access/xloginsert.h"
#include "fmgr.h"
#include "utils/pg_lsn.h"
#include "varatt.h"

PG_MODULE_MAGIC;

/*
 * test_custom_rmgrs WAL record message.
 */
typedef struct xl_testcustomrmgrs_message
{
	Size		message_size;	/* size of the message */
	char		message[FLEXIBLE_ARRAY_MEMBER]; /* payload */
} xl_testcustomrmgrs_message;

#define SizeOfTestCustomRmgrsMessage	(offsetof(xl_testcustomrmgrs_message, message))
#define XLOG_TEST_CUSTOM_RMGRS_MESSAGE	0x00

/*
 * While developing or testing, use RM_EXPERIMENTAL_ID for rmid. For a real
 * extension, reserve a new resource manager ID to avoid conflicting with
 * other extensions; see:
 * https://wiki.postgresql.org/wiki/CustomWALResourceManagers
 */
#define RM_TESTCUSTOMRMGRS_ID			RM_EXPERIMENTAL_ID
#define TESTCUSTOMRMGRS_NAME			"test_custom_rmgrs"

/* RMGR API, see xlog_internal.h */
void		testcustomrmgrs_redo(XLogReaderState *record);
void		testcustomrmgrs_desc(StringInfo buf, XLogReaderState *record);
const char *testcustomrmgrs_identify(uint8 info);

static const RmgrData testcustomrmgrs_rmgr = {
	.rm_name = TESTCUSTOMRMGRS_NAME,
	.rm_redo = testcustomrmgrs_redo,
	.rm_desc = testcustomrmgrs_desc,
	.rm_identify = testcustomrmgrs_identify
};

/*
 * Module load callback
 */
void
_PG_init(void)
{
	/*
	 * In order to create our own custom resource manager, we have to be
	 * loaded via shared_preload_libraries. Otherwise, registration will fail.
	 */
	RegisterCustomRmgr(RM_TESTCUSTOMRMGRS_ID, &testcustomrmgrs_rmgr);
}

/* RMGR API implementation */

/*
 * Redo is just a noop for this module, because we aren't testing recovery of
 * any real structure.
 */
void
testcustomrmgrs_redo(XLogReaderState *record)
{
	uint8		info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;

	if (info != XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
		elog(PANIC, "testcustomrmgrs_redo: unknown op code %u", info);
}

void
testcustomrmgrs_desc(StringInfo buf, XLogReaderState *record)
{
	char	   *rec = XLogRecGetData(record);
	uint8		info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;

	if (info == XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
	{
		xl_testcustomrmgrs_message *xlrec = (xl_testcustomrmgrs_message *) rec;

		appendStringInfo(buf, "payload (%zu bytes): ", xlrec->message_size);
		appendBinaryStringInfo(buf, xlrec->message, xlrec->message_size);
	}
}

const char *
testcustomrmgrs_identify(uint8 info)
{
	if ((info & ~XLR_INFO_MASK) == XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
		return "TEST_CUSTOM_RMGRS_MESSAGE";

	return NULL;
}

/*
 * SQL function for writing a simple message into WAL with the help of custom
 * WAL resource manager.
 */
PG_FUNCTION_INFO_V1(test_custom_rmgrs_insert_wal_record);
Datum
test_custom_rmgrs_insert_wal_record(PG_FUNCTION_ARGS)
{
	text	   *arg = PG_GETARG_TEXT_PP(0);
	char	   *payload = VARDATA_ANY(arg);
	Size		len = VARSIZE_ANY_EXHDR(arg);
	XLogRecPtr	lsn;
	xl_testcustomrmgrs_message xlrec;

	xlrec.message_size = len;

	XLogBeginInsert();
	XLogRegisterData((char *) &xlrec, SizeOfTestCustomRmgrsMessage);
	XLogRegisterData((char *) payload, len);

	/* Let's mark this record as unimportant, just in case. */
	XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT);

	lsn = XLogInsert(RM_TESTCUSTOMRMGRS_ID, XLOG_TEST_CUSTOM_RMGRS_MESSAGE);

	PG_RETURN_LSN(lsn);
}