-pgbench README 2003/11/26 Tatsuo Ishii (t-ishii@sra.co.jp)
+pgbench README 2005/09/29 Tatsuo Ishii
\e$B"#\e(Bpgbench \e$B$H$O!)\e(B
-pgbench \e$B$O\e(B TPC-B\e$B$K;w$?%Y%s%A%^!<%/%F%9%H$r9T$J$&%W%m%0%i%`$G$9!%:#$N$H\e(B
-\e$B$3$m\e(B PostgreSQL \e$B@lMQ$G$9!%\e(B
+pgbench \e$B$O%Y%s%A%^!<%/%F%9%H$r9T$J$&%W%m%0%i%`$G$9!%:#$N$H$3$m\e(B
+PostgreSQL \e$B@lMQ$G$9!%\e(B
pgbench \e$B$O\e(B select/update/insert \e$B$r4^$`%H%i%s%6%/%7%g%s$r<B9T$7!$A4BN$N\e(B
\e$B<B9T;~4V$H<B:]$K40N;$7$?%H%i%s%6%/%7%g%s$N?t$+$i\e(B 1 \e$BIC4V$K<B9T$G$-$?%H\e(B
\e$B"#\e(Bpgbench \e$B$N%$%s%9%H!<%k\e(B
-(1) PostgreSQL\e$B$r\e(Bconfigure\e$B!$%3%s%Q%$%k$7$^$9!%\e(Bpgbench\e$B$N%$%s%9%H!<%k$@$1\e(B
- \e$B$,L\E*$G$"$l$P!$\e(BPostgreSQL\e$B$N$9$Y$F$r%3%s%Q%$%k$9$kI,MW$O$"$j$^$;$s!%\e(B
- PostgreSQL\e$B%=!<%9$N%H%C%W%G%#%l%/%H%j$G\e(Bconfigure\e$B$r$7$?8e!$\e(B
- src/interface/libpq \e$B$G\e(B "make all" \e$B$r<B9T$9$l$P=`Hw40N;$G$9!%\e(B
+PostgreSQL\e$B$r%3%s%Q%$%k!$%$%s%9%H!<%k$7$?8e\e(B
-(2) \e$B$3$N%G%#%l%/%H%j$G\e(B make \e$B$r<B9T$7$^$9!%$=$&$9$k$H!$\e(B"pgbench" \e$B$H$$$&\e(B
- \e$B<B9T%W%m%0%i%`$,$G$-$^$9!%$=$N$^$^<B9T$7$F$b9=$$$^$;$s$7!$\e(B"make
- install" \e$B$r<B9T$7$F\e(B PostgreSQL \e$B$NI8=`<B9T%W%m%0%i%`%G%#%l%/%H%j\e(B
- (\e$B%G%U%)%k%H$G$O\e(B /usr/local/pgsql/bin) \e$B$K%$%s%9%H!<%k$9$k$3$H$b$G$-\e(B
- \e$B$^$9!%\e(B
+$ make
+$ make install
+
+\e$B$H$7$^$9!%\e(B
\e$B"#\e(Bpgbench \e$B$N;H$$J}\e(B
\e$B$OE,9g$7$J$/$J$j$^$9$,!$$h$j8=<BE*$JIi2Y$r%F%9%H$9$k$3\e(B
\e$B$H$,$G$-$^$9!%\e(B
+-f filename \e$B%H%i%s%6%/%7%g%s$NFbMF$,5-=R$5$l$?%U%!%$%kL>$r;XDj$7$^\e(B
+ \e$B$9!%$3$N%*%W%7%g%s$r;XDj$9$k$H!$%U%!%$%k$K5-=R$5$l$?Fb\e(B
+ \e$BMF$N%H%i%s%6%/%7%g%s$r<B9T$7$^$9!%$J$*!$%Y%s%A%^!<%/$N\e(B
+ \e$BBP>]$H$J$k%G!<%?%Y!<%9$O$"$i$+$8$a=i4|2=$7$F$*$/I,MW$,\e(B
+ \e$B$"$j$^$9!%F~NO%U%)!<%^%C%H$K$D$$$F$O8e=R$7$^$9!%\e(B
+
-C \e$B$3$N%*%W%7%g%s$r;XDj$9$k$H!$:G=i$K3NN)$7$?%3%M%/%7%g%s\e(B
\e$B$r;H$$2s$9$N$G$O$J$/!$3F%H%i%s%6%/%7%g%s$4$H$K\e(BDB\e$B$X$N@\\e(B
\e$BB3$r9T$$$^$9!%%3%M%/%7%g%s$N%*!<%P!<$X%C%I$rB,Dj$9$k$N\e(B
(7) end;
+\e$B"#F~NO%U%!%$%k$N%U%)!<%^%C%H\e(B
+
+pgbench \e$B$G$O!$\e(B-f \e$B%*%W%7%g%s$r;XDj$7$F%H%i%s%6%/%7%g%s$K4^$^$l$k\e(B SQL \e$B%3\e(B
+\e$B%^%s%I$NFbMF$r5-=R$7$?%U%!%$%k$rFI$_9~$`$3$H$,$G$-$^$9!%F~NO%U%!%$%k$K\e(B
+\e$B$O\e(B 1 \e$B9T$K$D$-\e(B 1 \e$B$D$N%3%^%s%I$r5-=R$7$^$9!%6u9T$OL5;k$5$l!$Fs=E%O%$%U%s\e(B
+\e$B$G;O$^$k9T$O%3%a%s%H$r0UL#$7$^$9!%\e(B
+
+\e$B%3%^%s%I$K$O!$\e(BSQL \e$B%3%^%s%I$K2C$(!$%P%C%/%9%i%C%7%e$G;O$^$k%a%?%3%^%s%I\e(B
+\e$B$r5-=R$G$-$^$9!%%a%?%3%^%s%I$O\e(B pgbench \e$B<+?H$K$h$C$F<B9T$5$l$^$9!%%a%?\e(B
+\e$B%3%^%s%I$N7A<0$O%P%C%/%9%i%C%7%e!$$=$ND>8e$K%3%^%s%I$NF0;l!$$=$N<!$K0z\e(B
+\e$B?t$,B3$-$^$9!%F0;l%3%^%s%I$H0z?t!$$^$?$=$l$>$l$N0z?t$O6uGrJ8;z$K$h$C$F\e(B
+\e$B6h@Z$i$l$^$9!%\e(B
+
+\e$B8=:_$N$H$3$m!$0J2<$N%a%?%3%^%s%I$,Dj5A$5$l$F$$$^$9!%\e(B
+
+\setrandom name min max
+ \e$B:G>.CM\e(B min \e$B$H:GBgCM\e(B max \e$B$N4V$NCM$r<h$kMp?t$r!$\e(Bname \e$BJQ?t$K@_Dj\e(B
+ \e$B$7$^$9!%\e(B
+
+\e$BJQ?t$KMp?t$r@_Dj$9$k$K$O!$\e(B\setrandom \e$B%a%?%3%^%s%I$r;HMQ$7$F0J2<$N$h$&\e(B
+\e$B$K5-=R$7$^$9!%\e(B
+
+\setrandom aid 1 100000
+
+\e$B$3$l$O!$JQ?t\e(B aid \e$B$K\e(B 1 \e$B$+$i\e(B 100000 \e$B$N4V$NMp?t$r@_Dj$7$^$9!%$^$?!$JQ?t$N\e(B
+\e$BCM$r\e(B SQL \e$B%3%^%s%I$KKd$a9~$`$K$O!$0J2<$N$h$&$K$=$NL>A0$NA0$K%3%m%s$rIU\e(B
+\e$B$1$^$9!%\e(B
+
+SELECT abalance FROM accounts WHERE aid = :aid
+
+\e$BNc$($P!$\e(BTCP-B \e$B$KN`;w$7$?%Y%s%A%^!<%/$r7WB,$9$k$K$O!$0J2<$N$h$&$K%H%i%s\e(B
+\e$B%6%/%7%g%s$NFbMF$r%U%!%$%k$K5-=R$7!$\e(B-f \e$B%*%W%7%g%s$K$h$C$F$=$N%U%!%$%k\e(B
+\e$B$r;XDj$7$F\e(B pgbench \e$B$r<B9T$7$^$9!%\e(B
+
+\setrandom aid 1 100000
+\setrandom bid 1 1
+\setrandom tid 1 10
+\setrandom delta 1 10000
+BEGIN
+UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid
+SELECT abalance FROM accounts WHERE aid = :aid
+UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid
+UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid
+INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, 'now')
+END
+
\e$B"#:n<T$H%i%$%;%s%9>r7o\e(B
pgbench \e$B$O@P0f\e(B \e$BC#IW$K$h$C$F=q$+$l$^$7$?!%%i%$%;%s%9>r7o$O\e(B pgbench.c \e$B$N\e(B
\e$B"#2~DjMzNr\e(B
+2005/09/29
+ * \e$B:4F#$5$s$N%Q%C%A$rE,MQ!%\e(B-f \e$B%*%W%7%g%s$NDI2C!%\e(B
+
+[\e$B$3$N4V$$$m$$$mJQ99$,$"$C$?$h$&$@$,\e(BREADME\e$B$O%a%$%s%F%J%s%9$5$l$F$$$J$$\e(B]
+
2003/11/26
* \e$BC+ED$5$s$N%Q%C%A$rE,MQ!%\e(Bpgbench -i\e$B$N:]$K!$8e$+$i<g%-!<$r:n@.\e(B
\e$B$9$k$h$&$K$7$?!%$3$l$K$h$C$F=i4|2=$N<B9T;~4V$,BgI}$KC;=L$G$-\e(B
/*
- * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.36 2005/05/24 00:26:40 neilc Exp $
+ * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.37 2005/09/29 13:44:25 ishii Exp $
*
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2000-2004 Tatsuo Ishii
+ * Copyright (c) 2000-2005 Tatsuo Ishii
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
#include <sys/resource.h>
#endif /* ! WIN32 */
+#include <ctype.h>
+#include <search.h>
+
extern char *optarg;
extern int optind;
#define ntellers 10
#define naccounts 100000
+#define SQL_COMMAND 1
+#define META_COMMAND 2
+
FILE *LOGFILE = NULL;
bool use_log; /* log transaction latencies to a file */
char *pwd = NULL;
char *dbName;
+typedef struct
+{
+ char *name;
+ char *value;
+} Variable;
+
typedef struct
{
PGconn *con; /* connection handle to DB */
int tid; /* teller id for this transaction */
int delta;
int abalance;
+ void *variables;
struct timeval txn_begin; /* used for measuring latencies */
} CState;
+typedef struct
+{
+ int type;
+ int argc;
+ char **argv;
+} Command;
+
+Command **commands = NULL;
+
static void
usage(void)
{
- fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-n][-C][-v][-S][-N][-l][-U login][-P password][-d][dbname]\n");
+ fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-n][-C][-v][-S][-N][-f filename][-l][-U login][-P password][-d][dbname]\n");
fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
}
return (0); /* OK */
}
+static int
+compareVariables(const void *v1, const void *v2)
+{
+ return strcmp(((Variable *)v1)->name, ((Variable *)v2)->name);
+}
+
+static char *
+getVariable(CState * st, char *name)
+{
+ Variable key = { name }, *var;
+
+ var = tfind(&key, &st->variables, compareVariables);
+ if (var != NULL)
+ return (*(Variable **)var)->value;
+ else
+ return NULL;
+}
+
+static int
+putVariable(CState * st, char *name, char *value)
+{
+ Variable key = { name }, *var;
+
+ var = tfind(&key, &st->variables, compareVariables);
+ if (var == NULL)
+ {
+ if ((var = malloc(sizeof(Variable))) == NULL)
+ return false;
+
+ var->name = NULL;
+ var->value = NULL;
+
+ if ((var->name = strdup(name)) == NULL
+ || (var->value = strdup(value)) == NULL
+ || tsearch(var, &st->variables, compareVariables) == NULL)
+ {
+ free(var->name);
+ free(var->value);
+ free(var);
+ return false;
+ }
+ }
+ else
+ {
+ free((*(Variable **)var)->value);
+ if (((*(Variable **)var)->value = strdup(value)) == NULL)
+ return false;
+ }
+
+ return true;
+}
+
+static char *
+assignVariables(CState * st, char *sql)
+{
+ int i, j;
+ char *p, *name, *val;
+ void *tmp;
+
+ i = 0;
+ while ((p = strchr(&sql[i], ':')) != NULL)
+ {
+ i = j = p - sql;
+ do
+ i++;
+ while (isalnum(sql[i]) != 0 || sql[i] == '_');
+ if (i == j + 1)
+ continue;
+
+ if ((name = strndup(&sql[j + 1], i - (j + 1))) == NULL)
+ return NULL;
+ val = getVariable(st, name);
+ free(name);
+ if (val == NULL)
+ continue;
+
+ if (strlen(val) > i - j)
+ {
+ tmp = realloc(sql, strlen(sql) - (i - j) + strlen(val) + 1);
+ if (tmp == NULL)
+ {
+ free(sql);
+ return NULL;
+ }
+ sql = tmp;
+ }
+
+ if (strlen(val) != i - j)
+ memmove(&sql[j + strlen(val)], &sql[i], strlen(&sql[i]) + 1);
+
+ strncpy(&sql[j], val, strlen(val));
+
+ if (strlen(val) < i - j)
+ {
+ tmp = realloc(sql, strlen(sql) + 1);
+ if (tmp == NULL)
+ {
+ free(sql);
+ return NULL;
+ }
+ sql = tmp;
+ }
+
+ i = j + strlen(val);
+ }
+
+ return sql;
+}
+
/* process a transaction */
static void
doOne(CState * state, int n, int debug, int ttype)
}
}
+static void
+doCustom(CState * state, int n, int debug)
+{
+ PGresult *res;
+ CState *st = &state[n];
+
+ if (st->listen)
+ { /* are we receiver? */
+ if (commands[st->state]->type == SQL_COMMAND)
+ {
+ if (debug)
+ fprintf(stderr, "client %d receiving\n", n);
+ if (!PQconsumeInput(st->con))
+ { /* there's something wrong */
+ fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
+ remains--; /* I've aborted */
+ PQfinish(st->con);
+ st->con = NULL;
+ return;
+ }
+ if (PQisBusy(st->con))
+ return; /* don't have the whole result yet */
+ }
+
+ /*
+ * transaction finished: record the time it took in the
+ * log
+ */
+ if (use_log && commands[st->state + 1] == NULL)
+ {
+ double diff;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ diff = (int) (now.tv_sec - st->txn_begin.tv_sec) * 1000000.0 +
+ (int) (now.tv_usec - st->txn_begin.tv_usec);
+
+ fprintf(LOGFILE, "%d %d %.0f\n", st->id, st->cnt, diff);
+ }
+
+ if (commands[st->state]->type == SQL_COMMAND)
+ {
+ res = PQgetResult(st->con);
+ if (strncasecmp(commands[st->state]->argv[0], "select", 6) != 0)
+ {
+ if (check(state, res, n, PGRES_COMMAND_OK))
+ return;
+ }
+ else
+ {
+ if (check(state, res, n, PGRES_TUPLES_OK))
+ return;
+ }
+ PQclear(res);
+ discard_response(st);
+ }
+
+ if (commands[st->state + 1] == NULL)
+ {
+ if (is_connect)
+ {
+ PQfinish(st->con);
+ st->con = NULL;
+ }
+
+ if (++st->cnt >= nxacts)
+ {
+ remains--; /* I'm done */
+ if (st->con != NULL)
+ {
+ PQfinish(st->con);
+ st->con = NULL;
+ }
+ return;
+ }
+ }
+
+ /* increment state counter */
+ st->state++;
+ if (commands[st->state] == NULL)
+ st->state = 0;
+ }
+
+ if (st->con == NULL)
+ {
+ if ((st->con = doConnect()) == NULL)
+ {
+ fprintf(stderr, "Client %d aborted in establishing connection.\n",
+ n);
+ remains--; /* I've aborted */
+ PQfinish(st->con);
+ st->con = NULL;
+ return;
+ }
+ }
+
+ if (use_log && st->state == 0)
+ gettimeofday(&(st->txn_begin), NULL);
+
+ if (commands[st->state]->type == SQL_COMMAND)
+ {
+ char *sql;
+
+ if ((sql = strdup(commands[st->state]->argv[0])) == NULL
+ || (sql = assignVariables(st, sql)) == NULL)
+ {
+ fprintf(stderr, "out of memory\n");
+ st->ecnt++;
+ return;
+ }
+
+ if (debug)
+ fprintf(stderr, "client %d sending %s\n", n, sql);
+ if (PQsendQuery(st->con, sql) == 0)
+ {
+ if (debug)
+ fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
+ st->ecnt++;
+ }
+ else
+ {
+ st->listen++; /* flags that should be listened */
+ }
+ }
+ else if (commands[st->state]->type == META_COMMAND)
+ {
+ int argc = commands[st->state]->argc, i;
+ char **argv = commands[st->state]->argv;
+
+ if (debug)
+ {
+ fprintf(stderr, "client %d executing \\%s", n, argv[0]);
+ for (i = 1; i < argc; i++)
+ fprintf(stderr, " %s", argv[i]);
+ fprintf(stderr, "\n");
+ }
+
+ if (strcasecmp(argv[0], "setrandom") == 0)
+ {
+ char *val;
+
+ if ((val = malloc(strlen(argv[3]) + 1)) == NULL)
+ {
+ fprintf(stderr, "%s: out of memory\n", argv[0]);
+ st->ecnt++;
+ return;
+ }
+
+ sprintf(val, "%d", getrand(atoi(argv[2]), atoi(argv[3])));
+
+ if (putVariable(st, argv[1], val) == false)
+ {
+ fprintf(stderr, "%s: out of memory\n", argv[0]);
+ free(val);
+ st->ecnt++;
+ return;
+ }
+
+ free(val);
+ st->listen++;
+ }
+ }
+}
+
/* discard connections */
static void
disconnect_all(CState * state)
PQfinish(con);
}
+static int
+process_file(char *filename)
+{
+ const char delim[] = " \f\n\r\t\v";
+
+ FILE *fd;
+ int lineno, i, j;
+ char buf[BUFSIZ], *p, *tok;
+ void *tmp;
+
+ if (strcmp(filename, "-") == 0)
+ fd = stdin;
+ else if ((fd = fopen(filename, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: %s\n", strerror(errno), filename);
+ return false;
+ }
+
+ fprintf(stderr, "processing file...\n");
+
+ lineno = 1;
+ i = 0;
+ while (fgets(buf, sizeof(buf), fd) != NULL)
+ {
+ if ((p = strchr(buf, '\n')) != NULL)
+ *p = '\0';
+ p = buf;
+ while (isspace(*p))
+ p++;
+ if (*p == '\0' || strncmp(p, "--", 2) == 0)
+ {
+ lineno++;
+ continue;
+ }
+
+ if ((tmp = realloc(commands, sizeof(Command *) * (i + 1))) == NULL)
+ {
+ i--;
+ goto error;
+ }
+ commands = tmp;
+
+ if ((commands[i] = malloc(sizeof(Command))) == NULL)
+ goto error;
+
+ commands[i]->argv = NULL;
+ commands[i]->argc = 0;
+
+ if (*p == '\\')
+ {
+ commands[i]->type = META_COMMAND;
+
+ j = 0;
+ tok = strtok(++p, delim);
+ while (tok != NULL)
+ {
+ tmp = realloc(commands[i]->argv, sizeof(char *) * (j + 1));
+ if (tmp == NULL)
+ goto error;
+ commands[i]->argv = tmp;
+
+ if ((commands[i]->argv[j] = strdup(tok)) == NULL)
+ goto error;
+
+ commands[i]->argc++;
+
+ j++;
+ tok = strtok(NULL, delim);
+ }
+
+ if (strcasecmp(commands[i]->argv[0], "setrandom") == 0)
+ {
+ int min, max;
+
+ if (commands[i]->argc < 4)
+ {
+ fprintf(stderr, "%s: %d: \\%s: missing argument\n", filename, lineno, commands[i]->argv[0]);
+ goto error;
+ }
+
+ for (j = 4; j < commands[i]->argc; j++)
+ fprintf(stderr, "%s: %d: \\%s: extra argument \"%s\" ignored\n", filename, lineno, commands[i]->argv[0], commands[i]->argv[j]);
+
+ if ((min = atoi(commands[i]->argv[2])) < 0)
+ {
+ fprintf(stderr, "%s: %d: \\%s: invalid minimum number %s\n", filename, lineno, commands[i]->argv[0], commands[i]->argv[2]);
+ goto error;
+ }
+
+ if ((max = atoi(commands[i]->argv[3])) < min || max > RAND_MAX)
+ {
+ fprintf(stderr, "%s: %d: \\%s: invalid maximum number %s\n", filename, lineno, commands[i]->argv[0], commands[i]->argv[3]);
+ goto error;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s: %d: invalid command \\%s\n", filename, lineno, commands[i]->argv[0]);
+ goto error;
+ }
+ }
+ else
+ {
+ commands[i]->type = SQL_COMMAND;
+
+ if ((commands[i]->argv = malloc(sizeof(char *))) == NULL)
+ goto error;
+
+ if ((commands[i]->argv[0] = strdup(p)) == NULL)
+ goto error;
+
+ commands[i]->argc++;
+ }
+
+ i++;
+ lineno++;
+ }
+ fclose(fd);
+
+ if ((tmp = realloc(commands, sizeof(Command *) * (i + 1))) == NULL)
+ goto error;
+ commands = tmp;
+
+ commands[i] = NULL;
+
+ return true;
+
+error:
+ if (errno == ENOMEM)
+ fprintf(stderr, "%s: %d: out of memory\n", filename, lineno);
+
+ fclose(fd);
+
+ if (commands == NULL)
+ return false;
+
+ while (i >= 0)
+ {
+ if (commands[i] != NULL)
+ {
+ for (j = 0; j < commands[i]->argc; j++)
+ free(commands[i]->argv[j]);
+
+ free(commands[i]->argv);
+ free(commands[i]);
+ }
+
+ i--;
+ }
+ free(commands);
+
+ return false;
+}
+
/* print out results */
static void
printResults(
s = "TPC-B (sort of)";
else if (ttype == 2)
s = "Update only accounts";
- else
+ else if (ttype == 1)
s = "SELECT only";
+ else
+ s = "Custom query";
printf("transaction type: %s\n", s);
printf("scaling factor: %d\n", tps);
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT
* only, 2: skip update of branches and
* tellers */
+ char *filename = NULL;
static CState *state; /* status of clients */
else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
login = env;
- while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSl")) != -1)
+ while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:")) != -1)
{
switch (c)
{
case 'l':
use_log = true;
break;
+ case 'f':
+ ttype = 3;
+ filename = optarg;
+ break;
default:
usage();
exit(1);
exit(1);
}
- /*
- * get the scaling factor that should be same as count(*) from
- * branches...
- */
- res = PQexec(con, "select count(*) from branches");
- if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ if (ttype == 3)
{
- fprintf(stderr, "%s", PQerrorMessage(con));
- exit(1);
- }
- tps = atoi(PQgetvalue(res, 0, 0));
- if (tps < 0)
- {
- fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);
- exit(1);
+ PQfinish(con);
+ if (process_file(filename) == false)
+ exit(1);
}
- PQclear(res);
-
- if (!is_no_vacuum)
+ else
{
- fprintf(stderr, "starting vacuum...");
- res = PQexec(con, "vacuum branches");
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ /*
+ * get the scaling factor that should be same as count(*) from
+ * branches...
+ */
+ res = PQexec(con, "select count(*) from branches");
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
- PQclear(res);
-
- res = PQexec(con, "vacuum tellers");
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ tps = atoi(PQgetvalue(res, 0, 0));
+ if (tps < 0)
{
- fprintf(stderr, "%s", PQerrorMessage(con));
+ fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);
exit(1);
}
PQclear(res);
- res = PQexec(con, "delete from history");
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ if (!is_no_vacuum)
{
- fprintf(stderr, "%s", PQerrorMessage(con));
- exit(1);
- }
- PQclear(res);
- res = PQexec(con, "vacuum history");
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- fprintf(stderr, "%s", PQerrorMessage(con));
- exit(1);
- }
- PQclear(res);
+ fprintf(stderr, "starting vacuum...");
+ res = PQexec(con, "vacuum branches");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "%s", PQerrorMessage(con));
+ exit(1);
+ }
+ PQclear(res);
- fprintf(stderr, "end.\n");
+ res = PQexec(con, "vacuum tellers");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "%s", PQerrorMessage(con));
+ exit(1);
+ }
+ PQclear(res);
- if (is_full_vacuum)
- {
- fprintf(stderr, "starting full vacuum...");
- res = PQexec(con, "vacuum analyze accounts");
+ res = PQexec(con, "delete from history");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "%s", PQerrorMessage(con));
+ exit(1);
+ }
+ PQclear(res);
+ res = PQexec(con, "vacuum history");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
+
fprintf(stderr, "end.\n");
+
+ if (is_full_vacuum)
+ {
+ fprintf(stderr, "starting full vacuum...");
+ res = PQexec(con, "vacuum analyze accounts");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "%s", PQerrorMessage(con));
+ exit(1);
+ }
+ PQclear(res);
+ fprintf(stderr, "end.\n");
+ }
}
+ PQfinish(con);
}
- PQfinish(con);
/* set random seed */
gettimeofday(&tv1, NULL);
doOne(state, i, debug, ttype);
else if (ttype == 1)
doSelectOnly(state, i, debug);
+ else if (ttype == 3)
+ doCustom(state, i, debug);
}
for (;;)
FD_ZERO(&input_mask);
- maxsock = 0;
+ maxsock = -1;
for (i = 0; i < nclients; i++)
{
- if (state[i].con)
+ if (state[i].con &&
+ (ttype != 3 || commands[state[i].state]->type != META_COMMAND))
{
int sock = PQsocket(state[i].con);
if (sock < 0)
{
- fprintf(stderr, "Client %d: PQsocket failed\n", i);
disconnect_all(state);
exit(1);
}
}
}
- if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
- (fd_set *) NULL, (struct timeval *) NULL)) < 0)
+ if (maxsock != -1)
{
- if (errno == EINTR)
- continue;
- /* must be something wrong */
- disconnect_all(state);
- fprintf(stderr, "select failed: %s\n", strerror(errno));
- exit(1);
- }
- else if (nsocks == 0)
- { /* timeout */
- fprintf(stderr, "select timeout\n");
- for (i = 0; i < nclients; i++)
+ if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
+ (fd_set *) NULL, (struct timeval *) NULL)) < 0)
{
- fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
- i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
+ if (errno == EINTR)
+ continue;
+ /* must be something wrong */
+ disconnect_all(state);
+ fprintf(stderr, "select failed: %s\n", strerror(errno));
+ exit(1);
+ }
+ else if (nsocks == 0)
+ { /* timeout */
+ fprintf(stderr, "select timeout\n");
+ for (i = 0; i < nclients; i++)
+ {
+ fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
+ i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
+ }
+ exit(0);
}
- exit(0);
}
/* ok, backend returns reply */
for (i = 0; i < nclients; i++)
{
- if (state[i].con && FD_ISSET(PQsocket(state[i].con), &input_mask))
+ if (state[i].con && (FD_ISSET(PQsocket(state[i].con), &input_mask)
+ || (ttype == 3
+ && commands[state[i].state]->type == META_COMMAND)))
{
if (ttype == 0 || ttype == 2)
doOne(state, i, debug, ttype);
else if (ttype == 1)
doSelectOnly(state, i, debug);
+ else if (ttype == 3)
+ doCustom(state, i, debug);
}
}
}