mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Add -f option which enables to read SQL commands from a file.
Patches Contributed by Tomoaki Sato.
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
pgbench README 2003/11/26 Tatsuo Ishii (t-ishii@sra.co.jp)
|
pgbench README 2005/09/29 Tatsuo Ishii
|
||||||
|
|
||||||
o What is pgbench?
|
o What is pgbench?
|
||||||
|
|
||||||
@ -34,16 +34,8 @@ o features of pgbench
|
|||||||
|
|
||||||
o How to install pgbench
|
o How to install pgbench
|
||||||
|
|
||||||
(1) Configure and build the standard Postgres distribution.
|
$make
|
||||||
|
$make install
|
||||||
You can get away with just running configure at the top level
|
|
||||||
and doing "make all" in src/interfaces/libpq.
|
|
||||||
|
|
||||||
(2) Run make in this directory.
|
|
||||||
|
|
||||||
You will see an executable file "pgbench". You can run it here,
|
|
||||||
or install it with the standard Postgres programs by doing
|
|
||||||
"make install".
|
|
||||||
|
|
||||||
o How to use pgbench?
|
o How to use pgbench?
|
||||||
|
|
||||||
@ -124,6 +116,15 @@ o options
|
|||||||
-S
|
-S
|
||||||
Perform select only transactions instead of TPC-B.
|
Perform select only transactions instead of TPC-B.
|
||||||
|
|
||||||
|
-N Do not update "branches" and "tellers". This will
|
||||||
|
avoid heavy update contention on branches and tellers,
|
||||||
|
while it will not make pgbench supporting TPC-B like
|
||||||
|
transactions.
|
||||||
|
|
||||||
|
-f filename
|
||||||
|
Read transaction script from file. Detailed
|
||||||
|
explanation will appear later.
|
||||||
|
|
||||||
-C
|
-C
|
||||||
Establish connection for each transaction, rather than
|
Establish connection for each transaction, rather than
|
||||||
doing it just once at beginning of pgbench in the normal
|
doing it just once at beginning of pgbench in the normal
|
||||||
@ -158,12 +159,58 @@ o What is the "transaction" actually performed in pgbench?
|
|||||||
|
|
||||||
(7) end;
|
(7) end;
|
||||||
|
|
||||||
|
o -f option
|
||||||
|
|
||||||
|
This supports for reading transaction script from a specified
|
||||||
|
file. This file should include SQL commands in each line. SQL
|
||||||
|
command consists of multiple lines are not supported. Empty lines
|
||||||
|
and lines begging with "--" will be ignored.
|
||||||
|
|
||||||
|
SQL commands can include "meta command" which begins with "\" (back
|
||||||
|
slash). A meta command takes some arguments separted by white
|
||||||
|
spaces. Currently following meta command is supported:
|
||||||
|
|
||||||
|
\setrandom name min max
|
||||||
|
|
||||||
|
assign random integer to name between min and max
|
||||||
|
|
||||||
|
example:
|
||||||
|
|
||||||
|
\setrandom aid 1 100000
|
||||||
|
|
||||||
|
variables can be reffered to in SQL comands by adding ":" in front
|
||||||
|
of the varible name.
|
||||||
|
|
||||||
|
example:
|
||||||
|
|
||||||
|
SELECT abalance FROM accounts WHERE aid = :aid
|
||||||
|
|
||||||
|
For example, TPC-B like benchmark can be defined as follows(scaling
|
||||||
|
factor = 1):
|
||||||
|
|
||||||
|
\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
|
||||||
|
|
||||||
o License?
|
o License?
|
||||||
|
|
||||||
Basically it is same as BSD license. See pgbench.c for more details.
|
Basically it is same as BSD license. See pgbench.c for more details.
|
||||||
|
|
||||||
o History
|
o History
|
||||||
|
|
||||||
|
2005/09/29
|
||||||
|
* add -f option. contributed by Tomoaki Sato.
|
||||||
|
|
||||||
|
[updation records were missing]
|
||||||
|
|
||||||
2003/11/26
|
2003/11/26
|
||||||
* create indexes after data insertion to reduce time.
|
* create indexes after data insertion to reduce time.
|
||||||
patch from Yutaka Tanida.
|
patch from Yutaka Tanida.
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
pgbench README 2003/11/26 Tatsuo Ishii (t-ishii@sra.co.jp)
|
pgbench README 2005/09/29 Tatsuo Ishii
|
||||||
|
|
||||||
$B"#(Bpgbench $B$H$O!)(B
|
$B"#(Bpgbench $B$H$O!)(B
|
||||||
|
|
||||||
pgbench $B$O(B TPC-B$B$K;w$?%Y%s%A%^!<%/%F%9%H$r9T$J$&%W%m%0%i%`$G$9!%:#$N$H(B
|
pgbench $B$O%Y%s%A%^!<%/%F%9%H$r9T$J$&%W%m%0%i%`$G$9!%:#$N$H$3$m(B
|
||||||
$B$3$m(B PostgreSQL $B@lMQ$G$9!%(B
|
PostgreSQL $B@lMQ$G$9!%(B
|
||||||
|
|
||||||
pgbench $B$O(B select/update/insert $B$r4^$`%H%i%s%6%/%7%g%s$r<B9T$7!$A4BN$N(B
|
pgbench $B$O(B select/update/insert $B$r4^$`%H%i%s%6%/%7%g%s$r<B9T$7!$A4BN$N(B
|
||||||
$B<B9T;~4V$H<B:]$K40N;$7$?%H%i%s%6%/%7%g%s$N?t$+$i(B 1 $BIC4V$K<B9T$G$-$?%H(B
|
$B<B9T;~4V$H<B:]$K40N;$7$?%H%i%s%6%/%7%g%s$N?t$+$i(B 1 $BIC4V$K<B9T$G$-$?%H(B
|
||||||
@ -31,16 +31,12 @@ o pgbench $B$O(B libpq $B$NHsF14|=hM}5!G=$r;H$C$F%^%k%A%f!<%64D6-$r%7%_%e%l!<
|
|||||||
|
|
||||||
$B"#(Bpgbench $B$N%$%s%9%H!<%k(B
|
$B"#(Bpgbench $B$N%$%s%9%H!<%k(B
|
||||||
|
|
||||||
(1) PostgreSQL$B$r(Bconfigure$B!$%3%s%Q%$%k$7$^$9!%(Bpgbench$B$N%$%s%9%H!<%k$@$1(B
|
PostgreSQL$B$r%3%s%Q%$%k!$%$%s%9%H!<%k$7$?8e(B
|
||||||
$B$,L\E*$G$"$l$P!$(BPostgreSQL$B$N$9$Y$F$r%3%s%Q%$%k$9$kI,MW$O$"$j$^$;$s!%(B
|
|
||||||
PostgreSQL$B%=!<%9$N%H%C%W%G%#%l%/%H%j$G(Bconfigure$B$r$7$?8e!$(B
|
|
||||||
src/interface/libpq $B$G(B "make all" $B$r<B9T$9$l$P=`Hw40N;$G$9!%(B
|
|
||||||
|
|
||||||
(2) $B$3$N%G%#%l%/%H%j$G(B make $B$r<B9T$7$^$9!%$=$&$9$k$H!$(B"pgbench" $B$H$$$&(B
|
$ make
|
||||||
$B<B9T%W%m%0%i%`$,$G$-$^$9!%$=$N$^$^<B9T$7$F$b9=$$$^$;$s$7!$(B"make
|
$ make install
|
||||||
install" $B$r<B9T$7$F(B PostgreSQL $B$NI8=`<B9T%W%m%0%i%`%G%#%l%/%H%j(B
|
|
||||||
($B%G%U%)%k%H$G$O(B /usr/local/pgsql/bin) $B$K%$%s%9%H!<%k$9$k$3$H$b$G$-(B
|
$B$H$7$^$9!%(B
|
||||||
$B$^$9!%(B
|
|
||||||
|
|
||||||
$B"#(Bpgbench $B$N;H$$J}(B
|
$B"#(Bpgbench $B$N;H$$J}(B
|
||||||
|
|
||||||
@ -104,6 +100,12 @@ pgbench $B$K$O$$$m$$$m$J%*%W%7%g%s$,$"$j$^$9!%(B
|
|||||||
$B$OE,9g$7$J$/$J$j$^$9$,!$$h$j8=<BE*$JIi2Y$r%F%9%H$9$k$3(B
|
$B$OE,9g$7$J$/$J$j$^$9$,!$$h$j8=<BE*$JIi2Y$r%F%9%H$9$k$3(B
|
||||||
$B$H$,$G$-$^$9!%(B
|
$B$H$,$G$-$^$9!%(B
|
||||||
|
|
||||||
|
-f filename $B%H%i%s%6%/%7%g%s$NFbMF$,5-=R$5$l$?%U%!%$%kL>$r;XDj$7$^(B
|
||||||
|
$B$9!%$3$N%*%W%7%g%s$r;XDj$9$k$H!$%U%!%$%k$K5-=R$5$l$?Fb(B
|
||||||
|
$BMF$N%H%i%s%6%/%7%g%s$r<B9T$7$^$9!%$J$*!$%Y%s%A%^!<%/$N(B
|
||||||
|
$BBP>]$H$J$k%G!<%?%Y!<%9$O$"$i$+$8$a=i4|2=$7$F$*$/I,MW$,(B
|
||||||
|
$B$"$j$^$9!%F~NO%U%)!<%^%C%H$K$D$$$F$O8e=R$7$^$9!%(B
|
||||||
|
|
||||||
-C $B$3$N%*%W%7%g%s$r;XDj$9$k$H!$:G=i$K3NN)$7$?%3%M%/%7%g%s(B
|
-C $B$3$N%*%W%7%g%s$r;XDj$9$k$H!$:G=i$K3NN)$7$?%3%M%/%7%g%s(B
|
||||||
$B$r;H$$2s$9$N$G$O$J$/!$3F%H%i%s%6%/%7%g%s$4$H$K(BDB$B$X$N@\(B
|
$B$r;H$$2s$9$N$G$O$J$/!$3F%H%i%s%6%/%7%g%s$4$H$K(BDB$B$X$N@\(B
|
||||||
$BB3$r9T$$$^$9!%%3%M%/%7%g%s$N%*!<%P!<$X%C%I$rB,Dj$9$k$N(B
|
$BB3$r9T$$$^$9!%%3%M%/%7%g%s$N%*!<%P!<$X%C%I$rB,Dj$9$k$N(B
|
||||||
@ -176,6 +178,52 @@ 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(
|
|||||||
|
|
||||||
(7) end;
|
(7) end;
|
||||||
|
|
||||||
|
$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
|
||||||
|
$B%^%s%I$NFbMF$r5-=R$7$?%U%!%$%k$rFI$_9~$`$3$H$,$G$-$^$9!%F~NO%U%!%$%k$K(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
|
||||||
|
$B$G;O$^$k9T$O%3%a%s%H$r0UL#$7$^$9!%(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%3%^%s%I$N7A<0$O%P%C%/%9%i%C%7%e!$$=$ND>8e$K%3%^%s%I$NF0;l!$$=$N<!$K0z(B
|
||||||
|
$B?t$,B3$-$^$9!%F0;l%3%^%s%I$H0z?t!$$^$?$=$l$>$l$N0z?t$O6uGrJ8;z$K$h$C$F(B
|
||||||
|
$B6h@Z$i$l$^$9!%(B
|
||||||
|
|
||||||
|
$B8=:_$N$H$3$m!$0J2<$N%a%?%3%^%s%I$,Dj5A$5$l$F$$$^$9!%(B
|
||||||
|
|
||||||
|
\setrandom name min max
|
||||||
|
$B:G>.CM(B min $B$H:GBgCM(B max $B$N4V$NCM$r<h$kMp?t$r!$(Bname $BJQ?t$K@_Dj(B
|
||||||
|
$B$7$^$9!%(B
|
||||||
|
|
||||||
|
$BJQ?t$KMp?t$r@_Dj$9$k$K$O!$(B\setrandom $B%a%?%3%^%s%I$r;HMQ$7$F0J2<$N$h$&(B
|
||||||
|
$B$K5-=R$7$^$9!%(B
|
||||||
|
|
||||||
|
\setrandom aid 1 100000
|
||||||
|
|
||||||
|
$B$3$l$O!$JQ?t(B aid $B$K(B 1 $B$+$i(B 100000 $B$N4V$NMp?t$r@_Dj$7$^$9!%$^$?!$JQ?t$N(B
|
||||||
|
$BCM$r(B SQL $B%3%^%s%I$KKd$a9~$`$K$O!$0J2<$N$h$&$K$=$NL>A0$NA0$K%3%m%s$rIU(B
|
||||||
|
$B$1$^$9!%(B
|
||||||
|
|
||||||
|
SELECT abalance FROM accounts WHERE aid = :aid
|
||||||
|
|
||||||
|
$BNc$($P!$(BTCP-B $B$KN`;w$7$?%Y%s%A%^!<%/$r7WB,$9$k$K$O!$0J2<$N$h$&$K%H%i%s(B
|
||||||
|
$B%6%/%7%g%s$NFbMF$r%U%!%$%k$K5-=R$7!$(B-f $B%*%W%7%g%s$K$h$C$F$=$N%U%!%$%k(B
|
||||||
|
$B$r;XDj$7$F(B pgbench $B$r<B9T$7$^$9!%(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
|
||||||
|
|
||||||
$B"#:n<T$H%i%$%;%s%9>r7o(B
|
$B"#:n<T$H%i%$%;%s%9>r7o(B
|
||||||
|
|
||||||
pgbench $B$O@P0f(B $BC#IW$K$h$C$F=q$+$l$^$7$?!%%i%$%;%s%9>r7o$O(B pgbench.c $B$N(B
|
pgbench $B$O@P0f(B $BC#IW$K$h$C$F=q$+$l$^$7$?!%%i%$%;%s%9>r7o$O(B pgbench.c $B$N(B
|
||||||
@ -184,6 +232,11 @@ pgbench $B$O@P0f(B $BC#IW$K$h$C$F=q$+$l$^$7$?!%%i%$%;%s%9>r7o$O(B pgbench.c
|
|||||||
|
|
||||||
$B"#2~DjMzNr(B
|
$B"#2~DjMzNr(B
|
||||||
|
|
||||||
|
2005/09/29
|
||||||
|
* $B:4F#$5$s$N%Q%C%A$rE,MQ!%(B-f $B%*%W%7%g%s$NDI2C!%(B
|
||||||
|
|
||||||
|
[$B$3$N4V$$$m$$$mJQ99$,$"$C$?$h$&$@$,(BREADME$B$O%a%$%s%F%J%s%9$5$l$F$$$J$$(B]
|
||||||
|
|
||||||
2003/11/26
|
2003/11/26
|
||||||
* $BC+ED$5$s$N%Q%C%A$rE,MQ!%(Bpgbench -i$B$N:]$K!$8e$+$i<g%-!<$r:n@.(B
|
* $BC+ED$5$s$N%Q%C%A$rE,MQ!%(Bpgbench -i$B$N:]$K!$8e$+$i<g%-!<$r:n@.(B
|
||||||
$B$9$k$h$&$K$7$?!%$3$l$K$h$C$F=i4|2=$N<B9T;~4V$,BgI}$KC;=L$G$-(B
|
$B$9$k$h$&$K$7$?!%$3$l$K$h$C$F=i4|2=$N<B9T;~4V$,BgI}$KC;=L$G$-(B
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* $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
|
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
|
||||||
* written by Tatsuo Ishii
|
* 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
|
* Permission to use, copy, modify, and distribute this software and
|
||||||
* its documentation for any purpose and without fee is hereby
|
* its documentation for any purpose and without fee is hereby
|
||||||
@ -41,6 +41,9 @@
|
|||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#endif /* ! WIN32 */
|
#endif /* ! WIN32 */
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <search.h>
|
||||||
|
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind;
|
extern int optind;
|
||||||
|
|
||||||
@ -72,6 +75,9 @@ 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 */
|
||||||
@ -89,6 +95,12 @@ 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 */
|
||||||
@ -103,13 +115,23 @@ typedef struct
|
|||||||
int tid; /* teller id for this transaction */
|
int tid; /* teller id for this transaction */
|
||||||
int delta;
|
int delta;
|
||||||
int abalance;
|
int abalance;
|
||||||
|
void *variables;
|
||||||
struct timeval txn_begin; /* used for measuring latencies */
|
struct timeval txn_begin; /* used for measuring latencies */
|
||||||
} CState;
|
} CState;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
} Command;
|
||||||
|
|
||||||
|
Command **commands = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(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");
|
fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +212,115 @@ check(CState * state, PGresult *res, int n, int good)
|
|||||||
return (0); /* OK */
|
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 */
|
/* process a transaction */
|
||||||
static void
|
static void
|
||||||
doOne(CState * state, int n, int debug, int ttype)
|
doOne(CState * state, int n, int debug, int ttype)
|
||||||
@ -465,6 +596,170 @@ doSelectOnly(CState * state, int n, int debug)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 */
|
/* discard connections */
|
||||||
static void
|
static void
|
||||||
disconnect_all(CState * state)
|
disconnect_all(CState * state)
|
||||||
@ -644,6 +939,160 @@ init(void)
|
|||||||
PQfinish(con);
|
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 */
|
/* print out results */
|
||||||
static void
|
static void
|
||||||
printResults(
|
printResults(
|
||||||
@ -670,8 +1119,10 @@ printResults(
|
|||||||
s = "TPC-B (sort of)";
|
s = "TPC-B (sort of)";
|
||||||
else if (ttype == 2)
|
else if (ttype == 2)
|
||||||
s = "Update only accounts";
|
s = "Update only accounts";
|
||||||
else
|
else if (ttype == 1)
|
||||||
s = "SELECT only";
|
s = "SELECT only";
|
||||||
|
else
|
||||||
|
s = "Custom query";
|
||||||
|
|
||||||
printf("transaction type: %s\n", s);
|
printf("transaction type: %s\n", s);
|
||||||
printf("scaling factor: %d\n", tps);
|
printf("scaling factor: %d\n", tps);
|
||||||
@ -695,6 +1146,7 @@ main(int argc, char **argv)
|
|||||||
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT
|
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT
|
||||||
* only, 2: skip update of branches and
|
* only, 2: skip update of branches and
|
||||||
* tellers */
|
* tellers */
|
||||||
|
char *filename = NULL;
|
||||||
|
|
||||||
static CState *state; /* status of clients */
|
static CState *state; /* status of clients */
|
||||||
|
|
||||||
@ -724,7 +1176,7 @@ main(int argc, char **argv)
|
|||||||
else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
|
else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
|
||||||
login = env;
|
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)
|
switch (c)
|
||||||
{
|
{
|
||||||
@ -806,6 +1258,10 @@ main(int argc, char **argv)
|
|||||||
case 'l':
|
case 'l':
|
||||||
use_log = true;
|
use_log = true;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
ttype = 3;
|
||||||
|
filename = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -868,74 +1324,83 @@ main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (ttype == 3)
|
||||||
* 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));
|
PQfinish(con);
|
||||||
exit(1);
|
if (process_file(filename) == false)
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
tps = atoi(PQgetvalue(res, 0, 0));
|
else
|
||||||
if (tps < 0)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);
|
/*
|
||||||
exit(1);
|
* get the scaling factor that should be same as count(*) from
|
||||||
}
|
* branches...
|
||||||
PQclear(res);
|
*/
|
||||||
|
res = PQexec(con, "select count(*) from branches");
|
||||||
if (!is_no_vacuum)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
|
||||||
fprintf(stderr, "starting vacuum...");
|
|
||||||
res = PQexec(con, "vacuum branches");
|
|
||||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s", PQerrorMessage(con));
|
fprintf(stderr, "%s", PQerrorMessage(con));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
PQclear(res);
|
tps = atoi(PQgetvalue(res, 0, 0));
|
||||||
|
if (tps < 0)
|
||||||
res = PQexec(con, "vacuum tellers");
|
|
||||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s", PQerrorMessage(con));
|
fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
res = PQexec(con, "delete from history");
|
if (!is_no_vacuum)
|
||||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s", PQerrorMessage(con));
|
fprintf(stderr, "starting vacuum...");
|
||||||
exit(1);
|
res = PQexec(con, "vacuum branches");
|
||||||
}
|
|
||||||
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)
|
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 tellers");
|
||||||
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s", PQerrorMessage(con));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
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");
|
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);
|
||||||
@ -965,6 +1430,8 @@ main(int argc, char **argv)
|
|||||||
doOne(state, i, debug, ttype);
|
doOne(state, i, debug, ttype);
|
||||||
else if (ttype == 1)
|
else if (ttype == 1)
|
||||||
doSelectOnly(state, i, debug);
|
doSelectOnly(state, i, debug);
|
||||||
|
else if (ttype == 3)
|
||||||
|
doCustom(state, i, debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -982,16 +1449,16 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
FD_ZERO(&input_mask);
|
FD_ZERO(&input_mask);
|
||||||
|
|
||||||
maxsock = 0;
|
maxsock = -1;
|
||||||
for (i = 0; i < nclients; i++)
|
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);
|
int sock = PQsocket(state[i].con);
|
||||||
|
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Client %d: PQsocket failed\n", i);
|
|
||||||
disconnect_all(state);
|
disconnect_all(state);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -1001,36 +1468,43 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
|
if (maxsock != -1)
|
||||||
(fd_set *) NULL, (struct timeval *) NULL)) < 0)
|
|
||||||
{
|
{
|
||||||
if (errno == EINTR)
|
if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
|
||||||
continue;
|
(fd_set *) NULL, (struct timeval *) NULL)) < 0)
|
||||||
/* 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",
|
if (errno == EINTR)
|
||||||
i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
|
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 */
|
/* ok, backend returns reply */
|
||||||
for (i = 0; i < nclients; i++)
|
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)
|
if (ttype == 0 || ttype == 2)
|
||||||
doOne(state, i, debug, ttype);
|
doOne(state, i, debug, ttype);
|
||||||
else if (ttype == 1)
|
else if (ttype == 1)
|
||||||
doSelectOnly(state, i, debug);
|
doSelectOnly(state, i, debug);
|
||||||
|
else if (ttype == 3)
|
||||||
|
doCustom(state, i, debug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user