From 1bfbfcde0f953586fcd31e76e5789b99caa2c5a0 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 13 Nov 2018 13:19:36 +1300 Subject: [PATCH] Quick hack to try wrapping a DSA area in a MemoryContext. --- contrib/hoge/Makefile | 18 +++ contrib/hoge/hoge--1.0.sql | 15 +++ contrib/hoge/hoge.c | 247 +++++++++++++++++++++++++++++++++++++ contrib/hoge/hoge.control | 5 + 4 files changed, 285 insertions(+) create mode 100644 contrib/hoge/Makefile create mode 100644 contrib/hoge/hoge--1.0.sql create mode 100644 contrib/hoge/hoge.c create mode 100644 contrib/hoge/hoge.control diff --git a/contrib/hoge/Makefile b/contrib/hoge/Makefile new file mode 100644 index 00000000000..c569c928e09 --- /dev/null +++ b/contrib/hoge/Makefile @@ -0,0 +1,18 @@ +# contrib/isn/Makefile + +MODULES = hoge + +EXTENSION = hoge +DATA = hoge--1.0.sql +PGFILEDESC = "hoge" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/hoge +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/hoge/hoge--1.0.sql b/contrib/hoge/hoge--1.0.sql new file mode 100644 index 00000000000..cf007f8ef08 --- /dev/null +++ b/contrib/hoge/hoge--1.0.sql @@ -0,0 +1,15 @@ +/* contrib/hoge/hoge--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION hoge" to load this file. \quit + +-- Create the user-defined type for 1-D floating point intervals (seg) + +CREATE PROCEDURE hoge() +AS 'MODULE_PATHNAME' +LANGUAGE C; + +CREATE PROCEDURE hoge_list(i int) +AS 'MODULE_PATHNAME' +LANGUAGE C; + diff --git a/contrib/hoge/hoge.c b/contrib/hoge/hoge.c new file mode 100644 index 00000000000..4acb2ec13b3 --- /dev/null +++ b/contrib/hoge/hoge.c @@ -0,0 +1,247 @@ +/* + * This is terrible hack code, just to experiment with wrapping a DSA area + * in a MemoryContext. There are probably many things wrong with it, it's + * a 15 minute experiment only! + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "miscadmin.h" +#include "nodes/pg_list.h" +#include "nodes/memnodes.h" +#include "storage/ipc.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" +#include "utils/dsa.h" +#include "utils/memutils.h" + +#define MY_AREA_SIZE (1024 * 1024) + +PG_MODULE_MAGIC; + +void _PG_init(void); +PG_FUNCTION_INFO_V1(hoge); +PG_FUNCTION_INFO_V1(hoge_list); + +static void hoge_shmem_startup_hook(void); +static MemoryContext make_hoge_memory_context(dsa_area *area, void *base); + +static shmem_startup_hook_type prev_shmem_startup_hook; +static void *my_raw_memory; +static dsa_area *my_area; +static MemoryContext my_memory_context; + +static List **my_list; + +void +_PG_init(void) +{ + /* This only works if preloaded by the postmaster. */ + if (!process_shared_preload_libraries_in_progress) + return; + + /* Request a chunk of traditional shared memory. */ + RequestAddinShmemSpace(MY_AREA_SIZE); + + /* Register our hook for phase II of initialization. */ + prev_shmem_startup_hook = shmem_startup_hook; + shmem_startup_hook = hoge_shmem_startup_hook; +} + +static void +hoge_shmem_startup_hook(void) +{ + MemoryContext old_context; + bool found; + + if (prev_shmem_startup_hook) + prev_shmem_startup_hook(); + + old_context = MemoryContextSwitchTo(TopMemoryContext); + + LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); + + /* Allocate, or look up, a chunk of raw fixed-address shared memory. */ + my_raw_memory = ShmemInitStruct("hoge", MY_AREA_SIZE, &found); + if (!found) + { + /* + * Create a new DSA area, and clamp its size so it can't make any + * segments outside the provided space. + */ + my_area = dsa_create_in_place(my_raw_memory, MY_AREA_SIZE, 0, NULL); + dsa_set_size_limit(my_area, MY_AREA_SIZE); + } + else + { + /* Attach to an existing area. */ + my_area = dsa_attach_in_place(my_raw_memory, NULL); + } + + /* Also allocate or look up a list header. */ + my_list = ShmemInitStruct("hoge_list", MY_AREA_SIZE, &found); + if (!found) + *my_list = NIL; + + LWLockRelease(AddinShmemInitLock); + + /* Create a memory context. */ + my_memory_context = make_hoge_memory_context(my_area, my_raw_memory); + + MemoryContextSwitchTo(old_context); +} + +Datum +hoge(PG_FUNCTION_ARGS) +{ + char *s; + + MemoryContext old_context = MemoryContextSwitchTo(my_memory_context); + + /* Simple smoke test: allocate and free immediately. */ + s = pstrdup("hello world"); + pfree(s); + MemoryContextSwitchTo(old_context); + + PG_RETURN_VOID(); +} + +Datum +hoge_list(PG_FUNCTION_ARGS) +{ + MemoryContext old_context = MemoryContextSwitchTo(my_memory_context); + int i = PG_GETARG_INT32(0); + ListCell *lc; + + /* Manipulate a list in shared memory. */ + LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); + if (i < 0) + *my_list = list_delete_int(*my_list, -i); + else + *my_list = lappend_int(*my_list, i); + LWLockRelease(AddinShmemInitLock); + + /* Dump list. */ + elog(NOTICE, "Contents of list:"); + foreach(lc, *my_list) + elog(NOTICE, " %d", lfirst_int(lc)); + + MemoryContextSwitchTo(old_context); + + PG_RETURN_VOID(); +} + + +/* Support code to make a dsa_area into a MemoryContext. */ + +struct hoge_memory_context +{ + struct MemoryContextData memory_context; + char *base; + dsa_area *area; +}; + +static void * +hoge_alloc(MemoryContext context, Size size) +{ + struct hoge_memory_context *c = (struct hoge_memory_context *) context; + dsa_pointer chunk; + char *chunk_p; + + /* Add space for the secret context pointer. */ + chunk = dsa_allocate(c->area, sizeof(void *) + size); + chunk_p = c->base + chunk; + *(void **) chunk_p = context; + + return chunk_p + sizeof(void *); +} + +static void +hoge_free(MemoryContext context, void *pointer) +{ + struct hoge_memory_context *c = (struct hoge_memory_context *) context; + char *chunk_p; + + /* Rewind to the secret start of the chunk. */ + chunk_p = (char *) pointer - sizeof(void *); + + dsa_free(c->area, (dsa_pointer) (chunk_p - c->base)); +} + +static void * +hoge_realloc(MemoryContext context, void *pointer, Size size) +{ + elog(ERROR, "hoge_realloc not implemented"); + return NULL; +} + +static void +hoge_reset(MemoryContext context) +{ + elog(ERROR, "hoge_reset not implemented"); +} + +static void +hoge_delete(MemoryContext context) +{ + elog(ERROR, "hoge_delete not implemented"); +} + +static Size +hoge_get_chunk_space(MemoryContext context, void *pointer) +{ + elog(ERROR, "hoge_get_chunk_space not implemented"); + return 0; +} + +static bool +hoge_is_empty(MemoryContext context) +{ + elog(ERROR, "hoge_is_empty not implemented"); + return false; +} + +static void +hoge_set_state(MemoryContext context, + MemoryStatsPrintFunc printfunc, void *passthru, + MemoryContextCounters *totals) +{ + elog(ERROR, "hoge_set_state not implemented"); +} + +static void +hoge_set_check(MemoryContext context) +{ +} + +static MemoryContext +make_hoge_memory_context(dsa_area *area, void *base) +{ + static const MemoryContextMethods hoge_methods = { + hoge_alloc, + hoge_free, + hoge_realloc, + hoge_reset, + hoge_delete, + hoge_get_chunk_space, + hoge_is_empty, + hoge_set_state, +#ifdef MEMORY_CONTEXT_CHECKING + hoge_set_check +#endif + }; + + struct hoge_memory_context *result = + palloc0(sizeof(struct hoge_memory_context)); + + MemoryContextCreate(&result->memory_context, + T_SlabContext, /* TODO: this is a lie */ + &hoge_methods, + NULL, + "hoge"); + result->base = base; + result->area = area; + + return &result->memory_context; +} diff --git a/contrib/hoge/hoge.control b/contrib/hoge/hoge.control new file mode 100644 index 00000000000..1b560214823 --- /dev/null +++ b/contrib/hoge/hoge.control @@ -0,0 +1,5 @@ +# hack extension +comment = 'hoge' +default_version = '1.0' +module_pathname = '$libdir/hoge' +relocatable = true -- 2.19.1