Обсуждение: enhanced pgbench

Поиск
Список
Период
Сортировка

enhanced pgbench

От
Tatsuo Ishii
Дата:
Hi all,

We have enhanced pgbench so that it accepts a series of SQL commands
in a file(see attached patches against 8.0.3). This would make it
possible to test various sets of SQL commands. In the file it is
allowed to use a "meta command".  Currently only "\setrandom" meta
command is allowed, which sets specified random number into a
variable. For example,

\setrandom aid 1 100000

will set a random number into variable "aid" between 1 and 10000.

A variable can be reffered to in an SQL command by adding ":" in front
of the the command name.

Here is an example SQL command file.

\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

This will execute virtually same SQL commands builtin pgbench.

To use the SQL command file, you can use "-f" option:

pgbench -f /foo/bar/sqlfile

I think the enhanced pgbench is quite usefull and I would like to
include in 8.1. Or should I keep it for 8.2?
--
SRA OSS, Inc. Japan
Tatsuo Ishii
*** pgbench/pgbench.c    2004-11-09 15:09:31.000000000 +0900
--- pgbench-new/pgbench.c    2005-09-27 14:31:34.000000000 +0900
***************
*** 41,46 ****
--- 41,49 ---- #include <sys/resource.h> #endif   /* ! WIN32 */ 
+ #include <ctype.h>
+ #include <search.h>
+  extern char *optarg; extern int    optind; 
***************
*** 72,77 ****
--- 75,83 ---- #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 */
***************
*** 91,96 ****
--- 97,108 ----  typedef struct {
+     char       *name;
+     char       *value;
+ }    Variable;
+ 
+ typedef struct
+ {     PGconn       *con;            /* connection handle to DB */     int            id;                /* client No.
*/    int            state;            /* state No. */
 
***************
*** 103,115 ****     int            tid;            /* teller id for this transaction */     int            delta;
int           abalance;     struct timeval txn_begin;    /* used for measuring latencies */ }    CState;  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][-Ulogin][-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"); } 
 
--- 115,137 ----     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][-ffilename][-l][-U login][-P password][-d][dbname]\n");     fprintf(stderr,
"(initializemode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n"); } 
 
***************
*** 190,195 ****
--- 212,326 ----     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)
***************
*** 465,470 ****
--- 596,765 ----     } } 
+ 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)
***************
*** 644,649 ****
--- 939,1098 ----     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(
***************
*** 670,677 ****         s = "TPC-B (sort of)";     else if (ttype == 2)         s = "Update only accounts";
!     else         s = "SELECT only";      printf("transaction type: %s\n", s);     printf("scaling factor: %d\n",
tps);
--- 1119,1128 ----         s = "TPC-B (sort of)";     else if (ttype == 2)         s = "Update only accounts";
!     else if (ttype == 1)         s = "SELECT only";
+     else
+         s = "Custom query";      printf("transaction type: %s\n", s);     printf("scaling factor: %d\n", tps);
***************
*** 695,700 ****
--- 1146,1152 ----     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 */ 
***************
*** 724,730 ****     else if ((env = getenv("PGUSER")) != NULL && *env != '\0')         login = env; 
!     while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSl")) != -1)     {         switch (c)         {
--- 1176,1182 ----     else if ((env = getenv("PGUSER")) != NULL && *env != '\0')         login = env; 
!     while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:")) != -1)     {         switch (c)         {
***************
*** 806,811 ****
--- 1258,1267 ----             case 'l':                 use_log = true;                 break;
+             case 'f':
+                 ttype = 3;
+                 filename = optarg;
+                 break;             default:                 usage();                 exit(1);
***************
*** 868,941 ****         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)     {
!         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);     }
!     PQclear(res);
! 
!     if (!is_no_vacuum)     {
!         fprintf(stderr, "starting vacuum...");
!         res = PQexec(con, "vacuum branches");
!         if (PQresultStatus(res) != PGRES_COMMAND_OK)         {             fprintf(stderr, "%s",
PQerrorMessage(con));            exit(1);         }
 
!         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"); 
!         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);      /* set random seed */     gettimeofday(&tv1, NULL);
--- 1324,1406 ----         exit(1);     } 
!     if (ttype == 3)     {
!         PQfinish(con);
!         if (process_file(filename) == false)
!             exit(1);     }
!     else     {
!         /*
!          * 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);         }
 
!         tps = atoi(PQgetvalue(res, 0, 0));
!         if (tps < 0)         {
!             fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);             exit(1);         }
PQclear(res);
 
!         if (!is_no_vacuum)         {
!             fprintf(stderr, "starting vacuum...");
!             res = PQexec(con, "vacuum branches");
!             if (PQresultStatus(res) != PGRES_COMMAND_OK)
!             {
!                 fprintf(stderr, "%s", PQerrorMessage(con));
!                 exit(1);
!             }
!             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");
+ 
+             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);     }      /* set random seed */     gettimeofday(&tv1, NULL);
***************
*** 965,970 ****
--- 1430,1437 ----             doOne(state, i, debug, ttype);         else if (ttype == 1)
doSelectOnly(state,i, debug);
 
+         else if (ttype == 3)
+             doCustom(state, i, debug);     }      for (;;)
***************
*** 982,997 ****          FD_ZERO(&input_mask); 
!         maxsock = 0;         for (i = 0; i < nclients; i++)         {
!             if (state[i].con)             {                 int            sock = PQsocket(state[i].con);
    if (sock < 0)                 {
 
-                     fprintf(stderr, "Client %d: PQsocket failed\n", i);                     disconnect_all(state);
                exit(1);                 }
 
--- 1449,1464 ----          FD_ZERO(&input_mask); 
!         maxsock = -1;         for (i = 0; i < nclients; i++)         {
!             if (state[i].con &&
!                 (ttype != 3 || commands[state[i].state]->type != META_COMMAND))             {                 int
      sock = PQsocket(state[i].con);                  if (sock < 0)                 {
disconnect_all(state);                    exit(1);                 }
 
***************
*** 1001,1036 ****             }         } 
!         if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
!                           (fd_set *) NULL, (struct timeval *) NULL)) < 0)         {
!             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);         }          /* ok, backend returns reply */         for (i = 0; i < nclients; i++)
{
 
!             if (state[i].con && FD_ISSET(PQsocket(state[i].con), &input_mask))             {                 if
(ttype== 0 || ttype == 2)                     doOne(state, i, debug, ttype);                 else if (ttype == 1)
             doSelectOnly(state, i, debug);             }         }     }
 
