Add test module for Custom WAL Resource Manager feature.

Author: Bharath Rupireddy, Jeff Davis
Discussion: https://postgr.es/m/CALj2ACVTBNA1wfVCsikfhygAbZe6kFY8Oz6PhOyhHyA4vAGouA%40mail.gmail.com
This commit is contained in:
Jeff Davis 2022-11-15 13:10:27 -08:00
parent 9e5405993c
commit ae168c794f
10 changed files with 291 additions and 0 deletions

View File

@ -57,6 +57,13 @@ typedef struct RmgrData
} RmgrData;
</programlisting>
</para>
<para>
The <filename>src/test/modules/test_custom_rmgrs</filename> module
contains a working example, which demonstrates usage of custom WAL
resource managers.
</para>
<para>
Then, register your new resource
manager.

View File

@ -16,6 +16,7 @@ SUBDIRS = \
spgist_name_ops \
test_bloomfilter \
test_copy_callbacks \
test_custom_rmgrs \
test_ddl_deparse \
test_extensions \
test_ginpostinglist \

View File

@ -10,6 +10,7 @@ subdir('spgist_name_ops')
subdir('ssl_passphrase_callback')
subdir('test_bloomfilter')
subdir('test_copy_callbacks')
subdir('test_custom_rmgrs')
subdir('test_ddl_deparse')
subdir('test_extensions')
subdir('test_ginpostinglist')

View File

@ -0,0 +1,4 @@
# Generated subdirectories
/log/
/results/
/tmp_check/

View File

@ -0,0 +1,24 @@
# src/test/modules/test_custom_rmgrs/Makefile
MODULE_big = test_custom_rmgrs
OBJS = \
$(WIN32RES) \
test_custom_rmgrs.o
PGFILEDESC = "test_custom_rmgrs - test custom WAL resource managers"
EXTENSION = test_custom_rmgrs
DATA = test_custom_rmgrs--1.0.sql
EXTRA_INSTALL = contrib/pg_walinspect
TAP_TESTS = 1
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = src/test/modules/test_custom_rmgrs
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif

View File

@ -0,0 +1,34 @@
# FIXME: prevent install during main install, but not during test :/
test_custom_rmgrs_sources = files(
'test_custom_rmgrs.c',
)
if host_system == 'windows'
test_custom_rmgrs_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
'--NAME', 'test_custom_rmgrs',
'--FILEDESC', 'test_custom_rmgrs - test custom WAL resource managers',])
endif
test_custom_rmgrs = shared_module('test_custom_rmgrs',
test_custom_rmgrs_sources,
kwargs: pg_mod_args,
)
testprep_targets += test_custom_rmgrs
install_data(
'test_custom_rmgrs.control',
'test_custom_rmgrs--1.0.sql',
kwargs: contrib_data_args,
)
tests += {
'name': 'test_custom_rmgrs',
'sd': meson.current_source_dir(),
'bd': meson.current_build_dir(),
'tap': {
'tests': [
't/001_basic.pl',
],
},
}

View File

@ -0,0 +1,61 @@
# Copyright (c) 2021-2022, PostgreSQL Global Development Group
use strict;
use warnings;
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;
my $node = PostgreSQL::Test::Cluster->new('main');
$node->init;
$node->append_conf(
'postgresql.conf', q{
wal_level = 'replica'
max_wal_senders = 4
shared_preload_libraries = 'test_custom_rmgrs'
});
$node->start;
# setup
$node->safe_psql('postgres', 'CREATE EXTENSION test_custom_rmgrs');
# pg_walinspect is required only for verifying test_custom_rmgrs output.
# test_custom_rmgrs doesn't use/depend on it internally.
$node->safe_psql('postgres', 'CREATE EXTENSION pg_walinspect');
# make sure checkpoints don't interfere with the test.
my $start_lsn = $node->safe_psql('postgres',
qq[SELECT lsn FROM pg_create_physical_replication_slot('regress_test_slot1', true, false);]);
# write and save the WAL record's returned end LSN for verifying it later
my $record_end_lsn = $node->safe_psql('postgres',
'SELECT * FROM test_custom_rmgrs_insert_wal_record(\'payload123\')');
# ensure the WAL is written and flushed to disk
$node->safe_psql('postgres', 'SELECT pg_switch_wal()');
my $end_lsn = $node->safe_psql('postgres', 'SELECT pg_current_wal_flush_lsn()');
# check if our custom WAL resource manager has successfully registered with the server
my $row_count =
$node->safe_psql('postgres',
qq[SELECT count(*) FROM pg_get_wal_resource_managers()
WHERE rm_name = 'test_custom_rmgrs';]);
is($row_count, '1',
'custom WAL resource manager has successfully registered with the server'
);
# check if our custom WAL resource manager has successfully written a WAL record
my $expected = qq($record_end_lsn|test_custom_rmgrs|TEST_CUSTOM_RMGRS_MESSAGE|44|18|0|payload (10 bytes): payload123);
my $result =
$node->safe_psql('postgres',
qq[SELECT end_lsn, resource_manager, record_type, record_length, main_data_length, fpi_length, description FROM pg_get_wal_records_info('$start_lsn', '$end_lsn')
WHERE resource_manager = 'test_custom_rmgrs';]);
is($result, $expected,
'custom WAL resource manager has successfully written a WAL record'
);
$node->stop;
done_testing();

View File

@ -0,0 +1,16 @@
/* src/test/modules/test_custom_rmgrs/test_custom_rmgrs--1.0.sql */
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION test_custom_rmgrs" to load this file. \quit
--
-- test_custom_rmgrs_insert_wal_record()
--
-- Writes a simple message into WAL with the help of custom WAL
-- resource manager.
--
CREATE FUNCTION test_custom_rmgrs_insert_wal_record(IN payload TEXT,
OUT lsn pg_lsn
)
AS 'MODULE_PATHNAME', 'test_custom_rmgrs_insert_wal_record'
LANGUAGE C STRICT PARALLEL UNSAFE;

View File

@ -0,0 +1,139 @@
/*--------------------------------------------------------------------------
*
* test_custom_rmgrs.c
* Code for testing custom WAL resource managers.
*
* Portions Copyright (c) 1996-2022, 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"
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 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);
}

View File

@ -0,0 +1,4 @@
comment = 'Test code for custom WAL resource managers'
default_version = '1.0'
module_pathname = '$libdir/test_custom_rmgrs'
relocatable = true