2 * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.62 2007/03/13 09:06:35 mha 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 /* set up a connection to the backend */
198 con = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName,
202 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
203 fprintf(stderr, "Memory allocatin problem?\n");
207 if (PQstatus(con) == CONNECTION_BAD)
209 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
211 if (PQerrorMessage(con))
212 fprintf(stderr, "%s", PQerrorMessage(con));
214 fprintf(stderr, "No explanation from the backend\n");
219 res = PQexec(con, "SET search_path = public");
220 if (PQresultStatus(res) != PGRES_COMMAND_OK)
222 fprintf(stderr, "%s", PQerrorMessage(con));
230 /* throw away response from backend */
232 discard_response(CState * state)
238 res = PQgetResult(state->con);
244 /* check to see if the SQL result was good */
246 check(CState *state, PGresult *res, int n)
248 CState *st = &state[n];
250 switch (PQresultStatus(res))
252 case PGRES_COMMAND_OK:
253 case PGRES_TUPLES_OK:
257 fprintf(stderr, "Client %d aborted in state %d: %s",
258 n, st->state, PQerrorMessage(st->con));
259 remains--; /* I've aborted */
268 compareVariables(const void *v1, const void *v2)
270 return strcmp(((const Variable *) v1)->name,
271 ((const Variable *) v2)->name);
275 getVariable(CState * st, char *name)
280 /* On some versions of Solaris, bsearch of zero items dumps core */
281 if (st->nvariables <= 0)
285 var = (Variable *) bsearch((void *) &key,
286 (void *) st->variables,
297 putVariable(CState * st, char *name, char *value)
303 /* On some versions of Solaris, bsearch of zero items dumps core */
304 if (st->nvariables > 0)
305 var = (Variable *) bsearch((void *) &key,
306 (void *) st->variables,
318 newvars = (Variable *) realloc(st->variables,
319 (st->nvariables + 1) * sizeof(Variable));
321 newvars = (Variable *) malloc(sizeof(Variable));
326 st->variables = newvars;
328 var = &newvars[st->nvariables];
333 if ((var->name = strdup(name)) == NULL
334 || (var->value = strdup(value)) == NULL)
343 qsort((void *) st->variables, st->nvariables, sizeof(Variable),
350 if ((val = strdup(value)) == NULL)
361 assignVariables(CState * st, char *sql)
371 while ((p = strchr(&sql[i], ':')) != NULL)
377 } while (isalnum((unsigned char) sql[i]) || sql[i] == '_');
381 name = malloc(i - j);
384 memcpy(name, &sql[j + 1], i - (j + 1));
385 name[i - (j + 1)] = '\0';
386 val = getVariable(st, name);
391 if (strlen(val) > i - j)
393 tmp = realloc(sql, strlen(sql) - (i - j) + strlen(val) + 1);
402 if (strlen(val) != i - j)
403 memmove(&sql[j + strlen(val)], &sql[i], strlen(&sql[i]) + 1);
405 strncpy(&sql[j], val, strlen(val));
407 if (strlen(val) < i - j)
409 tmp = realloc(sql, strlen(sql) + 1);
425 doCustom(CState * state, int n, int debug)
428 CState *st = &state[n];
432 commands = sql_files[st->use_file];
435 { /* are we receiver? */
436 if (commands[st->state]->type == SQL_COMMAND)
439 fprintf(stderr, "client %d receiving\n", n);
440 if (!PQconsumeInput(st->con))
441 { /* there's something wrong */
442 fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
443 remains--; /* I've aborted */
448 if (PQisBusy(st->con))
449 return; /* don't have the whole result yet */
453 * transaction finished: record the time it took in the log
455 if (use_log && commands[st->state + 1] == NULL)
460 gettimeofday(&now, NULL);
461 diff = (int) (now.tv_sec - st->txn_begin.tv_sec) * 1000000.0 +
462 (int) (now.tv_usec - st->txn_begin.tv_usec);
464 fprintf(LOGFILE, "%d %d %.0f\n", st->id, st->cnt, diff);
467 if (commands[st->state]->type == SQL_COMMAND)
469 res = PQgetResult(st->con);
470 if (check(state, res, n))
476 discard_response(st);
479 if (commands[st->state + 1] == NULL)
487 if (++st->cnt >= nxacts)
489 remains--; /* I've done */
499 /* increment state counter */
501 if (commands[st->state] == NULL)
504 st->use_file = getrand(0, num_files - 1);
505 commands = sql_files[st->use_file];
511 if ((st->con = doConnect()) == NULL)
513 fprintf(stderr, "Client %d aborted in establishing connection.\n",
515 remains--; /* I've aborted */
522 if (use_log && st->state == 0)
523 gettimeofday(&(st->txn_begin), NULL);
525 if (commands[st->state]->type == SQL_COMMAND)
529 if ((sql = strdup(commands[st->state]->argv[0])) == NULL
530 || (sql = assignVariables(st, sql)) == NULL)
532 fprintf(stderr, "out of memory\n");
538 fprintf(stderr, "client %d sending %s\n", n, sql);
539 if (PQsendQuery(st->con, sql) == 0)
542 fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
547 st->listen = 1; /* flags that should be listened */
551 else if (commands[st->state]->type == META_COMMAND)
553 int argc = commands[st->state]->argc,
555 char **argv = commands[st->state]->argv;
559 fprintf(stderr, "client %d executing \\%s", n, argv[0]);
560 for (i = 1; i < argc; i++)
561 fprintf(stderr, " %s", argv[i]);
562 fprintf(stderr, "\n");
565 if (pg_strcasecmp(argv[0], "setrandom") == 0)
574 if ((var = getVariable(st, argv[2] + 1)) == NULL)
576 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[2]);
588 fprintf(stderr, "%s: invalid minimum number %d\n", argv[0], min);
596 if ((var = getVariable(st, argv[3] + 1)) == NULL)
598 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[3]);
607 if (max < min || max > MAX_RANDOM_VALUE)
609 fprintf(stderr, "%s: invalid maximum number %d\n", argv[0], max);
615 printf("min: %d max: %d random: %d\n", min, max, getrand(min, max));
617 snprintf(res, sizeof(res), "%d", getrand(min, max));
619 if (putVariable(st, argv[1], res) == false)
621 fprintf(stderr, "%s: out of memory\n", argv[0]);
628 else if (pg_strcasecmp(argv[0], "set") == 0)
637 if ((var = getVariable(st, argv[2] + 1)) == NULL)
639 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[2]);
646 ope1 = atoi(argv[2]);
649 snprintf(res, sizeof(res), "%d", ope1);
654 if ((var = getVariable(st, argv[4] + 1)) == NULL)
656 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[4]);
663 ope2 = atoi(argv[4]);
665 if (strcmp(argv[3], "+") == 0)
666 snprintf(res, sizeof(res), "%d", ope1 + ope2);
667 else if (strcmp(argv[3], "-") == 0)
668 snprintf(res, sizeof(res), "%d", ope1 - ope2);
669 else if (strcmp(argv[3], "*") == 0)
670 snprintf(res, sizeof(res), "%d", ope1 * ope2);
671 else if (strcmp(argv[3], "/") == 0)
675 fprintf(stderr, "%s: division by zero\n", argv[0]);
679 snprintf(res, sizeof(res), "%d", ope1 / ope2);
683 fprintf(stderr, "%s: unsupported operator %s\n", argv[0], argv[3]);
689 if (putVariable(st, argv[1], res) == false)
691 fprintf(stderr, "%s: out of memory\n", argv[0]);
703 /* discard connections */
705 disconnect_all(CState * state)
709 for (i = 0; i < nclients; i++)
712 PQfinish(state[i].con);
716 /* create tables and setup data */
722 static char *DDLs[] = {
723 "drop table branches",
724 "create table branches(bid int not null,bbalance int,filler char(88))",
725 "drop table tellers",
726 "create table tellers(tid int not null,bid int,tbalance int,filler char(84))",
727 "drop table accounts",
728 "create table accounts(aid int not null,bid int,abalance int,filler char(84))",
729 "drop table history",
730 "create table history(tid int,bid int,aid int,delta int,mtime timestamp,filler char(22))"};
731 static char *DDLAFTERs[] = {
732 "alter table branches add primary key (bid)",
733 "alter table tellers add primary key (tid)",
734 "alter table accounts add primary key (aid)"};
741 if ((con = doConnect()) == NULL)
744 for (i = 0; i < (sizeof(DDLs) / sizeof(char *)); i++)
746 res = PQexec(con, DDLs[i]);
747 if (strncmp(DDLs[i], "drop", 4) && PQresultStatus(res) != PGRES_COMMAND_OK)
749 fprintf(stderr, "%s", PQerrorMessage(con));
755 res = PQexec(con, "begin");
756 if (PQresultStatus(res) != PGRES_COMMAND_OK)
758 fprintf(stderr, "%s", PQerrorMessage(con));
763 for (i = 0; i < nbranches * scale; i++)
765 snprintf(sql, 256, "insert into branches(bid,bbalance) values(%d,0)", i + 1);
766 res = PQexec(con, sql);
767 if (PQresultStatus(res) != PGRES_COMMAND_OK)
769 fprintf(stderr, "%s", PQerrorMessage(con));
775 for (i = 0; i < ntellers * scale; i++)
777 snprintf(sql, 256, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)"
778 ,i + 1, i / ntellers + 1);
779 res = PQexec(con, sql);
780 if (PQresultStatus(res) != PGRES_COMMAND_OK)
782 fprintf(stderr, "%s", PQerrorMessage(con));
788 res = PQexec(con, "end");
789 if (PQresultStatus(res) != PGRES_COMMAND_OK)
791 fprintf(stderr, "%s", PQerrorMessage(con));
797 * occupy accounts table with some data
799 fprintf(stderr, "creating tables...\n");
800 for (i = 0; i < naccounts * scale; i++)
806 res = PQexec(con, "copy accounts from stdin");
807 if (PQresultStatus(res) != PGRES_COPY_IN)
809 fprintf(stderr, "%s", PQerrorMessage(con));
815 snprintf(sql, 256, "%d\t%d\t%d\t\n", j, i / naccounts + 1, 0);
816 if (PQputline(con, sql))
818 fprintf(stderr, "PQputline failed\n");
825 * every 10000 tuples, we commit the copy command. this should
826 * avoid generating too much WAL logs
828 fprintf(stderr, "%d tuples done.\n", j);
829 if (PQputline(con, "\\.\n"))
831 fprintf(stderr, "very last PQputline failed\n");
837 fprintf(stderr, "PQendcopy failed\n");
844 * do a checkpoint to purge the old WAL logs
846 res = PQexec(con, "checkpoint");
847 if (PQresultStatus(res) != PGRES_COMMAND_OK)
849 fprintf(stderr, "%s", PQerrorMessage(con));
853 #endif /* NOT_USED */
856 fprintf(stderr, "set primary key...\n");
857 for (i = 0; i < (sizeof(DDLAFTERs) / sizeof(char *)); i++)
859 res = PQexec(con, DDLAFTERs[i]);
860 if (PQresultStatus(res) != PGRES_COMMAND_OK)
862 fprintf(stderr, "%s", PQerrorMessage(con));
869 fprintf(stderr, "vacuum...");
870 res = PQexec(con, "vacuum analyze");
871 if (PQresultStatus(res) != PGRES_COMMAND_OK)
873 fprintf(stderr, "%s", PQerrorMessage(con));
877 fprintf(stderr, "done.\n");
883 process_commands(char *buf)
885 const char delim[] = " \f\n\r\t\v";
887 Command *my_commands;
892 if ((p = strchr(buf, '\n')) != NULL)
896 while (isspace((unsigned char) *p))
899 if (*p == '\0' || strncmp(p, "--", 2) == 0)
904 my_commands = (Command *) malloc(sizeof(Command));
905 if (my_commands == NULL)
910 my_commands->argc = 0;
914 my_commands->type = META_COMMAND;
917 tok = strtok(++p, delim);
921 if ((my_commands->argv[j] = strdup(tok)) == NULL)
927 tok = strtok(NULL, delim);
930 if (pg_strcasecmp(my_commands->argv[0], "setrandom") == 0)
932 if (my_commands->argc < 4)
934 fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
938 for (j = 4; j < my_commands->argc; j++)
939 fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
940 my_commands->argv[0], my_commands->argv[j]);
942 else if (pg_strcasecmp(my_commands->argv[0], "set") == 0)
944 if (my_commands->argc < 3)
946 fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
950 for (j = my_commands->argc < 5 ? 3 : 5; j < my_commands->argc; j++)
951 fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
952 my_commands->argv[0], my_commands->argv[j]);
956 fprintf(stderr, "invalid command %s\n", my_commands->argv[0]);
962 my_commands->type = SQL_COMMAND;
964 if ((my_commands->argv[0] = strdup(p)) == NULL)
974 process_file(char *filename)
976 #define COMMANDS_ALLOC_NUM 128
978 Command **my_commands;
984 if (num_files >= MAX_FILES)
986 fprintf(stderr, "Up to only %d SQL files are allowed\n", MAX_FILES);
990 alloc_num = COMMANDS_ALLOC_NUM;
991 my_commands = (Command **) malloc(sizeof(Command *) * alloc_num);
992 if (my_commands == NULL)
995 if (strcmp(filename, "-") == 0)
997 else if ((fd = fopen(filename, "r")) == NULL)
999 fprintf(stderr, "%s: %s\n", filename, strerror(errno));
1005 while (fgets(buf, sizeof(buf), fd) != NULL)
1011 while (isspace((unsigned char) buf[i]))
1014 if (buf[i] != '\0' && strncmp(&buf[i], "--", 2) != 0)
1016 commands = process_commands(&buf[i]);
1017 if (commands == NULL)
1026 my_commands[lineno] = commands;
1029 if (lineno >= alloc_num)
1031 alloc_num += COMMANDS_ALLOC_NUM;
1032 my_commands = realloc(my_commands, sizeof(Command *) * alloc_num);
1033 if (my_commands == NULL)
1042 my_commands[lineno] = NULL;
1044 sql_files[num_files++] = my_commands;
1050 process_builtin(char *tb)
1052 #define COMMANDS_ALLOC_NUM 128
1054 Command **my_commands;
1062 alloc_num = COMMANDS_ALLOC_NUM;
1063 my_commands = (Command **) malloc(sizeof(Command *) * alloc_num);
1064 if (my_commands == NULL)
1075 while (*tb && *tb != '\n')
1086 commands = process_commands(buf);
1087 if (commands == NULL)
1092 my_commands[lineno] = commands;
1095 if (lineno >= alloc_num)
1097 alloc_num += COMMANDS_ALLOC_NUM;
1098 my_commands = realloc(my_commands, sizeof(Command *) * alloc_num);
1099 if (my_commands == NULL)
1106 my_commands[lineno] = NULL;
1111 /* print out results */
1114 int ttype, CState * state,
1115 struct timeval * tv1, struct timeval * tv2,
1116 struct timeval * tv3)
1121 int normal_xacts = 0;
1124 for (i = 0; i < nclients; i++)
1125 normal_xacts += state[i].cnt;
1127 t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
1128 t1 = normal_xacts * 1000000.0 / t1;
1130 t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
1131 t2 = normal_xacts * 1000000.0 / t2;
1134 s = "TPC-B (sort of)";
1135 else if (ttype == 2)
1136 s = "Update only accounts";
1137 else if (ttype == 1)
1142 printf("transaction type: %s\n", s);
1143 printf("scaling factor: %d\n", scale);
1144 printf("number of clients: %d\n", nclients);
1145 printf("number of transactions per client: %d\n", nxacts);
1146 printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients);
1147 printf("tps = %f (including connections establishing)\n", t1);
1148 printf("tps = %f (excluding connections establishing)\n", t2);
1153 main(int argc, char **argv)
1156 int is_init_mode = 0; /* initialize mode? */
1157 int is_no_vacuum = 0; /* no vacuum at all before testing? */
1158 int is_full_vacuum = 0; /* do full vacuum before testing? */
1159 int debug = 0; /* debug flag */
1160 int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT only,
1161 * 2: skip update of branches and tellers */
1162 char *filename = NULL;
1164 CState *state; /* status of clients */
1166 struct timeval tv1; /* start up time */
1167 struct timeval tv2; /* after establishing all connections to the
1169 struct timeval tv3; /* end time */
1174 int nsocks; /* return from select(2) */
1175 int maxsock; /* max socket number to be waited */
1177 #ifdef HAVE_GETRLIMIT
1188 /* stderr is buffered on Win32. */
1189 setvbuf(stderr, NULL, _IONBF, 0);
1192 if ((env = getenv("PGHOST")) != NULL && *env != '\0')
1194 if ((env = getenv("PGPORT")) != NULL && *env != '\0')
1196 else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
1199 state = (CState *) malloc(sizeof(CState));
1202 fprintf(stderr, "Couldn't allocate memory for state\n");
1206 memset(state, 0, sizeof(*state));
1208 while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:D:")) != -1)
1237 nclients = atoi(optarg);
1238 if (nclients <= 0 || nclients > MAXCLIENTS)
1240 fprintf(stderr, "invalid number of clients: %d\n", nclients);
1243 #ifdef HAVE_GETRLIMIT
1244 #ifdef RLIMIT_NOFILE /* most platforms use RLIMIT_NOFILE */
1245 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
1246 #else /* but BSD doesn't ... */
1247 if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
1248 #endif /* RLIMIT_NOFILE */
1250 fprintf(stderr, "getrlimit failed: %s\n", strerror(errno));
1253 if (rlim.rlim_cur <= (nclients + 2))
1255 fprintf(stderr, "You need at least %d open files but you are only allowed to use %ld.\n", nclients + 2, (long) rlim.rlim_cur);
1256 fprintf(stderr, "Use limit/ulimit to increase the limit before using pgbench.\n");
1259 #endif /* HAVE_GETRLIMIT */
1265 scale = atoi(optarg);
1268 fprintf(stderr, "invalid scaling factor: %d\n", scale);
1273 nxacts = atoi(optarg);
1276 fprintf(stderr, "invalid number of transactions: %d\n", nxacts);
1292 if (process_file(filename) == false || *sql_files[num_files - 1] == NULL)
1299 if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
1301 fprintf(stderr, "invalid variable definition: %s\n", optarg);
1306 if (putVariable(&state[0], optarg, p) == false)
1308 fprintf(stderr, "Couldn't allocate memory for variable\n");
1321 dbName = argv[optind];
1324 if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
1326 else if (login != NULL && *login != '\0')
1340 if (getVariable(&state[0], "scale") == NULL)
1342 snprintf(val, sizeof(val), "%d", scale);
1343 if (putVariable(&state[0], "scale", val) == false)
1345 fprintf(stderr, "Couldn't allocate memory for variable\n");
1352 state = (CState *) realloc(state, sizeof(CState) * nclients);
1355 fprintf(stderr, "Couldn't allocate memory for state\n");
1359 memset(state + 1, 0, sizeof(*state) * (nclients - 1));
1361 snprintf(val, sizeof(val), "%d", scale);
1363 for (i = 1; i < nclients; i++)
1367 for (j = 0; j < state[0].nvariables; j++)
1369 if (putVariable(&state[i], state[0].variables[j].name, state[0].variables[j].value) == false)
1371 fprintf(stderr, "Couldn't allocate memory for variable\n");
1376 if (putVariable(&state[i], "scale", val) == false)
1378 fprintf(stderr, "Couldn't allocate memory for variable\n");
1388 snprintf(logpath, 64, "pgbench_log.%d", getpid());
1389 LOGFILE = fopen(logpath, "w");
1391 if (LOGFILE == NULL)
1393 fprintf(stderr, "Couldn't open logfile \"%s\": %s", logpath, strerror(errno));
1400 printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
1401 pghost, pgport, nclients, nxacts, dbName);
1404 /* opening connection... */
1409 if (PQstatus(con) == CONNECTION_BAD)
1411 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
1412 fprintf(stderr, "%s", PQerrorMessage(con));
1419 * get the scaling factor that should be same as count(*) from
1420 * branches if this is not a custom query
1422 res = PQexec(con, "select count(*) from branches");
1423 if (PQresultStatus(res) != PGRES_TUPLES_OK)
1425 fprintf(stderr, "%s", PQerrorMessage(con));
1428 scale = atoi(PQgetvalue(res, 0, 0));
1431 fprintf(stderr, "count(*) from branches invalid (%d)\n", scale);
1436 snprintf(val, sizeof(val), "%d", scale);
1437 if (putVariable(&state[0], "scale", val) == false)
1439 fprintf(stderr, "Couldn't allocate memory for variable\n");
1445 for (i = 1; i < nclients; i++)
1447 if (putVariable(&state[i], "scale", val) == false)
1449 fprintf(stderr, "Couldn't allocate memory for variable\n");
1458 fprintf(stderr, "starting vacuum...");
1459 res = PQexec(con, "vacuum branches");
1460 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1462 fprintf(stderr, "%s", PQerrorMessage(con));
1467 res = PQexec(con, "vacuum tellers");
1468 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1470 fprintf(stderr, "%s", PQerrorMessage(con));
1475 res = PQexec(con, "delete from history");
1476 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1478 fprintf(stderr, "%s", PQerrorMessage(con));
1482 res = PQexec(con, "vacuum history");
1483 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1485 fprintf(stderr, "%s", PQerrorMessage(con));
1490 fprintf(stderr, "end.\n");
1494 fprintf(stderr, "starting full vacuum...");
1495 res = PQexec(con, "vacuum analyze accounts");
1496 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1498 fprintf(stderr, "%s", PQerrorMessage(con));
1502 fprintf(stderr, "end.\n");
1507 /* set random seed */
1508 gettimeofday(&tv1, NULL);
1509 srandom((unsigned int) tv1.tv_usec);
1511 /* get start up time */
1512 gettimeofday(&tv1, NULL);
1514 if (is_connect == 0)
1516 /* make connections to the database */
1517 for (i = 0; i < nclients; i++)
1520 if ((state[i].con = doConnect()) == NULL)
1525 /* time after connections set up */
1526 gettimeofday(&tv2, NULL);
1528 /* process bultin SQL scripts */
1532 sql_files[0] = process_builtin(tpc_b);
1537 sql_files[0] = process_builtin(select_only);
1542 sql_files[0] = process_builtin(simple_update);
1550 /* send start up queries in async manner */
1551 for (i = 0; i < nclients; i++)
1553 Command **commands = sql_files[state[i].use_file];
1554 int prev_ecnt = state[i].ecnt;
1556 state[i].use_file = getrand(0, num_files - 1);
1557 doCustom(state, i, debug);
1559 if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
1561 fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
1562 remains--; /* I've aborted */
1563 PQfinish(state[i].con);
1564 state[i].con = NULL;
1572 disconnect_all(state);
1574 gettimeofday(&tv3, NULL);
1575 printResults(ttype, state, &tv1, &tv2, &tv3);
1581 FD_ZERO(&input_mask);
1584 for (i = 0; i < nclients; i++)
1586 Command **commands = sql_files[state[i].use_file];
1588 if (state[i].con && commands[state[i].state]->type != META_COMMAND)
1590 int sock = PQsocket(state[i].con);
1594 disconnect_all(state);
1597 FD_SET(sock, &input_mask);
1605 if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
1606 (fd_set *) NULL, (struct timeval *) NULL)) < 0)
1610 /* must be something wrong */
1611 disconnect_all(state);
1612 fprintf(stderr, "select failed: %s\n", strerror(errno));
1615 else if (nsocks == 0)
1617 fprintf(stderr, "select timeout\n");
1618 for (i = 0; i < nclients; i++)
1620 fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
1621 i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
1627 /* ok, backend returns reply */
1628 for (i = 0; i < nclients; i++)
1630 Command **commands = sql_files[state[i].use_file];
1631 int prev_ecnt = state[i].ecnt;
1633 if (state[i].con && (FD_ISSET(PQsocket(state[i].con), &input_mask)
1634 || commands[state[i].state]->type == META_COMMAND))
1636 doCustom(state, i, debug);
1639 if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
1641 fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
1642 remains--; /* I've aborted */
1643 PQfinish(state[i].con);
1644 state[i].con = NULL;