Added a new scripting meta command
authorJan Wieck <JanWieck@Yahoo.com>
Fri, 6 Jul 2007 13:36:55 +0000 (13:36 +0000)
committerJan Wieck <JanWieck@Yahoo.com>
Fri, 6 Jul 2007 13:36:55 +0000 (13:36 +0000)
    \usleep [milliseconds|:variable]

which can be used in -f scripts to insert a thinking time between
other commands.

Jan

contrib/pgbench/README.pgbench
contrib/pgbench/pgbench.c

index 599dc3b6c541552579ff524b2102b5548c1e5e97..2afd4db25e8355ef56735a244a4d9157ba3807bd 100644 (file)
@@ -1,4 +1,4 @@
-$PostgreSQL: pgsql/contrib/pgbench/README.pgbench,v 1.18 2007/04/08 01:15:07 ishii Exp $
+$PostgreSQL: pgsql/contrib/pgbench/README.pgbench,v 1.19 2007/07/06 13:36:55 wieck Exp $
 
 pgbench README
 
@@ -231,6 +231,16 @@ o -f option
 
   Variables can also be defined by using -D option.
 
+  \usleep usec
+
+   causes script execution to sleep for the specified duration in
+   microseconds.
+
+  example:
+
+  \setrandom usec 1000000 3000000
+  \usleep :usec
+
   Example, TPC-B like benchmark can be defined as follows(scaling
   factor = 1):
 
index 2de6a51b053c9e83e5c65fae1e8b45d877599925..77d3a735d062bf38e11ae0fed20ef3a2a99f4a18 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.66 2007/05/24 18:54:10 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.67 2007/07/06 13:36:55 wieck Exp $
  *
  * pgbench: a simple benchmark program for PostgreSQL
  * written by Tatsuo Ishii
@@ -114,6 +114,8 @@ typedef struct
    int         ecnt;           /* error count */
    int         listen;         /* 0 indicates that an async query has been
                                 * sent */
+   int         sleeping;       /* 1 indicates that the client is napping */
+   struct timeval until;       /* napping until */
    Variable   *variables;      /* array of variable definitions */
    int         nvariables;
    struct timeval txn_begin;   /* used for measuring latencies */
@@ -445,6 +447,20 @@ doCustom(CState * state, int n, int debug)
 top:
    commands = sql_files[st->use_file];
 
+   if (st->sleeping)
+   {                           /* are we sleeping? */
+       int             usec;
+       struct timeval  now;
+
+       gettimeofday(&now, NULL);
+       usec = (st->until.tv_sec - now.tv_sec) * 1000000 +
+               st->until.tv_usec - now.tv_usec;
+       if (usec <= 0)
+           st->sleeping = 0;   /* Done sleeping, go ahead with next command */
+       else
+           return;             /* Still sleeping, nothing to do here */
+   }
+
    if (st->listen)
    {                           /* are we receiver? */
        if (commands[st->state]->type == SQL_COMMAND)
@@ -711,6 +727,32 @@ top:
 
            st->listen = 1;
        }
+       else if (pg_strcasecmp(argv[0], "usleep") == 0)
+       {
+           char       *var;
+           int         usec;
+           struct timeval now;
+
+           if (*argv[1] == ':')
+           {
+               if ((var = getVariable(st, argv[1] + 1)) == NULL)
+               {
+                   fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[1]);
+                   st->ecnt++;
+                   return;
+               }
+               usec = atoi(var);
+           }
+           else
+               usec = atoi(argv[1]);
+
+           gettimeofday(&now, NULL);
+           st->until.tv_sec = now.tv_sec + (now.tv_usec + usec) / 1000000;
+           st->until.tv_usec = (now.tv_usec + usec) % 1000000;
+           st->sleeping = 1;
+
+           st->listen = 1;
+       }
 
        goto top;
    }
@@ -921,9 +963,21 @@ process_commands(char *buf)
                fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
                        my_commands->argv[0], my_commands->argv[j]);
        }
+       else if (pg_strcasecmp(my_commands->argv[0], "usleep") == 0)
+       {
+           if (my_commands->argc < 2)
+           {
+               fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]);
+               return NULL;
+           }
+
+           for (j = 2; j < my_commands->argc; j++)
+               fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
+                       my_commands->argv[0], my_commands->argv[j]);
+       }
        else
        {
-           fprintf(stderr, "invalid command %s\n", my_commands->argv[0]);
+           fprintf(stderr, "Invalid command %s\n", my_commands->argv[0]);
            return NULL;
        }
    }
@@ -1143,6 +1197,9 @@ main(int argc, char **argv)
    fd_set      input_mask;
    int         nsocks;         /* return from select(2) */
    int         maxsock;        /* max socket number to be waited */
+   struct timeval now;
+   struct timeval timeout;
+   int         min_usec;
 
 #ifdef HAVE_GETRLIMIT
    struct rlimit rlim;
@@ -1526,11 +1583,33 @@ main(int argc, char **argv)
        FD_ZERO(&input_mask);
 
        maxsock = -1;
+       min_usec = -1;
        for (i = 0; i < nclients; i++)
        {
            Command   **commands = sql_files[state[i].use_file];
 
-           if (state[i].con && commands[state[i].state]->type != META_COMMAND)
+           if (state[i].sleeping)
+           {
+               int     this_usec;
+               int     sock = PQsocket(state[i].con);
+
+               if (min_usec < 0)
+               {
+                   gettimeofday(&now, NULL);
+                   min_usec = 0;
+               }
+
+               this_usec = (state[i].until.tv_sec - now.tv_sec) * 1000000 +
+                           state[i].until.tv_usec - now.tv_usec;
+
+               if (this_usec > 0 && (min_usec == 0 || this_usec < min_usec))
+                   min_usec = this_usec;
+
+               FD_SET(sock, &input_mask);
+               if (maxsock < sock)
+                   maxsock = sock;
+           }
+           else if (state[i].con && commands[state[i].state]->type != META_COMMAND)
            {
                int         sock = PQsocket(state[i].con);
 
@@ -1547,8 +1626,18 @@ main(int argc, char **argv)
 
        if (maxsock != -1)
        {
-           if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
-                             (fd_set *) NULL, (struct timeval *) NULL)) < 0)
+           if (min_usec >= 0)
+           {
+               timeout.tv_sec = min_usec / 1000000;
+               timeout.tv_usec = min_usec % 1000000;
+
+               nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
+                             (fd_set *) NULL, &timeout);
+           }
+           else
+               nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
+                             (fd_set *) NULL, (struct timeval *) NULL);
+           if (nsocks < 0)
            {
                if (errno == EINTR)
                    continue;
@@ -1557,6 +1646,7 @@ main(int argc, char **argv)
                fprintf(stderr, "select failed: %s\n", strerror(errno));
                exit(1);
            }
+#ifdef NOT_USED
            else if (nsocks == 0)
            {                   /* timeout */
                fprintf(stderr, "select timeout\n");
@@ -1567,6 +1657,7 @@ main(int argc, char **argv)
                }
                exit(0);
            }
+#endif
        }
 
        /* ok, backend returns reply */