Skip to content

Commit 2d64147

Browse files
authored
Fix compat with Postgres 15devel again. (#842)
A recent patch in Postgres source code replaces the random() API that is embedded in libpq client-side (and also in the backend, but we're good on that front). See https://git.postgresql.org/cgit/postgresql.git/commit/?id=3804539e48e794781c6145c7f988f5d507418fa8 for details.
1 parent e7edc49 commit 2d64147

3 files changed

Lines changed: 71 additions & 17 deletions

File tree

src/bin/pg_autoctl/demoapp.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
#include <time.h>
1717
#include <unistd.h>
1818

19+
#include "postgres.h"
20+
21+
#if PG_MAJORVERSION_NUM >= 15
22+
#include "common/pg_prng.h"
23+
#endif
24+
1925
#include "cli_do_demoapp.h"
2026
#include "defaults.h"
2127
#include "demoapp.h"
@@ -530,8 +536,13 @@ demoapp_update_client_failovers(const char *pguri, int clientId, int failovers)
530536
/*
531537
* http://c-faq.com/lib/randrange.html
532538
*/
539+
#if PG_MAJORVERSION_NUM < 15
533540
#define random_between(M, N) \
534541
((M) + pg_lrand48() / (RAND_MAX / ((N) -(M) +1) + 1))
542+
#else
543+
#define random_between(M, N) \
544+
((M) + pg_prng_uint32(&prng_state) / (RAND_MAX / ((N) -(M) +1) + 1))
545+
#endif
535546

536547
/*
537548
* demo_start_client starts a sub-process that implements our demo application:
@@ -558,7 +569,14 @@ demoapp_start_client(const char *pguri, int clientId,
558569
int retrySleepTime = 500; /* first retry happens after 500 ms */
559570

560571
/* initialize a seed for our random number generator */
572+
573+
#if PG_MAJORVERSION_NUM < 15
561574
pg_srand48(((unsigned int) (getpid() ^ time(NULL))));
575+
#else
576+
pg_prng_state prng_state;
577+
578+
pg_prng_seed(&prng_state, (uint64) (getpid() ^ time(NULL)));
579+
#endif
562580

563581
/* pick a random retry policy for this client */
564582
retryCap = random_between(50, 500);

src/bin/pg_autoctl/pgsql.c

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@
1010
#include <time.h>
1111
#include <unistd.h>
1212

13+
#include "postgres.h"
1314
#include "postgres_fe.h"
1415
#include "libpq-fe.h"
1516
#include "pqexpbuffer.h"
1617
#include "portability/instr_time.h"
1718

19+
#if PG_MAJORVERSION_NUM >= 15
20+
#include "common/pg_prng.h"
21+
#endif
22+
1823
#include "cli_root.h"
1924
#include "defaults.h"
2025
#include "log.h"
@@ -24,13 +29,13 @@
2429
#include "string_utils.h"
2530

2631

27-
#define ERRCODE_DUPLICATE_OBJECT "42710"
28-
#define ERRCODE_DUPLICATE_DATABASE "42P04"
32+
#define STR_ERRCODE_DUPLICATE_OBJECT "42710"
33+
#define STR_ERRCODE_DUPLICATE_DATABASE "42P04"
2934

30-
#define ERRCODE_INVALID_OBJECT_DEFINITION "42P17"
31-
#define ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE "55000"
32-
#define ERRCODE_OBJECT_IN_USE "55006"
33-
#define ERRCODE_UNDEFINED_OBJECT "42704"
35+
#define STR_ERRCODE_INVALID_OBJECT_DEFINITION "42P17"
36+
#define STR_ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE "55000"
37+
#define STR_ERRCODE_OBJECT_IN_USE "55006"
38+
#define STR_ERRCODE_UNDEFINED_OBJECT "42704"
3439

3540
static char * ConnectionTypeToString(ConnectionType connectionType);
3641
static void log_connection_error(PGconn *connection, int logLevel);
@@ -177,7 +182,11 @@ pgsql_set_retry_policy(ConnectionRetryPolicy *retryPolicy,
177182
retryPolicy->baseSleepTime = baseSleepTime;
178183

179184
/* initialize a seed for our random number generator */
185+
#if PG_MAJORVERSION_NUM < 15
180186
pg_srand48(time(0));
187+
#else
188+
pg_prng_seed(&(retryPolicy->prng_state), (uint64) (getpid() ^ time(NULL)));
189+
#endif
181190
}
182191

183192

@@ -263,8 +272,28 @@ pgsql_set_monitor_interactive_retry_policy(ConnectionRetryPolicy *retryPolicy)
263272
/*
264273
* http://c-faq.com/lib/randrange.html
265274
*/
266-
#define random_between(M, N) \
267-
((M) + pg_lrand48() / (RAND_MAX / ((N) -(M) +1) + 1))
275+
#define random_between(R, M, N) ((M) + R / (RAND_MAX / ((N) -(M) +1) + 1))
276+
277+
/*
278+
* pick_random_sleep_time picks a random sleep time between the given policy
279+
* base sleep time and 3 times the previous sleep time. See below in
280+
* pgsql_compute_connection_retry_sleep_time for a deep dive into why we are
281+
* interested in this computation.
282+
*/
283+
static int
284+
pick_random_sleep_time(ConnectionRetryPolicy *retryPolicy)
285+
{
286+
#if PG_MAJORVERSION_NUM < 15
287+
long random = pg_lrand48();
288+
#else
289+
uint32_t random = pg_prng_uint32(&(retryPolicy->prng_state));
290+
#endif
291+
292+
return random_between(random,
293+
retryPolicy->baseSleepTime,
294+
retryPolicy->sleepTime * 3);
295+
}
296+
268297

269298
/*
270299
* pgsql_compute_connection_retry_sleep_time returns how much time to sleep
@@ -312,9 +341,7 @@ pgsql_compute_connection_retry_sleep_time(ConnectionRetryPolicy *retryPolicy)
312341
* time spent, something we care to optimize for even when it means more
313342
* work on the monitor side.
314343
*/
315-
int previousSleepTime = retryPolicy->sleepTime;
316-
int sleepTime =
317-
random_between(retryPolicy->baseSleepTime, previousSleepTime * 3);
344+
int sleepTime = pick_random_sleep_time(retryPolicy);
318345

319346
retryPolicy->sleepTime = min(retryPolicy->maxSleepTime, sleepTime);
320347

@@ -1070,10 +1097,10 @@ pgsql_execute_with_params(PGSQL *pgsql, const char *sql, int paramCount,
10701097
*/
10711098
if (pgsql->connectionType == PGSQL_CONN_MONITOR &&
10721099
sqlstate != NULL &&
1073-
!(strcmp(sqlstate, ERRCODE_INVALID_OBJECT_DEFINITION) == 0 ||
1074-
strcmp(sqlstate, ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE) == 0 ||
1075-
strcmp(sqlstate, ERRCODE_OBJECT_IN_USE) == 0 ||
1076-
strcmp(sqlstate, ERRCODE_UNDEFINED_OBJECT) == 0))
1100+
!(strcmp(sqlstate, STR_ERRCODE_INVALID_OBJECT_DEFINITION) == 0 ||
1101+
strcmp(sqlstate, STR_ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE) == 0 ||
1102+
strcmp(sqlstate, STR_ERRCODE_OBJECT_IN_USE) == 0 ||
1103+
strcmp(sqlstate, STR_ERRCODE_UNDEFINED_OBJECT) == 0))
10771104
{
10781105
log_error("SQL query: %s", sql);
10791106
log_error("SQL params: %s", debugParameters);
@@ -2073,7 +2100,7 @@ pgsql_create_database(PGSQL *pgsql, const char *dbname, const char *owner)
20732100
*/
20742101
char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
20752102

2076-
if (strcmp(sqlstate, ERRCODE_DUPLICATE_DATABASE) == 0)
2103+
if (strcmp(sqlstate, STR_ERRCODE_DUPLICATE_DATABASE) == 0)
20772104
{
20782105
log_info("The database \"%s\" already exists, skipping.", dbname);
20792106
}
@@ -2270,7 +2297,7 @@ pgsql_create_user(PGSQL *pgsql, const char *userName, const char *password,
22702297
*/
22712298
char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
22722299

2273-
if (strcmp(sqlstate, ERRCODE_DUPLICATE_OBJECT) == 0)
2300+
if (strcmp(sqlstate, STR_ERRCODE_DUPLICATE_OBJECT) == 0)
22742301
{
22752302
log_info("The user \"%s\" already exists, skipping.", userName);
22762303
}

src/bin/pg_autoctl/pgsql.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@
1414
#include <limits.h>
1515
#include <stdbool.h>
1616

17+
#include "postgres.h"
1718
#include "libpq-fe.h"
1819
#include "portability/instr_time.h"
1920

21+
#if PG_MAJORVERSION_NUM >= 15
22+
#include "common/pg_prng.h"
23+
#endif
24+
2025
#include "defaults.h"
2126
#include "pgsetup.h"
2227
#include "state.h"
@@ -92,6 +97,10 @@ typedef struct ConnectionRetryPolicy
9297
instr_time startTime; /* time of the first attempt */
9398
instr_time connectTime; /* time of successful connection */
9499
int attempts; /* how many attempts have been made so far */
100+
101+
#if PG_MAJORVERSION_NUM >= 15
102+
pg_prng_state prng_state;
103+
#endif
95104
} ConnectionRetryPolicy;
96105

97106
/*

0 commit comments

Comments
 (0)