2 * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.50 2006/07/26 07:24:50 ishii Exp $
4 * pgbench: a simple benchmark program for PostgreSQL
5 * written by Tatsuo Ishii
7 * Copyright (c) 2000-2005 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>
41 #include <sys/resource.h>
52 /********************************************************************
53 * some configurable parameters */
55 #define MAXCLIENTS 1024 /* max number of clients allowed */
57 int nclients = 1; /* default number of simulated clients */
58 int nxacts = 10; /* default number of transactions per clients */
61 * scaling factor. for example, tps = 10 will make 1000000 tuples of
67 * end of configurable parameters
68 *********************************************************************/
72 #define naccounts 100000
76 bool use_log; /* log transaction latencies to a file */
78 int remains; /* number of remaining clients */
80 int is_connect; /* establish connection for each transaction */
84 char *pgoptions = NULL;
90 /* variable definitions */
93 char *name; /* variable name */
94 char *value; /* its value */
98 * structures used in custom query mode
103 PGconn *con; /* connection handle to DB */
104 int id; /* client No. */
105 int state; /* state No. */
106 int cnt; /* xacts count */
107 int ecnt; /* error count */
108 int listen; /* 0 indicates that an async query has been
110 Variable *variables; /* array of variable definitions */
112 struct timeval txn_begin; /* used for measuring latencies */
113 int use_file; /* index in sql_files for this client */
117 * queries read from files
119 #define SQL_COMMAND 1
120 #define META_COMMAND 2
125 int type; /* command type (SQL_COMMAND or META_COMMAND) */
126 int argc; /* number of commands */
127 char *argv[MAX_ARGS]; /* command list */
130 #define MAX_FILES 128 /* max number of SQL script files allowed */
132 Command **sql_files[MAX_FILES]; /* SQL script files */
133 int num_files; /* its number */
135 /* default scenario */
136 static char *tpc_b = {
137 "\\setrandom aid 1 100000\n"
138 "\\setrandom bid 1 1\n"
139 "\\setrandom tid 1 10\n"
140 "\\setrandom delta 1 10000\n"
142 "UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
143 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
144 "UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
145 "UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
146 "INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
151 static char *simple_update = {
152 "\\setrandom aid 1 100000\n"
153 "\\setrandom bid 1 1\n"
154 "\\setrandom tid 1 10\n"
155 "\\setrandom delta 1 10000\n"
157 "UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
158 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
159 "INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
164 static char *select_only = {
165 "\\setrandom aid 1 100000\n"
166 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
172 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");
173 fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
176 /* random number generator */
178 getrand(int min, int max)
180 return min + (int) (((max - min) * (double) random()) / MAX_RANDOM_VALUE + 0.5);
183 /* set up a connection to the backend */
190 con = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName,
194 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
195 fprintf(stderr, "Memory allocatin problem?\n");
199 if (PQstatus(con) == CONNECTION_BAD)
201 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
203 if (PQerrorMessage(con))
204 fprintf(stderr, "%s", PQerrorMessage(con));
206 fprintf(stderr, "No explanation from the backend\n");
211 res = PQexec(con, "SET search_path = public");
212 if (PQresultStatus(res) != PGRES_COMMAND_OK)
214 fprintf(stderr, "%s", PQerrorMessage(con));
222 /* throw away response from backend */
224 discard_response(CState * state)
230 res = PQgetResult(state->con);
236 /* check to see if the SQL result was good */
238 check(CState * state, PGresult *res, int n, int good)
240 CState *st = &state[n];
242 if (res && PQresultStatus(res) != good)
244 fprintf(stderr, "Client %d aborted in state %d: %s", n, st->state, PQerrorMessage(st->con));
245 remains--; /* I've aborted */
254 compareVariables(const void *v1, const void *v2)
256 return strcmp(((const Variable *) v1)->name,
257 ((const Variable *) v2)->name);
261 getVariable(CState * st, char *name)
266 /* On some versions of Solaris, bsearch of zero items dumps core */
267 if (st->nvariables <= 0)
271 var = (Variable *) bsearch((void *) &key,
272 (void *) st->variables,
283 putVariable(CState * st, char *name, char *value)
289 /* On some versions of Solaris, bsearch of zero items dumps core */
290 if (st->nvariables > 0)
291 var = (Variable *) bsearch((void *) &key,
292 (void *) st->variables,
304 newvars = (Variable *) realloc(st->variables,
305 (st->nvariables + 1) * sizeof(Variable));
307 newvars = (Variable *) malloc(sizeof(Variable));
312 st->variables = newvars;
314 var = &newvars[st->nvariables];
319 if ((var->name = strdup(name)) == NULL
320 || (var->value = strdup(value)) == NULL)
329 qsort((void *) st->variables, st->nvariables, sizeof(Variable),
334 if ((value = strdup(value)) == NULL)
344 assignVariables(CState * st, char *sql)
354 while ((p = strchr(&sql[i], ':')) != NULL)
360 } while (isalnum((unsigned char) sql[i]) || sql[i] == '_');
364 name = malloc(i - j);
367 memcpy(name, &sql[j + 1], i - (j + 1));
368 name[i - (j + 1)] = '\0';
369 val = getVariable(st, name);
374 if (strlen(val) > i - j)
376 tmp = realloc(sql, strlen(sql) - (i - j) + strlen(val) + 1);
385 if (strlen(val) != i - j)
386 memmove(&sql[j + strlen(val)], &sql[i], strlen(&sql[i]) + 1);
388 strncpy(&sql[j], val, strlen(val));
390 if (strlen(val) < i - j)
392 tmp = realloc(sql, strlen(sql) + 1);
408 doCustom(CState * state, int n, int debug)
411 CState *st = &state[n];
415 commands = sql_files[st->use_file];
418 { /* are we receiver? */
419 if (commands[st->state]->type == SQL_COMMAND)
422 fprintf(stderr, "client %d receiving\n", n);
423 if (!PQconsumeInput(st->con))
424 { /* there's something wrong */
425 fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
426 remains--; /* I've aborted */
431 if (PQisBusy(st->con))
432 return; /* don't have the whole result yet */
436 * transaction finished: record the time it took in the log
438 if (use_log && commands[st->state + 1] == NULL)
443 gettimeofday(&now, NULL);
444 diff = (int) (now.tv_sec - st->txn_begin.tv_sec) * 1000000.0 +
445 (int) (now.tv_usec - st->txn_begin.tv_usec);
447 fprintf(LOGFILE, "%d %d %.0f\n", st->id, st->cnt, diff);
450 if (commands[st->state]->type == SQL_COMMAND)
452 res = PQgetResult(st->con);
453 if (strncasecmp(commands[st->state]->argv[0], "select", 6) != 0)
455 if (check(state, res, n, PGRES_COMMAND_OK))
460 if (check(state, res, n, PGRES_TUPLES_OK))
464 discard_response(st);
467 if (commands[st->state + 1] == NULL)
475 if (++st->cnt >= nxacts)
477 remains--; /* I've done */
487 /* increment state counter */
489 if (commands[st->state] == NULL)
492 st->use_file = getrand(0, num_files - 1);
493 commands = sql_files[st->use_file];
499 if ((st->con = doConnect()) == NULL)
501 fprintf(stderr, "Client %d aborted in establishing connection.\n",
503 remains--; /* I've aborted */
510 if (use_log && st->state == 0)
511 gettimeofday(&(st->txn_begin), NULL);
513 if (commands[st->state]->type == SQL_COMMAND)
517 if ((sql = strdup(commands[st->state]->argv[0])) == NULL
518 || (sql = assignVariables(st, sql)) == NULL)
520 fprintf(stderr, "out of memory\n");
526 fprintf(stderr, "client %d sending %s\n", n, sql);
527 if (PQsendQuery(st->con, sql) == 0)
530 fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
535 st->listen = 1; /* flags that should be listened */
539 else if (commands[st->state]->type == META_COMMAND)
541 int argc = commands[st->state]->argc,
543 char **argv = commands[st->state]->argv;
547 fprintf(stderr, "client %d executing \\%s", n, argv[0]);
548 for (i = 1; i < argc; i++)
549 fprintf(stderr, " %s", argv[i]);
550 fprintf(stderr, "\n");
553 if (strcasecmp(argv[0], "setrandom") == 0)
562 if ((var = getVariable(st, argv[2] + 1)) == NULL)
564 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[2]);
575 fprintf(stderr, "%s: invalid minimum number %d\n", argv[0], min);
582 if ((var = getVariable(st, argv[3] + 1)) == NULL)
584 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[3]);
593 if (max < min || max > MAX_RANDOM_VALUE)
595 fprintf(stderr, "%s: invalid maximum number %d\n", argv[0], max);
600 snprintf(res, sizeof(res), "%d", getrand(min, max));
602 if (putVariable(st, argv[1], res) == false)
604 fprintf(stderr, "%s: out of memory\n", argv[0]);
611 else if (strcasecmp(argv[0], "set") == 0)
620 if ((var = getVariable(st, argv[2] + 1)) == NULL)
622 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[2]);
629 ope1 = atoi(argv[2]);
632 snprintf(res, sizeof(res), "%d", ope1);
637 if ((var = getVariable(st, argv[4] + 1)) == NULL)
639 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[4]);
646 ope2 = atoi(argv[4]);
648 if (strcmp(argv[3], "+") == 0)
649 snprintf(res, sizeof(res), "%d", ope1 + ope2);
650 else if (strcmp(argv[3], "-") == 0)
651 snprintf(res, sizeof(res), "%d", ope1 - ope2);
652 else if (strcmp(argv[3], "*") == 0)
653 snprintf(res, sizeof(res), "%d", ope1 * ope2);
654 else if (strcmp(argv[3], "/") == 0)
658 fprintf(stderr, "%s: division by zero\n", argv[0]);
662 snprintf(res, sizeof(res), "%d", ope1 / ope2);
666 fprintf(stderr, "%s: unsupported operator %s\n", argv[0], argv[3]);
672 if (putVariable(st, argv[1], res) == false)
674 fprintf(stderr, "%s: out of memory\n", argv[0]);
686 /* discard connections */
688 disconnect_all(CState * state)
692 for (i = 0; i < nclients; i++)
695 PQfinish(state[i].con);
699 /* create tables and setup data */
705 static char *DDLs[] = {
706 "drop table branches",
707 "create table branches(bid int not null,bbalance int,filler char(88))",
708 "drop table tellers",
709 "create table tellers(tid int not null,bid int,tbalance int,filler char(84))",
710 "drop table accounts",
711 "create table accounts(aid int not null,bid int,abalance int,filler char(84))",
712 "drop table history",
713 "create table history(tid int,bid int,aid int,delta int,mtime timestamp,filler char(22))"};
714 static char *DDLAFTERs[] = {
715 "alter table branches add primary key (bid)",
716 "alter table tellers add primary key (tid)",
717 "alter table accounts add primary key (aid)"};
724 if ((con = doConnect()) == NULL)
727 for (i = 0; i < (sizeof(DDLs) / sizeof(char *)); i++)
729 res = PQexec(con, DDLs[i]);
730 if (strncmp(DDLs[i], "drop", 4) && PQresultStatus(res) != PGRES_COMMAND_OK)
732 fprintf(stderr, "%s", PQerrorMessage(con));
738 res = PQexec(con, "begin");
739 if (PQresultStatus(res) != PGRES_COMMAND_OK)
741 fprintf(stderr, "%s", PQerrorMessage(con));
746 for (i = 0; i < nbranches * tps; i++)
748 snprintf(sql, 256, "insert into branches(bid,bbalance) values(%d,0)", i + 1);
749 res = PQexec(con, sql);
750 if (PQresultStatus(res) != PGRES_COMMAND_OK)
752 fprintf(stderr, "%s", PQerrorMessage(con));
758 for (i = 0; i < ntellers * tps; i++)
760 snprintf(sql, 256, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)"
761 ,i + 1, i / ntellers + 1);
762 res = PQexec(con, sql);
763 if (PQresultStatus(res) != PGRES_COMMAND_OK)
765 fprintf(stderr, "%s", PQerrorMessage(con));
771 res = PQexec(con, "end");
772 if (PQresultStatus(res) != PGRES_COMMAND_OK)
774 fprintf(stderr, "%s", PQerrorMessage(con));
780 * occupy accounts table with some data
782 fprintf(stderr, "creating tables...\n");
783 for (i = 0; i < naccounts * tps; i++)
789 res = PQexec(con, "copy accounts from stdin");
790 if (PQresultStatus(res) != PGRES_COPY_IN)
792 fprintf(stderr, "%s", PQerrorMessage(con));
798 snprintf(sql, 256, "%d\t%d\t%d\t\n", j, i / naccounts + 1, 0);
799 if (PQputline(con, sql))
801 fprintf(stderr, "PQputline failed\n");
808 * every 10000 tuples, we commit the copy command. this should
809 * avoid generating too much WAL logs
811 fprintf(stderr, "%d tuples done.\n", j);
812 if (PQputline(con, "\\.\n"))
814 fprintf(stderr, "very last PQputline failed\n");
820 fprintf(stderr, "PQendcopy failed\n");
827 * do a checkpoint to purge the old WAL logs
829 res = PQexec(con, "checkpoint");
830 if (PQresultStatus(res) != PGRES_COMMAND_OK)
832 fprintf(stderr, "%s", PQerrorMessage(con));
836 #endif /* NOT_USED */
839 fprintf(stderr, "set primary key...\n");
840 for (i = 0; i < (sizeof(DDLAFTERs) / sizeof(char *)); i++)
842 res = PQexec(con, DDLAFTERs[i]);
843 if (PQresultStatus(res) != PGRES_COMMAND_OK)
845 fprintf(stderr, "%s", PQerrorMessage(con));
852 fprintf(stderr, "vacuum...");
853 res = PQexec(con, "vacuum analyze");
854 if (PQresultStatus(res) != PGRES_COMMAND_OK)
856 fprintf(stderr, "%s", PQerrorMessage(con));
860 fprintf(stderr, "done.\n");
866 process_commands(char *buf)
868 const char delim[] = " \f\n\r\t\v";
870 Command *my_commands;
875 if ((p = strchr(buf, '\n')) != NULL)
879 while (isspace((unsigned char) *p))
882 if (*p == '\0' || strncmp(p, "--", 2) == 0)
887 my_commands = (Command *) malloc(sizeof(Command));
888 if (my_commands == NULL)
893 my_commands->argc = 0;
897 my_commands->type = META_COMMAND;
900 tok = strtok(++p, delim);
904 if ((my_commands->argv[j] = strdup(tok)) == NULL)
910 tok = strtok(NULL, delim);
913 if (strcasecmp(my_commands->argv[0], "setrandom") == 0)
915 if (my_commands->argc < 4)
917 fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
921 for (j = 4; j < my_commands->argc; j++)
922 fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
923 my_commands->argv[0], my_commands->argv[j]);
925 else if (strcasecmp(my_commands->argv[0], "set") == 0)
927 if (my_commands->argc < 3)
929 fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
933 for (j = my_commands->argc < 5 ? 3 : 5; j < my_commands->argc; j++)
934 fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
935 my_commands->argv[0], my_commands->argv[j]);
939 fprintf(stderr, "invalid command %s\n", my_commands->argv[0]);
945 my_commands->type = SQL_COMMAND;
947 if ((my_commands->argv[0] = strdup(p)) == NULL)
957 process_file(char *filename)
959 #define COMMANDS_ALLOC_NUM 128
961 Command **my_commands;
967 if (num_files >= MAX_FILES)
969 fprintf(stderr, "Up to only %d SQL files are allowed\n", MAX_FILES);
973 alloc_num = COMMANDS_ALLOC_NUM;
974 my_commands = (Command **) malloc(sizeof(Command *) * alloc_num);
975 if (my_commands == NULL)
978 if (strcmp(filename, "-") == 0)
980 else if ((fd = fopen(filename, "r")) == NULL)
982 fprintf(stderr, "%s: %s\n", filename, strerror(errno));
988 while (fgets(buf, sizeof(buf), fd) != NULL)
994 while (isspace((unsigned char) buf[i]))
997 if (strncmp(&buf[i], "\n", 1) != 0 && strncmp(&buf[i], "--", 2) != 0) {
998 commands = process_commands(&buf[i]);
999 if (commands == NULL)
1007 my_commands[lineno] = commands;
1010 if (lineno >= alloc_num)
1012 alloc_num += COMMANDS_ALLOC_NUM;
1013 my_commands = realloc(my_commands, sizeof(Command *) * alloc_num);
1014 if (my_commands == NULL)
1023 my_commands[lineno] = NULL;
1025 sql_files[num_files++] = my_commands;
1031 process_builtin(char *tb)
1033 #define COMMANDS_ALLOC_NUM 128
1035 Command **my_commands;
1043 alloc_num = COMMANDS_ALLOC_NUM;
1044 my_commands = (Command **) malloc(sizeof(Command *) * alloc_num);
1045 if (my_commands == NULL)
1056 while (*tb && *tb != '\n')
1067 commands = process_commands(buf);
1068 if (commands == NULL)
1073 my_commands[lineno] = commands;
1076 if (lineno >= alloc_num)
1078 alloc_num += COMMANDS_ALLOC_NUM;
1079 my_commands = realloc(my_commands, sizeof(Command *) * alloc_num);
1080 if (my_commands == NULL)
1087 my_commands[lineno] = NULL;
1092 /* print out results */
1095 int ttype, CState * state,
1096 struct timeval * tv1, struct timeval * tv2,
1097 struct timeval * tv3)
1102 int normal_xacts = 0;
1105 for (i = 0; i < nclients; i++)
1106 normal_xacts += state[i].cnt;
1108 t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
1109 t1 = normal_xacts * 1000000.0 / t1;
1111 t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
1112 t2 = normal_xacts * 1000000.0 / t2;
1115 s = "TPC-B (sort of)";
1116 else if (ttype == 2)
1117 s = "Update only accounts";
1118 else if (ttype == 1)
1123 printf("transaction type: %s\n", s);
1124 printf("scaling factor: %d\n", tps);
1125 printf("number of clients: %d\n", nclients);
1126 printf("number of transactions per client: %d\n", nxacts);
1127 printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients);
1128 printf("tps = %f (including connections establishing)\n", t1);
1129 printf("tps = %f (excluding connections establishing)\n", t2);
1134 main(int argc, char **argv)
1137 int is_init_mode = 0; /* initialize mode? */
1138 int is_no_vacuum = 0; /* no vacuum at all before testing? */
1139 int is_full_vacuum = 0; /* do full vacuum before testing? */
1140 int debug = 0; /* debug flag */
1141 int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT only,
1142 * 2: skip update of branches and tellers */
1143 char *filename = NULL;
1145 CState *state; /* status of clients */
1147 struct timeval tv1; /* start up time */
1148 struct timeval tv2; /* after establishing all connections to the
1150 struct timeval tv3; /* end time */
1155 int nsocks; /* return from select(2) */
1156 int maxsock; /* max socket number to be waited */
1158 #if !(defined(__CYGWIN__) || defined(__MINGW32__))
1166 if ((env = getenv("PGHOST")) != NULL && *env != '\0')
1168 if ((env = getenv("PGPORT")) != NULL && *env != '\0')
1170 else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
1173 state = (CState *) malloc(sizeof(CState));
1176 fprintf(stderr, "Couldn't allocate memory for state\n");
1180 memset(state, 0, sizeof(*state));
1182 while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:D:")) != -1)
1211 nclients = atoi(optarg);
1212 if (nclients <= 0 || nclients > MAXCLIENTS)
1214 fprintf(stderr, "invalid number of clients: %d\n", nclients);
1217 #if !(defined(__CYGWIN__) || defined(__MINGW32__))
1218 #ifdef RLIMIT_NOFILE /* most platform uses RLIMIT_NOFILE */
1219 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
1220 #else /* but BSD doesn't ... */
1221 if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
1222 #endif /* RLIMIT_NOFILE */
1224 fprintf(stderr, "getrlimit failed: %s\n", strerror(errno));
1227 if (rlim.rlim_cur <= (nclients + 2))
1229 fprintf(stderr, "You need at least %d open files resource but you are only allowed to use %ld.\n", nclients + 2, (long) rlim.rlim_cur);
1230 fprintf(stderr, "Use limit/ulimt to increase the limit before using pgbench.\n");
1242 fprintf(stderr, "invalid scaling factor: %d\n", tps);
1247 nxacts = atoi(optarg);
1250 fprintf(stderr, "invalid number of transactions: %d\n", nxacts);
1266 if (process_file(filename) == false || *sql_files[num_files - 1] == NULL)
1273 if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
1275 fprintf(stderr, "invalid variable definition: %s\n", optarg);
1280 if (putVariable(&state[0], optarg, p) == false)
1282 fprintf(stderr, "Couldn't allocate memory for variable\n");
1295 dbName = argv[optind];
1298 if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
1300 else if (login != NULL && *login != '\0')
1314 if (getVariable(&state[0], "tps") == NULL)
1318 snprintf(val, sizeof(val), "%d", tps);
1319 if (putVariable(&state[0], "tps", val) == false)
1321 fprintf(stderr, "Couldn't allocate memory for variable\n");
1328 state = (CState *) realloc(state, sizeof(CState) * nclients);
1331 fprintf(stderr, "Couldn't allocate memory for state\n");
1335 memset(state + sizeof(*state), 0, sizeof(*state) * (nclients - 1));
1337 for (i = 1; i < nclients; i++)
1341 for (j = 0; j < state[0].nvariables; j++)
1343 if (putVariable(&state[i], state[0].variables[j].name, state[0].variables[j].value) == false)
1345 fprintf(stderr, "Couldn't allocate memory for variable\n");
1356 snprintf(logpath, 64, "pgbench_log.%d", getpid());
1357 LOGFILE = fopen(logpath, "w");
1359 if (LOGFILE == NULL)
1361 fprintf(stderr, "Couldn't open logfile \"%s\": %s", logpath, strerror(errno));
1368 printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
1369 pghost, pgport, nclients, nxacts, dbName);
1372 /* opening connection... */
1377 if (PQstatus(con) == CONNECTION_BAD)
1379 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
1380 fprintf(stderr, "%s", PQerrorMessage(con));
1387 * get the scaling factor that should be same as count(*) from
1388 * branches if this is not a custom query
1390 res = PQexec(con, "select count(*) from branches");
1391 if (PQresultStatus(res) != PGRES_TUPLES_OK)
1393 fprintf(stderr, "%s", PQerrorMessage(con));
1396 tps = atoi(PQgetvalue(res, 0, 0));
1399 fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);
1407 fprintf(stderr, "starting vacuum...");
1408 res = PQexec(con, "vacuum branches");
1409 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1411 fprintf(stderr, "%s", PQerrorMessage(con));
1416 res = PQexec(con, "vacuum tellers");
1417 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1419 fprintf(stderr, "%s", PQerrorMessage(con));
1424 res = PQexec(con, "delete from history");
1425 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1427 fprintf(stderr, "%s", PQerrorMessage(con));
1431 res = PQexec(con, "vacuum history");
1432 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1434 fprintf(stderr, "%s", PQerrorMessage(con));
1439 fprintf(stderr, "end.\n");
1443 fprintf(stderr, "starting full vacuum...");
1444 res = PQexec(con, "vacuum analyze accounts");
1445 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1447 fprintf(stderr, "%s", PQerrorMessage(con));
1451 fprintf(stderr, "end.\n");
1456 /* set random seed */
1457 gettimeofday(&tv1, NULL);
1458 srand((unsigned int) tv1.tv_usec);
1460 /* get start up time */
1461 gettimeofday(&tv1, NULL);
1463 if (is_connect == 0)
1465 /* make connections to the database */
1466 for (i = 0; i < nclients; i++)
1469 if ((state[i].con = doConnect()) == NULL)
1474 /* time after connections set up */
1475 gettimeofday(&tv2, NULL);
1477 /* process bultin SQL scripts */
1483 sql_files[0] = process_builtin(tpc_b);
1484 snprintf(buf, sizeof(buf), "%d", 100000 * tps);
1485 sql_files[0][0]->argv[3] = strdup(buf);
1486 snprintf(buf, sizeof(buf), "%d", 1 * tps);
1487 sql_files[0][1]->argv[3] = strdup(buf);
1488 snprintf(buf, sizeof(buf), "%d", 10 * tps);
1489 sql_files[0][2]->argv[3] = strdup(buf);
1490 snprintf(buf, sizeof(buf), "%d", 10000 * tps);
1491 sql_files[0][3]->argv[3] = strdup(buf);
1495 sql_files[0] = process_builtin(select_only);
1496 snprintf(buf, sizeof(buf), "%d", 100000 * tps);
1497 sql_files[0][0]->argv[3] = strdup(buf);
1501 sql_files[0] = process_builtin(simple_update);
1502 snprintf(buf, sizeof(buf), "%d", 100000 * tps);
1503 sql_files[0][0]->argv[3] = strdup(buf);
1504 snprintf(buf, sizeof(buf), "%d", 1 * tps);
1505 sql_files[0][1]->argv[3] = strdup(buf);
1506 snprintf(buf, sizeof(buf), "%d", 10 * tps);
1507 sql_files[0][2]->argv[3] = strdup(buf);
1508 snprintf(buf, sizeof(buf), "%d", 10000 * tps);
1509 sql_files[0][3]->argv[3] = strdup(buf);
1516 /* send start up queries in async manner */
1517 for (i = 0; i < nclients; i++)
1519 Command **commands = sql_files[state[i].use_file];
1520 int prev_ecnt = state[i].ecnt;
1522 state[i].use_file = getrand(0, num_files - 1);
1523 doCustom(state, i, debug);
1525 if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
1527 fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
1528 remains--; /* I've aborted */
1529 PQfinish(state[i].con);
1530 state[i].con = NULL;
1538 disconnect_all(state);
1540 gettimeofday(&tv3, NULL);
1541 printResults(ttype, state, &tv1, &tv2, &tv3);
1547 FD_ZERO(&input_mask);
1550 for (i = 0; i < nclients; i++)
1552 Command **commands = sql_files[state[i].use_file];
1554 if (state[i].con && commands[state[i].state]->type != META_COMMAND)
1556 int sock = PQsocket(state[i].con);
1560 disconnect_all(state);
1563 FD_SET(sock, &input_mask);
1571 if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
1572 (fd_set *) NULL, (struct timeval *) NULL)) < 0)
1576 /* must be something wrong */
1577 disconnect_all(state);
1578 fprintf(stderr, "select failed: %s\n", strerror(errno));
1581 else if (nsocks == 0)
1583 fprintf(stderr, "select timeout\n");
1584 for (i = 0; i < nclients; i++)
1586 fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
1587 i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
1593 /* ok, backend returns reply */
1594 for (i = 0; i < nclients; i++)
1596 Command **commands = sql_files[state[i].use_file];
1597 int prev_ecnt = state[i].ecnt;
1599 if (state[i].con && (FD_ISSET(PQsocket(state[i].con), &input_mask)
1600 || commands[state[i].state]->type == META_COMMAND))
1602 doCustom(state, i, debug);
1605 if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
1607 fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
1608 remains--; /* I've aborted */
1609 PQfinish(state[i].con);
1610 state[i].con = NULL;