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