|
10 | 10 | #include <time.h> |
11 | 11 | #include <unistd.h> |
12 | 12 |
|
| 13 | +#include "postgres.h" |
13 | 14 | #include "postgres_fe.h" |
14 | 15 | #include "libpq-fe.h" |
15 | 16 | #include "pqexpbuffer.h" |
16 | 17 | #include "portability/instr_time.h" |
17 | 18 |
|
| 19 | +#if PG_MAJORVERSION_NUM >= 15 |
| 20 | +#include "common/pg_prng.h" |
| 21 | +#endif |
| 22 | + |
18 | 23 | #include "cli_root.h" |
19 | 24 | #include "defaults.h" |
20 | 25 | #include "log.h" |
|
24 | 29 | #include "string_utils.h" |
25 | 30 |
|
26 | 31 |
|
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" |
29 | 34 |
|
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" |
34 | 39 |
|
35 | 40 | static char * ConnectionTypeToString(ConnectionType connectionType); |
36 | 41 | static void log_connection_error(PGconn *connection, int logLevel); |
@@ -177,7 +182,11 @@ pgsql_set_retry_policy(ConnectionRetryPolicy *retryPolicy, |
177 | 182 | retryPolicy->baseSleepTime = baseSleepTime; |
178 | 183 |
|
179 | 184 | /* initialize a seed for our random number generator */ |
| 185 | +#if PG_MAJORVERSION_NUM < 15 |
180 | 186 | pg_srand48(time(0)); |
| 187 | +#else |
| 188 | + pg_prng_seed(&(retryPolicy->prng_state), (uint64) (getpid() ^ time(NULL))); |
| 189 | +#endif |
181 | 190 | } |
182 | 191 |
|
183 | 192 |
|
@@ -263,8 +272,28 @@ pgsql_set_monitor_interactive_retry_policy(ConnectionRetryPolicy *retryPolicy) |
263 | 272 | /* |
264 | 273 | * http://c-faq.com/lib/randrange.html |
265 | 274 | */ |
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 | + |
268 | 297 |
|
269 | 298 | /* |
270 | 299 | * pgsql_compute_connection_retry_sleep_time returns how much time to sleep |
@@ -312,9 +341,7 @@ pgsql_compute_connection_retry_sleep_time(ConnectionRetryPolicy *retryPolicy) |
312 | 341 | * time spent, something we care to optimize for even when it means more |
313 | 342 | * work on the monitor side. |
314 | 343 | */ |
315 | | - int previousSleepTime = retryPolicy->sleepTime; |
316 | | - int sleepTime = |
317 | | - random_between(retryPolicy->baseSleepTime, previousSleepTime * 3); |
| 344 | + int sleepTime = pick_random_sleep_time(retryPolicy); |
318 | 345 |
|
319 | 346 | retryPolicy->sleepTime = min(retryPolicy->maxSleepTime, sleepTime); |
320 | 347 |
|
@@ -1070,10 +1097,10 @@ pgsql_execute_with_params(PGSQL *pgsql, const char *sql, int paramCount, |
1070 | 1097 | */ |
1071 | 1098 | if (pgsql->connectionType == PGSQL_CONN_MONITOR && |
1072 | 1099 | 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)) |
1077 | 1104 | { |
1078 | 1105 | log_error("SQL query: %s", sql); |
1079 | 1106 | log_error("SQL params: %s", debugParameters); |
@@ -2073,7 +2100,7 @@ pgsql_create_database(PGSQL *pgsql, const char *dbname, const char *owner) |
2073 | 2100 | */ |
2074 | 2101 | char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE); |
2075 | 2102 |
|
2076 | | - if (strcmp(sqlstate, ERRCODE_DUPLICATE_DATABASE) == 0) |
| 2103 | + if (strcmp(sqlstate, STR_ERRCODE_DUPLICATE_DATABASE) == 0) |
2077 | 2104 | { |
2078 | 2105 | log_info("The database \"%s\" already exists, skipping.", dbname); |
2079 | 2106 | } |
@@ -2270,7 +2297,7 @@ pgsql_create_user(PGSQL *pgsql, const char *userName, const char *password, |
2270 | 2297 | */ |
2271 | 2298 | char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE); |
2272 | 2299 |
|
2273 | | - if (strcmp(sqlstate, ERRCODE_DUPLICATE_OBJECT) == 0) |
| 2300 | + if (strcmp(sqlstate, STR_ERRCODE_DUPLICATE_OBJECT) == 0) |
2274 | 2301 | { |
2275 | 2302 | log_info("The user \"%s\" already exists, skipping.", userName); |
2276 | 2303 | } |
|
0 commit comments