--- /dev/null
+# contrib/test_freepage/Makefile
+
+MODULES = test_freepage
+
+EXTENSION = test_freepage
+DATA = test_freepage--1.0.sql
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/test_shm_mq
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
--- /dev/null
+/* contrib/test_freepage/test_freepage--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_freepage" to load this file. \quit
+
+CREATE FUNCTION init(size pg_catalog.int8) RETURNS pg_catalog.void
+ AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
+CREATE FUNCTION get(pages pg_catalog.int8) RETURNS pg_catalog.int8
+ AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
+CREATE FUNCTION put(first_page pg_catalog.int8, npages pg_catalog.int8)
+ RETURNS pg_catalog.void AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
+CREATE FUNCTION dump() RETURNS pg_catalog.text
+ AS 'MODULE_PATHNAME' LANGUAGE C STRICT:
--- /dev/null
+/*--------------------------------------------------------------------------
+ *
+ * test_freepage.c
+ * Test harness code for free page manager.
+ *
+ * Copyright (C) 2013, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * contrib/test_freepage/test_freepage.c
+ *
+ * -------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "utils/freepage.h"
+
+PG_MODULE_MAGIC;
+PG_FUNCTION_INFO_V1(init);
+PG_FUNCTION_INFO_V1(get);
+PG_FUNCTION_INFO_V1(put);
+PG_FUNCTION_INFO_V1(dump);
+
+Datum init(PG_FUNCTION_ARGS);
+Datum get(PG_FUNCTION_ARGS);
+Datum put(PG_FUNCTION_ARGS);
+Datum dump(PG_FUNCTION_ARGS);
+
+char *space;
+FreePageManager *fpm;
+
+Datum
+init(PG_FUNCTION_ARGS)
+{
+ int64 size = PG_GETARG_INT64(0);
+ Size first_usable_page;
+ Size total_pages;
+
+ if (size <= 0 || size % FPM_PAGE_SIZE != 0)
+ elog(ERROR, "bad size");
+
+ if (space != NULL)
+ {
+ free(space);
+ space = NULL;
+ fpm = NULL;
+ }
+
+ space = malloc(size);
+ if (space == NULL)
+ elog(ERROR, "malloc failed: %m");
+
+ fpm = (FreePageManager *) space;
+ FreePageManagerInitialize(fpm, space, NULL, false);
+
+ first_usable_page = sizeof(FreePageManager) / FPM_PAGE_SIZE +
+ (sizeof(FreePageManager) % FPM_PAGE_SIZE == 0 ? 0 : 1);
+ total_pages = size / FPM_PAGE_SIZE;
+
+ FreePageManagerPut(fpm, first_usable_page,
+ total_pages - first_usable_page);
+
+ PG_RETURN_VOID();
+}
+
+Datum
+get(PG_FUNCTION_ARGS)
+{
+ int64 npages = PG_GETARG_INT64(0);
+ Size first_page;
+
+ if (fpm == NULL)
+ PG_RETURN_NULL();
+
+ if (!FreePageManagerGet(fpm, npages, &first_page))
+ PG_RETURN_NULL();
+
+ PG_RETURN_INT64(first_page);
+}
+
+Datum
+put(PG_FUNCTION_ARGS)
+{
+ int64 first_page = PG_GETARG_INT64(0);
+ int64 npages = PG_GETARG_INT64(1);
+
+ FreePageManagerPut(fpm, first_page, npages);
+
+ PG_RETURN_VOID();
+}
+
+Datum
+dump(PG_FUNCTION_ARGS)
+{
+ if (fpm == NULL)
+ PG_RETURN_NULL();
+
+ PG_RETURN_TEXT_P(cstring_to_text(FreePageManagerDump(fpm)));
+}