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