--- 1468,1510 ----             }         } 
!         if (maxsock != -1)         {
!             if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
!                               (fd_set *) NULL, (struct timeval *) NULL)) < 0)             {
!                 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);             }         }          /* ok, backend returns reply */         for (i = 0; i <
nclients;i++)         {
 
!             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);             }         }     }

Re: enhanced pgbench

От
Tom Lane
Дата:
Tatsuo Ishii <ishii@sraoss.co.jp> writes:
> I think the enhanced pgbench is quite usefull and I would like to
> include in 8.1. Or should I keep it for 8.2?

Well, we've traditionally been laxer about contrib than the core
software, so the fact that we're past feature freeze isn't sufficient
reason to say "no".  I'm inclined to say "yes" because I think this
might make a handy debugging tool --- for instance, Janning Vygen's
current problem with temp tables might be reproducible using a pgbench
script, without having to write any new software.

Have you thought about ripping out all the original pgbench code and
instead having a "default script" that duplicates the original behavior?

Also it seems like it'd be useful if there could be more than one
script, so as to test situations where the clients aren't all doing
exactly the same thing.
        regards, tom lane


Re: enhanced pgbench

От
Tatsuo Ishii
Дата:
> Tatsuo Ishii <ishii@sraoss.co.jp> writes:
> > I think the enhanced pgbench is quite usefull and I would like to
> > include in 8.1. Or should I keep it for 8.2?
> 
> Well, we've traditionally been laxer about contrib than the core
> software, so the fact that we're past feature freeze isn't sufficient
> reason to say "no".  I'm inclined to say "yes" because I think this
> might make a handy debugging tool --- for instance, Janning Vygen's
> current problem with temp tables might be reproducible using a pgbench
> script, without having to write any new software.

Ok. I will commit patches and will continue to work on below.

> Have you thought about ripping out all the original pgbench code and
> instead having a "default script" that duplicates the original behavior?

No, but seems an idea. There are few things I need to think about:

1) There are three pgbench's default behaviors: TPC-B like(default),  -N and -S. So we need three scripts.

2) it requires a location where those scripts reside. $prefix/etc  seems appropriate?

> Also it seems like it'd be useful if there could be more than one
> script, so as to test situations where the clients aren't all doing
> exactly the same thing.

How do you assign different scripts to different clients?
--
SRA OSS, Inc. Japan
Tatsuo Ishii


Re: enhanced pgbench

От
Tom Lane
Дата:
Tatsuo Ishii <ishii@sraoss.co.jp> writes:
> 2) it requires a location where those scripts reside. $prefix/etc
>    seems appropriate?

I was thinking of just embedding the default scripts as constants in
the program text.  A little bit ugly but saves a lot of headache with
needing to find installed files.

>> Also it seems like it'd be useful if there could be more than one
>> script, so as to test situations where the clients aren't all doing
>> exactly the same thing.

> How do you assign different scripts to different clients?

I'd be happy with either round-robin or random selection of a new script
each time a thread finishes a script.
        regards, tom lane


Re: enhanced pgbench

От
Tatsuo Ishii
Дата:
> Tatsuo Ishii <ishii@sraoss.co.jp> writes:
> > 2) it requires a location where those scripts reside. $prefix/etc
> >    seems appropriate?
> 
> I was thinking of just embedding the default scripts as constants in
> the program text.  A little bit ugly but saves a lot of headache with
> needing to find installed files.

I see.

> >> Also it seems like it'd be useful if there could be more than one
> >> script, so as to test situations where the clients aren't all doing
> >> exactly the same thing.
> 
> > How do you assign different scripts to different clients?
> 
> I'd be happy with either round-robin or random selection of a new script
> each time a thread finishes a script.

Ok.
--
SRA OSS, Inc. Japan
Tatsuo Ishii