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:
parent
9e5405993c
commit
ae168c794f
@ -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.
|
||||
|
@ -16,6 +16,7 @@ SUBDIRS = \
|
||||
spgist_name_ops \
|
||||
test_bloomfilter \
|
||||
test_copy_callbacks \
|
||||
test_custom_rmgrs \
|
||||
test_ddl_deparse \
|
||||
test_extensions \
|
||||
test_ginpostinglist \
|
||||
|
@ -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')
|
||||
|
4
src/test/modules/test_custom_rmgrs/.gitignore
vendored
Normal file
4
src/test/modules/test_custom_rmgrs/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Generated subdirectories
|
||||
/log/
|
||||
/results/
|
||||
/tmp_check/
|
24
src/test/modules/test_custom_rmgrs/Makefile
Normal file
24
src/test/modules/test_custom_rmgrs/Makefile
Normal 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
|
34
src/test/modules/test_custom_rmgrs/meson.build
Normal file
34
src/test/modules/test_custom_rmgrs/meson.build
Normal 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',
|
||||
],
|
||||
},
|
||||
}
|
61
src/test/modules/test_custom_rmgrs/t/001_basic.pl
Normal file
61
src/test/modules/test_custom_rmgrs/t/001_basic.pl
Normal 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();
|
@ -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;
|
139
src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
Normal file
139
src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
Normal 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);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
comment = 'Test code for custom WAL resource managers'
|
||||
default_version = '1.0'
|
||||
module_pathname = '$libdir/test_custom_rmgrs'
|
||||
relocatable = true
|
Loading…
x
Reference in New Issue
Block a user