[pgpool-hackers: 4598] Re: Shuffle random functions and use better random numbers

Tatsuo Ishii ishii at postgresql.org
Wed May 28 08:26:49 JST 2025


[Re-send with Cc: to pgpool-hackers]

> Looks like you missed pg_prng.h in your diff.

Oops. pg_prng.h attached.

> No strong objections, but some questions:
> - Why put initialize_prng() inside do_child()? Wouldn't it make sense
>   to put it inside select_load_balancing_node() under a
>   `static int init` guard? That way people might not overlook to
>   initialize it if the prng code is used somewhere else, in another
>   process.
> - I'm not too fond of initializing the entire prng_state with random
>   crap. While it currently only holds two uint64 values that are
>   supposed to be random, it could cause major head scratching if with
>   some update adds a new non-random field to it. If nothing else it
>   just feels like bad practice. I'd suggest to something like
>   uint64 seed;
>   if (!pg_strong_random(&seed, sizeof(seed)))
>     seed = 1; /* Pick a value, as long as it spreads */
>   pg_prng_seed(&pg_global_prng_state, seed);
> - initialize_prng feels overengineered. If strong crypto fails why not
>   fall back to simply a value of 1, or simply crash? The goal is to
>   have an even spread over the backends, not that the distribution
>   follows a different path on each restart.

I will answer them later on.

> 
> For the rest no issues spotted from reading the code, but since
> pg_prng.h is missing I can't compile/run test it.
>
> Martijn van Duren
> 
> On Wed, 2025-05-21 at 15:58 +0900, Tatsuo Ishii wrote:
>> > I have pushed the patch to master branch, with slightly modified
>> > commit message, and credited you as a reviewer.
>> 
>> Attached is the followup commit to import pg_prng.c and use
>> pg_prng_double() for calculating a random number between 0 and 1.0.
>> Actually pg_prng_double() generates a random number [0, 1.0) (1.0 is
>> not inclusive), I think it's ok for our purpose.
>> 
>> [ from the commit message]
>> 
>> Other notes regarding the port:
>> 
>> - pg_prng needs to be initialized using pg_prng_strong_seed() per
>>   process. Currently the only caller is child.c (per session
>>   process). If other process needs to use pg_prng, it needs the same
>>   initialization as child.c.
>> 
>> - Some of functions in the file were not ported because they require
>>   additional library: pg_bitutils.c. In the future we may revisit and
>>   import pg_bitutils.c.
>> 
>> - likely/unlikely are ignored. In the future we may revisit and import
>>   them.
>> 
>> - All conditional compiling regarding "sun" or "_sun" are removed. It
>>   seems the platform is not used for running pgpool anymore.
>> 
>> - Since srandom() is not necessary any more, related code are removed
>>   from pgpool_main.c, child.c and pcp_worker.c.
>> 
>> Best regards,
>> --
>> Tatsuo Ishii
>> SRA OSS K.K.
>> English: http://www.sraoss.co.jp/index_en/
>> Japanese:http://www.sraoss.co.jp
> 
-------------- next part --------------
/*-------------------------------------------------------------------------
 *
 * Pseudo-Random Number Generator
 *
 * Copyright (c) 2021-2025, 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(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 int64 pg_prng_int64_range(pg_prng_state *state, int64 rmin, int64 rmax);
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 double pg_prng_double_normal(pg_prng_state *state);
extern bool pg_prng_bool(pg_prng_state *state);

#endif							/* PG_PRNG_H */


More information about the pgpool-hackers mailing list