From 1bfbfcde0f953586fcd31e76e5789b99caa2c5a0 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
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

