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