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
This commit is contained in:
parent
f44ceb46ec
commit
3804539e48
26
configure
vendored
26
configure
vendored
@ -16463,32 +16463,6 @@ esac
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ac_fn_c_check_func "$LINENO" "random" "ac_cv_func_random"
|
|
||||||
if test "x$ac_cv_func_random" = xyes; then :
|
|
||||||
$as_echo "#define HAVE_RANDOM 1" >>confdefs.h
|
|
||||||
|
|
||||||
else
|
|
||||||
case " $LIBOBJS " in
|
|
||||||
*" random.$ac_objext "* ) ;;
|
|
||||||
*) LIBOBJS="$LIBOBJS random.$ac_objext"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
ac_fn_c_check_func "$LINENO" "srandom" "ac_cv_func_srandom"
|
|
||||||
if test "x$ac_cv_func_srandom" = xyes; then :
|
|
||||||
$as_echo "#define HAVE_SRANDOM 1" >>confdefs.h
|
|
||||||
|
|
||||||
else
|
|
||||||
case " $LIBOBJS " in
|
|
||||||
*" srandom.$ac_objext "* ) ;;
|
|
||||||
*) LIBOBJS="$LIBOBJS srandom.$ac_objext"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat"
|
ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat"
|
||||||
if test "x$ac_cv_func_strlcat" = xyes; then :
|
if test "x$ac_cv_func_strlcat" = xyes; then :
|
||||||
$as_echo "#define HAVE_STRLCAT 1" >>confdefs.h
|
$as_echo "#define HAVE_STRLCAT 1" >>confdefs.h
|
||||||
|
@ -1858,8 +1858,6 @@ AC_REPLACE_FUNCS(m4_normalize([
|
|||||||
mkdtemp
|
mkdtemp
|
||||||
pread
|
pread
|
||||||
pwrite
|
pwrite
|
||||||
random
|
|
||||||
srandom
|
|
||||||
strlcat
|
strlcat
|
||||||
strlcpy
|
strlcpy
|
||||||
strnlen
|
strnlen
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "lib/bloomfilter.h"
|
#include "lib/bloomfilter.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
@ -466,8 +467,8 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
|
|||||||
total_pages = RelationGetNumberOfBlocks(rel);
|
total_pages = RelationGetNumberOfBlocks(rel);
|
||||||
total_elems = Max(total_pages * (MaxTIDsPerBTreePage / 3),
|
total_elems = Max(total_pages * (MaxTIDsPerBTreePage / 3),
|
||||||
(int64) state->rel->rd_rel->reltuples);
|
(int64) state->rel->rd_rel->reltuples);
|
||||||
/* Random seed relies on backend srandom() call to avoid repetition */
|
/* Generate a random seed to avoid repetition */
|
||||||
seed = random();
|
seed = pg_prng_uint64(&pg_global_prng_state);
|
||||||
/* Create Bloom filter to fingerprint index */
|
/* Create Bloom filter to fingerprint index */
|
||||||
state->filter = bloom_create(total_elems, maintenance_work_mem, seed);
|
state->filter = bloom_create(total_elems, maintenance_work_mem, seed);
|
||||||
state->heaptuplespresent = 0;
|
state->heaptuplespresent = 0;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "access/parallel.h"
|
#include "access/parallel.h"
|
||||||
#include "commands/explain.h"
|
#include "commands/explain.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "executor/instrument.h"
|
#include "executor/instrument.h"
|
||||||
#include "jit/jit.h"
|
#include "jit/jit.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
@ -275,8 +276,7 @@ explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
|
|||||||
if (nesting_level == 0)
|
if (nesting_level == 0)
|
||||||
{
|
{
|
||||||
if (auto_explain_log_min_duration >= 0 && !IsParallelWorker())
|
if (auto_explain_log_min_duration >= 0 && !IsParallelWorker())
|
||||||
current_query_sampled = (random() < auto_explain_sample_rate *
|
current_query_sampled = (pg_prng_double(&pg_global_prng_state) < auto_explain_sample_rate);
|
||||||
((double) MAX_RANDOM_VALUE + 1));
|
|
||||||
else
|
else
|
||||||
current_query_sampled = false;
|
current_query_sampled = false;
|
||||||
}
|
}
|
||||||
|
@ -1188,7 +1188,7 @@ file_acquire_sample_rows(Relation onerel, int elevel,
|
|||||||
* Found a suitable tuple, so save it, replacing one old tuple
|
* Found a suitable tuple, so save it, replacing one old tuple
|
||||||
* at random
|
* 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);
|
Assert(k >= 0 && k < targrows);
|
||||||
heap_freetuple(rows[k]);
|
heap_freetuple(rows[k]);
|
||||||
|
@ -5158,7 +5158,7 @@ analyze_row_processor(PGresult *res, int row, PgFdwAnalyzeState *astate)
|
|||||||
if (astate->rowstoskip <= 0)
|
if (astate->rowstoskip <= 0)
|
||||||
{
|
{
|
||||||
/* Choose a random reservoir element to replace. */
|
/* Choose a random reservoir element to replace. */
|
||||||
pos = (int) (targrows * sampler_random_fract(astate->rstate.randstate));
|
pos = (int) (targrows * sampler_random_fract(&astate->rstate.randstate));
|
||||||
Assert(pos >= 0 && pos < targrows);
|
Assert(pos >= 0 && pos < targrows);
|
||||||
heap_freetuple(astate->rows[pos]);
|
heap_freetuple(astate->rows[pos]);
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
@ -290,8 +291,8 @@ get_normal_pair(float8 *x1, float8 *x2)
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
u1 = (float8) random() / (float8) MAX_RANDOM_VALUE;
|
u1 = pg_prng_double(&pg_global_prng_state);
|
||||||
u2 = (float8) random() / (float8) MAX_RANDOM_VALUE;
|
u2 = pg_prng_double(&pg_global_prng_state);
|
||||||
|
|
||||||
v1 = (2.0 * u1) - 1.0;
|
v1 = (2.0 * u1) - 1.0;
|
||||||
v2 = (2.0 * u2) - 1.0;
|
v2 = (2.0 * u2) - 1.0;
|
||||||
|
@ -69,7 +69,7 @@ static BlockNumber system_rows_nextsampleblock(SampleScanState *node, BlockNumbe
|
|||||||
static OffsetNumber system_rows_nextsampletuple(SampleScanState *node,
|
static OffsetNumber system_rows_nextsampletuple(SampleScanState *node,
|
||||||
BlockNumber blockno,
|
BlockNumber blockno,
|
||||||
OffsetNumber maxoffset);
|
OffsetNumber maxoffset);
|
||||||
static uint32 random_relative_prime(uint32 n, SamplerRandomState randstate);
|
static uint32 random_relative_prime(uint32 n, pg_prng_state *randstate);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -213,25 +213,25 @@ system_rows_nextsampleblock(SampleScanState *node, BlockNumber nblocks)
|
|||||||
if (sampler->step == 0)
|
if (sampler->step == 0)
|
||||||
{
|
{
|
||||||
/* Initialize now that we have scan descriptor */
|
/* Initialize now that we have scan descriptor */
|
||||||
SamplerRandomState randstate;
|
pg_prng_state randstate;
|
||||||
|
|
||||||
/* If relation is empty, there's nothing to scan */
|
/* If relation is empty, there's nothing to scan */
|
||||||
if (nblocks == 0)
|
if (nblocks == 0)
|
||||||
return InvalidBlockNumber;
|
return InvalidBlockNumber;
|
||||||
|
|
||||||
/* We only need an RNG during this setup step */
|
/* We only need an RNG during this setup step */
|
||||||
sampler_random_init_state(sampler->seed, randstate);
|
sampler_random_init_state(sampler->seed, &randstate);
|
||||||
|
|
||||||
/* Compute nblocks/firstblock/step only once per query */
|
/* Compute nblocks/firstblock/step only once per query */
|
||||||
sampler->nblocks = nblocks;
|
sampler->nblocks = nblocks;
|
||||||
|
|
||||||
/* Choose random starting block within the relation */
|
/* Choose random starting block within the relation */
|
||||||
/* (Actually this is the predecessor of the first block visited) */
|
/* (Actually this is the predecessor of the first block visited) */
|
||||||
sampler->firstblock = sampler_random_fract(randstate) *
|
sampler->firstblock = sampler_random_fract(&randstate) *
|
||||||
sampler->nblocks;
|
sampler->nblocks;
|
||||||
|
|
||||||
/* Find relative prime as step size for linear probing */
|
/* Find relative prime as step size for linear probing */
|
||||||
sampler->step = random_relative_prime(sampler->nblocks, randstate);
|
sampler->step = random_relative_prime(sampler->nblocks, &randstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reinitialize lb */
|
/* Reinitialize lb */
|
||||||
@ -317,7 +317,7 @@ gcd(uint32 a, uint32 b)
|
|||||||
* (else return 1).
|
* (else return 1).
|
||||||
*/
|
*/
|
||||||
static uint32
|
static uint32
|
||||||
random_relative_prime(uint32 n, SamplerRandomState randstate)
|
random_relative_prime(uint32 n, pg_prng_state *randstate)
|
||||||
{
|
{
|
||||||
uint32 r;
|
uint32 r;
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ static BlockNumber system_time_nextsampleblock(SampleScanState *node, BlockNumbe
|
|||||||
static OffsetNumber system_time_nextsampletuple(SampleScanState *node,
|
static OffsetNumber system_time_nextsampletuple(SampleScanState *node,
|
||||||
BlockNumber blockno,
|
BlockNumber blockno,
|
||||||
OffsetNumber maxoffset);
|
OffsetNumber maxoffset);
|
||||||
static uint32 random_relative_prime(uint32 n, SamplerRandomState randstate);
|
static uint32 random_relative_prime(uint32 n, pg_prng_state *randstate);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -224,25 +224,25 @@ system_time_nextsampleblock(SampleScanState *node, BlockNumber nblocks)
|
|||||||
if (sampler->step == 0)
|
if (sampler->step == 0)
|
||||||
{
|
{
|
||||||
/* Initialize now that we have scan descriptor */
|
/* Initialize now that we have scan descriptor */
|
||||||
SamplerRandomState randstate;
|
pg_prng_state randstate;
|
||||||
|
|
||||||
/* If relation is empty, there's nothing to scan */
|
/* If relation is empty, there's nothing to scan */
|
||||||
if (nblocks == 0)
|
if (nblocks == 0)
|
||||||
return InvalidBlockNumber;
|
return InvalidBlockNumber;
|
||||||
|
|
||||||
/* We only need an RNG during this setup step */
|
/* We only need an RNG during this setup step */
|
||||||
sampler_random_init_state(sampler->seed, randstate);
|
sampler_random_init_state(sampler->seed, &randstate);
|
||||||
|
|
||||||
/* Compute nblocks/firstblock/step only once per query */
|
/* Compute nblocks/firstblock/step only once per query */
|
||||||
sampler->nblocks = nblocks;
|
sampler->nblocks = nblocks;
|
||||||
|
|
||||||
/* Choose random starting block within the relation */
|
/* Choose random starting block within the relation */
|
||||||
/* (Actually this is the predecessor of the first block visited) */
|
/* (Actually this is the predecessor of the first block visited) */
|
||||||
sampler->firstblock = sampler_random_fract(randstate) *
|
sampler->firstblock = sampler_random_fract(&randstate) *
|
||||||
sampler->nblocks;
|
sampler->nblocks;
|
||||||
|
|
||||||
/* Find relative prime as step size for linear probing */
|
/* Find relative prime as step size for linear probing */
|
||||||
sampler->step = random_relative_prime(sampler->nblocks, randstate);
|
sampler->step = random_relative_prime(sampler->nblocks, &randstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reinitialize lb and start_time */
|
/* Reinitialize lb and start_time */
|
||||||
@ -330,7 +330,7 @@ gcd(uint32 a, uint32 b)
|
|||||||
* (else return 1).
|
* (else return 1).
|
||||||
*/
|
*/
|
||||||
static uint32
|
static uint32
|
||||||
random_relative_prime(uint32 n, SamplerRandomState randstate)
|
random_relative_prime(uint32 n, pg_prng_state *randstate)
|
||||||
{
|
{
|
||||||
uint32 r;
|
uint32 r;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "access/gin_private.h"
|
#include "access/gin_private.h"
|
||||||
#include "access/relscan.h"
|
#include "access/relscan.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/predicate.h"
|
#include "storage/predicate.h"
|
||||||
#include "utils/datum.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)) )
|
#define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) )
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/reloptions.h"
|
#include "access/reloptions.h"
|
||||||
#include "catalog/pg_opclass.h"
|
#include "catalog/pg_opclass.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "storage/indexfsm.h"
|
#include "storage/indexfsm.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "utils/float.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)
|
if (keep_current_best == -1)
|
||||||
{
|
{
|
||||||
/* we didn't make the random choice yet for this old best */
|
/* 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)
|
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)
|
if (keep_current_best == -1)
|
||||||
{
|
{
|
||||||
/* we didn't make the random choice yet for this old best */
|
/* 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)
|
if (keep_current_best == 1)
|
||||||
break;
|
break;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "access/nbtxlog.h"
|
#include "access/nbtxlog.h"
|
||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
#include "access/xloginsert.h"
|
#include "access/xloginsert.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "lib/qunique.h"
|
#include "lib/qunique.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
@ -965,7 +966,7 @@ _bt_findinsertloc(Relation rel,
|
|||||||
|
|
||||||
if (P_RIGHTMOST(opaque) ||
|
if (P_RIGHTMOST(opaque) ||
|
||||||
_bt_compare(rel, itup_key, page, P_HIKEY) != 0 ||
|
_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;
|
break;
|
||||||
|
|
||||||
_bt_stepright(rel, insertstate, stack);
|
_bt_stepright(rel, insertstate, stack);
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "access/spgist_private.h"
|
#include "access/spgist_private.h"
|
||||||
#include "access/spgxlog.h"
|
#include "access/spgxlog.h"
|
||||||
#include "access/xloginsert.h"
|
#include "access/xloginsert.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
@ -2210,7 +2211,9 @@ spgdoinsert(Relation index, SpGistState *state,
|
|||||||
if (out.resultType == spgAddNode)
|
if (out.resultType == spgAddNode)
|
||||||
elog(ERROR, "cannot add a node to an allTheSame inner tuple");
|
elog(ERROR, "cannot add a node to an allTheSame inner tuple");
|
||||||
else if (out.resultType == spgMatchNode)
|
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)
|
switch (out.resultType)
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "commands/async.h"
|
#include "commands/async.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "libpq/be-fsstubs.h"
|
#include "libpq/be-fsstubs.h"
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
@ -1990,7 +1991,7 @@ StartTransaction(void)
|
|||||||
/* Determine if statements are logged in this transaction */
|
/* Determine if statements are logged in this transaction */
|
||||||
xact_is_sampled = log_xact_sample_rate != 0 &&
|
xact_is_sampled = log_xact_sample_rate != 0 &&
|
||||||
(log_xact_sample_rate == 1 ||
|
(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
|
* initialize current transaction state fields
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "commands/progress.h"
|
#include "commands/progress.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
#include "commands/vacuum.h"
|
#include "commands/vacuum.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "foreign/fdwapi.h"
|
#include "foreign/fdwapi.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
@ -1140,7 +1141,7 @@ acquire_sample_rows(Relation onerel, int elevel,
|
|||||||
double liverows = 0; /* # live rows seen */
|
double liverows = 0; /* # live rows seen */
|
||||||
double deadrows = 0; /* # dead rows seen */
|
double deadrows = 0; /* # dead rows seen */
|
||||||
double rowstoskip = -1; /* -1 means not set yet */
|
double rowstoskip = -1; /* -1 means not set yet */
|
||||||
long randseed; /* Seed for block sampler(s) */
|
uint32 randseed; /* Seed for block sampler(s) */
|
||||||
BlockNumber totalblocks;
|
BlockNumber totalblocks;
|
||||||
TransactionId OldestXmin;
|
TransactionId OldestXmin;
|
||||||
BlockSamplerData bs;
|
BlockSamplerData bs;
|
||||||
@ -1162,7 +1163,7 @@ acquire_sample_rows(Relation onerel, int elevel,
|
|||||||
OldestXmin = GetOldestNonRemovableTransactionId(onerel);
|
OldestXmin = GetOldestNonRemovableTransactionId(onerel);
|
||||||
|
|
||||||
/* Prepare for sampling block numbers */
|
/* Prepare for sampling block numbers */
|
||||||
randseed = random();
|
randseed = pg_prng_uint32(&pg_global_prng_state);
|
||||||
nblocks = BlockSampler_Init(&bs, totalblocks, targrows, randseed);
|
nblocks = BlockSampler_Init(&bs, totalblocks, targrows, randseed);
|
||||||
|
|
||||||
#ifdef USE_PREFETCH
|
#ifdef USE_PREFETCH
|
||||||
@ -1279,7 +1280,7 @@ acquire_sample_rows(Relation onerel, int elevel,
|
|||||||
* Found a suitable tuple, so save it, replacing one old
|
* Found a suitable tuple, so save it, replacing one old
|
||||||
* tuple at random
|
* 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);
|
Assert(k >= 0 && k < targrows);
|
||||||
heap_freetuple(rows[k]);
|
heap_freetuple(rows[k]);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "access/relscan.h"
|
#include "access/relscan.h"
|
||||||
#include "access/tableam.h"
|
#include "access/tableam.h"
|
||||||
#include "access/tsmapi.h"
|
#include "access/tsmapi.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "executor/nodeSamplescan.h"
|
#include "executor/nodeSamplescan.h"
|
||||||
#include "miscadmin.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.
|
* do this just once, since the seed shouldn't change over rescans.
|
||||||
*/
|
*/
|
||||||
if (tsc->repeatable == NULL)
|
if (tsc->repeatable == NULL)
|
||||||
scanstate->seed = random();
|
scanstate->seed = pg_prng_uint32(&pg_global_prng_state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally, initialize the TABLESAMPLE method handler.
|
* Finally, initialize the TABLESAMPLE method handler.
|
||||||
|
@ -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
|
* 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.
|
* 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
|
* 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
|
* 0. Callers can also use a pseudo-random seed, eg from pg_prng_uint64().
|
||||||
* calling random().
|
|
||||||
*/
|
*/
|
||||||
bloom_filter *
|
bloom_filter *
|
||||||
bloom_create(int64 total_elems, int bloom_work_mem, uint64 seed)
|
bloom_create(int64 total_elems, int bloom_work_mem, uint64 seed)
|
||||||
|
@ -21,14 +21,7 @@ geqo_set_seed(PlannerInfo *root, double seed)
|
|||||||
{
|
{
|
||||||
GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
|
GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
|
||||||
|
|
||||||
/*
|
pg_prng_fseed(&private->random_state, seed);
|
||||||
* 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)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
@ -36,5 +29,17 @@ geqo_rand(PlannerInfo *root)
|
|||||||
{
|
{
|
||||||
GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -63,10 +63,6 @@ geqo_selection(PlannerInfo *root, Chromosome *momma, Chromosome *daddy,
|
|||||||
/*
|
/*
|
||||||
* Ensure we have selected different genes, except if pool size is only
|
* Ensure we have selected different genes, except if pool size is only
|
||||||
* one, when we can't.
|
* 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)
|
if (pool->size > 1)
|
||||||
{
|
{
|
||||||
@ -95,11 +91,11 @@ linear_rand(PlannerInfo *root, int pool_size, double bias)
|
|||||||
double max = (double) pool_size;
|
double max = (double) pool_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If geqo_rand() returns exactly 1.0 then we will get exactly max from
|
* geqo_rand() is not supposed to return 1.0, but if it does then we will
|
||||||
* this equation, whereas we need 0 <= index < max. Also it seems
|
* get exactly max from this equation, whereas we need 0 <= index < max.
|
||||||
* possible that roundoff error might deliver values slightly outside the
|
* Also it seems possible that roundoff error might deliver values
|
||||||
* range; in particular avoid passing a value slightly less than 0 to
|
* slightly outside the range; in particular avoid passing a value
|
||||||
* sqrt(). If we get a bad value just try again.
|
* slightly less than 0 to sqrt(). If we get a bad value just try again.
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -98,6 +98,7 @@
|
|||||||
#include "catalog/pg_control.h"
|
#include "catalog/pg_control.h"
|
||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/ip.h"
|
#include "common/ip.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
#include "lib/ilist.h"
|
#include "lib/ilist.h"
|
||||||
#include "libpq/auth.h"
|
#include "libpq/auth.h"
|
||||||
@ -2699,19 +2700,19 @@ ClosePostmasterPorts(bool am_syslogger)
|
|||||||
void
|
void
|
||||||
InitProcessGlobals(void)
|
InitProcessGlobals(void)
|
||||||
{
|
{
|
||||||
unsigned int rseed;
|
|
||||||
|
|
||||||
MyProcPid = getpid();
|
MyProcPid = getpid();
|
||||||
MyStartTimestamp = GetCurrentTimestamp();
|
MyStartTimestamp = GetCurrentTimestamp();
|
||||||
MyStartTime = timestamptz_to_time_t(MyStartTimestamp);
|
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
|
* unpredictable, so if possible, use high-quality random bits for the
|
||||||
* seed. Otherwise, fall back to a seed based on timestamp and PID.
|
* 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
|
* Since PIDs and timestamps tend to change more frequently in their
|
||||||
* least significant bits, shift the timestamp left to allow a larger
|
* least significant bits, shift the timestamp left to allow a larger
|
||||||
@ -2722,8 +2723,17 @@ InitProcessGlobals(void)
|
|||||||
rseed = ((uint64) MyProcPid) ^
|
rseed = ((uint64) MyProcPid) ^
|
||||||
((uint64) MyStartTimestamp << 12) ^
|
((uint64) MyStartTimestamp << 12) ^
|
||||||
((uint64) MyStartTimestamp >> 20);
|
((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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@
|
|||||||
#include "catalog/pg_tablespace.h"
|
#include "catalog/pg_tablespace.h"
|
||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/file_utils.h"
|
#include "common/file_utils.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
#include "port/pg_iovec.h"
|
#include "port/pg_iovec.h"
|
||||||
@ -2939,7 +2940,8 @@ SetTempTablespaces(Oid *tableSpaces, int numSpaces)
|
|||||||
* available tablespaces.
|
* available tablespaces.
|
||||||
*/
|
*/
|
||||||
if (numSpaces > 1)
|
if (numSpaces > 1)
|
||||||
nextTempTableSpace = random() % numSpaces;
|
nextTempTableSpace = pg_prng_uint64_range(&pg_global_prng_state,
|
||||||
|
0, numSpaces - 1);
|
||||||
else
|
else
|
||||||
nextTempTableSpace = 0;
|
nextTempTableSpace = 0;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "lib/ilist.h"
|
#include "lib/ilist.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "port/pg_bitutils.h"
|
#include "port/pg_bitutils.h"
|
||||||
@ -180,7 +181,8 @@ dsm_postmaster_startup(PGShmemHeader *shim)
|
|||||||
{
|
{
|
||||||
Assert(dsm_control_address == NULL);
|
Assert(dsm_control_address == NULL);
|
||||||
Assert(dsm_control_mapped_size == 0);
|
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)
|
if (dsm_control_handle == DSM_HANDLE_INVALID)
|
||||||
continue;
|
continue;
|
||||||
if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize,
|
if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize,
|
||||||
@ -536,7 +538,8 @@ dsm_create(Size size, int flags)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Assert(seg->mapped_address == NULL && seg->mapped_size == 0);
|
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 */
|
if (seg->handle == DSM_HANDLE_INVALID) /* Reserve sentinel */
|
||||||
continue;
|
continue;
|
||||||
if (dsm_impl_op(DSM_OP_CREATE, seg->handle, size, &seg->impl_private,
|
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 = 1;
|
||||||
handle |= slot << 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;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,9 +30,10 @@ ifdef TAS
|
|||||||
TASPATH = $(top_builddir)/src/backend/port/tas.o
|
TASPATH = $(top_builddir)/src/backend/port/tas.o
|
||||||
endif
|
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 \
|
$(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
|
# see notes in src/backend/parser/Makefile
|
||||||
lwlocknames.c: lwlocknames.h
|
lwlocknames.c: lwlocknames.h
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "port/atomics.h"
|
#include "port/atomics.h"
|
||||||
#include "storage/s_lock.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 */
|
/* increase delay by a random fraction between 1X and 2X */
|
||||||
status->cur_delay += (int) (status->cur_delay *
|
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 */
|
/* wrap back to minimum delay when max is exceeded */
|
||||||
if (status->cur_delay > MAX_DELAY_USEC)
|
if (status->cur_delay > MAX_DELAY_USEC)
|
||||||
status->cur_delay = MIN_DELAY_USEC;
|
status->cur_delay = MIN_DELAY_USEC;
|
||||||
@ -303,7 +304,7 @@ volatile struct test_lock_struct test_lock;
|
|||||||
int
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
srandom((unsigned int) time(NULL));
|
pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
|
||||||
|
|
||||||
test_lock.pad1 = test_lock.pad2 = 0x44;
|
test_lock.pad1 = test_lock.pad2 = 0x44;
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/async.h"
|
#include "commands/async.h"
|
||||||
#include "commands/prepare.h"
|
#include "commands/prepare.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "jit/jit.h"
|
#include "jit/jit.h"
|
||||||
#include "libpq/libpq.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
|
* Do not log if log_statement_sample_rate = 0. Log a sample if
|
||||||
* log_statement_sample_rate <= 1 and avoid unnecessary random() call
|
* log_statement_sample_rate <= 1 and avoid unnecessary PRNG call if
|
||||||
* if log_statement_sample_rate = 1.
|
* log_statement_sample_rate = 1.
|
||||||
*/
|
*/
|
||||||
if (exceeded_sample_duration)
|
if (exceeded_sample_duration)
|
||||||
in_sample = log_statement_sample_rate != 0 &&
|
in_sample = log_statement_sample_rate != 0 &&
|
||||||
(log_statement_sample_rate == 1 ||
|
(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)
|
if (exceeded_duration || in_sample || log_duration || xact_is_sampled)
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "common/int.h"
|
#include "common/int.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "common/shortest_dec.h"
|
#include "common/shortest_dec.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
@ -65,7 +66,7 @@ float8 degree_c_one = 1.0;
|
|||||||
|
|
||||||
/* State for drandom() and setseed() */
|
/* State for drandom() and setseed() */
|
||||||
static bool drandom_seed_set = false;
|
static bool drandom_seed_set = false;
|
||||||
static unsigned short drandom_seed[3] = {0, 0, 0};
|
static pg_prng_state drandom_seed;
|
||||||
|
|
||||||
/* Local function prototypes */
|
/* Local function prototypes */
|
||||||
static double sind_q1(double x);
|
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
|
* Should that fail for some reason, we fall back on a lower-quality
|
||||||
* seed based on current time and PID.
|
* 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();
|
TimestampTz now = GetCurrentTimestamp();
|
||||||
uint64 iseed;
|
uint64 iseed;
|
||||||
|
|
||||||
/* Mix the PID with the most predictable bits of the timestamp */
|
/* Mix the PID with the most predictable bits of the timestamp */
|
||||||
iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
|
iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
|
||||||
drandom_seed[0] = (unsigned short) iseed;
|
pg_prng_seed(&drandom_seed, iseed);
|
||||||
drandom_seed[1] = (unsigned short) (iseed >> 16);
|
|
||||||
drandom_seed[2] = (unsigned short) (iseed >> 32);
|
|
||||||
}
|
}
|
||||||
drandom_seed_set = true;
|
drandom_seed_set = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pg_erand48 produces desired result range [0.0 - 1.0) */
|
/* pg_prng_double produces desired result range [0.0 - 1.0) */
|
||||||
result = pg_erand48(drandom_seed);
|
result = pg_prng_double(&drandom_seed);
|
||||||
|
|
||||||
PG_RETURN_FLOAT8(result);
|
PG_RETURN_FLOAT8(result);
|
||||||
}
|
}
|
||||||
@ -2790,7 +2789,6 @@ Datum
|
|||||||
setseed(PG_FUNCTION_ARGS)
|
setseed(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
float8 seed = PG_GETARG_FLOAT8(0);
|
float8 seed = PG_GETARG_FLOAT8(0);
|
||||||
uint64 iseed;
|
|
||||||
|
|
||||||
if (seed < -1 || seed > 1 || isnan(seed))
|
if (seed < -1 || seed > 1 || isnan(seed))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -2798,11 +2796,7 @@ setseed(PG_FUNCTION_ARGS)
|
|||||||
errmsg("setseed parameter %g is out of allowed range [-1,1]",
|
errmsg("setseed parameter %g is out of allowed range [-1,1]",
|
||||||
seed)));
|
seed)));
|
||||||
|
|
||||||
/* Use sign bit + 47 fractional bits to fill drandom_seed[] */
|
pg_prng_fseed(&drandom_seed, 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);
|
|
||||||
drandom_seed_set = true;
|
drandom_seed_set = true;
|
||||||
|
|
||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
*/
|
*/
|
||||||
BlockNumber
|
BlockNumber
|
||||||
BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, int samplesize,
|
BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, int samplesize,
|
||||||
long randseed)
|
uint32 randseed)
|
||||||
{
|
{
|
||||||
bs->N = nblocks; /* measured table size */
|
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->t = 0; /* blocks scanned so far */
|
||||||
bs->m = 0; /* blocks selected 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);
|
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.
|
* 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;
|
p = 1.0 - (double) k / (double) K;
|
||||||
while (V < p)
|
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
|
* Reservoir sampling is not used anywhere where it would need to return
|
||||||
* repeatable results so we can initialize it randomly.
|
* 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) */
|
/* 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
|
double
|
||||||
@ -154,7 +155,7 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
|
|||||||
double V,
|
double V,
|
||||||
quot;
|
quot;
|
||||||
|
|
||||||
V = sampler_random_fract(rs->randstate); /* Generate V */
|
V = sampler_random_fract(&rs->randstate); /* Generate V */
|
||||||
S = 0;
|
S = 0;
|
||||||
t += 1;
|
t += 1;
|
||||||
/* Note: "num" in Vitter's code is always equal to t - n */
|
/* 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;
|
tmp;
|
||||||
|
|
||||||
/* Generate U and X */
|
/* Generate U and X */
|
||||||
U = sampler_random_fract(rs->randstate);
|
U = sampler_random_fract(&rs->randstate);
|
||||||
X = t * (W - 1.0);
|
X = t * (W - 1.0);
|
||||||
S = floor(X); /* S is tentatively set to floor(X) */
|
S = floor(X); /* S is tentatively set to floor(X) */
|
||||||
/* Test if U <= h(S)/cg(X) in the manner of (6.3) */
|
/* 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;
|
y *= numer / denom;
|
||||||
denom -= 1;
|
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)
|
if (exp(log(y) / n) <= (t + X) / t)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -230,24 +231,22 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
|
|||||||
*----------
|
*----------
|
||||||
*/
|
*/
|
||||||
void
|
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 */
|
pg_prng_seed(randstate, (uint64) seed);
|
||||||
randstate[1] = (unsigned short) seed;
|
|
||||||
randstate[2] = (unsigned short) (seed >> 16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select a random value R uniformly distributed in (0 - 1) */
|
/* Select a random value R uniformly distributed in (0 - 1) */
|
||||||
double
|
double
|
||||||
sampler_random_fract(SamplerRandomState randstate)
|
sampler_random_fract(pg_prng_state *randstate)
|
||||||
{
|
{
|
||||||
double res;
|
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
|
do
|
||||||
{
|
{
|
||||||
res = pg_erand48(randstate);
|
res = pg_prng_double(randstate);
|
||||||
} while (res == 0.0);
|
} while (unlikely(res == 0.0));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,27 +260,36 @@ sampler_random_fract(SamplerRandomState randstate)
|
|||||||
* except that a common random state is used across all callers.
|
* except that a common random state is used across all callers.
|
||||||
*/
|
*/
|
||||||
static ReservoirStateData oldrs;
|
static ReservoirStateData oldrs;
|
||||||
|
static bool oldrs_initialized = false;
|
||||||
|
|
||||||
double
|
double
|
||||||
anl_random_fract(void)
|
anl_random_fract(void)
|
||||||
{
|
{
|
||||||
/* initialize if first time through */
|
/* initialize if first time through */
|
||||||
if (oldrs.randstate[0] == 0)
|
if (unlikely(!oldrs_initialized))
|
||||||
sampler_random_init_state(random(), oldrs.randstate);
|
{
|
||||||
|
sampler_random_init_state(pg_prng_uint32(&pg_global_prng_state),
|
||||||
|
&oldrs.randstate);
|
||||||
|
oldrs_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* and compute a random fraction */
|
/* and compute a random fraction */
|
||||||
return sampler_random_fract(oldrs.randstate);
|
return sampler_random_fract(&oldrs.randstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
anl_init_selection_state(int n)
|
anl_init_selection_state(int n)
|
||||||
{
|
{
|
||||||
/* initialize if first time through */
|
/* initialize if first time through */
|
||||||
if (oldrs.randstate[0] == 0)
|
if (unlikely(!oldrs_initialized))
|
||||||
sampler_random_init_state(random(), oldrs.randstate);
|
{
|
||||||
|
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) */
|
/* 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
|
double
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/file_utils.h"
|
#include "common/file_utils.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "common/restricted_token.h"
|
#include "common/restricted_token.h"
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
#include "common/username.h"
|
#include "common/username.h"
|
||||||
@ -880,9 +881,10 @@ choose_dsm_implementation(void)
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_SHM_OPEN
|
#ifdef HAVE_SHM_OPEN
|
||||||
int ntries = 10;
|
int ntries = 10;
|
||||||
|
pg_prng_state prng_state;
|
||||||
|
|
||||||
/* Initialize random(); this function is its only user in this program. */
|
/* Initialize prng; this function is its only user in this program. */
|
||||||
srandom((unsigned int) (getpid() ^ time(NULL)));
|
pg_prng_seed(&prng_state, (uint64) (getpid() ^ time(NULL)));
|
||||||
|
|
||||||
while (ntries > 0)
|
while (ntries > 0)
|
||||||
{
|
{
|
||||||
@ -890,7 +892,7 @@ choose_dsm_implementation(void)
|
|||||||
char name[64];
|
char name[64];
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
handle = random();
|
handle = pg_prng_uint32(&prng_state);
|
||||||
snprintf(name, 64, "/PostgreSQL.%u", handle);
|
snprintf(name, 64, "/PostgreSQL.%u", handle);
|
||||||
if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) != -1)
|
if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) != -1)
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "access/xlogdefs.h"
|
#include "access/xlogdefs.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "getopt_long.h"
|
#include "getopt_long.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -117,6 +118,8 @@ main(int argc, char *argv[])
|
|||||||
pqsignal(SIGHUP, signal_cleanup);
|
pqsignal(SIGHUP, signal_cleanup);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
|
||||||
|
|
||||||
prepare_buf();
|
prepare_buf();
|
||||||
|
|
||||||
test_open();
|
test_open();
|
||||||
@ -233,7 +236,7 @@ prepare_buf(void)
|
|||||||
|
|
||||||
/* write random data into buffer */
|
/* write random data into buffer */
|
||||||
for (ops = 0; ops < DEFAULT_XLOG_SEG_SIZE; ops++)
|
for (ops = 0; ops < DEFAULT_XLOG_SEG_SIZE; ops++)
|
||||||
full_buf[ops] = random();
|
full_buf[ops] = (char) pg_prng_int32(&pg_global_prng_state);
|
||||||
|
|
||||||
buf = (char *) TYPEALIGN(XLOG_BLCKSZ, full_buf);
|
buf = (char *) TYPEALIGN(XLOG_BLCKSZ, full_buf);
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
|
|
||||||
#include "common/int.h"
|
#include "common/int.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
#include "common/username.h"
|
#include "common/username.h"
|
||||||
#include "fe_utils/cancel.h"
|
#include "fe_utils/cancel.h"
|
||||||
@ -350,16 +351,8 @@ typedef struct StatsData
|
|||||||
*/
|
*/
|
||||||
pg_time_usec_t epoch_shift;
|
pg_time_usec_t epoch_shift;
|
||||||
|
|
||||||
/*
|
|
||||||
* Struct to keep random state.
|
|
||||||
*/
|
|
||||||
typedef struct RandomState
|
|
||||||
{
|
|
||||||
unsigned short xseed[3];
|
|
||||||
} RandomState;
|
|
||||||
|
|
||||||
/* Various random sequences are initialized from this one. */
|
/* Various random sequences are initialized from this one. */
|
||||||
static RandomState base_random_sequence;
|
static pg_prng_state base_random_sequence;
|
||||||
|
|
||||||
/* Synchronization barrier for start and connection */
|
/* Synchronization barrier for start and connection */
|
||||||
static THREAD_BARRIER_T barrier;
|
static THREAD_BARRIER_T barrier;
|
||||||
@ -461,7 +454,7 @@ typedef struct
|
|||||||
* Separate randomness for each client. This is used for random functions
|
* Separate randomness for each client. This is used for random functions
|
||||||
* PGBENCH_RANDOM_* during the execution of the script.
|
* PGBENCH_RANDOM_* during the execution of the script.
|
||||||
*/
|
*/
|
||||||
RandomState cs_func_rs;
|
pg_prng_state cs_func_rs;
|
||||||
|
|
||||||
int use_file; /* index in sql_script for this client */
|
int use_file; /* index in sql_script for this client */
|
||||||
int command; /* command number in script */
|
int command; /* command number in script */
|
||||||
@ -498,9 +491,9 @@ typedef struct
|
|||||||
* random state to make all of them independent of each other and
|
* random state to make all of them independent of each other and
|
||||||
* therefore deterministic at the thread level.
|
* therefore deterministic at the thread level.
|
||||||
*/
|
*/
|
||||||
RandomState ts_choose_rs; /* random state for selecting a script */
|
pg_prng_state ts_choose_rs; /* random state for selecting a script */
|
||||||
RandomState ts_throttle_rs; /* random state for transaction throttling */
|
pg_prng_state ts_throttle_rs; /* random state for transaction throttling */
|
||||||
RandomState ts_sample_rs; /* random state for log sampling */
|
pg_prng_state ts_sample_rs; /* random state for log sampling */
|
||||||
|
|
||||||
int64 throttle_trigger; /* previous/next throttling (us) */
|
int64 throttle_trigger; /* previous/next throttling (us) */
|
||||||
FILE *logfile; /* where to log, or NULL */
|
FILE *logfile; /* where to log, or NULL */
|
||||||
@ -898,42 +891,28 @@ strtodouble(const char *str, bool errorOK, double *dv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize a random state struct.
|
* Initialize a prng state struct.
|
||||||
*
|
*
|
||||||
* We derive the seed from base_random_sequence, which must be set up already.
|
* We derive the seed from base_random_sequence, which must be set up already.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
initRandomState(RandomState *random_state)
|
initRandomState(pg_prng_state *state)
|
||||||
{
|
{
|
||||||
random_state->xseed[0] = (unsigned short)
|
pg_prng_seed(state, pg_prng_uint64(&base_random_sequence));
|
||||||
(pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
|
|
||||||
random_state->xseed[1] = (unsigned short)
|
|
||||||
(pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
|
|
||||||
random_state->xseed[2] = (unsigned short)
|
|
||||||
(pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Random number generator: uniform distribution from min to max inclusive.
|
* random number generator: uniform distribution from min to max inclusive.
|
||||||
*
|
*
|
||||||
* Although the limits are expressed as int64, you can't generate the full
|
* Although the limits are expressed as int64, you can't generate the full
|
||||||
* int64 range in one call, because the difference of the limits mustn't
|
* int64 range in one call, because the difference of the limits mustn't
|
||||||
* overflow int64. In practice it's unwise to ask for more than an int32
|
* overflow int64. This is not checked.
|
||||||
* range, because of the limited precision of pg_erand48().
|
|
||||||
*/
|
*/
|
||||||
static int64
|
static int64
|
||||||
getrand(RandomState *random_state, int64 min, int64 max)
|
getrand(pg_prng_state *state, int64 min, int64 max)
|
||||||
{
|
{
|
||||||
/*
|
return min + (int64) pg_prng_uint64_range(state, 0, max - min);
|
||||||
* Odd coding is so that min and max have approximately the same chance of
|
|
||||||
* being selected as do numbers between them.
|
|
||||||
*
|
|
||||||
* pg_erand48() is thread-safe and concurrent, which is why we use it
|
|
||||||
* rather than random(), which in glibc is non-reentrant, and therefore
|
|
||||||
* protected by a mutex, and therefore a bottleneck on machines with many
|
|
||||||
* CPUs.
|
|
||||||
*/
|
|
||||||
return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -942,7 +921,7 @@ getrand(RandomState *random_state, int64 min, int64 max)
|
|||||||
* value is exp(-parameter).
|
* value is exp(-parameter).
|
||||||
*/
|
*/
|
||||||
static int64
|
static int64
|
||||||
getExponentialRand(RandomState *random_state, int64 min, int64 max,
|
getExponentialRand(pg_prng_state *state, int64 min, int64 max,
|
||||||
double parameter)
|
double parameter)
|
||||||
{
|
{
|
||||||
double cut,
|
double cut,
|
||||||
@ -952,8 +931,8 @@ getExponentialRand(RandomState *random_state, int64 min, int64 max,
|
|||||||
/* abort if wrong parameter, but must really be checked beforehand */
|
/* abort if wrong parameter, but must really be checked beforehand */
|
||||||
Assert(parameter > 0.0);
|
Assert(parameter > 0.0);
|
||||||
cut = exp(-parameter);
|
cut = exp(-parameter);
|
||||||
/* erand in [0, 1), uniform in (0, 1] */
|
/* pg_prng_double value in [0, 1), uniform in (0, 1] */
|
||||||
uniform = 1.0 - pg_erand48(random_state->xseed);
|
uniform = 1.0 - pg_prng_double(state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
|
* inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
|
||||||
@ -966,7 +945,7 @@ getExponentialRand(RandomState *random_state, int64 min, int64 max,
|
|||||||
|
|
||||||
/* random number generator: gaussian distribution from min to max inclusive */
|
/* random number generator: gaussian distribution from min to max inclusive */
|
||||||
static int64
|
static int64
|
||||||
getGaussianRand(RandomState *random_state, int64 min, int64 max,
|
getGaussianRand(pg_prng_state *state, int64 min, int64 max,
|
||||||
double parameter)
|
double parameter)
|
||||||
{
|
{
|
||||||
double stdev;
|
double stdev;
|
||||||
@ -990,13 +969,13 @@ getGaussianRand(RandomState *random_state, int64 min, int64 max,
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* pg_erand48 generates [0,1), but for the basic version of the
|
* pg_prng_double generates [0, 1), but for the basic version of the
|
||||||
* Box-Muller transform the two uniformly distributed random numbers
|
* Box-Muller transform the two uniformly distributed random numbers
|
||||||
* are expected in (0, 1] (see
|
* are expected to be in (0, 1] (see
|
||||||
* https://en.wikipedia.org/wiki/Box-Muller_transform)
|
* https://en.wikipedia.org/wiki/Box-Muller_transform)
|
||||||
*/
|
*/
|
||||||
double rand1 = 1.0 - pg_erand48(random_state->xseed);
|
double rand1 = 1.0 - pg_prng_double(state);
|
||||||
double rand2 = 1.0 - pg_erand48(random_state->xseed);
|
double rand2 = 1.0 - pg_prng_double(state);
|
||||||
|
|
||||||
/* Box-Muller basic form transform */
|
/* Box-Muller basic form transform */
|
||||||
double var_sqrt = sqrt(-2.0 * log(rand1));
|
double var_sqrt = sqrt(-2.0 * log(rand1));
|
||||||
@ -1026,7 +1005,7 @@ getGaussianRand(RandomState *random_state, int64 min, int64 max,
|
|||||||
* not be one.
|
* not be one.
|
||||||
*/
|
*/
|
||||||
static int64
|
static int64
|
||||||
getPoissonRand(RandomState *random_state, double center)
|
getPoissonRand(pg_prng_state *state, double center)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Use inverse transform sampling to generate a value > 0, such that the
|
* Use inverse transform sampling to generate a value > 0, such that the
|
||||||
@ -1034,8 +1013,8 @@ getPoissonRand(RandomState *random_state, double center)
|
|||||||
*/
|
*/
|
||||||
double uniform;
|
double uniform;
|
||||||
|
|
||||||
/* erand in [0, 1), uniform in (0, 1] */
|
/* pg_prng_double value in [0, 1), uniform in (0, 1] */
|
||||||
uniform = 1.0 - pg_erand48(random_state->xseed);
|
uniform = 1.0 - pg_prng_double(state);
|
||||||
|
|
||||||
return (int64) (-log(uniform) * center + 0.5);
|
return (int64) (-log(uniform) * center + 0.5);
|
||||||
}
|
}
|
||||||
@ -1048,7 +1027,7 @@ getPoissonRand(RandomState *random_state, double center)
|
|||||||
* This works for s > 1.0, but may perform badly for s very close to 1.0.
|
* This works for s > 1.0, but may perform badly for s very close to 1.0.
|
||||||
*/
|
*/
|
||||||
static int64
|
static int64
|
||||||
computeIterativeZipfian(RandomState *random_state, int64 n, double s)
|
computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
|
||||||
{
|
{
|
||||||
double b = pow(2.0, s - 1.0);
|
double b = pow(2.0, s - 1.0);
|
||||||
double x,
|
double x,
|
||||||
@ -1063,8 +1042,8 @@ computeIterativeZipfian(RandomState *random_state, int64 n, double s)
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
/* random variates */
|
/* random variates */
|
||||||
u = pg_erand48(random_state->xseed);
|
u = pg_prng_double(state);
|
||||||
v = pg_erand48(random_state->xseed);
|
v = pg_prng_double(state);
|
||||||
|
|
||||||
x = floor(pow(u, -1.0 / (s - 1.0)));
|
x = floor(pow(u, -1.0 / (s - 1.0)));
|
||||||
|
|
||||||
@ -1078,14 +1057,14 @@ computeIterativeZipfian(RandomState *random_state, int64 n, double s)
|
|||||||
|
|
||||||
/* random number generator: zipfian distribution from min to max inclusive */
|
/* random number generator: zipfian distribution from min to max inclusive */
|
||||||
static int64
|
static int64
|
||||||
getZipfianRand(RandomState *random_state, int64 min, int64 max, double s)
|
getZipfianRand(pg_prng_state *state, int64 min, int64 max, double s)
|
||||||
{
|
{
|
||||||
int64 n = max - min + 1;
|
int64 n = max - min + 1;
|
||||||
|
|
||||||
/* abort if parameter is invalid */
|
/* abort if parameter is invalid */
|
||||||
Assert(MIN_ZIPFIAN_PARAM <= s && s <= MAX_ZIPFIAN_PARAM);
|
Assert(MIN_ZIPFIAN_PARAM <= s && s <= MAX_ZIPFIAN_PARAM);
|
||||||
|
|
||||||
return min - 1 + computeIterativeZipfian(random_state, n, s);
|
return min - 1 + computeIterativeZipfian(state, n, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1142,7 +1121,7 @@ getHashMurmur2(int64 val, uint64 seed)
|
|||||||
* For small sizes, this generates each of the (size!) possible permutations
|
* For small sizes, this generates each of the (size!) possible permutations
|
||||||
* of integers in the range [0, size) with roughly equal probability. Once
|
* of integers in the range [0, size) with roughly equal probability. Once
|
||||||
* the size is larger than 20, the number of possible permutations exceeds the
|
* the size is larger than 20, the number of possible permutations exceeds the
|
||||||
* number of distinct states of the internal pseudorandom number generators,
|
* number of distinct states of the internal pseudorandom number generator,
|
||||||
* and so not all possible permutations can be generated, but the permutations
|
* and so not all possible permutations can be generated, but the permutations
|
||||||
* chosen should continue to give the appearance of being random.
|
* chosen should continue to give the appearance of being random.
|
||||||
*
|
*
|
||||||
@ -1152,8 +1131,8 @@ getHashMurmur2(int64 val, uint64 seed)
|
|||||||
static int64
|
static int64
|
||||||
permute(const int64 val, const int64 isize, const int64 seed)
|
permute(const int64 val, const int64 isize, const int64 seed)
|
||||||
{
|
{
|
||||||
RandomState random_state1;
|
/* using a high-end PRNG is probably overkill */
|
||||||
RandomState random_state2;
|
pg_prng_state state;
|
||||||
uint64 size;
|
uint64 size;
|
||||||
uint64 v;
|
uint64 v;
|
||||||
int masklen;
|
int masklen;
|
||||||
@ -1163,14 +1142,8 @@ permute(const int64 val, const int64 isize, const int64 seed)
|
|||||||
if (isize < 2)
|
if (isize < 2)
|
||||||
return 0; /* nothing to permute */
|
return 0; /* nothing to permute */
|
||||||
|
|
||||||
/* Initialize a pair of random states using the seed */
|
/* Initialize prng state using the seed */
|
||||||
random_state1.xseed[0] = seed & 0xFFFF;
|
pg_prng_seed(&state, (uint64) seed);
|
||||||
random_state1.xseed[1] = (seed >> 16) & 0xFFFF;
|
|
||||||
random_state1.xseed[2] = (seed >> 32) & 0xFFFF;
|
|
||||||
|
|
||||||
random_state2.xseed[0] = (((uint64) seed) >> 48) & 0xFFFF;
|
|
||||||
random_state2.xseed[1] = seed & 0xFFFF;
|
|
||||||
random_state2.xseed[2] = (seed >> 16) & 0xFFFF;
|
|
||||||
|
|
||||||
/* Computations are performed on unsigned values */
|
/* Computations are performed on unsigned values */
|
||||||
size = (uint64) isize;
|
size = (uint64) isize;
|
||||||
@ -1216,8 +1189,8 @@ permute(const int64 val, const int64 isize, const int64 seed)
|
|||||||
t;
|
t;
|
||||||
|
|
||||||
/* Random multiply (by an odd number), XOR and rotate of lower half */
|
/* Random multiply (by an odd number), XOR and rotate of lower half */
|
||||||
m = (uint64) getrand(&random_state1, 0, mask) | 1;
|
m = (pg_prng_uint64(&state) & mask) | 1;
|
||||||
r = (uint64) getrand(&random_state2, 0, mask);
|
r = pg_prng_uint64(&state) & mask;
|
||||||
if (v <= mask)
|
if (v <= mask)
|
||||||
{
|
{
|
||||||
v = ((v * m) ^ r) & mask;
|
v = ((v * m) ^ r) & mask;
|
||||||
@ -1225,8 +1198,8 @@ permute(const int64 val, const int64 isize, const int64 seed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Random multiply (by an odd number), XOR and rotate of upper half */
|
/* Random multiply (by an odd number), XOR and rotate of upper half */
|
||||||
m = (uint64) getrand(&random_state1, 0, mask) | 1;
|
m = (pg_prng_uint64(&state) & mask) | 1;
|
||||||
r = (uint64) getrand(&random_state2, 0, mask);
|
r = pg_prng_uint64(&state) & mask;
|
||||||
t = size - 1 - v;
|
t = size - 1 - v;
|
||||||
if (t <= mask)
|
if (t <= mask)
|
||||||
{
|
{
|
||||||
@ -1236,7 +1209,7 @@ permute(const int64 val, const int64 isize, const int64 seed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Random offset */
|
/* Random offset */
|
||||||
r = (uint64) getrand(&random_state2, 0, size - 1);
|
r = pg_prng_uint64_range(&state, 0, size - 1);
|
||||||
v = (v + r) % size;
|
v = (v + r) % size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3831,7 +3804,7 @@ doLog(TState *thread, CState *st,
|
|||||||
* to the random sample.
|
* to the random sample.
|
||||||
*/
|
*/
|
||||||
if (sample_rate != 0.0 &&
|
if (sample_rate != 0.0 &&
|
||||||
pg_erand48(thread->ts_sample_rs.xseed) > sample_rate)
|
pg_prng_double(&thread->ts_sample_rs) > sample_rate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* should we aggregate the results or not? */
|
/* should we aggregate the results or not? */
|
||||||
@ -5770,12 +5743,11 @@ set_random_seed(const char *seed)
|
|||||||
|
|
||||||
if (seed != NULL)
|
if (seed != NULL)
|
||||||
pg_log_info("setting random seed to %llu", (unsigned long long) iseed);
|
pg_log_info("setting random seed to %llu", (unsigned long long) iseed);
|
||||||
|
|
||||||
random_seed = iseed;
|
random_seed = iseed;
|
||||||
|
|
||||||
/* Fill base_random_sequence with low-order bits of seed */
|
/* Initialize base_random_sequence using seed */
|
||||||
base_random_sequence.xseed[0] = iseed & 0xFFFF;
|
pg_prng_seed(&base_random_sequence, (uint64) iseed);
|
||||||
base_random_sequence.xseed[1] = (iseed >> 16) & 0xFFFF;
|
|
||||||
base_random_sequence.xseed[2] = (iseed >> 32) & 0xFFFF;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -6449,9 +6421,7 @@ main(int argc, char **argv)
|
|||||||
/* set default seed for hash functions */
|
/* set default seed for hash functions */
|
||||||
if (lookupVariable(&state[0], "default_seed") == NULL)
|
if (lookupVariable(&state[0], "default_seed") == NULL)
|
||||||
{
|
{
|
||||||
uint64 seed =
|
uint64 seed = pg_prng_uint64(&base_random_sequence);
|
||||||
((uint64) pg_jrand48(base_random_sequence.xseed) & 0xFFFFFFFF) |
|
|
||||||
(((uint64) pg_jrand48(base_random_sequence.xseed) & 0xFFFFFFFF) << 32);
|
|
||||||
|
|
||||||
for (i = 0; i < nclients; i++)
|
for (i = 0; i < nclients; i++)
|
||||||
if (!putVariableInt(&state[i], "startup", "default_seed", (int64) seed))
|
if (!putVariableInt(&state[i], "startup", "default_seed", (int64) seed))
|
||||||
|
@ -369,7 +369,6 @@ $node->append_conf('postgresql.conf',
|
|||||||
$node->reload;
|
$node->reload;
|
||||||
|
|
||||||
# test expressions
|
# test expressions
|
||||||
# command 1..3 and 23 depend on random seed which is used to call srandom.
|
|
||||||
$node->pgbench(
|
$node->pgbench(
|
||||||
'--random-seed=5432 -t 1 -Dfoo=-10.1 -Dbla=false -Di=+3 -Dn=null -Dt=t -Df=of -Dd=1.0',
|
'--random-seed=5432 -t 1 -Dfoo=-10.1 -Dbla=false -Di=+3 -Dn=null -Dt=t -Df=of -Dd=1.0',
|
||||||
0,
|
0,
|
||||||
@ -378,9 +377,9 @@ $node->pgbench(
|
|||||||
qr{setting random seed to 5432\b},
|
qr{setting random seed to 5432\b},
|
||||||
|
|
||||||
# After explicit seeding, the four random checks (1-3,20) are
|
# After explicit seeding, the four random checks (1-3,20) are
|
||||||
# deterministic
|
# deterministic; but see also magic values in checks 111,113.
|
||||||
qr{command=1.: int 13\b}, # uniform random
|
qr{command=1.: int 17\b}, # uniform random
|
||||||
qr{command=2.: int 116\b}, # exponential random
|
qr{command=2.: int 104\b}, # exponential random
|
||||||
qr{command=3.: int 1498\b}, # gaussian random
|
qr{command=3.: int 1498\b}, # gaussian random
|
||||||
qr{command=4.: int 4\b},
|
qr{command=4.: int 4\b},
|
||||||
qr{command=5.: int 5\b},
|
qr{command=5.: int 5\b},
|
||||||
@ -394,7 +393,7 @@ $node->pgbench(
|
|||||||
qr{command=15.: double 15\b},
|
qr{command=15.: double 15\b},
|
||||||
qr{command=16.: double 16\b},
|
qr{command=16.: double 16\b},
|
||||||
qr{command=17.: double 17\b},
|
qr{command=17.: double 17\b},
|
||||||
qr{command=20.: int 1\b}, # zipfian random
|
qr{command=20.: int 3\b}, # zipfian random
|
||||||
qr{command=21.: double -27\b},
|
qr{command=21.: double -27\b},
|
||||||
qr{command=22.: double 1024\b},
|
qr{command=22.: double 1024\b},
|
||||||
qr{command=23.: double 1\b},
|
qr{command=23.: double 1\b},
|
||||||
@ -448,6 +447,7 @@ $node->pgbench(
|
|||||||
qr{command=109.: boolean true\b},
|
qr{command=109.: boolean true\b},
|
||||||
qr{command=110.: boolean true\b},
|
qr{command=110.: boolean true\b},
|
||||||
qr{command=111.: boolean true\b},
|
qr{command=111.: boolean true\b},
|
||||||
|
qr{command=113.: boolean true\b},
|
||||||
],
|
],
|
||||||
'pgbench expressions',
|
'pgbench expressions',
|
||||||
{
|
{
|
||||||
@ -591,8 +591,17 @@ SELECT :v0, :v1, :v2, :v3;
|
|||||||
\set t debug(0 <= :p and :p < :size and :p = permute(:v + :size, :size) and :p <> permute(:v + 1, :size))
|
\set t debug(0 <= :p and :p < :size and :p = permute(:v + :size, :size) and :p <> permute(:v + 1, :size))
|
||||||
-- actual values
|
-- actual values
|
||||||
\set t debug(permute(:v, 1) = 0)
|
\set t debug(permute(:v, 1) = 0)
|
||||||
\set t debug(permute(0, 2, 5432) = 0 and permute(1, 2, 5432) = 1 and \
|
\set t debug(permute(0, 2, 5431) = 0 and permute(1, 2, 5431) = 1 and \
|
||||||
permute(0, 2, 5435) = 1 and permute(1, 2, 5435) = 0)
|
permute(0, 2, 5433) = 1 and permute(1, 2, 5433) = 0)
|
||||||
|
-- check permute's portability across architectures
|
||||||
|
\set size debug(:max - 10)
|
||||||
|
\set t debug(permute(:size-1, :size, 5432) = 520382784483822430 and \
|
||||||
|
permute(:size-2, :size, 5432) = 1143715004660802862 and \
|
||||||
|
permute(:size-3, :size, 5432) = 447293596416496998 and \
|
||||||
|
permute(:size-4, :size, 5432) = 916527772266572956 and \
|
||||||
|
permute(:size-5, :size, 5432) = 2763809008686028849 and \
|
||||||
|
permute(:size-6, :size, 5432) = 8648551549198294572 and \
|
||||||
|
permute(:size-7, :size, 5432) = 4542876852200565125)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ OBJS_COMMON = \
|
|||||||
md5_common.o \
|
md5_common.o \
|
||||||
pg_get_line.o \
|
pg_get_line.o \
|
||||||
pg_lzcompress.o \
|
pg_lzcompress.o \
|
||||||
|
pg_prng.o \
|
||||||
pgfnames.o \
|
pgfnames.o \
|
||||||
psprintf.o \
|
psprintf.o \
|
||||||
relpath.o \
|
relpath.o \
|
||||||
|
247
src/common/pg_prng.c
Normal file
247
src/common/pg_prng.c
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pseudo-Random Number Generator
|
||||||
|
*
|
||||||
|
* We use Blackman and Vigna's xoroshiro128** 1.0 algorithm
|
||||||
|
* to have a small, fast PRNG suitable for generating reasonably
|
||||||
|
* good-quality 64-bit data. This should not be considered
|
||||||
|
* cryptographically strong, however.
|
||||||
|
*
|
||||||
|
* About these generators: https://prng.di.unimi.it/
|
||||||
|
* See also https://en.wikipedia.org/wiki/List_of_random_number_generators
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* src/common/pg_prng.c
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "c.h"
|
||||||
|
|
||||||
|
#include <math.h> /* for ldexp() */
|
||||||
|
|
||||||
|
#include "common/pg_prng.h"
|
||||||
|
#include "port/pg_bitutils.h"
|
||||||
|
|
||||||
|
/* process-wide state vector */
|
||||||
|
pg_prng_state pg_global_prng_state;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 64-bit rotate left
|
||||||
|
*/
|
||||||
|
static inline uint64
|
||||||
|
rotl(uint64 x, int bits)
|
||||||
|
{
|
||||||
|
return (x << bits) | (x >> (64 - bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The basic xoroshiro128** algorithm.
|
||||||
|
* Generates and returns a 64-bit uniformly distributed number,
|
||||||
|
* updating the state vector for next time.
|
||||||
|
*
|
||||||
|
* Note: the state vector must not be all-zeroes, as that is a fixed point.
|
||||||
|
*/
|
||||||
|
static uint64
|
||||||
|
xoroshiro128ss(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
uint64 s0 = state->s0,
|
||||||
|
sx = state->s1 ^ s0,
|
||||||
|
val = rotl(s0 * 5, 7) * 9;
|
||||||
|
|
||||||
|
/* update state */
|
||||||
|
state->s0 = rotl(s0, 24) ^ sx ^ (sx << 16);
|
||||||
|
state->s1 = rotl(sx, 37);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use this generator just to fill the xoroshiro128** state vector
|
||||||
|
* from a 64-bit seed.
|
||||||
|
*/
|
||||||
|
static uint64
|
||||||
|
splitmix64(uint64 *state)
|
||||||
|
{
|
||||||
|
/* state update */
|
||||||
|
uint64 val = (*state += UINT64CONST(0x9E3779B97f4A7C15));
|
||||||
|
|
||||||
|
/* value extraction */
|
||||||
|
val = (val ^ (val >> 30)) * UINT64CONST(0xBF58476D1CE4E5B9);
|
||||||
|
val = (val ^ (val >> 27)) * UINT64CONST(0x94D049BB133111EB);
|
||||||
|
|
||||||
|
return val ^ (val >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the PRNG state from a 64-bit integer,
|
||||||
|
* taking care that we don't produce all-zeroes.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pg_prng_seed(pg_prng_state *state, uint64 seed)
|
||||||
|
{
|
||||||
|
state->s0 = splitmix64(&seed);
|
||||||
|
state->s1 = splitmix64(&seed);
|
||||||
|
/* Let's just make sure we didn't get all-zeroes */
|
||||||
|
(void) pg_prng_seed_check(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the PRNG state from a double in the range [-1.0, 1.0],
|
||||||
|
* taking care that we don't produce all-zeroes.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pg_prng_fseed(pg_prng_state *state, double fseed)
|
||||||
|
{
|
||||||
|
/* Assume there's about 52 mantissa bits; the sign contributes too. */
|
||||||
|
int64 seed = ((double) ((UINT64CONST(1) << 52) - 1)) * fseed;
|
||||||
|
|
||||||
|
pg_prng_seed(state, (uint64) seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate a PRNG seed value.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
pg_prng_seed_check(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the seeding mechanism chanced to produce all-zeroes, insert
|
||||||
|
* something nonzero. Anything would do; use Knuth's LCG parameters.
|
||||||
|
*/
|
||||||
|
if (unlikely(state->s0 == 0 && state->s1 == 0))
|
||||||
|
{
|
||||||
|
state->s0 = UINT64CONST(0x5851F42D4C957F2D);
|
||||||
|
state->s1 = UINT64CONST(0x14057B7EF767814F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As a convenience for the pg_prng_strong_seed macro, return true */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random uint64 uniformly from the range [0, PG_UINT64_MAX].
|
||||||
|
*/
|
||||||
|
uint64
|
||||||
|
pg_prng_uint64(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
return xoroshiro128ss(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random uint64 uniformly from the range [rmin, rmax].
|
||||||
|
* If the range is empty, rmin is always produced.
|
||||||
|
*/
|
||||||
|
uint64
|
||||||
|
pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
|
||||||
|
{
|
||||||
|
uint64 val;
|
||||||
|
|
||||||
|
if (likely(rmax > rmin))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Use bitmask rejection method to generate an offset in 0..range.
|
||||||
|
* Each generated val is less than twice "range", so on average we
|
||||||
|
* should not have to iterate more than twice.
|
||||||
|
*/
|
||||||
|
uint64 range = rmax - rmin;
|
||||||
|
uint32 rshift = 63 - pg_leftmost_one_pos64(range);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
val = xoroshiro128ss(state) >> rshift;
|
||||||
|
} while (val > range);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
val = 0;
|
||||||
|
|
||||||
|
return rmin + val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random int64 uniformly from the range [PG_INT64_MIN, PG_INT64_MAX].
|
||||||
|
*/
|
||||||
|
int64
|
||||||
|
pg_prng_int64(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
return (int64) xoroshiro128ss(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random int64 uniformly from the range [0, PG_INT64_MAX].
|
||||||
|
*/
|
||||||
|
int64
|
||||||
|
pg_prng_int64p(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
return (int64) (xoroshiro128ss(state) & UINT64CONST(0x7FFFFFFFFFFFFFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random uint32 uniformly from the range [0, PG_UINT32_MAX].
|
||||||
|
*/
|
||||||
|
uint32
|
||||||
|
pg_prng_uint32(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Although xoroshiro128** is not known to have any weaknesses in
|
||||||
|
* randomness of low-order bits, we prefer to use the upper bits of its
|
||||||
|
* result here and below.
|
||||||
|
*/
|
||||||
|
uint64 v = xoroshiro128ss(state);
|
||||||
|
|
||||||
|
return (uint32) (v >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random int32 uniformly from the range [PG_INT32_MIN, PG_INT32_MAX].
|
||||||
|
*/
|
||||||
|
int32
|
||||||
|
pg_prng_int32(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
uint64 v = xoroshiro128ss(state);
|
||||||
|
|
||||||
|
return (int32) (v >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random int32 uniformly from the range [0, PG_INT32_MAX].
|
||||||
|
*/
|
||||||
|
int32
|
||||||
|
pg_prng_int32p(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
uint64 v = xoroshiro128ss(state);
|
||||||
|
|
||||||
|
return (int32) (v >> 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random double uniformly from the range [0.0, 1.0).
|
||||||
|
*
|
||||||
|
* Note: if you want a result in the range (0.0, 1.0], the standard way
|
||||||
|
* to get that is "1.0 - pg_prng_double(state)".
|
||||||
|
*/
|
||||||
|
double
|
||||||
|
pg_prng_double(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
uint64 v = xoroshiro128ss(state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As above, assume there's 52 mantissa bits in a double. This result
|
||||||
|
* could round to 1.0 if double's precision is less than that; but we
|
||||||
|
* assume IEEE float arithmetic elsewhere in Postgres, so this seems OK.
|
||||||
|
*/
|
||||||
|
return ldexp((double) (v >> (64 - 52)), -52);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a random boolean value.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
pg_prng_bool(pg_prng_state *state)
|
||||||
|
{
|
||||||
|
uint64 v = xoroshiro128ss(state);
|
||||||
|
|
||||||
|
return (bool) (v >> 63);
|
||||||
|
}
|
60
src/include/common/pg_prng.h
Normal file
60
src/include/common/pg_prng.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pseudo-Random Number Generator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* src/include/common/pg_prng.h
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef PG_PRNG_H
|
||||||
|
#define PG_PRNG_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* State vector for PRNG generation. Callers should treat this as an
|
||||||
|
* opaque typedef, but we expose its definition to allow it to be
|
||||||
|
* embedded in other structs.
|
||||||
|
*/
|
||||||
|
typedef struct pg_prng_state
|
||||||
|
{
|
||||||
|
uint64 s0,
|
||||||
|
s1;
|
||||||
|
} pg_prng_state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callers not needing local PRNG series may use this global state vector,
|
||||||
|
* after initializing it with one of the pg_prng_...seed functions.
|
||||||
|
*/
|
||||||
|
extern PGDLLIMPORT pg_prng_state pg_global_prng_state;
|
||||||
|
|
||||||
|
extern void pg_prng_seed(pg_prng_state *state, uint64 seed);
|
||||||
|
extern void pg_prng_fseed(pg_prng_state *state, double fseed);
|
||||||
|
extern bool pg_prng_seed_check(pg_prng_state *state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the PRNG state from the pg_strong_random source,
|
||||||
|
* taking care that we don't produce all-zeroes. If this returns false,
|
||||||
|
* caller should initialize the PRNG state from some other random seed,
|
||||||
|
* using pg_prng_[f]seed.
|
||||||
|
*
|
||||||
|
* We implement this as a macro, so that the pg_strong_random() call is
|
||||||
|
* in the caller. If it were in pg_prng.c, programs using pg_prng.c
|
||||||
|
* but not needing strong seeding would nonetheless be forced to pull in
|
||||||
|
* pg_strong_random.c and thence OpenSSL.
|
||||||
|
*/
|
||||||
|
#define pg_prng_strong_seed(state) \
|
||||||
|
(pg_strong_random((void *) (state), sizeof(pg_prng_state)) ? \
|
||||||
|
pg_prng_seed_check(state) : false)
|
||||||
|
|
||||||
|
extern uint64 pg_prng_uint64(pg_prng_state *state);
|
||||||
|
extern uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax);
|
||||||
|
extern int64 pg_prng_int64(pg_prng_state *state);
|
||||||
|
extern int64 pg_prng_int64p(pg_prng_state *state);
|
||||||
|
extern uint32 pg_prng_uint32(pg_prng_state *state);
|
||||||
|
extern int32 pg_prng_int32(pg_prng_state *state);
|
||||||
|
extern int32 pg_prng_int32p(pg_prng_state *state);
|
||||||
|
extern double pg_prng_double(pg_prng_state *state);
|
||||||
|
extern bool pg_prng_bool(pg_prng_state *state);
|
||||||
|
|
||||||
|
#endif /* PG_PRNG_H */
|
@ -22,6 +22,7 @@
|
|||||||
#ifndef GEQO_H
|
#ifndef GEQO_H
|
||||||
#define GEQO_H
|
#define GEQO_H
|
||||||
|
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "nodes/pathnodes.h"
|
#include "nodes/pathnodes.h"
|
||||||
#include "optimizer/geqo_gene.h"
|
#include "optimizer/geqo_gene.h"
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ extern double Geqo_seed; /* 0 .. 1 */
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
List *initial_rels; /* the base relations we are joining */
|
List *initial_rels; /* the base relations we are joining */
|
||||||
unsigned short random_state[3]; /* state for pg_erand48() */
|
pg_prng_state random_state; /* PRNG state */
|
||||||
} GeqoPrivateData;
|
} GeqoPrivateData;
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,11 +31,10 @@
|
|||||||
|
|
||||||
extern void geqo_set_seed(PlannerInfo *root, double seed);
|
extern void geqo_set_seed(PlannerInfo *root, double seed);
|
||||||
|
|
||||||
/* geqo_rand returns a random float value between 0 and 1 inclusive */
|
/* geqo_rand returns a random float value in the range [0.0, 1.0) */
|
||||||
extern double geqo_rand(PlannerInfo *root);
|
extern double geqo_rand(PlannerInfo *root);
|
||||||
|
|
||||||
/* geqo_randint returns integer value between lower and upper inclusive */
|
/* geqo_randint returns integer value between lower and upper inclusive */
|
||||||
#define geqo_randint(root, upper, lower) \
|
extern int geqo_randint(PlannerInfo *root, int upper, int lower);
|
||||||
( (int) floor( geqo_rand(root)*(((upper)-(lower))+0.999999) ) + (lower) )
|
|
||||||
|
|
||||||
#endif /* GEQO_RANDOM_H */
|
#endif /* GEQO_RANDOM_H */
|
||||||
|
@ -445,9 +445,6 @@
|
|||||||
/* Define to 1 if you have the `pwrite' function. */
|
/* Define to 1 if you have the `pwrite' function. */
|
||||||
#undef HAVE_PWRITE
|
#undef HAVE_PWRITE
|
||||||
|
|
||||||
/* Define to 1 if you have the `random' function. */
|
|
||||||
#undef HAVE_RANDOM
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <readline.h> header file. */
|
/* Define to 1 if you have the <readline.h> header file. */
|
||||||
#undef HAVE_READLINE_H
|
#undef HAVE_READLINE_H
|
||||||
|
|
||||||
@ -512,9 +509,6 @@
|
|||||||
/* Define to 1 if you have spinlocks. */
|
/* Define to 1 if you have spinlocks. */
|
||||||
#undef HAVE_SPINLOCKS
|
#undef HAVE_SPINLOCKS
|
||||||
|
|
||||||
/* Define to 1 if you have the `srandom' function. */
|
|
||||||
#undef HAVE_SRANDOM
|
|
||||||
|
|
||||||
/* Define to 1 if stdbool.h conforms to C99. */
|
/* Define to 1 if stdbool.h conforms to C99. */
|
||||||
#undef HAVE_STDBOOL_H
|
#undef HAVE_STDBOOL_H
|
||||||
|
|
||||||
|
@ -234,17 +234,6 @@
|
|||||||
*/
|
*/
|
||||||
#define DEFAULT_EVENT_SOURCE "PostgreSQL"
|
#define DEFAULT_EVENT_SOURCE "PostgreSQL"
|
||||||
|
|
||||||
/*
|
|
||||||
* The random() function is expected to yield values between 0 and
|
|
||||||
* MAX_RANDOM_VALUE. Currently, all known implementations yield
|
|
||||||
* 0..2^31-1, so we just hardwire this constant. We could do a
|
|
||||||
* configure test if it proves to be necessary. CAUTION: Think not to
|
|
||||||
* replace this with RAND_MAX. RAND_MAX defines the maximum value of
|
|
||||||
* the older rand() function, which is often different from --- and
|
|
||||||
* considerably inferior to --- random().
|
|
||||||
*/
|
|
||||||
#define MAX_RANDOM_VALUE PG_INT32_MAX
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On PPC machines, decide whether to use the mutex hint bit in LWARX
|
* On PPC machines, decide whether to use the mutex hint bit in LWARX
|
||||||
* instructions. Setting the hint bit will slightly improve spinlock
|
* instructions. Setting the hint bit will slightly improve spinlock
|
||||||
|
@ -362,11 +362,6 @@ extern int gettimeofday(struct timeval *tp, struct timezone *tzp);
|
|||||||
#define pgoff_t off_t
|
#define pgoff_t off_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern double pg_erand48(unsigned short xseed[3]);
|
|
||||||
extern long pg_lrand48(void);
|
|
||||||
extern long pg_jrand48(unsigned short xseed[3]);
|
|
||||||
extern void pg_srand48(long seed);
|
|
||||||
|
|
||||||
#ifndef HAVE_FLS
|
#ifndef HAVE_FLS
|
||||||
extern int fls(int mask);
|
extern int fls(int mask);
|
||||||
#endif
|
#endif
|
||||||
@ -452,10 +447,6 @@ extern size_t strlcpy(char *dst, const char *src, size_t siz);
|
|||||||
extern size_t strnlen(const char *str, size_t maxlen);
|
extern size_t strnlen(const char *str, size_t maxlen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(HAVE_RANDOM)
|
|
||||||
extern long random(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_SETENV
|
#ifndef HAVE_SETENV
|
||||||
extern int setenv(const char *name, const char *value, int overwrite);
|
extern int setenv(const char *name, const char *value, int overwrite);
|
||||||
#endif
|
#endif
|
||||||
@ -464,10 +455,6 @@ extern int setenv(const char *name, const char *value, int overwrite);
|
|||||||
extern int unsetenv(const char *name);
|
extern int unsetenv(const char *name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_SRANDOM
|
|
||||||
extern void srandom(unsigned int seed);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_DLOPEN
|
#ifndef HAVE_DLOPEN
|
||||||
extern void *dlopen(const char *file, int mode);
|
extern void *dlopen(const char *file, int mode);
|
||||||
extern void *dlsym(void *handle, const char *symbol);
|
extern void *dlsym(void *handle, const char *symbol);
|
||||||
|
@ -13,15 +13,14 @@
|
|||||||
#ifndef SAMPLING_H
|
#ifndef SAMPLING_H
|
||||||
#define SAMPLING_H
|
#define SAMPLING_H
|
||||||
|
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "storage/block.h" /* for typedef BlockNumber */
|
#include "storage/block.h" /* for typedef BlockNumber */
|
||||||
|
|
||||||
|
|
||||||
/* Random generator for sampling code */
|
/* Random generator for sampling code */
|
||||||
typedef unsigned short SamplerRandomState[3];
|
extern void sampler_random_init_state(uint32 seed,
|
||||||
|
pg_prng_state *randstate);
|
||||||
extern void sampler_random_init_state(long seed,
|
extern double sampler_random_fract(pg_prng_state *randstate);
|
||||||
SamplerRandomState randstate);
|
|
||||||
extern double sampler_random_fract(SamplerRandomState randstate);
|
|
||||||
|
|
||||||
/* Block sampling methods */
|
/* Block sampling methods */
|
||||||
|
|
||||||
@ -32,13 +31,13 @@ typedef struct
|
|||||||
int n; /* desired sample size */
|
int n; /* desired sample size */
|
||||||
BlockNumber t; /* current block number */
|
BlockNumber t; /* current block number */
|
||||||
int m; /* blocks selected so far */
|
int m; /* blocks selected so far */
|
||||||
SamplerRandomState randstate; /* random generator state */
|
pg_prng_state randstate; /* random generator state */
|
||||||
} BlockSamplerData;
|
} BlockSamplerData;
|
||||||
|
|
||||||
typedef BlockSamplerData *BlockSampler;
|
typedef BlockSamplerData *BlockSampler;
|
||||||
|
|
||||||
extern BlockNumber BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
|
extern BlockNumber BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
|
||||||
int samplesize, long randseed);
|
int samplesize, uint32 randseed);
|
||||||
extern bool BlockSampler_HasMore(BlockSampler bs);
|
extern bool BlockSampler_HasMore(BlockSampler bs);
|
||||||
extern BlockNumber BlockSampler_Next(BlockSampler bs);
|
extern BlockNumber BlockSampler_Next(BlockSampler bs);
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ extern BlockNumber BlockSampler_Next(BlockSampler bs);
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
double W;
|
double W;
|
||||||
SamplerRandomState randstate; /* random generator state */
|
pg_prng_state randstate; /* random generator state */
|
||||||
} ReservoirStateData;
|
} ReservoirStateData;
|
||||||
|
|
||||||
typedef ReservoirStateData *ReservoirState;
|
typedef ReservoirStateData *ReservoirState;
|
||||||
|
@ -42,7 +42,6 @@ OBJS = \
|
|||||||
$(PG_CRC32C_OBJS) \
|
$(PG_CRC32C_OBJS) \
|
||||||
bsearch_arg.o \
|
bsearch_arg.o \
|
||||||
chklocale.o \
|
chklocale.o \
|
||||||
erand48.o \
|
|
||||||
inet_net_ntop.o \
|
inet_net_ntop.o \
|
||||||
noblock.o \
|
noblock.o \
|
||||||
path.o \
|
path.o \
|
||||||
|
@ -1,136 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* erand48.c
|
|
||||||
*
|
|
||||||
* This file supplies pg_erand48() and related functions, which except
|
|
||||||
* for the names are just like the POSIX-standard erand48() family.
|
|
||||||
* (We don't supply the full set though, only the ones we have found use
|
|
||||||
* for in Postgres. In particular, we do *not* implement lcong48(), so
|
|
||||||
* that there is no need for the multiplier and addend to be variable.)
|
|
||||||
*
|
|
||||||
* We used to test for an operating system version rather than
|
|
||||||
* unconditionally using our own, but (1) some versions of Cygwin have a
|
|
||||||
* buggy erand48() that always returns zero and (2) as of 2011, glibc's
|
|
||||||
* erand48() is strangely coded to be almost-but-not-quite thread-safe,
|
|
||||||
* which doesn't matter for the backend but is important for pgbench.
|
|
||||||
*
|
|
||||||
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
|
||||||
*
|
|
||||||
* Portions Copyright (c) 1993 Martin Birgmeier
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* You may redistribute unmodified or modified versions of this source
|
|
||||||
* code provided that the above copyright notice and this and the
|
|
||||||
* following conditions are retained.
|
|
||||||
*
|
|
||||||
* This software is provided ``as is'', and comes with no warranties
|
|
||||||
* of any kind. I shall in no event be liable for anything that happens
|
|
||||||
* to anyone/anything when using this software.
|
|
||||||
*
|
|
||||||
* IDENTIFICATION
|
|
||||||
* src/port/erand48.c
|
|
||||||
*
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "c.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
/* These values are specified by POSIX */
|
|
||||||
#define RAND48_MULT UINT64CONST(0x0005deece66d)
|
|
||||||
#define RAND48_ADD UINT64CONST(0x000b)
|
|
||||||
|
|
||||||
/* POSIX specifies 0x330e's use in srand48, but the other bits are arbitrary */
|
|
||||||
#define RAND48_SEED_0 (0x330e)
|
|
||||||
#define RAND48_SEED_1 (0xabcd)
|
|
||||||
#define RAND48_SEED_2 (0x1234)
|
|
||||||
|
|
||||||
static unsigned short _rand48_seed[3] = {
|
|
||||||
RAND48_SEED_0,
|
|
||||||
RAND48_SEED_1,
|
|
||||||
RAND48_SEED_2
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Advance the 48-bit value stored in xseed[] to the next "random" number.
|
|
||||||
*
|
|
||||||
* Also returns the value of that number --- without masking it to 48 bits.
|
|
||||||
* If caller uses the result, it must mask off the bits it wants.
|
|
||||||
*/
|
|
||||||
static uint64
|
|
||||||
_dorand48(unsigned short xseed[3])
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We do the arithmetic in uint64; any type wider than 48 bits would work.
|
|
||||||
*/
|
|
||||||
uint64 in;
|
|
||||||
uint64 out;
|
|
||||||
|
|
||||||
in = (uint64) xseed[2] << 32 | (uint64) xseed[1] << 16 | (uint64) xseed[0];
|
|
||||||
|
|
||||||
out = in * RAND48_MULT + RAND48_ADD;
|
|
||||||
|
|
||||||
xseed[0] = out & 0xFFFF;
|
|
||||||
xseed[1] = (out >> 16) & 0xFFFF;
|
|
||||||
xseed[2] = (out >> 32) & 0xFFFF;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate a random floating-point value using caller-supplied state.
|
|
||||||
* Values are uniformly distributed over the interval [0.0, 1.0).
|
|
||||||
*/
|
|
||||||
double
|
|
||||||
pg_erand48(unsigned short xseed[3])
|
|
||||||
{
|
|
||||||
uint64 x = _dorand48(xseed);
|
|
||||||
|
|
||||||
return ldexp((double) (x & UINT64CONST(0xFFFFFFFFFFFF)), -48);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate a random non-negative integral value using internal state.
|
|
||||||
* Values are uniformly distributed over the interval [0, 2^31).
|
|
||||||
*/
|
|
||||||
long
|
|
||||||
pg_lrand48(void)
|
|
||||||
{
|
|
||||||
uint64 x = _dorand48(_rand48_seed);
|
|
||||||
|
|
||||||
return (x >> 17) & UINT64CONST(0x7FFFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate a random signed integral value using caller-supplied state.
|
|
||||||
* Values are uniformly distributed over the interval [-2^31, 2^31).
|
|
||||||
*/
|
|
||||||
long
|
|
||||||
pg_jrand48(unsigned short xseed[3])
|
|
||||||
{
|
|
||||||
uint64 x = _dorand48(xseed);
|
|
||||||
|
|
||||||
return (int32) ((x >> 16) & UINT64CONST(0xFFFFFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize the internal state using the given seed.
|
|
||||||
*
|
|
||||||
* Per POSIX, this uses only 32 bits from "seed" even if "long" is wider.
|
|
||||||
* Hence, the set of possible seed values is smaller than it could be.
|
|
||||||
* Better practice is to use caller-supplied state and initialize it with
|
|
||||||
* random bits obtained from a high-quality source of random bits.
|
|
||||||
*
|
|
||||||
* Note: POSIX specifies a function seed48() that allows all 48 bits
|
|
||||||
* of the internal state to be set, but we don't currently support that.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pg_srand48(long seed)
|
|
||||||
{
|
|
||||||
_rand48_seed[0] = RAND48_SEED_0;
|
|
||||||
_rand48_seed[1] = (unsigned short) seed;
|
|
||||||
_rand48_seed[2] = (unsigned short) (seed >> 16);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* random.c
|
|
||||||
* random() wrapper
|
|
||||||
*
|
|
||||||
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* IDENTIFICATION
|
|
||||||
* src/port/random.c
|
|
||||||
*
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "c.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
|
|
||||||
long
|
|
||||||
random(void)
|
|
||||||
{
|
|
||||||
return pg_lrand48();
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* srandom.c
|
|
||||||
* srandom() wrapper
|
|
||||||
*
|
|
||||||
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* IDENTIFICATION
|
|
||||||
* src/port/srandom.c
|
|
||||||
*
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "c.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
srandom(unsigned int seed)
|
|
||||||
{
|
|
||||||
pg_srand48((long int) seed);
|
|
||||||
}
|
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "lib/bloomfilter.h"
|
#include "lib/bloomfilter.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
@ -83,9 +84,8 @@ create_and_test_bloom(int power, int64 nelements, int callerseed)
|
|||||||
* Generate random seed, or use caller's. Seed should always be a
|
* Generate random seed, or use caller's. Seed should always be a
|
||||||
* positive value less than or equal to PG_INT32_MAX, to ensure that any
|
* positive value less than or equal to PG_INT32_MAX, to ensure that any
|
||||||
* random seed can be recreated through callerseed if the need arises.
|
* random seed can be recreated through callerseed if the need arises.
|
||||||
* (Don't assume that RAND_MAX cannot exceed PG_INT32_MAX.)
|
|
||||||
*/
|
*/
|
||||||
seed = callerseed < 0 ? random() % PG_INT32_MAX : callerseed;
|
seed = callerseed < 0 ? pg_prng_int32p(&pg_global_prng_state) : callerseed;
|
||||||
|
|
||||||
/* Create Bloom filter, populate it, and report on false positive rate */
|
/* Create Bloom filter, populate it, and report on false positive rate */
|
||||||
filter = bloom_create(nelements, bloom_work_mem, seed);
|
filter = bloom_create(nelements, bloom_work_mem, seed);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "lib/integerset.h"
|
#include "lib/integerset.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
@ -248,8 +249,7 @@ test_pattern(const test_spec *spec)
|
|||||||
* only a small part of the integer space is used. We would very
|
* only a small part of the integer space is used. We would very
|
||||||
* rarely hit values that are actually in the set.
|
* rarely hit values that are actually in the set.
|
||||||
*/
|
*/
|
||||||
x = (pg_lrand48() << 31) | pg_lrand48();
|
x = pg_prng_uint64_range(&pg_global_prng_state, 0, last_int + 1000);
|
||||||
x = x % (last_int + 1000);
|
|
||||||
|
|
||||||
/* Do we expect this value to be present in the set? */
|
/* Do we expect this value to be present in the set? */
|
||||||
if (x >= last_int)
|
if (x >= last_int)
|
||||||
@ -571,7 +571,7 @@ test_huge_distances(void)
|
|||||||
*/
|
*/
|
||||||
while (num_values < 1000)
|
while (num_values < 1000)
|
||||||
{
|
{
|
||||||
val += pg_lrand48();
|
val += pg_prng_uint32(&pg_global_prng_state);
|
||||||
values[num_values++] = val;
|
values[num_values++] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "common/pg_prng.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "lib/rbtree.h"
|
#include "lib/rbtree.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
@ -108,7 +109,7 @@ GetPermutation(int size)
|
|||||||
*/
|
*/
|
||||||
for (i = 1; i < size; i++)
|
for (i = 1; i < size; i++)
|
||||||
{
|
{
|
||||||
int j = random() % (i + 1);
|
int j = pg_prng_uint64_range(&pg_global_prng_state, 0, i);
|
||||||
|
|
||||||
if (j < i) /* avoid fetching undefined data if j=i */
|
if (j < i) /* avoid fetching undefined data if j=i */
|
||||||
permutation[i] = permutation[j];
|
permutation[i] = permutation[j];
|
||||||
@ -320,7 +321,7 @@ testdelete(int size, int delsize)
|
|||||||
|
|
||||||
for (i = 0; i < delsize; i++)
|
for (i = 0; i < delsize; i++)
|
||||||
{
|
{
|
||||||
int k = random() % size;
|
int k = pg_prng_uint64_range(&pg_global_prng_state, 0, size - 1);
|
||||||
|
|
||||||
while (chosen[k])
|
while (chosen[k])
|
||||||
k = (k + 1) % size;
|
k = (k + 1) % size;
|
||||||
|
@ -99,9 +99,9 @@ sub mkvcbuild
|
|||||||
$solution = CreateSolution($vsVersion, $config);
|
$solution = CreateSolution($vsVersion, $config);
|
||||||
|
|
||||||
our @pgportfiles = qw(
|
our @pgportfiles = qw(
|
||||||
chklocale.c explicit_bzero.c fls.c getpeereid.c getrusage.c inet_aton.c random.c
|
chklocale.c explicit_bzero.c fls.c getpeereid.c getrusage.c inet_aton.c
|
||||||
srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
|
getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
|
||||||
erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
|
snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
|
||||||
dirent.c dlopen.c getopt.c getopt_long.c link.c
|
dirent.c dlopen.c getopt.c getopt_long.c link.c
|
||||||
pread.c preadv.c pwrite.c pwritev.c pg_bitutils.c
|
pread.c preadv.c pwrite.c pwritev.c pg_bitutils.c
|
||||||
pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
|
pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
|
||||||
@ -127,9 +127,9 @@ sub mkvcbuild
|
|||||||
config_info.c controldata_utils.c d2s.c encnames.c exec.c
|
config_info.c controldata_utils.c d2s.c encnames.c exec.c
|
||||||
f2s.c file_perm.c file_utils.c hashfn.c ip.c jsonapi.c
|
f2s.c file_perm.c file_utils.c hashfn.c ip.c jsonapi.c
|
||||||
keywords.c kwlookup.c link-canary.c md5_common.c
|
keywords.c kwlookup.c link-canary.c md5_common.c
|
||||||
pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
|
pg_get_line.c pg_lzcompress.c pg_prng.c pgfnames.c psprintf.c relpath.c
|
||||||
saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c
|
rmtree.c saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c
|
||||||
wait_error.c wchar.c);
|
username.c wait_error.c wchar.c);
|
||||||
|
|
||||||
if ($solution->{options}->{openssl})
|
if ($solution->{options}->{openssl})
|
||||||
{
|
{
|
||||||
|
@ -342,7 +342,6 @@ sub GenerateFiles
|
|||||||
HAVE_PTHREAD_IS_THREADED_NP => undef,
|
HAVE_PTHREAD_IS_THREADED_NP => undef,
|
||||||
HAVE_PTHREAD_PRIO_INHERIT => undef,
|
HAVE_PTHREAD_PRIO_INHERIT => undef,
|
||||||
HAVE_PWRITE => undef,
|
HAVE_PWRITE => undef,
|
||||||
HAVE_RANDOM => undef,
|
|
||||||
HAVE_READLINE_H => undef,
|
HAVE_READLINE_H => undef,
|
||||||
HAVE_READLINE_HISTORY_H => undef,
|
HAVE_READLINE_HISTORY_H => undef,
|
||||||
HAVE_READLINE_READLINE_H => undef,
|
HAVE_READLINE_READLINE_H => undef,
|
||||||
@ -363,7 +362,6 @@ sub GenerateFiles
|
|||||||
HAVE_SHM_OPEN => undef,
|
HAVE_SHM_OPEN => undef,
|
||||||
HAVE_SOCKLEN_T => 1,
|
HAVE_SOCKLEN_T => 1,
|
||||||
HAVE_SPINLOCKS => 1,
|
HAVE_SPINLOCKS => 1,
|
||||||
HAVE_SRANDOM => undef,
|
|
||||||
HAVE_STDBOOL_H => 1,
|
HAVE_STDBOOL_H => 1,
|
||||||
HAVE_STDINT_H => 1,
|
HAVE_STDINT_H => 1,
|
||||||
HAVE_STDLIB_H => 1,
|
HAVE_STDLIB_H => 1,
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "common/int128.h"
|
#include "common/int128.h"
|
||||||
|
#include "common/pg_prng.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume the parts of this union are laid out compatibly.
|
* We assume the parts of this union are laid out compatibly.
|
||||||
@ -61,27 +62,11 @@ my_int128_compare(int128 x, int128 y)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get a random uint64 value.
|
|
||||||
* We don't assume random() is good for more than 16 bits.
|
|
||||||
*/
|
|
||||||
static uint64
|
|
||||||
get_random_uint64(void)
|
|
||||||
{
|
|
||||||
uint64 x;
|
|
||||||
|
|
||||||
x = (uint64) (random() & 0xFFFF) << 48;
|
|
||||||
x |= (uint64) (random() & 0xFFFF) << 32;
|
|
||||||
x |= (uint64) (random() & 0xFFFF) << 16;
|
|
||||||
x |= (uint64) (random() & 0xFFFF);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main program.
|
* Main program.
|
||||||
*
|
*
|
||||||
* Generates a lot of random numbers and tests the implementation for each.
|
* Generates a lot of random numbers and tests the implementation for each.
|
||||||
* The results should be reproducible, since we don't call srandom().
|
* The results should be reproducible, since we use a fixed PRNG seed.
|
||||||
*
|
*
|
||||||
* You can give a loop count if you don't like the default 1B iterations.
|
* You can give a loop count if you don't like the default 1B iterations.
|
||||||
*/
|
*/
|
||||||
@ -90,6 +75,8 @@ main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
long count;
|
long count;
|
||||||
|
|
||||||
|
pg_prng_seed(&pg_global_prng_state, 0);
|
||||||
|
|
||||||
if (argc >= 2)
|
if (argc >= 2)
|
||||||
count = strtol(argv[1], NULL, 0);
|
count = strtol(argv[1], NULL, 0);
|
||||||
else
|
else
|
||||||
@ -97,9 +84,9 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
while (count-- > 0)
|
while (count-- > 0)
|
||||||
{
|
{
|
||||||
int64 x = get_random_uint64();
|
int64 x = pg_prng_uint64(&pg_global_prng_state);
|
||||||
int64 y = get_random_uint64();
|
int64 y = pg_prng_uint64(&pg_global_prng_state);
|
||||||
int64 z = get_random_uint64();
|
int64 z = pg_prng_uint64(&pg_global_prng_state);
|
||||||
test128 t1;
|
test128 t1;
|
||||||
test128 t2;
|
test128 t2;
|
||||||
|
|
||||||
@ -151,7 +138,7 @@ main(int argc, char **argv)
|
|||||||
t1.hl.hi = x;
|
t1.hl.hi = x;
|
||||||
t1.hl.lo = y;
|
t1.hl.lo = y;
|
||||||
t2.hl.hi = z;
|
t2.hl.hi = z;
|
||||||
t2.hl.lo = get_random_uint64();
|
t2.hl.lo = pg_prng_uint64(&pg_global_prng_state);
|
||||||
|
|
||||||
if (my_int128_compare(t1.i128, t2.i128) !=
|
if (my_int128_compare(t1.i128, t2.i128) !=
|
||||||
int128_compare(t1.I128, t2.I128))
|
int128_compare(t1.I128, t2.I128))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user