Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gczu6-0000VX-CN for pgsql-hackers@arkaria.postgresql.org; Fri, 28 Dec 2018 21:42:50 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1gczu4-0001Cy-Ol for pgsql-hackers@arkaria.postgresql.org; Fri, 28 Dec 2018 21:42:48 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gczu4-0001Cr-HC for pgsql-hackers@lists.postgresql.org; Fri, 28 Dec 2018 21:42:48 +0000 Received: from sss.pgh.pa.us ([66.207.139.130]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gcztx-0004Sr-Fp for pgsql-hackers@postgresql.org; Fri, 28 Dec 2018 21:42:48 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.14.4/8.14.4) with ESMTP id wBSLgKAq022402; Fri, 28 Dec 2018 16:42:21 -0500 From: Tom Lane To: Peter Geoghegan cc: Michael Paquier , Alvaro Herrera , Adrien Nayrat , Thomas Munro , Dmitry Dolgov <9erthalion6@gmail.com>, Tomas Vondra , Vik Fearing , Robert Haas , David Rowley , Pg Hackers Subject: Re: random() (was Re: New GUC to sample log queries) In-reply-to: <10518.1545940836@sss.pgh.pa.us> References: <20181129214850.kiq6mvofsgplqjdr@alvherre.pgsql> <3859.1545849900@sss.pgh.pa.us> <20181227013458.GF2106@paquier.xyz> <32696.1545875185@sss.pgh.pa.us> <2820.1545878340@sss.pgh.pa.us> <9585.1545939214@sss.pgh.pa.us> <10518.1545940836@sss.pgh.pa.us> Comments: In-reply-to Tom Lane message dated "Thu, 27 Dec 2018 15:00:36 -0500" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <22348.1546033262.0@sss.pgh.pa.us> Date: Fri, 28 Dec 2018 16:42:20 -0500 Message-ID: <22401.1546033340@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <22348.1546033262.1@sss.pgh.pa.us> I wrote: > On further reflection, it seems likely that in most installations a lot > of processes never invoke drandom()/setseed() at all, making such work > in InitProcessGlobals a waste of cycles. Probably a better idea is to > have drandom() initialize the seed on first use, if it wasn't already > set by setseed(). Here's a proposed patch for that. It occurs to me that there's still another good reason to decouple drandom from everything else: the point of setseed(), if it has any at all, is to allow a repeatable sequence of drandom values to be generated. Without this patch, no such guarantee exists because of the possibility of the backend making additional internal calls of libc random(). regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="decouple-drandom-from-other-random-calls-1.patch"; charset="us-ascii" Content-ID: <22348.1546033262.2@sss.pgh.pa.us> Content-Description: decouple-drandom-from-other-random-calls-1.patch Content-Transfer-Encoding: quoted-printable diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 3786099..1df4356 100644 *** a/doc/src/sgml/func.sgml --- b/doc/src/sgml/func.sgml *************** *** 1136,1146 **** = ! The characteristics of the values returned by ! random() depend ! on the system implementation. It is not suitable for cryptographic ! applications; see module for an alternat= ive. ! = Finally, shows the --- 1136,1150 ---- = ! The random() function uses a simple linear ! congruential algorithm. It is fast but not suitable for cryptographi= c ! applications; see the module for an ! alternative. ! If setseed() is called, the results of ! subsequent random() calls in the current session= are ! repeatable by re-issuing setseed() with the same ! argument. ! = Finally, shows the diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index cf9327f..add099e 100644 *** a/src/backend/utils/adt/float.c --- b/src/backend/utils/adt/float.c *************** *** 22,31 **** --- 22,34 ---- #include "catalog/pg_type.h" #include "common/int.h" #include "libpq/pqformat.h" + #include "miscadmin.h" #include "utils/array.h" + #include "utils/backend_random.h" #include "utils/float.h" #include "utils/fmgrprotos.h" #include "utils/sortsupport.h" + #include "utils/timestamp.h" = = /* Configurable GUC parameter */ *************** float8 degree_c_sixty =3D 60.0; *** 53,58 **** --- 56,65 ---- float8 degree_c_one_half =3D 0.5; float8 degree_c_one =3D 1.0; = + /* State for drandom() and setseed() */ + static bool drandom_seed_set =3D false; + static unsigned short drandom_seed[3] =3D {0, 0, 0}; + = /* Local function prototypes */ static double sind_q1(double x); static double cosd_q1(double x); *************** drandom(PG_FUNCTION_ARGS) *** 2378,2385 **** { float8 result; = ! /* result [0.0 - 1.0) */ ! result =3D (double) random() / ((double) MAX_RANDOM_VALUE + 1); = PG_RETURN_FLOAT8(result); } --- 2385,2414 ---- { float8 result; = ! /* Initialize random seed, if not done yet in this process */ ! if (unlikely(!drandom_seed_set)) ! { ! /* ! * If possible, initialize the seed using high-quality random bits. ! * Should that fail for some reason, we fall back on a lower-quality ! * seed based on current time and PID. ! */ ! if (!pg_backend_random((char *) drandom_seed, sizeof(drandom_seed))) ! { ! TimestampTz now =3D GetCurrentTimestamp(); ! uint64 iseed; ! = ! /* Mix the PID with the most predictable bits of the timestamp */ ! iseed =3D (uint64) now ^ ((uint64) MyProcPid << 32); ! drandom_seed[0] =3D (unsigned short) iseed; ! drandom_seed[1] =3D (unsigned short) (iseed >> 16); ! drandom_seed[2] =3D (unsigned short) (iseed >> 32); ! } ! drandom_seed_set =3D true; ! } ! = ! /* pg_erand48 produces desired result range [0.0 - 1.0) */ ! result =3D pg_erand48(drandom_seed); = PG_RETURN_FLOAT8(result); } *************** Datum *** 2392,2404 **** setseed(PG_FUNCTION_ARGS) { float8 seed =3D PG_GETARG_FLOAT8(0); ! int iseed; = ! if (seed < -1 || seed > 1) ! elog(ERROR, "setseed parameter %f out of range [-1,1]", seed); = ! iseed =3D (int) (seed * MAX_RANDOM_VALUE); ! srandom((unsigned int) iseed); = PG_RETURN_VOID(); } --- 2421,2440 ---- setseed(PG_FUNCTION_ARGS) { float8 seed =3D PG_GETARG_FLOAT8(0); ! uint64 iseed; = ! if (seed < -1 || seed > 1 || isnan(seed)) ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("setseed parameter %g is out of allowed range [-1,1]", ! seed))); = ! /* Use sign bit + 47 fractional bits to fill drandom_seed[] */ ! iseed =3D (int64) (seed * (float8) UINT64CONST(0x7FFFFFFFFFFF)); ! drandom_seed[0] =3D (unsigned short) iseed; ! drandom_seed[1] =3D (unsigned short) (iseed >> 16); ! drandom_seed[2] =3D (unsigned short) (iseed >> 32); ! drandom_seed_set =3D true; = PG_RETURN_VOID(); } ------- =_aaaaaaaaaa0--