Skip to content

Commit 3804539

Browse files
committed
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
1 parent f44ceb4 commit 3804539

File tree

50 files changed

+544
-481
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+544
-481
lines changed

configure

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16463,32 +16463,6 @@ esac
1646316463

1646416464
fi
1646516465

16466-
ac_fn_c_check_func "$LINENO" "random" "ac_cv_func_random"
16467-
if test "x$ac_cv_func_random" = xyes; then :
16468-
$as_echo "#define HAVE_RANDOM 1" >>confdefs.h
16469-
16470-
else
16471-
case " $LIBOBJS " in
16472-
*" random.$ac_objext "* ) ;;
16473-
*) LIBOBJS="$LIBOBJS random.$ac_objext"
16474-
;;
16475-
esac
16476-
16477-
fi
16478-
16479-
ac_fn_c_check_func "$LINENO" "srandom" "ac_cv_func_srandom"
16480-
if test "x$ac_cv_func_srandom" = xyes; then :
16481-
$as_echo "#define HAVE_SRANDOM 1" >>confdefs.h
16482-
16483-
else
16484-
case " $LIBOBJS " in
16485-
*" srandom.$ac_objext "* ) ;;
16486-
*) LIBOBJS="$LIBOBJS srandom.$ac_objext"
16487-
;;
16488-
esac
16489-
16490-
fi
16491-
1649216466
ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat"
1649316467
if test "x$ac_cv_func_strlcat" = xyes; then :
1649416468
$as_echo "#define HAVE_STRLCAT 1" >>confdefs.h

