Add a test module csn5
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 22 Aug 2016 16:23:34 +0000 (19:23 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 22 Aug 2016 18:21:58 +0000 (21:21 +0300)
src/test/modules/mvcctorture/Makefile [new file with mode: 0644]
src/test/modules/mvcctorture/README [new file with mode: 0644]
src/test/modules/mvcctorture/mvcctorture--1.0.sql [new file with mode: 0644]
src/test/modules/mvcctorture/mvcctorture.c [new file with mode: 0644]
src/test/modules/mvcctorture/mvcctorture.control [new file with mode: 0644]

diff --git a/src/test/modules/mvcctorture/Makefile b/src/test/modules/mvcctorture/Makefile
new file mode 100644 (file)
index 0000000..cc4ebc8
--- /dev/null
@@ -0,0 +1,18 @@
+# src/test/modules/mvcctorture/Makefile
+
+MODULE_big     = mvcctorture
+OBJS           = mvcctorture.o
+
+EXTENSION = mvcctorture
+DATA = mvcctorture--1.0.sql
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/mvcctorture
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/mvcctorture/README b/src/test/modules/mvcctorture/README
new file mode 100644 (file)
index 0000000..915b001
--- /dev/null
@@ -0,0 +1,25 @@
+A litte helper module for testing MVCC performance.
+
+The populate_mvcc_test_table function can be used to create a test table,
+with given number of rows. Each row in the table is stamped with a different
+xmin, and XMIN_COMMITTED hint bit can be set or not. Furthermore, the
+xmins values are shuffled, to defeat caching in transam.c and clog.c as badly
+as possible.
+
+The test table is always called "mvcc_test_table". You'll have to drop it
+yourself between tests.
+
+For example:
+
+-- Create a test table with 10 million rows, without setting hint bits
+select populate_mvcc_test_table(10000000, false);
+
+-- See how long it takes to scan it
+\timing
+select count(*) from mvcc_test_table;
+
+
+
+If you do the above, but have another psql session open, in a transaction
+that's done some updates, i.e. is holding backthe xmin horizon, you will
+see the worst-case performance of the CSN patch.
diff --git a/src/test/modules/mvcctorture/mvcctorture--1.0.sql b/src/test/modules/mvcctorture/mvcctorture--1.0.sql
new file mode 100644 (file)
index 0000000..652a6a3
--- /dev/null
@@ -0,0 +1,9 @@
+/* src/test/modules/mvcctorture/mvcctorture--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION mvcctorture" to load this file. \quit
+
+CREATE FUNCTION populate_mvcc_test_table(int4, bool)
+RETURNS void
+AS 'MODULE_PATHNAME', 'populate_mvcc_test_table'
+LANGUAGE C STRICT;
diff --git a/src/test/modules/mvcctorture/mvcctorture.c b/src/test/modules/mvcctorture/mvcctorture.c
new file mode 100644 (file)
index 0000000..a89a2e6
--- /dev/null
@@ -0,0 +1,129 @@
+/*-------------------------------------------------------------------------
+ *
+ * mvctorture.c
+ *
+ * Copyright (c) 2012, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *       src/test/modules/mvcctorture.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/hio.h"
+#include "access/htup_details.h"
+#include "access/transam.h"
+#include "access/xact.h"
+#include "access/visibilitymap.h"
+#include "catalog/pg_am.h"
+#include "executor/spi.h"
+#include "funcapi.h"
+#include "nodes/makefuncs.h"
+#include "storage/bufmgr.h"
+#include "utils/rel.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(populate_mvcc_test_table);
+
+Datum
+populate_mvcc_test_table(PG_FUNCTION_ARGS)
+{
+       uint32          nrows = PG_GETARG_UINT32(0);
+       bool            set_xmin_committed = PG_GETARG_BOOL(1);
+       RangeVar   *rv;
+       Relation        rel;
+       Datum           values[1];
+       bool            isnull[1];
+       HeapTuple       tup;
+       TransactionId *xids;
+       int                     ret;
+       int                     i;
+       Buffer          buffer;
+       Buffer          vmbuffer = InvalidBuffer;
+
+       /* Connect to SPI manager */
+       if ((ret = SPI_connect()) < 0)
+               /* internal error */
+               elog(ERROR, "populate_mvcc_test_table: SPI_connect returned %d", ret);
+
+       SPI_execute("CREATE TABLE mvcc_test_table(i int4)", false, 0);
+
+       SPI_finish();
+
+       /* Generate a different XID for each tuple */
+       xids = (TransactionId *) palloc0(nrows * sizeof(TransactionId));
+       for (i = 0; i < nrows; i++)
+       {
+               BeginInternalSubTransaction(NULL);
+               xids[i] = GetCurrentTransactionId();
+               ReleaseCurrentSubTransaction();
+       }
+
+       rv = makeRangeVar(NULL, "mvcc_test_table", -1);
+
+       rel = heap_openrv(rv, RowExclusiveLock);
+
+       /* shuffle */
+       for (i = 0; i < nrows - 1; i++)
+       {
+               int x = i + (random() % (nrows - i));
+               TransactionId tmp;
+
+               tmp = xids[i];
+               xids[i] = xids[x];
+               xids[x] = tmp;
+       }
+
+       for (i = 0; i < nrows; i++)
+       {
+               values[0] = Int32GetDatum(i);
+               isnull[0] = false;
+
+               tup = heap_form_tuple(RelationGetDescr(rel), values, isnull);
+
+               /* Fill the header fields, like heap_prepare_insert does */
+               tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
+               tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
+               tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
+               if (set_xmin_committed)
+                       tup->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
+               HeapTupleHeaderSetXmin(tup->t_data, xids[i]);
+               HeapTupleHeaderSetCmin(tup->t_data, 1);
+               HeapTupleHeaderSetXmax(tup->t_data, 0);         /* for cleanliness */
+               tup->t_tableOid = RelationGetRelid(rel);
+
+               heap_freetuple(tup);
+
+               /*
+                * Find buffer to insert this tuple into.  If the page is all visible,
+                * this will also pin the requisite visibility map page.
+                */
+               buffer = RelationGetBufferForTuple(rel, tup->t_len,
+                                                                                  InvalidBuffer,
+                                                                                  0, NULL,
+                                                                                  &vmbuffer, NULL);
+               RelationPutHeapTuple(rel, buffer, tup, false);
+
+               if (PageIsAllVisible(BufferGetPage(buffer)))
+               {
+                       PageClearAllVisible(BufferGetPage(buffer));
+                       visibilitymap_clear(rel,
+                                                               ItemPointerGetBlockNumber(&(tup->t_self)),
+                                                               vmbuffer, VISIBILITYMAP_VALID_BITS);
+               }
+
+               MarkBufferDirty(buffer);
+               UnlockReleaseBuffer(buffer);
+       }
+
+       if (vmbuffer != InvalidBuffer)
+               ReleaseBuffer(vmbuffer);
+
+       heap_close(rel, NoLock);
+
+       PG_RETURN_VOID();
+}
diff --git a/src/test/modules/mvcctorture/mvcctorture.control b/src/test/modules/mvcctorture/mvcctorture.control
new file mode 100644 (file)
index 0000000..1b5feb9
--- /dev/null
@@ -0,0 +1,5 @@
+# mvcctorture extension
+comment = 'populate a table with a mix of different XIDs'
+default_version = '1.0'
+module_pathname = '$libdir/mvcctorture'
+relocatable = true