mirror of https://github.com/postgres/postgres
Author: Bharath Rupireddy, Jeff Davis Discussion: https://postgr.es/m/CALj2ACVTBNA1wfVCsikfhygAbZe6kFY8Oz6PhOyhHyA4vAGouA%40mail.gmail.compull/138/head^2
parent
9e5405993c
commit
ae168c794f
@ -0,0 +1,4 @@ |
||||
# Generated subdirectories |
||||
/log/ |
||||
/results/ |
||||
/tmp_check/ |
||||
@ -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 |
||||
@ -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', |
||||
], |
||||
}, |
||||
} |
||||
@ -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; |
||||
@ -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…
Reference in new issue