Line data Source code
1 : /*
2 : * pgbench.c
3 : *
4 : * A simple benchmark program for PostgreSQL
5 : * Originally written by Tatsuo Ishii and enhanced by many contributors.
6 : *
7 : * src/bin/pgbench/pgbench.c
8 : * Copyright (c) 2000-2023, PostgreSQL Global Development Group
9 : * ALL RIGHTS RESERVED;
10 : *
11 : * Permission to use, copy, modify, and distribute this software and its
12 : * documentation for any purpose, without fee, and without a written agreement
13 : * is hereby granted, provided that the above copyright notice and this
14 : * paragraph and the following two paragraphs appear in all copies.
15 : *
16 : * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
17 : * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
18 : * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
19 : * DOCUMENTATION, EVEN IF THE AUTHOR OR DISTRIBUTORS HAVE BEEN ADVISED OF THE
20 : * POSSIBILITY OF SUCH DAMAGE.
21 : *
22 : * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIMS ANY WARRANTIES,
23 : * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24 : * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
25 : * ON AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAS NO OBLIGATIONS TO
26 : * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27 : *
28 : */
29 :
30 : #if defined(WIN32) && FD_SETSIZE < 1024
31 : #error FD_SETSIZE needs to have been increased
32 : #endif
33 :
34 : #include "postgres_fe.h"
35 :
36 : #include <ctype.h>
37 : #include <float.h>
38 : #include <limits.h>
39 : #include <math.h>
40 : #include <signal.h>
41 : #include <time.h>
42 : #include <sys/time.h>
43 : #include <sys/resource.h> /* for getrlimit */
44 :
45 : /* For testing, PGBENCH_USE_SELECT can be defined to force use of that code */
46 : #if defined(HAVE_PPOLL) && !defined(PGBENCH_USE_SELECT)
47 : #define POLL_USING_PPOLL
48 : #ifdef HAVE_POLL_H
49 : #include <poll.h>
50 : #endif
51 : #else /* no ppoll(), so use select() */
52 : #define POLL_USING_SELECT
53 : #include <sys/select.h>
54 : #endif
55 :
56 : #include "common/int.h"
57 : #include "common/logging.h"
58 : #include "common/pg_prng.h"
59 : #include "common/string.h"
60 : #include "common/username.h"
61 : #include "fe_utils/cancel.h"
62 : #include "fe_utils/conditional.h"
63 : #include "fe_utils/option_utils.h"
64 : #include "fe_utils/string_utils.h"
65 : #include "getopt_long.h"
66 : #include "libpq-fe.h"
67 : #include "pgbench.h"
68 : #include "port/pg_bitutils.h"
69 : #include "portability/instr_time.h"
70 :
71 : /* X/Open (XSI) requires <math.h> to provide M_PI, but core POSIX does not */
72 : #ifndef M_PI
73 : #define M_PI 3.14159265358979323846
74 : #endif
75 :
76 : #define ERRCODE_T_R_SERIALIZATION_FAILURE "40001"
77 : #define ERRCODE_T_R_DEADLOCK_DETECTED "40P01"
78 : #define ERRCODE_UNDEFINED_TABLE "42P01"
79 :
80 : /*
81 : * Hashing constants
82 : */
83 : #define FNV_PRIME UINT64CONST(0x100000001b3)
84 : #define FNV_OFFSET_BASIS UINT64CONST(0xcbf29ce484222325)
85 : #define MM2_MUL UINT64CONST(0xc6a4a7935bd1e995)
86 : #define MM2_MUL_TIMES_8 UINT64CONST(0x35253c9ade8f4ca8)
87 : #define MM2_ROT 47
88 :
89 : /*
90 : * Multi-platform socket set implementations
91 : */
92 :
93 : #ifdef POLL_USING_PPOLL
94 : #define SOCKET_WAIT_METHOD "ppoll"
95 :
96 : typedef struct socket_set
97 : {
98 : int maxfds; /* allocated length of pollfds[] array */
99 : int curfds; /* number currently in use */
100 : struct pollfd pollfds[FLEXIBLE_ARRAY_MEMBER];
101 : } socket_set;
102 :
103 : #endif /* POLL_USING_PPOLL */
104 :
105 : #ifdef POLL_USING_SELECT
106 : #define SOCKET_WAIT_METHOD "select"
107 :
108 : typedef struct socket_set
109 : {
110 : int maxfd; /* largest FD currently set in fds */
111 : fd_set fds;
112 : } socket_set;
113 :
114 : #endif /* POLL_USING_SELECT */
115 :
116 : /*
117 : * Multi-platform thread implementations
118 : */
119 :
120 : #ifdef WIN32
121 : /* Use Windows threads */
122 : #include <windows.h>
123 : #define GETERRNO() (_dosmaperr(GetLastError()), errno)
124 : #define THREAD_T HANDLE
125 : #define THREAD_FUNC_RETURN_TYPE unsigned
126 : #define THREAD_FUNC_RETURN return 0
127 : #define THREAD_FUNC_CC __stdcall
128 : #define THREAD_CREATE(handle, function, arg) \
129 : ((*(handle) = (HANDLE) _beginthreadex(NULL, 0, (function), (arg), 0, NULL)) == 0 ? errno : 0)
130 : #define THREAD_JOIN(handle) \
131 : (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0 ? \
132 : GETERRNO() : CloseHandle(handle) ? 0 : GETERRNO())
133 : #define THREAD_BARRIER_T SYNCHRONIZATION_BARRIER
134 : #define THREAD_BARRIER_INIT(barrier, n) \
135 : (InitializeSynchronizationBarrier((barrier), (n), 0) ? 0 : GETERRNO())
136 : #define THREAD_BARRIER_WAIT(barrier) \
137 : EnterSynchronizationBarrier((barrier), \
138 : SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY)
139 : #define THREAD_BARRIER_DESTROY(barrier)
140 : #elif defined(ENABLE_THREAD_SAFETY)
141 : /* Use POSIX threads */
142 : #include "port/pg_pthread.h"
143 : #define THREAD_T pthread_t
144 : #define THREAD_FUNC_RETURN_TYPE void *
145 : #define THREAD_FUNC_RETURN return NULL
146 : #define THREAD_FUNC_CC
147 : #define THREAD_CREATE(handle, function, arg) \
148 : pthread_create((handle), NULL, (function), (arg))
149 : #define THREAD_JOIN(handle) \
150 : pthread_join((handle), NULL)
151 : #define THREAD_BARRIER_T pthread_barrier_t
152 : #define THREAD_BARRIER_INIT(barrier, n) \
153 : pthread_barrier_init((barrier), NULL, (n))
154 : #define THREAD_BARRIER_WAIT(barrier) pthread_barrier_wait((barrier))
155 : #define THREAD_BARRIER_DESTROY(barrier) pthread_barrier_destroy((barrier))
156 : #else
157 : /* No threads implementation, use none (-j 1) */
158 : #define THREAD_T void *
159 : #define THREAD_FUNC_RETURN_TYPE void *
160 : #define THREAD_FUNC_RETURN return NULL
161 : #define THREAD_FUNC_CC
162 : #define THREAD_BARRIER_T int
163 : #define THREAD_BARRIER_INIT(barrier, n) (*(barrier) = 0)
164 : #define THREAD_BARRIER_WAIT(barrier)
165 : #define THREAD_BARRIER_DESTROY(barrier)
166 : #endif
167 :
168 :
169 : /********************************************************************
170 : * some configurable parameters */
171 :
172 : #define DEFAULT_INIT_STEPS "dtgvp" /* default -I setting */
173 : #define ALL_INIT_STEPS "dtgGvpf" /* all possible steps */
174 :
175 : #define LOG_STEP_SECONDS 5 /* seconds between log messages */
176 : #define DEFAULT_NXACTS 10 /* default nxacts */
177 :
178 : #define MIN_GAUSSIAN_PARAM 2.0 /* minimum parameter for gauss */
179 :
180 : #define MIN_ZIPFIAN_PARAM 1.001 /* minimum parameter for zipfian */
181 : #define MAX_ZIPFIAN_PARAM 1000.0 /* maximum parameter for zipfian */
182 :
183 : int nxacts = 0; /* number of transactions per client */
184 : int duration = 0; /* duration in seconds */
185 : int64 end_time = 0; /* when to stop in micro seconds, under -T */
186 :
187 : /*
188 : * scaling factor. for example, scale = 10 will make 1000000 tuples in
189 : * pgbench_accounts table.
190 : */
191 : int scale = 1;
192 :
193 : /*
194 : * fillfactor. for example, fillfactor = 90 will use only 90 percent
195 : * space during inserts and leave 10 percent free.
196 : */
197 : int fillfactor = 100;
198 :
199 : /*
200 : * use unlogged tables?
201 : */
202 : bool unlogged_tables = false;
203 :
204 : /*
205 : * log sampling rate (1.0 = log everything, 0.0 = option not given)
206 : */
207 : double sample_rate = 0.0;
208 :
209 : /*
210 : * When threads are throttled to a given rate limit, this is the target delay
211 : * to reach that rate in usec. 0 is the default and means no throttling.
212 : */
213 : double throttle_delay = 0;
214 :
215 : /*
216 : * Transactions which take longer than this limit (in usec) are counted as
217 : * late, and reported as such, although they are completed anyway. When
218 : * throttling is enabled, execution time slots that are more than this late
219 : * are skipped altogether, and counted separately.
220 : */
221 : int64 latency_limit = 0;
222 :
223 : /*
224 : * tablespace selection
225 : */
226 : char *tablespace = NULL;
227 : char *index_tablespace = NULL;
228 :
229 : /*
230 : * Number of "pgbench_accounts" partitions. 0 is the default and means no
231 : * partitioning.
232 : */
233 : static int partitions = 0;
234 :
235 : /* partitioning strategy for "pgbench_accounts" */
236 : typedef enum
237 : {
238 : PART_NONE, /* no partitioning */
239 : PART_RANGE, /* range partitioning */
240 : PART_HASH /* hash partitioning */
241 : } partition_method_t;
242 :
243 : static partition_method_t partition_method = PART_NONE;
244 : static const char *PARTITION_METHOD[] = {"none", "range", "hash"};
245 :
246 : /* random seed used to initialize base_random_sequence */
247 : int64 random_seed = -1;
248 :
249 : /*
250 : * end of configurable parameters
251 : *********************************************************************/
252 :
253 : #define nbranches 1 /* Makes little sense to change this. Change
254 : * -s instead */
255 : #define ntellers 10
256 : #define naccounts 100000
257 :
258 : /*
259 : * The scale factor at/beyond which 32bit integers are incapable of storing
260 : * 64bit values.
261 : *
262 : * Although the actual threshold is 21474, we use 20000 because it is easier to
263 : * document and remember, and isn't that far away from the real threshold.
264 : */
265 : #define SCALE_32BIT_THRESHOLD 20000
266 :
267 : bool use_log; /* log transaction latencies to a file */
268 : bool use_quiet; /* quiet logging onto stderr */
269 : int agg_interval; /* log aggregates instead of individual
270 : * transactions */
271 : bool per_script_stats = false; /* whether to collect stats per script */
272 : int progress = 0; /* thread progress report every this seconds */
273 : bool progress_timestamp = false; /* progress report with Unix time */
274 : int nclients = 1; /* number of clients */
275 : int nthreads = 1; /* number of threads */
276 : bool is_connect; /* establish connection for each transaction */
277 : bool report_per_command = false; /* report per-command latencies,
278 : * retries after errors and failures
279 : * (errors without retrying) */
280 : int main_pid; /* main process id used in log filename */
281 :
282 : /*
283 : * There are different types of restrictions for deciding that the current
284 : * transaction with a serialization/deadlock error can no longer be retried and
285 : * should be reported as failed:
286 : * - max_tries (--max-tries) can be used to limit the number of tries;
287 : * - latency_limit (-L) can be used to limit the total time of tries;
288 : * - duration (-T) can be used to limit the total benchmark time.
289 : *
290 : * They can be combined together, and you need to use at least one of them to
291 : * retry the transactions with serialization/deadlock errors. If none of them is
292 : * used, the default value of max_tries is 1 and such transactions will not be
293 : * retried.
294 : */
295 :
296 : /*
297 : * We cannot retry a transaction after the serialization/deadlock error if its
298 : * number of tries reaches this maximum; if its value is zero, it is not used.
299 : */
300 : uint32 max_tries = 1;
301 :
302 : bool failures_detailed = false; /* whether to group failures in
303 : * reports or logs by basic types */
304 :
305 : const char *pghost = NULL;
306 : const char *pgport = NULL;
307 : const char *username = NULL;
308 : const char *dbName = NULL;
309 : char *logfile_prefix = NULL;
310 : const char *progname;
311 :
312 : #define WSEP '@' /* weight separator */
313 :
314 : volatile sig_atomic_t timer_exceeded = false; /* flag from signal handler */
315 :
316 : /*
317 : * We don't want to allocate variables one by one; for efficiency, add a
318 : * constant margin each time it overflows.
319 : */
320 : #define VARIABLES_ALLOC_MARGIN 8
321 :
322 : /*
323 : * Variable definitions.
324 : *
325 : * If a variable only has a string value, "svalue" is that value, and value is
326 : * "not set". If the value is known, "value" contains the value (in any
327 : * variant).
328 : *
329 : * In this case "svalue" contains the string equivalent of the value, if we've
330 : * had occasion to compute that, or NULL if we haven't.
331 : */
332 : typedef struct
333 : {
334 : char *name; /* variable's name */
335 : char *svalue; /* its value in string form, if known */
336 : PgBenchValue value; /* actual variable's value */
337 : } Variable;
338 :
339 : /*
340 : * Data structure for client variables.
341 : */
342 : typedef struct
343 : {
344 : Variable *vars; /* array of variable definitions */
345 : int nvars; /* number of variables */
346 :
347 : /*
348 : * The maximum number of variables that we can currently store in 'vars'
349 : * without having to reallocate more space. We must always have max_vars
350 : * >= nvars.
351 : */
352 : int max_vars;
353 :
354 : bool vars_sorted; /* are variables sorted by name? */
355 : } Variables;
356 :
357 : #define MAX_SCRIPTS 128 /* max number of SQL scripts allowed */
358 : #define SHELL_COMMAND_SIZE 256 /* maximum size allowed for shell command */
359 :
360 : /*
361 : * Simple data structure to keep stats about something.
362 : *
363 : * XXX probably the first value should be kept and used as an offset for
364 : * better numerical stability...
365 : */
366 : typedef struct SimpleStats
367 : {
368 : int64 count; /* how many values were encountered */
369 : double min; /* the minimum seen */
370 : double max; /* the maximum seen */
371 : double sum; /* sum of values */
372 : double sum2; /* sum of squared values */
373 : } SimpleStats;
374 :
375 : /*
376 : * The instr_time type is expensive when dealing with time arithmetic. Define
377 : * a type to hold microseconds instead. Type int64 is good enough for about
378 : * 584500 years.
379 : */
380 : typedef int64 pg_time_usec_t;
381 :
382 : /*
383 : * Data structure to hold various statistics: per-thread and per-script stats
384 : * are maintained and merged together.
385 : */
386 : typedef struct StatsData
387 : {
388 : pg_time_usec_t start_time; /* interval start time, for aggregates */
389 :
390 : /*----------
391 : * Transactions are counted depending on their execution and outcome.
392 : * First a transaction may have started or not: skipped transactions occur
393 : * under --rate and --latency-limit when the client is too late to execute
394 : * them. Secondly, a started transaction may ultimately succeed or fail,
395 : * possibly after some retries when --max-tries is not one. Thus
396 : *
397 : * the number of all transactions =
398 : * 'skipped' (it was too late to execute them) +
399 : * 'cnt' (the number of successful transactions) +
400 : * 'failed' (the number of failed transactions).
401 : *
402 : * A successful transaction can have several unsuccessful tries before a
403 : * successful run. Thus
404 : *
405 : * 'cnt' (the number of successful transactions) =
406 : * successfully retried transactions (they got a serialization or a
407 : * deadlock error(s), but were
408 : * successfully retried from the very
409 : * beginning) +
410 : * directly successful transactions (they were successfully completed on
411 : * the first try).
412 : *
413 : * A failed transaction is defined as unsuccessfully retried transactions.
414 : * It can be one of two types:
415 : *
416 : * failed (the number of failed transactions) =
417 : * 'serialization_failures' (they got a serialization error and were not
418 : * successfully retried) +
419 : * 'deadlock_failures' (they got a deadlock error and were not
420 : * successfully retried).
421 : *
422 : * If the transaction was retried after a serialization or a deadlock
423 : * error this does not guarantee that this retry was successful. Thus
424 : *
425 : * 'retries' (number of retries) =
426 : * number of retries in all retried transactions =
427 : * number of retries in (successfully retried transactions +
428 : * failed transactions);
429 : *
430 : * 'retried' (number of all retried transactions) =
431 : * successfully retried transactions +
432 : * failed transactions.
433 : *----------
434 : */
435 : int64 cnt; /* number of successful transactions, not
436 : * including 'skipped' */
437 : int64 skipped; /* number of transactions skipped under --rate
438 : * and --latency-limit */
439 : int64 retries; /* number of retries after a serialization or
440 : * a deadlock error in all the transactions */
441 : int64 retried; /* number of all transactions that were
442 : * retried after a serialization or a deadlock
443 : * error (perhaps the last try was
444 : * unsuccessful) */
445 : int64 serialization_failures; /* number of transactions that were
446 : * not successfully retried after a
447 : * serialization error */
448 : int64 deadlock_failures; /* number of transactions that were not
449 : * successfully retried after a deadlock
450 : * error */
451 : SimpleStats latency;
452 : SimpleStats lag;
453 : } StatsData;
454 :
455 : /*
456 : * For displaying Unix epoch timestamps, as some time functions may have
457 : * another reference.
458 : */
459 : pg_time_usec_t epoch_shift;
460 :
461 : /*
462 : * Error status for errors during script execution.
463 : */
464 : typedef enum EStatus
465 : {
466 : ESTATUS_NO_ERROR = 0,
467 : ESTATUS_META_COMMAND_ERROR,
468 :
469 : /* SQL errors */
470 : ESTATUS_SERIALIZATION_ERROR,
471 : ESTATUS_DEADLOCK_ERROR,
472 : ESTATUS_OTHER_SQL_ERROR
473 : } EStatus;
474 :
475 : /*
476 : * Transaction status at the end of a command.
477 : */
478 : typedef enum TStatus
479 : {
480 : TSTATUS_IDLE,
481 : TSTATUS_IN_BLOCK,
482 : TSTATUS_CONN_ERROR,
483 : TSTATUS_OTHER_ERROR
484 : } TStatus;
485 :
486 : /* Various random sequences are initialized from this one. */
487 : static pg_prng_state base_random_sequence;
488 :
489 : /* Synchronization barrier for start and connection */
490 : static THREAD_BARRIER_T barrier;
491 :
492 : /*
493 : * Connection state machine states.
494 : */
495 : typedef enum
496 : {
497 : /*
498 : * The client must first choose a script to execute. Once chosen, it can
499 : * either be throttled (state CSTATE_PREPARE_THROTTLE under --rate), start
500 : * right away (state CSTATE_START_TX) or not start at all if the timer was
501 : * exceeded (state CSTATE_FINISHED).
502 : */
503 : CSTATE_CHOOSE_SCRIPT,
504 :
505 : /*
506 : * CSTATE_START_TX performs start-of-transaction processing. Establishes
507 : * a new connection for the transaction in --connect mode, records the
508 : * transaction start time, and proceed to the first command.
509 : *
510 : * Note: once a script is started, it will either error or run till its
511 : * end, where it may be interrupted. It is not interrupted while running,
512 : * so pgbench --time is to be understood as tx are allowed to start in
513 : * that time, and will finish when their work is completed.
514 : */
515 : CSTATE_START_TX,
516 :
517 : /*
518 : * In CSTATE_PREPARE_THROTTLE state, we calculate when to begin the next
519 : * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
520 : * sleeps until that moment, then advances to CSTATE_START_TX, or
521 : * CSTATE_FINISHED if the next transaction would start beyond the end of
522 : * the run.
523 : */
524 : CSTATE_PREPARE_THROTTLE,
525 : CSTATE_THROTTLE,
526 :
527 : /*
528 : * We loop through these states, to process each command in the script:
529 : *
530 : * CSTATE_START_COMMAND starts the execution of a command. On a SQL
531 : * command, the command is sent to the server, and we move to
532 : * CSTATE_WAIT_RESULT state unless in pipeline mode. On a \sleep
533 : * meta-command, the timer is set, and we enter the CSTATE_SLEEP state to
534 : * wait for it to expire. Other meta-commands are executed immediately. If
535 : * the command about to start is actually beyond the end of the script,
536 : * advance to CSTATE_END_TX.
537 : *
538 : * CSTATE_WAIT_RESULT waits until we get a result set back from the server
539 : * for the current command.
540 : *
541 : * CSTATE_SLEEP waits until the end of \sleep.
542 : *
543 : * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
544 : * command counter, and loops back to CSTATE_START_COMMAND state.
545 : *
546 : * CSTATE_SKIP_COMMAND is used by conditional branches which are not
547 : * executed. It quickly skip commands that do not need any evaluation.
548 : * This state can move forward several commands, till there is something
549 : * to do or the end of the script.
550 : */
551 : CSTATE_START_COMMAND,
552 : CSTATE_WAIT_RESULT,
553 : CSTATE_SLEEP,
554 : CSTATE_END_COMMAND,
555 : CSTATE_SKIP_COMMAND,
556 :
557 : /*
558 : * States for failed commands.
559 : *
560 : * If the SQL/meta command fails, in CSTATE_ERROR clean up after an error:
561 : * (1) clear the conditional stack; (2) if we have an unterminated
562 : * (possibly failed) transaction block, send the rollback command to the
563 : * server and wait for the result in CSTATE_WAIT_ROLLBACK_RESULT. If
564 : * something goes wrong with rolling back, go to CSTATE_ABORTED.
565 : *
566 : * But if everything is ok we are ready for future transactions: if this
567 : * is a serialization or deadlock error and we can re-execute the
568 : * transaction from the very beginning, go to CSTATE_RETRY; otherwise go
569 : * to CSTATE_FAILURE.
570 : *
571 : * In CSTATE_RETRY report an error, set the same parameters for the
572 : * transaction execution as in the previous tries and process the first
573 : * transaction command in CSTATE_START_COMMAND.
574 : *
575 : * In CSTATE_FAILURE report a failure, set the parameters for the
576 : * transaction execution as they were before the first run of this
577 : * transaction (except for a random state) and go to CSTATE_END_TX to
578 : * complete this transaction.
579 : */
580 : CSTATE_ERROR,
581 : CSTATE_WAIT_ROLLBACK_RESULT,
582 : CSTATE_RETRY,
583 : CSTATE_FAILURE,
584 :
585 : /*
586 : * CSTATE_END_TX performs end-of-transaction processing. It calculates
587 : * latency, and logs the transaction. In --connect mode, it closes the
588 : * current connection.
589 : *
590 : * Then either starts over in CSTATE_CHOOSE_SCRIPT, or enters
591 : * CSTATE_FINISHED if we have no more work to do.
592 : */
593 : CSTATE_END_TX,
594 :
595 : /*
596 : * Final states. CSTATE_ABORTED means that the script execution was
597 : * aborted because a command failed, CSTATE_FINISHED means success.
598 : */
599 : CSTATE_ABORTED,
600 : CSTATE_FINISHED
601 : } ConnectionStateEnum;
602 :
603 : /*
604 : * Connection state.
605 : */
606 : typedef struct
607 : {
608 : PGconn *con; /* connection handle to DB */
609 : int id; /* client No. */
610 : ConnectionStateEnum state; /* state machine's current state. */
611 : ConditionalStack cstack; /* enclosing conditionals state */
612 :
613 : /*
614 : * Separate randomness for each client. This is used for random functions
615 : * PGBENCH_RANDOM_* during the execution of the script.
616 : */
617 : pg_prng_state cs_func_rs;
618 :
619 : int use_file; /* index in sql_script for this client */
620 : int command; /* command number in script */
621 :
622 : /* client variables */
623 : Variables variables;
624 :
625 : /* various times about current transaction in microseconds */
626 : pg_time_usec_t txn_scheduled; /* scheduled start time of transaction */
627 : pg_time_usec_t sleep_until; /* scheduled start time of next cmd */
628 : pg_time_usec_t txn_begin; /* used for measuring schedule lag times */
629 : pg_time_usec_t stmt_begin; /* used for measuring statement latencies */
630 :
631 : /* whether client prepared each command of each script */
632 : bool **prepared;
633 :
634 : /*
635 : * For processing failures and repeating transactions with serialization
636 : * or deadlock errors:
637 : */
638 : EStatus estatus; /* the error status of the current transaction
639 : * execution; this is ESTATUS_NO_ERROR if
640 : * there were no errors */
641 : pg_prng_state random_state; /* random state */
642 : uint32 tries; /* how many times have we already tried the
643 : * current transaction? */
644 :
645 : /* per client collected stats */
646 : int64 cnt; /* client transaction count, for -t; skipped
647 : * and failed transactions are also counted
648 : * here */
649 : } CState;
650 :
651 : /*
652 : * Thread state
653 : */
654 : typedef struct
655 : {
656 : int tid; /* thread id */
657 : THREAD_T thread; /* thread handle */
658 : CState *state; /* array of CState */
659 : int nstate; /* length of state[] */
660 :
661 : /*
662 : * Separate randomness for each thread. Each thread option uses its own
663 : * random state to make all of them independent of each other and
664 : * therefore deterministic at the thread level.
665 : */
666 : pg_prng_state ts_choose_rs; /* random state for selecting a script */
667 : pg_prng_state ts_throttle_rs; /* random state for transaction throttling */
668 : pg_prng_state ts_sample_rs; /* random state for log sampling */
669 :
670 : int64 throttle_trigger; /* previous/next throttling (us) */
671 : FILE *logfile; /* where to log, or NULL */
672 :
673 : /* per thread collected stats in microseconds */
674 : pg_time_usec_t create_time; /* thread creation time */
675 : pg_time_usec_t started_time; /* thread is running */
676 : pg_time_usec_t bench_start; /* thread is benchmarking */
677 : pg_time_usec_t conn_duration; /* cumulated connection and disconnection
678 : * delays */
679 :
680 : StatsData stats;
681 : int64 latency_late; /* count executed but late transactions */
682 : } TState;
683 :
684 : /*
685 : * queries read from files
686 : */
687 : #define SQL_COMMAND 1
688 : #define META_COMMAND 2
689 :
690 : /*
691 : * max number of backslash command arguments or SQL variables,
692 : * including the command or SQL statement itself
693 : */
694 : #define MAX_ARGS 256
695 :
696 : typedef enum MetaCommand
697 : {
698 : META_NONE, /* not a known meta-command */
699 : META_SET, /* \set */
700 : META_SETSHELL, /* \setshell */
701 : META_SHELL, /* \shell */
702 : META_SLEEP, /* \sleep */
703 : META_GSET, /* \gset */
704 : META_ASET, /* \aset */
705 : META_IF, /* \if */
706 : META_ELIF, /* \elif */
707 : META_ELSE, /* \else */
708 : META_ENDIF, /* \endif */
709 : META_STARTPIPELINE, /* \startpipeline */
710 : META_ENDPIPELINE /* \endpipeline */
711 : } MetaCommand;
712 :
713 : typedef enum QueryMode
714 : {
715 : QUERY_SIMPLE, /* simple query */
716 : QUERY_EXTENDED, /* extended query */
717 : QUERY_PREPARED, /* extended query with prepared statements */
718 : NUM_QUERYMODE
719 : } QueryMode;
720 :
721 : static QueryMode querymode = QUERY_SIMPLE;
722 : static const char *QUERYMODE[] = {"simple", "extended", "prepared"};
723 :
724 : /*
725 : * struct Command represents one command in a script.
726 : *
727 : * lines The raw, possibly multi-line command text. Variable substitution
728 : * not applied.
729 : * first_line A short, single-line extract of 'lines', for error reporting.
730 : * type SQL_COMMAND or META_COMMAND
731 : * meta The type of meta-command, with META_NONE/GSET/ASET if command
732 : * is SQL.
733 : * argc Number of arguments of the command, 0 if not yet processed.
734 : * argv Command arguments, the first of which is the command or SQL
735 : * string itself. For SQL commands, after post-processing
736 : * argv[0] is the same as 'lines' with variables substituted.
737 : * prepname The name that this command is prepared under, in prepare mode
738 : * varprefix SQL commands terminated with \gset or \aset have this set
739 : * to a non NULL value. If nonempty, it's used to prefix the
740 : * variable name that receives the value.
741 : * aset do gset on all possible queries of a combined query (\;).
742 : * expr Parsed expression, if needed.
743 : * stats Time spent in this command.
744 : * retries Number of retries after a serialization or deadlock error in the
745 : * current command.
746 : * failures Number of errors in the current command that were not retried.
747 : */
748 : typedef struct Command
749 : {
750 : PQExpBufferData lines;
751 : char *first_line;
752 : int type;
753 : MetaCommand meta;
754 : int argc;
755 : char *argv[MAX_ARGS];
756 : char *prepname;
757 : char *varprefix;
758 : PgBenchExpr *expr;
759 : SimpleStats stats;
760 : int64 retries;
761 : int64 failures;
762 : } Command;
763 :
764 : typedef struct ParsedScript
765 : {
766 : const char *desc; /* script descriptor (eg, file name) */
767 : int weight; /* selection weight */
768 : Command **commands; /* NULL-terminated array of Commands */
769 : StatsData stats; /* total time spent in script */
770 : } ParsedScript;
771 :
772 : static ParsedScript sql_script[MAX_SCRIPTS]; /* SQL script files */
773 : static int num_scripts; /* number of scripts in sql_script[] */
774 : static int64 total_weight = 0;
775 :
776 : static bool verbose_errors = false; /* print verbose messages of all errors */
777 :
778 : /* Builtin test scripts */
779 : typedef struct BuiltinScript
780 : {
781 : const char *name; /* very short name for -b ... */
782 : const char *desc; /* short description */
783 : const char *script; /* actual pgbench script */
784 : } BuiltinScript;
785 :
786 : static const BuiltinScript builtin_script[] =
787 : {
788 : {
789 : "tpcb-like",
790 : "<builtin: TPC-B (sort of)>",
791 : "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
792 : "\\set bid random(1, " CppAsString2(nbranches) " * :scale)\n"
793 : "\\set tid random(1, " CppAsString2(ntellers) " * :scale)\n"
794 : "\\set delta random(-5000, 5000)\n"
795 : "BEGIN;\n"
796 : "UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
797 : "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
798 : "UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
799 : "UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
800 : "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
801 : "END;\n"
802 : },
803 : {
804 : "simple-update",
805 : "<builtin: simple update>",
806 : "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
807 : "\\set bid random(1, " CppAsString2(nbranches) " * :scale)\n"
808 : "\\set tid random(1, " CppAsString2(ntellers) " * :scale)\n"
809 : "\\set delta random(-5000, 5000)\n"
810 : "BEGIN;\n"
811 : "UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
812 : "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
813 : "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
814 : "END;\n"
815 : },
816 : {
817 : "select-only",
818 : "<builtin: select only>",
819 : "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
820 : "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
821 : }
822 : };
823 :
824 :
825 : /* Function prototypes */
826 : static void setNullValue(PgBenchValue *pv);
827 : static void setBoolValue(PgBenchValue *pv, bool bval);
828 : static void setIntValue(PgBenchValue *pv, int64 ival);
829 : static void setDoubleValue(PgBenchValue *pv, double dval);
830 : static bool evaluateExpr(CState *st, PgBenchExpr *expr,
831 : PgBenchValue *retval);
832 : static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now);
833 : static void doLog(TState *thread, CState *st,
834 : StatsData *agg, bool skipped, double latency, double lag);
835 : static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now,
836 : bool skipped, StatsData *agg);
837 : static void addScript(const ParsedScript *script);
838 : static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun(void *arg);
839 : static void finishCon(CState *st);
840 : static void setalarm(int seconds);
841 : static socket_set *alloc_socket_set(int count);
842 : static void free_socket_set(socket_set *sa);
843 : static void clear_socket_set(socket_set *sa);
844 : static void add_socket_to_set(socket_set *sa, int fd, int idx);
845 : static int wait_on_socket_set(socket_set *sa, int64 usecs);
846 : static bool socket_has_input(socket_set *sa, int fd, int idx);
847 :
848 :
849 : /* callback functions for our flex lexer */
850 : static const PsqlScanCallbacks pgbench_callbacks = {
851 : NULL, /* don't need get_variable functionality */
852 : };
853 :
854 : static inline pg_time_usec_t
855 12454 : pg_time_now(void)
856 : {
857 : instr_time now;
858 :
859 12454 : INSTR_TIME_SET_CURRENT(now);
860 :
861 12454 : return (pg_time_usec_t) INSTR_TIME_GET_MICROSEC(now);
862 : }
863 :
864 : static inline void
865 10444 : pg_time_now_lazy(pg_time_usec_t *now)
866 : {
867 10444 : if ((*now) == 0)
868 8400 : (*now) = pg_time_now();
869 10444 : }
870 :
871 : #define PG_TIME_GET_DOUBLE(t) (0.000001 * (t))
872 :
873 : static void
874 2 : usage(void)
875 : {
876 2 : printf("%s is a benchmarking tool for PostgreSQL.\n\n"
877 : "Usage:\n"
878 : " %s [OPTION]... [DBNAME]\n"
879 : "\nInitialization options:\n"
880 : " -i, --initialize invokes initialization mode\n"
881 : " -I, --init-steps=[" ALL_INIT_STEPS "]+ (default \"" DEFAULT_INIT_STEPS "\")\n"
882 : " run selected initialization steps\n"
883 : " -F, --fillfactor=NUM set fill factor\n"
884 : " -n, --no-vacuum do not run VACUUM during initialization\n"
885 : " -q, --quiet quiet logging (one message each 5 seconds)\n"
886 : " -s, --scale=NUM scaling factor\n"
887 : " --foreign-keys create foreign key constraints between tables\n"
888 : " --index-tablespace=TABLESPACE\n"
889 : " create indexes in the specified tablespace\n"
890 : " --partition-method=(range|hash)\n"
891 : " partition pgbench_accounts with this method (default: range)\n"
892 : " --partitions=NUM partition pgbench_accounts into NUM parts (default: 0)\n"
893 : " --tablespace=TABLESPACE create tables in the specified tablespace\n"
894 : " --unlogged-tables create tables as unlogged tables\n"
895 : "\nOptions to select what to run:\n"
896 : " -b, --builtin=NAME[@W] add builtin script NAME weighted at W (default: 1)\n"
897 : " (use \"-b list\" to list available scripts)\n"
898 : " -f, --file=FILENAME[@W] add script FILENAME weighted at W (default: 1)\n"
899 : " -N, --skip-some-updates skip updates of pgbench_tellers and pgbench_branches\n"
900 : " (same as \"-b simple-update\")\n"
901 : " -S, --select-only perform SELECT-only transactions\n"
902 : " (same as \"-b select-only\")\n"
903 : "\nBenchmarking options:\n"
904 : " -c, --client=NUM number of concurrent database clients (default: 1)\n"
905 : " -C, --connect establish new connection for each transaction\n"
906 : " -D, --define=VARNAME=VALUE\n"
907 : " define variable for use by custom script\n"
908 : " -j, --jobs=NUM number of threads (default: 1)\n"
909 : " -l, --log write transaction times to log file\n"
910 : " -L, --latency-limit=NUM count transactions lasting more than NUM ms as late\n"
911 : " -M, --protocol=simple|extended|prepared\n"
912 : " protocol for submitting queries (default: simple)\n"
913 : " -n, --no-vacuum do not run VACUUM before tests\n"
914 : " -P, --progress=NUM show thread progress report every NUM seconds\n"
915 : " -r, --report-per-command report latencies, failures, and retries per command\n"
916 : " -R, --rate=NUM target rate in transactions per second\n"
917 : " -s, --scale=NUM report this scale factor in output\n"
918 : " -t, --transactions=NUM number of transactions each client runs (default: 10)\n"
919 : " -T, --time=NUM duration of benchmark test in seconds\n"
920 : " -v, --vacuum-all vacuum all four standard tables before tests\n"
921 : " --aggregate-interval=NUM aggregate data over NUM seconds\n"
922 : " --failures-detailed report the failures grouped by basic types\n"
923 : " --log-prefix=PREFIX prefix for transaction time log file\n"
924 : " (default: \"pgbench_log\")\n"
925 : " --max-tries=NUM max number of tries to run transaction (default: 1)\n"
926 : " --progress-timestamp use Unix epoch timestamps for progress\n"
927 : " --random-seed=SEED set random seed (\"time\", \"rand\", integer)\n"
928 : " --sampling-rate=NUM fraction of transactions to log (e.g., 0.01 for 1%%)\n"
929 : " --show-script=NAME show builtin script code, then exit\n"
930 : " --verbose-errors print messages of all errors\n"
931 : "\nCommon options:\n"
932 : " -d, --debug print debugging output\n"
933 : " -h, --host=HOSTNAME database server host or socket directory\n"
934 : " -p, --port=PORT database server port number\n"
935 : " -U, --username=USERNAME connect as specified database user\n"
936 : " -V, --version output version information, then exit\n"
937 : " -?, --help show this help, then exit\n"
938 : "\n"
939 : "Report bugs to <%s>.\n"
940 : "%s home page: <%s>\n",
941 : progname, progname, PACKAGE_BUGREPORT, PACKAGE_NAME, PACKAGE_URL);
942 2 : }
943 :
944 : /* return whether str matches "^\s*[-+]?[0-9]+$" */
945 : static bool
946 850 : is_an_int(const char *str)
947 : {
948 850 : const char *ptr = str;
949 :
950 : /* skip leading spaces; cast is consistent with strtoint64 */
951 850 : while (*ptr && isspace((unsigned char) *ptr))
952 0 : ptr++;
953 :
954 : /* skip sign */
955 850 : if (*ptr == '+' || *ptr == '-')
956 6 : ptr++;
957 :
958 : /* at least one digit */
959 850 : if (*ptr && !isdigit((unsigned char) *ptr))
960 4 : return false;
961 :
962 : /* eat all digits */
963 1802 : while (*ptr && isdigit((unsigned char) *ptr))
964 956 : ptr++;
965 :
966 : /* must have reached end of string */
967 846 : return *ptr == '\0';
968 : }
969 :
970 :
971 : /*
972 : * strtoint64 -- convert a string to 64-bit integer
973 : *
974 : * This function is a slightly modified version of pg_strtoint64() from
975 : * src/backend/utils/adt/numutils.c.
976 : *
977 : * The function returns whether the conversion worked, and if so
978 : * "*result" is set to the result.
979 : *
980 : * If not errorOK, an error message is also printed out on errors.
981 : */
982 : bool
983 2432 : strtoint64(const char *str, bool errorOK, int64 *result)
984 : {
985 2432 : const char *ptr = str;
986 2432 : int64 tmp = 0;
987 2432 : bool neg = false;
988 :
989 : /*
990 : * Do our own scan, rather than relying on sscanf which might be broken
991 : * for long long.
992 : *
993 : * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate
994 : * value as a negative number.
995 : */
996 :
997 : /* skip leading spaces */
998 2432 : while (*ptr && isspace((unsigned char) *ptr))
999 0 : ptr++;
1000 :
1001 : /* handle sign */
1002 2432 : if (*ptr == '-')
1003 : {
1004 4 : ptr++;
1005 4 : neg = true;
1006 : }
1007 2428 : else if (*ptr == '+')
1008 0 : ptr++;
1009 :
1010 : /* require at least one digit */
1011 2432 : if (unlikely(!isdigit((unsigned char) *ptr)))
1012 0 : goto invalid_syntax;
1013 :
1014 : /* process digits */
1015 7470 : while (*ptr && isdigit((unsigned char) *ptr))
1016 : {
1017 5040 : int8 digit = (*ptr++ - '0');
1018 :
1019 5040 : if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) ||
1020 5038 : unlikely(pg_sub_s64_overflow(tmp, digit, &tmp)))
1021 2 : goto out_of_range;
1022 : }
1023 :
1024 : /* allow trailing whitespace, but not other trailing chars */
1025 2430 : while (*ptr != '\0' && isspace((unsigned char) *ptr))
1026 0 : ptr++;
1027 :
1028 2430 : if (unlikely(*ptr != '\0'))
1029 0 : goto invalid_syntax;
1030 :
1031 2430 : if (!neg)
1032 : {
1033 2426 : if (unlikely(tmp == PG_INT64_MIN))
1034 0 : goto out_of_range;
1035 2426 : tmp = -tmp;
1036 : }
1037 :
1038 2430 : *result = tmp;
1039 2430 : return true;
1040 :
1041 2 : out_of_range:
1042 2 : if (!errorOK)
1043 0 : pg_log_error("value \"%s\" is out of range for type bigint", str);
1044 2 : return false;
1045 :
1046 0 : invalid_syntax:
1047 0 : if (!errorOK)
1048 0 : pg_log_error("invalid input syntax for type bigint: \"%s\"", str);
1049 0 : return false;
1050 : }
1051 :
1052 : /* convert string to double, detecting overflows/underflows */
1053 : bool
1054 132 : strtodouble(const char *str, bool errorOK, double *dv)
1055 : {
1056 : char *end;
1057 :
1058 132 : errno = 0;
1059 132 : *dv = strtod(str, &end);
1060 :
1061 132 : if (unlikely(errno != 0))
1062 : {
1063 4 : if (!errorOK)
1064 0 : pg_log_error("value \"%s\" is out of range for type double", str);
1065 4 : return false;
1066 : }
1067 :
1068 128 : if (unlikely(end == str || *end != '\0'))
1069 : {
1070 4 : if (!errorOK)
1071 0 : pg_log_error("invalid input syntax for type double: \"%s\"", str);
1072 4 : return false;
1073 : }
1074 124 : return true;
1075 : }
1076 :
1077 : /*
1078 : * Initialize a prng state struct.
1079 : *
1080 : * We derive the seed from base_random_sequence, which must be set up already.
1081 : */
1082 : static void
1083 616 : initRandomState(pg_prng_state *state)
1084 : {
1085 616 : pg_prng_seed(state, pg_prng_uint64(&base_random_sequence));
1086 616 : }
1087 :
1088 :
1089 : /*
1090 : * random number generator: uniform distribution from min to max inclusive.
1091 : *
1092 : * Although the limits are expressed as int64, you can't generate the full
1093 : * int64 range in one call, because the difference of the limits mustn't
1094 : * overflow int64. This is not checked.
1095 : */
1096 : static int64
1097 5222 : getrand(pg_prng_state *state, int64 min, int64 max)
1098 : {
1099 5222 : return min + (int64) pg_prng_uint64_range(state, 0, max - min);
1100 : }
1101 :
1102 : /*
1103 : * random number generator: exponential distribution from min to max inclusive.
1104 : * the parameter is so that the density of probability for the last cut-off max
1105 : * value is exp(-parameter).
1106 : */
1107 : static int64
1108 6 : getExponentialRand(pg_prng_state *state, int64 min, int64 max,
1109 : double parameter)
1110 : {
1111 : double cut,
1112 : uniform,
1113 : rand;
1114 :
1115 : /* abort if wrong parameter, but must really be checked beforehand */
1116 : Assert(parameter > 0.0);
1117 6 : cut = exp(-parameter);
1118 : /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1119 6 : uniform = 1.0 - pg_prng_double(state);
1120 :
1121 : /*
1122 : * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
1123 : */
1124 : Assert((1.0 - cut) != 0.0);
1125 6 : rand = -log(cut + (1.0 - cut) * uniform) / parameter;
1126 : /* return int64 random number within between min and max */
1127 6 : return min + (int64) ((max - min + 1) * rand);
1128 : }
1129 :
1130 : /* random number generator: gaussian distribution from min to max inclusive */
1131 : static int64
1132 6 : getGaussianRand(pg_prng_state *state, int64 min, int64 max,
1133 : double parameter)
1134 : {
1135 : double stdev;
1136 : double rand;
1137 :
1138 : /* abort if parameter is too low, but must really be checked beforehand */
1139 : Assert(parameter >= MIN_GAUSSIAN_PARAM);
1140 :
1141 : /*
1142 : * Get normally-distributed random number in the range -parameter <= stdev
1143 : * < parameter.
1144 : *
1145 : * This loop is executed until the number is in the expected range.
1146 : *
1147 : * As the minimum parameter is 2.0, the probability of looping is low:
1148 : * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
1149 : * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
1150 : * the worst case. For a parameter value of 5.0, the looping probability
1151 : * is about e^{-5} * 2 / pi ~ 0.43%.
1152 : */
1153 : do
1154 : {
1155 6 : stdev = pg_prng_double_normal(state);
1156 : }
1157 6 : while (stdev < -parameter || stdev >= parameter);
1158 :
1159 : /* stdev is in [-parameter, parameter), normalization to [0,1) */
1160 6 : rand = (stdev + parameter) / (parameter * 2.0);
1161 :
1162 : /* return int64 random number within between min and max */
1163 6 : return min + (int64) ((max - min + 1) * rand);
1164 : }
1165 :
1166 : /*
1167 : * random number generator: generate a value, such that the series of values
1168 : * will approximate a Poisson distribution centered on the given value.
1169 : *
1170 : * Individual results are rounded to integers, though the center value need
1171 : * not be one.
1172 : */
1173 : static int64
1174 420 : getPoissonRand(pg_prng_state *state, double center)
1175 : {
1176 : /*
1177 : * Use inverse transform sampling to generate a value > 0, such that the
1178 : * expected (i.e. average) value is the given argument.
1179 : */
1180 : double uniform;
1181 :
1182 : /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1183 420 : uniform = 1.0 - pg_prng_double(state);
1184 :
1185 420 : return (int64) (-log(uniform) * center + 0.5);
1186 : }
1187 :
1188 : /*
1189 : * Computing zipfian using rejection method, based on
1190 : * "Non-Uniform Random Variate Generation",
1191 : * Luc Devroye, p. 550-551, Springer 1986.
1192 : *
1193 : * This works for s > 1.0, but may perform badly for s very close to 1.0.
1194 : */
1195 : static int64
1196 6 : computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
1197 : {
1198 6 : double b = pow(2.0, s - 1.0);
1199 : double x,
1200 : t,
1201 : u,
1202 : v;
1203 :
1204 : /* Ensure n is sane */
1205 6 : if (n <= 1)
1206 0 : return 1;
1207 :
1208 : while (true)
1209 : {
1210 : /* random variates */
1211 6 : u = pg_prng_double(state);
1212 6 : v = pg_prng_double(state);
1213 :
1214 6 : x = floor(pow(u, -1.0 / (s - 1.0)));
1215 :
1216 6 : t = pow(1.0 + 1.0 / x, s - 1.0);
1217 : /* reject if too large or out of bound */
1218 6 : if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1219 6 : break;
1220 : }
1221 6 : return (int64) x;
1222 : }
1223 :
1224 : /* random number generator: zipfian distribution from min to max inclusive */
1225 : static int64
1226 6 : getZipfianRand(pg_prng_state *state, int64 min, int64 max, double s)
1227 : {
1228 6 : int64 n = max - min + 1;
1229 :
1230 : /* abort if parameter is invalid */
1231 : Assert(MIN_ZIPFIAN_PARAM <= s && s <= MAX_ZIPFIAN_PARAM);
1232 :
1233 6 : return min - 1 + computeIterativeZipfian(state, n, s);
1234 : }
1235 :
1236 : /*
1237 : * FNV-1a hash function
1238 : */
1239 : static int64
1240 2 : getHashFnv1a(int64 val, uint64 seed)
1241 : {
1242 : int64 result;
1243 : int i;
1244 :
1245 2 : result = FNV_OFFSET_BASIS ^ seed;
1246 18 : for (i = 0; i < 8; ++i)
1247 : {
1248 16 : int32 octet = val & 0xff;
1249 :
1250 16 : val = val >> 8;
1251 16 : result = result ^ octet;
1252 16 : result = result * FNV_PRIME;
1253 : }
1254 :
1255 2 : return result;
1256 : }
1257 :
1258 : /*
1259 : * Murmur2 hash function
1260 : *
1261 : * Based on original work of Austin Appleby
1262 : * https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp
1263 : */
1264 : static int64
1265 10 : getHashMurmur2(int64 val, uint64 seed)
1266 : {
1267 10 : uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1268 10 : uint64 k = (uint64) val;
1269 :
1270 10 : k *= MM2_MUL;
1271 10 : k ^= k >> MM2_ROT;
1272 10 : k *= MM2_MUL;
1273 :
1274 10 : result ^= k;
1275 10 : result *= MM2_MUL;
1276 :
1277 10 : result ^= result >> MM2_ROT;
1278 10 : result *= MM2_MUL;
1279 10 : result ^= result >> MM2_ROT;
1280 :
1281 10 : return (int64) result;
1282 : }
1283 :
1284 : /*
1285 : * Pseudorandom permutation function
1286 : *
1287 : * For small sizes, this generates each of the (size!) possible permutations
1288 : * of integers in the range [0, size) with roughly equal probability. Once
1289 : * the size is larger than 20, the number of possible permutations exceeds the
1290 : * number of distinct states of the internal pseudorandom number generator,
1291 : * and so not all possible permutations can be generated, but the permutations
1292 : * chosen should continue to give the appearance of being random.
1293 : *
1294 : * THIS FUNCTION IS NOT CRYPTOGRAPHICALLY SECURE.
1295 : * DO NOT USE FOR SUCH PURPOSE.
1296 : */
1297 : static int64
1298 90 : permute(const int64 val, const int64 isize, const int64 seed)
1299 : {
1300 : /* using a high-end PRNG is probably overkill */
1301 : pg_prng_state state;
1302 : uint64 size;
1303 : uint64 v;
1304 : int masklen;
1305 : uint64 mask;
1306 : int i;
1307 :
1308 90 : if (isize < 2)
1309 2 : return 0; /* nothing to permute */
1310 :
1311 : /* Initialize prng state using the seed */
1312 88 : pg_prng_seed(&state, (uint64) seed);
1313 :
1314 : /* Computations are performed on unsigned values */
1315 88 : size = (uint64) isize;
1316 88 : v = (uint64) val % size;
1317 :
1318 : /* Mask to work modulo largest power of 2 less than or equal to size */
1319 88 : masklen = pg_leftmost_one_pos64(size);
1320 88 : mask = (((uint64) 1) << masklen) - 1;
1321 :
1322 : /*
1323 : * Permute the input value by applying several rounds of pseudorandom
1324 : * bijective transformations. The intention here is to distribute each
1325 : * input uniformly randomly across the range, and separate adjacent inputs
1326 : * approximately uniformly randomly from each other, leading to a fairly
1327 : * random overall choice of permutation.
1328 : *
1329 : * To separate adjacent inputs, we multiply by a random number modulo
1330 : * (mask + 1), which is a power of 2. For this to be a bijection, the
1331 : * multiplier must be odd. Since this is known to lead to less randomness
1332 : * in the lower bits, we also apply a rotation that shifts the topmost bit
1333 : * into the least significant bit. In the special cases where size <= 3,
1334 : * mask = 1 and each of these operations is actually a no-op, so we also
1335 : * XOR the value with a different random number to inject additional
1336 : * randomness. Since the size is generally not a power of 2, we apply
1337 : * this bijection on overlapping upper and lower halves of the input.
1338 : *
1339 : * To distribute the inputs uniformly across the range, we then also apply
1340 : * a random offset modulo the full range.
1341 : *
1342 : * Taken together, these operations resemble a modified linear
1343 : * congruential generator, as is commonly used in pseudorandom number
1344 : * generators. The number of rounds is fairly arbitrary, but six has been
1345 : * found empirically to give a fairly good tradeoff between performance
1346 : * and uniform randomness. For small sizes it selects each of the (size!)
1347 : * possible permutations with roughly equal probability. For larger
1348 : * sizes, not all permutations can be generated, but the intended random
1349 : * spread is still produced.
1350 : */
1351 616 : for (i = 0; i < 6; i++)
1352 : {
1353 : uint64 m,
1354 : r,
1355 : t;
1356 :
1357 : /* Random multiply (by an odd number), XOR and rotate of lower half */
1358 528 : m = (pg_prng_uint64(&state) & mask) | 1;
1359 528 : r = pg_prng_uint64(&state) & mask;
1360 528 : if (v <= mask)
1361 : {
1362 438 : v = ((v * m) ^ r) & mask;
1363 438 : v = ((v << 1) & mask) | (v >> (masklen - 1));
1364 : }
1365 :
1366 : /* Random multiply (by an odd number), XOR and rotate of upper half */
1367 528 : m = (pg_prng_uint64(&state) & mask) | 1;
1368 528 : r = pg_prng_uint64(&state) & mask;
1369 528 : t = size - 1 - v;
1370 528 : if (t <= mask)
1371 : {
1372 470 : t = ((t * m) ^ r) & mask;
1373 470 : t = ((t << 1) & mask) | (t >> (masklen - 1));
1374 470 : v = size - 1 - t;
1375 : }
1376 :
1377 : /* Random offset */
1378 528 : r = pg_prng_uint64_range(&state, 0, size - 1);
1379 528 : v = (v + r) % size;
1380 : }
1381 :
1382 88 : return (int64) v;
1383 : }
1384 :
1385 : /*
1386 : * Initialize the given SimpleStats struct to all zeroes
1387 : */
1388 : static void
1389 3548 : initSimpleStats(SimpleStats *ss)
1390 : {
1391 3548 : memset(ss, 0, sizeof(SimpleStats));
1392 3548 : }
1393 :
1394 : /*
1395 : * Accumulate one value into a SimpleStats struct.
1396 : */
1397 : static void
1398 8262 : addToSimpleStats(SimpleStats *ss, double val)
1399 : {
1400 8262 : if (ss->count == 0 || val < ss->min)
1401 258 : ss->min = val;
1402 8262 : if (ss->count == 0 || val > ss->max)
1403 970 : ss->max = val;
1404 8262 : ss->count++;
1405 8262 : ss->sum += val;
1406 8262 : ss->sum2 += val * val;
1407 8262 : }
1408 :
1409 : /*
1410 : * Merge two SimpleStats objects
1411 : */
1412 : static void
1413 276 : mergeSimpleStats(SimpleStats *acc, SimpleStats *ss)
1414 : {
1415 276 : if (acc->count == 0 || ss->min < acc->min)
1416 274 : acc->min = ss->min;
1417 276 : if (acc->count == 0 || ss->max > acc->max)
1418 274 : acc->max = ss->max;
1419 276 : acc->count += ss->count;
1420 276 : acc->sum += ss->sum;
1421 276 : acc->sum2 += ss->sum2;
1422 276 : }
1423 :
1424 : /*
1425 : * Initialize a StatsData struct to mostly zeroes, with its start time set to
1426 : * the given value.
1427 : */
1428 : static void
1429 936 : initStats(StatsData *sd, pg_time_usec_t start)
1430 : {
1431 936 : sd->start_time = start;
1432 936 : sd->cnt = 0;
1433 936 : sd->skipped = 0;
1434 936 : sd->retries = 0;
1435 936 : sd->retried = 0;
1436 936 : sd->serialization_failures = 0;
1437 936 : sd->deadlock_failures = 0;
1438 936 : initSimpleStats(&sd->latency);
1439 936 : initSimpleStats(&sd->lag);
1440 936 : }
1441 :
1442 : /*
1443 : * Accumulate one additional item into the given stats object.
1444 : */
1445 : static void
1446 7076 : accumStats(StatsData *stats, bool skipped, double lat, double lag,
1447 : EStatus estatus, int64 tries)
1448 : {
1449 : /* Record the skipped transaction */
1450 7076 : if (skipped)
1451 : {
1452 : /* no latency to record on skipped transactions */
1453 18 : stats->skipped++;
1454 18 : return;
1455 : }
1456 :
1457 : /*
1458 : * Record the number of retries regardless of whether the transaction was
1459 : * successful or failed.
1460 : */
1461 7058 : if (tries > 1)
1462 : {
1463 4 : stats->retries += (tries - 1);
1464 4 : stats->retried++;
1465 : }
1466 :
1467 7058 : switch (estatus)
1468 : {
1469 : /* Record the successful transaction */
1470 7058 : case ESTATUS_NO_ERROR:
1471 7058 : stats->cnt++;
1472 :
1473 7058 : addToSimpleStats(&stats->latency, lat);
1474 :
1475 : /* and possibly the same for schedule lag */
1476 7058 : if (throttle_delay)
1477 402 : addToSimpleStats(&stats->lag, lag);
1478 7058 : break;
1479 :
1480 : /* Record the failed transaction */
1481 0 : case ESTATUS_SERIALIZATION_ERROR:
1482 0 : stats->serialization_failures++;
1483 0 : break;
1484 0 : case ESTATUS_DEADLOCK_ERROR:
1485 0 : stats->deadlock_failures++;
1486 0 : break;
1487 0 : default:
1488 : /* internal error which should never occur */
1489 0 : pg_fatal("unexpected error status: %d", estatus);
1490 : }
1491 : }
1492 :
1493 : /* call PQexec() and exit() on failure */
1494 : static void
1495 162 : executeStatement(PGconn *con, const char *sql)
1496 : {
1497 : PGresult *res;
1498 :
1499 162 : res = PQexec(con, sql);
1500 162 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
1501 : {
1502 0 : pg_log_error("query failed: %s", PQerrorMessage(con));
1503 0 : pg_log_error_detail("Query was: %s", sql);
1504 0 : exit(1);
1505 : }
1506 162 : PQclear(res);
1507 162 : }
1508 :
1509 : /* call PQexec() and complain, but without exiting, on failure */
1510 : static void
1511 54 : tryExecuteStatement(PGconn *con, const char *sql)
1512 : {
1513 : PGresult *res;
1514 :
1515 54 : res = PQexec(con, sql);
1516 54 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
1517 : {
1518 0 : pg_log_error("%s", PQerrorMessage(con));
1519 0 : pg_log_error_detail("(ignoring this error and continuing anyway)");
1520 : }
1521 54 : PQclear(res);
1522 54 : }
1523 :
1524 : /* set up a connection to the backend */
1525 : static PGconn *
1526 550 : doConnect(void)
1527 : {
1528 : PGconn *conn;
1529 : bool new_pass;
1530 : static char *password = NULL;
1531 :
1532 : /*
1533 : * Start the connection. Loop until we have a password if requested by
1534 : * backend.
1535 : */
1536 : do
1537 : {
1538 : #define PARAMS_ARRAY_SIZE 7
1539 :
1540 : const char *keywords[PARAMS_ARRAY_SIZE];
1541 : const char *values[PARAMS_ARRAY_SIZE];
1542 :
1543 550 : keywords[0] = "host";
1544 550 : values[0] = pghost;
1545 550 : keywords[1] = "port";
1546 550 : values[1] = pgport;
1547 550 : keywords[2] = "user";
1548 550 : values[2] = username;
1549 550 : keywords[3] = "password";
1550 550 : values[3] = password;
1551 550 : keywords[4] = "dbname";
1552 550 : values[4] = dbName;
1553 550 : keywords[5] = "fallback_application_name";
1554 550 : values[5] = progname;
1555 550 : keywords[6] = NULL;
1556 550 : values[6] = NULL;
1557 :
1558 550 : new_pass = false;
1559 :
1560 550 : conn = PQconnectdbParams(keywords, values, true);
1561 :
1562 550 : if (!conn)
1563 : {
1564 0 : pg_log_error("connection to database \"%s\" failed", dbName);
1565 0 : return NULL;
1566 : }
1567 :
1568 552 : if (PQstatus(conn) == CONNECTION_BAD &&
1569 2 : PQconnectionNeedsPassword(conn) &&
1570 0 : !password)
1571 : {
1572 0 : PQfinish(conn);
1573 0 : password = simple_prompt("Password: ", false);
1574 0 : new_pass = true;
1575 : }
1576 550 : } while (new_pass);
1577 :
1578 : /* check to see that the backend connection was successfully made */
1579 550 : if (PQstatus(conn) == CONNECTION_BAD)
1580 : {
1581 2 : pg_log_error("%s", PQerrorMessage(conn));
1582 2 : PQfinish(conn);
1583 2 : return NULL;
1584 : }
1585 :
1586 548 : return conn;
1587 : }
1588 :
1589 : /* qsort comparator for Variable array */
1590 : static int
1591 106380 : compareVariableNames(const void *v1, const void *v2)
1592 : {
1593 212760 : return strcmp(((const Variable *) v1)->name,
1594 106380 : ((const Variable *) v2)->name);
1595 : }
1596 :
1597 : /* Locate a variable by name; returns NULL if unknown */
1598 : static Variable *
1599 15576 : lookupVariable(Variables *variables, char *name)
1600 : {
1601 : Variable key;
1602 :
1603 : /* On some versions of Solaris, bsearch of zero items dumps core */
1604 15576 : if (variables->nvars <= 0)
1605 308 : return NULL;
1606 :
1607 : /* Sort if we have to */
1608 15268 : if (!variables->vars_sorted)
1609 : {
1610 1852 : qsort(variables->vars, variables->nvars, sizeof(Variable),
1611 : compareVariableNames);
1612 1852 : variables->vars_sorted = true;
1613 : }
1614 :
1615 : /* Now we can search */
1616 15268 : key.name = name;
1617 15268 : return (Variable *) bsearch(&key,
1618 15268 : variables->vars,
1619 15268 : variables->nvars,
1620 : sizeof(Variable),
1621 : compareVariableNames);
1622 : }
1623 :
1624 : /* Get the value of a variable, in string form; returns NULL if unknown */
1625 : static char *
1626 5300 : getVariable(Variables *variables, char *name)
1627 : {
1628 : Variable *var;
1629 : char stringform[64];
1630 :
1631 5300 : var = lookupVariable(variables, name);
1632 5300 : if (var == NULL)
1633 8 : return NULL; /* not found */
1634 :
1635 5292 : if (var->svalue)
1636 2080 : return var->svalue; /* we have it in string form */
1637 :
1638 : /* We need to produce a string equivalent of the value */
1639 : Assert(var->value.type != PGBT_NO_VALUE);
1640 3212 : if (var->value.type == PGBT_NULL)
1641 2 : snprintf(stringform, sizeof(stringform), "NULL");
1642 3210 : else if (var->value.type == PGBT_BOOLEAN)
1643 2 : snprintf(stringform, sizeof(stringform),
1644 2 : "%s", var->value.u.bval ? "true" : "false");
1645 3208 : else if (var->value.type == PGBT_INT)
1646 3204 : snprintf(stringform, sizeof(stringform),
1647 : INT64_FORMAT, var->value.u.ival);
1648 4 : else if (var->value.type == PGBT_DOUBLE)
1649 4 : snprintf(stringform, sizeof(stringform),
1650 : "%.*g", DBL_DIG, var->value.u.dval);
1651 : else /* internal error, unexpected type */
1652 : Assert(0);
1653 3212 : var->svalue = pg_strdup(stringform);
1654 3212 : return var->svalue;
1655 : }
1656 :
1657 : /* Try to convert variable to a value; return false on failure */
1658 : static bool
1659 3824 : makeVariableValue(Variable *var)
1660 : {
1661 : size_t slen;
1662 :
1663 3824 : if (var->value.type != PGBT_NO_VALUE)
1664 2968 : return true; /* no work */
1665 :
1666 856 : slen = strlen(var->svalue);
1667 :
1668 856 : if (slen == 0)
1669 : /* what should it do on ""? */
1670 0 : return false;
1671 :
1672 856 : if (pg_strcasecmp(var->svalue, "null") == 0)
1673 : {
1674 2 : setNullValue(&var->value);
1675 : }
1676 :
1677 : /*
1678 : * accept prefixes such as y, ye, n, no... but not for "o". 0/1 are
1679 : * recognized later as an int, which is converted to bool if needed.
1680 : */
1681 1706 : else if (pg_strncasecmp(var->svalue, "true", slen) == 0 ||
1682 1704 : pg_strncasecmp(var->svalue, "yes", slen) == 0 ||
1683 852 : pg_strcasecmp(var->svalue, "on") == 0)
1684 : {
1685 2 : setBoolValue(&var->value, true);
1686 : }
1687 1704 : else if (pg_strncasecmp(var->svalue, "false", slen) == 0 ||
1688 1704 : pg_strncasecmp(var->svalue, "no", slen) == 0 ||
1689 1704 : pg_strcasecmp(var->svalue, "off") == 0 ||
1690 852 : pg_strcasecmp(var->svalue, "of") == 0)
1691 : {
1692 2 : setBoolValue(&var->value, false);
1693 : }
1694 850 : else if (is_an_int(var->svalue))
1695 : {
1696 : /* if it looks like an int, it must be an int without overflow */
1697 : int64 iv;
1698 :
1699 844 : if (!strtoint64(var->svalue, false, &iv))
1700 0 : return false;
1701 :
1702 844 : setIntValue(&var->value, iv);
1703 : }
1704 : else /* type should be double */
1705 : {
1706 : double dv;
1707 :
1708 6 : if (!strtodouble(var->svalue, true, &dv))
1709 : {
1710 4 : pg_log_error("malformed variable \"%s\" value: \"%s\"",
1711 : var->name, var->svalue);
1712 4 : return false;
1713 : }
1714 2 : setDoubleValue(&var->value, dv);
1715 : }
1716 852 : return true;
1717 : }
1718 :
1719 : /*
1720 : * Check whether a variable's name is allowed.
1721 : *
1722 : * We allow any non-ASCII character, as well as ASCII letters, digits, and
1723 : * underscore.
1724 : *
1725 : * Keep this in sync with the definitions of variable name characters in
1726 : * "src/fe_utils/psqlscan.l", "src/bin/psql/psqlscanslash.l" and
1727 : * "src/bin/pgbench/exprscan.l". Also see parseVariable(), below.
1728 : *
1729 : * Note: this static function is copied from "src/bin/psql/variables.c"
1730 : * but changed to disallow variable names starting with a digit.
1731 : */
1732 : static bool
1733 1982 : valid_variable_name(const char *name)
1734 : {
1735 1982 : const unsigned char *ptr = (const unsigned char *) name;
1736 :
1737 : /* Mustn't be zero-length */
1738 1982 : if (*ptr == '\0')
1739 0 : return false;
1740 :
1741 : /* must not start with [0-9] */
1742 1982 : if (IS_HIGHBIT_SET(*ptr) ||
1743 1982 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1744 1982 : "_", *ptr) != NULL)
1745 1978 : ptr++;
1746 : else
1747 4 : return false;
1748 :
1749 : /* remaining characters can include [0-9] */
1750 12336 : while (*ptr)
1751 : {
1752 10360 : if (IS_HIGHBIT_SET(*ptr) ||
1753 10360 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1754 10360 : "_0123456789", *ptr) != NULL)
1755 10358 : ptr++;
1756 : else
1757 2 : return false;
1758 : }
1759 :
1760 1976 : return true;
1761 : }
1762 :
1763 : /*
1764 : * Make sure there is enough space for 'needed' more variable in the variables
1765 : * array.
1766 : */
1767 : static void
1768 1976 : enlargeVariables(Variables *variables, int needed)
1769 : {
1770 : /* total number of variables required now */
1771 1976 : needed += variables->nvars;
1772 :
1773 1976 : if (variables->max_vars < needed)
1774 : {
1775 322 : variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1776 322 : variables->vars = (Variable *)
1777 322 : pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1778 : }
1779 1976 : }
1780 :
1781 : /*
1782 : * Lookup a variable by name, creating it if need be.
1783 : * Caller is expected to assign a value to the variable.
1784 : * Returns NULL on failure (bad name).
1785 : */
1786 : static Variable *
1787 5904 : lookupCreateVariable(Variables *variables, const char *context, char *name)
1788 : {
1789 : Variable *var;
1790 :
1791 5904 : var = lookupVariable(variables, name);
1792 5904 : if (var == NULL)
1793 : {
1794 : /*
1795 : * Check for the name only when declaring a new variable to avoid
1796 : * overhead.
1797 : */
1798 1982 : if (!valid_variable_name(name))
1799 : {
1800 6 : pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1801 6 : return NULL;
1802 : }
1803 :
1804 : /* Create variable at the end of the array */
1805 1976 : enlargeVariables(variables, 1);
1806 :
1807 1976 : var = &(variables->vars[variables->nvars]);
1808 :
1809 1976 : var->name = pg_strdup(name);
1810 1976 : var->svalue = NULL;
1811 : /* caller is expected to initialize remaining fields */
1812 :
1813 1976 : variables->nvars++;
1814 : /* we don't re-sort the array till we have to */
1815 1976 : variables->vars_sorted = false;
1816 : }
1817 :
1818 5898 : return var;
1819 : }
1820 :
1821 : /* Assign a string value to a variable, creating it if need be */
1822 : /* Returns false on failure (bad name) */
1823 : static bool
1824 1732 : putVariable(Variables *variables, const char *context, char *name,
1825 : const char *value)
1826 : {
1827 : Variable *var;
1828 : char *val;
1829 :
1830 1732 : var = lookupCreateVariable(variables, context, name);
1831 1732 : if (!var)
1832 4 : return false;
1833 :
1834 : /* dup then free, in case value is pointing at this variable */
1835 1728 : val = pg_strdup(value);
1836 :
1837 1728 : free(var->svalue);
1838 1728 : var->svalue = val;
1839 1728 : var->value.type = PGBT_NO_VALUE;
1840 :
1841 1728 : return true;
1842 : }
1843 :
1844 : /* Assign a value to a variable, creating it if need be */
1845 : /* Returns false on failure (bad name) */
1846 : static bool
1847 4172 : putVariableValue(Variables *variables, const char *context, char *name,
1848 : const PgBenchValue *value)
1849 : {
1850 : Variable *var;
1851 :
1852 4172 : var = lookupCreateVariable(variables, context, name);
1853 4172 : if (!var)
1854 2 : return false;
1855 :
1856 4170 : free(var->svalue);
1857 4170 : var->svalue = NULL;
1858 4170 : var->value = *value;
1859 :
1860 4170 : return true;
1861 : }
1862 :
1863 : /* Assign an integer value to a variable, creating it if need be */
1864 : /* Returns false on failure (bad name) */
1865 : static bool
1866 794 : putVariableInt(Variables *variables, const char *context, char *name,
1867 : int64 value)
1868 : {
1869 : PgBenchValue val;
1870 :
1871 794 : setIntValue(&val, value);
1872 794 : return putVariableValue(variables, context, name, &val);
1873 : }
1874 :
1875 : /*
1876 : * Parse a possible variable reference (:varname).
1877 : *
1878 : * "sql" points at a colon. If what follows it looks like a valid
1879 : * variable name, return a malloc'd string containing the variable name,
1880 : * and set *eaten to the number of characters consumed (including the colon).
1881 : * Otherwise, return NULL.
1882 : */
1883 : static char *
1884 3378 : parseVariable(const char *sql, int *eaten)
1885 : {
1886 3378 : int i = 1; /* starting at 1 skips the colon */
1887 : char *name;
1888 :
1889 : /* keep this logic in sync with valid_variable_name() */
1890 3378 : if (IS_HIGHBIT_SET(sql[i]) ||
1891 3378 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1892 3378 : "_", sql[i]) != NULL)
1893 2480 : i++;
1894 : else
1895 898 : return NULL;
1896 :
1897 12818 : while (IS_HIGHBIT_SET(sql[i]) ||
1898 12818 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1899 12818 : "_0123456789", sql[i]) != NULL)
1900 10338 : i++;
1901 :
1902 2480 : name = pg_malloc(i);
1903 2480 : memcpy(name, &sql[1], i - 1);
1904 2480 : name[i - 1] = '\0';
1905 :
1906 2480 : *eaten = i;
1907 2480 : return name;
1908 : }
1909 :
1910 : static char *
1911 2478 : replaceVariable(char **sql, char *param, int len, char *value)
1912 : {
1913 2478 : int valueln = strlen(value);
1914 :
1915 2478 : if (valueln > len)
1916 : {
1917 1172 : size_t offset = param - *sql;
1918 :
1919 1172 : *sql = pg_realloc(*sql, strlen(*sql) - len + valueln + 1);
1920 1172 : param = *sql + offset;
1921 : }
1922 :
1923 2478 : if (valueln != len)
1924 2426 : memmove(param + valueln, param + len, strlen(param + len) + 1);
1925 2478 : memcpy(param, value, valueln);
1926 :
1927 2478 : return param + valueln;
1928 : }
1929 :
1930 : static char *
1931 6648 : assignVariables(Variables *variables, char *sql)
1932 : {
1933 : char *p,
1934 : *name,
1935 : *val;
1936 :
1937 6648 : p = sql;
1938 9432 : while ((p = strchr(p, ':')) != NULL)
1939 : {
1940 : int eaten;
1941 :
1942 2784 : name = parseVariable(p, &eaten);
1943 2784 : if (name == NULL)
1944 : {
1945 2598 : while (*p == ':')
1946 : {
1947 1732 : p++;
1948 : }
1949 866 : continue;
1950 : }
1951 :
1952 1918 : val = getVariable(variables, name);
1953 1918 : free(name);
1954 1918 : if (val == NULL)
1955 : {
1956 0 : p++;
1957 0 : continue;
1958 : }
1959 :
1960 1918 : p = replaceVariable(&sql, p, eaten, val);
1961 : }
1962 :
1963 6648 : return sql;
1964 : }
1965 :
1966 : static void
1967 4568 : getQueryParams(Variables *variables, const Command *command,
1968 : const char **params)
1969 : {
1970 : int i;
1971 :
1972 7940 : for (i = 0; i < command->argc - 1; i++)
1973 3372 : params[i] = getVariable(variables, command->argv[i + 1]);
1974 4568 : }
1975 :
1976 : static char *
1977 8 : valueTypeName(PgBenchValue *pval)
1978 : {
1979 8 : if (pval->type == PGBT_NO_VALUE)
1980 0 : return "none";
1981 8 : else if (pval->type == PGBT_NULL)
1982 0 : return "null";
1983 8 : else if (pval->type == PGBT_INT)
1984 0 : return "int";
1985 8 : else if (pval->type == PGBT_DOUBLE)
1986 2 : return "double";
1987 6 : else if (pval->type == PGBT_BOOLEAN)
1988 6 : return "boolean";
1989 : else
1990 : {
1991 : /* internal error, should never get there */
1992 : Assert(false);
1993 0 : return NULL;
1994 : }
1995 : }
1996 :
1997 : /* get a value as a boolean, or tell if there is a problem */
1998 : static bool
1999 216 : coerceToBool(PgBenchValue *pval, bool *bval)
2000 : {
2001 216 : if (pval->type == PGBT_BOOLEAN)
2002 : {
2003 214 : *bval = pval->u.bval;
2004 214 : return true;
2005 : }
2006 : else /* NULL, INT or DOUBLE */
2007 : {
2008 2 : pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2009 2 : *bval = false; /* suppress uninitialized-variable warnings */
2010 2 : return false;
2011 : }
2012 : }
2013 :
2014 : /*
2015 : * Return true or false from an expression for conditional purposes.
2016 : * Non zero numerical values are true, zero and NULL are false.
2017 : */
2018 : static bool
2019 870 : valueTruth(PgBenchValue *pval)
2020 : {
2021 870 : switch (pval->type)
2022 : {
2023 2 : case PGBT_NULL:
2024 2 : return false;
2025 42 : case PGBT_BOOLEAN:
2026 42 : return pval->u.bval;
2027 824 : case PGBT_INT:
2028 824 : return pval->u.ival != 0;
2029 2 : case PGBT_DOUBLE:
2030 2 : return pval->u.dval != 0.0;
2031 0 : default:
2032 : /* internal error, unexpected type */
2033 : Assert(0);
2034 0 : return false;
2035 : }
2036 : }
2037 :
2038 : /* get a value as an int, tell if there is a problem */
2039 : static bool
2040 13088 : coerceToInt(PgBenchValue *pval, int64 *ival)
2041 : {
2042 13088 : if (pval->type == PGBT_INT)
2043 : {
2044 13080 : *ival = pval->u.ival;
2045 13080 : return true;
2046 : }
2047 8 : else if (pval->type == PGBT_DOUBLE)
2048 : {
2049 4 : double dval = rint(pval->u.dval);
2050 :
2051 4 : if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
2052 : {
2053 2 : pg_log_error("double to int overflow for %f", dval);
2054 2 : return false;
2055 : }
2056 2 : *ival = (int64) dval;
2057 2 : return true;
2058 : }
2059 : else /* BOOLEAN or NULL */
2060 : {
2061 4 : pg_log_error("cannot coerce %s to int", valueTypeName(pval));
2062 4 : return false;
2063 : }
2064 : }
2065 :
2066 : /* get a value as a double, or tell if there is a problem */
2067 : static bool
2068 208 : coerceToDouble(PgBenchValue *pval, double *dval)
2069 : {
2070 208 : if (pval->type == PGBT_DOUBLE)
2071 : {
2072 146 : *dval = pval->u.dval;
2073 146 : return true;
2074 : }
2075 62 : else if (pval->type == PGBT_INT)
2076 : {
2077 60 : *dval = (double) pval->u.ival;
2078 60 : return true;
2079 : }
2080 : else /* BOOLEAN or NULL */
2081 : {
2082 2 : pg_log_error("cannot coerce %s to double", valueTypeName(pval));
2083 2 : return false;
2084 : }
2085 : }
2086 :
2087 : /* assign a null value */
2088 : static void
2089 8 : setNullValue(PgBenchValue *pv)
2090 : {
2091 8 : pv->type = PGBT_NULL;
2092 8 : pv->u.ival = 0;
2093 8 : }
2094 :
2095 : /* assign a boolean value */
2096 : static void
2097 268 : setBoolValue(PgBenchValue *pv, bool bval)
2098 : {
2099 268 : pv->type = PGBT_BOOLEAN;
2100 268 : pv->u.bval = bval;
2101 268 : }
2102 :
2103 : /* assign an integer value */
2104 : static void
2105 8010 : setIntValue(PgBenchValue *pv, int64 ival)
2106 : {
2107 8010 : pv->type = PGBT_INT;
2108 8010 : pv->u.ival = ival;
2109 8010 : }
2110 :
2111 : /* assign a double value */
2112 : static void
2113 78 : setDoubleValue(PgBenchValue *pv, double dval)
2114 : {
2115 78 : pv->type = PGBT_DOUBLE;
2116 78 : pv->u.dval = dval;
2117 78 : }
2118 :
2119 : static bool
2120 6956 : isLazyFunc(PgBenchFunction func)
2121 : {
2122 6956 : return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
2123 : }
2124 :
2125 : /* lazy evaluation of some functions */
2126 : static bool
2127 130 : evalLazyFunc(CState *st,
2128 : PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
2129 : {
2130 : PgBenchValue a1,
2131 : a2;
2132 : bool ba1,
2133 : ba2;
2134 :
2135 : Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
2136 :
2137 : /* args points to first condition */
2138 130 : if (!evaluateExpr(st, args->expr, &a1))
2139 2 : return false;
2140 :
2141 : /* second condition for AND/OR and corresponding branch for CASE */
2142 128 : args = args->next;
2143 :
2144 128 : switch (func)
2145 : {
2146 88 : case PGBENCH_AND:
2147 88 : if (a1.type == PGBT_NULL)
2148 : {
2149 0 : setNullValue(retval);
2150 0 : return true;
2151 : }
2152 :
2153 88 : if (!coerceToBool(&a1, &ba1))
2154 0 : return false;
2155 :
2156 88 : if (!ba1)
2157 : {
2158 6 : setBoolValue(retval, false);
2159 6 : return true;
2160 : }
2161 :
2162 82 : if (!evaluateExpr(st, args->expr, &a2))
2163 0 : return false;
2164 :
2165 82 : if (a2.type == PGBT_NULL)
2166 : {
2167 0 : setNullValue(retval);
2168 0 : return true;
2169 : }
2170 82 : else if (!coerceToBool(&a2, &ba2))
2171 0 : return false;
2172 : else
2173 : {
2174 82 : setBoolValue(retval, ba2);
2175 82 : return true;
2176 : }
2177 :
2178 : return true;
2179 :
2180 8 : case PGBENCH_OR:
2181 :
2182 8 : if (a1.type == PGBT_NULL)
2183 : {
2184 0 : setNullValue(retval);
2185 0 : return true;
2186 : }
2187 :
2188 8 : if (!coerceToBool(&a1, &ba1))
2189 0 : return false;
2190 :
2191 8 : if (ba1)
2192 : {
2193 2 : setBoolValue(retval, true);
2194 2 : return true;
2195 : }
2196 :
2197 6 : if (!evaluateExpr(st, args->expr, &a2))
2198 0 : return false;
2199 :
2200 6 : if (a2.type == PGBT_NULL)
2201 : {
2202 0 : setNullValue(retval);
2203 0 : return true;
2204 : }
2205 6 : else if (!coerceToBool(&a2, &ba2))
2206 0 : return false;
2207 : else
2208 : {
2209 6 : setBoolValue(retval, ba2);
2210 6 : return true;
2211 : }
2212 :
2213 32 : case PGBENCH_CASE:
2214 : /* when true, execute branch */
2215 32 : if (valueTruth(&a1))
2216 22 : return evaluateExpr(st, args->expr, retval);
2217 :
2218 : /* now args contains next condition or final else expression */
2219 10 : args = args->next;
2220 :
2221 : /* final else case? */
2222 10 : if (args->next == NULL)
2223 6 : return evaluateExpr(st, args->expr, retval);
2224 :
2225 : /* no, another when, proceed */
2226 4 : return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2227 :
2228 0 : default:
2229 : /* internal error, cannot get here */
2230 : Assert(0);
2231 0 : break;
2232 : }
2233 0 : return false;
2234 : }
2235 :
2236 : /* maximum number of function arguments */
2237 : #define MAX_FARGS 16
2238 :
2239 : /*
2240 : * Recursive evaluation of standard functions,
2241 : * which do not require lazy evaluation.
2242 : */
2243 : static bool
2244 6830 : evalStandardFunc(CState *st,
2245 : PgBenchFunction func, PgBenchExprLink *args,
2246 : PgBenchValue *retval)
2247 : {
2248 : /* evaluate all function arguments */
2249 6830 : int nargs = 0;
2250 : PgBenchValue vargs[MAX_FARGS];
2251 6830 : PgBenchExprLink *l = args;
2252 6830 : bool has_null = false;
2253 :
2254 20416 : for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
2255 : {
2256 13590 : if (!evaluateExpr(st, l->expr, &vargs[nargs]))
2257 4 : return false;
2258 13586 : has_null |= vargs[nargs].type == PGBT_NULL;
2259 : }
2260 :
2261 6826 : if (l != NULL)
2262 : {
2263 2 : pg_log_error("too many function arguments, maximum is %d", MAX_FARGS);
2264 2 : return false;
2265 : }
2266 :
2267 : /* NULL arguments */
2268 6824 : if (has_null && func != PGBENCH_IS && func != PGBENCH_DEBUG)
2269 : {
2270 6 : setNullValue(retval);
2271 6 : return true;
2272 : }
2273 :
2274 : /* then evaluate function */
2275 6818 : switch (func)
2276 : {
2277 : /* overloaded operators */
2278 3366 : case PGBENCH_ADD:
2279 : case PGBENCH_SUB:
2280 : case PGBENCH_MUL:
2281 : case PGBENCH_DIV:
2282 : case PGBENCH_MOD:
2283 : case PGBENCH_EQ:
2284 : case PGBENCH_NE:
2285 : case PGBENCH_LE:
2286 : case PGBENCH_LT:
2287 : {
2288 3366 : PgBenchValue *lval = &vargs[0],
2289 3366 : *rval = &vargs[1];
2290 :
2291 : Assert(nargs == 2);
2292 :
2293 : /* overloaded type management, double if some double */
2294 3366 : if ((lval->type == PGBT_DOUBLE ||
2295 3366 : rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
2296 0 : {
2297 : double ld,
2298 : rd;
2299 :
2300 62 : if (!coerceToDouble(lval, &ld) ||
2301 62 : !coerceToDouble(rval, &rd))
2302 62 : return false;
2303 :
2304 62 : switch (func)
2305 : {
2306 2 : case PGBENCH_ADD:
2307 2 : setDoubleValue(retval, ld + rd);
2308 2 : return true;
2309 :
2310 20 : case PGBENCH_SUB:
2311 20 : setDoubleValue(retval, ld - rd);
2312 20 : return true;
2313 :
2314 16 : case PGBENCH_MUL:
2315 16 : setDoubleValue(retval, ld * rd);
2316 16 : return true;
2317 :
2318 4 : case PGBENCH_DIV:
2319 4 : setDoubleValue(retval, ld / rd);
2320 4 : return true;
2321 :
2322 8 : case PGBENCH_EQ:
2323 8 : setBoolValue(retval, ld == rd);
2324 8 : return true;
2325 :
2326 4 : case PGBENCH_NE:
2327 4 : setBoolValue(retval, ld != rd);
2328 4 : return true;
2329 :
2330 4 : case PGBENCH_LE:
2331 4 : setBoolValue(retval, ld <= rd);
2332 4 : return true;
2333 :
2334 4 : case PGBENCH_LT:
2335 4 : setBoolValue(retval, ld < rd);
2336 4 : return true;
2337 :
2338 0 : default:
2339 : /* cannot get here */
2340 : Assert(0);
2341 : }
2342 : }
2343 : else /* we have integer operands, or % */
2344 : {
2345 : int64 li,
2346 : ri,
2347 : res;
2348 :
2349 3304 : if (!coerceToInt(lval, &li) ||
2350 3302 : !coerceToInt(rval, &ri))
2351 3304 : return false;
2352 :
2353 3302 : switch (func)
2354 : {
2355 88 : case PGBENCH_ADD:
2356 88 : if (pg_add_s64_overflow(li, ri, &res))
2357 : {
2358 2 : pg_log_error("bigint add out of range");
2359 2 : return false;
2360 : }
2361 86 : setIntValue(retval, res);
2362 86 : return true;
2363 :
2364 298 : case PGBENCH_SUB:
2365 298 : if (pg_sub_s64_overflow(li, ri, &res))
2366 : {
2367 2 : pg_log_error("bigint sub out of range");
2368 2 : return false;
2369 : }
2370 296 : setIntValue(retval, res);
2371 296 : return true;
2372 :
2373 2800 : case PGBENCH_MUL:
2374 2800 : if (pg_mul_s64_overflow(li, ri, &res))
2375 : {
2376 2 : pg_log_error("bigint mul out of range");
2377 2 : return false;
2378 : }
2379 2798 : setIntValue(retval, res);
2380 2798 : return true;
2381 :
2382 54 : case PGBENCH_EQ:
2383 54 : setBoolValue(retval, li == ri);
2384 54 : return true;
2385 :
2386 10 : case PGBENCH_NE:
2387 10 : setBoolValue(retval, li != ri);
2388 10 : return true;
2389 :
2390 10 : case PGBENCH_LE:
2391 10 : setBoolValue(retval, li <= ri);
2392 10 : return true;
2393 :
2394 24 : case PGBENCH_LT:
2395 24 : setBoolValue(retval, li < ri);
2396 24 : return true;
2397 :
2398 18 : case PGBENCH_DIV:
2399 : case PGBENCH_MOD:
2400 18 : if (ri == 0)
2401 : {
2402 2 : pg_log_error("division by zero");
2403 2 : return false;
2404 : }
2405 : /* special handling of -1 divisor */
2406 16 : if (ri == -1)
2407 : {
2408 6 : if (func == PGBENCH_DIV)
2409 : {
2410 : /* overflow check (needed for INT64_MIN) */
2411 4 : if (li == PG_INT64_MIN)
2412 : {
2413 2 : pg_log_error("bigint div out of range");
2414 2 : return false;
2415 : }
2416 : else
2417 2 : setIntValue(retval, -li);
2418 : }
2419 : else
2420 2 : setIntValue(retval, 0);
2421 4 : return true;
2422 : }
2423 : /* else divisor is not -1 */
2424 10 : if (func == PGBENCH_DIV)
2425 4 : setIntValue(retval, li / ri);
2426 : else /* func == PGBENCH_MOD */
2427 6 : setIntValue(retval, li % ri);
2428 :
2429 10 : return true;
2430 :
2431 0 : default:
2432 : /* cannot get here */
2433 : Assert(0);
2434 : }
2435 : }
2436 :
2437 : Assert(0);
2438 0 : return false; /* NOTREACHED */
2439 : }
2440 :
2441 : /* integer bitwise operators */
2442 28 : case PGBENCH_BITAND:
2443 : case PGBENCH_BITOR:
2444 : case PGBENCH_BITXOR:
2445 : case PGBENCH_LSHIFT:
2446 : case PGBENCH_RSHIFT:
2447 : {
2448 : int64 li,
2449 : ri;
2450 :
2451 28 : if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
2452 0 : return false;
2453 :
2454 28 : if (func == PGBENCH_BITAND)
2455 2 : setIntValue(retval, li & ri);
2456 26 : else if (func == PGBENCH_BITOR)
2457 4 : setIntValue(retval, li | ri);
2458 22 : else if (func == PGBENCH_BITXOR)
2459 6 : setIntValue(retval, li ^ ri);
2460 16 : else if (func == PGBENCH_LSHIFT)
2461 14 : setIntValue(retval, li << ri);
2462 2 : else if (func == PGBENCH_RSHIFT)
2463 2 : setIntValue(retval, li >> ri);
2464 : else /* cannot get here */
2465 : Assert(0);
2466 :
2467 28 : return true;
2468 : }
2469 :
2470 : /* logical operators */
2471 32 : case PGBENCH_NOT:
2472 : {
2473 : bool b;
2474 :
2475 32 : if (!coerceToBool(&vargs[0], &b))
2476 2 : return false;
2477 :
2478 30 : setBoolValue(retval, !b);
2479 30 : return true;
2480 : }
2481 :
2482 : /* no arguments */
2483 2 : case PGBENCH_PI:
2484 2 : setDoubleValue(retval, M_PI);
2485 2 : return true;
2486 :
2487 : /* 1 overloaded argument */
2488 4 : case PGBENCH_ABS:
2489 : {
2490 4 : PgBenchValue *varg = &vargs[0];
2491 :
2492 : Assert(nargs == 1);
2493 :
2494 4 : if (varg->type == PGBT_INT)
2495 : {
2496 2 : int64 i = varg->u.ival;
2497 :
2498 2 : setIntValue(retval, i < 0 ? -i : i);
2499 : }
2500 : else
2501 : {
2502 2 : double d = varg->u.dval;
2503 :
2504 : Assert(varg->type == PGBT_DOUBLE);
2505 2 : setDoubleValue(retval, d < 0.0 ? -d : d);
2506 : }
2507 :
2508 4 : return true;
2509 : }
2510 :
2511 168 : case PGBENCH_DEBUG:
2512 : {
2513 168 : PgBenchValue *varg = &vargs[0];
2514 :
2515 : Assert(nargs == 1);
2516 :
2517 168 : fprintf(stderr, "debug(script=%d,command=%d): ",
2518 168 : st->use_file, st->command + 1);
2519 :
2520 168 : if (varg->type == PGBT_NULL)
2521 4 : fprintf(stderr, "null\n");
2522 164 : else if (varg->type == PGBT_BOOLEAN)
2523 38 : fprintf(stderr, "boolean %s\n", varg->u.bval ? "true" : "false");
2524 126 : else if (varg->type == PGBT_INT)
2525 94 : fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
2526 32 : else if (varg->type == PGBT_DOUBLE)
2527 32 : fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
2528 : else /* internal error, unexpected type */
2529 : Assert(0);
2530 :
2531 168 : *retval = *varg;
2532 :
2533 168 : return true;
2534 : }
2535 :
2536 : /* 1 double argument */
2537 10 : case PGBENCH_DOUBLE:
2538 : case PGBENCH_SQRT:
2539 : case PGBENCH_LN:
2540 : case PGBENCH_EXP:
2541 : {
2542 : double dval;
2543 :
2544 : Assert(nargs == 1);
2545 :
2546 10 : if (!coerceToDouble(&vargs[0], &dval))
2547 2 : return false;
2548 :
2549 8 : if (func == PGBENCH_SQRT)
2550 2 : dval = sqrt(dval);
2551 6 : else if (func == PGBENCH_LN)
2552 2 : dval = log(dval);
2553 4 : else if (func == PGBENCH_EXP)
2554 2 : dval = exp(dval);
2555 : /* else is cast: do nothing */
2556 :
2557 8 : setDoubleValue(retval, dval);
2558 8 : return true;
2559 : }
2560 :
2561 : /* 1 int argument */
2562 4 : case PGBENCH_INT:
2563 : {
2564 : int64 ival;
2565 :
2566 : Assert(nargs == 1);
2567 :
2568 4 : if (!coerceToInt(&vargs[0], &ival))
2569 2 : return false;
2570 :
2571 2 : setIntValue(retval, ival);
2572 2 : return true;
2573 : }
2574 :
2575 : /* variable number of arguments */
2576 8 : case PGBENCH_LEAST:
2577 : case PGBENCH_GREATEST:
2578 : {
2579 : bool havedouble;
2580 : int i;
2581 :
2582 : Assert(nargs >= 1);
2583 :
2584 : /* need double result if any input is double */
2585 8 : havedouble = false;
2586 28 : for (i = 0; i < nargs; i++)
2587 : {
2588 24 : if (vargs[i].type == PGBT_DOUBLE)
2589 : {
2590 4 : havedouble = true;
2591 4 : break;
2592 : }
2593 : }
2594 8 : if (havedouble)
2595 : {
2596 : double extremum;
2597 :
2598 4 : if (!coerceToDouble(&vargs[0], &extremum))
2599 0 : return false;
2600 12 : for (i = 1; i < nargs; i++)
2601 : {
2602 : double dval;
2603 :
2604 8 : if (!coerceToDouble(&vargs[i], &dval))
2605 0 : return false;
2606 8 : if (func == PGBENCH_LEAST)
2607 4 : extremum = Min(extremum, dval);
2608 : else
2609 4 : extremum = Max(extremum, dval);
2610 : }
2611 4 : setDoubleValue(retval, extremum);
2612 : }
2613 : else
2614 : {
2615 : int64 extremum;
2616 :
2617 4 : if (!coerceToInt(&vargs[0], &extremum))
2618 0 : return false;
2619 16 : for (i = 1; i < nargs; i++)
2620 : {
2621 : int64 ival;
2622 :
2623 12 : if (!coerceToInt(&vargs[i], &ival))
2624 0 : return false;
2625 12 : if (func == PGBENCH_LEAST)
2626 6 : extremum = Min(extremum, ival);
2627 : else
2628 6 : extremum = Max(extremum, ival);
2629 : }
2630 4 : setIntValue(retval, extremum);
2631 : }
2632 8 : return true;
2633 : }
2634 :
2635 : /* random functions */
2636 3054 : case PGBENCH_RANDOM:
2637 : case PGBENCH_RANDOM_EXPONENTIAL:
2638 : case PGBENCH_RANDOM_GAUSSIAN:
2639 : case PGBENCH_RANDOM_ZIPFIAN:
2640 : {
2641 : int64 imin,
2642 : imax,
2643 : delta;
2644 :
2645 : Assert(nargs >= 2);
2646 :
2647 3054 : if (!coerceToInt(&vargs[0], &imin) ||
2648 3052 : !coerceToInt(&vargs[1], &imax))
2649 2 : return false;
2650 :
2651 : /* check random range */
2652 3052 : if (unlikely(imin > imax))
2653 : {
2654 2 : pg_log_error("empty range given to random");
2655 2 : return false;
2656 : }
2657 3050 : else if (unlikely(pg_sub_s64_overflow(imax, imin, &delta) ||
2658 : pg_add_s64_overflow(delta, 1, &delta)))
2659 : {
2660 : /* prevent int overflows in random functions */
2661 2 : pg_log_error("random range is too large");
2662 2 : return false;
2663 : }
2664 :
2665 3048 : if (func == PGBENCH_RANDOM)
2666 : {
2667 : Assert(nargs == 2);
2668 3022 : setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
2669 : }
2670 : else /* gaussian & exponential */
2671 : {
2672 : double param;
2673 :
2674 : Assert(nargs == 3);
2675 :
2676 26 : if (!coerceToDouble(&vargs[2], ¶m))
2677 8 : return false;
2678 :
2679 26 : if (func == PGBENCH_RANDOM_GAUSSIAN)
2680 : {
2681 8 : if (param < MIN_GAUSSIAN_PARAM)
2682 : {
2683 2 : pg_log_error("gaussian parameter must be at least %f (not %f)",
2684 : MIN_GAUSSIAN_PARAM, param);
2685 2 : return false;
2686 : }
2687 :
2688 6 : setIntValue(retval,
2689 : getGaussianRand(&st->cs_func_rs,
2690 : imin, imax, param));
2691 : }
2692 18 : else if (func == PGBENCH_RANDOM_ZIPFIAN)
2693 : {
2694 10 : if (param < MIN_ZIPFIAN_PARAM || param > MAX_ZIPFIAN_PARAM)
2695 : {
2696 4 : pg_log_error("zipfian parameter must be in range [%.3f, %.0f] (not %f)",
2697 : MIN_ZIPFIAN_PARAM, MAX_ZIPFIAN_PARAM, param);
2698 4 : return false;
2699 : }
2700 :
2701 6 : setIntValue(retval,
2702 : getZipfianRand(&st->cs_func_rs, imin, imax, param));
2703 : }
2704 : else /* exponential */
2705 : {
2706 8 : if (param <= 0.0)
2707 : {
2708 2 : pg_log_error("exponential parameter must be greater than zero (not %f)",
2709 : param);
2710 2 : return false;
2711 : }
2712 :
2713 6 : setIntValue(retval,
2714 : getExponentialRand(&st->cs_func_rs,
2715 : imin, imax, param));
2716 : }
2717 : }
2718 :
2719 3040 : return true;
2720 : }
2721 :
2722 18 : case PGBENCH_POW:
2723 : {
2724 18 : PgBenchValue *lval = &vargs[0];
2725 18 : PgBenchValue *rval = &vargs[1];
2726 : double ld,
2727 : rd;
2728 :
2729 : Assert(nargs == 2);
2730 :
2731 18 : if (!coerceToDouble(lval, &ld) ||
2732 18 : !coerceToDouble(rval, &rd))
2733 0 : return false;
2734 :
2735 18 : setDoubleValue(retval, pow(ld, rd));
2736 :
2737 18 : return true;
2738 : }
2739 :
2740 20 : case PGBENCH_IS:
2741 : {
2742 : Assert(nargs == 2);
2743 :
2744 : /*
2745 : * note: this simple implementation is more permissive than
2746 : * SQL
2747 : */
2748 20 : setBoolValue(retval,
2749 30 : vargs[0].type == vargs[1].type &&
2750 10 : vargs[0].u.bval == vargs[1].u.bval);
2751 20 : return true;
2752 : }
2753 :
2754 : /* hashing */
2755 12 : case PGBENCH_HASH_FNV1A:
2756 : case PGBENCH_HASH_MURMUR2:
2757 : {
2758 : int64 val,
2759 : seed;
2760 :
2761 : Assert(nargs == 2);
2762 :
2763 12 : if (!coerceToInt(&vargs[0], &val) ||
2764 12 : !coerceToInt(&vargs[1], &seed))
2765 0 : return false;
2766 :
2767 12 : if (func == PGBENCH_HASH_MURMUR2)
2768 10 : setIntValue(retval, getHashMurmur2(val, seed));
2769 2 : else if (func == PGBENCH_HASH_FNV1A)
2770 2 : setIntValue(retval, getHashFnv1a(val, seed));
2771 : else
2772 : /* cannot get here */
2773 : Assert(0);
2774 :
2775 12 : return true;
2776 : }
2777 :
2778 92 : case PGBENCH_PERMUTE:
2779 : {
2780 : int64 val,
2781 : size,
2782 : seed;
2783 :
2784 : Assert(nargs == 3);
2785 :
2786 92 : if (!coerceToInt(&vargs[0], &val) ||
2787 92 : !coerceToInt(&vargs[1], &size) ||
2788 92 : !coerceToInt(&vargs[2], &seed))
2789 0 : return false;
2790 :
2791 92 : if (size <= 0)
2792 : {
2793 2 : pg_log_error("permute size parameter must be greater than zero");
2794 2 : return false;
2795 : }
2796 :
2797 90 : setIntValue(retval, permute(val, size, seed));
2798 90 : return true;
2799 : }
2800 :
2801 0 : default:
2802 : /* cannot get here */
2803 : Assert(0);
2804 : /* dead code to avoid a compiler warning */
2805 0 : return false;
2806 : }
2807 : }
2808 :
2809 : /* evaluate some function */
2810 : static bool
2811 6956 : evalFunc(CState *st,
2812 : PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
2813 : {
2814 6956 : if (isLazyFunc(func))
2815 126 : return evalLazyFunc(st, func, args, retval);
2816 : else
2817 6830 : return evalStandardFunc(st, func, args, retval);
2818 : }
2819 :
2820 : /*
2821 : * Recursive evaluation of an expression in a pgbench script
2822 : * using the current state of variables.
2823 : * Returns whether the evaluation was ok,
2824 : * the value itself is returned through the retval pointer.
2825 : */
2826 : static bool
2827 18096 : evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
2828 : {
2829 18096 : switch (expr->etype)
2830 : {
2831 7312 : case ENODE_CONSTANT:
2832 : {
2833 7312 : *retval = expr->u.constant;
2834 7312 : return true;
2835 : }
2836 :
2837 3828 : case ENODE_VARIABLE:
2838 : {
2839 : Variable *var;
2840 :
2841 3828 : if ((var = lookupVariable(&st->variables, expr->u.variable.varname)) == NULL)
2842 : {
2843 4 : pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2844 4 : return false;
2845 : }
2846 :
2847 3824 : if (!makeVariableValue(var))
2848 4 : return false;
2849 :
2850 3820 : *retval = var->value;
2851 3820 : return true;
2852 : }
2853 :
2854 6956 : case ENODE_FUNCTION:
2855 6956 : return evalFunc(st,
2856 : expr->u.function.function,
2857 : expr->u.function.args,
2858 : retval);
2859 :
2860 0 : default:
2861 : /* internal error which should never occur */
2862 0 : pg_fatal("unexpected enode type in evaluation: %d", expr->etype);
2863 : }
2864 : }
2865 :
2866 : /*
2867 : * Convert command name to meta-command enum identifier
2868 : */
2869 : static MetaCommand
2870 938 : getMetaCommand(const char *cmd)
2871 : {
2872 : MetaCommand mc;
2873 :
2874 938 : if (cmd == NULL)
2875 0 : mc = META_NONE;
2876 938 : else if (pg_strcasecmp(cmd, "set") == 0)
2877 724 : mc = META_SET;
2878 214 : else if (pg_strcasecmp(cmd, "setshell") == 0)
2879 8 : mc = META_SETSHELL;
2880 206 : else if (pg_strcasecmp(cmd, "shell") == 0)
2881 10 : mc = META_SHELL;
2882 196 : else if (pg_strcasecmp(cmd, "sleep") == 0)
2883 18 : mc = META_SLEEP;
2884 178 : else if (pg_strcasecmp(cmd, "if") == 0)
2885 30 : mc = META_IF;
2886 148 : else if (pg_strcasecmp(cmd, "elif") == 0)
2887 16 : mc = META_ELIF;
2888 132 : else if (pg_strcasecmp(cmd, "else") == 0)
2889 16 : mc = META_ELSE;
2890 116 : else if (pg_strcasecmp(cmd, "endif") == 0)
2891 24 : mc = META_ENDIF;
2892 92 : else if (pg_strcasecmp(cmd, "gset") == 0)
2893 58 : mc = META_GSET;
2894 34 : else if (pg_strcasecmp(cmd, "aset") == 0)
2895 6 : mc = META_ASET;
2896 28 : else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2897 14 : mc = META_STARTPIPELINE;
2898 14 : else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2899 12 : mc = META_ENDPIPELINE;
2900 : else
2901 2 : mc = META_NONE;
2902 938 : return mc;
2903 : }
2904 :
2905 : /*
2906 : * Run a shell command. The result is assigned to the variable if not NULL.
2907 : * Return true if succeeded, or false on error.
2908 : */
2909 : static bool
2910 12 : runShellCommand(Variables *variables, char *variable, char **argv, int argc)
2911 : {
2912 : char command[SHELL_COMMAND_SIZE];
2913 : int i,
2914 12 : len = 0;
2915 : FILE *fp;
2916 : char res[64];
2917 : char *endptr;
2918 : int retval;
2919 :
2920 : /*----------
2921 : * Join arguments with whitespace separators. Arguments starting with
2922 : * exactly one colon are treated as variables:
2923 : * name - append a string "name"
2924 : * :var - append a variable named 'var'
2925 : * ::name - append a string ":name"
2926 : *----------
2927 : */
2928 34 : for (i = 0; i < argc; i++)
2929 : {
2930 : char *arg;
2931 : int arglen;
2932 :
2933 24 : if (argv[i][0] != ':')
2934 : {
2935 18 : arg = argv[i]; /* a string literal */
2936 : }
2937 6 : else if (argv[i][1] == ':')
2938 : {
2939 2 : arg = argv[i] + 1; /* a string literal starting with colons */
2940 : }
2941 4 : else if ((arg = getVariable(variables, argv[i] + 1)) == NULL)
2942 : {
2943 2 : pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[i]);
2944 2 : return false;
2945 : }
2946 :
2947 22 : arglen = strlen(arg);
2948 22 : if (len + arglen + (i > 0 ? 1 : 0) >= SHELL_COMMAND_SIZE - 1)
2949 : {
2950 0 : pg_log_error("%s: shell command is too long", argv[0]);
2951 0 : return false;
2952 : }
2953 :
2954 22 : if (i > 0)
2955 10 : command[len++] = ' ';
2956 22 : memcpy(command + len, arg, arglen);
2957 22 : len += arglen;
2958 : }
2959 :
2960 10 : command[len] = '\0';
2961 :
2962 10 : fflush(NULL); /* needed before either system() or popen() */
2963 :
2964 : /* Fast path for non-assignment case */
2965 10 : if (variable == NULL)
2966 : {
2967 4 : if (system(command))
2968 : {
2969 2 : if (!timer_exceeded)
2970 2 : pg_log_error("%s: could not launch shell command", argv[0]);
2971 2 : return false;
2972 : }
2973 2 : return true;
2974 : }
2975 :
2976 : /* Execute the command with pipe and read the standard output. */
2977 6 : if ((fp = popen(command, "r")) == NULL)
2978 : {
2979 0 : pg_log_error("%s: could not launch shell command", argv[0]);
2980 0 : return false;
2981 : }
2982 6 : if (fgets(res, sizeof(res), fp) == NULL)
2983 : {
2984 2 : if (!timer_exceeded)
2985 2 : pg_log_error("%s: could not read result of shell command", argv[0]);
2986 2 : (void) pclose(fp);
2987 2 : return false;
2988 : }
2989 4 : if (pclose(fp) < 0)
2990 : {
2991 0 : pg_log_error("%s: could not run shell command: %m", argv[0]);
2992 0 : return false;
2993 : }
2994 :
2995 : /* Check whether the result is an integer and assign it to the variable */
2996 4 : retval = (int) strtol(res, &endptr, 10);
2997 6 : while (*endptr != '\0' && isspace((unsigned char) *endptr))
2998 2 : endptr++;
2999 4 : if (*res == '\0' || *endptr != '\0')
3000 : {
3001 2 : pg_log_error("%s: shell command must return an integer (not \"%s\")", argv[0], res);
3002 2 : return false;
3003 : }
3004 2 : if (!putVariableInt(variables, "setshell", variable, retval))
3005 0 : return false;
3006 :
3007 2 : pg_log_debug("%s: shell parameter name: \"%s\", value: \"%s\"", argv[0], argv[1], res);
3008 :
3009 2 : return true;
3010 : }
3011 :
3012 : /*
3013 : * Report the abortion of the client when processing SQL commands.
3014 : */
3015 : static void
3016 62 : commandFailed(CState *st, const char *cmd, const char *message)
3017 : {
3018 62 : pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3019 : st->id, st->command, cmd, st->use_file, message);
3020 62 : }
3021 :
3022 : /*
3023 : * Report the error in the command while the script is executing.
3024 : */
3025 : static void
3026 4 : commandError(CState *st, const char *message)
3027 : {
3028 : Assert(sql_script[st->use_file].commands[st->command]->type == SQL_COMMAND);
3029 4 : pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3030 : st->id, st->command, st->use_file, message);
3031 4 : }
3032 :
3033 : /* return a script number with a weighted choice. */
3034 : static int
3035 4946 : chooseScript(TState *thread)
3036 : {
3037 4946 : int i = 0;
3038 : int64 w;
3039 :
3040 4946 : if (num_scripts == 1)
3041 2746 : return 0;
3042 :
3043 2200 : w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3044 : do
3045 : {
3046 4844 : w -= sql_script[i++].weight;
3047 4844 : } while (w >= 0);
3048 :
3049 2200 : return i - 1;
3050 : }
3051 :
3052 : /*
3053 : * Allocate space for CState->prepared: we need one boolean for each command
3054 : * of each script.
3055 : */
3056 : static void
3057 58 : allocCStatePrepared(CState *st)
3058 : {
3059 : Assert(st->prepared == NULL);
3060 :
3061 58 : st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3062 118 : for (int i = 0; i < num_scripts; i++)
3063 : {
3064 60 : ParsedScript *script = &sql_script[i];
3065 : int numcmds;
3066 :
3067 300 : for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3068 : ;
3069 60 : st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3070 : }
3071 58 : }
3072 :
3073 : /*
3074 : * Prepare the SQL command from st->use_file at command_num.
3075 : */
3076 : static void
3077 3544 : prepareCommand(CState *st, int command_num)
3078 : {
3079 3544 : Command *command = sql_script[st->use_file].commands[command_num];
3080 :
3081 : /* No prepare for non-SQL commands */
3082 3544 : if (command->type != SQL_COMMAND)
3083 0 : return;
3084 :
3085 3544 : if (!st->prepared)
3086 48 : allocCStatePrepared(st);
3087 :
3088 3544 : if (!st->prepared[st->use_file][command_num])
3089 : {
3090 : PGresult *res;
3091 :
3092 198 : pg_log_debug("client %d preparing %s", st->id, command->prepname);
3093 198 : res = PQprepare(st->con, command->prepname,
3094 198 : command->argv[0], command->argc - 1, NULL);
3095 198 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
3096 2 : pg_log_error("%s", PQerrorMessage(st->con));
3097 198 : PQclear(res);
3098 198 : st->prepared[st->use_file][command_num] = true;
3099 : }
3100 : }
3101 :
3102 : /*
3103 : * Prepare all the commands in the script that come after the \startpipeline
3104 : * that's at position st->command, and the first \endpipeline we find.
3105 : *
3106 : * This sets the ->prepared flag for each relevant command as well as the
3107 : * \startpipeline itself, but doesn't move the st->command counter.
3108 : */
3109 : static void
3110 84 : prepareCommandsInPipeline(CState *st)
3111 : {
3112 : int j;
3113 84 : Command **commands = sql_script[st->use_file].commands;
3114 :
3115 : Assert(commands[st->command]->type == META_COMMAND &&
3116 : commands[st->command]->meta == META_STARTPIPELINE);
3117 :
3118 84 : if (!st->prepared)
3119 10 : allocCStatePrepared(st);
3120 :
3121 : /*
3122 : * We set the 'prepared' flag on the \startpipeline itself to flag that we
3123 : * don't need to do this next time without calling prepareCommand(), even
3124 : * though we don't actually prepare this command.
3125 : */
3126 84 : if (st->prepared[st->use_file][st->command])
3127 72 : return;
3128 :
3129 128 : for (j = st->command + 1; commands[j] != NULL; j++)
3130 : {
3131 128 : if (commands[j]->type == META_COMMAND &&
3132 12 : commands[j]->meta == META_ENDPIPELINE)
3133 12 : break;
3134 :
3135 116 : prepareCommand(st, j);
3136 : }
3137 :
3138 12 : st->prepared[st->use_file][st->command] = true;
3139 : }
3140 :
3141 : /* Send a SQL command, using the chosen querymode */
3142 : static bool
3143 11216 : sendCommand(CState *st, Command *command)
3144 : {
3145 : int r;
3146 :
3147 11216 : if (querymode == QUERY_SIMPLE)
3148 : {
3149 : char *sql;
3150 :
3151 6648 : sql = pg_strdup(command->argv[0]);
3152 6648 : sql = assignVariables(&st->variables, sql);
3153 :
3154 6648 : pg_log_debug("client %d sending %s", st->id, sql);
3155 6648 : r = PQsendQuery(st->con, sql);
3156 6648 : free(sql);
3157 : }
3158 4568 : else if (querymode == QUERY_EXTENDED)
3159 : {
3160 1140 : const char *sql = command->argv[0];
3161 : const char *params[MAX_ARGS];
3162 :
3163 1140 : getQueryParams(&st->variables, command, params);
3164 :
3165 1140 : pg_log_debug("client %d sending %s", st->id, sql);
3166 1140 : r = PQsendQueryParams(st->con, sql, command->argc - 1,
3167 : NULL, params, NULL, NULL, 0);
3168 : }
3169 3428 : else if (querymode == QUERY_PREPARED)
3170 : {
3171 : const char *params[MAX_ARGS];
3172 :
3173 3428 : prepareCommand(st, st->command);
3174 3428 : getQueryParams(&st->variables, command, params);
3175 :
3176 3428 : pg_log_debug("client %d sending %s", st->id, command->prepname);
3177 3428 : r = PQsendQueryPrepared(st->con, command->prepname, command->argc - 1,
3178 : params, NULL, NULL, 0);
3179 : }
3180 : else /* unknown sql mode */
3181 0 : r = 0;
3182 :
3183 11216 : if (r == 0)
3184 : {
3185 0 : pg_log_debug("client %d could not send %s", st->id, command->argv[0]);
3186 0 : return false;
3187 : }
3188 : else
3189 11216 : return true;
3190 : }
3191 :
3192 : /*
3193 : * Get the error status from the error code.
3194 : */
3195 : static EStatus
3196 18 : getSQLErrorStatus(const char *sqlState)
3197 : {
3198 18 : if (sqlState != NULL)
3199 : {
3200 18 : if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3201 2 : return ESTATUS_SERIALIZATION_ERROR;
3202 16 : else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3203 2 : return ESTATUS_DEADLOCK_ERROR;
3204 : }
3205 :
3206 14 : return ESTATUS_OTHER_SQL_ERROR;
3207 : }
3208 :
3209 : /*
3210 : * Returns true if this type of error can be retried.
3211 : */
3212 : static bool
3213 50 : canRetryError(EStatus estatus)
3214 : {
3215 50 : return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3216 : estatus == ESTATUS_DEADLOCK_ERROR);
3217 : }
3218 :
3219 : /*
3220 : * Process query response from the backend.
3221 : *
3222 : * If varprefix is not NULL, it's the variable name prefix where to store
3223 : * the results of the *last* command (META_GSET) or *all* commands
3224 : * (META_ASET).
3225 : *
3226 : * Returns true if everything is A-OK, false if any error occurs.
3227 : */
3228 : static bool
3229 11302 : readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
3230 : {
3231 : PGresult *res;
3232 : PGresult *next_res;
3233 11302 : int qrynum = 0;
3234 :
3235 : /*
3236 : * varprefix should be set only with \gset or \aset, and \endpipeline and
3237 : * SQL commands do not need it.
3238 : */
3239 : Assert((meta == META_NONE && varprefix == NULL) ||
3240 : ((meta == META_ENDPIPELINE) && varprefix == NULL) ||
3241 : ((meta == META_GSET || meta == META_ASET) && varprefix != NULL));
3242 :
3243 11302 : res = PQgetResult(st->con);
3244 :
3245 22580 : while (res != NULL)
3246 : {
3247 : bool is_last;
3248 :
3249 : /* peek at the next result to know whether the current is last */
3250 11306 : next_res = PQgetResult(st->con);
3251 11306 : is_last = (next_res == NULL);
3252 :
3253 11306 : switch (PQresultStatus(res))
3254 : {
3255 6808 : case PGRES_COMMAND_OK: /* non-SELECT commands */
3256 : case PGRES_EMPTY_QUERY: /* may be used for testing no-op overhead */
3257 6808 : if (is_last && meta == META_GSET)
3258 : {
3259 2 : pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3260 : st->id, st->use_file, st->command, qrynum, 0);
3261 2 : st->estatus = ESTATUS_META_COMMAND_ERROR;
3262 2 : goto error;
3263 : }
3264 6806 : break;
3265 :
3266 4394 : case PGRES_TUPLES_OK:
3267 4394 : if ((is_last && meta == META_GSET) || meta == META_ASET)
3268 : {
3269 868 : int ntuples = PQntuples(res);
3270 :
3271 868 : if (meta == META_GSET && ntuples != 1)
3272 : {
3273 : /* under \gset, report the error */
3274 4 : pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3275 : st->id, st->use_file, st->command, qrynum, PQntuples(res));
3276 4 : st->estatus = ESTATUS_META_COMMAND_ERROR;
3277 4 : goto error;
3278 : }
3279 864 : else if (meta == META_ASET && ntuples <= 0)
3280 : {
3281 : /* coldly skip empty result under \aset */
3282 2 : break;
3283 : }
3284 :
3285 : /* store results into variables */
3286 1724 : for (int fld = 0; fld < PQnfields(res); fld++)
3287 : {
3288 866 : char *varname = PQfname(res, fld);
3289 :
3290 : /* allocate varname only if necessary, freed below */
3291 866 : if (*varprefix != '\0')
3292 2 : varname = psprintf("%s%s", varprefix, varname);
3293 :
3294 : /* store last row result as a string */
3295 866 : if (!putVariable(&st->variables, meta == META_ASET ? "aset" : "gset", varname,
3296 866 : PQgetvalue(res, ntuples - 1, fld)))
3297 : {
3298 : /* internal error */
3299 4 : pg_log_error("client %d script %d command %d query %d: error storing into variable %s",
3300 : st->id, st->use_file, st->command, qrynum, varname);
3301 4 : st->estatus = ESTATUS_META_COMMAND_ERROR;
3302 4 : goto error;
3303 : }
3304 :
3305 862 : if (*varprefix != '\0')
3306 2 : pg_free(varname);
3307 : }
3308 : }
3309 : /* otherwise the result is simply thrown away by PQclear below */
3310 4384 : break;
3311 :
3312 86 : case PGRES_PIPELINE_SYNC:
3313 86 : pg_log_debug("client %d pipeline ending", st->id);
3314 86 : if (PQexitPipelineMode(st->con) != 1)
3315 0 : pg_log_error("client %d failed to exit pipeline mode: %s", st->id,
3316 : PQerrorMessage(st->con));
3317 86 : break;
3318 :
3319 18 : case PGRES_NONFATAL_ERROR:
3320 : case PGRES_FATAL_ERROR:
3321 18 : st->estatus = getSQLErrorStatus(PQresultErrorField(res,
3322 : PG_DIAG_SQLSTATE));
3323 18 : if (canRetryError(st->estatus))
3324 : {
3325 4 : if (verbose_errors)
3326 4 : commandError(st, PQerrorMessage(st->con));
3327 4 : goto error;
3328 : }
3329 : /* fall through */
3330 :
3331 : default:
3332 : /* anything else is unexpected */
3333 14 : pg_log_error("client %d script %d aborted in command %d query %d: %s",
3334 : st->id, st->use_file, st->command, qrynum,
3335 : PQerrorMessage(st->con));
3336 14 : goto error;
3337 : }
3338 :
3339 11278 : PQclear(res);
3340 11278 : qrynum++;
3341 11278 : res = next_res;
3342 : }
3343 :
3344 11274 : if (qrynum == 0)
3345 : {
3346 0 : pg_log_error("client %d command %d: no results", st->id, st->command);
3347 0 : return false;
3348 : }
3349 :
3350 11274 : return true;
3351 :
3352 28 : error:
3353 28 : PQclear(res);
3354 28 : PQclear(next_res);
3355 : do
3356 : {
3357 28 : res = PQgetResult(st->con);
3358 28 : PQclear(res);
3359 28 : } while (res);
3360 :
3361 28 : return false;
3362 : }
3363 :
3364 : /*
3365 : * Parse the argument to a \sleep command, and return the requested amount
3366 : * of delay, in microseconds. Returns true on success, false on error.
3367 : */
3368 : static bool
3369 12 : evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
3370 : {
3371 : char *var;
3372 : int usec;
3373 :
3374 12 : if (*argv[1] == ':')
3375 : {
3376 6 : if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3377 : {
3378 2 : pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3379 2 : return false;
3380 : }
3381 :
3382 4 : usec = atoi(var);
3383 :
3384 : /* Raise an error if the value of a variable is not a number */
3385 4 : if (usec == 0 && !isdigit((unsigned char) *var))
3386 : {
3387 0 : pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3388 : argv[0], var, argv[1] + 1);
3389 0 : return false;
3390 : }
3391 : }
3392 : else
3393 6 : usec = atoi(argv[1]);
3394 :
3395 10 : if (argc > 2)
3396 : {
3397 8 : if (pg_strcasecmp(argv[2], "ms") == 0)
3398 4 : usec *= 1000;
3399 4 : else if (pg_strcasecmp(argv[2], "s") == 0)
3400 2 : usec *= 1000000;
3401 : }
3402 : else
3403 2 : usec *= 1000000;
3404 :
3405 10 : *usecs = usec;
3406 10 : return true;
3407 : }
3408 :
3409 :
3410 : /*
3411 : * Returns true if the error can be retried.
3412 : */
3413 : static bool
3414 4 : doRetry(CState *st, pg_time_usec_t *now)
3415 : {
3416 : Assert(st->estatus != ESTATUS_NO_ERROR);
3417 :
3418 : /* We can only retry serialization or deadlock errors. */
3419 4 : if (!canRetryError(st->estatus))
3420 0 : return false;
3421 :
3422 : /*
3423 : * We must have at least one option to limit the retrying of transactions
3424 : * that got an error.
3425 : */
3426 : Assert(max_tries || latency_limit || duration > 0);
3427 :
3428 : /*
3429 : * We cannot retry the error if we have reached the maximum number of
3430 : * tries.
3431 : */
3432 4 : if (max_tries && st->tries >= max_tries)
3433 0 : return false;
3434 :
3435 : /*
3436 : * We cannot retry the error if we spent too much time on this
3437 : * transaction.
3438 : */
3439 4 : if (latency_limit)
3440 : {
3441 0 : pg_time_now_lazy(now);
3442 0 : if (*now - st->txn_scheduled > latency_limit)
3443 0 : return false;
3444 : }
3445 :
3446 : /*
3447 : * We cannot retry the error if the benchmark duration is over.
3448 : */
3449 4 : if (timer_exceeded)
3450 0 : return false;
3451 :
3452 : /* OK */
3453 4 : return true;
3454 : }
3455 :
3456 : /*
3457 : * Read results and discard it until a sync point.
3458 : */
3459 : static int
3460 0 : discardUntilSync(CState *st)
3461 : {
3462 : /* send a sync */
3463 0 : if (!PQpipelineSync(st->con))
3464 : {
3465 0 : pg_log_error("client %d aborted: failed to send a pipeline sync",
3466 : st->id);
3467 0 : return 0;
3468 : }
3469 :
3470 : /* receive PGRES_PIPELINE_SYNC and null following it */
3471 : for (;;)
3472 0 : {
3473 0 : PGresult *res = PQgetResult(st->con);
3474 :
3475 0 : if (PQresultStatus(res) == PGRES_PIPELINE_SYNC)
3476 : {
3477 0 : PQclear(res);
3478 0 : res = PQgetResult(st->con);
3479 : Assert(res == NULL);
3480 0 : break;
3481 : }
3482 0 : PQclear(res);
3483 : }
3484 :
3485 : /* exit pipeline */
3486 0 : if (PQexitPipelineMode(st->con) != 1)
3487 : {
3488 0 : pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3489 : st->id);
3490 0 : return 0;
3491 : }
3492 0 : return 1;
3493 : }
3494 :
3495 : /*
3496 : * Get the transaction status at the end of a command especially for
3497 : * checking if we are in a (failed) transaction block.
3498 : */
3499 : static TStatus
3500 4862 : getTransactionStatus(PGconn *con)
3501 : {
3502 : PGTransactionStatusType tx_status;
3503 :
3504 4862 : tx_status = PQtransactionStatus(con);
3505 4862 : switch (tx_status)
3506 : {
3507 4858 : case PQTRANS_IDLE:
3508 4858 : return TSTATUS_IDLE;
3509 4 : case PQTRANS_INTRANS:
3510 : case PQTRANS_INERROR:
3511 4 : return TSTATUS_IN_BLOCK;
3512 0 : case PQTRANS_UNKNOWN:
3513 : /* PQTRANS_UNKNOWN is expected given a broken connection */
3514 0 : if (PQstatus(con) == CONNECTION_BAD)
3515 0 : return TSTATUS_CONN_ERROR;
3516 : /* fall through */
3517 : case PQTRANS_ACTIVE:
3518 : default:
3519 :
3520 : /*
3521 : * We cannot find out whether we are in a transaction block or
3522 : * not. Internal error which should never occur.
3523 : */
3524 0 : pg_log_error("unexpected transaction status %d", tx_status);
3525 0 : return TSTATUS_OTHER_ERROR;
3526 : }
3527 :
3528 : /* not reached */
3529 : Assert(false);
3530 : return TSTATUS_OTHER_ERROR;
3531 : }
3532 :
3533 : /*
3534 : * Print verbose messages of an error
3535 : */
3536 : static void
3537 4 : printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
3538 : {
3539 : static PQExpBuffer buf = NULL;
3540 :
3541 4 : if (buf == NULL)
3542 4 : buf = createPQExpBuffer();
3543 : else
3544 0 : resetPQExpBuffer(buf);
3545 :
3546 4 : printfPQExpBuffer(buf, "client %d ", st->id);
3547 4 : appendPQExpBufferStr(buf, (is_retry ?
3548 : "repeats the transaction after the error" :
3549 : "ends the failed transaction"));
3550 4 : appendPQExpBuffer(buf, " (try %u", st->tries);
3551 :
3552 : /* Print max_tries if it is not unlimited. */
3553 4 : if (max_tries)
3554 4 : appendPQExpBuffer(buf, "/%u", max_tries);
3555 :
3556 : /*
3557 : * If the latency limit is used, print a percentage of the current
3558 : * transaction latency from the latency limit.
3559 : */
3560 4 : if (latency_limit)
3561 : {
3562 0 : pg_time_now_lazy(now);
3563 0 : appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used",
3564 0 : (100.0 * (*now - st->txn_scheduled) / latency_limit));
3565 : }
3566 4 : appendPQExpBufferStr(buf, ")\n");
3567 :
3568 4 : pg_log_info("%s", buf->data);
3569 4 : }
3570 :
3571 : /*
3572 : * Advance the state machine of a connection.
3573 : */
3574 : static void
3575 15258 : advanceConnectionState(TState *thread, CState *st, StatsData *agg)
3576 : {
3577 :
3578 : /*
3579 : * gettimeofday() isn't free, so we get the current timestamp lazily the
3580 : * first time it's needed, and reuse the same value throughout this
3581 : * function after that. This also ensures that e.g. the calculated
3582 : * latency reported in the log file and in the totals are the same. Zero
3583 : * means "not set yet". Reset "now" when we execute shell commands or
3584 : * expressions, which might take a non-negligible amount of time, though.
3585 : */
3586 15258 : pg_time_usec_t now = 0;
3587 :
3588 : /*
3589 : * Loop in the state machine, until we have to wait for a result from the
3590 : * server or have to sleep for throttling or \sleep.
3591 : *
3592 : * Note: In the switch-statement below, 'break' will loop back here,
3593 : * meaning "continue in the state machine". Return is used to return to
3594 : * the caller, giving the thread the opportunity to advance another
3595 : * client.
3596 : */
3597 : for (;;)
3598 59204 : {
3599 : Command *command;
3600 :
3601 74462 : switch (st->state)
3602 : {
3603 : /* Select transaction (script) to run. */
3604 4946 : case CSTATE_CHOOSE_SCRIPT:
3605 4946 : st->use_file = chooseScript(thread);
3606 : Assert(conditional_stack_empty(st->cstack));
3607 :
3608 : /* reset transaction variables to default values */
3609 4946 : st->estatus = ESTATUS_NO_ERROR;
3610 4946 : st->tries = 1;
3611 :
3612 4946 : pg_log_debug("client %d executing script \"%s\"",
3613 : st->id, sql_script[st->use_file].desc);
3614 :
3615 : /*
3616 : * If time is over, we're done; otherwise, get ready to start
3617 : * a new transaction, or to get throttled if that's requested.
3618 : */
3619 9892 : st->state = timer_exceeded ? CSTATE_FINISHED :
3620 4946 : throttle_delay > 0 ? CSTATE_PREPARE_THROTTLE : CSTATE_START_TX;
3621 4946 : break;
3622 :
3623 : /* Start new transaction (script) */
3624 4944 : case CSTATE_START_TX:
3625 4944 : pg_time_now_lazy(&now);
3626 :
3627 : /* establish connection if needed, i.e. under --connect */
3628 4944 : if (st->con == NULL)
3629 : {
3630 220 : pg_time_usec_t start = now;
3631 :
3632 220 : if ((st->con = doConnect()) == NULL)
3633 : {
3634 : /*
3635 : * as the bench is already running, we do not abort
3636 : * the process
3637 : */
3638 0 : pg_log_error("client %d aborted while establishing connection", st->id);
3639 0 : st->state = CSTATE_ABORTED;
3640 0 : break;
3641 : }
3642 :
3643 : /* reset now after connection */
3644 220 : now = pg_time_now();
3645 :
3646 220 : thread->conn_duration += now - start;
3647 :
3648 : /* Reset session-local state */
3649 220 : pg_free(st->prepared);
3650 220 : st->prepared = NULL;
3651 : }
3652 :
3653 : /*
3654 : * It is the first try to run this transaction. Remember the
3655 : * random state: maybe it will get an error and we will need
3656 : * to run it again.
3657 : */
3658 4944 : st->random_state = st->cs_func_rs;
3659 :
3660 : /* record transaction start time */
3661 4944 : st->txn_begin = now;
3662 :
3663 : /*
3664 : * When not throttling, this is also the transaction's
3665 : * scheduled start time.
3666 : */
3667 4944 : if (!throttle_delay)
3668 4542 : st->txn_scheduled = now;
3669 :
3670 : /* Begin with the first command */
3671 4944 : st->state = CSTATE_START_COMMAND;
3672 4944 : st->command = 0;
3673 4944 : break;
3674 :
3675 : /*
3676 : * Handle throttling once per transaction by sleeping.
3677 : */
3678 420 : case CSTATE_PREPARE_THROTTLE:
3679 :
3680 : /*
3681 : * Generate a delay such that the series of delays will
3682 : * approximate a Poisson distribution centered on the
3683 : * throttle_delay time.
3684 : *
3685 : * If transactions are too slow or a given wait is shorter
3686 : * than a transaction, the next transaction will start right
3687 : * away.
3688 : */
3689 : Assert(throttle_delay > 0);
3690 :
3691 420 : thread->throttle_trigger +=
3692 420 : getPoissonRand(&thread->ts_throttle_rs, throttle_delay);
3693 420 : st->txn_scheduled = thread->throttle_trigger;
3694 :
3695 : /*
3696 : * If --latency-limit is used, and this slot is already late
3697 : * so that the transaction will miss the latency limit even if
3698 : * it completed immediately, skip this time slot and loop to
3699 : * reschedule.
3700 : */
3701 420 : if (latency_limit)
3702 : {
3703 420 : pg_time_now_lazy(&now);
3704 :
3705 420 : if (thread->throttle_trigger < now - latency_limit)
3706 : {
3707 18 : processXactStats(thread, st, &now, true, agg);
3708 :
3709 : /*
3710 : * Finish client if -T or -t was exceeded.
3711 : *
3712 : * Stop counting skipped transactions under -T as soon
3713 : * as the timer is exceeded. Because otherwise it can
3714 : * take a very long time to count all of them
3715 : * especially when quite a lot of them happen with
3716 : * unrealistically high rate setting in -R, which
3717 : * would prevent pgbench from ending immediately.
3718 : * Because of this behavior, note that there is no
3719 : * guarantee that all skipped transactions are counted
3720 : * under -T though there is under -t. This is OK in
3721 : * practice because it's very unlikely to happen with
3722 : * realistic setting.
3723 : */
3724 18 : if (timer_exceeded || (nxacts > 0 && st->cnt >= nxacts))
3725 2 : st->state = CSTATE_FINISHED;
3726 :
3727 : /* Go back to top of loop with CSTATE_PREPARE_THROTTLE */
3728 18 : break;
3729 : }
3730 : }
3731 :
3732 : /*
3733 : * stop client if next transaction is beyond pgbench end of
3734 : * execution; otherwise, throttle it.
3735 : */
3736 0 : st->state = end_time > 0 && st->txn_scheduled > end_time ?
3737 402 : CSTATE_FINISHED : CSTATE_THROTTLE;
3738 402 : break;
3739 :
3740 : /*
3741 : * Wait until it's time to start next transaction.
3742 : */
3743 402 : case CSTATE_THROTTLE:
3744 402 : pg_time_now_lazy(&now);
3745 :
3746 402 : if (now < st->txn_scheduled)
3747 0 : return; /* still sleeping, nothing to do here */
3748 :
3749 : /* done sleeping, but don't start transaction if we're done */
3750 402 : st->state = timer_exceeded ? CSTATE_FINISHED : CSTATE_START_TX;
3751 402 : break;
3752 :
3753 : /*
3754 : * Send a command to server (or execute a meta-command)
3755 : */
3756 20622 : case CSTATE_START_COMMAND:
3757 20622 : command = sql_script[st->use_file].commands[st->command];
3758 :
3759 : /* Transition to script end processing if done */
3760 20622 : if (command == NULL)
3761 : {
3762 4858 : st->state = CSTATE_END_TX;
3763 4858 : break;
3764 : }
3765 :
3766 : /* record begin time of next command, and initiate it */
3767 15764 : if (report_per_command)
3768 : {
3769 802 : pg_time_now_lazy(&now);
3770 802 : st->stmt_begin = now;
3771 : }
3772 :
3773 : /* Execute the command */
3774 15764 : if (command->type == SQL_COMMAND)
3775 : {
3776 : /* disallow \aset and \gset in pipeline mode */
3777 11218 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3778 : {
3779 1002 : if (command->meta == META_GSET)
3780 : {
3781 2 : commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
3782 2 : st->state = CSTATE_ABORTED;
3783 2 : break;
3784 : }
3785 1000 : else if (command->meta == META_ASET)
3786 : {
3787 0 : commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3788 0 : st->state = CSTATE_ABORTED;
3789 0 : break;
3790 : }
3791 : }
3792 :
3793 11216 : if (!sendCommand(st, command))
3794 : {
3795 0 : commandFailed(st, "SQL", "SQL command send failed");
3796 0 : st->state = CSTATE_ABORTED;
3797 : }
3798 : else
3799 : {
3800 : /* Wait for results, unless in pipeline mode */
3801 11216 : if (PQpipelineStatus(st->con) == PQ_PIPELINE_OFF)
3802 10216 : st->state = CSTATE_WAIT_RESULT;
3803 : else
3804 1000 : st->state = CSTATE_END_COMMAND;
3805 : }
3806 : }
3807 4546 : else if (command->type == META_COMMAND)
3808 : {
3809 : /*-----
3810 : * Possible state changes when executing meta commands:
3811 : * - on errors CSTATE_ABORTED
3812 : * - on sleep CSTATE_SLEEP
3813 : * - else CSTATE_END_COMMAND
3814 : */
3815 4546 : st->state = executeMetaCommand(st, &now);
3816 4546 : if (st->state == CSTATE_ABORTED)
3817 60 : st->estatus = ESTATUS_META_COMMAND_ERROR;
3818 : }
3819 :
3820 : /*
3821 : * We're now waiting for an SQL command to complete, or
3822 : * finished processing a metacommand, or need to sleep, or
3823 : * something bad happened.
3824 : */
3825 : Assert(st->state == CSTATE_WAIT_RESULT ||
3826 : st->state == CSTATE_END_COMMAND ||
3827 : st->state == CSTATE_SLEEP ||
3828 : st->state == CSTATE_ABORTED);
3829 15762 : break;
3830 :
3831 : /*
3832 : * non executed conditional branch
3833 : */
3834 3566 : case CSTATE_SKIP_COMMAND:
3835 : Assert(!conditional_active(st->cstack));
3836 : /* quickly skip commands until something to do... */
3837 : while (true)
3838 : {
3839 3566 : command = sql_script[st->use_file].commands[st->command];
3840 :
3841 : /* cannot reach end of script in that state */
3842 : Assert(command != NULL);
3843 :
3844 : /*
3845 : * if this is conditional related, update conditional
3846 : * state
3847 : */
3848 3566 : if (command->type == META_COMMAND &&
3849 782 : (command->meta == META_IF ||
3850 782 : command->meta == META_ELIF ||
3851 776 : command->meta == META_ELSE ||
3852 772 : command->meta == META_ENDIF))
3853 : {
3854 766 : switch (conditional_stack_peek(st->cstack))
3855 : {
3856 758 : case IFSTATE_FALSE:
3857 758 : if (command->meta == META_IF ||
3858 758 : command->meta == META_ELIF)
3859 : {
3860 : /* we must evaluate the condition */
3861 6 : st->state = CSTATE_START_COMMAND;
3862 : }
3863 752 : else if (command->meta == META_ELSE)
3864 : {
3865 : /* we must execute next command */
3866 2 : conditional_stack_poke(st->cstack,
3867 : IFSTATE_ELSE_TRUE);
3868 2 : st->state = CSTATE_START_COMMAND;
3869 2 : st->command++;
3870 : }
3871 750 : else if (command->meta == META_ENDIF)
3872 : {
3873 : Assert(!conditional_stack_empty(st->cstack));
3874 750 : conditional_stack_pop(st->cstack);
3875 750 : if (conditional_active(st->cstack))
3876 750 : st->state = CSTATE_START_COMMAND;
3877 :
3878 : /*
3879 : * else state remains in
3880 : * CSTATE_SKIP_COMMAND
3881 : */
3882 750 : st->command++;
3883 : }
3884 758 : break;
3885 :
3886 8 : case IFSTATE_IGNORED:
3887 : case IFSTATE_ELSE_FALSE:
3888 8 : if (command->meta == META_IF)
3889 0 : conditional_stack_push(st->cstack,
3890 : IFSTATE_IGNORED);
3891 8 : else if (command->meta == META_ENDIF)
3892 : {
3893 : Assert(!conditional_stack_empty(st->cstack));
3894 6 : conditional_stack_pop(st->cstack);
3895 6 : if (conditional_active(st->cstack))
3896 6 : st->state = CSTATE_START_COMMAND;
3897 : }
3898 : /* could detect "else" & "elif" after "else" */
3899 8 : st->command++;
3900 8 : break;
3901 :
3902 766 : case IFSTATE_NONE:
3903 : case IFSTATE_TRUE:
3904 : case IFSTATE_ELSE_TRUE:
3905 : default:
3906 :
3907 : /*
3908 : * inconsistent if inactive, unreachable dead
3909 : * code
3910 : */
3911 : Assert(false);
3912 : }
3913 : }
3914 : else
3915 : {
3916 : /* skip and consider next */
3917 2800 : st->command++;
3918 : }
3919 :
3920 3566 : if (st->state != CSTATE_SKIP_COMMAND)
3921 : /* out of quick skip command loop */
3922 764 : break;
3923 : }
3924 764 : break;
3925 :
3926 : /*
3927 : * Wait for the current SQL command to complete
3928 : */
3929 21606 : case CSTATE_WAIT_RESULT:
3930 21606 : pg_log_debug("client %d receiving", st->id);
3931 :
3932 : /*
3933 : * Only check for new network data if we processed all data
3934 : * fetched prior. Otherwise we end up doing a syscall for each
3935 : * individual pipelined query, which has a measurable
3936 : * performance impact.
3937 : */
3938 21606 : if (PQisBusy(st->con) && !PQconsumeInput(st->con))
3939 : {
3940 : /* there's something wrong */
3941 0 : commandFailed(st, "SQL", "perhaps the backend died while processing");
3942 0 : st->state = CSTATE_ABORTED;
3943 0 : break;
3944 : }
3945 21606 : if (PQisBusy(st->con))
3946 10304 : return; /* don't have the whole result yet */
3947 :
3948 : /* store or discard the query results */
3949 11302 : if (readCommandResponse(st,
3950 11302 : sql_script[st->use_file].commands[st->command]->meta,
3951 11302 : sql_script[st->use_file].commands[st->command]->varprefix))
3952 : {
3953 : /*
3954 : * outside of pipeline mode: stop reading results.
3955 : * pipeline mode: continue reading results until an
3956 : * end-of-pipeline response.
3957 : */
3958 11274 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3959 10274 : st->state = CSTATE_END_COMMAND;
3960 : }
3961 28 : else if (canRetryError(st->estatus))
3962 4 : st->state = CSTATE_ERROR;
3963 : else
3964 24 : st->state = CSTATE_ABORTED;
3965 11302 : break;
3966 :
3967 : /*
3968 : * Wait until sleep is done. This state is entered after a
3969 : * \sleep metacommand. The behavior is similar to
3970 : * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3971 : * instead of CSTATE_START_TX.
3972 : */
3973 16 : case CSTATE_SLEEP:
3974 16 : pg_time_now_lazy(&now);
3975 16 : if (now < st->sleep_until)
3976 6 : return; /* still sleeping, nothing to do here */
3977 : /* Else done sleeping. */
3978 10 : st->state = CSTATE_END_COMMAND;
3979 10 : break;
3980 :
3981 : /*
3982 : * End of command: record stats and proceed to next command.
3983 : */
3984 15674 : case CSTATE_END_COMMAND:
3985 :
3986 : /*
3987 : * command completed: accumulate per-command execution times
3988 : * in thread-local data structure, if per-command latencies
3989 : * are requested.
3990 : */
3991 15674 : if (report_per_command)
3992 : {
3993 802 : pg_time_now_lazy(&now);
3994 :
3995 802 : command = sql_script[st->use_file].commands[st->command];
3996 : /* XXX could use a mutex here, but we choose not to */
3997 802 : addToSimpleStats(&command->stats,
3998 802 : PG_TIME_GET_DOUBLE(now - st->stmt_begin));
3999 : }
4000 :
4001 : /* Go ahead with next command, to be executed or skipped */
4002 15674 : st->command++;
4003 15674 : st->state = conditional_active(st->cstack) ?
4004 15674 : CSTATE_START_COMMAND : CSTATE_SKIP_COMMAND;
4005 15674 : break;
4006 :
4007 : /*
4008 : * Clean up after an error.
4009 : */
4010 4 : case CSTATE_ERROR:
4011 : {
4012 : TStatus tstatus;
4013 :
4014 : Assert(st->estatus != ESTATUS_NO_ERROR);
4015 :
4016 : /* Clear the conditional stack */
4017 4 : conditional_stack_reset(st->cstack);
4018 :
4019 : /* Read and discard until a sync point in pipeline mode */
4020 4 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4021 : {
4022 0 : if (!discardUntilSync(st))
4023 : {
4024 0 : st->state = CSTATE_ABORTED;
4025 0 : break;
4026 : }
4027 : }
4028 :
4029 : /*
4030 : * Check if we have a (failed) transaction block or not,
4031 : * and roll it back if any.
4032 : */
4033 4 : tstatus = getTransactionStatus(st->con);
4034 4 : if (tstatus == TSTATUS_IN_BLOCK)
4035 : {
4036 : /* Try to rollback a (failed) transaction block. */
4037 2 : if (!PQsendQuery(st->con, "ROLLBACK"))
4038 : {
4039 0 : pg_log_error("client %d aborted: failed to send sql command for rolling back the failed transaction",
4040 : st->id);
4041 0 : st->state = CSTATE_ABORTED;
4042 : }
4043 : else
4044 2 : st->state = CSTATE_WAIT_ROLLBACK_RESULT;
4045 : }
4046 2 : else if (tstatus == TSTATUS_IDLE)
4047 : {
4048 : /*
4049 : * If time is over, we're done; otherwise, check if we
4050 : * can retry the error.
4051 : */
4052 4 : st->state = timer_exceeded ? CSTATE_FINISHED :
4053 2 : doRetry(st, &now) ? CSTATE_RETRY : CSTATE_FAILURE;
4054 : }
4055 : else
4056 : {
4057 0 : if (tstatus == TSTATUS_CONN_ERROR)
4058 0 : pg_log_error("perhaps the backend died while processing");
4059 :
4060 0 : pg_log_error("client %d aborted while receiving the transaction status", st->id);
4061 0 : st->state = CSTATE_ABORTED;
4062 : }
4063 4 : break;
4064 : }
4065 :
4066 : /*
4067 : * Wait for the rollback command to complete
4068 : */
4069 4 : case CSTATE_WAIT_ROLLBACK_RESULT:
4070 : {
4071 : PGresult *res;
4072 :
4073 4 : pg_log_debug("client %d receiving", st->id);
4074 4 : if (!PQconsumeInput(st->con))
4075 : {
4076 0 : pg_log_error("client %d aborted while rolling back the transaction after an error; perhaps the backend died while processing",
4077 : st->id);
4078 0 : st->state = CSTATE_ABORTED;
4079 0 : break;
4080 : }
4081 4 : if (PQisBusy(st->con))
4082 2 : return; /* don't have the whole result yet */
4083 :
4084 : /*
4085 : * Read and discard the query result;
4086 : */
4087 2 : res = PQgetResult(st->con);
4088 2 : switch (PQresultStatus(res))
4089 : {
4090 2 : case PGRES_COMMAND_OK:
4091 : /* OK */
4092 2 : PQclear(res);
4093 : /* null must be returned */
4094 2 : res = PQgetResult(st->con);
4095 : Assert(res == NULL);
4096 :
4097 : /*
4098 : * If time is over, we're done; otherwise, check
4099 : * if we can retry the error.
4100 : */
4101 4 : st->state = timer_exceeded ? CSTATE_FINISHED :
4102 2 : doRetry(st, &now) ? CSTATE_RETRY : CSTATE_FAILURE;
4103 2 : break;
4104 0 : default:
4105 0 : pg_log_error("client %d aborted while rolling back the transaction after an error; %s",
4106 : st->id, PQerrorMessage(st->con));
4107 0 : PQclear(res);
4108 0 : st->state = CSTATE_ABORTED;
4109 0 : break;
4110 : }
4111 2 : break;
4112 : }
4113 :
4114 : /*
4115 : * Retry the transaction after an error.
4116 : */
4117 4 : case CSTATE_RETRY:
4118 4 : command = sql_script[st->use_file].commands[st->command];
4119 :
4120 : /*
4121 : * Inform that the transaction will be retried after the
4122 : * error.
4123 : */
4124 4 : if (verbose_errors)
4125 4 : printVerboseErrorMessages(st, &now, true);
4126 :
4127 : /* Count tries and retries */
4128 4 : st->tries++;
4129 4 : command->retries++;
4130 :
4131 : /*
4132 : * Reset the random state as they were at the beginning of the
4133 : * transaction.
4134 : */
4135 4 : st->cs_func_rs = st->random_state;
4136 :
4137 : /* Process the first transaction command. */
4138 4 : st->command = 0;
4139 4 : st->estatus = ESTATUS_NO_ERROR;
4140 4 : st->state = CSTATE_START_COMMAND;
4141 4 : break;
4142 :
4143 : /*
4144 : * Record a failed transaction.
4145 : */
4146 0 : case CSTATE_FAILURE:
4147 0 : command = sql_script[st->use_file].commands[st->command];
4148 :
4149 : /* Accumulate the failure. */
4150 0 : command->failures++;
4151 :
4152 : /*
4153 : * Inform that the failed transaction will not be retried.
4154 : */
4155 0 : if (verbose_errors)
4156 0 : printVerboseErrorMessages(st, &now, false);
4157 :
4158 : /* End the failed transaction. */
4159 0 : st->state = CSTATE_END_TX;
4160 0 : break;
4161 :
4162 : /*
4163 : * End of transaction (end of script, really).
4164 : */
4165 4858 : case CSTATE_END_TX:
4166 : {
4167 : TStatus tstatus;
4168 :
4169 : /* transaction finished: calculate latency and do log */
4170 4858 : processXactStats(thread, st, &now, false, agg);
4171 :
4172 : /*
4173 : * missing \endif... cannot happen if CheckConditional was
4174 : * okay
4175 : */
4176 : Assert(conditional_stack_empty(st->cstack));
4177 :
4178 : /*
4179 : * We must complete all the transaction blocks that were
4180 : * started in this script.
4181 : */
4182 4858 : tstatus = getTransactionStatus(st->con);
4183 4858 : if (tstatus == TSTATUS_IN_BLOCK)
4184 : {
4185 2 : pg_log_error("client %d aborted: end of script reached without completing the last transaction",
4186 : st->id);
4187 2 : st->state = CSTATE_ABORTED;
4188 2 : break;
4189 : }
4190 4856 : else if (tstatus != TSTATUS_IDLE)
4191 : {
4192 0 : if (tstatus == TSTATUS_CONN_ERROR)
4193 0 : pg_log_error("perhaps the backend died while processing");
4194 :
4195 0 : pg_log_error("client %d aborted while receiving the transaction status", st->id);
4196 0 : st->state = CSTATE_ABORTED;
4197 0 : break;
4198 : }
4199 :
4200 4856 : if (is_connect)
4201 : {
4202 220 : pg_time_usec_t start = now;
4203 :
4204 220 : pg_time_now_lazy(&start);
4205 220 : finishCon(st);
4206 220 : now = pg_time_now();
4207 220 : thread->conn_duration += now - start;
4208 : }
4209 :
4210 4856 : if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
4211 : {
4212 : /* script completed */
4213 108 : st->state = CSTATE_FINISHED;
4214 108 : break;
4215 : }
4216 :
4217 : /* next transaction (script) */
4218 4748 : st->state = CSTATE_CHOOSE_SCRIPT;
4219 :
4220 : /*
4221 : * Ensure that we always return on this point, so as to
4222 : * avoid an infinite loop if the script only contains meta
4223 : * commands.
4224 : */
4225 4748 : return;
4226 : }
4227 :
4228 : /*
4229 : * Final states. Close the connection if it's still open.
4230 : */
4231 198 : case CSTATE_ABORTED:
4232 : case CSTATE_FINISHED:
4233 :
4234 : /*
4235 : * Don't measure the disconnection delays here even if in
4236 : * CSTATE_FINISHED and -C/--connect option is specified.
4237 : * Because in this case all the connections that this thread
4238 : * established are closed at the end of transactions and the
4239 : * disconnection delays should have already been measured at
4240 : * that moment.
4241 : *
4242 : * In CSTATE_ABORTED state, the measurement is no longer
4243 : * necessary because we cannot report complete results anyways
4244 : * in this case.
4245 : */
4246 198 : finishCon(st);
4247 198 : return;
4248 : }
4249 59204 : }
4250 : }
4251 :
4252 : /*
4253 : * Subroutine for advanceConnectionState -- initiate or execute the current
4254 : * meta command, and return the next state to set.
4255 : *
4256 : * *now is updated to the current time, unless the command is expected to
4257 : * take no time to execute.
4258 : */
4259 : static ConnectionStateEnum
4260 4546 : executeMetaCommand(CState *st, pg_time_usec_t *now)
4261 : {
4262 4546 : Command *command = sql_script[st->use_file].commands[st->command];
4263 : int argc;
4264 : char **argv;
4265 :
4266 : Assert(command != NULL && command->type == META_COMMAND);
4267 :
4268 4546 : argc = command->argc;
4269 4546 : argv = command->argv;
4270 :
4271 4546 : if (unlikely(__pg_log_level <= PG_LOG_DEBUG))
4272 : {
4273 : PQExpBufferData buf;
4274 :
4275 1406 : initPQExpBuffer(&buf);
4276 :
4277 1406 : printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4278 2812 : for (int i = 1; i < argc; i++)
4279 1406 : appendPQExpBuffer(&buf, " %s", argv[i]);
4280 :
4281 1406 : pg_log_debug("%s", buf.data);
4282 :
4283 1406 : termPQExpBuffer(&buf);
4284 : }
4285 :
4286 4546 : if (command->meta == META_SLEEP)
4287 : {
4288 : int usec;
4289 :
4290 : /*
4291 : * A \sleep doesn't execute anything, we just get the delay from the
4292 : * argument, and enter the CSTATE_SLEEP state. (The per-command
4293 : * latency will be recorded in CSTATE_SLEEP state, not here, after the
4294 : * delay has elapsed.)
4295 : */
4296 12 : if (!evaluateSleep(&st->variables, argc, argv, &usec))
4297 : {
4298 2 : commandFailed(st, "sleep", "execution of meta-command failed");
4299 2 : return CSTATE_ABORTED;
4300 : }
4301 :
4302 10 : pg_time_now_lazy(now);
4303 10 : st->sleep_until = (*now) + usec;
4304 10 : return CSTATE_SLEEP;
4305 : }
4306 4534 : else if (command->meta == META_SET)
4307 : {
4308 3422 : PgBenchExpr *expr = command->expr;
4309 : PgBenchValue result;
4310 :
4311 3422 : if (!evaluateExpr(st, expr, &result))
4312 : {
4313 44 : commandFailed(st, argv[0], "evaluation of meta-command failed");
4314 46 : return CSTATE_ABORTED;
4315 : }
4316 :
4317 3378 : if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4318 : {
4319 2 : commandFailed(st, "set", "assignment of meta-command failed");
4320 2 : return CSTATE_ABORTED;
4321 : }
4322 : }
4323 1112 : else if (command->meta == META_IF)
4324 : {
4325 : /* backslash commands with an expression to evaluate */
4326 832 : PgBenchExpr *expr = command->expr;
4327 : PgBenchValue result;
4328 : bool cond;
4329 :
4330 832 : if (!evaluateExpr(st, expr, &result))
4331 : {
4332 0 : commandFailed(st, argv[0], "evaluation of meta-command failed");
4333 0 : return CSTATE_ABORTED;
4334 : }
4335 :
4336 832 : cond = valueTruth(&result);
4337 832 : conditional_stack_push(st->cstack, cond ? IFSTATE_TRUE : IFSTATE_FALSE);
4338 : }
4339 280 : else if (command->meta == META_ELIF)
4340 : {
4341 : /* backslash commands with an expression to evaluate */
4342 10 : PgBenchExpr *expr = command->expr;
4343 : PgBenchValue result;
4344 : bool cond;
4345 :
4346 10 : if (conditional_stack_peek(st->cstack) == IFSTATE_TRUE)
4347 : {
4348 : /* elif after executed block, skip eval and wait for endif. */
4349 4 : conditional_stack_poke(st->cstack, IFSTATE_IGNORED);
4350 4 : return CSTATE_END_COMMAND;
4351 : }
4352 :
4353 6 : if (!evaluateExpr(st, expr, &result))
4354 : {
4355 0 : commandFailed(st, argv[0], "evaluation of meta-command failed");
4356 0 : return CSTATE_ABORTED;
4357 : }
4358 :
4359 6 : cond = valueTruth(&result);
4360 : Assert(conditional_stack_peek(st->cstack) == IFSTATE_FALSE);
4361 6 : conditional_stack_poke(st->cstack, cond ? IFSTATE_TRUE : IFSTATE_FALSE);
4362 : }
4363 270 : else if (command->meta == META_ELSE)
4364 : {
4365 2 : switch (conditional_stack_peek(st->cstack))
4366 : {
4367 2 : case IFSTATE_TRUE:
4368 2 : conditional_stack_poke(st->cstack, IFSTATE_ELSE_FALSE);
4369 2 : break;
4370 2 : case IFSTATE_FALSE: /* inconsistent if active */
4371 : case IFSTATE_IGNORED: /* inconsistent if active */
4372 : case IFSTATE_NONE: /* else without if */
4373 : case IFSTATE_ELSE_TRUE: /* else after else */
4374 : case IFSTATE_ELSE_FALSE: /* else after else */
4375 : default:
4376 : /* dead code if conditional check is ok */
4377 : Assert(false);
4378 : }
4379 : }
4380 268 : else if (command->meta == META_ENDIF)
4381 : {
4382 : Assert(!conditional_stack_empty(st->cstack));
4383 76 : conditional_stack_pop(st->cstack);
4384 : }
4385 192 : else if (command->meta == META_SETSHELL)
4386 : {
4387 6 : if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4388 : {
4389 4 : commandFailed(st, "setshell", "execution of meta-command failed");
4390 4 : return CSTATE_ABORTED;
4391 : }
4392 : }
4393 186 : else if (command->meta == META_SHELL)
4394 : {
4395 6 : if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4396 : {
4397 4 : commandFailed(st, "shell", "execution of meta-command failed");
4398 4 : return CSTATE_ABORTED;
4399 : }
4400 : }
4401 180 : else if (command->meta == META_STARTPIPELINE)
4402 : {
4403 : /*
4404 : * In pipeline mode, we use a workflow based on libpq pipeline
4405 : * functions.
4406 : */
4407 92 : if (querymode == QUERY_SIMPLE)
4408 : {
4409 0 : commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4410 0 : return CSTATE_ABORTED;
4411 : }
4412 :
4413 : /*
4414 : * If we're in prepared-query mode, we need to prepare all the
4415 : * commands that are inside the pipeline before we actually start the
4416 : * pipeline itself. This solves the problem that running BEGIN
4417 : * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4418 : * snapshot having been acquired by the prepare within the pipeline.
4419 : */
4420 92 : if (querymode == QUERY_PREPARED)
4421 84 : prepareCommandsInPipeline(st);
4422 :
4423 92 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4424 : {
4425 2 : commandFailed(st, "startpipeline", "already in pipeline mode");
4426 2 : return CSTATE_ABORTED;
4427 : }
4428 90 : if (PQenterPipelineMode(st->con) == 0)
4429 : {
4430 0 : commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4431 0 : return CSTATE_ABORTED;
4432 : }
4433 : }
4434 88 : else if (command->meta == META_ENDPIPELINE)
4435 : {
4436 88 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
4437 : {
4438 2 : commandFailed(st, "endpipeline", "not in pipeline mode");
4439 2 : return CSTATE_ABORTED;
4440 : }
4441 86 : if (!PQpipelineSync(st->con))
4442 : {
4443 0 : commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4444 0 : return CSTATE_ABORTED;
4445 : }
4446 : /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4447 : /* collect pending results before getting out of pipeline mode */
4448 86 : return CSTATE_WAIT_RESULT;
4449 : }
4450 :
4451 : /*
4452 : * executing the expression or shell command might have taken a
4453 : * non-negligible amount of time, so reset 'now'
4454 : */
4455 4386 : *now = 0;
4456 :
4457 4386 : return CSTATE_END_COMMAND;
4458 : }
4459 :
4460 : /*
4461 : * Return the number of failed transactions.
4462 : */
4463 : static int64
4464 154 : getFailures(const StatsData *stats)
4465 : {
4466 308 : return (stats->serialization_failures +
4467 154 : stats->deadlock_failures);
4468 : }
4469 :
4470 : /*
4471 : * Return a string constant representing the result of a transaction
4472 : * that is not successfully processed.
4473 : */
4474 : static const char *
4475 0 : getResultString(bool skipped, EStatus estatus)
4476 : {
4477 0 : if (skipped)
4478 0 : return "skipped";
4479 0 : else if (failures_detailed)
4480 : {
4481 0 : switch (estatus)
4482 : {
4483 0 : case ESTATUS_SERIALIZATION_ERROR:
4484 0 : return "serialization";
4485 0 : case ESTATUS_DEADLOCK_ERROR:
4486 0 : return "deadlock";
4487 0 : default:
4488 : /* internal error which should never occur */
4489 0 : pg_fatal("unexpected error status: %d", estatus);
4490 : }
4491 : }
4492 : else
4493 0 : return "failed";
4494 : }
4495 :
4496 : /*
4497 : * Print log entry after completing one transaction.
4498 : *
4499 : * We print Unix-epoch timestamps in the log, so that entries can be
4500 : * correlated against other logs.
4501 : *
4502 : * XXX We could obtain the time from the caller and just shift it here, to
4503 : * avoid the cost of an extra call to pg_time_now().
4504 : */
4505 : static void
4506 220 : doLog(TState *thread, CState *st,
4507 : StatsData *agg, bool skipped, double latency, double lag)
4508 : {
4509 220 : FILE *logfile = thread->logfile;
4510 220 : pg_time_usec_t now = pg_time_now() + epoch_shift;
4511 :
4512 : Assert(use_log);
4513 :
4514 : /*
4515 : * Skip the log entry if sampling is enabled and this row doesn't belong
4516 : * to the random sample.
4517 : */
4518 220 : if (sample_rate != 0.0 &&
4519 200 : pg_prng_double(&thread->ts_sample_rs) > sample_rate)
4520 104 : return;
4521 :
4522 : /* should we aggregate the results or not? */
4523 116 : if (agg_interval > 0)
4524 : {
4525 : pg_time_usec_t next;
4526 :
4527 : /*
4528 : * Loop until we reach the interval of the current moment, and print
4529 : * any empty intervals in between (this may happen with very low tps,
4530 : * e.g. --rate=0.1).
4531 : */
4532 :
4533 0 : while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4534 : {
4535 0 : double lag_sum = 0.0;
4536 0 : double lag_sum2 = 0.0;
4537 0 : double lag_min = 0.0;
4538 0 : double lag_max = 0.0;
4539 0 : int64 skipped = 0;
4540 0 : int64 serialization_failures = 0;
4541 0 : int64 deadlock_failures = 0;
4542 0 : int64 retried = 0;
4543 0 : int64 retries = 0;
4544 :
4545 : /* print aggregated report to logfile */
4546 0 : fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4547 0 : agg->start_time / 1000000, /* seconds since Unix epoch */
4548 : agg->cnt,
4549 : agg->latency.sum,
4550 : agg->latency.sum2,
4551 : agg->latency.min,
4552 : agg->latency.max);
4553 :
4554 0 : if (throttle_delay)
4555 : {
4556 0 : lag_sum = agg->lag.sum;
4557 0 : lag_sum2 = agg->lag.sum2;
4558 0 : lag_min = agg->lag.min;
4559 0 : lag_max = agg->lag.max;
4560 : }
4561 0 : fprintf(logfile, " %.0f %.0f %.0f %.0f",
4562 : lag_sum,
4563 : lag_sum2,
4564 : lag_min,
4565 : lag_max);
4566 :
4567 0 : if (latency_limit)
4568 0 : skipped = agg->skipped;
4569 0 : fprintf(logfile, " " INT64_FORMAT, skipped);
4570 :
4571 0 : if (max_tries != 1)
4572 : {
4573 0 : retried = agg->retried;
4574 0 : retries = agg->retries;
4575 : }
4576 0 : fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4577 :
4578 0 : if (failures_detailed)
4579 : {
4580 0 : serialization_failures = agg->serialization_failures;
4581 0 : deadlock_failures = agg->deadlock_failures;
4582 : }
4583 0 : fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT,
4584 : serialization_failures,
4585 : deadlock_failures);
4586 :
4587 0 : fputc('\n', logfile);
4588 :
4589 : /* reset data and move to next interval */
4590 0 : initStats(agg, next);
4591 : }
4592 :
4593 : /* accumulate the current transaction */
4594 0 : accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4595 : }
4596 : else
4597 : {
4598 : /* no, print raw transactions */
4599 116 : if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4600 116 : fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4601 : INT64_FORMAT,
4602 : st->id, st->cnt, latency, st->use_file,
4603 : now / 1000000, now % 1000000);
4604 : else
4605 0 : fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4606 : INT64_FORMAT,
4607 : st->id, st->cnt, getResultString(skipped, st->estatus),
4608 : st->use_file, now / 1000000, now % 1000000);
4609 :
4610 116 : if (throttle_delay)
4611 0 : fprintf(logfile, " %.0f", lag);
4612 116 : if (max_tries != 1)
4613 0 : fprintf(logfile, " %u", st->tries - 1);
4614 116 : fputc('\n', logfile);
4615 : }
4616 : }
4617 :
4618 : /*
4619 : * Accumulate and report statistics at end of a transaction.
4620 : *
4621 : * (This is also called when a transaction is late and thus skipped.
4622 : * Note that even skipped and failed transactions are counted in the CState
4623 : * "cnt" field.)
4624 : */
4625 : static void
4626 4876 : processXactStats(TState *thread, CState *st, pg_time_usec_t *now,
4627 : bool skipped, StatsData *agg)
4628 : {
4629 4876 : double latency = 0.0,
4630 4876 : lag = 0.0;
4631 4876 : bool detailed = progress || throttle_delay || latency_limit ||
4632 9752 : use_log || per_script_stats;
4633 :
4634 4876 : if (detailed && !skipped && st->estatus == ESTATUS_NO_ERROR)
4635 : {
4636 2822 : pg_time_now_lazy(now);
4637 :
4638 : /* compute latency & lag */
4639 2822 : latency = (*now) - st->txn_scheduled;
4640 2822 : lag = st->txn_begin - st->txn_scheduled;
4641 : }
4642 :
4643 : /* keep detailed thread stats */
4644 4876 : accumStats(&thread->stats, skipped, latency, lag, st->estatus, st->tries);
4645 :
4646 : /* count transactions over the latency limit, if needed */
4647 4876 : if (latency_limit && latency > latency_limit)
4648 2 : thread->latency_late++;
4649 :
4650 : /* client stat is just counting */
4651 4876 : st->cnt++;
4652 :
4653 4876 : if (use_log)
4654 220 : doLog(thread, st, agg, skipped, latency, lag);
4655 :
4656 : /* XXX could use a mutex here, but we choose not to */
4657 4876 : if (per_script_stats)
4658 2200 : accumStats(&sql_script[st->use_file].stats, skipped, latency, lag,
4659 2200 : st->estatus, st->tries);
4660 4876 : }
4661 :
4662 :
4663 : /* discard connections */
4664 : static void
4665 274 : disconnect_all(CState *state, int length)
4666 : {
4667 : int i;
4668 :
4669 670 : for (i = 0; i < length; i++)
4670 396 : finishCon(&state[i]);
4671 274 : }
4672 :
4673 : /*
4674 : * Remove old pgbench tables, if any exist
4675 : */
4676 : static void
4677 6 : initDropTables(PGconn *con)
4678 : {
4679 6 : fprintf(stderr, "dropping old tables...\n");
4680 :
4681 : /*
4682 : * We drop all the tables in one command, so that whether there are
4683 : * foreign key dependencies or not doesn't matter.
4684 : */
4685 6 : executeStatement(con, "drop table if exists "
4686 : "pgbench_accounts, "
4687 : "pgbench_branches, "
4688 : "pgbench_history, "
4689 : "pgbench_tellers");
4690 6 : }
4691 :
4692 : /*
4693 : * Create "pgbench_accounts" partitions if needed.
4694 : *
4695 : * This is the larger table of pgbench default tpc-b like schema
4696 : * with a known size, so we choose to partition it.
4697 : */
4698 : static void
4699 4 : createPartitions(PGconn *con)
4700 : {
4701 : PQExpBufferData query;
4702 :
4703 : /* we must have to create some partitions */
4704 : Assert(partitions > 0);
4705 :
4706 4 : fprintf(stderr, "creating %d partitions...\n", partitions);
4707 :
4708 4 : initPQExpBuffer(&query);
4709 :
4710 14 : for (int p = 1; p <= partitions; p++)
4711 : {
4712 10 : if (partition_method == PART_RANGE)
4713 : {
4714 6 : int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4715 :
4716 6 : printfPQExpBuffer(&query,
4717 : "create%s table pgbench_accounts_%d\n"
4718 : " partition of pgbench_accounts\n"
4719 : " for values from (",
4720 6 : unlogged_tables ? " unlogged" : "", p);
4721 :
4722 : /*
4723 : * For RANGE, we use open-ended partitions at the beginning and
4724 : * end to allow any valid value for the primary key. Although the
4725 : * actual minimum and maximum values can be derived from the
4726 : * scale, it is more generic and the performance is better.
4727 : */
4728 6 : if (p == 1)
4729 2 : appendPQExpBufferStr(&query, "minvalue");
4730 : else
4731 4 : appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4732 :
4733 6 : appendPQExpBufferStr(&query, ") to (");
4734 :
4735 6 : if (p < partitions)
4736 4 : appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4737 : else
4738 2 : appendPQExpBufferStr(&query, "maxvalue");
4739 :
4740 6 : appendPQExpBufferChar(&query, ')');
4741 : }
4742 4 : else if (partition_method == PART_HASH)
4743 4 : printfPQExpBuffer(&query,
4744 : "create%s table pgbench_accounts_%d\n"
4745 : " partition of pgbench_accounts\n"
4746 : " for values with (modulus %d, remainder %d)",
4747 4 : unlogged_tables ? " unlogged" : "", p,
4748 : partitions, p - 1);
4749 : else /* cannot get there */
4750 : Assert(0);
4751 :
4752 : /*
4753 : * Per ddlinfo in initCreateTables, fillfactor is needed on table
4754 : * pgbench_accounts.
4755 : */
4756 10 : appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4757 :
4758 10 : executeStatement(con, query.data);
4759 : }
4760 :
4761 4 : termPQExpBuffer(&query);
4762 4 : }
4763 :
4764 : /*
4765 : * Create pgbench's standard tables
4766 : */
4767 : static void
4768 6 : initCreateTables(PGconn *con)
4769 : {
4770 : /*
4771 : * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4772 : * fields in these table declarations were intended to comply with that.
4773 : * The pgbench_accounts table complies with that because the "filler"
4774 : * column is set to blank-padded empty string. But for all other tables
4775 : * the columns default to NULL and so don't actually take any space. We
4776 : * could fix that by giving them non-null default values. However, that
4777 : * would completely break comparability of pgbench results with prior
4778 : * versions. Since pgbench has never pretended to be fully TPC-B compliant
4779 : * anyway, we stick with the historical behavior.
4780 : */
4781 : struct ddlinfo
4782 : {
4783 : const char *table; /* table name */
4784 : const char *smcols; /* column decls if accountIDs are 32 bits */
4785 : const char *bigcols; /* column decls if accountIDs are 64 bits */
4786 : int declare_fillfactor;
4787 : };
4788 : static const struct ddlinfo DDLs[] = {
4789 : {
4790 : "pgbench_history",
4791 : "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4792 : "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4793 : 0
4794 : },
4795 : {
4796 : "pgbench_tellers",
4797 : "tid int not null,bid int,tbalance int,filler char(84)",
4798 : "tid int not null,bid int,tbalance int,filler char(84)",
4799 : 1
4800 : },
4801 : {
4802 : "pgbench_accounts",
4803 : "aid int not null,bid int,abalance int,filler char(84)",
4804 : "aid bigint not null,bid int,abalance int,filler char(84)",
4805 : 1
4806 : },
4807 : {
4808 : "pgbench_branches",
4809 : "bid int not null,bbalance int,filler char(88)",
4810 : "bid int not null,bbalance int,filler char(88)",
4811 : 1
4812 : }
4813 : };
4814 : int i;
4815 : PQExpBufferData query;
4816 :
4817 6 : fprintf(stderr, "creating tables...\n");
4818 :
4819 6 : initPQExpBuffer(&query);
4820 :
4821 30 : for (i = 0; i < lengthof(DDLs); i++)
4822 : {
4823 24 : const struct ddlinfo *ddl = &DDLs[i];
4824 :
4825 : /* Construct new create table statement. */
4826 48 : printfPQExpBuffer(&query, "create%s table %s(%s)",
4827 24 : unlogged_tables ? " unlogged" : "",
4828 : ddl->table,
4829 24 : (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4830 :
4831 : /* Partition pgbench_accounts table */
4832 24 : if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4833 4 : appendPQExpBuffer(&query,
4834 : " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4835 20 : else if (ddl->declare_fillfactor)
4836 : {
4837 : /* fillfactor is only expected on actual tables */
4838 14 : appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4839 : }
4840 :
4841 24 : if (tablespace != NULL)
4842 : {
4843 : char *escape_tablespace;
4844 :
4845 8 : escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4846 8 : appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4847 8 : PQfreemem(escape_tablespace);
4848 : }
4849 :
4850 24 : executeStatement(con, query.data);
4851 : }
4852 :
4853 6 : termPQExpBuffer(&query);
4854 :
4855 6 : if (partition_method != PART_NONE)
4856 4 : createPartitions(con);
4857 6 : }
4858 :
4859 : /*
4860 : * Truncate away any old data, in one command in case there are foreign keys
4861 : */
4862 : static void
4863 6 : initTruncateTables(PGconn *con)
4864 : {
4865 6 : executeStatement(con, "truncate table "
4866 : "pgbench_accounts, "
4867 : "pgbench_branches, "
4868 : "pgbench_history, "
4869 : "pgbench_tellers");
4870 6 : }
4871 :
4872 : /*
4873 : * Fill the standard tables with some data generated and sent from the client
4874 : */
4875 : static void
4876 4 : initGenerateDataClientSide(PGconn *con)
4877 : {
4878 : PQExpBufferData sql;
4879 : PGresult *res;
4880 : int i;
4881 : int64 k;
4882 : char *copy_statement;
4883 :
4884 : /* used to track elapsed time and estimate of the remaining time */
4885 : pg_time_usec_t start;
4886 4 : int log_interval = 1;
4887 :
4888 : /* Stay on the same line if reporting to a terminal */
4889 4 : char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4890 :
4891 4 : fprintf(stderr, "generating data (client-side)...\n");
4892 :
4893 : /*
4894 : * we do all of this in one transaction to enable the backend's
4895 : * data-loading optimizations
4896 : */
4897 4 : executeStatement(con, "begin");
4898 :
4899 : /* truncate away any old data */
4900 4 : initTruncateTables(con);
4901 :
4902 4 : initPQExpBuffer(&sql);
4903 :
4904 : /*
4905 : * fill branches, tellers, accounts in that order in case foreign keys
4906 : * already exist
4907 : */
4908 8 : for (i = 0; i < nbranches * scale; i++)
4909 : {
4910 : /* "filler" column defaults to NULL */
4911 4 : printfPQExpBuffer(&sql,
4912 : "insert into pgbench_branches(bid,bbalance) values(%d,0)",
4913 : i + 1);
4914 4 : executeStatement(con, sql.data);
4915 : }
4916 :
4917 44 : for (i = 0; i < ntellers * scale; i++)
4918 : {
4919 : /* "filler" column defaults to NULL */
4920 40 : printfPQExpBuffer(&sql,
4921 : "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
4922 40 : i + 1, i / ntellers + 1);
4923 40 : executeStatement(con, sql.data);
4924 : }
4925 :
4926 : /*
4927 : * accounts is big enough to be worth using COPY and tracking runtime
4928 : */
4929 :
4930 : /* use COPY with FREEZE on v14 and later without partitioning */
4931 4 : if (partitions == 0 && PQserverVersion(con) >= 140000)
4932 2 : copy_statement = "copy pgbench_accounts from stdin with (freeze on)";
4933 : else
4934 2 : copy_statement = "copy pgbench_accounts from stdin";
4935 :
4936 4 : res = PQexec(con, copy_statement);
4937 :
4938 4 : if (PQresultStatus(res) != PGRES_COPY_IN)
4939 0 : pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
4940 4 : PQclear(res);
4941 :
4942 4 : start = pg_time_now();
4943 :
4944 400004 : for (k = 0; k < (int64) naccounts * scale; k++)
4945 : {
4946 400000 : int64 j = k + 1;
4947 :
4948 : /* "filler" column defaults to blank padded empty string */
4949 400000 : printfPQExpBuffer(&sql,
4950 : INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
4951 400000 : j, k / naccounts + 1, 0);
4952 400000 : if (PQputline(con, sql.data))
4953 0 : pg_fatal("PQputline failed");
4954 :
4955 400000 : if (CancelRequested)
4956 0 : break;
4957 :
4958 : /*
4959 : * If we want to stick with the original logging, print a message each
4960 : * 100k inserted rows.
4961 : */
4962 400000 : if ((!use_quiet) && (j % 100000 == 0))
4963 2 : {
4964 2 : double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4965 2 : double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4966 :
4967 2 : fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4968 : j, (int64) naccounts * scale,
4969 2 : (int) (((int64) j * 100) / (naccounts * (int64) scale)),
4970 : elapsed_sec, remaining_sec, eol);
4971 : }
4972 : /* let's not call the timing for each row, but only each 100 rows */
4973 399998 : else if (use_quiet && (j % 100 == 0))
4974 : {
4975 2000 : double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4976 2000 : double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4977 :
4978 : /* have we reached the next interval (or end)? */
4979 2000 : if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
4980 : {
4981 2 : fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4982 : j, (int64) naccounts * scale,
4983 2 : (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
4984 :
4985 : /* skip to the next interval */
4986 2 : log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
4987 : }
4988 : }
4989 : }
4990 :
4991 4 : if (eol != '\n')
4992 0 : fputc('\n', stderr); /* Need to move to next line */
4993 :
4994 4 : if (PQputline(con, "\\.\n"))
4995 0 : pg_fatal("very last PQputline failed");
4996 4 : if (PQendcopy(con))
4997 0 : pg_fatal("PQendcopy failed");
4998 :
4999 4 : termPQExpBuffer(&sql);
5000 :
5001 4 : executeStatement(con, "commit");
5002 4 : }
5003 :
5004 : /*
5005 : * Fill the standard tables with some data generated on the server
5006 : *
5007 : * As already the case with the client-side data generation, the filler
5008 : * column defaults to NULL in pgbench_branches and pgbench_tellers,
5009 : * and is a blank-padded string in pgbench_accounts.
5010 : */
5011 : static void
5012 2 : initGenerateDataServerSide(PGconn *con)
5013 : {
5014 : PQExpBufferData sql;
5015 :
5016 2 : fprintf(stderr, "generating data (server-side)...\n");
5017 :
5018 : /*
5019 : * we do all of this in one transaction to enable the backend's
5020 : * data-loading optimizations
5021 : */
5022 2 : executeStatement(con, "begin");
5023 :
5024 : /* truncate away any old data */
5025 2 : initTruncateTables(con);
5026 :
5027 2 : initPQExpBuffer(&sql);
5028 :
5029 2 : printfPQExpBuffer(&sql,
5030 : "insert into pgbench_branches(bid,bbalance) "
5031 : "select bid, 0 "
5032 : "from generate_series(1, %d) as bid", nbranches * scale);
5033 2 : executeStatement(con, sql.data);
5034 :
5035 2 : printfPQExpBuffer(&sql,
5036 : "insert into pgbench_tellers(tid,bid,tbalance) "
5037 : "select tid, (tid - 1) / %d + 1, 0 "
5038 : "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5039 2 : executeStatement(con, sql.data);
5040 :
5041 2 : printfPQExpBuffer(&sql,
5042 : "insert into pgbench_accounts(aid,bid,abalance,filler) "
5043 : "select aid, (aid - 1) / %d + 1, 0, '' "
5044 : "from generate_series(1, " INT64_FORMAT ") as aid",
5045 : naccounts, (int64) naccounts * scale);
5046 2 : executeStatement(con, sql.data);
5047 :
5048 2 : termPQExpBuffer(&sql);
5049 :
5050 2 : executeStatement(con, "commit");
5051 2 : }
5052 :
5053 : /*
5054 : * Invoke vacuum on the standard tables
5055 : */
5056 : static void
5057 4 : initVacuum(PGconn *con)
5058 : {
5059 4 : fprintf(stderr, "vacuuming...\n");
5060 4 : executeStatement(con, "vacuum analyze pgbench_branches");
5061 4 : executeStatement(con, "vacuum analyze pgbench_tellers");
5062 4 : executeStatement(con, "vacuum analyze pgbench_accounts");
5063 4 : executeStatement(con, "vacuum analyze pgbench_history");
5064 4 : }
5065 :
5066 : /*
5067 : * Create primary keys on the standard tables
5068 : */
5069 : static void
5070 6 : initCreatePKeys(PGconn *con)
5071 : {
5072 : static const char *const DDLINDEXes[] = {
5073 : "alter table pgbench_branches add primary key (bid)",
5074 : "alter table pgbench_tellers add primary key (tid)",
5075 : "alter table pgbench_accounts add primary key (aid)"
5076 : };
5077 : int i;
5078 : PQExpBufferData query;
5079 :
5080 6 : fprintf(stderr, "creating primary keys...\n");
5081 6 : initPQExpBuffer(&query);
5082 :
5083 24 : for (i = 0; i < lengthof(DDLINDEXes); i++)
5084 : {
5085 18 : resetPQExpBuffer(&query);
5086 18 : appendPQExpBufferStr(&query, DDLINDEXes[i]);
5087 :
5088 18 : if (index_tablespace != NULL)
5089 : {
5090 : char *escape_tablespace;
5091 :
5092 6 : escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5093 : strlen(index_tablespace));
5094 6 : appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5095 6 : PQfreemem(escape_tablespace);
5096 : }
5097 :
5098 18 : executeStatement(con, query.data);
5099 : }
5100 :
5101 6 : termPQExpBuffer(&query);
5102 6 : }
5103 :
5104 : /*
5105 : * Create foreign key constraints between the standard tables
5106 : */
5107 : static void
5108 4 : initCreateFKeys(PGconn *con)
5109 : {
5110 : static const char *const DDLKEYs[] = {
5111 : "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5112 : "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5113 : "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5114 : "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5115 : "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5116 : };
5117 : int i;
5118 :
5119 4 : fprintf(stderr, "creating foreign keys...\n");
5120 24 : for (i = 0; i < lengthof(DDLKEYs); i++)
5121 : {
5122 20 : executeStatement(con, DDLKEYs[i]);
5123 : }
5124 4 : }
5125 :
5126 : /*
5127 : * Validate an initialization-steps string
5128 : *
5129 : * (We could just leave it to runInitSteps() to fail if there are wrong
5130 : * characters, but since initialization can take awhile, it seems friendlier
5131 : * to check during option parsing.)
5132 : */
5133 : static void
5134 8 : checkInitSteps(const char *initialize_steps)
5135 : {
5136 8 : if (initialize_steps[0] == '\0')
5137 0 : pg_fatal("no initialization steps specified");
5138 :
5139 42 : for (const char *step = initialize_steps; *step != '\0'; step++)
5140 : {
5141 36 : if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5142 : {
5143 2 : pg_log_error("unrecognized initialization step \"%c\"", *step);
5144 2 : pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5145 2 : exit(1);
5146 : }
5147 : }
5148 6 : }
5149 :
5150 : /*
5151 : * Invoke each initialization step in the given string
5152 : */
5153 : static void
5154 6 : runInitSteps(const char *initialize_steps)
5155 : {
5156 : PQExpBufferData stats;
5157 : PGconn *con;
5158 : const char *step;
5159 6 : double run_time = 0.0;
5160 6 : bool first = true;
5161 :
5162 6 : initPQExpBuffer(&stats);
5163 :
5164 6 : if ((con = doConnect()) == NULL)
5165 0 : pg_fatal("could not create connection for initialization");
5166 :
5167 6 : setup_cancel_handler(NULL);
5168 6 : SetCancelConn(con);
5169 :
5170 44 : for (step = initialize_steps; *step != '\0'; step++)
5171 : {
5172 38 : char *op = NULL;
5173 38 : pg_time_usec_t start = pg_time_now();
5174 :
5175 38 : switch (*step)
5176 : {
5177 6 : case 'd':
5178 6 : op = "drop tables";
5179 6 : initDropTables(con);
5180 6 : break;
5181 6 : case 't':
5182 6 : op = "create tables";
5183 6 : initCreateTables(con);
5184 6 : break;
5185 4 : case 'g':
5186 4 : op = "client-side generate";
5187 4 : initGenerateDataClientSide(con);
5188 4 : break;
5189 2 : case 'G':
5190 2 : op = "server-side generate";
5191 2 : initGenerateDataServerSide(con);
5192 2 : break;
5193 4 : case 'v':
5194 4 : op = "vacuum";
5195 4 : initVacuum(con);
5196 4 : break;
5197 6 : case 'p':
5198 6 : op = "primary keys";
5199 6 : initCreatePKeys(con);
5200 6 : break;
5201 4 : case 'f':
5202 4 : op = "foreign keys";
5203 4 : initCreateFKeys(con);
5204 4 : break;
5205 6 : case ' ':
5206 6 : break; /* ignore */
5207 0 : default:
5208 0 : pg_log_error("unrecognized initialization step \"%c\"", *step);
5209 0 : PQfinish(con);
5210 0 : exit(1);
5211 : }
5212 :
5213 38 : if (op != NULL)
5214 : {
5215 32 : double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5216 :
5217 32 : if (!first)
5218 26 : appendPQExpBufferStr(&stats, ", ");
5219 : else
5220 6 : first = false;
5221 :
5222 32 : appendPQExpBuffer(&stats, "%s %.2f s", op, elapsed_sec);
5223 :
5224 32 : run_time += elapsed_sec;
5225 : }
5226 : }
5227 :
5228 6 : fprintf(stderr, "done in %.2f s (%s).\n", run_time, stats.data);
5229 6 : ResetCancelConn();
5230 6 : PQfinish(con);
5231 6 : termPQExpBuffer(&stats);
5232 6 : }
5233 :
5234 : /*
5235 : * Extract pgbench table information into global variables scale,
5236 : * partition_method and partitions.
5237 : */
5238 : static void
5239 14 : GetTableInfo(PGconn *con, bool scale_given)
5240 : {
5241 : PGresult *res;
5242 :
5243 : /*
5244 : * get the scaling factor that should be same as count(*) from
5245 : * pgbench_branches if this is not a custom query
5246 : */
5247 14 : res = PQexec(con, "select count(*) from pgbench_branches");
5248 14 : if (PQresultStatus(res) != PGRES_TUPLES_OK)
5249 : {
5250 2 : char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5251 :
5252 2 : pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5253 :
5254 2 : if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5255 2 : pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5256 : PQdb(con));
5257 :
5258 2 : exit(1);
5259 : }
5260 12 : scale = atoi(PQgetvalue(res, 0, 0));
5261 12 : if (scale < 0)
5262 0 : pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5263 : PQgetvalue(res, 0, 0));
5264 12 : PQclear(res);
5265 :
5266 : /* warn if we override user-given -s switch */
5267 12 : if (scale_given)
5268 2 : pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5269 : scale);
5270 :
5271 : /*
5272 : * Get the partition information for the first "pgbench_accounts" table
5273 : * found in search_path.
5274 : *
5275 : * The result is empty if no "pgbench_accounts" is found.
5276 : *
5277 : * Otherwise, it always returns one row even if the table is not
5278 : * partitioned (in which case the partition strategy is NULL).
5279 : *
5280 : * The number of partitions can be 0 even for partitioned tables, if no
5281 : * partition is attached.
5282 : *
5283 : * We assume no partitioning on any failure, so as to avoid failing on an
5284 : * old version without "pg_partitioned_table".
5285 : */
5286 12 : res = PQexec(con,
5287 : "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5288 : "from pg_catalog.pg_class as c "
5289 : "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5290 : "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5291 : "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5292 : "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5293 : "where c.relname = 'pgbench_accounts' and o.n is not null "
5294 : "group by 1, 2 "
5295 : "order by 1 asc "
5296 : "limit 1");
5297 :
5298 12 : if (PQresultStatus(res) != PGRES_TUPLES_OK)
5299 : {
5300 : /* probably an older version, coldly assume no partitioning */
5301 0 : partition_method = PART_NONE;
5302 0 : partitions = 0;
5303 : }
5304 12 : else if (PQntuples(res) == 0)
5305 : {
5306 : /*
5307 : * This case is unlikely as pgbench already found "pgbench_branches"
5308 : * above to compute the scale.
5309 : */
5310 0 : pg_log_error("no pgbench_accounts table found in search_path");
5311 0 : pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5312 0 : exit(1);
5313 : }
5314 : else /* PQntuples(res) == 1 */
5315 : {
5316 : /* normal case, extract partition information */
5317 12 : if (PQgetisnull(res, 0, 1))
5318 0 : partition_method = PART_NONE;
5319 : else
5320 : {
5321 12 : char *ps = PQgetvalue(res, 0, 1);
5322 :
5323 : /* column must be there */
5324 : Assert(ps != NULL);
5325 :
5326 12 : if (strcmp(ps, "r") == 0)
5327 12 : partition_method = PART_RANGE;
5328 0 : else if (strcmp(ps, "h") == 0)
5329 0 : partition_method = PART_HASH;
5330 : else
5331 : {
5332 : /* possibly a newer version with new partition method */
5333 0 : pg_fatal("unexpected partition method: \"%s\"", ps);
5334 : }
5335 : }
5336 :
5337 12 : partitions = atoi(PQgetvalue(res, 0, 2));
5338 : }
5339 :
5340 12 : PQclear(res);
5341 12 : }
5342 :
5343 : /*
5344 : * Replace :param with $n throughout the command's SQL text, which
5345 : * is a modifiable string in cmd->lines.
5346 : */
5347 : static bool
5348 138 : parseQuery(Command *cmd)
5349 : {
5350 : char *sql,
5351 : *p;
5352 :
5353 138 : cmd->argc = 1;
5354 :
5355 138 : p = sql = pg_strdup(cmd->lines.data);
5356 730 : while ((p = strchr(p, ':')) != NULL)
5357 : {
5358 : char var[13];
5359 : char *name;
5360 : int eaten;
5361 :
5362 594 : name = parseVariable(p, &eaten);
5363 594 : if (name == NULL)
5364 : {
5365 96 : while (*p == ':')
5366 : {
5367 64 : p++;
5368 : }
5369 32 : continue;
5370 : }
5371 :
5372 : /*
5373 : * cmd->argv[0] is the SQL statement itself, so the max number of
5374 : * arguments is one less than MAX_ARGS
5375 : */
5376 562 : if (cmd->argc >= MAX_ARGS)
5377 : {
5378 2 : pg_log_error("statement has too many arguments (maximum is %d): %s",
5379 : MAX_ARGS - 1, cmd->lines.data);
5380 2 : pg_free(name);
5381 2 : return false;
5382 : }
5383 :
5384 560 : sprintf(var, "$%d", cmd->argc);
5385 560 : p = replaceVariable(&sql, p, eaten, var);
5386 :
5387 560 : cmd->argv[cmd->argc] = name;
5388 560 : cmd->argc++;
5389 : }
5390 :
5391 : Assert(cmd->argv[0] == NULL);
5392 136 : cmd->argv[0] = sql;
5393 136 : return true;
5394 : }
5395 :
5396 : /*
5397 : * syntax error while parsing a script (in practice, while parsing a
5398 : * backslash command, because we don't detect syntax errors in SQL)
5399 : *
5400 : * source: source of script (filename or builtin-script ID)
5401 : * lineno: line number within script (count from 1)
5402 : * line: whole line of backslash command, if available
5403 : * command: backslash command name, if available
5404 : * msg: the actual error message
5405 : * more: optional extra message
5406 : * column: zero-based column number, or -1 if unknown
5407 : */
5408 : void
5409 66 : syntax_error(const char *source, int lineno,
5410 : const char *line, const char *command,
5411 : const char *msg, const char *more, int column)
5412 : {
5413 : PQExpBufferData buf;
5414 :
5415 66 : initPQExpBuffer(&buf);
5416 :
5417 66 : printfPQExpBuffer(&buf, "%s:%d: %s", source, lineno, msg);
5418 66 : if (more != NULL)
5419 30 : appendPQExpBuffer(&buf, " (%s)", more);
5420 66 : if (column >= 0 && line == NULL)
5421 0 : appendPQExpBuffer(&buf, " at column %d", column + 1);
5422 66 : if (command != NULL)
5423 60 : appendPQExpBuffer(&buf, " in command \"%s\"", command);
5424 :
5425 66 : pg_log_error("%s", buf.data);
5426 :
5427 66 : termPQExpBuffer(&buf);
5428 :
5429 66 : if (line != NULL)
5430 : {
5431 56 : fprintf(stderr, "%s\n", line);
5432 56 : if (column >= 0)
5433 42 : fprintf(stderr, "%*c error found here\n", column + 1, '^');
5434 : }
5435 :
5436 66 : exit(1);
5437 : }
5438 :
5439 : /*
5440 : * Return a pointer to the start of the SQL command, after skipping over
5441 : * whitespace and "--" comments.
5442 : * If the end of the string is reached, return NULL.
5443 : */
5444 : static char *
5445 2074 : skip_sql_comments(char *sql_command)
5446 : {
5447 2074 : char *p = sql_command;
5448 :
5449 : /* Skip any leading whitespace, as well as "--" style comments */
5450 : for (;;)
5451 : {
5452 2074 : if (isspace((unsigned char) *p))
5453 0 : p++;
5454 2074 : else if (strncmp(p, "--", 2) == 0)
5455 : {
5456 0 : p = strchr(p, '\n');
5457 0 : if (p == NULL)
5458 0 : return NULL;
5459 0 : p++;
5460 : }
5461 : else
5462 2074 : break;
5463 : }
5464 :
5465 : /* NULL if there's nothing but whitespace and comments */
5466 2074 : if (*p == '\0')
5467 1336 : return NULL;
5468 :
5469 738 : return p;
5470 : }
5471 :
5472 : /*
5473 : * Parse a SQL command; return a Command struct, or NULL if it's a comment
5474 : *
5475 : * On entry, psqlscan.l has collected the command into "buf", so we don't
5476 : * really need to do much here except check for comments and set up a Command
5477 : * struct.
5478 : */
5479 : static Command *
5480 2074 : create_sql_command(PQExpBuffer buf, const char *source)
5481 : {
5482 : Command *my_command;
5483 2074 : char *p = skip_sql_comments(buf->data);
5484 :
5485 2074 : if (p == NULL)
5486 1336 : return NULL;
5487 :
5488 : /* Allocate and initialize Command structure */
5489 738 : my_command = (Command *) pg_malloc(sizeof(Command));
5490 738 : initPQExpBuffer(&my_command->lines);
5491 738 : appendPQExpBufferStr(&my_command->lines, p);
5492 738 : my_command->first_line = NULL; /* this is set later */
5493 738 : my_command->type = SQL_COMMAND;
5494 738 : my_command->meta = META_NONE;
5495 738 : my_command->argc = 0;
5496 738 : my_command->retries = 0;
5497 738 : my_command->failures = 0;
5498 738 : memset(my_command->argv, 0, sizeof(my_command->argv));
5499 738 : my_command->varprefix = NULL; /* allocated later, if needed */
5500 738 : my_command->expr = NULL;
5501 738 : initSimpleStats(&my_command->stats);
5502 738 : my_command->prepname = NULL; /* set later, if needed */
5503 :
5504 738 : return my_command;
5505 : }
5506 :
5507 : /* Free a Command structure and associated data */
5508 : static void
5509 56 : free_command(Command *command)
5510 : {
5511 56 : termPQExpBuffer(&command->lines);
5512 56 : pg_free(command->first_line);
5513 116 : for (int i = 0; i < command->argc; i++)
5514 60 : pg_free(command->argv[i]);
5515 56 : pg_free(command->varprefix);
5516 :
5517 : /*
5518 : * It should also free expr recursively, but this is currently not needed
5519 : * as only gset commands (which do not have an expression) are freed.
5520 : */
5521 56 : pg_free(command);
5522 56 : }
5523 :
5524 : /*
5525 : * Once an SQL command is fully parsed, possibly by accumulating several
5526 : * parts, complete other fields of the Command structure.
5527 : */
5528 : static void
5529 476 : postprocess_sql_command(Command *my_command)
5530 : {
5531 : char buffer[128];
5532 : static int prepnum = 0;
5533 :
5534 : Assert(my_command->type == SQL_COMMAND);
5535 :
5536 : /* Save the first line for error display. */
5537 476 : strlcpy(buffer, my_command->lines.data, sizeof(buffer));
5538 476 : buffer[strcspn(buffer, "\n\r")] = '\0';
5539 476 : my_command->first_line = pg_strdup(buffer);
5540 :
5541 : /* Parse query and generate prepared statement name, if necessary */
5542 476 : switch (querymode)
5543 : {
5544 338 : case QUERY_SIMPLE:
5545 338 : my_command->argv[0] = my_command->lines.data;
5546 338 : my_command->argc++;
5547 338 : break;
5548 100 : case QUERY_PREPARED:
5549 100 : my_command->prepname = psprintf("P_%d", prepnum++);
5550 : /* fall through */
5551 138 : case QUERY_EXTENDED:
5552 138 : if (!parseQuery(my_command))
5553 2 : exit(1);
5554 136 : break;
5555 0 : default:
5556 0 : exit(1);
5557 : }
5558 474 : }
5559 :
5560 : /*
5561 : * Parse a backslash command; return a Command struct, or NULL if comment
5562 : *
5563 : * At call, we have scanned only the initial backslash.
5564 : */
5565 : static Command *
5566 938 : process_backslash_command(PsqlScanState sstate, const char *source)
5567 : {
5568 : Command *my_command;
5569 : PQExpBufferData word_buf;
5570 : int word_offset;
5571 : int offsets[MAX_ARGS]; /* offsets of argument words */
5572 : int start_offset;
5573 : int lineno;
5574 : int j;
5575 :
5576 938 : initPQExpBuffer(&word_buf);
5577 :
5578 : /* Remember location of the backslash */
5579 938 : start_offset = expr_scanner_offset(sstate) - 1;
5580 938 : lineno = expr_scanner_get_lineno(sstate, start_offset);
5581 :
5582 : /* Collect first word of command */
5583 938 : if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5584 : {
5585 0 : termPQExpBuffer(&word_buf);
5586 0 : return NULL;
5587 : }
5588 :
5589 : /* Allocate and initialize Command structure */
5590 938 : my_command = (Command *) pg_malloc0(sizeof(Command));
5591 938 : my_command->type = META_COMMAND;
5592 938 : my_command->argc = 0;
5593 938 : initSimpleStats(&my_command->stats);
5594 :
5595 : /* Save first word (command name) */
5596 938 : j = 0;
5597 938 : offsets[j] = word_offset;
5598 938 : my_command->argv[j++] = pg_strdup(word_buf.data);
5599 938 : my_command->argc++;
5600 :
5601 : /* ... and convert it to enum form */
5602 938 : my_command->meta = getMetaCommand(my_command->argv[0]);
5603 :
5604 938 : if (my_command->meta == META_SET ||
5605 214 : my_command->meta == META_IF ||
5606 184 : my_command->meta == META_ELIF)
5607 : {
5608 : yyscan_t yyscanner;
5609 :
5610 : /* For \set, collect var name */
5611 770 : if (my_command->meta == META_SET)
5612 : {
5613 724 : if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5614 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5615 : "missing argument", NULL, -1);
5616 :
5617 722 : offsets[j] = word_offset;
5618 722 : my_command->argv[j++] = pg_strdup(word_buf.data);
5619 722 : my_command->argc++;
5620 : }
5621 :
5622 : /* then for all parse the expression */
5623 768 : yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
5624 768 : my_command->argv[0]);
5625 :
5626 768 : if (expr_yyparse(yyscanner) != 0)
5627 : {
5628 : /* dead code: exit done from syntax_error called by yyerror */
5629 0 : exit(1);
5630 : }
5631 :
5632 730 : my_command->expr = expr_parse_result;
5633 :
5634 : /* Save line, trimming any trailing newline */
5635 730 : my_command->first_line =
5636 730 : expr_scanner_get_substring(sstate,
5637 : start_offset,
5638 : expr_scanner_offset(sstate),
5639 : true);
5640 :
5641 730 : expr_scanner_finish(yyscanner);
5642 :
5643 730 : termPQExpBuffer(&word_buf);
5644 :
5645 730 : return my_command;
5646 : }
5647 :
5648 : /* For all other commands, collect remaining words. */
5649 750 : while (expr_lex_one_word(sstate, &word_buf, &word_offset))
5650 : {
5651 : /*
5652 : * my_command->argv[0] is the command itself, so the max number of
5653 : * arguments is one less than MAX_ARGS
5654 : */
5655 584 : if (j >= MAX_ARGS)
5656 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5657 : "too many arguments", NULL, -1);
5658 :
5659 582 : offsets[j] = word_offset;
5660 582 : my_command->argv[j++] = pg_strdup(word_buf.data);
5661 582 : my_command->argc++;
5662 : }
5663 :
5664 : /* Save line, trimming any trailing newline */
5665 166 : my_command->first_line =
5666 166 : expr_scanner_get_substring(sstate,
5667 : start_offset,
5668 : expr_scanner_offset(sstate),
5669 : true);
5670 :
5671 166 : if (my_command->meta == META_SLEEP)
5672 : {
5673 18 : if (my_command->argc < 2)
5674 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5675 : "missing argument", NULL, -1);
5676 :
5677 16 : if (my_command->argc > 3)
5678 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5679 : "too many arguments", NULL,
5680 2 : offsets[3] - start_offset);
5681 :
5682 : /*
5683 : * Split argument into number and unit to allow "sleep 1ms" etc. We
5684 : * don't have to terminate the number argument with null because it
5685 : * will be parsed with atoi, which ignores trailing non-digit
5686 : * characters.
5687 : */
5688 14 : if (my_command->argv[1][0] != ':')
5689 : {
5690 8 : char *c = my_command->argv[1];
5691 8 : bool have_digit = false;
5692 :
5693 : /* Skip sign */
5694 8 : if (*c == '+' || *c == '-')
5695 0 : c++;
5696 :
5697 : /* Require at least one digit */
5698 8 : if (*c && isdigit((unsigned char) *c))
5699 8 : have_digit = true;
5700 :
5701 : /* Eat all digits */
5702 20 : while (*c && isdigit((unsigned char) *c))
5703 12 : c++;
5704 :
5705 8 : if (*c)
5706 : {
5707 2 : if (my_command->argc == 2 && have_digit)
5708 : {
5709 2 : my_command->argv[2] = c;
5710 2 : offsets[2] = offsets[1] + (c - my_command->argv[1]);
5711 2 : my_command->argc = 3;
5712 : }
5713 : else
5714 : {
5715 : /*
5716 : * Raise an error if argument starts with non-digit
5717 : * character (after sign).
5718 : */
5719 0 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5720 : "invalid sleep time, must be an integer",
5721 0 : my_command->argv[1], offsets[1] - start_offset);
5722 : }
5723 : }
5724 : }
5725 :
5726 14 : if (my_command->argc == 3)
5727 : {
5728 18 : if (pg_strcasecmp(my_command->argv[2], "us") != 0 &&
5729 12 : pg_strcasecmp(my_command->argv[2], "ms") != 0 &&
5730 4 : pg_strcasecmp(my_command->argv[2], "s") != 0)
5731 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5732 : "unrecognized time unit, must be us, ms or s",
5733 2 : my_command->argv[2], offsets[2] - start_offset);
5734 : }
5735 : }
5736 148 : else if (my_command->meta == META_SETSHELL)
5737 : {
5738 8 : if (my_command->argc < 3)
5739 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5740 : "missing argument", NULL, -1);
5741 : }
5742 140 : else if (my_command->meta == META_SHELL)
5743 : {
5744 8 : if (my_command->argc < 2)
5745 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5746 : "missing command", NULL, -1);
5747 : }
5748 132 : else if (my_command->meta == META_ELSE || my_command->meta == META_ENDIF ||
5749 92 : my_command->meta == META_STARTPIPELINE ||
5750 78 : my_command->meta == META_ENDPIPELINE)
5751 : {
5752 66 : if (my_command->argc != 1)
5753 4 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5754 : "unexpected argument", NULL, -1);
5755 : }
5756 66 : else if (my_command->meta == META_GSET || my_command->meta == META_ASET)
5757 : {
5758 64 : if (my_command->argc > 2)
5759 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5760 : "too many arguments", NULL, -1);
5761 : }
5762 : else
5763 : {
5764 : /* my_command->meta == META_NONE */
5765 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5766 : "invalid command", NULL, -1);
5767 : }
5768 :
5769 148 : termPQExpBuffer(&word_buf);
5770 :
5771 148 : return my_command;
5772 : }
5773 :
5774 : static void
5775 12 : ConditionError(const char *desc, int cmdn, const char *msg)
5776 : {
5777 12 : pg_fatal("condition error in script \"%s\" command %d: %s",
5778 : desc, cmdn, msg);
5779 : }
5780 :
5781 : /*
5782 : * Partial evaluation of conditionals before recording and running the script.
5783 : */
5784 : static void
5785 454 : CheckConditional(const ParsedScript *ps)
5786 : {
5787 : /* statically check conditional structure */
5788 454 : ConditionalStack cs = conditional_stack_create();
5789 : int i;
5790 :
5791 1978 : for (i = 0; ps->commands[i] != NULL; i++)
5792 : {
5793 1534 : Command *cmd = ps->commands[i];
5794 :
5795 1534 : if (cmd->type == META_COMMAND)
5796 : {
5797 802 : switch (cmd->meta)
5798 : {
5799 22 : case META_IF:
5800 22 : conditional_stack_push(cs, IFSTATE_FALSE);
5801 22 : break;
5802 14 : case META_ELIF:
5803 14 : if (conditional_stack_empty(cs))
5804 2 : ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5805 12 : if (conditional_stack_peek(cs) == IFSTATE_ELSE_FALSE)
5806 2 : ConditionError(ps->desc, i + 1, "\\elif after \\else");
5807 10 : break;
5808 14 : case META_ELSE:
5809 14 : if (conditional_stack_empty(cs))
5810 2 : ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5811 12 : if (conditional_stack_peek(cs) == IFSTATE_ELSE_FALSE)
5812 2 : ConditionError(ps->desc, i + 1, "\\else after \\else");
5813 10 : conditional_stack_poke(cs, IFSTATE_ELSE_FALSE);
5814 10 : break;
5815 18 : case META_ENDIF:
5816 18 : if (!conditional_stack_pop(cs))
5817 2 : ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5818 16 : break;
5819 734 : default:
5820 : /* ignore anything else... */
5821 734 : break;
5822 : }
5823 732 : }
5824 : }
5825 444 : if (!conditional_stack_empty(cs))
5826 2 : ConditionError(ps->desc, i + 1, "\\if without matching \\endif");
5827 442 : conditional_stack_destroy(cs);
5828 442 : }
5829 :
5830 : /*
5831 : * Parse a script (either the contents of a file, or a built-in script)
5832 : * and add it to the list of scripts.
5833 : */
5834 : static void
5835 524 : ParseScript(const char *script, const char *desc, int weight)
5836 : {
5837 : ParsedScript ps;
5838 : PsqlScanState sstate;
5839 : PQExpBufferData line_buf;
5840 : int alloc_num;
5841 : int index;
5842 : int lineno;
5843 : int start_offset;
5844 :
5845 : #define COMMANDS_ALLOC_NUM 128
5846 524 : alloc_num = COMMANDS_ALLOC_NUM;
5847 :
5848 : /* Initialize all fields of ps */
5849 524 : ps.desc = desc;
5850 524 : ps.weight = weight;
5851 524 : ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
5852 524 : initStats(&ps.stats, 0);
5853 :
5854 : /* Prepare to parse script */
5855 524 : sstate = psql_scan_create(&pgbench_callbacks);
5856 :
5857 : /*
5858 : * Ideally, we'd scan scripts using the encoding and stdstrings settings
5859 : * we get from a DB connection. However, without major rearrangement of
5860 : * pgbench's argument parsing, we can't have a DB connection at the time
5861 : * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
5862 : * with any backend-safe encoding, though conceivably we could be fooled
5863 : * if a script file uses a client-only encoding. We also assume that
5864 : * stdstrings should be true, which is a bit riskier.
5865 : */
5866 524 : psql_scan_setup(sstate, script, strlen(script), 0, true);
5867 524 : start_offset = expr_scanner_offset(sstate) - 1;
5868 :
5869 524 : initPQExpBuffer(&line_buf);
5870 :
5871 524 : index = 0;
5872 :
5873 : for (;;)
5874 1550 : {
5875 : PsqlScanResult sr;
5876 : promptStatus_t prompt;
5877 2074 : Command *command = NULL;
5878 :
5879 2074 : resetPQExpBuffer(&line_buf);
5880 2074 : lineno = expr_scanner_get_lineno(sstate, start_offset);
5881 :
5882 2074 : sr = psql_scan(sstate, &line_buf, &prompt);
5883 :
5884 : /* If we collected a new SQL command, process that */
5885 2074 : command = create_sql_command(&line_buf, desc);
5886 :
5887 : /* store new command */
5888 2074 : if (command)
5889 738 : ps.commands[index++] = command;
5890 :
5891 : /* If we reached a backslash, process that */
5892 2074 : if (sr == PSCAN_BACKSLASH)
5893 : {
5894 938 : command = process_backslash_command(sstate, desc);
5895 :
5896 878 : if (command)
5897 : {
5898 : /*
5899 : * If this is gset or aset, merge into the preceding command.
5900 : * (We don't use a command slot in this case).
5901 : */
5902 878 : if (command->meta == META_GSET || command->meta == META_ASET)
5903 : {
5904 : Command *cmd;
5905 :
5906 62 : if (index == 0)
5907 2 : syntax_error(desc, lineno, NULL, NULL,
5908 : "\\gset must follow an SQL command",
5909 : NULL, -1);
5910 :
5911 60 : cmd = ps.commands[index - 1];
5912 :
5913 60 : if (cmd->type != SQL_COMMAND ||
5914 58 : cmd->varprefix != NULL)
5915 4 : syntax_error(desc, lineno, NULL, NULL,
5916 : "\\gset must follow an SQL command",
5917 4 : cmd->first_line, -1);
5918 :
5919 : /* get variable prefix */
5920 56 : if (command->argc <= 1 || command->argv[1][0] == '\0')
5921 52 : cmd->varprefix = pg_strdup("");
5922 : else
5923 4 : cmd->varprefix = pg_strdup(command->argv[1]);
5924 :
5925 : /* update the sql command meta */
5926 56 : cmd->meta = command->meta;
5927 :
5928 : /* cleanup unused command */
5929 56 : free_command(command);
5930 :
5931 56 : continue;
5932 : }
5933 :
5934 : /* Attach any other backslash command as a new command */
5935 816 : ps.commands[index++] = command;
5936 : }
5937 : }
5938 :
5939 : /*
5940 : * Since we used a command slot, allocate more if needed. Note we
5941 : * always allocate one more in order to accommodate the NULL
5942 : * terminator below.
5943 : */
5944 1952 : if (index >= alloc_num)
5945 : {
5946 0 : alloc_num += COMMANDS_ALLOC_NUM;
5947 0 : ps.commands = (Command **)
5948 0 : pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
5949 : }
5950 :
5951 : /* Done if we reached EOF */
5952 1952 : if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
5953 : break;
5954 : }
5955 :
5956 458 : ps.commands[index] = NULL;
5957 :
5958 458 : addScript(&ps);
5959 :
5960 442 : termPQExpBuffer(&line_buf);
5961 442 : psql_scan_finish(sstate);
5962 442 : psql_scan_destroy(sstate);
5963 442 : }
5964 :
5965 : /*
5966 : * Read the entire contents of file fd, and return it in a malloc'd buffer.
5967 : *
5968 : * The buffer will typically be larger than necessary, but we don't care
5969 : * in this program, because we'll free it as soon as we've parsed the script.
5970 : */
5971 : static char *
5972 218 : read_file_contents(FILE *fd)
5973 : {
5974 : char *buf;
5975 218 : size_t buflen = BUFSIZ;
5976 218 : size_t used = 0;
5977 :
5978 218 : buf = (char *) pg_malloc(buflen);
5979 :
5980 : for (;;)
5981 0 : {
5982 : size_t nread;
5983 :
5984 218 : nread = fread(buf + used, 1, BUFSIZ, fd);
5985 218 : used += nread;
5986 : /* If fread() read less than requested, must be EOF or error */
5987 218 : if (nread < BUFSIZ)
5988 218 : break;
5989 : /* Enlarge buf so we can read some more */
5990 0 : buflen += BUFSIZ;
5991 0 : buf = (char *) pg_realloc(buf, buflen);
5992 : }
5993 : /* There is surely room for a terminator */
5994 218 : buf[used] = '\0';
5995 :
5996 218 : return buf;
5997 : }
5998 :
5999 : /*
6000 : * Given a file name, read it and add its script to the list.
6001 : * "-" means to read stdin.
6002 : * NB: filename must be storage that won't disappear.
6003 : */
6004 : static void
6005 220 : process_file(const char *filename, int weight)
6006 : {
6007 : FILE *fd;
6008 : char *buf;
6009 :
6010 : /* Slurp the file contents into "buf" */
6011 220 : if (strcmp(filename, "-") == 0)
6012 0 : fd = stdin;
6013 220 : else if ((fd = fopen(filename, "r")) == NULL)
6014 2 : pg_fatal("could not open file \"%s\": %m", filename);
6015 :
6016 218 : buf = read_file_contents(fd);
6017 :
6018 218 : if (ferror(fd))
6019 0 : pg_fatal("could not read file \"%s\": %m", filename);
6020 :
6021 218 : if (fd != stdin)
6022 218 : fclose(fd);
6023 :
6024 218 : ParseScript(buf, filename, weight);
6025 :
6026 138 : free(buf);
6027 138 : }
6028 :
6029 : /* Parse the given builtin script and add it to the list. */
6030 : static void
6031 306 : process_builtin(const BuiltinScript *bi, int weight)
6032 : {
6033 306 : ParseScript(bi->script, bi->desc, weight);
6034 304 : }
6035 :
6036 : /* show available builtin scripts */
6037 : static void
6038 6 : listAvailableScripts(void)
6039 : {
6040 : int i;
6041 :
6042 6 : fprintf(stderr, "Available builtin scripts:\n");
6043 24 : for (i = 0; i < lengthof(builtin_script); i++)
6044 18 : fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
6045 6 : fprintf(stderr, "\n");
6046 6 : }
6047 :
6048 : /* return builtin script "name" if unambiguous, fails if not found */
6049 : static const BuiltinScript *
6050 312 : findBuiltin(const char *name)
6051 : {
6052 : int i,
6053 312 : found = 0,
6054 312 : len = strlen(name);
6055 312 : const BuiltinScript *result = NULL;
6056 :
6057 1248 : for (i = 0; i < lengthof(builtin_script); i++)
6058 : {
6059 936 : if (strncmp(builtin_script[i].name, name, len) == 0)
6060 : {
6061 312 : result = &builtin_script[i];
6062 312 : found++;
6063 : }
6064 : }
6065 :
6066 : /* ok, unambiguous result */
6067 312 : if (found == 1)
6068 308 : return result;
6069 :
6070 : /* error cases */
6071 4 : if (found == 0)
6072 2 : pg_log_error("no builtin script found for name \"%s\"", name);
6073 : else /* found > 1 */
6074 2 : pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6075 :
6076 4 : listAvailableScripts();
6077 4 : exit(1);
6078 : }
6079 :
6080 : /*
6081 : * Determine the weight specification from a script option (-b, -f), if any,
6082 : * and return it as an integer (1 is returned if there's no weight). The
6083 : * script name is returned in *script as a malloc'd string.
6084 : */
6085 : static int
6086 242 : parseScriptWeight(const char *option, char **script)
6087 : {
6088 : char *sep;
6089 : int weight;
6090 :
6091 242 : if ((sep = strrchr(option, WSEP)))
6092 : {
6093 14 : int namelen = sep - option;
6094 : long wtmp;
6095 : char *badp;
6096 :
6097 : /* generate the script name */
6098 14 : *script = pg_malloc(namelen + 1);
6099 14 : strncpy(*script, option, namelen);
6100 14 : (*script)[namelen] = '\0';
6101 :
6102 : /* process digits of the weight spec */
6103 14 : errno = 0;
6104 14 : wtmp = strtol(sep + 1, &badp, 10);
6105 14 : if (errno != 0 || badp == sep + 1 || *badp != '\0')
6106 2 : pg_fatal("invalid weight specification: %s", sep);
6107 12 : if (wtmp > INT_MAX || wtmp < 0)
6108 2 : pg_fatal("weight specification out of range (0 .. %d): %lld",
6109 : INT_MAX, (long long) wtmp);
6110 10 : weight = wtmp;
6111 : }
6112 : else
6113 : {
6114 228 : *script = pg_strdup(option);
6115 228 : weight = 1;
6116 : }
6117 :
6118 238 : return weight;
6119 : }
6120 :
6121 : /* append a script to the list of scripts to process */
6122 : static void
6123 458 : addScript(const ParsedScript *script)
6124 : {
6125 458 : if (script->commands == NULL || script->commands[0] == NULL)
6126 2 : pg_fatal("empty command list for script \"%s\"", script->desc);
6127 :
6128 456 : if (num_scripts >= MAX_SCRIPTS)
6129 2 : pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6130 :
6131 454 : CheckConditional(script);
6132 :
6133 442 : sql_script[num_scripts] = *script;
6134 442 : num_scripts++;
6135 442 : }
6136 :
6137 : /*
6138 : * Print progress report.
6139 : *
6140 : * On entry, *last and *last_report contain the statistics and time of last
6141 : * progress report. On exit, they are updated with the new stats.
6142 : */
6143 : static void
6144 0 : printProgressReport(TState *threads, int64 test_start, pg_time_usec_t now,
6145 : StatsData *last, int64 *last_report)
6146 : {
6147 : /* generate and show report */
6148 0 : pg_time_usec_t run = now - *last_report;
6149 : int64 cnt,
6150 : failures,
6151 : retried;
6152 : double tps,
6153 : total_run,
6154 : latency,
6155 : sqlat,
6156 : lag,
6157 : stdev;
6158 : char tbuf[315];
6159 : StatsData cur;
6160 :
6161 : /*
6162 : * Add up the statistics of all threads.
6163 : *
6164 : * XXX: No locking. There is no guarantee that we get an atomic snapshot
6165 : * of the transaction count and latencies, so these figures can well be
6166 : * off by a small amount. The progress report's purpose is to give a
6167 : * quick overview of how the test is going, so that shouldn't matter too
6168 : * much. (If a read from a 64-bit integer is not atomic, you might get a
6169 : * "torn" read and completely bogus latencies though!)
6170 : */
6171 0 : initStats(&cur, 0);
6172 0 : for (int i = 0; i < nthreads; i++)
6173 : {
6174 0 : mergeSimpleStats(&cur.latency, &threads[i].stats.latency);
6175 0 : mergeSimpleStats(&cur.lag, &threads[i].stats.lag);
6176 0 : cur.cnt += threads[i].stats.cnt;
6177 0 : cur.skipped += threads[i].stats.skipped;
6178 0 : cur.retries += threads[i].stats.retries;
6179 0 : cur.retried += threads[i].stats.retried;
6180 0 : cur.serialization_failures +=
6181 0 : threads[i].stats.serialization_failures;
6182 0 : cur.deadlock_failures += threads[i].stats.deadlock_failures;
6183 : }
6184 :
6185 : /* we count only actually executed transactions */
6186 0 : cnt = cur.cnt - last->cnt;
6187 0 : total_run = (now - test_start) / 1000000.0;
6188 0 : tps = 1000000.0 * cnt / run;
6189 0 : if (cnt > 0)
6190 : {
6191 0 : latency = 0.001 * (cur.latency.sum - last->latency.sum) / cnt;
6192 0 : sqlat = 1.0 * (cur.latency.sum2 - last->latency.sum2) / cnt;
6193 0 : stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
6194 0 : lag = 0.001 * (cur.lag.sum - last->lag.sum) / cnt;
6195 : }
6196 : else
6197 : {
6198 0 : latency = sqlat = stdev = lag = 0;
6199 : }
6200 0 : failures = getFailures(&cur) - getFailures(last);
6201 0 : retried = cur.retried - last->retried;
6202 :
6203 0 : if (progress_timestamp)
6204 : {
6205 0 : snprintf(tbuf, sizeof(tbuf), "%.3f s",
6206 0 : PG_TIME_GET_DOUBLE(now + epoch_shift));
6207 : }
6208 : else
6209 : {
6210 : /* round seconds are expected, but the thread may be late */
6211 0 : snprintf(tbuf, sizeof(tbuf), "%.1f s", total_run);
6212 : }
6213 :
6214 0 : fprintf(stderr,
6215 : "progress: %s, %.1f tps, lat %.3f ms stddev %.3f, " INT64_FORMAT " failed",
6216 : tbuf, tps, latency, stdev, failures);
6217 :
6218 0 : if (throttle_delay)
6219 : {
6220 0 : fprintf(stderr, ", lag %.3f ms", lag);
6221 0 : if (latency_limit)
6222 0 : fprintf(stderr, ", " INT64_FORMAT " skipped",
6223 0 : cur.skipped - last->skipped);
6224 : }
6225 :
6226 : /* it can be non-zero only if max_tries is not equal to one */
6227 0 : if (max_tries != 1)
6228 0 : fprintf(stderr,
6229 : ", " INT64_FORMAT " retried, " INT64_FORMAT " retries",
6230 0 : retried, cur.retries - last->retries);
6231 0 : fprintf(stderr, "\n");
6232 :
6233 0 : *last = cur;
6234 0 : *last_report = now;
6235 0 : }
6236 :
6237 : static void
6238 22 : printSimpleStats(const char *prefix, SimpleStats *ss)
6239 : {
6240 22 : if (ss->count > 0)
6241 : {
6242 22 : double latency = ss->sum / ss->count;
6243 22 : double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
6244 :
6245 22 : printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
6246 22 : printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
6247 : }
6248 22 : }
6249 :
6250 : /* print version banner */
6251 : static void
6252 138 : printVersion(PGconn *con)
6253 : {
6254 138 : int server_ver = PQserverVersion(con);
6255 138 : int client_ver = PG_VERSION_NUM;
6256 :
6257 138 : if (server_ver != client_ver)
6258 : {
6259 : const char *server_version;
6260 : char sverbuf[32];
6261 :
6262 : /* Try to get full text form, might include "devel" etc */
6263 0 : server_version = PQparameterStatus(con, "server_version");
6264 : /* Otherwise fall back on server_ver */
6265 0 : if (!server_version)
6266 : {
6267 0 : formatPGVersionNumber(server_ver, true,
6268 : sverbuf, sizeof(sverbuf));
6269 0 : server_version = sverbuf;
6270 : }
6271 :
6272 0 : printf(_("%s (%s, server %s)\n"),
6273 : "pgbench", PG_VERSION, server_version);
6274 : }
6275 : /* For version match, only print pgbench version */
6276 : else
6277 138 : printf("%s (%s)\n", "pgbench", PG_VERSION);
6278 138 : fflush(stdout);
6279 138 : }
6280 :
6281 : /* print out results */
6282 : static void
6283 136 : printResults(StatsData *total,
6284 : pg_time_usec_t total_duration, /* benchmarking time */
6285 : pg_time_usec_t conn_total_duration, /* is_connect */
6286 : pg_time_usec_t conn_elapsed_duration, /* !is_connect */
6287 : int64 latency_late)
6288 : {
6289 : /* tps is about actually executed transactions during benchmarking */
6290 136 : int64 failures = getFailures(total);
6291 136 : int64 total_cnt = total->cnt + total->skipped + failures;
6292 136 : double bench_duration = PG_TIME_GET_DOUBLE(total_duration);
6293 136 : double tps = total->cnt / bench_duration;
6294 :
6295 : /* Report test parameters. */
6296 136 : printf("transaction type: %s\n",
6297 : num_scripts == 1 ? sql_script[0].desc : "multiple scripts");
6298 136 : printf("scaling factor: %d\n", scale);
6299 : /* only print partitioning information if some partitioning was detected */
6300 136 : if (partition_method != PART_NONE)
6301 12 : printf("partition method: %s\npartitions: %d\n",
6302 : PARTITION_METHOD[partition_method], partitions);
6303 136 : printf("query mode: %s\n", QUERYMODE[querymode]);
6304 136 : printf("number of clients: %d\n", nclients);
6305 136 : printf("number of threads: %d\n", nthreads);
6306 :
6307 136 : if (max_tries)
6308 136 : printf("maximum number of tries: %u\n", max_tries);
6309 :
6310 136 : if (duration <= 0)
6311 : {
6312 136 : printf("number of transactions per client: %d\n", nxacts);
6313 136 : printf("number of transactions actually processed: " INT64_FORMAT "/%d\n",
6314 : total->cnt, nxacts * nclients);
6315 : }
6316 : else
6317 : {
6318 0 : printf("duration: %d s\n", duration);
6319 0 : printf("number of transactions actually processed: " INT64_FORMAT "\n",
6320 : total->cnt);
6321 : }
6322 :
6323 136 : printf("number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6324 : failures, 100.0 * failures / total_cnt);
6325 :
6326 136 : if (failures_detailed)
6327 : {
6328 0 : printf("number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6329 : total->serialization_failures,
6330 : 100.0 * total->serialization_failures / total_cnt);
6331 0 : printf("number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6332 : total->deadlock_failures,
6333 : 100.0 * total->deadlock_failures / total_cnt);
6334 : }
6335 :
6336 : /* it can be non-zero only if max_tries is not equal to one */
6337 136 : if (max_tries != 1)
6338 : {
6339 4 : printf("number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6340 : total->retried, 100.0 * total->retried / total_cnt);
6341 4 : printf("total number of retries: " INT64_FORMAT "\n", total->retries);
6342 : }
6343 :
6344 : /* Remaining stats are nonsensical if we failed to execute any xacts */
6345 136 : if (total->cnt + total->skipped <= 0)
6346 86 : return;
6347 :
6348 50 : if (throttle_delay && latency_limit)
6349 4 : printf("number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6350 : total->skipped, 100.0 * total->skipped / total_cnt);
6351 :
6352 50 : if (latency_limit)
6353 4 : printf("number of transactions above the %.1f ms latency limit: " INT64_FORMAT "/" INT64_FORMAT " (%.3f%%)\n",
6354 : latency_limit / 1000.0, latency_late, total->cnt,
6355 : (total->cnt > 0) ? 100.0 * latency_late / total->cnt : 0.0);
6356 :
6357 50 : if (throttle_delay || progress || latency_limit)
6358 4 : printSimpleStats("latency", &total->latency);
6359 : else
6360 : {
6361 : /* no measurement, show average latency computed from run time */
6362 46 : printf("latency average = %.3f ms%s\n",
6363 : 0.001 * total_duration * nclients / total_cnt,
6364 : failures > 0 ? " (including failures)" : "");
6365 : }
6366 :
6367 50 : if (throttle_delay)
6368 : {
6369 : /*
6370 : * Report average transaction lag under rate limit throttling. This
6371 : * is the delay between scheduled and actual start times for the
6372 : * transaction. The measured lag may be caused by thread/client load,
6373 : * the database load, or the Poisson throttling process.
6374 : */
6375 4 : printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
6376 : 0.001 * total->lag.sum / total->cnt, 0.001 * total->lag.max);
6377 : }
6378 :
6379 : /*
6380 : * Under -C/--connect, each transaction incurs a significant connection
6381 : * cost, it would not make much sense to ignore it in tps, and it would
6382 : * not be tps anyway.
6383 : *
6384 : * Otherwise connections are made just once at the beginning of the run
6385 : * and should not impact performance but for very short run, so they are
6386 : * (right)fully ignored in tps.
6387 : */
6388 50 : if (is_connect)
6389 : {
6390 4 : printf("average connection time = %.3f ms\n", 0.001 * conn_total_duration / (total->cnt + failures));
6391 4 : printf("tps = %f (including reconnection times)\n", tps);
6392 : }
6393 : else
6394 : {
6395 46 : printf("initial connection time = %.3f ms\n", 0.001 * conn_elapsed_duration);
6396 46 : printf("tps = %f (without initial connection time)\n", tps);
6397 : }
6398 :
6399 : /* Report per-script/command statistics */
6400 50 : if (per_script_stats || report_per_command)
6401 : {
6402 : int i;
6403 :
6404 32 : for (i = 0; i < num_scripts; i++)
6405 : {
6406 22 : if (per_script_stats)
6407 : {
6408 18 : StatsData *sstats = &sql_script[i].stats;
6409 18 : int64 script_failures = getFailures(sstats);
6410 18 : int64 script_total_cnt =
6411 18 : sstats->cnt + sstats->skipped + script_failures;
6412 :
6413 18 : printf("SQL script %d: %s\n"
6414 : " - weight: %d (targets %.1f%% of total)\n"
6415 : " - " INT64_FORMAT " transactions (%.1f%% of total, tps = %f)\n",
6416 : i + 1, sql_script[i].desc,
6417 : sql_script[i].weight,
6418 : 100.0 * sql_script[i].weight / total_weight,
6419 : sstats->cnt,
6420 : 100.0 * sstats->cnt / total->cnt,
6421 : sstats->cnt / bench_duration);
6422 :
6423 18 : printf(" - number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6424 : script_failures,
6425 : 100.0 * script_failures / script_total_cnt);
6426 :
6427 18 : if (failures_detailed)
6428 : {
6429 0 : printf(" - number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6430 : sstats->serialization_failures,
6431 : (100.0 * sstats->serialization_failures /
6432 : script_total_cnt));
6433 0 : printf(" - number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6434 : sstats->deadlock_failures,
6435 : (100.0 * sstats->deadlock_failures /
6436 : script_total_cnt));
6437 : }
6438 :
6439 : /* it can be non-zero only if max_tries is not equal to one */
6440 18 : if (max_tries != 1)
6441 : {
6442 0 : printf(" - number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6443 : sstats->retried,
6444 : 100.0 * sstats->retried / script_total_cnt);
6445 0 : printf(" - total number of retries: " INT64_FORMAT "\n",
6446 : sstats->retries);
6447 : }
6448 :
6449 18 : if (throttle_delay && latency_limit && script_total_cnt > 0)
6450 0 : printf(" - number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6451 : sstats->skipped,
6452 : 100.0 * sstats->skipped / script_total_cnt);
6453 :
6454 18 : printSimpleStats(" - latency", &sstats->latency);
6455 : }
6456 :
6457 : /*
6458 : * Report per-command statistics: latencies, retries after errors,
6459 : * failures (errors without retrying).
6460 : */
6461 22 : if (report_per_command)
6462 : {
6463 : Command **commands;
6464 :
6465 4 : printf("%sstatement latencies in milliseconds%s:\n",
6466 : per_script_stats ? " - " : "",
6467 : (max_tries == 1 ?
6468 : " and failures" :
6469 : ", failures and retries"));
6470 :
6471 4 : for (commands = sql_script[i].commands;
6472 10 : *commands != NULL;
6473 6 : commands++)
6474 : {
6475 6 : SimpleStats *cstats = &(*commands)->stats;
6476 :
6477 6 : if (max_tries == 1)
6478 6 : printf(" %11.3f %10" INT64_MODIFIER "d %s\n",
6479 : (cstats->count > 0) ?
6480 : 1000.0 * cstats->sum / cstats->count : 0.0,
6481 : (*commands)->failures,
6482 : (*commands)->first_line);
6483 : else
6484 0 : printf(" %11.3f %10" INT64_MODIFIER "d %10" INT64_MODIFIER "d %s\n",
6485 : (cstats->count > 0) ?
6486 : 1000.0 * cstats->sum / cstats->count : 0.0,
6487 : (*commands)->failures,
6488 : (*commands)->retries,
6489 : (*commands)->first_line);
6490 : }
6491 : }
6492 : }
6493 : }
6494 : }
6495 :
6496 : /*
6497 : * Set up a random seed according to seed parameter (NULL means default),
6498 : * and initialize base_random_sequence for use in initializing other sequences.
6499 : */
6500 : static bool
6501 322 : set_random_seed(const char *seed)
6502 : {
6503 : uint64 iseed;
6504 :
6505 322 : if (seed == NULL || strcmp(seed, "time") == 0)
6506 : {
6507 : /* rely on current time */
6508 314 : iseed = pg_time_now();
6509 : }
6510 8 : else if (strcmp(seed, "rand") == 0)
6511 : {
6512 : /* use some "strong" random source */
6513 0 : if (!pg_strong_random(&iseed, sizeof(iseed)))
6514 : {
6515 0 : pg_log_error("could not generate random seed");
6516 0 : return false;
6517 : }
6518 : }
6519 : else
6520 : {
6521 : /* parse unsigned-int seed value */
6522 : unsigned long ulseed;
6523 : char garbage;
6524 :
6525 : /* Don't try to use UINT64_FORMAT here; it might not work for sscanf */
6526 8 : if (sscanf(seed, "%lu%c", &ulseed, &garbage) != 1)
6527 : {
6528 2 : pg_log_error("unrecognized random seed option \"%s\"", seed);
6529 2 : pg_log_error_detail("Expecting an unsigned integer, \"time\" or \"rand\".");
6530 2 : return false;
6531 : }
6532 6 : iseed = (uint64) ulseed;
6533 : }
6534 :
6535 320 : if (seed != NULL)
6536 6 : pg_log_info("setting random seed to %llu", (unsigned long long) iseed);
6537 :
6538 320 : random_seed = iseed;
6539 :
6540 : /* Initialize base_random_sequence using seed */
6541 320 : pg_prng_seed(&base_random_sequence, (uint64) iseed);
6542 :
6543 320 : return true;
6544 : }
6545 :
6546 : int
6547 318 : main(int argc, char **argv)
6548 : {
6549 : static struct option long_options[] = {
6550 : /* systematic long/short named options */
6551 : {"builtin", required_argument, NULL, 'b'},
6552 : {"client", required_argument, NULL, 'c'},
6553 : {"connect", no_argument, NULL, 'C'},
6554 : {"debug", no_argument, NULL, 'd'},
6555 : {"define", required_argument, NULL, 'D'},
6556 : {"file", required_argument, NULL, 'f'},
6557 : {"fillfactor", required_argument, NULL, 'F'},
6558 : {"host", required_argument, NULL, 'h'},
6559 : {"initialize", no_argument, NULL, 'i'},
6560 : {"init-steps", required_argument, NULL, 'I'},
6561 : {"jobs", required_argument, NULL, 'j'},
6562 : {"log", no_argument, NULL, 'l'},
6563 : {"latency-limit", required_argument, NULL, 'L'},
6564 : {"no-vacuum", no_argument, NULL, 'n'},
6565 : {"port", required_argument, NULL, 'p'},
6566 : {"progress", required_argument, NULL, 'P'},
6567 : {"protocol", required_argument, NULL, 'M'},
6568 : {"quiet", no_argument, NULL, 'q'},
6569 : {"report-per-command", no_argument, NULL, 'r'},
6570 : {"rate", required_argument, NULL, 'R'},
6571 : {"scale", required_argument, NULL, 's'},
6572 : {"select-only", no_argument, NULL, 'S'},
6573 : {"skip-some-updates", no_argument, NULL, 'N'},
6574 : {"time", required_argument, NULL, 'T'},
6575 : {"transactions", required_argument, NULL, 't'},
6576 : {"username", required_argument, NULL, 'U'},
6577 : {"vacuum-all", no_argument, NULL, 'v'},
6578 : /* long-named only options */
6579 : {"unlogged-tables", no_argument, NULL, 1},
6580 : {"tablespace", required_argument, NULL, 2},
6581 : {"index-tablespace", required_argument, NULL, 3},
6582 : {"sampling-rate", required_argument, NULL, 4},
6583 : {"aggregate-interval", required_argument, NULL, 5},
6584 : {"progress-timestamp", no_argument, NULL, 6},
6585 : {"log-prefix", required_argument, NULL, 7},
6586 : {"foreign-keys", no_argument, NULL, 8},
6587 : {"random-seed", required_argument, NULL, 9},
6588 : {"show-script", required_argument, NULL, 10},
6589 : {"partitions", required_argument, NULL, 11},
6590 : {"partition-method", required_argument, NULL, 12},
6591 : {"failures-detailed", no_argument, NULL, 13},
6592 : {"max-tries", required_argument, NULL, 14},
6593 : {"verbose-errors", no_argument, NULL, 15},
6594 : {NULL, 0, NULL, 0}
6595 : };
6596 :
6597 : int c;
6598 318 : bool is_init_mode = false; /* initialize mode? */
6599 318 : char *initialize_steps = NULL;
6600 318 : bool foreign_keys = false;
6601 318 : bool is_no_vacuum = false;
6602 318 : bool do_vacuum_accounts = false; /* vacuum accounts table? */
6603 : int optindex;
6604 318 : bool scale_given = false;
6605 :
6606 318 : bool benchmarking_option_set = false;
6607 318 : bool initialization_option_set = false;
6608 318 : bool internal_script_used = false;
6609 :
6610 : CState *state; /* status of clients */
6611 : TState *threads; /* array of thread */
6612 :
6613 : pg_time_usec_t
6614 : start_time, /* start up time */
6615 318 : bench_start = 0, /* first recorded benchmarking time */
6616 : conn_total_duration; /* cumulated connection time in
6617 : * threads */
6618 318 : int64 latency_late = 0;
6619 : StatsData stats;
6620 : int weight;
6621 :
6622 : int i;
6623 : int nclients_dealt;
6624 :
6625 : #ifdef HAVE_GETRLIMIT
6626 : struct rlimit rlim;
6627 : #endif
6628 :
6629 : PGconn *con;
6630 : char *env;
6631 :
6632 318 : int exit_code = 0;
6633 : struct timeval tv;
6634 :
6635 : /*
6636 : * Record difference between Unix time and instr_time time. We'll use
6637 : * this for logging and aggregation.
6638 : */
6639 318 : gettimeofday(&tv, NULL);
6640 318 : epoch_shift = tv.tv_sec * INT64CONST(1000000) + tv.tv_usec - pg_time_now();
6641 :
6642 318 : pg_logging_init(argv[0]);
6643 318 : progname = get_progname(argv[0]);
6644 :
6645 318 : if (argc > 1)
6646 : {
6647 318 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
6648 : {
6649 2 : usage();
6650 2 : exit(0);
6651 : }
6652 316 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
6653 : {
6654 2 : puts("pgbench (PostgreSQL) " PG_VERSION);
6655 2 : exit(0);
6656 : }
6657 : }
6658 :
6659 314 : state = (CState *) pg_malloc0(sizeof(CState));
6660 :
6661 : /* set random seed early, because it may be used while parsing scripts. */
6662 314 : if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
6663 0 : pg_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
6664 :
6665 2288 : while ((c = getopt_long(argc, argv, "b:c:CdD:f:F:h:iI:j:lL:M:nNp:P:qrR:s:St:T:U:v", long_options, &optindex)) != -1)
6666 : {
6667 : char *script;
6668 :
6669 2110 : switch (c)
6670 : {
6671 24 : case 'b':
6672 24 : if (strcmp(optarg, "list") == 0)
6673 : {
6674 2 : listAvailableScripts();
6675 2 : exit(0);
6676 : }
6677 22 : weight = parseScriptWeight(optarg, &script);
6678 18 : process_builtin(findBuiltin(script), weight);
6679 14 : benchmarking_option_set = true;
6680 14 : internal_script_used = true;
6681 14 : break;
6682 42 : case 'c':
6683 42 : benchmarking_option_set = true;
6684 42 : if (!option_parse_int(optarg, "-c/--clients", 1, INT_MAX,
6685 : &nclients))
6686 : {
6687 2 : exit(1);
6688 : }
6689 : #ifdef HAVE_GETRLIMIT
6690 40 : if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
6691 0 : pg_fatal("getrlimit failed: %m");
6692 40 : if (rlim.rlim_cur < nclients + 3)
6693 : {
6694 0 : pg_log_error("need at least %d open files, but system limit is %ld",
6695 : nclients + 3, (long) rlim.rlim_cur);
6696 0 : pg_log_error_hint("Reduce number of clients, or use limit/ulimit to increase the system limit.");
6697 0 : exit(1);
6698 : }
6699 : #endif /* HAVE_GETRLIMIT */
6700 40 : break;
6701 4 : case 'C':
6702 4 : benchmarking_option_set = true;
6703 4 : is_connect = true;
6704 4 : break;
6705 6 : case 'd':
6706 6 : pg_logging_increase_verbosity();
6707 6 : break;
6708 866 : case 'D':
6709 : {
6710 : char *p;
6711 :
6712 866 : benchmarking_option_set = true;
6713 :
6714 866 : if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
6715 2 : pg_fatal("invalid variable definition: \"%s\"", optarg);
6716 :
6717 864 : *p++ = '\0';
6718 864 : if (!putVariable(&state[0].variables, "option", optarg, p))
6719 0 : exit(1);
6720 : }
6721 864 : break;
6722 220 : case 'f':
6723 220 : weight = parseScriptWeight(optarg, &script);
6724 220 : process_file(script, weight);
6725 138 : benchmarking_option_set = true;
6726 138 : break;
6727 6 : case 'F':
6728 6 : initialization_option_set = true;
6729 6 : if (!option_parse_int(optarg, "-F/--fillfactor", 10, 100,
6730 : &fillfactor))
6731 2 : exit(1);
6732 4 : break;
6733 2 : case 'h':
6734 2 : pghost = pg_strdup(optarg);
6735 2 : break;
6736 18 : case 'i':
6737 18 : is_init_mode = true;
6738 18 : break;
6739 8 : case 'I':
6740 8 : pg_free(initialize_steps);
6741 8 : initialize_steps = pg_strdup(optarg);
6742 8 : checkInitSteps(initialize_steps);
6743 6 : initialization_option_set = true;
6744 6 : break;
6745 8 : case 'j': /* jobs */
6746 8 : benchmarking_option_set = true;
6747 8 : if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
6748 : &nthreads))
6749 : {
6750 2 : exit(1);
6751 : }
6752 : #ifndef ENABLE_THREAD_SAFETY
6753 : if (nthreads != 1)
6754 : pg_fatal("threads are not supported on this platform; use -j1");
6755 : #endif /* !ENABLE_THREAD_SAFETY */
6756 6 : break;
6757 14 : case 'l':
6758 14 : benchmarking_option_set = true;
6759 14 : use_log = true;
6760 14 : break;
6761 6 : case 'L':
6762 : {
6763 6 : double limit_ms = atof(optarg);
6764 :
6765 6 : if (limit_ms <= 0.0)
6766 2 : pg_fatal("invalid latency limit: \"%s\"", optarg);
6767 4 : benchmarking_option_set = true;
6768 4 : latency_limit = (int64) (limit_ms * 1000);
6769 : }
6770 4 : break;
6771 146 : case 'M':
6772 146 : benchmarking_option_set = true;
6773 420 : for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
6774 418 : if (strcmp(optarg, QUERYMODE[querymode]) == 0)
6775 144 : break;
6776 146 : if (querymode >= NUM_QUERYMODE)
6777 2 : pg_fatal("invalid query mode (-M): \"%s\"", optarg);
6778 144 : break;
6779 164 : case 'n':
6780 164 : is_no_vacuum = true;
6781 164 : break;
6782 2 : case 'N':
6783 2 : process_builtin(findBuiltin("simple-update"), 1);
6784 2 : benchmarking_option_set = true;
6785 2 : internal_script_used = true;
6786 2 : break;
6787 2 : case 'p':
6788 2 : pgport = pg_strdup(optarg);
6789 2 : break;
6790 4 : case 'P':
6791 4 : benchmarking_option_set = true;
6792 4 : if (!option_parse_int(optarg, "-P/--progress", 1, INT_MAX,
6793 : &progress))
6794 2 : exit(1);
6795 2 : break;
6796 2 : case 'q':
6797 2 : initialization_option_set = true;
6798 2 : use_quiet = true;
6799 2 : break;
6800 4 : case 'r':
6801 4 : benchmarking_option_set = true;
6802 4 : report_per_command = true;
6803 4 : break;
6804 6 : case 'R':
6805 : {
6806 : /* get a double from the beginning of option value */
6807 6 : double throttle_value = atof(optarg);
6808 :
6809 6 : benchmarking_option_set = true;
6810 :
6811 6 : if (throttle_value <= 0.0)
6812 2 : pg_fatal("invalid rate limit: \"%s\"", optarg);
6813 : /* Invert rate limit into per-transaction delay in usec */
6814 4 : throttle_delay = 1000000.0 / throttle_value;
6815 : }
6816 4 : break;
6817 6 : case 's':
6818 6 : scale_given = true;
6819 6 : if (!option_parse_int(optarg, "-s/--scale", 1, INT_MAX,
6820 : &scale))
6821 2 : exit(1);
6822 4 : break;
6823 268 : case 'S':
6824 268 : process_builtin(findBuiltin("select-only"), 1);
6825 266 : benchmarking_option_set = true;
6826 266 : internal_script_used = true;
6827 266 : break;
6828 184 : case 't':
6829 184 : benchmarking_option_set = true;
6830 184 : if (!option_parse_int(optarg, "-t/--transactions", 1, INT_MAX,
6831 : &nxacts))
6832 2 : exit(1);
6833 182 : break;
6834 10 : case 'T':
6835 10 : benchmarking_option_set = true;
6836 10 : if (!option_parse_int(optarg, "-T/--time", 1, INT_MAX,
6837 : &duration))
6838 2 : exit(1);
6839 8 : break;
6840 2 : case 'U':
6841 2 : username = pg_strdup(optarg);
6842 2 : break;
6843 2 : case 'v':
6844 2 : benchmarking_option_set = true;
6845 2 : do_vacuum_accounts = true;
6846 2 : break;
6847 4 : case 1: /* unlogged-tables */
6848 4 : initialization_option_set = true;
6849 4 : unlogged_tables = true;
6850 4 : break;
6851 2 : case 2: /* tablespace */
6852 2 : initialization_option_set = true;
6853 2 : tablespace = pg_strdup(optarg);
6854 2 : break;
6855 2 : case 3: /* index-tablespace */
6856 2 : initialization_option_set = true;
6857 2 : index_tablespace = pg_strdup(optarg);
6858 2 : break;
6859 10 : case 4: /* sampling-rate */
6860 10 : benchmarking_option_set = true;
6861 10 : sample_rate = atof(optarg);
6862 10 : if (sample_rate <= 0.0 || sample_rate > 1.0)
6863 2 : pg_fatal("invalid sampling rate: \"%s\"", optarg);
6864 8 : break;
6865 12 : case 5: /* aggregate-interval */
6866 12 : benchmarking_option_set = true;
6867 12 : if (!option_parse_int(optarg, "--aggregate-interval", 1, INT_MAX,
6868 : &agg_interval))
6869 2 : exit(1);
6870 10 : break;
6871 4 : case 6: /* progress-timestamp */
6872 4 : progress_timestamp = true;
6873 4 : benchmarking_option_set = true;
6874 4 : break;
6875 8 : case 7: /* log-prefix */
6876 8 : benchmarking_option_set = true;
6877 8 : logfile_prefix = pg_strdup(optarg);
6878 8 : break;
6879 4 : case 8: /* foreign-keys */
6880 4 : initialization_option_set = true;
6881 4 : foreign_keys = true;
6882 4 : break;
6883 8 : case 9: /* random-seed */
6884 8 : benchmarking_option_set = true;
6885 8 : if (!set_random_seed(optarg))
6886 2 : pg_fatal("error while setting random seed from --random-seed option");
6887 6 : break;
6888 2 : case 10: /* list */
6889 : {
6890 2 : const BuiltinScript *s = findBuiltin(optarg);
6891 :
6892 2 : fprintf(stderr, "-- %s: %s\n%s\n", s->name, s->desc, s->script);
6893 2 : exit(0);
6894 : }
6895 : break;
6896 6 : case 11: /* partitions */
6897 6 : initialization_option_set = true;
6898 6 : if (!option_parse_int(optarg, "--partitions", 0, INT_MAX,
6899 : &partitions))
6900 2 : exit(1);
6901 4 : break;
6902 6 : case 12: /* partition-method */
6903 6 : initialization_option_set = true;
6904 6 : if (pg_strcasecmp(optarg, "range") == 0)
6905 0 : partition_method = PART_RANGE;
6906 6 : else if (pg_strcasecmp(optarg, "hash") == 0)
6907 4 : partition_method = PART_HASH;
6908 : else
6909 2 : pg_fatal("invalid partition method, expecting \"range\" or \"hash\", got: \"%s\"",
6910 : optarg);
6911 4 : break;
6912 0 : case 13: /* failures-detailed */
6913 0 : benchmarking_option_set = true;
6914 0 : failures_detailed = true;
6915 0 : break;
6916 8 : case 14: /* max-tries */
6917 : {
6918 8 : int32 max_tries_arg = atoi(optarg);
6919 :
6920 8 : if (max_tries_arg < 0)
6921 2 : pg_fatal("invalid number of maximum tries: \"%s\"", optarg);
6922 :
6923 6 : benchmarking_option_set = true;
6924 6 : max_tries = (uint32) max_tries_arg;
6925 : }
6926 6 : break;
6927 4 : case 15: /* verbose-errors */
6928 4 : benchmarking_option_set = true;
6929 4 : verbose_errors = true;
6930 4 : break;
6931 4 : default:
6932 : /* getopt_long already emitted a complaint */
6933 4 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
6934 4 : exit(1);
6935 : }
6936 : }
6937 :
6938 : /* set default script if none */
6939 178 : if (num_scripts == 0 && !is_init_mode)
6940 : {
6941 22 : process_builtin(findBuiltin("tpcb-like"), 1);
6942 22 : benchmarking_option_set = true;
6943 22 : internal_script_used = true;
6944 : }
6945 :
6946 : /* complete SQL command initialization and compute total weight */
6947 362 : for (i = 0; i < num_scripts; i++)
6948 : {
6949 186 : Command **commands = sql_script[i].commands;
6950 :
6951 1186 : for (int j = 0; commands[j] != NULL; j++)
6952 1002 : if (commands[j]->type == SQL_COMMAND)
6953 476 : postprocess_sql_command(commands[j]);
6954 :
6955 : /* cannot overflow: weight is 32b, total_weight 64b */
6956 184 : total_weight += sql_script[i].weight;
6957 : }
6958 :
6959 176 : if (total_weight == 0 && !is_init_mode)
6960 2 : pg_fatal("total script weight must not be zero");
6961 :
6962 : /* show per script stats if several scripts are used */
6963 174 : if (num_scripts > 1)
6964 6 : per_script_stats = true;
6965 :
6966 : /*
6967 : * Don't need more threads than there are clients. (This is not merely an
6968 : * optimization; throttle_delay is calculated incorrectly below if some
6969 : * threads have no clients assigned to them.)
6970 : */
6971 174 : if (nthreads > nclients)
6972 2 : nthreads = nclients;
6973 :
6974 : /*
6975 : * Convert throttle_delay to a per-thread delay time. Note that this
6976 : * might be a fractional number of usec, but that's OK, since it's just
6977 : * the center of a Poisson distribution of delays.
6978 : */
6979 174 : throttle_delay *= nthreads;
6980 :
6981 174 : if (argc > optind)
6982 2 : dbName = argv[optind++];
6983 : else
6984 : {
6985 172 : if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
6986 144 : dbName = env;
6987 28 : else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
6988 0 : dbName = env;
6989 : else
6990 28 : dbName = get_user_name_or_exit(progname);
6991 : }
6992 :
6993 174 : if (optind < argc)
6994 : {
6995 0 : pg_log_error("too many command-line arguments (first is \"%s\")",
6996 : argv[optind]);
6997 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
6998 0 : exit(1);
6999 : }
7000 :
7001 174 : if (is_init_mode)
7002 : {
7003 10 : if (benchmarking_option_set)
7004 2 : pg_fatal("some of the specified options cannot be used in initialization (-i) mode");
7005 :
7006 8 : if (partitions == 0 && partition_method != PART_NONE)
7007 2 : pg_fatal("--partition-method requires greater than zero --partitions");
7008 :
7009 : /* set default method */
7010 6 : if (partitions > 0 && partition_method == PART_NONE)
7011 2 : partition_method = PART_RANGE;
7012 :
7013 6 : if (initialize_steps == NULL)
7014 2 : initialize_steps = pg_strdup(DEFAULT_INIT_STEPS);
7015 :
7016 6 : if (is_no_vacuum)
7017 : {
7018 : /* Remove any vacuum step in initialize_steps */
7019 : char *p;
7020 :
7021 8 : while ((p = strchr(initialize_steps, 'v')) != NULL)
7022 6 : *p = ' ';
7023 : }
7024 :
7025 6 : if (foreign_keys)
7026 : {
7027 : /* Add 'f' to end of initialize_steps, if not already there */
7028 4 : if (strchr(initialize_steps, 'f') == NULL)
7029 : {
7030 : initialize_steps = (char *)
7031 4 : pg_realloc(initialize_steps,
7032 4 : strlen(initialize_steps) + 2);
7033 4 : strcat(initialize_steps, "f");
7034 : }
7035 : }
7036 :
7037 6 : runInitSteps(initialize_steps);
7038 6 : exit(0);
7039 : }
7040 : else
7041 : {
7042 164 : if (initialization_option_set)
7043 4 : pg_fatal("some of the specified options cannot be used in benchmarking mode");
7044 : }
7045 :
7046 160 : if (nxacts > 0 && duration > 0)
7047 4 : pg_fatal("specify either a number of transactions (-t) or a duration (-T), not both");
7048 :
7049 : /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
7050 156 : if (nxacts <= 0 && duration <= 0)
7051 16 : nxacts = DEFAULT_NXACTS;
7052 :
7053 : /* --sampling-rate may be used only with -l */
7054 156 : if (sample_rate > 0.0 && !use_log)
7055 2 : pg_fatal("log sampling (--sampling-rate) is allowed only when logging transactions (-l)");
7056 :
7057 : /* --sampling-rate may not be used with --aggregate-interval */
7058 154 : if (sample_rate > 0.0 && agg_interval > 0)
7059 2 : pg_fatal("log sampling (--sampling-rate) and aggregation (--aggregate-interval) cannot be used at the same time");
7060 :
7061 152 : if (agg_interval > 0 && !use_log)
7062 2 : pg_fatal("log aggregation is allowed only when actually logging transactions");
7063 :
7064 150 : if (!use_log && logfile_prefix)
7065 2 : pg_fatal("log file prefix (--log-prefix) is allowed only when logging transactions (-l)");
7066 :
7067 148 : if (duration > 0 && agg_interval > duration)
7068 2 : pg_fatal("number of seconds for aggregation (%d) must not be higher than test duration (%d)", agg_interval, duration);
7069 :
7070 146 : if (duration > 0 && agg_interval > 0 && duration % agg_interval != 0)
7071 2 : pg_fatal("duration (%d) must be a multiple of aggregation interval (%d)", duration, agg_interval);
7072 :
7073 144 : if (progress_timestamp && progress == 0)
7074 2 : pg_fatal("--progress-timestamp is allowed only under --progress");
7075 :
7076 142 : if (!max_tries)
7077 : {
7078 2 : if (!latency_limit && duration <= 0)
7079 2 : pg_fatal("an unlimited number of transaction tries can only be used with --latency-limit or a duration (-T)");
7080 : }
7081 :
7082 : /*
7083 : * save main process id in the global variable because process id will be
7084 : * changed after fork.
7085 : */
7086 140 : main_pid = (int) getpid();
7087 :
7088 140 : if (nclients > 1)
7089 : {
7090 24 : state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
7091 24 : memset(state + 1, 0, sizeof(CState) * (nclients - 1));
7092 :
7093 : /* copy any -D switch values to all clients */
7094 86 : for (i = 1; i < nclients; i++)
7095 : {
7096 : int j;
7097 :
7098 62 : state[i].id = i;
7099 64 : for (j = 0; j < state[0].variables.nvars; j++)
7100 : {
7101 2 : Variable *var = &state[0].variables.vars[j];
7102 :
7103 2 : if (var->value.type != PGBT_NO_VALUE)
7104 : {
7105 0 : if (!putVariableValue(&state[i].variables, "startup",
7106 0 : var->name, &var->value))
7107 0 : exit(1);
7108 : }
7109 : else
7110 : {
7111 2 : if (!putVariable(&state[i].variables, "startup",
7112 2 : var->name, var->svalue))
7113 0 : exit(1);
7114 : }
7115 : }
7116 : }
7117 : }
7118 :
7119 : /* other CState initializations */
7120 342 : for (i = 0; i < nclients; i++)
7121 : {
7122 202 : state[i].cstack = conditional_stack_create();
7123 202 : initRandomState(&state[i].cs_func_rs);
7124 : }
7125 :
7126 : /* opening connection... */
7127 140 : con = doConnect();
7128 140 : if (con == NULL)
7129 2 : pg_fatal("could not create connection for setup");
7130 :
7131 : /* report pgbench and server versions */
7132 138 : printVersion(con);
7133 :
7134 138 : pg_log_debug("pghost: %s pgport: %s nclients: %d %s: %d dbName: %s",
7135 : PQhost(con), PQport(con), nclients,
7136 : duration <= 0 ? "nxacts" : "duration",
7137 : duration <= 0 ? nxacts : duration, PQdb(con));
7138 :
7139 138 : if (internal_script_used)
7140 14 : GetTableInfo(con, scale_given);
7141 :
7142 : /*
7143 : * :scale variables normally get -s or database scale, but don't override
7144 : * an explicit -D switch
7145 : */
7146 136 : if (lookupVariable(&state[0].variables, "scale") == NULL)
7147 : {
7148 334 : for (i = 0; i < nclients; i++)
7149 : {
7150 198 : if (!putVariableInt(&state[i].variables, "startup", "scale", scale))
7151 0 : exit(1);
7152 : }
7153 : }
7154 :
7155 : /*
7156 : * Define a :client_id variable that is unique per connection. But don't
7157 : * override an explicit -D switch.
7158 : */
7159 136 : if (lookupVariable(&state[0].variables, "client_id") == NULL)
7160 : {
7161 334 : for (i = 0; i < nclients; i++)
7162 198 : if (!putVariableInt(&state[i].variables, "startup", "client_id", i))
7163 0 : exit(1);
7164 : }
7165 :
7166 : /* set default seed for hash functions */
7167 136 : if (lookupVariable(&state[0].variables, "default_seed") == NULL)
7168 : {
7169 136 : uint64 seed = pg_prng_uint64(&base_random_sequence);
7170 :
7171 334 : for (i = 0; i < nclients; i++)
7172 198 : if (!putVariableInt(&state[i].variables, "startup", "default_seed",
7173 : (int64) seed))
7174 0 : exit(1);
7175 : }
7176 :
7177 : /* set random seed unless overwritten */
7178 136 : if (lookupVariable(&state[0].variables, "random_seed") == NULL)
7179 : {
7180 334 : for (i = 0; i < nclients; i++)
7181 198 : if (!putVariableInt(&state[i].variables, "startup", "random_seed",
7182 : random_seed))
7183 0 : exit(1);
7184 : }
7185 :
7186 136 : if (!is_no_vacuum)
7187 : {
7188 18 : fprintf(stderr, "starting vacuum...");
7189 18 : tryExecuteStatement(con, "vacuum pgbench_branches");
7190 18 : tryExecuteStatement(con, "vacuum pgbench_tellers");
7191 18 : tryExecuteStatement(con, "truncate pgbench_history");
7192 18 : fprintf(stderr, "end.\n");
7193 :
7194 18 : if (do_vacuum_accounts)
7195 : {
7196 0 : fprintf(stderr, "starting vacuum pgbench_accounts...");
7197 0 : tryExecuteStatement(con, "vacuum analyze pgbench_accounts");
7198 0 : fprintf(stderr, "end.\n");
7199 : }
7200 : }
7201 136 : PQfinish(con);
7202 :
7203 : /* set up thread data structures */
7204 136 : threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
7205 136 : nclients_dealt = 0;
7206 :
7207 274 : for (i = 0; i < nthreads; i++)
7208 : {
7209 138 : TState *thread = &threads[i];
7210 :
7211 138 : thread->tid = i;
7212 138 : thread->state = &state[nclients_dealt];
7213 138 : thread->nstate =
7214 138 : (nclients - nclients_dealt + nthreads - i - 1) / (nthreads - i);
7215 138 : initRandomState(&thread->ts_choose_rs);
7216 138 : initRandomState(&thread->ts_throttle_rs);
7217 138 : initRandomState(&thread->ts_sample_rs);
7218 138 : thread->logfile = NULL; /* filled in later */
7219 138 : thread->latency_late = 0;
7220 138 : initStats(&thread->stats, 0);
7221 :
7222 138 : nclients_dealt += thread->nstate;
7223 : }
7224 :
7225 : /* all clients must be assigned to a thread */
7226 : Assert(nclients_dealt == nclients);
7227 :
7228 : /* get start up time for the whole computation */
7229 136 : start_time = pg_time_now();
7230 :
7231 : /* set alarm if duration is specified. */
7232 136 : if (duration > 0)
7233 0 : setalarm(duration);
7234 :
7235 136 : errno = THREAD_BARRIER_INIT(&barrier, nthreads);
7236 136 : if (errno != 0)
7237 0 : pg_fatal("could not initialize barrier: %m");
7238 :
7239 : #ifdef ENABLE_THREAD_SAFETY
7240 : /* start all threads but thread 0 which is executed directly later */
7241 138 : for (i = 1; i < nthreads; i++)
7242 : {
7243 2 : TState *thread = &threads[i];
7244 :
7245 2 : thread->create_time = pg_time_now();
7246 2 : errno = THREAD_CREATE(&thread->thread, threadRun, thread);
7247 :
7248 2 : if (errno != 0)
7249 0 : pg_fatal("could not create thread: %m");
7250 : }
7251 : #else
7252 : Assert(nthreads == 1);
7253 : #endif /* ENABLE_THREAD_SAFETY */
7254 :
7255 : /* compute when to stop */
7256 136 : threads[0].create_time = pg_time_now();
7257 136 : if (duration > 0)
7258 0 : end_time = threads[0].create_time + (int64) 1000000 * duration;
7259 :
7260 : /* run thread 0 directly */
7261 136 : (void) threadRun(&threads[0]);
7262 :
7263 : /* wait for other threads and accumulate results */
7264 136 : initStats(&stats, 0);
7265 136 : conn_total_duration = 0;
7266 :
7267 274 : for (i = 0; i < nthreads; i++)
7268 : {
7269 138 : TState *thread = &threads[i];
7270 :
7271 : #ifdef ENABLE_THREAD_SAFETY
7272 138 : if (i > 0)
7273 2 : THREAD_JOIN(thread->thread);
7274 : #endif /* ENABLE_THREAD_SAFETY */
7275 :
7276 336 : for (int j = 0; j < thread->nstate; j++)
7277 198 : if (thread->state[j].state != CSTATE_FINISHED)
7278 88 : exit_code = 2;
7279 :
7280 : /* aggregate thread level stats */
7281 138 : mergeSimpleStats(&stats.latency, &thread->stats.latency);
7282 138 : mergeSimpleStats(&stats.lag, &thread->stats.lag);
7283 138 : stats.cnt += thread->stats.cnt;
7284 138 : stats.skipped += thread->stats.skipped;
7285 138 : stats.retries += thread->stats.retries;
7286 138 : stats.retried += thread->stats.retried;
7287 138 : stats.serialization_failures += thread->stats.serialization_failures;
7288 138 : stats.deadlock_failures += thread->stats.deadlock_failures;
7289 138 : latency_late += thread->latency_late;
7290 138 : conn_total_duration += thread->conn_duration;
7291 :
7292 : /* first recorded benchmarking start time */
7293 138 : if (bench_start == 0 || thread->bench_start < bench_start)
7294 136 : bench_start = thread->bench_start;
7295 : }
7296 :
7297 : /*
7298 : * All connections should be already closed in threadRun(), so this
7299 : * disconnect_all() will be a no-op, but clean up the connections just to
7300 : * be sure. We don't need to measure the disconnection delays here.
7301 : */
7302 136 : disconnect_all(state, nclients);
7303 :
7304 : /*
7305 : * Beware that performance of short benchmarks with many threads and
7306 : * possibly long transactions can be deceptive because threads do not
7307 : * start and finish at the exact same time. The total duration computed
7308 : * here encompasses all transactions so that tps shown is somehow slightly
7309 : * underestimated.
7310 : */
7311 136 : printResults(&stats, pg_time_now() - bench_start, conn_total_duration,
7312 : bench_start - start_time, latency_late);
7313 :
7314 136 : THREAD_BARRIER_DESTROY(&barrier);
7315 :
7316 136 : if (exit_code != 0)
7317 88 : pg_log_error("Run was aborted; the above results are incomplete.");
7318 :
7319 136 : return exit_code;
7320 : }
7321 :
7322 : static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC
7323 138 : threadRun(void *arg)
7324 : {
7325 138 : TState *thread = (TState *) arg;
7326 138 : CState *state = thread->state;
7327 : pg_time_usec_t start;
7328 138 : int nstate = thread->nstate;
7329 138 : int remains = nstate; /* number of remaining clients */
7330 138 : socket_set *sockets = alloc_socket_set(nstate);
7331 : int64 thread_start,
7332 : last_report,
7333 : next_report;
7334 : StatsData last,
7335 : aggs;
7336 :
7337 : /* open log file if requested */
7338 138 : if (use_log)
7339 : {
7340 : char logpath[MAXPGPATH];
7341 4 : char *prefix = logfile_prefix ? logfile_prefix : "pgbench_log";
7342 :
7343 4 : if (thread->tid == 0)
7344 4 : snprintf(logpath, sizeof(logpath), "%s.%d", prefix, main_pid);
7345 : else
7346 0 : snprintf(logpath, sizeof(logpath), "%s.%d.%d", prefix, main_pid, thread->tid);
7347 :
7348 4 : thread->logfile = fopen(logpath, "w");
7349 :
7350 4 : if (thread->logfile == NULL)
7351 0 : pg_fatal("could not open logfile \"%s\": %m", logpath);
7352 : }
7353 :
7354 : /* explicitly initialize the state machines */
7355 336 : for (int i = 0; i < nstate; i++)
7356 198 : state[i].state = CSTATE_CHOOSE_SCRIPT;
7357 :
7358 : /* READY */
7359 138 : THREAD_BARRIER_WAIT(&barrier);
7360 :
7361 138 : thread_start = pg_time_now();
7362 138 : thread->started_time = thread_start;
7363 138 : thread->conn_duration = 0;
7364 138 : last_report = thread_start;
7365 138 : next_report = last_report + (int64) 1000000 * progress;
7366 :
7367 : /* STEADY */
7368 138 : if (!is_connect)
7369 : {
7370 : /* make connections to the database before starting */
7371 318 : for (int i = 0; i < nstate; i++)
7372 : {
7373 184 : if ((state[i].con = doConnect()) == NULL)
7374 : {
7375 : /* coldly abort on initial connection failure */
7376 0 : pg_fatal("could not create connection for client %d",
7377 : state[i].id);
7378 : }
7379 : }
7380 : }
7381 :
7382 : /* GO */
7383 138 : THREAD_BARRIER_WAIT(&barrier);
7384 :
7385 138 : start = pg_time_now();
7386 138 : thread->bench_start = start;
7387 138 : thread->throttle_trigger = start;
7388 :
7389 : /*
7390 : * The log format currently has Unix epoch timestamps with whole numbers
7391 : * of seconds. Round the first aggregate's start time down to the nearest
7392 : * Unix epoch second (the very first aggregate might really have started a
7393 : * fraction of a second later, but later aggregates are measured from the
7394 : * whole number time that is actually logged).
7395 : */
7396 138 : initStats(&aggs, (start + epoch_shift) / 1000000 * 1000000);
7397 138 : last = aggs;
7398 :
7399 : /* loop till all clients have terminated */
7400 13362 : while (remains > 0)
7401 : {
7402 : int nsocks; /* number of sockets to be waited for */
7403 : pg_time_usec_t min_usec;
7404 13224 : pg_time_usec_t now = 0; /* set this only if needed */
7405 :
7406 : /*
7407 : * identify which client sockets should be checked for input, and
7408 : * compute the nearest time (if any) at which we need to wake up.
7409 : */
7410 13224 : clear_socket_set(sockets);
7411 13224 : nsocks = 0;
7412 13224 : min_usec = PG_INT64_MAX;
7413 60976 : for (int i = 0; i < nstate; i++)
7414 : {
7415 52078 : CState *st = &state[i];
7416 :
7417 52078 : if (st->state == CSTATE_SLEEP || st->state == CSTATE_THROTTLE)
7418 6 : {
7419 : /* a nap from the script, or under throttling */
7420 : pg_time_usec_t this_usec;
7421 :
7422 : /* get current time if needed */
7423 6 : pg_time_now_lazy(&now);
7424 :
7425 : /* min_usec should be the minimum delay across all clients */
7426 12 : this_usec = (st->state == CSTATE_SLEEP ?
7427 6 : st->sleep_until : st->txn_scheduled) - now;
7428 6 : if (min_usec > this_usec)
7429 6 : min_usec = this_usec;
7430 : }
7431 52072 : else if (st->state == CSTATE_WAIT_RESULT ||
7432 8332 : st->state == CSTATE_WAIT_ROLLBACK_RESULT)
7433 43742 : {
7434 : /*
7435 : * waiting for result from server - nothing to do unless the
7436 : * socket is readable
7437 : */
7438 43742 : int sock = PQsocket(st->con);
7439 :
7440 43742 : if (sock < 0)
7441 : {
7442 0 : pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7443 0 : goto done;
7444 : }
7445 :
7446 43742 : add_socket_to_set(sockets, sock, nsocks++);
7447 : }
7448 8330 : else if (st->state != CSTATE_ABORTED &&
7449 8330 : st->state != CSTATE_FINISHED)
7450 : {
7451 : /*
7452 : * This client thread is ready to do something, so we don't
7453 : * want to wait. No need to examine additional clients.
7454 : */
7455 4326 : min_usec = 0;
7456 4326 : break;
7457 : }
7458 : }
7459 :
7460 : /* also wake up to print the next progress report on time */
7461 13224 : if (progress && min_usec > 0 && thread->tid == 0)
7462 : {
7463 0 : pg_time_now_lazy(&now);
7464 :
7465 0 : if (now >= next_report)
7466 0 : min_usec = 0;
7467 0 : else if ((next_report - now) < min_usec)
7468 0 : min_usec = next_report - now;
7469 : }
7470 :
7471 : /*
7472 : * If no clients are ready to execute actions, sleep until we receive
7473 : * data on some client socket or the timeout (if any) elapses.
7474 : */
7475 13224 : if (min_usec > 0)
7476 : {
7477 8898 : int rc = 0;
7478 :
7479 8898 : if (min_usec != PG_INT64_MAX)
7480 : {
7481 6 : if (nsocks > 0)
7482 : {
7483 0 : rc = wait_on_socket_set(sockets, min_usec);
7484 : }
7485 : else /* nothing active, simple sleep */
7486 : {
7487 6 : pg_usleep(min_usec);
7488 : }
7489 : }
7490 : else /* no explicit delay, wait without timeout */
7491 : {
7492 8892 : rc = wait_on_socket_set(sockets, 0);
7493 : }
7494 :
7495 8898 : if (rc < 0)
7496 : {
7497 0 : if (errno == EINTR)
7498 : {
7499 : /* On EINTR, go back to top of loop */
7500 0 : continue;
7501 : }
7502 : /* must be something wrong */
7503 0 : pg_log_error("%s() failed: %m", SOCKET_WAIT_METHOD);
7504 0 : goto done;
7505 : }
7506 : }
7507 : else
7508 : {
7509 : /* min_usec <= 0, i.e. something needs to be executed now */
7510 :
7511 : /* If we didn't wait, don't try to read any data */
7512 4326 : clear_socket_set(sockets);
7513 : }
7514 :
7515 : /* ok, advance the state machine of each connection */
7516 13224 : nsocks = 0;
7517 73670 : for (int i = 0; i < nstate; i++)
7518 : {
7519 60446 : CState *st = &state[i];
7520 :
7521 60446 : if (st->state == CSTATE_WAIT_RESULT ||
7522 9582 : st->state == CSTATE_WAIT_ROLLBACK_RESULT)
7523 10306 : {
7524 : /* don't call advanceConnectionState unless data is available */
7525 50866 : int sock = PQsocket(st->con);
7526 :
7527 50866 : if (sock < 0)
7528 : {
7529 0 : pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7530 0 : goto done;
7531 : }
7532 :
7533 50866 : if (!socket_has_input(sockets, sock, nsocks++))
7534 40560 : continue;
7535 : }
7536 9580 : else if (st->state == CSTATE_FINISHED ||
7537 4952 : st->state == CSTATE_ABORTED)
7538 : {
7539 : /* this client is done, no need to consider it anymore */
7540 4628 : continue;
7541 : }
7542 :
7543 15258 : advanceConnectionState(thread, st, &aggs);
7544 :
7545 : /*
7546 : * If advanceConnectionState changed client to finished state,
7547 : * that's one fewer client that remains.
7548 : */
7549 15258 : if (st->state == CSTATE_FINISHED || st->state == CSTATE_ABORTED)
7550 198 : remains--;
7551 : }
7552 :
7553 : /* progress report is made by thread 0 for all threads */
7554 13224 : if (progress && thread->tid == 0)
7555 : {
7556 0 : pg_time_usec_t now2 = pg_time_now();
7557 :
7558 0 : if (now2 >= next_report)
7559 : {
7560 : /*
7561 : * Horrible hack: this relies on the thread pointer we are
7562 : * passed to be equivalent to threads[0], that is the first
7563 : * entry of the threads array. That is why this MUST be done
7564 : * by thread 0 and not any other.
7565 : */
7566 0 : printProgressReport(thread, thread_start, now2,
7567 : &last, &last_report);
7568 :
7569 : /*
7570 : * Ensure that the next report is in the future, in case
7571 : * pgbench/postgres got stuck somewhere.
7572 : */
7573 : do
7574 : {
7575 0 : next_report += (int64) 1000000 * progress;
7576 0 : } while (now2 >= next_report);
7577 : }
7578 : }
7579 : }
7580 :
7581 138 : done:
7582 138 : disconnect_all(state, nstate);
7583 :
7584 138 : if (thread->logfile)
7585 : {
7586 4 : if (agg_interval > 0)
7587 : {
7588 : /* log aggregated but not yet reported transactions */
7589 0 : doLog(thread, state, &aggs, false, 0, 0);
7590 : }
7591 4 : fclose(thread->logfile);
7592 4 : thread->logfile = NULL;
7593 : }
7594 138 : free_socket_set(sockets);
7595 138 : THREAD_FUNC_RETURN;
7596 : }
7597 :
7598 : static void
7599 814 : finishCon(CState *st)
7600 : {
7601 814 : if (st->con != NULL)
7602 : {
7603 404 : PQfinish(st->con);
7604 404 : st->con = NULL;
7605 : }
7606 814 : }
7607 :
7608 : /*
7609 : * Support for duration option: set timer_exceeded after so many seconds.
7610 : */
7611 :
7612 : #ifndef WIN32
7613 :
7614 : static void
7615 0 : handle_sig_alarm(SIGNAL_ARGS)
7616 : {
7617 0 : timer_exceeded = true;
7618 0 : }
7619 :
7620 : static void
7621 0 : setalarm(int seconds)
7622 : {
7623 0 : pqsignal(SIGALRM, handle_sig_alarm);
7624 0 : alarm(seconds);
7625 0 : }
7626 :
7627 : #else /* WIN32 */
7628 :
7629 : static VOID CALLBACK
7630 : win32_timer_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
7631 : {
7632 : timer_exceeded = true;
7633 : }
7634 :
7635 : static void
7636 : setalarm(int seconds)
7637 : {
7638 : HANDLE queue;
7639 : HANDLE timer;
7640 :
7641 : /* This function will be called at most once, so we can cheat a bit. */
7642 : queue = CreateTimerQueue();
7643 : if (seconds > ((DWORD) -1) / 1000 ||
7644 : !CreateTimerQueueTimer(&timer, queue,
7645 : win32_timer_callback, NULL, seconds * 1000, 0,
7646 : WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE))
7647 : pg_fatal("failed to set timer");
7648 : }
7649 :
7650 : #endif /* WIN32 */
7651 :
7652 :
7653 : /*
7654 : * These functions provide an abstraction layer that hides the syscall
7655 : * we use to wait for input on a set of sockets.
7656 : *
7657 : * Currently there are two implementations, based on ppoll(2) and select(2).
7658 : * ppoll() is preferred where available due to its typically higher ceiling
7659 : * on the number of usable sockets. We do not use the more-widely-available
7660 : * poll(2) because it only offers millisecond timeout resolution, which could
7661 : * be problematic with high --rate settings.
7662 : *
7663 : * Function APIs:
7664 : *
7665 : * alloc_socket_set: allocate an empty socket set with room for up to
7666 : * "count" sockets.
7667 : *
7668 : * free_socket_set: deallocate a socket set.
7669 : *
7670 : * clear_socket_set: reset a socket set to empty.
7671 : *
7672 : * add_socket_to_set: add socket with indicated FD to slot "idx" in the
7673 : * socket set. Slots must be filled in order, starting with 0.
7674 : *
7675 : * wait_on_socket_set: wait for input on any socket in set, or for timeout
7676 : * to expire. timeout is measured in microseconds; 0 means wait forever.
7677 : * Returns result code of underlying syscall (>=0 if OK, else see errno).
7678 : *
7679 : * socket_has_input: after waiting, call this to see if given socket has
7680 : * input. fd and idx parameters should match some previous call to
7681 : * add_socket_to_set.
7682 : *
7683 : * Note that wait_on_socket_set destructively modifies the state of the
7684 : * socket set. After checking for input, caller must apply clear_socket_set
7685 : * and add_socket_to_set again before waiting again.
7686 : */
7687 :
7688 : #ifdef POLL_USING_PPOLL
7689 :
7690 : static socket_set *
7691 138 : alloc_socket_set(int count)
7692 : {
7693 : socket_set *sa;
7694 :
7695 138 : sa = (socket_set *) pg_malloc0(offsetof(socket_set, pollfds) +
7696 : sizeof(struct pollfd) * count);
7697 138 : sa->maxfds = count;
7698 138 : sa->curfds = 0;
7699 138 : return sa;
7700 : }
7701 :
7702 : static void
7703 138 : free_socket_set(socket_set *sa)
7704 : {
7705 138 : pg_free(sa);
7706 138 : }
7707 :
7708 : static void
7709 17550 : clear_socket_set(socket_set *sa)
7710 : {
7711 17550 : sa->curfds = 0;
7712 17550 : }
7713 :
7714 : static void
7715 43742 : add_socket_to_set(socket_set *sa, int fd, int idx)
7716 : {
7717 : Assert(idx < sa->maxfds && idx == sa->curfds);
7718 43742 : sa->pollfds[idx].fd = fd;
7719 43742 : sa->pollfds[idx].events = POLLIN;
7720 43742 : sa->pollfds[idx].revents = 0;
7721 43742 : sa->curfds++;
7722 43742 : }
7723 :
7724 : static int
7725 8892 : wait_on_socket_set(socket_set *sa, int64 usecs)
7726 : {
7727 8892 : if (usecs > 0)
7728 : {
7729 : struct timespec timeout;
7730 :
7731 0 : timeout.tv_sec = usecs / 1000000;
7732 0 : timeout.tv_nsec = (usecs % 1000000) * 1000;
7733 0 : return ppoll(sa->pollfds, sa->curfds, &timeout, NULL);
7734 : }
7735 : else
7736 : {
7737 8892 : return ppoll(sa->pollfds, sa->curfds, NULL, NULL);
7738 : }
7739 : }
7740 :
7741 : static bool
7742 50866 : socket_has_input(socket_set *sa, int fd, int idx)
7743 : {
7744 : /*
7745 : * In some cases, threadRun will apply clear_socket_set and then try to
7746 : * apply socket_has_input anyway with arguments that it used before that,
7747 : * or might've used before that except that it exited its setup loop
7748 : * early. Hence, if the socket set is empty, silently return false
7749 : * regardless of the parameters. If it's not empty, we can Assert that
7750 : * the parameters match a previous call.
7751 : */
7752 50866 : if (sa->curfds == 0)
7753 13812 : return false;
7754 :
7755 : Assert(idx < sa->curfds && sa->pollfds[idx].fd == fd);
7756 37054 : return (sa->pollfds[idx].revents & POLLIN) != 0;
7757 : }
7758 :
7759 : #endif /* POLL_USING_PPOLL */
7760 :
7761 : #ifdef POLL_USING_SELECT
7762 :
7763 : static socket_set *
7764 : alloc_socket_set(int count)
7765 : {
7766 : return (socket_set *) pg_malloc0(sizeof(socket_set));
7767 : }
7768 :
7769 : static void
7770 : free_socket_set(socket_set *sa)
7771 : {
7772 : pg_free(sa);
7773 : }
7774 :
7775 : static void
7776 : clear_socket_set(socket_set *sa)
7777 : {
7778 : FD_ZERO(&sa->fds);
7779 : sa->maxfd = -1;
7780 : }
7781 :
7782 : static void
7783 : add_socket_to_set(socket_set *sa, int fd, int idx)
7784 : {
7785 : if (fd < 0 || fd >= FD_SETSIZE)
7786 : {
7787 : /*
7788 : * Doing a hard exit here is a bit grotty, but it doesn't seem worth
7789 : * complicating the API to make it less grotty.
7790 : */
7791 : pg_fatal("too many client connections for select()");
7792 : }
7793 : FD_SET(fd, &sa->fds);
7794 : if (fd > sa->maxfd)
7795 : sa->maxfd = fd;
7796 : }
7797 :
7798 : static int
7799 : wait_on_socket_set(socket_set *sa, int64 usecs)
7800 : {
7801 : if (usecs > 0)
7802 : {
7803 : struct timeval timeout;
7804 :
7805 : timeout.tv_sec = usecs / 1000000;
7806 : timeout.tv_usec = usecs % 1000000;
7807 : return select(sa->maxfd + 1, &sa->fds, NULL, NULL, &timeout);
7808 : }
7809 : else
7810 : {
7811 : return select(sa->maxfd + 1, &sa->fds, NULL, NULL, NULL);
7812 : }
7813 : }
7814 :
7815 : static bool
7816 : socket_has_input(socket_set *sa, int fd, int idx)
7817 : {
7818 : return (FD_ISSET(fd, &sa->fds) != 0);
7819 : }
7820 :
7821 : #endif /* POLL_USING_SELECT */
|