2 * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.64 2007/04/06 09:16:16 ishii Exp $
4 * pgbench: a simple benchmark program for PostgreSQL
5 * written by Tatsuo Ishii
7 * Copyright (c) 2000-2007 Tatsuo Ishii
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that copyright notice and this permission
13 * notice appear in supporting documentation, and that the name of the
14 * author not be used in advertising or publicity pertaining to
15 * distribution of the software without specific, written prior
16 * permission. The author makes no representations about the
17 * suitability of this software for any purpose. It is provided "as
18 * is" without express or implied warranty.
20 #include "postgres_fe.h"
36 #ifdef HAVE_SYS_SELECT_H
37 #include <sys/select.h>
40 #ifdef HAVE_SYS_RESOURCE_H
41 #include <sys/resource.h> /* for getrlimit */
53 /********************************************************************
54 * some configurable parameters */
56 #define MAXCLIENTS 1024 /* max number of clients allowed */
58 int nclients = 1; /* default number of simulated clients */
59 int nxacts = 10; /* default number of transactions per clients */
62 * scaling factor. for example, scale = 10 will make 1000000 tuples of
68 * end of configurable parameters
69 *********************************************************************/
73 #define naccounts 100000
77 bool use_log; /* log transaction latencies to a file */
79 int remains; /* number of remaining clients */
81 int is_connect; /* establish connection for each transaction */
85 char *pgoptions = NULL;
91 /* variable definitions */
94 char *name; /* variable name */
95 char *value; /* its value */
99 * structures used in custom query mode
104 PGconn *con; /* connection handle to DB */
105 int id; /* client No. */
106 int state; /* state No. */
107 int cnt; /* xacts count */
108 int ecnt; /* error count */
109 int listen; /* 0 indicates that an async query has been
111 Variable *variables; /* array of variable definitions */
113 struct timeval txn_begin; /* used for measuring latencies */
114 int use_file; /* index in sql_files for this client */
118 * queries read from files
120 #define SQL_COMMAND 1
121 #define META_COMMAND 2
126 int type; /* command type (SQL_COMMAND or META_COMMAND) */
127 int argc; /* number of commands */
128 char *argv[MAX_ARGS]; /* command list */
131 #define MAX_FILES 128 /* max number of SQL script files allowed */
133 Command **sql_files[MAX_FILES]; /* SQL script files */
134 int num_files; /* its number */
136 /* default scenario */
137 static char *tpc_b = {
138 "\\set nbranches :scale\n"
139 "\\set ntellers 10 * :scale\n"
140 "\\set naccounts 100000 * :scale\n"
141 "\\setrandom aid 1 :naccounts\n"
142 "\\setrandom bid 1 :nbranches\n"
143 "\\setrandom tid 1 :ntellers\n"
144 "\\setrandom delta -5000 5000\n"
146 "UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
147 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
148 "UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
149 "UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
150 "INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
155 static char *simple_update = {
156 "\\set nbranches :scale\n"
157 "\\set ntellers 10 * :scale\n"
158 "\\set naccounts 100000 * :scale\n"
159 "\\setrandom aid 1 :naccounts\n"
160 "\\setrandom bid 1 :nbranches\n"
161 "\\setrandom tid 1 :ntellers\n"
162 "\\setrandom delta -5000 5000\n"
164 "UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
165 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
166 "INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
171 static char *select_only = {
172 "\\set naccounts 100000 * :scale\n"
173 "\\setrandom aid 1 :naccounts\n"
174 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
180 fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-D varname=value][-n][-C][-v][-S][-N][-f filename][-l][-U login][-P password][-d][dbname]\n");
181 fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
184 /* random number generator */
186 getrand(int min, int max)
188 return min + (int) (((max - min) * (double) random()) / MAX_RANDOM_VALUE + 0.5);
191 /* call PQexec() and exit() on failure */
193 executeStatement(PGconn *con, const char* sql)
197 res = PQexec(con, sql);
198 if (PQresultStatus(res) != PGRES_COMMAND_OK)
200 fprintf(stderr, "%s", PQerrorMessage(con));
206 /* set up a connection to the backend */
212 con = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName,
216 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
217 fprintf(stderr, "Memory allocatin problem?\n");
221 if (PQstatus(con) == CONNECTION_BAD)
223 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
225 if (PQerrorMessage(con))
226 fprintf(stderr, "%s", PQerrorMessage(con));
228 fprintf(stderr, "No explanation from the backend\n");
233 executeStatement(con, "SET search_path = public");
238 /* throw away response from backend */
240 discard_response(CState * state)
246 res = PQgetResult(state->con);
252 /* check to see if the SQL result was good */
254 check(CState *state, PGresult *res, int n)
256 CState *st = &state[n];
258 switch (PQresultStatus(res))
260 case PGRES_COMMAND_OK:
261 case PGRES_TUPLES_OK:
265 fprintf(stderr, "Client %d aborted in state %d: %s",
266 n, st->state, PQerrorMessage(st->con));
267 remains--; /* I've aborted */
276 compareVariables(const void *v1, const void *v2)
278 return strcmp(((const Variable *) v1)->name,
279 ((const Variable *) v2)->name);
283 getVariable(CState * st, char *name)
288 /* On some versions of Solaris, bsearch of zero items dumps core */
289 if (st->nvariables <= 0)
293 var = (Variable *) bsearch((void *) &key,
294 (void *) st->variables,
305 putVariable(CState * st, char *name, char *value)
311 /* On some versions of Solaris, bsearch of zero items dumps core */
312 if (st->nvariables > 0)
313 var = (Variable *) bsearch((void *) &key,
314 (void *) st->variables,
326 newvars = (Variable *) realloc(st->variables,
327 (st->nvariables + 1) * sizeof(Variable));
329 newvars = (Variable *) malloc(sizeof(Variable));
334 st->variables = newvars;
336 var = &newvars[st->nvariables];
341 if ((var->name = strdup(name)) == NULL
342 || (var->value = strdup(value)) == NULL)
351 qsort((void *) st->variables, st->nvariables, sizeof(Variable),
358 if ((val = strdup(value)) == NULL)
369 assignVariables(CState * st, char *sql)
379 while ((p = strchr(&sql[i], ':')) != NULL)
385 } while (isalnum((unsigned char) sql[i]) || sql[i] == '_');
389 name = malloc(i - j);
392 memcpy(name, &sql[j + 1], i - (j + 1));
393 name[i - (j + 1)] = '\0';
394 val = getVariable(st, name);
399 if (strlen(val) > i - j)
401 tmp = realloc(sql, strlen(sql) - (i - j) + strlen(val) + 1);
410 if (strlen(val) != i - j)
411 memmove(&sql[j + strlen(val)], &sql[i], strlen(&sql[i]) + 1);
413 strncpy(&sql[j], val, strlen(val));
415 if (strlen(val) < i - j)
417 tmp = realloc(sql, strlen(sql) + 1);
433 doCustom(CState * state, int n, int debug)
436 CState *st = &state[n];
440 commands = sql_files[st->use_file];
443 { /* are we receiver? */
444 if (commands[st->state]->type == SQL_COMMAND)
447 fprintf(stderr, "client %d receiving\n", n);
448 if (!PQconsumeInput(st->con))
449 { /* there's something wrong */
450 fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
451 remains--; /* I've aborted */
456 if (PQisBusy(st->con))
457 return; /* don't have the whole result yet */
461 * transaction finished: record the time it took in the log
463 if (use_log && commands[st->state + 1] == NULL)
468 gettimeofday(&now, NULL);
469 diff = (int) (now.tv_sec - st->txn_begin.tv_sec) * 1000000.0 +
470 (int) (now.tv_usec - st->txn_begin.tv_usec);
472 fprintf(LOGFILE, "%d %d %.0f %d %ld %ld\n",
473 st->id, st->cnt, diff, st->use_file, now.tv_sec,now.tv_usec);
476 if (commands[st->state]->type == SQL_COMMAND)
478 res = PQgetResult(st->con);
479 if (check(state, res, n))
485 discard_response(st);
488 if (commands[st->state + 1] == NULL)
496 if (++st->cnt >= nxacts)
498 remains--; /* I've done */
508 /* increment state counter */
510 if (commands[st->state] == NULL)
513 st->use_file = getrand(0, num_files - 1);
514 commands = sql_files[st->use_file];
520 if ((st->con = doConnect()) == NULL)
522 fprintf(stderr, "Client %d aborted in establishing connection.\n",
524 remains--; /* I've aborted */
531 if (use_log && st->state == 0)
532 gettimeofday(&(st->txn_begin), NULL);
534 if (commands[st->state]->type == SQL_COMMAND)
538 if ((sql = strdup(commands[st->state]->argv[0])) == NULL
539 || (sql = assignVariables(st, sql)) == NULL)
541 fprintf(stderr, "out of memory\n");
547 fprintf(stderr, "client %d sending %s\n", n, sql);
548 if (PQsendQuery(st->con, sql) == 0)
551 fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
556 st->listen = 1; /* flags that should be listened */
560 else if (commands[st->state]->type == META_COMMAND)
562 int argc = commands[st->state]->argc,
564 char **argv = commands[st->state]->argv;
568 fprintf(stderr, "client %d executing \\%s", n, argv[0]);
569 for (i = 1; i < argc; i++)
570 fprintf(stderr, " %s", argv[i]);
571 fprintf(stderr, "\n");
574 if (pg_strcasecmp(argv[0], "setrandom") == 0)
583 if ((var = getVariable(st, argv[2] + 1)) == NULL)
585 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[2]);
597 fprintf(stderr, "%s: invalid minimum number %d\n", argv[0], min);
605 if ((var = getVariable(st, argv[3] + 1)) == NULL)
607 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[3]);
616 if (max < min || max > MAX_RANDOM_VALUE)
618 fprintf(stderr, "%s: invalid maximum number %d\n", argv[0], max);
624 printf("min: %d max: %d random: %d\n", min, max, getrand(min, max));
626 snprintf(res, sizeof(res), "%d", getrand(min, max));
628 if (putVariable(st, argv[1], res) == false)
630 fprintf(stderr, "%s: out of memory\n", argv[0]);
637 else if (pg_strcasecmp(argv[0], "set") == 0)
646 if ((var = getVariable(st, argv[2] + 1)) == NULL)
648 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[2]);
655 ope1 = atoi(argv[2]);
658 snprintf(res, sizeof(res), "%d", ope1);
663 if ((var = getVariable(st, argv[4] + 1)) == NULL)
665 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[4]);
672 ope2 = atoi(argv[4]);
674 if (strcmp(argv[3], "+") == 0)
675 snprintf(res, sizeof(res), "%d", ope1 + ope2);
676 else if (strcmp(argv[3], "-") == 0)
677 snprintf(res, sizeof(res), "%d", ope1 - ope2);
678 else if (strcmp(argv[3], "*") == 0)
679 snprintf(res, sizeof(res), "%d", ope1 * ope2);
680 else if (strcmp(argv[3], "/") == 0)
684 fprintf(stderr, "%s: division by zero\n", argv[0]);
688 snprintf(res, sizeof(res), "%d", ope1 / ope2);
692 fprintf(stderr, "%s: unsupported operator %s\n", argv[0], argv[3]);
698 if (putVariable(st, argv[1], res) == false)
700 fprintf(stderr, "%s: out of memory\n", argv[0]);
712 /* discard connections */
714 disconnect_all(CState * state)
718 for (i = 0; i < nclients; i++)
721 PQfinish(state[i].con);
725 /* create tables and setup data */
731 static char *DDLs[] = {
732 "drop table if exists branches",
733 "create table branches(bid int not null,bbalance int,filler char(88))",
734 "drop table if exists tellers",
735 "create table tellers(tid int not null,bid int,tbalance int,filler char(84))",
736 "drop table if exists accounts",
737 "create table accounts(aid int not null,bid int,abalance int,filler char(84))",
738 "drop table if exists history",
739 "create table history(tid int,bid int,aid int,delta int,mtime timestamp,filler char(22))"};
740 static char *DDLAFTERs[] = {
741 "alter table branches add primary key (bid)",
742 "alter table tellers add primary key (tid)",
743 "alter table accounts add primary key (aid)"};
750 if ((con = doConnect()) == NULL)
753 for (i = 0; i < lengthof(DDLs); i++)
754 executeStatement(con, DDLs[i]);
756 executeStatement(con, "begin");
758 for (i = 0; i < nbranches * scale; i++)
760 snprintf(sql, 256, "insert into branches(bid,bbalance) values(%d,0)", i + 1);
761 executeStatement(con, sql);
764 for (i = 0; i < ntellers * scale; i++)
766 snprintf(sql, 256, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)"
767 ,i + 1, i / ntellers + 1);
768 executeStatement(con, sql);
771 executeStatement(con, "commit");
774 * fill the accounts table with some data
776 fprintf(stderr, "creating tables...\n");
778 executeStatement(con, "begin");
779 executeStatement(con, "truncate accounts");
781 res = PQexec(con, "copy accounts from stdin");
782 if (PQresultStatus(res) != PGRES_COPY_IN)
784 fprintf(stderr, "%s", PQerrorMessage(con));
789 for (i = 0; i < naccounts * scale; i++)
793 snprintf(sql, 256, "%d\t%d\t%d\t\n", j, i / naccounts + 1, 0);
794 if (PQputline(con, sql))
796 fprintf(stderr, "PQputline failed\n");
801 fprintf(stderr, "%d tuples done.\n", j);
803 if (PQputline(con, "\\.\n"))
805 fprintf(stderr, "very last PQputline failed\n");
810 fprintf(stderr, "PQendcopy failed\n");
813 executeStatement(con, "commit");
818 fprintf(stderr, "set primary key...\n");
819 for (i = 0; i < lengthof(DDLAFTERs); i++)
820 executeStatement(con, DDLAFTERs[i]);
823 fprintf(stderr, "vacuum...");
824 executeStatement(con, "vacuum analyze");
826 fprintf(stderr, "done.\n");
831 process_commands(char *buf)
833 const char delim[] = " \f\n\r\t\v";
835 Command *my_commands;
840 if ((p = strchr(buf, '\n')) != NULL)
844 while (isspace((unsigned char) *p))
847 if (*p == '\0' || strncmp(p, "--", 2) == 0)
852 my_commands = (Command *) malloc(sizeof(Command));
853 if (my_commands == NULL)
858 my_commands->argc = 0;
862 my_commands->type = META_COMMAND;
865 tok = strtok(++p, delim);
869 if ((my_commands->argv[j] = strdup(tok)) == NULL)
875 tok = strtok(NULL, delim);
878 if (pg_strcasecmp(my_commands->argv[0], "setrandom") == 0)
880 if (my_commands->argc < 4)
882 fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
886 for (j = 4; j < my_commands->argc; j++)
887 fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
888 my_commands->argv[0], my_commands->argv[j]);
890 else if (pg_strcasecmp(my_commands->argv[0], "set") == 0)
892 if (my_commands->argc < 3)
894 fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
898 for (j = my_commands->argc < 5 ? 3 : 5; j < my_commands->argc; j++)
899 fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
900 my_commands->argv[0], my_commands->argv[j]);
904 fprintf(stderr, "invalid command %s\n", my_commands->argv[0]);
910 my_commands->type = SQL_COMMAND;
912 if ((my_commands->argv[0] = strdup(p)) == NULL)
922 process_file(char *filename)
924 #define COMMANDS_ALLOC_NUM 128
926 Command **my_commands;
932 if (num_files >= MAX_FILES)
934 fprintf(stderr, "Up to only %d SQL files are allowed\n", MAX_FILES);
938 alloc_num = COMMANDS_ALLOC_NUM;
939 my_commands = (Command **) malloc(sizeof(Command *) * alloc_num);
940 if (my_commands == NULL)
943 if (strcmp(filename, "-") == 0)
945 else if ((fd = fopen(filename, "r")) == NULL)
947 fprintf(stderr, "%s: %s\n", filename, strerror(errno));
953 while (fgets(buf, sizeof(buf), fd) != NULL)
959 while (isspace((unsigned char) buf[i]))
962 if (buf[i] != '\0' && strncmp(&buf[i], "--", 2) != 0)
964 commands = process_commands(&buf[i]);
965 if (commands == NULL)
974 my_commands[lineno] = commands;
977 if (lineno >= alloc_num)
979 alloc_num += COMMANDS_ALLOC_NUM;
980 my_commands = realloc(my_commands, sizeof(Command *) * alloc_num);
981 if (my_commands == NULL)
990 my_commands[lineno] = NULL;
992 sql_files[num_files++] = my_commands;
998 process_builtin(char *tb)
1000 #define COMMANDS_ALLOC_NUM 128
1002 Command **my_commands;
1010 alloc_num = COMMANDS_ALLOC_NUM;
1011 my_commands = (Command **) malloc(sizeof(Command *) * alloc_num);
1012 if (my_commands == NULL)
1023 while (*tb && *tb != '\n')
1034 commands = process_commands(buf);
1035 if (commands == NULL)
1040 my_commands[lineno] = commands;
1043 if (lineno >= alloc_num)
1045 alloc_num += COMMANDS_ALLOC_NUM;
1046 my_commands = realloc(my_commands, sizeof(Command *) * alloc_num);
1047 if (my_commands == NULL)
1054 my_commands[lineno] = NULL;
1059 /* print out results */
1062 int ttype, CState * state,
1063 struct timeval * tv1, struct timeval * tv2,
1064 struct timeval * tv3)
1069 int normal_xacts = 0;
1072 for (i = 0; i < nclients; i++)
1073 normal_xacts += state[i].cnt;
1075 t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
1076 t1 = normal_xacts * 1000000.0 / t1;
1078 t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
1079 t2 = normal_xacts * 1000000.0 / t2;
1082 s = "TPC-B (sort of)";
1083 else if (ttype == 2)
1084 s = "Update only accounts";
1085 else if (ttype == 1)
1090 printf("transaction type: %s\n", s);
1091 printf("scaling factor: %d\n", scale);
1092 printf("number of clients: %d\n", nclients);
1093 printf("number of transactions per client: %d\n", nxacts);
1094 printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients);
1095 printf("tps = %f (including connections establishing)\n", t1);
1096 printf("tps = %f (excluding connections establishing)\n", t2);
1101 main(int argc, char **argv)
1104 int is_init_mode = 0; /* initialize mode? */
1105 int is_no_vacuum = 0; /* no vacuum at all before testing? */
1106 int do_vacuum_accounts = 0; /* do vacuum accounts before testing? */
1107 int debug = 0; /* debug flag */
1108 int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT only,
1109 * 2: skip update of branches and tellers */
1110 char *filename = NULL;
1112 CState *state; /* status of clients */
1114 struct timeval tv1; /* start up time */
1115 struct timeval tv2; /* after establishing all connections to the
1117 struct timeval tv3; /* end time */
1122 int nsocks; /* return from select(2) */
1123 int maxsock; /* max socket number to be waited */
1125 #ifdef HAVE_GETRLIMIT
1136 /* stderr is buffered on Win32. */
1137 setvbuf(stderr, NULL, _IONBF, 0);
1140 if ((env = getenv("PGHOST")) != NULL && *env != '\0')
1142 if ((env = getenv("PGPORT")) != NULL && *env != '\0')
1144 else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
1147 state = (CState *) malloc(sizeof(CState));
1150 fprintf(stderr, "Couldn't allocate memory for state\n");
1154 memset(state, 0, sizeof(*state));
1156 while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:D:")) != -1)
1170 do_vacuum_accounts++;
1185 nclients = atoi(optarg);
1186 if (nclients <= 0 || nclients > MAXCLIENTS)
1188 fprintf(stderr, "invalid number of clients: %d\n", nclients);
1191 #ifdef HAVE_GETRLIMIT
1192 #ifdef RLIMIT_NOFILE /* most platforms use RLIMIT_NOFILE */
1193 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
1194 #else /* but BSD doesn't ... */
1195 if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
1196 #endif /* RLIMIT_NOFILE */
1198 fprintf(stderr, "getrlimit failed: %s\n", strerror(errno));
1201 if (rlim.rlim_cur <= (nclients + 2))
1203 fprintf(stderr, "You need at least %d open files but you are only allowed to use %ld.\n", nclients + 2, (long) rlim.rlim_cur);
1204 fprintf(stderr, "Use limit/ulimit to increase the limit before using pgbench.\n");
1207 #endif /* HAVE_GETRLIMIT */
1213 scale = atoi(optarg);
1216 fprintf(stderr, "invalid scaling factor: %d\n", scale);
1221 nxacts = atoi(optarg);
1224 fprintf(stderr, "invalid number of transactions: %d\n", nxacts);
1240 if (process_file(filename) == false || *sql_files[num_files - 1] == NULL)
1247 if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
1249 fprintf(stderr, "invalid variable definition: %s\n", optarg);
1254 if (putVariable(&state[0], optarg, p) == false)
1256 fprintf(stderr, "Couldn't allocate memory for variable\n");
1269 dbName = argv[optind];
1272 if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
1274 else if (login != NULL && *login != '\0')
1288 if (getVariable(&state[0], "scale") == NULL)
1290 snprintf(val, sizeof(val), "%d", scale);
1291 if (putVariable(&state[0], "scale", val) == false)
1293 fprintf(stderr, "Couldn't allocate memory for variable\n");
1300 state = (CState *) realloc(state, sizeof(CState) * nclients);
1303 fprintf(stderr, "Couldn't allocate memory for state\n");
1307 memset(state + 1, 0, sizeof(*state) * (nclients - 1));
1309 snprintf(val, sizeof(val), "%d", scale);
1311 for (i = 1; i < nclients; i++)
1315 for (j = 0; j < state[0].nvariables; j++)
1317 if (putVariable(&state[i], state[0].variables[j].name, state[0].variables[j].value) == false)
1319 fprintf(stderr, "Couldn't allocate memory for variable\n");
1324 if (putVariable(&state[i], "scale", val) == false)
1326 fprintf(stderr, "Couldn't allocate memory for variable\n");
1336 snprintf(logpath, 64, "pgbench_log.%d", getpid());
1337 LOGFILE = fopen(logpath, "w");
1339 if (LOGFILE == NULL)
1341 fprintf(stderr, "Couldn't open logfile \"%s\": %s", logpath, strerror(errno));
1348 printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
1349 pghost, pgport, nclients, nxacts, dbName);
1352 /* opening connection... */
1357 if (PQstatus(con) == CONNECTION_BAD)
1359 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
1360 fprintf(stderr, "%s", PQerrorMessage(con));
1367 * get the scaling factor that should be same as count(*) from
1368 * branches if this is not a custom query
1370 res = PQexec(con, "select count(*) from branches");
1371 if (PQresultStatus(res) != PGRES_TUPLES_OK)
1373 fprintf(stderr, "%s", PQerrorMessage(con));
1376 scale = atoi(PQgetvalue(res, 0, 0));
1379 fprintf(stderr, "count(*) from branches invalid (%d)\n", scale);
1384 snprintf(val, sizeof(val), "%d", scale);
1385 if (putVariable(&state[0], "scale", val) == false)
1387 fprintf(stderr, "Couldn't allocate memory for variable\n");
1393 for (i = 1; i < nclients; i++)
1395 if (putVariable(&state[i], "scale", val) == false)
1397 fprintf(stderr, "Couldn't allocate memory for variable\n");
1406 fprintf(stderr, "starting vacuum...");
1407 executeStatement(con, "vacuum branches");
1408 executeStatement(con, "vacuum tellers");
1409 executeStatement(con, "delete from history");
1410 executeStatement(con, "vacuum history");
1411 fprintf(stderr, "end.\n");
1413 if (do_vacuum_accounts)
1415 fprintf(stderr, "starting vacuum accounts...");
1416 executeStatement(con, "vacuum analyze accounts");
1417 fprintf(stderr, "end.\n");
1422 /* set random seed */
1423 gettimeofday(&tv1, NULL);
1424 srandom((unsigned int) tv1.tv_usec);
1426 /* get start up time */
1427 gettimeofday(&tv1, NULL);
1429 if (is_connect == 0)
1431 /* make connections to the database */
1432 for (i = 0; i < nclients; i++)
1435 if ((state[i].con = doConnect()) == NULL)
1440 /* time after connections set up */
1441 gettimeofday(&tv2, NULL);
1443 /* process bultin SQL scripts */
1447 sql_files[0] = process_builtin(tpc_b);
1452 sql_files[0] = process_builtin(select_only);
1457 sql_files[0] = process_builtin(simple_update);
1465 /* send start up queries in async manner */
1466 for (i = 0; i < nclients; i++)
1468 Command **commands = sql_files[state[i].use_file];
1469 int prev_ecnt = state[i].ecnt;
1471 state[i].use_file = getrand(0, num_files - 1);
1472 doCustom(state, i, debug);
1474 if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
1476 fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
1477 remains--; /* I've aborted */
1478 PQfinish(state[i].con);
1479 state[i].con = NULL;
1487 disconnect_all(state);
1489 gettimeofday(&tv3, NULL);
1490 printResults(ttype, state, &tv1, &tv2, &tv3);
1496 FD_ZERO(&input_mask);
1499 for (i = 0; i < nclients; i++)
1501 Command **commands = sql_files[state[i].use_file];
1503 if (state[i].con && commands[state[i].state]->type != META_COMMAND)
1505 int sock = PQsocket(state[i].con);
1509 disconnect_all(state);
1512 FD_SET(sock, &input_mask);
1520 if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
1521 (fd_set *) NULL, (struct timeval *) NULL)) < 0)
1525 /* must be something wrong */
1526 disconnect_all(state);
1527 fprintf(stderr, "select failed: %s\n", strerror(errno));
1530 else if (nsocks == 0)
1532 fprintf(stderr, "select timeout\n");
1533 for (i = 0; i < nclients; i++)
1535 fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
1536 i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
1542 /* ok, backend returns reply */
1543 for (i = 0; i < nclients; i++)
1545 Command **commands = sql_files[state[i].use_file];
1546 int prev_ecnt = state[i].ecnt;
1548 if (state[i].con && (FD_ISSET(PQsocket(state[i].con), &input_mask)
1549 || commands[state[i].state]->type == META_COMMAND))
1551 doCustom(state, i, debug);
1554 if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
1556 fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
1557 remains--; /* I've aborted */
1558 PQfinish(state[i].con);
1559 state[i].con = NULL;