aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-11-28 21:32:36 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2021-11-28 21:33:07 -0500
commit3804539e48e794781c6145c7f988f5d507418fa8 (patch)
tree317904b43ca8c1d510b23cb8fdd7b05a75e971bc /src/backend
parentf44ceb46ec2d8da48f6e145bf462d5620c25e079 (diff)
downloadpostgresql-3804539e48e794781c6145c7f988f5d507418fa8.tar.gz
postgresql-3804539e48e794781c6145c7f988f5d507418fa8.zip
Replace random(), pg_erand48(), etc with a better PRNG API and algorithm.
Standardize on xoroshiro128** as our basic PRNG algorithm, eliminating a bunch of platform dependencies as well as fundamentally-obsolete PRNG code. In addition, this API replacement will ease replacing the algorithm again in future, should that become necessary. xoroshiro128** is a few percent slower than the drand48 family, but it can produce full-width 64-bit random values not only 48-bit, and it should be much more trustworthy. It's likely to be noticeably faster than the platform's random(), depending on which platform you are thinking about; and we can have non-global state vectors easily, unlike with random(). It is not cryptographically strong, but neither are the functions it replaces. Fabien Coelho, reviewed by Dean Rasheed, Aleksander Alekseev, and myself Discussion: https://postgr.es/m/alpine.DEB.2.22.394.2105241211230.165418@pseudo
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/gin/ginget.c3
-rw-r--r--src/backend/access/gist/gistutil.c5
-rw-r--r--src/backend/access/nbtree/nbtinsert.c3
-rw-r--r--src/backend/access/spgist/spgdoinsert.c5
-rw-r--r--src/backend/access/transam/xact.c3
-rw-r--r--src/backend/commands/analyze.c7
-rw-r--r--src/backend/executor/nodeSamplescan.c3
-rw-r--r--src/backend/lib/bloomfilter.c3
-rw-r--r--src/backend/optimizer/geqo/geqo_random.c23
-rw-r--r--src/backend/optimizer/geqo/geqo_selection.c14
-rw-r--r--src/backend/postmaster/postmaster.c20
-rw-r--r--src/backend/storage/file/fd.c4
-rw-r--r--src/backend/storage/ipc/dsm.c9
-rw-r--r--src/backend/storage/lmgr/Makefile5
-rw-r--r--src/backend/storage/lmgr/s_lock.c5
-rw-r--r--src/backend/tcop/postgres.c7
-rw-r--r--src/backend/utils/adt/float.c20
-rw-r--r--src/backend/utils/misc/sampling.c52
18 files changed, 110 insertions, 81 deletions
diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index 03191e016ce..e93bf299990 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -16,6 +16,7 @@
#include "access/gin_private.h"
#include "access/relscan.h"
+#include "common/pg_prng.h"
#include "miscadmin.h"
#include "storage/predicate.h"
#include "utils/datum.h"
@@ -787,7 +788,7 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry,
}
}
-#define gin_rand() (((double) random()) / ((double) MAX_RANDOM_VALUE))
+#define gin_rand() pg_prng_double(&pg_global_prng_state)
#define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) )
/*
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 43ba03b6eb9..94dbabc1988 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 "common/pg_prng.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_prng_bool(&pg_global_prng_state) ? 1 : 0;
}
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_prng_bool(&pg_global_prng_state) ? 1 : 0;
}
if (keep_current_best == 1)
break;
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 0fe8c709395..37ee0b4d6ee 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -19,6 +19,7 @@
#include "access/nbtxlog.h"
#include "access/transam.h"
#include "access/xloginsert.h"
+#include "common/pg_prng.h"
#include "lib/qunique.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
@@ -965,7 +966,7 @@ _bt_findinsertloc(Relation rel,
if (P_RIGHTMOST(opaque) ||
_bt_compare(rel, itup_key, page, P_HIKEY) != 0 ||
- random() <= (MAX_RANDOM_VALUE / 100))
+ pg_prng_uint32(&pg_global_prng_state) <= (PG_UINT32_MAX / 100))
break;
_bt_stepright(rel, insertstate, stack);
diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index 70557bcf3d0..e7afb2c242a 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -19,6 +19,7 @@
#include "access/spgist_private.h"
#include "access/spgxlog.h"
#include "access/xloginsert.h"
+#include "common/pg_prng.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "utils/rel.h"
@@ -2210,7 +2211,9 @@ spgdoinsert(Relation index, SpGistState *state,
if (out.resultType == spgAddNode)
elog(ERROR, "cannot add a node to an allTheSame inner tuple");
else if (out.resultType == spgMatchNode)
- out.result.matchNode.nodeN = random() % innerTuple->nNodes;
+ out.result.matchNode.nodeN =
+ pg_prng_uint64_range(&pg_global_prng_state,
+ 0, innerTuple->nNodes - 1);
}
switch (out.resultType)
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 8e35c432f5c..e7b0bc804d8 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -37,6 +37,7 @@
#include "commands/async.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
+#include "common/pg_prng.h"
#include "executor/spi.h"
#include "libpq/be-fsstubs.h"
#include "libpq/pqsignal.h"
@@ -1990,7 +1991,7 @@ StartTransaction(void)
/* Determine if statements are logged in this transaction */
xact_is_sampled = log_xact_sample_rate != 0 &&
(log_xact_sample_rate == 1 ||
- random() <= log_xact_sample_rate * MAX_RANDOM_VALUE);
+ pg_prng_double(&pg_global_prng_state) <= log_xact_sample_rate);
/*
* initialize current transaction state fields
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 4928702aec0..cd77907fc74 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -38,6 +38,7 @@
#include "commands/progress.h"
#include "commands/tablecmds.h"
#include "commands/vacuum.h"
+#include "common/pg_prng.h"
#include "executor/executor.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
@@ -1140,7 +1141,7 @@ acquire_sample_rows(Relation onerel, int elevel,
double liverows = 0; /* # live rows seen */
double deadrows = 0; /* # dead rows seen */
double rowstoskip = -1; /* -1 means not set yet */
- long randseed; /* Seed for block sampler(s) */
+ uint32 randseed; /* Seed for block sampler(s) */
BlockNumber totalblocks;
TransactionId OldestXmin;
BlockSamplerData bs;
@@ -1162,7 +1163,7 @@ acquire_sample_rows(Relation onerel, int elevel,
OldestXmin = GetOldestNonRemovableTransactionId(onerel);
/* Prepare for sampling block numbers */
- randseed = random();
+ randseed = pg_prng_uint32(&pg_global_prng_state);
nblocks = BlockSampler_Init(&bs, totalblocks, targrows, randseed);
#ifdef USE_PREFETCH
@@ -1279,7 +1280,7 @@ acquire_sample_rows(Relation onerel, int elevel,
* Found a suitable tuple, so save it, replacing one old
* tuple at random
*/
- int k = (int) (targrows * sampler_random_fract(rstate.randstate));
+ int k = (int) (targrows * sampler_random_fract(&rstate.randstate));
Assert(k >= 0 && k < targrows);
heap_freetuple(rows[k]);
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 44232d50d0a..33b6fb13778 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -17,6 +17,7 @@
#include "access/relscan.h"
#include "access/tableam.h"
#include "access/tsmapi.h"
+#include "common/pg_prng.h"
#include "executor/executor.h"
#include "executor/nodeSamplescan.h"
#include "miscadmin.h"
@@ -154,7 +155,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
* do this just once, since the seed shouldn't change over rescans.
*/
if (tsc->repeatable == NULL)
- scanstate->seed = random();
+ scanstate->seed = pg_prng_uint32(&pg_global_prng_state);
/*
* Finally, initialize the TABLESAMPLE method handler.
diff --git a/src/backend/lib/bloomfilter.c b/src/backend/lib/bloomfilter.c
index daf2c40ebf5..ac6001b712d 100644
--- a/src/backend/lib/bloomfilter.c
+++ b/src/backend/lib/bloomfilter.c
@@ -81,8 +81,7 @@ static inline uint32 mod_m(uint32 a, uint64 m);
* distinct seed value on every call makes it unlikely that the same false
* positives will reoccur when the same set is fingerprinted a second time.
* Callers that don't care about this pass a constant as their seed, typically
- * 0. Callers can use a pseudo-random seed in the range of 0 - INT_MAX by
- * calling random().
+ * 0. Callers can also use a pseudo-random seed, eg from pg_prng_uint64().
*/
bloom_filter *
bloom_create(int64 total_elems, int bloom_work_mem, uint64 seed)
diff --git a/src/backend/optimizer/geqo/geqo_random.c b/src/backend/optimizer/geqo/geqo_random.c
index f21bc047e68..4d9432c0dfe 100644
--- a/src/backend/optimizer/geqo/geqo_random.c
+++ b/src/backend/optimizer/geqo/geqo_random.c
@@ -21,14 +21,7 @@ geqo_set_seed(PlannerInfo *root, double seed)
{
GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
- /*
- * XXX. This seeding algorithm could certainly be improved - but it is not
- * critical to do so.
- */
- memset(private->random_state, 0, sizeof(private->random_state));
- memcpy(private->random_state,
- &seed,
- Min(sizeof(private->random_state), sizeof(seed)));
+ pg_prng_fseed(&private->random_state, seed);
}
double
@@ -36,5 +29,17 @@ geqo_rand(PlannerInfo *root)
{
GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
- return pg_erand48(private->random_state);
+ return pg_prng_double(&private->random_state);
+}
+
+int
+geqo_randint(PlannerInfo *root, int upper, int lower)
+{
+ GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+
+ /*
+ * In current usage, "lower" is never negative so we can just use
+ * pg_prng_uint64_range directly.
+ */
+ return (int) pg_prng_uint64_range(&private->random_state, lower, upper);
}
diff --git a/src/backend/optimizer/geqo/geqo_selection.c b/src/backend/optimizer/geqo/geqo_selection.c
index 66b6c8ae38e..68a2e4e9f15 100644
--- a/src/backend/optimizer/geqo/geqo_selection.c
+++ b/src/backend/optimizer/geqo/geqo_selection.c
@@ -63,10 +63,6 @@ geqo_selection(PlannerInfo *root, Chromosome *momma, Chromosome *daddy,
/*
* Ensure we have selected different genes, except if pool size is only
* one, when we can't.
- *
- * This code was observed to hang up in an infinite loop when the
- * platform's implementation of erand48() was broken. We now always use
- * our own version.
*/
if (pool->size > 1)
{
@@ -95,11 +91,11 @@ linear_rand(PlannerInfo *root, int pool_size, double bias)
double max = (double) pool_size;
/*
- * If geqo_rand() returns exactly 1.0 then we will get exactly max from
- * this equation, whereas we need 0 <= index < max. Also it seems
- * possible that roundoff error might deliver values slightly outside the
- * range; in particular avoid passing a value slightly less than 0 to
- * sqrt(). If we get a bad value just try again.
+ * geqo_rand() is not supposed to return 1.0, but if it does then we will
+ * get exactly max from this equation, whereas we need 0 <= index < max.
+ * Also it seems possible that roundoff error might deliver values
+ * slightly outside the range; in particular avoid passing a value
+ * slightly less than 0 to sqrt(). If we get a bad value just try again.
*/
do
{
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index db797c040bf..328ecafa8cb 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -98,6 +98,7 @@
#include "catalog/pg_control.h"
#include "common/file_perm.h"
#include "common/ip.h"
+#include "common/pg_prng.h"
#include "common/string.h"
#include "lib/ilist.h"
#include "libpq/auth.h"
@@ -2699,19 +2700,19 @@ ClosePostmasterPorts(bool am_syslogger)
void
InitProcessGlobals(void)
{
- unsigned int rseed;
-
MyProcPid = getpid();
MyStartTimestamp = GetCurrentTimestamp();
MyStartTime = timestamptz_to_time_t(MyStartTimestamp);
/*
- * Set a different seed for random() in every process. We want something
+ * Set a different global seed in every process. We want something
* unpredictable, so if possible, use high-quality random bits for the
* seed. Otherwise, fall back to a seed based on timestamp and PID.
*/
- if (!pg_strong_random(&rseed, sizeof(rseed)))
+ if (unlikely(!pg_prng_strong_seed(&pg_global_prng_state)))
{
+ uint64 rseed;
+
/*
* Since PIDs and timestamps tend to change more frequently in their
* least significant bits, shift the timestamp left to allow a larger
@@ -2722,8 +2723,17 @@ InitProcessGlobals(void)
rseed = ((uint64) MyProcPid) ^
((uint64) MyStartTimestamp << 12) ^
((uint64) MyStartTimestamp >> 20);
+
+ pg_prng_seed(&pg_global_prng_state, rseed);
}
- srandom(rseed);
+
+ /*
+ * Also make sure that we've set a good seed for random(3). Use of that
+ * is deprecated in core Postgres, but extensions might use it.
+ */
+#ifndef WIN32
+ srandom(pg_prng_uint32(&pg_global_prng_state));
+#endif
}
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index cb1a8dd34f2..263057841dd 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -92,6 +92,7 @@
#include "catalog/pg_tablespace.h"
#include "common/file_perm.h"
#include "common/file_utils.h"
+#include "common/pg_prng.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/pg_iovec.h"
@@ -2939,7 +2940,8 @@ SetTempTablespaces(Oid *tableSpaces, int numSpaces)
* available tablespaces.
*/
if (numSpaces > 1)
- nextTempTableSpace = random() % numSpaces;
+ nextTempTableSpace = pg_prng_uint64_range(&pg_global_prng_state,
+ 0, numSpaces - 1);
else
nextTempTableSpace = 0;
}
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index b461a5f7e96..074dff4e6d8 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -33,6 +33,7 @@
#endif
#include <sys/stat.h>
+#include "common/pg_prng.h"
#include "lib/ilist.h"
#include "miscadmin.h"
#include "port/pg_bitutils.h"
@@ -180,7 +181,8 @@ dsm_postmaster_startup(PGShmemHeader *shim)
{
Assert(dsm_control_address == NULL);
Assert(dsm_control_mapped_size == 0);
- dsm_control_handle = random() << 1; /* Even numbers only */
+ /* Use even numbers only */
+ dsm_control_handle = pg_prng_uint32(&pg_global_prng_state) << 1;
if (dsm_control_handle == DSM_HANDLE_INVALID)
continue;
if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize,
@@ -536,7 +538,8 @@ dsm_create(Size size, int flags)
for (;;)
{
Assert(seg->mapped_address == NULL && seg->mapped_size == 0);
- seg->handle = random() << 1; /* Even numbers only */
+ /* Use even numbers only */
+ seg->handle = pg_prng_uint32(&pg_global_prng_state) << 1;
if (seg->handle == DSM_HANDLE_INVALID) /* Reserve sentinel */
continue;
if (dsm_impl_op(DSM_OP_CREATE, seg->handle, size, &seg->impl_private,
@@ -1237,7 +1240,7 @@ make_main_region_dsm_handle(int slot)
*/
handle = 1;
handle |= slot << 1;
- handle |= random() << (pg_leftmost_one_pos32(dsm_control->maxitems) + 1);
+ handle |= pg_prng_uint32(&pg_global_prng_state) << (pg_leftmost_one_pos32(dsm_control->maxitems) + 1);
return handle;
}
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 829b792fcb1..b25b7ee421d 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -30,9 +30,10 @@ ifdef TAS
TASPATH = $(top_builddir)/src/backend/port/tas.o
endif
-s_lock_test: s_lock.c $(top_builddir)/src/port/libpgport.a
+s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/src/port/libpgport.a
$(CC) $(CPPFLAGS) $(CFLAGS) -DS_LOCK_TEST=1 $(srcdir)/s_lock.c \
- $(TASPATH) -L $(top_builddir)/src/port -lpgport -o s_lock_test
+ $(TASPATH) -L $(top_builddir)/src/common -lpgcommon \
+ -L $(top_builddir)/src/port -lpgport -o s_lock_test
# see notes in src/backend/parser/Makefile
lwlocknames.c: lwlocknames.h
diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c
index 91322a40c1c..75c0f4535cd 100644
--- a/src/backend/storage/lmgr/s_lock.c
+++ b/src/backend/storage/lmgr/s_lock.c
@@ -50,6 +50,7 @@
#include <time.h>
#include <unistd.h>
+#include "common/pg_prng.h"
#include "port/atomics.h"
#include "storage/s_lock.h"
@@ -144,7 +145,7 @@ perform_spin_delay(SpinDelayStatus *status)
/* increase delay by a random fraction between 1X and 2X */
status->cur_delay += (int) (status->cur_delay *
- ((double) random() / (double) MAX_RANDOM_VALUE) + 0.5);
+ pg_prng_double(&pg_global_prng_state) + 0.5);
/* wrap back to minimum delay when max is exceeded */
if (status->cur_delay > MAX_DELAY_USEC)
status->cur_delay = MIN_DELAY_USEC;
@@ -303,7 +304,7 @@ volatile struct test_lock_struct test_lock;
int
main()
{
- srandom((unsigned int) time(NULL));
+ pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
test_lock.pad1 = test_lock.pad2 = 0x44;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 0775abe35de..82de01cdc67 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -42,6 +42,7 @@
#include "catalog/pg_type.h"
#include "commands/async.h"
#include "commands/prepare.h"
+#include "common/pg_prng.h"
#include "executor/spi.h"
#include "jit/jit.h"
#include "libpq/libpq.h"
@@ -2355,13 +2356,13 @@ check_log_duration(char *msec_str, bool was_logged)
/*
* Do not log if log_statement_sample_rate = 0. Log a sample if
- * log_statement_sample_rate <= 1 and avoid unnecessary random() call
- * if log_statement_sample_rate = 1.
+ * log_statement_sample_rate <= 1 and avoid unnecessary PRNG call if
+ * log_statement_sample_rate = 1.
*/
if (exceeded_sample_duration)
in_sample = log_statement_sample_rate != 0 &&
(log_statement_sample_rate == 1 ||
- random() <= log_statement_sample_rate * MAX_RANDOM_VALUE);
+ pg_prng_double(&pg_global_prng_state) <= log_statement_sample_rate);
if (exceeded_duration || in_sample || log_duration || xact_is_sampled)
{
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 098bbb372bf..455e5d8cbea 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -21,6 +21,7 @@
#include "catalog/pg_type.h"
#include "common/int.h"
+#include "common/pg_prng.h"
#include "common/shortest_dec.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
@@ -65,7 +66,7 @@ float8 degree_c_one = 1.0;
/* State for drandom() and setseed() */
static bool drandom_seed_set = false;
-static unsigned short drandom_seed[3] = {0, 0, 0};
+static pg_prng_state drandom_seed;
/* Local function prototypes */
static double sind_q1(double x);
@@ -2762,22 +2763,20 @@ drandom(PG_FUNCTION_ARGS)
* Should that fail for some reason, we fall back on a lower-quality
* seed based on current time and PID.
*/
- if (!pg_strong_random(drandom_seed, sizeof(drandom_seed)))
+ if (unlikely(!pg_prng_strong_seed(&drandom_seed)))
{
TimestampTz now = GetCurrentTimestamp();
uint64 iseed;
/* Mix the PID with the most predictable bits of the timestamp */
iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
- drandom_seed[0] = (unsigned short) iseed;
- drandom_seed[1] = (unsigned short) (iseed >> 16);
- drandom_seed[2] = (unsigned short) (iseed >> 32);
+ pg_prng_seed(&drandom_seed, iseed);
}
drandom_seed_set = true;
}
- /* pg_erand48 produces desired result range [0.0 - 1.0) */
- result = pg_erand48(drandom_seed);
+ /* pg_prng_double produces desired result range [0.0 - 1.0) */
+ result = pg_prng_double(&drandom_seed);
PG_RETURN_FLOAT8(result);
}
@@ -2790,7 +2789,6 @@ Datum
setseed(PG_FUNCTION_ARGS)
{
float8 seed = PG_GETARG_FLOAT8(0);
- uint64 iseed;
if (seed < -1 || seed > 1 || isnan(seed))
ereport(ERROR,
@@ -2798,11 +2796,7 @@ setseed(PG_FUNCTION_ARGS)
errmsg("setseed parameter %g is out of allowed range [-1,1]",
seed)));
- /* Use sign bit + 47 fractional bits to fill drandom_seed[] */
- iseed = (int64) (seed * (float8) UINT64CONST(0x7FFFFFFFFFFF));
- drandom_seed[0] = (unsigned short) iseed;
- drandom_seed[1] = (unsigned short) (iseed >> 16);
- drandom_seed[2] = (unsigned short) (iseed >> 32);
+ pg_prng_fseed(&drandom_seed, seed);
drandom_seed_set = true;
PG_RETURN_VOID();
diff --git a/src/backend/utils/misc/sampling.c b/src/backend/utils/misc/sampling.c
index 0c327e823f7..d1a2416e8b7 100644
--- a/src/backend/utils/misc/sampling.c
+++ b/src/backend/utils/misc/sampling.c
@@ -37,7 +37,7 @@
*/
BlockNumber
BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, int samplesize,
- long randseed)
+ uint32 randseed)
{
bs->N = nblocks; /* measured table size */
@@ -49,7 +49,7 @@ BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, int samplesize,
bs->t = 0; /* blocks scanned so far */
bs->m = 0; /* blocks selected so far */
- sampler_random_init_state(randseed, bs->randstate);
+ sampler_random_init_state(randseed, &bs->randstate);
return Min(bs->n, bs->N);
}
@@ -98,7 +98,7 @@ BlockSampler_Next(BlockSampler bs)
* less than k, which means that we cannot fail to select enough blocks.
*----------
*/
- V = sampler_random_fract(bs->randstate);
+ V = sampler_random_fract(&bs->randstate);
p = 1.0 - (double) k / (double) K;
while (V < p)
{
@@ -136,10 +136,11 @@ reservoir_init_selection_state(ReservoirState rs, int n)
* Reservoir sampling is not used anywhere where it would need to return
* repeatable results so we can initialize it randomly.
*/
- sampler_random_init_state(random(), rs->randstate);
+ sampler_random_init_state(pg_prng_uint32(&pg_global_prng_state),
+ &rs->randstate);
/* Initial value of W (for use when Algorithm Z is first applied) */
- rs->W = exp(-log(sampler_random_fract(rs->randstate)) / n);
+ rs->W = exp(-log(sampler_random_fract(&rs->randstate)) / n);
}
double
@@ -154,7 +155,7 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
double V,
quot;
- V = sampler_random_fract(rs->randstate); /* Generate V */
+ V = sampler_random_fract(&rs->randstate); /* Generate V */
S = 0;
t += 1;
/* Note: "num" in Vitter's code is always equal to t - n */
@@ -186,7 +187,7 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
tmp;
/* Generate U and X */
- U = sampler_random_fract(rs->randstate);
+ U = sampler_random_fract(&rs->randstate);
X = t * (W - 1.0);
S = floor(X); /* S is tentatively set to floor(X) */
/* Test if U <= h(S)/cg(X) in the manner of (6.3) */
@@ -215,7 +216,7 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
y *= numer / denom;
denom -= 1;
}
- W = exp(-log(sampler_random_fract(rs->randstate)) / n); /* Generate W in advance */
+ W = exp(-log(sampler_random_fract(&rs->randstate)) / n); /* Generate W in advance */
if (exp(log(y) / n) <= (t + X) / t)
break;
}
@@ -230,24 +231,22 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
*----------
*/
void
-sampler_random_init_state(long seed, SamplerRandomState randstate)
+sampler_random_init_state(uint32 seed, pg_prng_state *randstate)
{
- randstate[0] = 0x330e; /* same as pg_erand48, but could be anything */
- randstate[1] = (unsigned short) seed;
- randstate[2] = (unsigned short) (seed >> 16);
+ pg_prng_seed(randstate, (uint64) seed);
}
/* Select a random value R uniformly distributed in (0 - 1) */
double
-sampler_random_fract(SamplerRandomState randstate)
+sampler_random_fract(pg_prng_state *randstate)
{
double res;
- /* pg_erand48 returns a value in [0.0 - 1.0), so we must reject 0 */
+ /* pg_prng_double returns a value in [0.0 - 1.0), so we must reject 0.0 */
do
{
- res = pg_erand48(randstate);
- } while (res == 0.0);
+ res = pg_prng_double(randstate);
+ } while (unlikely(res == 0.0));
return res;
}
@@ -261,27 +260,36 @@ sampler_random_fract(SamplerRandomState randstate)
* except that a common random state is used across all callers.
*/
static ReservoirStateData oldrs;
+static bool oldrs_initialized = false;
double
anl_random_fract(void)
{
/* initialize if first time through */
- if (oldrs.randstate[0] == 0)
- sampler_random_init_state(random(), oldrs.randstate);
+ if (unlikely(!oldrs_initialized))
+ {
+ sampler_random_init_state(pg_prng_uint32(&pg_global_prng_state),
+ &oldrs.randstate);
+ oldrs_initialized = true;
+ }
/* and compute a random fraction */
- return sampler_random_fract(oldrs.randstate);
+ return sampler_random_fract(&oldrs.randstate);
}
double
anl_init_selection_state(int n)
{
/* initialize if first time through */
- if (oldrs.randstate[0] == 0)
- sampler_random_init_state(random(), oldrs.randstate);
+ if (unlikely(!oldrs_initialized))
+ {
+ sampler_random_init_state(pg_prng_uint32(&pg_global_prng_state),
+ &oldrs.randstate);
+ oldrs_initialized = true;
+ }
/* Initial value of W (for use when Algorithm Z is first applied) */
- return exp(-log(sampler_random_fract(oldrs.randstate)) / n);
+ return exp(-log(sampler_random_fract(&oldrs.randstate)) / n);
}
double