2 * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.56 2006/10/04 00:29:45 momjian Exp $
4 * pgbench: a simple benchmark program for PostgreSQL
5 * written by Tatsuo Ishii
7 * Copyright (c) 2000-2006 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, scale = 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 "\\set nbranches :scale\n"
138 "\\set ntellers 10 * :scale\n"
139 "\\set naccounts 100000 * :scale\n"
140 "\\setrandom aid 1 :naccounts\n"
141 "\\setrandom bid 1 :nbranches\n"
142 "\\setrandom tid 1 :ntellers\n"
143 "\\setrandom delta -5000 5000\n"
145 "UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
146 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
147 "UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
148 "UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
149 "INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
154 static char *simple_update = {
155 "\\set nbranches :scale\n"
156 "\\set ntellers 10 * :scale\n"
157 "\\set naccounts 100000 * :scale\n"
158 "\\setrandom aid 1 :naccounts\n"
159 "\\setrandom bid 1 :nbranches\n"
160 "\\setrandom tid 1 :ntellers\n"
161 "\\setrandom delta -5000 5000\n"
163 "UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
164 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
165 "INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
170 static char *select_only = {
171 "\\set naccounts 100000 * :scale\n"
172 "\\setrandom aid 1 :naccounts\n"
173 "SELECT abalance FROM accounts WHERE aid = :aid;\n"
179 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");
180 fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
183 /* random number generator */
185 getrand(int min, int max)
187 return min + (int) (((max - min) * (double) random()) / MAX_RANDOM_VALUE + 0.5);
190 /* set up a connection to the backend */
197 con = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName,
201 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
202 fprintf(stderr, "Memory allocatin problem?\n");
206 if (PQstatus(con) == CONNECTION_BAD)
208 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
210 if (PQerrorMessage(con))
211 fprintf(stderr, "%s", PQerrorMessage(con));
213 fprintf(stderr, "No explanation from the backend\n");
218 res = PQexec(con, "SET search_path = public");
219 if (PQresultStatus(res) != PGRES_COMMAND_OK)
221 fprintf(stderr, "%s", PQerrorMessage(con));
229 /* throw away response from backend */
231 discard_response(CState * state)
237 res = PQgetResult(state->con);
243 /* check to see if the SQL result was good */
245 check(CState * state, PGresult *res, int n, int good)
247 CState *st = &state[n];
249 if (res && PQresultStatus(res) != good)
251 fprintf(stderr, "Client %d aborted in state %d: %s", n, st->state, PQerrorMessage(st->con));
252 remains--; /* I've aborted */
261 compareVariables(const void *v1, const void *v2)
263 return strcmp(((const Variable *) v1)->name,
264 ((const Variable *) v2)->name);
268 getVariable(CState * st, char *name)
273 /* On some versions of Solaris, bsearch of zero items dumps core */
274 if (st->nvariables <= 0)
278 var = (Variable *) bsearch((void *) &key,
279 (void *) st->variables,
290 putVariable(CState * st, char *name, char *value)
296 /* On some versions of Solaris, bsearch of zero items dumps core */
297 if (st->nvariables > 0)
298 var = (Variable *) bsearch((void *) &key,
299 (void *) st->variables,
311 newvars = (Variable *) realloc(st->variables,
312 (st->nvariables + 1) * sizeof(Variable));
314 newvars = (Variable *) malloc(sizeof(Variable));
319 st->variables = newvars;
321 var = &newvars[st->nvariables];
326 if ((var->name = strdup(name)) == NULL
327 || (var->value = strdup(value)) == NULL)
336 qsort((void *) st->variables, st->nvariables, sizeof(Variable),
343 if ((val = strdup(value)) == NULL)
354 assignVariables(CState * st, char *sql)
364 while ((p = strchr(&sql[i], ':')) != NULL)
370 } while (isalnum((unsigned char) sql[i]) || sql[i] == '_');
374 name = malloc(i - j);
377 memcpy(name, &sql[j + 1], i - (j + 1));
378 name[i - (j + 1)] = '\0';
379 val = getVariable(st, name);
384 if (strlen(val) > i - j)
386 tmp = realloc(sql, strlen(sql) - (i - j) + strlen(val) + 1);
395 if (strlen(val) != i - j)
396 memmove(&sql[j + strlen(val)], &sql[i], strlen(&sql[i]) + 1);
398 strncpy(&sql[j], val, strlen(val));
400 if (strlen(val) < i - j)
402 tmp = realloc(sql, strlen(sql) + 1);
418 doCustom(CState * state, int n, int debug)
421 CState *st = &state[n];
425 commands = sql_files[st->use_file];
428 { /* are we receiver? */
429 if (commands[st->state]->type == SQL_COMMAND)
432 fprintf(stderr, "client %d receiving\n", n);
433 if (!PQconsumeInput(st->con))
434 { /* there's something wrong */
435 fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
436 remains--; /* I've aborted */
441 if (PQisBusy(st->con))
442 return; /* don't have the whole result yet */
446 * transaction finished: record the time it took in the log
448 if (use_log && commands[st->state + 1] == NULL)
453 gettimeofday(&now, NULL);
454 diff = (int) (now.tv_sec - st->txn_begin.tv_sec) * 1000000.0 +
455 (int) (now.tv_usec - st->txn_begin.tv_usec);
457 fprintf(LOGFILE, "%d %d %.0f\n", st->id, st->cnt, diff);
460 if (commands[st->state]->type == SQL_COMMAND)
462 res = PQgetResult(st->con);
463 if (pg_strncasecmp(commands[st->state]->argv[0], "select", 6) != 0)
465 if (check(state, res, n, PGRES_COMMAND_OK))
470 if (check(state, res, n, PGRES_TUPLES_OK))
474 discard_response(st);
477 if (commands[st->state + 1] == NULL)
485 if (++st->cnt >= nxacts)
487 remains--; /* I've done */
497 /* increment state counter */
499 if (commands[st->state] == NULL)
502 st->use_file = getrand(0, num_files - 1);
503 commands = sql_files[st->use_file];
509 if ((st->con = doConnect()) == NULL)
511 fprintf(stderr, "Client %d aborted in establishing connection.\n",
513 remains--; /* I've aborted */
520 if (use_log && st->state == 0)
521 gettimeofday(&(st->txn_begin), NULL);
523 if (commands[st->state]->type == SQL_COMMAND)
527 if ((sql = strdup(commands[st->state]->argv[0])) == NULL
528 || (sql = assignVariables(st, sql)) == NULL)
530 fprintf(stderr, "out of memory\n");
536 fprintf(stderr, "client %d sending %s\n", n, sql);
537 if (PQsendQuery(st->con, sql) == 0)
540 fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
545 st->listen = 1; /* flags that should be listened */
549 else if (commands[st->state]->type == META_COMMAND)
551 int argc = commands[st->state]->argc,
553 char **argv = commands[st->state]->argv;
557 fprintf(stderr, "client %d executing \\%s", n, argv[0]);
558 for (i = 1; i < argc; i++)
559 fprintf(stderr, " %s", argv[i]);
560 fprintf(stderr, "\n");
563 if (pg_strcasecmp(argv[0], "setrandom") == 0)
572 if ((var = getVariable(st, argv[2] + 1)) == NULL)
574 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[2]);
586 fprintf(stderr, "%s: invalid minimum number %d\n", argv[0], min);
594 if ((var = getVariable(st, argv[3] + 1)) == NULL)
596 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[3]);
605 if (max < min || max > MAX_RANDOM_VALUE)
607 fprintf(stderr, "%s: invalid maximum number %d\n", argv[0], max);
613 printf("min: %d max: %d random: %d\n", min, max, getrand(min, max));
615 snprintf(res, sizeof(res), "%d", getrand(min, max));
617 if (putVariable(st, argv[1], res) == false)
619 fprintf(stderr, "%s: out of memory\n", argv[0]);
626 else if (pg_strcasecmp(argv[0], "set") == 0)
635 if ((var = getVariable(st, argv[2] + 1)) == NULL)
637 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[2]);
644 ope1 = atoi(argv[2]);
647 snprintf(res, sizeof(res), "%d", ope1);
652 if ((var = getVariable(st, argv[4] + 1)) == NULL)
654 fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[4]);
661 ope2 = atoi(argv[4]);
663 if (strcmp(argv[3], "+") == 0)
664 snprintf(res, sizeof(res), "%d", ope1 + ope2);
665 else 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)
673 fprintf(stderr, "%s: division by zero\n", argv[0]);
677 snprintf(res, sizeof(res), "%d", ope1 / ope2);
681 fprintf(stderr, "%s: unsupported operator %s\n", argv[0], argv[3]);
687 if (putVariable(st, argv[1], res) == false)
689 fprintf(stderr, "%s: out of memory\n", argv[0]);
701 /* discard connections */
703 disconnect_all(CState * state)
707 for (i = 0; i < nclients; i++)
710 PQfinish(state[i].con);
714 /* create tables and setup data */
720 static char *DDLs[] = {
721 "drop table branches",
722 "create table branches(bid int not null,bbalance int,filler char(88))",
723 "drop table tellers",
724 "create table tellers(tid int not null,bid int,tbalance int,filler char(84))",
725 "drop table accounts",
726 "create table accounts(aid int not null,bid int,abalance int,filler char(84))",
727 "drop table history",
728 "create table history(tid int,bid int,aid int,delta int,mtime timestamp,filler char(22))"};
729 static char *DDLAFTERs[] = {
730 "alter table branches add primary key (bid)",
731 "alter table tellers add primary key (tid)",
732 "alter table accounts add primary key (aid)"};
739 if ((con = doConnect()) == NULL)
742 for (i = 0; i < (sizeof(DDLs) / sizeof(char *)); i++)
744 res = PQexec(con, DDLs[i]);
745 if (strncmp(DDLs[i], "drop", 4) && PQresultStatus(res) != PGRES_COMMAND_OK)
747 fprintf(stderr, "%s", PQerrorMessage(con));
753 res = PQexec(con, "begin");
754 if (PQresultStatus(res) != PGRES_COMMAND_OK)
756 fprintf(stderr, "%s", PQerrorMessage(con));
761 for (i = 0; i < nbranches * scale; i++)
763 snprintf(sql, 256, "insert into branches(bid,bbalance) values(%d,0)", i + 1);
764 res = PQexec(con, sql);
765 if (PQresultStatus(res) != PGRES_COMMAND_OK)
767 fprintf(stderr, "%s", PQerrorMessage(con));
773 for (i = 0; i < ntellers * scale; i++)
775 snprintf(sql, 256, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)"
776 ,i + 1, i / ntellers + 1);
777 res = PQexec(con, sql);
778 if (PQresultStatus(res) != PGRES_COMMAND_OK)
780 fprintf(stderr, "%s", PQerrorMessage(con));
786 res = PQexec(con, "end");
787 if (PQresultStatus(res) != PGRES_COMMAND_OK)
789 fprintf(stderr, "%s", PQerrorMessage(con));
795 * occupy accounts table with some data
797 fprintf(stderr, "creating tables...\n");
798 for (i = 0; i < naccounts * scale; i++)
804 res = PQexec(con, "copy accounts from stdin");
805 if (PQresultStatus(res) != PGRES_COPY_IN)
807 fprintf(stderr, "%s", PQerrorMessage(con));
813 snprintf(sql, 256, "%d\t%d\t%d\t\n", j, i / naccounts + 1, 0);
814 if (PQputline(con, sql))
816 fprintf(stderr, "PQputline failed\n");
823 * every 10000 tuples, we commit the copy command. this should
824 * avoid generating too much WAL logs
826 fprintf(stderr, "%d tuples done.\n", j);
827 if (PQputline(con, "\\.\n"))
829 fprintf(stderr, "very last PQputline failed\n");
835 fprintf(stderr, "PQendcopy failed\n");
842 * do a checkpoint to purge the old WAL logs
844 res = PQexec(con, "checkpoint");
845 if (PQresultStatus(res) != PGRES_COMMAND_OK)
847 fprintf(stderr, "%s", PQerrorMessage(con));
851 #endif /* NOT_USED */
854 fprintf(stderr, "set primary key...\n");
855 for (i = 0; i < (sizeof(DDLAFTERs) / sizeof(char *)); i++)
857 res = PQexec(con, DDLAFTERs[i]);
858 if (PQresultStatus(res) != PGRES_COMMAND_OK)
860 fprintf(stderr, "%s", PQerrorMessage(con));
867 fprintf(stderr, "vacuum...");
868 res = PQexec(con, "vacuum analyze");
869 if (PQresultStatus(res) != PGRES_COMMAND_OK)
871 fprintf(stderr, "%s", PQerrorMessage(con));
875 fprintf(stderr, "done.\n");
881 process_commands(char *buf)
883 const char delim[] = " \f\n\r\t\v";
885 Command *my_commands;
890 if ((p = strchr(buf, '\n')) != NULL)
894 while (isspace((unsigned char) *p))
897 if (*p == '\0' || strncmp(p, "--", 2) == 0)
902 my_commands = (Command *) malloc(sizeof(Command));
903 if (my_commands == NULL)
908 my_commands->argc = 0;
912 my_commands->type = META_COMMAND;
915 tok = strtok(++p, delim);
919 if ((my_commands->argv[j] = strdup(tok)) == NULL)
925 tok = strtok(NULL, delim);
928 if (pg_strcasecmp(my_commands->argv[0], "setrandom") == 0)
930 if (my_commands->argc < 4)
932 fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
936 for (j = 4; j < my_commands->argc; j++)
937 fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
938 my_commands->argv[0], my_commands->argv[j]);
940 else if (pg_strcasecmp(my_commands->argv[0], "set") == 0)
942 if (my_commands->argc < 3)
944 fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
948 for (j = my_commands->argc < 5 ? 3 : 5; j < my_commands->argc; j++)
949 fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
950 my_commands->argv[0], my_commands->argv[j]);
954 fprintf(stderr, "invalid command %s\n", my_commands->argv[0]);
960 my_commands->type = SQL_COMMAND;
962 if ((my_commands->argv[0] = strdup(p)) == NULL)
972 process_file(char *filename)
974 #define COMMANDS_ALLOC_NUM 128
976 Command **my_commands;
982 if (num_files >= MAX_FILES)
984 fprintf(stderr, "Up to only %d SQL files are allowed\n", MAX_FILES);
988 alloc_num = COMMANDS_ALLOC_NUM;
989 my_commands = (Command **) malloc(sizeof(Command *) * alloc_num);
990 if (my_commands == NULL)
993 if (strcmp(filename, "-") == 0)
995 else if ((fd = fopen(filename, "r")) == NULL)
997 fprintf(stderr, "%s: %s\n", filename, strerror(errno));
1003 while (fgets(buf, sizeof(buf), fd) != NULL)
1009 while (isspace((unsigned char) buf[i]))
1012 if (buf[i] != '\0' && strncmp(&buf[i], "--", 2) != 0)
1014 commands = process_commands(&buf[i]);
1015 if (commands == NULL)
1024 my_commands[lineno] = commands;
1027 if (lineno >= alloc_num)
1029 alloc_num += COMMANDS_ALLOC_NUM;
1030 my_commands = realloc(my_commands, sizeof(Command *) * alloc_num);
1031 if (my_commands == NULL)
1040 my_commands[lineno] = NULL;
1042 sql_files[num_files++] = my_commands;
1048 process_builtin(char *tb)
1050 #define COMMANDS_ALLOC_NUM 128
1052 Command **my_commands;
1060 alloc_num = COMMANDS_ALLOC_NUM;
1061 my_commands = (Command **) malloc(sizeof(Command *) * alloc_num);
1062 if (my_commands == NULL)
1073 while (*tb && *tb != '\n')
1084 commands = process_commands(buf);
1085 if (commands == NULL)
1090 my_commands[lineno] = commands;
1093 if (lineno >= alloc_num)
1095 alloc_num += COMMANDS_ALLOC_NUM;
1096 my_commands = realloc(my_commands, sizeof(Command *) * alloc_num);
1097 if (my_commands == NULL)
1104 my_commands[lineno] = NULL;
1109 /* print out results */
1112 int ttype, CState * state,
1113 struct timeval * tv1, struct timeval * tv2,
1114 struct timeval * tv3)
1119 int normal_xacts = 0;
1122 for (i = 0; i < nclients; i++)
1123 normal_xacts += state[i].cnt;
1125 t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
1126 t1 = normal_xacts * 1000000.0 / t1;
1128 t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
1129 t2 = normal_xacts * 1000000.0 / t2;
1132 s = "TPC-B (sort of)";
1133 else if (ttype == 2)
1134 s = "Update only accounts";
1135 else if (ttype == 1)
1140 printf("transaction type: %s\n", s);
1141 printf("scaling factor: %d\n", scale);
1142 printf("number of clients: %d\n", nclients);
1143 printf("number of transactions per client: %d\n", nxacts);
1144 printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients);
1145 printf("tps = %f (including connections establishing)\n", t1);
1146 printf("tps = %f (excluding connections establishing)\n", t2);
1151 main(int argc, char **argv)
1154 int is_init_mode = 0; /* initialize mode? */
1155 int is_no_vacuum = 0; /* no vacuum at all before testing? */
1156 int is_full_vacuum = 0; /* do full vacuum before testing? */
1157 int debug = 0; /* debug flag */
1158 int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT only,
1159 * 2: skip update of branches and tellers */
1160 char *filename = NULL;
1162 CState *state; /* status of clients */
1164 struct timeval tv1; /* start up time */
1165 struct timeval tv2; /* after establishing all connections to the
1167 struct timeval tv3; /* end time */
1172 int nsocks; /* return from select(2) */
1173 int maxsock; /* max socket number to be waited */
1175 #if !(defined(__CYGWIN__) || defined(__MINGW32__))
1185 if ((env = getenv("PGHOST")) != NULL && *env != '\0')
1187 if ((env = getenv("PGPORT")) != NULL && *env != '\0')
1189 else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
1192 state = (CState *) malloc(sizeof(CState));
1195 fprintf(stderr, "Couldn't allocate memory for state\n");
1199 memset(state, 0, sizeof(*state));
1201 while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:D:")) != -1)
1230 nclients = atoi(optarg);
1231 if (nclients <= 0 || nclients > MAXCLIENTS)
1233 fprintf(stderr, "invalid number of clients: %d\n", nclients);
1236 #if !(defined(__CYGWIN__) || defined(__MINGW32__))
1237 #ifdef RLIMIT_NOFILE /* most platform uses RLIMIT_NOFILE */
1238 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
1239 #else /* but BSD doesn't ... */
1240 if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
1241 #endif /* RLIMIT_NOFILE */
1243 fprintf(stderr, "getrlimit failed: %s\n", strerror(errno));
1246 if (rlim.rlim_cur <= (nclients + 2))
1248 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);
1249 fprintf(stderr, "Use limit/ulimt to increase the limit before using pgbench.\n");
1258 scale = atoi(optarg);
1261 fprintf(stderr, "invalid scaling factor: %d\n", scale);
1266 nxacts = atoi(optarg);
1269 fprintf(stderr, "invalid number of transactions: %d\n", nxacts);
1285 if (process_file(filename) == false || *sql_files[num_files - 1] == NULL)
1292 if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
1294 fprintf(stderr, "invalid variable definition: %s\n", optarg);
1299 if (putVariable(&state[0], optarg, p) == false)
1301 fprintf(stderr, "Couldn't allocate memory for variable\n");
1314 dbName = argv[optind];
1317 if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
1319 else if (login != NULL && *login != '\0')
1333 if (getVariable(&state[0], "scale") == NULL)
1335 snprintf(val, sizeof(val), "%d", scale);
1336 if (putVariable(&state[0], "scale", val) == false)
1338 fprintf(stderr, "Couldn't allocate memory for variable\n");
1345 state = (CState *) realloc(state, sizeof(CState) * nclients);
1348 fprintf(stderr, "Couldn't allocate memory for state\n");
1352 memset(state + 1, 0, sizeof(*state) * (nclients - 1));
1354 for (i = 1; i < nclients; i++)
1358 for (j = 0; j < state[0].nvariables; j++)
1360 if (putVariable(&state[i], state[0].variables[j].name, state[0].variables[j].value) == false)
1362 fprintf(stderr, "Couldn't allocate memory for variable\n");
1373 snprintf(logpath, 64, "pgbench_log.%d", getpid());
1374 LOGFILE = fopen(logpath, "w");
1376 if (LOGFILE == NULL)
1378 fprintf(stderr, "Couldn't open logfile \"%s\": %s", logpath, strerror(errno));
1385 printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
1386 pghost, pgport, nclients, nxacts, dbName);
1389 /* opening connection... */
1394 if (PQstatus(con) == CONNECTION_BAD)
1396 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
1397 fprintf(stderr, "%s", PQerrorMessage(con));
1404 * get the scaling factor that should be same as count(*) from
1405 * branches if this is not a custom query
1407 res = PQexec(con, "select count(*) from branches");
1408 if (PQresultStatus(res) != PGRES_TUPLES_OK)
1410 fprintf(stderr, "%s", PQerrorMessage(con));
1413 scale = atoi(PQgetvalue(res, 0, 0));
1416 fprintf(stderr, "count(*) from branches invalid (%d)\n", scale);
1421 snprintf(val, sizeof(val), "%d", scale);
1422 if (putVariable(&state[0], "scale", val) == false)
1424 fprintf(stderr, "Couldn't allocate memory for variable\n");
1431 fprintf(stderr, "starting vacuum...");
1432 res = PQexec(con, "vacuum branches");
1433 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1435 fprintf(stderr, "%s", PQerrorMessage(con));
1440 res = PQexec(con, "vacuum tellers");
1441 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1443 fprintf(stderr, "%s", PQerrorMessage(con));
1448 res = PQexec(con, "delete from history");
1449 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1451 fprintf(stderr, "%s", PQerrorMessage(con));
1455 res = PQexec(con, "vacuum history");
1456 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1458 fprintf(stderr, "%s", PQerrorMessage(con));
1463 fprintf(stderr, "end.\n");
1467 fprintf(stderr, "starting full vacuum...");
1468 res = PQexec(con, "vacuum analyze accounts");
1469 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1471 fprintf(stderr, "%s", PQerrorMessage(con));
1475 fprintf(stderr, "end.\n");
1480 /* set random seed */
1481 gettimeofday(&tv1, NULL);
1482 srand((unsigned int) tv1.tv_usec);
1484 /* get start up time */
1485 gettimeofday(&tv1, NULL);
1487 if (is_connect == 0)
1489 /* make connections to the database */
1490 for (i = 0; i < nclients; i++)
1493 if ((state[i].con = doConnect()) == NULL)
1498 /* time after connections set up */
1499 gettimeofday(&tv2, NULL);
1501 /* process bultin SQL scripts */
1505 sql_files[0] = process_builtin(tpc_b);
1510 sql_files[0] = process_builtin(select_only);
1515 sql_files[0] = process_builtin(simple_update);
1523 /* send start up queries in async manner */
1524 for (i = 0; i < nclients; i++)
1526 Command **commands = sql_files[state[i].use_file];
1527 int prev_ecnt = state[i].ecnt;
1529 state[i].use_file = getrand(0, num_files - 1);
1530 doCustom(state, i, debug);
1532 if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
1534 fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
1535 remains--; /* I've aborted */
1536 PQfinish(state[i].con);
1537 state[i].con = NULL;
1545 disconnect_all(state);
1547 gettimeofday(&tv3, NULL);
1548 printResults(ttype, state, &tv1, &tv2, &tv3);
1554 FD_ZERO(&input_mask);
1557 for (i = 0; i < nclients; i++)
1559 Command **commands = sql_files[state[i].use_file];
1561 if (state[i].con && commands[state[i].state]->type != META_COMMAND)
1563 int sock = PQsocket(state[i].con);
1567 disconnect_all(state);
1570 FD_SET(sock, &input_mask);
1578 if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
1579 (fd_set *) NULL, (struct timeval *) NULL)) < 0)
1583 /* must be something wrong */
1584 disconnect_all(state);
1585 fprintf(stderr, "select failed: %s\n", strerror(errno));
1588 else if (nsocks == 0)
1590 fprintf(stderr, "select timeout\n");
1591 for (i = 0; i < nclients; i++)
1593 fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
1594 i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
1600 /* ok, backend returns reply */
1601 for (i = 0; i < nclients; i++)
1603 Command **commands = sql_files[state[i].use_file];
1604 int prev_ecnt = state[i].ecnt;
1606 if (state[i].con && (FD_ISSET(PQsocket(state[i].con), &input_mask)
1607 || commands[state[i].state]->type == META_COMMAND))
1609 doCustom(state, i, debug);
1612 if (state[i].ecnt > prev_ecnt && commands[state[i].state]->type == META_COMMAND)
1614 fprintf(stderr, "Client %d aborted in state %d. Execution meta-command failed.\n", i, state[i].state);
1615 remains--; /* I've aborted */
1616 PQfinish(state[i].con);
1617 state[i].con = NULL;