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