configure.ac

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,8 +1858,6 @@ AC_REPLACE_FUNCS(m4_normalize([
18581858
mkdtemp
18591859
pread
18601860
pwrite
1861-
random
1862-
srandom
18631861
strlcat
18641862
strlcpy
18651863
strnlen

contrib/amcheck/verify_nbtree.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "catalog/index.h"
3333
#include "catalog/pg_am.h"
3434
#include "commands/tablecmds.h"
35+
#include "common/pg_prng.h"
3536
#include "lib/bloomfilter.h"
3637
#include "miscadmin.h"
3738
#include "storage/lmgr.h"
@@ -466,8 +467,8 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
466467
total_pages = RelationGetNumberOfBlocks(rel);
467468
total_elems = Max(total_pages * (MaxTIDsPerBTreePage / 3),
468469
(int64) state->rel->rd_rel->reltuples);
469-
/* Random seed relies on backend srandom() call to avoid repetition */
470-
seed = random();
470+
/* Generate a random seed to avoid repetition */
471+
seed = pg_prng_uint64(&pg_global_prng_state);
471472
/* Create Bloom filter to fingerprint index */
472473
state->filter = bloom_create(total_elems, maintenance_work_mem, seed);
473474
state->heaptuplespresent = 0;

contrib/auto_explain/auto_explain.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "access/parallel.h"
1818
#include "commands/explain.h"
19+
#include "common/pg_prng.h"
1920
#include "executor/instrument.h"
2021
#include "jit/jit.h"
2122
#include "utils/guc.h"
@@ -275,8 +276,7 @@ explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
275276
if (nesting_level == 0)
276277
{
277278
if (auto_explain_log_min_duration >= 0 && !IsParallelWorker())
278-
current_query_sampled = (random() < auto_explain_sample_rate *
279-
((double) MAX_RANDOM_VALUE + 1));
279+
current_query_sampled = (pg_prng_double(&pg_global_prng_state) < auto_explain_sample_rate);
280280
else
281281
current_query_sampled = false;
282282
}

contrib/file_fdw/file_fdw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1188,7 +1188,7 @@ file_acquire_sample_rows(Relation onerel, int elevel,
11881188
* Found a suitable tuple, so save it, replacing one old tuple
11891189
* at random
11901190
*/
1191-
int k = (int) (targrows * sampler_random_fract(rstate.randstate));
1191+
int k = (int) (targrows * sampler_random_fract(&rstate.randstate));
11921192

11931193
Assert(k >= 0 && k < targrows);
11941194
heap_freetuple(rows[k]);

contrib/postgres_fdw/postgres_fdw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5158,7 +5158,7 @@ analyze_row_processor(PGresult *res, int row, PgFdwAnalyzeState *astate)
51585158
if (astate->rowstoskip <= 0)
51595159
{
51605160
/* Choose a random reservoir element to replace. */
5161-
pos = (int) (targrows * sampler_random_fract(astate->rstate.randstate));
5161+
pos = (int) (targrows * sampler_random_fract(&astate->rstate.randstate));
51625162
Assert(pos >= 0 && pos < targrows);
51635163
heap_freetuple(astate->rows[pos]);
51645164
}

contrib/tablefunc/tablefunc.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
#include "access/htup_details.h"
3838
#include "catalog/pg_type.h"
39+
#include "common/pg_prng.h"
3940
#include "executor/spi.h"
4041
#include "funcapi.h"
4142
#include "lib/stringinfo.h"
@@ -290,8 +291,8 @@ get_normal_pair(float8 *x1, float8 *x2)
290291

291292
do
292293
{
293-
u1 = (float8) random() / (float8) MAX_RANDOM_VALUE;
294-
u2 = (float8) random() / (float8) MAX_RANDOM_VALUE;
294+
u1 = pg_prng_double(&pg_global_prng_state);
295+
u2 = pg_prng_double(&pg_global_prng_state);
295296

296297
v1 = (2.0 * u1) - 1.0;
297298
v2 = (2.0 * u2) - 1.0;

contrib/tsm_system_rows/tsm_system_rows.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ static BlockNumber system_rows_nextsampleblock(SampleScanState *node, BlockNumbe
6969
static OffsetNumber system_rows_nextsampletuple(SampleScanState *node,
7070
BlockNumber blockno,
7171
OffsetNumber maxoffset);
72-
static uint32 random_relative_prime(uint32 n, SamplerRandomState randstate);
72+
static uint32 random_relative_prime(uint32 n, pg_prng_state *randstate);
7373

7474

7575
/*
@@ -213,25 +213,25 @@ system_rows_nextsampleblock(SampleScanState *node, BlockNumber nblocks)
213213
if (sampler->step == 0)
214214
{
215215
/* Initialize now that we have scan descriptor */
216-
SamplerRandomState randstate;
216+
pg_prng_state randstate;
217217

218218
/* If relation is empty, there's nothing to scan */
219219
if (nblocks == 0)
220220
return InvalidBlockNumber;
221221

222222
/* We only need an RNG during this setup step */
223-
sampler_random_init_state(sampler->seed, randstate);
223+
sampler_random_init_state(sampler->seed, &randstate);
224224

225225
/* Compute nblocks/firstblock/step only once per query */
226226
sampler->nblocks = nblocks;
227227

228228
/* Choose random starting block within the relation */
229229
/* (Actually this is the predecessor of the first block visited) */
230-
sampler->firstblock = sampler_random_fract(randstate) *
230+
sampler->firstblock = sampler_random_fract(&randstate) *
231231
sampler->nblocks;
232232

233233
/* Find relative prime as step size for linear probing */
234-
sampler->step = random_relative_prime(sampler->nblocks, randstate);
234+
sampler->step = random_relative_prime(sampler->nblocks, &randstate);
235235
}
236236

237237
/* Reinitialize lb */
@@ -317,7 +317,7 @@ gcd(uint32 a, uint32 b)
317317
* (else return 1).
318318
*/
319319
static uint32
320-
random_relative_prime(uint32 n, SamplerRandomState randstate)
320+
random_relative_prime(uint32 n, pg_prng_state *randstate)
321321
{
322322
uint32 r;
323323

contrib/tsm_system_time/tsm_system_time.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ static BlockNumber system_time_nextsampleblock(SampleScanState *node, BlockNumbe
6969
static OffsetNumber system_time_nextsampletuple(SampleScanState *node,
7070
BlockNumber blockno,
7171
OffsetNumber maxoffset);
72-
static uint32 random_relative_prime(uint32 n, SamplerRandomState randstate);
72+
static uint32 random_relative_prime(uint32 n, pg_prng_state *randstate);
7373

7474

7575
/*
@@ -224,25 +224,25 @@ system_time_nextsampleblock(SampleScanState *node, BlockNumber nblocks)
224224
if (sampler->step == 0)
225225
{
226226
/* Initialize now that we have scan descriptor */
227-
SamplerRandomState randstate;
227+
pg_prng_state randstate;
228228

229229
/* If relation is empty, there's nothing to scan */
230230
if (nblocks == 0)
231231
return InvalidBlockNumber;
232232

233233
/* We only need an RNG during this setup step */
234-
sampler_random_init_state(sampler->seed, randstate);
234+
sampler_random_init_state(sampler->seed, &randstate);
235235

236236
/* Compute nblocks/firstblock/step only once per query */
237237
sampler->nblocks = nblocks;
238238

239239
/* Choose random starting block within the relation */
240240
/* (Actually this is the predecessor of the first block visited) */
241-
sampler->firstblock = sampler_random_fract(randstate) *
241+
sampler->firstblock = sampler_random_fract(&randstate) *
242242
sampler->nblocks;
243243

244244
/* Find relative prime as step size for linear probing */
245-
sampler->step = random_relative_prime(sampler->nblocks, randstate);
245+
sampler->step = random_relative_prime(sampler->nblocks, &randstate);
246246
}
247247

248248
/* Reinitialize lb and start_time */
@@ -330,7 +330,7 @@ gcd(uint32 a, uint32 b)
330330
* (else return 1).
331331
*/
332332
static uint32
333-
random_relative_prime(uint32 n, SamplerRandomState randstate)
333+
random_relative_prime(uint32 n, pg_prng_state *randstate)
334334
{
335335
uint32 r;
336336

src/backend/access/gin/ginget.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "access/gin_private.h"
1818
#include "access/relscan.h"
19+
#include "common/pg_prng.h"
1920
#include "miscadmin.h"
2021
#include "storage/predicate.h"
2122
#include "utils/datum.h"
@@ -787,7 +788,7 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry,
787788
}
788789
}
789790

790-
#define gin_rand() (((double) random()) / ((double) MAX_RANDOM_VALUE))
791+
#define gin_rand() pg_prng_double(&pg_global_prng_state)
791792
#define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) )
792793

793794
/*

src/backend/access/gist/gistutil.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "access/htup_details.h"
2020
#include "access/reloptions.h"
2121
#include "catalog/pg_opclass.h"
22+
#include "common/pg_prng.h"
2223
#include "storage/indexfsm.h"
2324
#include "storage/lmgr.h"
2425
#include "utils/float.h"
@@ -507,7 +508,7 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
507508
if (keep_current_best == -1)
508509
{
509510
/* we didn't make the random choice yet for this old best */
510-
keep_current_best = (random() <= (MAX_RANDOM_VALUE / 2)) ? 1 : 0;
511+
keep_current_best = pg_prng_bool(&pg_global_prng_state) ? 1 : 0;
511512
}
512513
if (keep_current_best == 0)
513514
{
@@ -529,7 +530,7 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
529530
if (keep_current_best == -1)
530531
{
531532
/* we didn't make the random choice yet for this old best */
532-
keep_current_best = (random() <= (MAX_RANDOM_VALUE / 2)) ? 1 : 0;
533+
keep_current_best = pg_prng_bool(&pg_global_prng_state) ? 1 : 0;
533534
}
534535
if (keep_current_best == 1)
535536
break;

src/backend/access/nbtree/nbtinsert.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "access/nbtxlog.h"
2020
#include "access/transam.h"
2121
#include "access/xloginsert.h"
22+
#include "common/pg_prng.h"
2223
#include "lib/qunique.h"
2324
#include "miscadmin.h"
2425
#include "storage/lmgr.h"
@@ -965,7 +966,7 @@ _bt_findinsertloc(Relation rel,
965966

966967
if (P_RIGHTMOST(opaque) ||
967968
_bt_compare(rel, itup_key, page, P_HIKEY) != 0 ||
968-
random() <= (MAX_RANDOM_VALUE / 100))
969+
pg_prng_uint32(&pg_global_prng_state) <= (PG_UINT32_MAX / 100))
969970
break;
970971

971972
_bt_stepright(rel, insertstate, stack);

src/backend/access/spgist/spgdoinsert.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "access/spgist_private.h"
2020
#include "access/spgxlog.h"
2121
#include "access/xloginsert.h"
22+
#include "common/pg_prng.h"
2223
#include "miscadmin.h"
2324
#include "storage/bufmgr.h"
2425
#include "utils/rel.h"
@@ -2210,7 +2211,9 @@ spgdoinsert(Relation index, SpGistState *state,
22102211
if (out.resultType == spgAddNode)
22112212
elog(ERROR, "cannot add a node to an allTheSame inner tuple");
22122213
else if (out.resultType == spgMatchNode)
2213-
out.result.matchNode.nodeN = random() % innerTuple->nNodes;
2214+
out.result.matchNode.nodeN =
2215+
pg_prng_uint64_range(&pg_global_prng_state,
2216+
0, innerTuple->nNodes - 1);
22142217
}
22152218

22162219
switch (out.resultType)

src/backend/access/transam/xact.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "commands/async.h"
3838
#include "commands/tablecmds.h"
3939
#include "commands/trigger.h"
40+
#include "common/pg_prng.h"
4041
#include "executor/spi.h"
4142
#include "libpq/be-fsstubs.h"
4243
#include "libpq/pqsignal.h"
@@ -1990,7 +1991,7 @@ StartTransaction(void)
19901991
/* Determine if statements are logged in this transaction */
19911992
xact_is_sampled = log_xact_sample_rate != 0 &&
19921993
(log_xact_sample_rate == 1 ||
1993-
random() <= log_xact_sample_rate * MAX_RANDOM_VALUE);
1994+
pg_prng_double(&pg_global_prng_state) <= log_xact_sample_rate);
19941995

19951996
/*
19961997
* initialize current transaction state fields

src/backend/commands/analyze.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "commands/progress.h"
3939
#include "commands/tablecmds.h"
4040
#include "commands/vacuum.h"
41+
#include "common/pg_prng.h"
4142
#include "executor/executor.h"
4243
#include "foreign/fdwapi.h"
4344
#include "miscadmin.h"
@@ -1140,7 +1141,7 @@ acquire_sample_rows(Relation onerel, int elevel,
11401141
double liverows = 0; /* # live rows seen */
11411142
double deadrows = 0; /* # dead rows seen */
11421143
double rowstoskip = -1; /* -1 means not set yet */
1143-
long randseed; /* Seed for block sampler(s) */
1144+
uint32 randseed; /* Seed for block sampler(s) */
11441145
BlockNumber totalblocks;
11451146
TransactionId OldestXmin;
11461147
BlockSamplerData bs;
@@ -1162,7 +1163,7 @@ acquire_sample_rows(Relation onerel, int elevel,
11621163
OldestXmin = GetOldestNonRemovableTransactionId(onerel);
11631164

11641165
/* Prepare for sampling block numbers */
1165-
randseed = random();
1166+
randseed = pg_prng_uint32(&pg_global_prng_state);
11661167
nblocks = BlockSampler_Init(&bs, totalblocks, targrows, randseed);
11671168

11681169
#ifdef USE_PREFETCH
@@ -1279,7 +1280,7 @@ acquire_sample_rows(Relation onerel, int elevel,
12791280
* Found a suitable tuple, so save it, replacing one old
12801281
* tuple at random
12811282
*/
1282-
int k = (int) (targrows * sampler_random_fract(rstate.randstate));
1283+
int k = (int) (targrows * sampler_random_fract(&rstate.randstate));
12831284

12841285
Assert(k >= 0 && k < targrows);
12851286
heap_freetuple(rows[k]);

src/backend/executor/nodeSamplescan.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "access/relscan.h"
1818
#include "access/tableam.h"
1919
#include "access/tsmapi.h"
20+
#include "common/pg_prng.h"
2021
#include "executor/executor.h"
2122
#include "executor/nodeSamplescan.h"
2223
#include "miscadmin.h"
@@ -154,7 +155,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
154155
* do this just once, since the seed shouldn't change over rescans.
155156
*/
156157
if (tsc->repeatable == NULL)
157-
scanstate->seed = random();
158+
scanstate->seed = pg_prng_uint32(&pg_global_prng_state);
158159

159160
/*
160161
* Finally, initialize the TABLESAMPLE method handler.

src/backend/lib/bloomfilter.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,7 @@ static inline uint32 mod_m(uint32 a, uint64 m);
8181
* distinct seed value on every call makes it unlikely that the same false
8282
* positives will reoccur when the same set is fingerprinted a second time.
8383
* Callers that don't care about this pass a constant as their seed, typically
84-
* 0. Callers can use a pseudo-random seed in the range of 0 - INT_MAX by
85-
* calling random().
84+
* 0. Callers can also use a pseudo-random seed, eg from pg_prng_uint64().
8685
*/
8786
bloom_filter *
8887
bloom_create(int64 total_elems, int bloom_work_mem, uint64 seed)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy