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