From c7bf0aaa470028372b27e05cf8b9132793ee18a8 Mon Sep 17 00:00:00 2001
From: Borodin Andrey <borodinandrew@tty1.local>
Date: Sat, 24 Oct 2020 15:47:20 +0500
Subject: [PATCH] Make GiST deterministic

This commit adds PRNG state of randomness used in GiST insertion
to GiST state. This renders all test runs detrministic.
---
 src/backend/access/gist/gist.c     |  7 +++++++
 src/backend/access/gist/gistutil.c |  5 +++--
 src/backend/utils/misc/guc.c       | 11 +++++++++++
 src/include/access/gist.h          |  2 ++
 src/include/access/gist_private.h  |  3 +++
 5 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 25b42e38f2..0b5842068a 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -27,6 +27,8 @@
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
+double gist_seed;
+
 /* non-export function prototypes */
 static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate);
 static bool gistinserttuple(GISTInsertState *state, GISTInsertStack *stack,
@@ -1617,6 +1619,11 @@ initGISTstate(Relation index)
 		giststate->supportCollation[i] = InvalidOid;
 	}
 
+	memset(&giststate->random_state, 0, sizeof(giststate->random_state));
+	memcpy(&giststate->random_state,
+		   &gist_seed,
+		   Min(sizeof(giststate->random_state), sizeof(gist_seed)));
+
 	MemoryContextSwitchTo(oldCxt);
 
 	return giststate;
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 615b5ade23..2ca53068c4 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -19,6 +19,7 @@
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
+#include "port.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "utils/float.h"
@@ -507,7 +508,7 @@ gistchoose(Relation r, Page p, IndexTuple it,	/* it has compressed entry */
 			if (keep_current_best == -1)
 			{
 				/* we didn't make the random choice yet for this old best */
-				keep_current_best = (random() <= (MAX_RANDOM_VALUE / 2)) ? 1 : 0;
+				keep_current_best = pg_jrand48(giststate->random_state) & 1;
 			}
 			if (keep_current_best == 0)
 			{
@@ -529,7 +530,7 @@ gistchoose(Relation r, Page p, IndexTuple it,	/* it has compressed entry */
 			if (keep_current_best == -1)
 			{
 				/* we didn't make the random choice yet for this old best */
-				keep_current_best = (random() <= (MAX_RANDOM_VALUE / 2)) ? 1 : 0;
+				keep_current_best = pg_jrand48(giststate->random_state) & 1;
 			}
 			if (keep_current_best == 1)
 				break;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a62d64eaa4..f2be4700e7 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -30,6 +30,7 @@
 #include <unistd.h>
 
 #include "access/commit_ts.h"
+#include "access/gist.h"
 #include "access/gin.h"
 #include "access/rmgr.h"
 #include "access/tableam.h"
@@ -3552,6 +3553,16 @@ static struct config_real ConfigureNamesReal[] =
 		0.0, 0.0, 1.0,
 		NULL, NULL, NULL
 	},
+	{
+		{"gist_seed", PGC_USERSET, DEVELOPER_OPTIONS,
+			gettext_noop("Seed for random path selection in GiST insertion."),
+			NULL,
+			GUC_EXPLAIN
+		},
+		&gist_seed,
+		0.0, 0.0, 1.0,
+		NULL, NULL, NULL
+	},
 
 	{
 		{"hash_mem_multiplier", PGC_USERSET, RESOURCES_MEM,
diff --git a/src/include/access/gist.h b/src/include/access/gist.h
index 4f6dae9a76..9fde15a399 100644
--- a/src/include/access/gist.h
+++ b/src/include/access/gist.h
@@ -237,4 +237,6 @@ typedef struct
 	do { (e).key = (k); (e).rel = (r); (e).page = (pg); \
 		 (e).offset = (o); (e).leafkey = (l); } while (0)
 
+extern double gist_seed;
+
 #endif							/* GIST_H */
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index b68c01a5f2..07319a225e 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -95,6 +95,9 @@ typedef struct GISTSTATE
 
 	/* Collations to pass to the support functions */
 	Oid			supportCollation[INDEX_MAX_KEYS];
+
+	/* Random state for gistchoose tie breaker PRNG */
+	unsigned short random_state[3];
 } GISTSTATE;
 
 
-- 
2.24.3 (Apple Git-128)

