Commit f50ae06e authored by Tatsuo Ishii's avatar Tatsuo Ishii

Allow multiple -f options.

Make pgbench "script driven" to eliminate hard coded transaction
scenario. (Tatsuo Ishii)
parent ffa156bb
pgbench README 2005/09/29 Tatsuo Ishii pgbench README 2005/10/04 Tatsuo Ishii
o What is pgbench? o What is pgbench?
...@@ -166,6 +166,9 @@ o -f option ...@@ -166,6 +166,9 @@ o -f option
command consists of multiple lines are not supported. Empty lines command consists of multiple lines are not supported. Empty lines
and lines begging with "--" will be ignored. and lines begging with "--" will be ignored.
Multiple -f options are allowed. In this case each transaction is
assigned randomly chosen script.
SQL commands can include "meta command" which begins with "\" (back SQL commands can include "meta command" which begins with "\" (back
slash). A meta command takes some arguments separted by white slash). A meta command takes some arguments separted by white
spaces. Currently following meta command is supported: spaces. Currently following meta command is supported:
......
...@@ -180,10 +180,12 @@ pgbench $B$G$O!$0J2<$N%7!<%1%s%9$rA4It40N;$7$F(B1$B%H%i%s%6%/%7%g%s$H?t$($F( ...@@ -180,10 +180,12 @@ pgbench $B$G$O!$0J2<$N%7!<%1%s%9$rA4It40N;$7$F(B1$B%H%i%s%6%/%7%g%s$H?t$($F(
$B"#F~NO%U%!%$%k$N%U%)!<%^%C%H(B $B"#F~NO%U%!%$%k$N%U%)!<%^%C%H(B
pgbench $B$G$O!$(B-f $B%*%W%7%g%s$r;XDj$7$F%H%i%s%6%/%7%g%s$K4^$^$l$k(B SQL $B%3(B -f $B%*%W%7%g%s$r;XDj$7$F%H%i%s%6%/%7%g%s$K4^$^$l$k(B SQL $B%3%^%s%I$NFbMF$r(B
$B%^%s%I$NFbMF$r5-=R$7$?%U%!%$%k$rFI$_9~$`$3$H$,$G$-$^$9!%F~NO%U%!%$%k$K(B $B5-=R$7$?%U%!%$%k$rFI$_9~$`$3$H$,$G$-$^$9!%F~NO%U%!%$%k$K$O(B 1 $B9T$K$D$-(B
$B$O(B 1 $B9T$K$D$-(B 1 $B$D$N%3%^%s%I$r5-=R$7$^$9!%6u9T$OL5;k$5$l!$Fs=E%O%$%U%s(B 1 $B$D$N%3%^%s%I$r5-=R$7$^$9!%6u9T$OL5;k$5$l!$Fs=E%O%$%U%s$G;O$^$k9T$O%3(B
$B$G;O$^$k9T$O%3%a%s%H$r0UL#$7$^$9!%(B $B%a%s%H$r0UL#$7$^$9!%(B
-f $B%*%W%7%g%s$OJ#?t;XDj$G$-$^$9!%$3$N>l9g$O(B
$B%3%^%s%I$K$O!$(BSQL $B%3%^%s%I$K2C$(!$%P%C%/%9%i%C%7%e$G;O$^$k%a%?%3%^%s%I(B $B%3%^%s%I$K$O!$(BSQL $B%3%^%s%I$K2C$(!$%P%C%/%9%i%C%7%e$G;O$^$k%a%?%3%^%s%I(B
$B$r5-=R$G$-$^$9!%%a%?%3%^%s%I$O(B pgbench $B<+?H$K$h$C$F<B9T$5$l$^$9!%%a%?(B $B$r5-=R$G$-$^$9!%%a%?%3%^%s%I$O(B pgbench $B<+?H$K$h$C$F<B9T$5$l$^$9!%%a%?(B
......
/* /*
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.38 2005/09/29 16:18:26 tgl Exp $ * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.39 2005/10/04 13:40:45 ishii Exp $
* *
* pgbench: a simple TPC-B like benchmark program for PostgreSQL * pgbench: a simple benchmark program for PostgreSQL
* written by Tatsuo Ishii * written by Tatsuo Ishii
* *
* Copyright (c) 2000-2005 Tatsuo Ishii * Copyright (c) 2000-2005 Tatsuo Ishii
...@@ -73,9 +73,6 @@ int tps = 1; ...@@ -73,9 +73,6 @@ int tps = 1;
#define ntellers 10 #define ntellers 10
#define naccounts 100000 #define naccounts 100000
#define SQL_COMMAND 1
#define META_COMMAND 2
FILE *LOGFILE = NULL; FILE *LOGFILE = NULL;
bool use_log; /* log transaction latencies to a file */ bool use_log; /* log transaction latencies to a file */
...@@ -93,12 +90,6 @@ char *login = NULL; ...@@ -93,12 +90,6 @@ char *login = NULL;
char *pwd = NULL; char *pwd = NULL;
char *dbName; char *dbName;
typedef struct
{
char *name;
char *value;
} Variable;
typedef struct typedef struct
{ {
PGconn *con; /* connection handle to DB */ PGconn *con; /* connection handle to DB */
...@@ -108,23 +99,75 @@ typedef struct ...@@ -108,23 +99,75 @@ typedef struct
int ecnt; /* error count */ int ecnt; /* error count */
int listen; /* 0 indicates that an async query has int listen; /* 0 indicates that an async query has
* been sent */ * been sent */
int aid; /* account id for this transaction */
int bid; /* branch id for this transaction */
int tid; /* teller id for this transaction */
int delta;
int abalance;
void *variables; void *variables;
struct timeval txn_begin; /* used for measuring latencies */ struct timeval txn_begin; /* used for measuring latencies */
int use_file; /* index in sql_files for this client */
} CState; } CState;
/*
* structures used in custom query mode
*/
/* variable definitions */
typedef struct
{
char *name; /* variable name */
char *value; /* its value */
} Variable;
/*
* queries read from files
*/
#define SQL_COMMAND 1
#define META_COMMAND 2
#define MAX_ARGS 10
typedef struct typedef struct
{ {
int type; int type; /* command type (SQL_COMMAND or META_COMMAND) */
int argc; int argc; /* number of commands */
char **argv; char *argv[MAX_ARGS]; /* command list */
} Command; } Command;
Command **commands = NULL; #define MAX_FILES 128 /* max number of SQL script files allowed */
Command **sql_files[MAX_FILES]; /* SQL script files */
int num_files; /* its number */
/* default scenario */
static char *tpc_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, CURRENT_TIMESTAMP);
END;
"};
/* -N case */
static char *simple_update = {
"\\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;
INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
END;
"};
/* -S case */
static char *select_only = {
"\\setrandom aid 1 100000
SELECT abalance FROM accounts WHERE aid = :aid;
"};
static void static void
usage(void) usage(void)
...@@ -137,7 +180,7 @@ usage(void) ...@@ -137,7 +180,7 @@ usage(void)
static int static int
getrand(int min, int max) getrand(int min, int max)
{ {
return (min + (int) (max * 1.0 * rand() / (RAND_MAX + 1.0))); return (min + (int) (max * 1.0 * rand() / (RAND_MAX + 1.0) + 0.5));
} }
/* set up a connection to the backend */ /* set up a connection to the backend */
...@@ -322,286 +365,14 @@ assignVariables(CState * st, char *sql) ...@@ -322,286 +365,14 @@ assignVariables(CState * st, char *sql)
return sql; return sql;
} }
/* process a transaction */
static void
doOne(CState * state, int n, int debug, int ttype)
{
char sql[256];
PGresult *res;
CState *st = &state[n];
if (st->listen)
{ /* are we receiver? */
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 */
switch (st->state)
{
case 0: /* response to "begin" */
res = PQgetResult(st->con);
if (check(state, res, n, PGRES_COMMAND_OK))
return;
PQclear(res);
discard_response(st);
break;
case 1: /* response to "update accounts..." */
res = PQgetResult(st->con);
if (check(state, res, n, PGRES_COMMAND_OK))
return;
PQclear(res);
discard_response(st);
break;
case 2: /* response to "select abalance ..." */
res = PQgetResult(st->con);
if (check(state, res, n, PGRES_TUPLES_OK))
return;
PQclear(res);
discard_response(st);
break;
case 3: /* response to "update tellers ..." */
res = PQgetResult(st->con);
if (check(state, res, n, PGRES_COMMAND_OK))
return;
PQclear(res);
discard_response(st);
break;
case 4: /* response to "update branches ..." */
res = PQgetResult(st->con);
if (check(state, res, n, PGRES_COMMAND_OK))
return;
PQclear(res);
discard_response(st);
break;
case 5: /* response to "insert into history ..." */
res = PQgetResult(st->con);
if (check(state, res, n, PGRES_COMMAND_OK))
return;
PQclear(res);
discard_response(st);
break;
case 6: /* response to "end" */
/*
* transaction finished: record the time it took in the
* log
*/
if (use_log)
{
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);
}
res = PQgetResult(st->con);
if (check(state, res, n, PGRES_COMMAND_OK))
return;
PQclear(res);
discard_response(st);
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;
}
break;
}
/* increment state counter */
st->state++;
if (st->state > 6)
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;
}
}
switch (st->state)
{
case 0: /* about to start */
strcpy(sql, "begin");
st->aid = getrand(1, naccounts * tps);
st->bid = getrand(1, nbranches * tps);
st->tid = getrand(1, ntellers * tps);
st->delta = getrand(1, 1000);
if (use_log)
gettimeofday(&(st->txn_begin), NULL);
break;
case 1:
snprintf(sql, 256, "update accounts set abalance = abalance + %d where aid = %d\n", st->delta, st->aid);
break;
case 2:
snprintf(sql, 256, "select abalance from accounts where aid = %d", st->aid);
break;
case 3:
if (ttype == 0)
{
snprintf(sql, 256, "update tellers set tbalance = tbalance + %d where tid = %d\n",
st->delta, st->tid);
break;
}
case 4:
if (ttype == 0)
{
snprintf(sql, 256, "update branches set bbalance = bbalance + %d where bid = %d", st->delta, st->bid);
break;
}
case 5:
snprintf(sql, 256, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
st->tid, st->bid, st->aid, st->delta);
break;
case 6:
strcpy(sql, "end");
break;
}
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 */
}
}
/* process a select only transaction */
static void
doSelectOnly(CState * state, int n, int debug)
{
char sql[256];
PGresult *res;
CState *st = &state[n];
if (st->listen)
{ /* are we receiver? */
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 */
switch (st->state)
{
case 0: /* response to "select abalance ..." */
res = PQgetResult(st->con);
if (check(state, res, n, PGRES_TUPLES_OK))
return;
PQclear(res);
discard_response(st);
if (is_connect)
{
PQfinish(st->con);
st->con = NULL;
}
if (++st->cnt >= nxacts)
{
remains--; /* I've done */
if (st->con != NULL)
{
PQfinish(st->con);
st->con = NULL;
}
return;
}
break;
}
/* increment state counter */
st->state++;
if (st->state > 0)
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;
}
}
switch (st->state)
{
case 0:
st->aid = getrand(1, naccounts * tps);
snprintf(sql, 256, "select abalance from accounts where aid = %d", st->aid);
break;
}
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 */
}
}
static void static void
doCustom(CState * state, int n, int debug) doCustom(CState * state, int n, int debug)
{ {
PGresult *res; PGresult *res;
CState *st = &state[n]; CState *st = &state[n];
Command **commands;
commands = sql_files[st->use_file];
if (st->listen) if (st->listen)
{ /* are we receiver? */ { /* are we receiver? */
...@@ -664,7 +435,7 @@ doCustom(CState * state, int n, int debug) ...@@ -664,7 +435,7 @@ doCustom(CState * state, int n, int debug)
if (++st->cnt >= nxacts) if (++st->cnt >= nxacts)
{ {
remains--; /* I'm done */ remains--; /* I've done */
if (st->con != NULL) if (st->con != NULL)
{ {
PQfinish(st->con); PQfinish(st->con);
...@@ -677,7 +448,10 @@ doCustom(CState * state, int n, int debug) ...@@ -677,7 +448,10 @@ doCustom(CState * state, int n, int debug)
/* increment state counter */ /* increment state counter */
st->state++; st->state++;
if (commands[st->state] == NULL) if (commands[st->state] == NULL)
{
st->state = 0; st->state = 0;
st->use_file = getrand(0, num_files-1);
}
} }
if (st->con == NULL) if (st->con == NULL)
...@@ -718,8 +492,9 @@ doCustom(CState * state, int n, int debug) ...@@ -718,8 +492,9 @@ doCustom(CState * state, int n, int debug)
} }
else else
{ {
st->listen++; /* flags that should be listened */ st->listen = 1; /* flags that should be listened */
} }
free(sql);
} }
else if (commands[st->state]->type == META_COMMAND) else if (commands[st->state]->type == META_COMMAND)
{ {
...@@ -756,7 +531,7 @@ doCustom(CState * state, int n, int debug) ...@@ -756,7 +531,7 @@ doCustom(CState * state, int n, int debug)
} }
free(val); free(val);
st->listen++; st->listen = 1;
} }
} }
} }
...@@ -940,158 +715,226 @@ init(void) ...@@ -940,158 +715,226 @@ init(void)
PQfinish(con); PQfinish(con);
} }
static int static Command*
process_file(char *filename) process_commands(char *buf)
{ {
const char delim[] = " \f\n\r\t\v"; const char delim[] = " \f\n\r\t\v";
FILE *fd; Command *my_commands;
int lineno, i, j; int j;
char buf[BUFSIZ], *p, *tok; char *p, *tok;
void *tmp;
if (strcmp(filename, "-") == 0) if ((p = strchr(buf, '\n')) != NULL)
fd = stdin; *p = '\0';
else if ((fd = fopen(filename, "r")) == NULL)
p = buf;
while (isspace((unsigned char) *p))
p++;
if (*p == '\0' || strncmp(p, "--", 2) == 0)
{ {
fprintf(stderr, "%s: %s\n", strerror(errno), filename); return NULL;
return false;
} }
fprintf(stderr, "processing file...\n"); my_commands = (Command *)malloc(sizeof(Command));
if (my_commands == NULL)
lineno = 1;
i = 0;
while (fgets(buf, sizeof(buf), fd) != NULL)
{ {
if ((p = strchr(buf, '\n')) != NULL) return NULL;
*p = '\0'; }
p = buf;
while (isspace((unsigned char) *p))
p++;
if (*p == '\0' || strncmp(p, "--", 2) == 0)
{
lineno++;
continue;
}
if ((tmp = realloc(commands, sizeof(Command *) * (i + 1))) == NULL) my_commands->argc = 0;
{
i--;
goto error;
}
commands = tmp;
if ((commands[i] = malloc(sizeof(Command))) == NULL) if (*p == '\\')
goto error; {
my_commands->type = META_COMMAND;
commands[i]->argv = NULL; j = 0;
commands[i]->argc = 0; tok = strtok(++p, delim);
if (*p == '\\') while (tok != NULL)
{ {
commands[i]->type = META_COMMAND; if ((my_commands->argv[j] = strdup(tok)) == NULL)
return NULL;
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++; my_commands->argc++;
j++; j++;
tok = strtok(NULL, delim); tok = strtok(NULL, delim);
} }
if (strcasecmp(my_commands->argv[0], "setrandom") == 0)
{
int min, max;
if (strcasecmp(commands[i]->argv[0], "setrandom") == 0) if (my_commands->argc < 4)
{ {
int min, max; fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
return NULL;
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++) for (j = 4; j < my_commands->argc; j++)
fprintf(stderr, "%s: %d: \\%s: extra argument \"%s\" ignored\n", filename, lineno, commands[i]->argv[0], commands[i]->argv[j]); fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
my_commands->argv[0], my_commands->argv[j]);
if ((min = atoi(commands[i]->argv[2])) < 0) if ((min = atoi(my_commands->argv[2])) < 0)
{ {
fprintf(stderr, "%s: %d: \\%s: invalid minimum number %s\n", filename, lineno, commands[i]->argv[0], commands[i]->argv[2]); fprintf(stderr, "%s: invalid minimum number %s\n",
goto error; my_commands->argv[0], my_commands->argv[2]);
} return NULL;
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
if ((max = atoi(my_commands->argv[3])) < min || max > RAND_MAX)
{ {
fprintf(stderr, "%s: %d: invalid command \\%s\n", filename, lineno, commands[i]->argv[0]); fprintf(stderr, "%s: invalid maximum number %s\n",
goto error; my_commands->argv[0], my_commands->argv[3]);
return NULL;
} }
} }
else else
{ {
commands[i]->type = SQL_COMMAND; fprintf(stderr, "invalid command %s\n", my_commands->argv[0]);
return NULL;
}
}
else
{
my_commands->type = SQL_COMMAND;
if ((my_commands->argv[0] = strdup(p)) == NULL)
return NULL;
my_commands->argc++;
}
return my_commands;
}
static int
process_file(char *filename)
{
#define COMMANDS_ALLOC_NUM 128
Command **my_commands;
FILE *fd;
int lineno;
char buf[BUFSIZ];
int alloc_num;
if (num_files >= MAX_FILES)
{
fprintf(stderr, "Up to only %d SQL files are allowed\n", MAX_FILES);
exit(1);
}
alloc_num = COMMANDS_ALLOC_NUM;
my_commands = (Command **)malloc(sizeof(Command **)*alloc_num);
if (my_commands == NULL)
return false;
if (strcmp(filename, "-") == 0)
fd = stdin;
else if ((fd = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "%s: %s\n", strerror(errno), filename);
return false;
}
if ((commands[i]->argv = malloc(sizeof(char *))) == NULL) lineno = 0;
goto error;
if ((commands[i]->argv[0] = strdup(p)) == NULL) while (fgets(buf, sizeof(buf), fd) != NULL)
goto error; {
Command *commands;
commands[i]->argc++; commands = process_commands(buf);
if (commands == NULL)
{
fclose(fd);
return false;
} }
i++; my_commands[lineno] = commands;
lineno++; lineno++;
if (lineno >= alloc_num)
{
alloc_num += COMMANDS_ALLOC_NUM;
my_commands = realloc(my_commands, alloc_num);
if (my_commands == NULL)
{
fclose(fd);
return false;
}
}
} }
fclose(fd); fclose(fd);
if ((tmp = realloc(commands, sizeof(Command *) * (i + 1))) == NULL) my_commands[lineno] = NULL;
goto error;
commands = tmp;
commands[i] = NULL; sql_files[num_files++] = my_commands;
return true; return true;
}
error: static Command **
if (errno == ENOMEM) process_builtin(char *tb)
fprintf(stderr, "%s: %d: out of memory\n", filename, lineno); {
#define COMMANDS_ALLOC_NUM 128
fclose(fd); Command **my_commands;
int lineno;
char buf[BUFSIZ];
int alloc_num;
if (commands == NULL) if (*tb == '\0')
return false; return NULL;
alloc_num = COMMANDS_ALLOC_NUM;
my_commands = malloc(sizeof(Command **)*alloc_num);
if (my_commands == NULL)
return NULL;
while (i >= 0) lineno = 0;
for(;;)
{ {
if (commands[i] != NULL) char *p;
{ Command *commands;
for (j = 0; j < commands[i]->argc; j++)
free(commands[i]->argv[j]);
free(commands[i]->argv); p = buf;
free(commands[i]); while (*tb && *tb != '\n')
*p++ = *tb++;
if (*tb == '\0')
break;
if (*tb == '\n')
tb++;
*p = '\0';
commands = process_commands(buf);
if (commands == NULL)
{
return NULL;
} }
i--; my_commands[lineno] = commands;
lineno++;
if (lineno >= alloc_num)
{
alloc_num += COMMANDS_ALLOC_NUM;
my_commands = realloc(my_commands, alloc_num);
if (my_commands == NULL)
{
return NULL;
}
}
} }
free(commands);
return false; my_commands[lineno] = NULL;
return my_commands;
} }
/* print out results */ /* print out results */
...@@ -1262,6 +1105,8 @@ main(int argc, char **argv) ...@@ -1262,6 +1105,8 @@ main(int argc, char **argv)
case 'f': case 'f':
ttype = 3; ttype = 3;
filename = optarg; filename = optarg;
if (process_file(filename) == false)
exit(1);
break; break;
default: default:
usage(); usage();
...@@ -1291,6 +1136,12 @@ main(int argc, char **argv) ...@@ -1291,6 +1136,12 @@ main(int argc, char **argv)
remains = nclients; remains = nclients;
state = (CState *) malloc(sizeof(*state) * nclients); state = (CState *) malloc(sizeof(*state) * nclients);
if (state == NULL)
{
fprintf(stderr, "Couldn't allocate memory for state\n");
exit(1);
}
memset(state, 0, sizeof(*state) * nclients); memset(state, 0, sizeof(*state) * nclients);
if (use_log) if (use_log)
...@@ -1325,17 +1176,11 @@ main(int argc, char **argv) ...@@ -1325,17 +1176,11 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
if (ttype == 3) if (ttype != 3)
{
PQfinish(con);
if (process_file(filename) == false)
exit(1);
}
else
{ {
/* /*
* get the scaling factor that should be same as count(*) from * get the scaling factor that should be same as count(*) from
* branches... * branches if this is not a custom query
*/ */
res = PQexec(con, "select count(*) from branches"); res = PQexec(con, "select count(*) from branches");
if (PQresultStatus(res) != PGRES_TUPLES_OK) if (PQresultStatus(res) != PGRES_TUPLES_OK)
...@@ -1350,58 +1195,58 @@ main(int argc, char **argv) ...@@ -1350,58 +1195,58 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
PQclear(res); PQclear(res);
}
if (!is_no_vacuum) if (!is_no_vacuum)
{
fprintf(stderr, "starting vacuum...");
res = PQexec(con, "vacuum branches");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{ {
fprintf(stderr, "starting vacuum..."); fprintf(stderr, "%s", PQerrorMessage(con));
res = PQexec(con, "vacuum branches"); exit(1);
if (PQresultStatus(res) != PGRES_COMMAND_OK) }
{ PQclear(res);
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
res = PQexec(con, "vacuum tellers"); res = PQexec(con, "vacuum tellers");
if (PQresultStatus(res) != PGRES_COMMAND_OK) if (PQresultStatus(res) != PGRES_COMMAND_OK)
{ {
fprintf(stderr, "%s", PQerrorMessage(con)); fprintf(stderr, "%s", PQerrorMessage(con));
exit(1); exit(1);
} }
PQclear(res); PQclear(res);
res = PQexec(con, "delete from history"); res = PQexec(con, "delete from history");
if (PQresultStatus(res) != PGRES_COMMAND_OK) if (PQresultStatus(res) != PGRES_COMMAND_OK)
{ {
fprintf(stderr, "%s", PQerrorMessage(con)); fprintf(stderr, "%s", PQerrorMessage(con));
exit(1); exit(1);
} }
PQclear(res); PQclear(res);
res = PQexec(con, "vacuum history"); 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) if (PQresultStatus(res) != PGRES_COMMAND_OK)
{ {
fprintf(stderr, "%s", PQerrorMessage(con)); fprintf(stderr, "%s", PQerrorMessage(con));
exit(1); exit(1);
} }
PQclear(res); PQclear(res);
fprintf(stderr, "end.\n"); 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 */ /* set random seed */
gettimeofday(&tv1, NULL); gettimeofday(&tv1, NULL);
...@@ -1424,15 +1269,50 @@ main(int argc, char **argv) ...@@ -1424,15 +1269,50 @@ main(int argc, char **argv)
/* time after connections set up */ /* time after connections set up */
gettimeofday(&tv2, NULL); gettimeofday(&tv2, NULL);
/* process bultin SQL scripts */
switch (ttype)
{
char buf[128];
case 0:
sql_files[0] = process_builtin(tpc_b);
snprintf(buf, sizeof(buf), "%d", 100000*tps);
sql_files[0][0]->argv[3] = strdup(buf);
snprintf(buf, sizeof(buf), "%d", 1*tps);
sql_files[0][1]->argv[3] = strdup(buf);
snprintf(buf, sizeof(buf), "%d", 10*tps);
sql_files[0][2]->argv[3] = strdup(buf);
snprintf(buf, sizeof(buf), "%d", 10000*tps);
sql_files[0][3]->argv[3] = strdup(buf);
num_files = 1;
break;
case 1:
sql_files[0] = process_builtin(select_only);
snprintf(buf, sizeof(buf), "%d", 100000*tps);
sql_files[0][0]->argv[3] = strdup(buf);
num_files = 1;
break;
case 2:
sql_files[0] = process_builtin(simple_update);
snprintf(buf, sizeof(buf), "%d", 100000*tps);
sql_files[0][0]->argv[3] = strdup(buf);
snprintf(buf, sizeof(buf), "%d", 1*tps);
sql_files[0][1]->argv[3] = strdup(buf);
snprintf(buf, sizeof(buf), "%d", 10*tps);
sql_files[0][2]->argv[3] = strdup(buf);
snprintf(buf, sizeof(buf), "%d", 10000*tps);
sql_files[0][3]->argv[3] = strdup(buf);
num_files = 1;
break;
default:
break;
}
/* send start up queries in async manner */ /* send start up queries in async manner */
for (i = 0; i < nclients; i++) for (i = 0; i < nclients; i++)
{ {
if (ttype == 0 || ttype == 2) state[i].use_file = getrand(0, num_files-1);
doOne(state, i, debug, ttype); doCustom(state, i, debug);
else if (ttype == 1)
doSelectOnly(state, i, debug);
else if (ttype == 3)
doCustom(state, i, debug);
} }
for (;;) for (;;)
...@@ -1453,8 +1333,9 @@ main(int argc, char **argv) ...@@ -1453,8 +1333,9 @@ main(int argc, char **argv)
maxsock = -1; maxsock = -1;
for (i = 0; i < nclients; i++) for (i = 0; i < nclients; i++)
{ {
if (state[i].con && Command **commands = sql_files[state[i].use_file];
(ttype != 3 || commands[state[i].state]->type != META_COMMAND))
if (state[i].con && commands[state[i].state]->type != META_COMMAND)
{ {
int sock = PQsocket(state[i].con); int sock = PQsocket(state[i].con);
...@@ -1496,16 +1377,12 @@ main(int argc, char **argv) ...@@ -1496,16 +1377,12 @@ main(int argc, char **argv)
/* ok, backend returns reply */ /* ok, backend returns reply */
for (i = 0; i < nclients; i++) for (i = 0; i < nclients; i++)
{ {
Command **commands = sql_files[state[i].use_file];
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))
&& commands[state[i].state]->type == META_COMMAND)))
{ {
if (ttype == 0 || ttype == 2) doCustom(state, i, debug);
doOne(state, i, debug, ttype);
else if (ttype == 1)
doSelectOnly(state, i, debug);
else if (ttype == 3)
doCustom(state, i, debug);
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment