]> granicus.if.org Git - postgresql/blob - contrib/pgbench/pgbench.c
Fix a bunch of 'old-style parameter declaration' warnings induced by
[postgresql] / contrib / pgbench / pgbench.c
1 /*
2  * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.34 2004/10/25 02:15:01 tgl Exp $
3  *
4  * pgbench: a simple TPC-B like benchmark program for PostgreSQL
5  * written by Tatsuo Ishii
6  *
7  * Copyright (c) 2000-2004      Tatsuo Ishii
8  *
9  * Permission to use, copy, modify, and distribute this software and
10  * its documentation for any purpose and without fee is hereby
11  * granted, provided that the above copyright notice appear in all
12  * copies and that both that copyright notice and this permission
13  * notice appear in supporting documentation, and that the name of the
14  * author not be used in advertising or publicity pertaining to
15  * distribution of the software without specific, written prior
16  * permission. The author makes no representations about the
17  * suitability of this software for any purpose.  It is provided "as
18  * is" without express or implied warranty.
19  */
20 #include "postgres_fe.h"
21
22 #include "libpq-fe.h"
23
24 #include <errno.h>
25
26 #ifdef WIN32
27 #include "win32.h"
28 #else
29 #include <sys/time.h>
30 #include <unistd.h>
31
32 #ifdef HAVE_GETOPT_H
33 #include <getopt.h>
34 #endif
35
36 #ifdef HAVE_SYS_SELECT_H
37 #include <sys/select.h>
38 #endif
39
40 /* for getrlimit */
41 #include <sys/resource.h>
42 #endif   /* ! WIN32 */
43
44 extern char *optarg;
45 extern int      optind;
46
47 #ifdef WIN32
48 #undef select
49 #endif
50
51
52 /********************************************************************
53  * some configurable parameters */
54
55 #define MAXCLIENTS 1024                 /* max number of clients allowed */
56
57 int                     nclients = 1;           /* default number of simulated clients */
58 int                     nxacts = 10;            /* default number of transactions per
59                                                                  * clients */
60
61 /*
62  * scaling factor. for example, tps = 10 will make 1000000 tuples of
63  * accounts table.
64  */
65 int                     tps = 1;
66
67 /*
68  * end of configurable parameters
69  *********************************************************************/
70
71 #define nbranches       1
72 #define ntellers        10
73 #define naccounts       100000
74
75 FILE       *LOGFILE = NULL;
76
77 bool            use_log;                        /* log transaction latencies to a file */
78
79 int                     remains;                        /* number of remaining clients */
80
81 int                     is_connect;                     /* establish connection  for each
82                                                                  * transaction */
83
84 char       *pghost = "";
85 char       *pgport = NULL;
86 char       *pgoptions = NULL;
87 char       *pgtty = NULL;
88 char       *login = NULL;
89 char       *pwd = NULL;
90 char       *dbName;
91
92 typedef struct
93 {
94         PGconn     *con;                        /* connection handle to DB */
95         int                     id;                             /* client No. */
96         int                     state;                  /* state No. */
97         int                     cnt;                    /* xacts count */
98         int                     ecnt;                   /* error count */
99         int                     listen;                 /* 0 indicates that an async query has
100                                                                  * been sent */
101         int                     aid;                    /* account id for this transaction */
102         int                     bid;                    /* branch id for this transaction */
103         int                     tid;                    /* teller id for this transaction */
104         int                     delta;
105         int                     abalance;
106         struct timeval txn_begin;       /* used for measuring latencies */
107 }       CState;
108
109 static void
110 usage(void)
111 {
112         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");
113         fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
114 }
115
116 /* random number generator */
117 static int
118 getrand(int min, int max)
119 {
120         return (min + (int) (max * 1.0 * rand() / (RAND_MAX + 1.0)));
121 }
122
123 /* set up a connection to the backend */
124 static PGconn *
125 doConnect(void)
126 {
127         PGconn     *con;
128         PGresult   *res;
129
130         con = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName,
131                                            login, pwd);
132         if (con == NULL)
133         {
134                 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
135                 fprintf(stderr, "Memory allocatin problem?\n");
136                 return (NULL);
137         }
138
139         if (PQstatus(con) == CONNECTION_BAD)
140         {
141                 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
142
143                 if (PQerrorMessage(con))
144                         fprintf(stderr, "%s", PQerrorMessage(con));
145                 else
146                         fprintf(stderr, "No explanation from the backend\n");
147
148                 return (NULL);
149         }
150
151         res = PQexec(con, "SET search_path = public");
152         if (PQresultStatus(res) != PGRES_COMMAND_OK)
153         {
154                 fprintf(stderr, "%s", PQerrorMessage(con));
155                 exit(1);
156         }
157         PQclear(res);
158
159         return (con);
160 }
161
162 /* throw away response from backend */
163 static void
164 discard_response(CState * state)
165 {
166         PGresult   *res;
167
168         do
169         {
170                 res = PQgetResult(state->con);
171                 if (res)
172                         PQclear(res);
173         } while (res);
174 }
175
176 /* check to see if the SQL result was good */
177 static int
178 check(CState * state, PGresult *res, int n, int good)
179 {
180         CState     *st = &state[n];
181
182         if (res && PQresultStatus(res) != good)
183         {
184                 fprintf(stderr, "Client %d aborted in state %d: %s", n, st->state, PQerrorMessage(st->con));
185                 remains--;                              /* I've aborted */
186                 PQfinish(st->con);
187                 st->con = NULL;
188                 return (-1);
189         }
190         return (0);                                     /* OK */
191 }
192
193 /* process a transaction */
194 static void
195 doOne(CState * state, int n, int debug, int ttype)
196 {
197         char            sql[256];
198         PGresult   *res;
199         CState     *st = &state[n];
200
201         if (st->listen)
202         {                                                       /* are we receiver? */
203                 if (debug)
204                         fprintf(stderr, "client %d receiving\n", n);
205                 if (!PQconsumeInput(st->con))
206                 {                                               /* there's something wrong */
207                         fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
208                         remains--;                      /* I've aborted */
209                         PQfinish(st->con);
210                         st->con = NULL;
211                         return;
212                 }
213                 if (PQisBusy(st->con))
214                         return;                         /* don't have the whole result yet */
215
216                 switch (st->state)
217                 {
218                         case 0:                         /* response to "begin" */
219                                 res = PQgetResult(st->con);
220                                 if (check(state, res, n, PGRES_COMMAND_OK))
221                                         return;
222                                 PQclear(res);
223                                 discard_response(st);
224                                 break;
225                         case 1:                         /* response to "update accounts..." */
226                                 res = PQgetResult(st->con);
227                                 if (check(state, res, n, PGRES_COMMAND_OK))
228                                         return;
229                                 PQclear(res);
230                                 discard_response(st);
231                                 break;
232                         case 2:                         /* response to "select abalance ..." */
233                                 res = PQgetResult(st->con);
234                                 if (check(state, res, n, PGRES_TUPLES_OK))
235                                         return;
236                                 PQclear(res);
237                                 discard_response(st);
238                                 break;
239                         case 3:                         /* response to "update tellers ..." */
240                                 res = PQgetResult(st->con);
241                                 if (check(state, res, n, PGRES_COMMAND_OK))
242                                         return;
243                                 PQclear(res);
244                                 discard_response(st);
245                                 break;
246                         case 4:                         /* response to "update branches ..." */
247                                 res = PQgetResult(st->con);
248                                 if (check(state, res, n, PGRES_COMMAND_OK))
249                                         return;
250                                 PQclear(res);
251                                 discard_response(st);
252                                 break;
253                         case 5:                         /* response to "insert into history ..." */
254                                 res = PQgetResult(st->con);
255                                 if (check(state, res, n, PGRES_COMMAND_OK))
256                                         return;
257                                 PQclear(res);
258                                 discard_response(st);
259                                 break;
260                         case 6:                         /* response to "end" */
261
262                                 /*
263                                  * transaction finished: record the time it took in the
264                                  * log
265                                  */
266                                 if (use_log)
267                                 {
268                                         double          diff;
269                                         struct timeval now;
270
271                                         gettimeofday(&now, 0);
272                                         diff = (int) (now.tv_sec - st->txn_begin.tv_sec) * 1000000.0 +
273                                                 (int) (now.tv_usec - st->txn_begin.tv_usec);
274
275                                         fprintf(LOGFILE, "%d %d %.0f\n", st->id, st->cnt, diff);
276                                 }
277
278                                 res = PQgetResult(st->con);
279                                 if (check(state, res, n, PGRES_COMMAND_OK))
280                                         return;
281                                 PQclear(res);
282                                 discard_response(st);
283
284                                 if (is_connect)
285                                 {
286                                         PQfinish(st->con);
287                                         st->con = NULL;
288                                 }
289
290                                 if (++st->cnt >= nxacts)
291                                 {
292                                         remains--;      /* I'm done */
293                                         if (st->con != NULL)
294                                         {
295                                                 PQfinish(st->con);
296                                                 st->con = NULL;
297                                         }
298                                         return;
299                                 }
300                                 break;
301                 }
302
303                 /* increment state counter */
304                 st->state++;
305                 if (st->state > 6)
306                         st->state = 0;
307         }
308
309         if (st->con == NULL)
310         {
311                 if ((st->con = doConnect()) == NULL)
312                 {
313                         fprintf(stderr, "Client %d aborted in establishing connection.\n",
314                                         n);
315                         remains--;                      /* I've aborted */
316                         PQfinish(st->con);
317                         st->con = NULL;
318                         return;
319                 }
320         }
321
322         switch (st->state)
323         {
324                 case 0:                 /* about to start */
325                         strcpy(sql, "begin");
326                         st->aid = getrand(1, naccounts * tps);
327                         st->bid = getrand(1, nbranches * tps);
328                         st->tid = getrand(1, ntellers * tps);
329                         st->delta = getrand(1, 1000);
330                         if (use_log)
331                                 gettimeofday(&(st->txn_begin), 0);
332                         break;
333                 case 1:
334                         snprintf(sql, 256, "update accounts set abalance = abalance + %d where aid = %d\n", st->delta, st->aid);
335                         break;
336                 case 2:
337                         snprintf(sql, 256, "select abalance from accounts where aid = %d", st->aid);
338                         break;
339                 case 3:
340                         if (ttype == 0)
341                         {
342                                 snprintf(sql, 256, "update tellers set tbalance = tbalance + %d where tid = %d\n",
343                                                  st->delta, st->tid);
344                                 break;
345                         }
346                 case 4:
347                         if (ttype == 0)
348                         {
349                                 snprintf(sql, 256, "update branches set bbalance = bbalance + %d where bid = %d", st->delta, st->bid);
350                                 break;
351                         }
352                 case 5:
353                         snprintf(sql, 256, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
354                                          st->tid, st->bid, st->aid, st->delta);
355                         break;
356                 case 6:
357                         strcpy(sql, "end");
358                         break;
359         }
360
361         if (debug)
362                 fprintf(stderr, "client %d sending %s\n", n, sql);
363         if (PQsendQuery(st->con, sql) == 0)
364         {
365                 if (debug)
366                         fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
367                 st->ecnt++;
368         }
369         else
370         {
371                 st->listen++;                   /* flags that should be listened */
372         }
373 }
374
375 /* process a select only transaction */
376 static void
377 doSelectOnly(CState * state, int n, int debug)
378 {
379         char            sql[256];
380         PGresult   *res;
381         CState     *st = &state[n];
382
383         if (st->listen)
384         {                                                       /* are we receiver? */
385                 if (debug)
386                         fprintf(stderr, "client %d receiving\n", n);
387                 if (!PQconsumeInput(st->con))
388                 {                                               /* there's something wrong */
389                         fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
390                         remains--;                      /* I've aborted */
391                         PQfinish(st->con);
392                         st->con = NULL;
393                         return;
394                 }
395                 if (PQisBusy(st->con))
396                         return;                         /* don't have the whole result yet */
397
398                 switch (st->state)
399                 {
400                         case 0:                         /* response to "select abalance ..." */
401                                 res = PQgetResult(st->con);
402                                 if (check(state, res, n, PGRES_TUPLES_OK))
403                                         return;
404                                 PQclear(res);
405                                 discard_response(st);
406
407                                 if (is_connect)
408                                 {
409                                         PQfinish(st->con);
410                                         st->con = NULL;
411                                 }
412
413                                 if (++st->cnt >= nxacts)
414                                 {
415                                         remains--;      /* I've done */
416                                         if (st->con != NULL)
417                                         {
418                                                 PQfinish(st->con);
419                                                 st->con = NULL;
420                                         }
421                                         return;
422                                 }
423                                 break;
424                 }
425
426                 /* increment state counter */
427                 st->state++;
428                 if (st->state > 0)
429                         st->state = 0;
430         }
431
432         if (st->con == NULL)
433         {
434                 if ((st->con = doConnect()) == NULL)
435                 {
436                         fprintf(stderr, "Client %d aborted in establishing connection.\n",
437                                         n);
438                         remains--;                      /* I've aborted */
439                         PQfinish(st->con);
440                         st->con = NULL;
441                         return;
442                 }
443         }
444
445         switch (st->state)
446         {
447                 case 0:
448                         st->aid = getrand(1, naccounts * tps);
449                         snprintf(sql, 256, "select abalance from accounts where aid = %d", st->aid);
450                         break;
451         }
452
453         if (debug)
454                 fprintf(stderr, "client %d sending %s\n", n, sql);
455
456         if (PQsendQuery(st->con, sql) == 0)
457         {
458                 if (debug)
459                         fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
460                 st->ecnt++;
461         }
462         else
463         {
464                 st->listen++;                   /* flags that should be listened */
465         }
466 }
467
468 /* discard connections */
469 static void
470 disconnect_all(CState * state)
471 {
472         int                     i;
473
474         for (i = 0; i < nclients; i++)
475         {
476                 if (state[i].con)
477                         PQfinish(state[i].con);
478         }
479 }
480
481 /* create tables and setup data */
482 static void
483 init(void)
484 {
485         PGconn     *con;
486         PGresult   *res;
487         static char *DDLs[] = {
488                 "drop table branches",
489                 "create table branches(bid int not null,bbalance int,filler char(88))",
490                 "drop table tellers",
491                 "create table tellers(tid int not null,bid int,tbalance int,filler char(84))",
492                 "drop table accounts",
493                 "create table accounts(aid int not null,bid int,abalance int,filler char(84))",
494                 "drop table history",
495         "create table history(tid int,bid int,aid int,delta int,mtime timestamp,filler char(22))"};
496         static char *DDLAFTERs[] = {
497                 "alter table branches add primary key (bid)",
498                 "alter table tellers add primary key (tid)",
499         "alter table accounts add primary key (aid)"};
500
501
502         char            sql[256];
503
504         int                     i;
505
506         if ((con = doConnect()) == NULL)
507                 exit(1);
508
509         for (i = 0; i < (sizeof(DDLs) / sizeof(char *)); i++)
510         {
511                 res = PQexec(con, DDLs[i]);
512                 if (strncmp(DDLs[i], "drop", 4) && PQresultStatus(res) != PGRES_COMMAND_OK)
513                 {
514                         fprintf(stderr, "%s", PQerrorMessage(con));
515                         exit(1);
516                 }
517                 PQclear(res);
518         }
519
520         res = PQexec(con, "begin");
521         if (PQresultStatus(res) != PGRES_COMMAND_OK)
522         {
523                 fprintf(stderr, "%s", PQerrorMessage(con));
524                 exit(1);
525         }
526         PQclear(res);
527
528         for (i = 0; i < nbranches * tps; i++)
529         {
530                 snprintf(sql, 256, "insert into branches(bid,bbalance) values(%d,0)", i + 1);
531                 res = PQexec(con, sql);
532                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
533                 {
534                         fprintf(stderr, "%s", PQerrorMessage(con));
535                         exit(1);
536                 }
537                 PQclear(res);
538         }
539
540         for (i = 0; i < ntellers * tps; i++)
541         {
542                 snprintf(sql, 256, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)"
543                                  ,i + 1, i / ntellers + 1);
544                 res = PQexec(con, sql);
545                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
546                 {
547                         fprintf(stderr, "%s", PQerrorMessage(con));
548                         exit(1);
549                 }
550                 PQclear(res);
551         }
552
553         res = PQexec(con, "end");
554         if (PQresultStatus(res) != PGRES_COMMAND_OK)
555         {
556                 fprintf(stderr, "%s", PQerrorMessage(con));
557                 exit(1);
558         }
559         PQclear(res);
560
561         /*
562          * occupy accounts table with some data
563          */
564         fprintf(stderr, "creating tables...\n");
565         for (i = 0; i < naccounts * tps; i++)
566         {
567                 int                     j = i + 1;
568
569                 if (j % 10000 == 1)
570                 {
571                         res = PQexec(con, "copy accounts from stdin");
572                         if (PQresultStatus(res) != PGRES_COPY_IN)
573                         {
574                                 fprintf(stderr, "%s", PQerrorMessage(con));
575                                 exit(1);
576                         }
577                         PQclear(res);
578                 }
579
580                 snprintf(sql, 256, "%d\t%d\t%d\t\n", j, i / naccounts + 1, 0);
581                 if (PQputline(con, sql))
582                 {
583                         fprintf(stderr, "PQputline failed\n");
584                         exit(1);
585                 }
586
587                 if (j % 10000 == 0)
588                 {
589                         /*
590                          * every 10000 tuples, we commit the copy command. this should
591                          * avoid generating too much WAL logs
592                          */
593                         fprintf(stderr, "%d tuples done.\n", j);
594                         if (PQputline(con, "\\.\n"))
595                         {
596                                 fprintf(stderr, "very last PQputline failed\n");
597                                 exit(1);
598                         }
599
600                         if (PQendcopy(con))
601                         {
602                                 fprintf(stderr, "PQendcopy failed\n");
603                                 exit(1);
604                         }
605
606 #ifdef NOT_USED
607
608                         /*
609                          * do a checkpoint to purge the old WAL logs
610                          */
611                         res = PQexec(con, "checkpoint");
612                         if (PQresultStatus(res) != PGRES_COMMAND_OK)
613                         {
614                                 fprintf(stderr, "%s", PQerrorMessage(con));
615                                 exit(1);
616                         }
617                         PQclear(res);
618 #endif   /* NOT_USED */
619                 }
620         }
621         fprintf(stderr, "set primary key...\n");
622         for (i = 0; i < (sizeof(DDLAFTERs) / sizeof(char *)); i++)
623         {
624                 res = PQexec(con, DDLAFTERs[i]);
625                 if (strncmp(DDLs[i], "drop", 4) && PQresultStatus(res) != PGRES_COMMAND_OK)
626                 {
627                         fprintf(stderr, "%s", PQerrorMessage(con));
628                         exit(1);
629                 }
630                 PQclear(res);
631         }
632
633         /* vacuum */
634         fprintf(stderr, "vacuum...");
635         res = PQexec(con, "vacuum analyze");
636         if (PQresultStatus(res) != PGRES_COMMAND_OK)
637         {
638                 fprintf(stderr, "%s", PQerrorMessage(con));
639                 exit(1);
640         }
641         PQclear(res);
642         fprintf(stderr, "done.\n");
643
644         PQfinish(con);
645 }
646
647 /* print out results */
648 static void
649 printResults(
650                          int ttype, CState * state,
651                          struct timeval * tv1, struct timeval * tv2,
652                          struct timeval * tv3)
653 {
654         double          t1,
655                                 t2;
656         int                     i;
657         int                     normal_xacts = 0;
658         char       *s;
659
660         for (i = 0; i < nclients; i++)
661                 normal_xacts += state[i].cnt;
662
663         t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
664         t1 = normal_xacts * 1000000.0 / t1;
665
666         t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
667         t2 = normal_xacts * 1000000.0 / t2;
668
669         if (ttype == 0)
670                 s = "TPC-B (sort of)";
671         else if (ttype == 2)
672                 s = "Update only accounts";
673         else
674                 s = "SELECT only";
675
676         printf("transaction type: %s\n", s);
677         printf("scaling factor: %d\n", tps);
678         printf("number of clients: %d\n", nclients);
679         printf("number of transactions per client: %d\n", nxacts);
680         printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients);
681         printf("tps = %f (including connections establishing)\n", t1);
682         printf("tps = %f (excluding connections establishing)\n", t2);
683 }
684
685
686 int
687 main(int argc, char **argv)
688 {
689         int                     c;
690         int                     is_init_mode = 0;               /* initialize mode? */
691         int                     is_no_vacuum = 0;               /* no vacuum at all before
692                                                                                  * testing? */
693         int                     is_full_vacuum = 0;             /* do full vacuum before testing? */
694         int                     debug = 0;              /* debug flag */
695         int                     ttype = 0;              /* transaction type. 0: TPC-B, 1: SELECT
696                                                                  * only, 2: skip update of branches and
697                                                                  * tellers */
698
699         static CState *state;           /* status of clients */
700
701         struct timeval tv1;                     /* start up time */
702         struct timeval tv2;                     /* after establishing all connections to
703                                                                  * the backend */
704         struct timeval tv3;                     /* end time */
705
706         int                     i;
707
708         fd_set          input_mask;
709         int                     nsocks;                 /* return from select(2) */
710         int                     maxsock;                /* max socket number to be waited */
711
712 #if !(defined(__CYGWIN__) || defined(__MINGW32__))
713         struct rlimit rlim;
714 #endif
715
716         PGconn     *con;
717         PGresult   *res;
718         char       *env;
719
720         if ((env = getenv("PGHOST")) != NULL && *env != '\0')
721                 pghost = env;
722         if ((env = getenv("PGPORT")) != NULL && *env != '\0')
723                 pgport = env;
724         else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
725                 login = env;
726
727         while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSl")) != -1)
728         {
729                 switch (c)
730                 {
731                         case 'i':
732                                 is_init_mode++;
733                                 break;
734                         case 'h':
735                                 pghost = optarg;
736                                 break;
737                         case 'n':
738                                 is_no_vacuum++;
739                                 break;
740                         case 'v':
741                                 is_full_vacuum++;
742                                 break;
743                         case 'p':
744                                 pgport = optarg;
745                                 break;
746                         case 'd':
747                                 debug++;
748                                 break;
749                         case 'S':
750                                 ttype = 1;
751                                 break;
752                         case 'N':
753                                 ttype = 2;
754                                 break;
755                         case 'c':
756                                 nclients = atoi(optarg);
757                                 if (nclients <= 0 || nclients > MAXCLIENTS)
758                                 {
759                                         fprintf(stderr, "invalid number of clients: %d\n", nclients);
760                                         exit(1);
761                                 }
762 #if !(defined(__CYGWIN__) || defined(__MINGW32__))
763 #ifdef RLIMIT_NOFILE                    /* most platform uses RLIMIT_NOFILE */
764                                 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
765                                 {
766 #else                                                   /* but BSD doesn't ... */
767                                 if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
768                                 {
769 #endif   /* HAVE_RLIMIT_NOFILE */
770                                         fprintf(stderr, "getrlimit failed. reason: %s\n", strerror(errno));
771                                         exit(1);
772                                 }
773                                 if (rlim.rlim_cur <= (nclients + 2))
774                                 {
775                                         fprintf(stderr, "You need at least %d open files resource but you are only allowed to use %ld.\n", nclients + 2, (long) rlim.rlim_cur);
776                                         fprintf(stderr, "Use limit/ulimt to increase the limit before using pgbench.\n");
777                                         exit(1);
778                                 }
779 #endif   /* #if !(defined(__CYGWIN__) || defined(__MINGW32__)) */
780                                 break;
781                         case 'C':
782                                 is_connect = 1;
783                                 break;
784                         case 's':
785                                 tps = atoi(optarg);
786                                 if (tps <= 0)
787                                 {
788                                         fprintf(stderr, "invalid scaling factor: %d\n", tps);
789                                         exit(1);
790                                 }
791                                 break;
792                         case 't':
793                                 nxacts = atoi(optarg);
794                                 if (nxacts <= 0)
795                                 {
796                                         fprintf(stderr, "invalid number of transactions: %d\n", nxacts);
797                                         exit(1);
798                                 }
799                                 break;
800                         case 'U':
801                                 login = optarg;
802                                 break;
803                         case 'P':
804                                 pwd = optarg;
805                                 break;
806                         case 'l':
807                                 use_log = true;
808                                 break;
809                         default:
810                                 usage();
811                                 exit(1);
812                                 break;
813                 }
814         }
815
816         if (argc > optind)
817                 dbName = argv[optind];
818         else
819         {
820                 if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
821                         dbName = env;
822                 else if (login != NULL && *login != '\0')
823                         dbName = login;
824                 else
825                         dbName = "";
826         }
827
828         if (is_init_mode)
829         {
830                 init();
831                 exit(0);
832         }
833
834         remains = nclients;
835
836         state = (CState *) malloc(sizeof(*state) * nclients);
837         memset(state, 0, sizeof(*state) * nclients);
838
839         if (use_log)
840         {
841                 char            logpath[64];
842
843                 snprintf(logpath, 64, "pgbench_log.%d", getpid());
844                 LOGFILE = fopen(logpath, "w");
845
846                 if (LOGFILE == NULL)
847                 {
848                         fprintf(stderr, "Couldn't open logfile \"%s\": %s", logpath, strerror(errno));
849                         exit(1);
850                 }
851         }
852
853         if (debug)
854         {
855                 printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
856                            pghost, pgport, nclients, nxacts, dbName);
857         }
858
859         /* opening connection... */
860         con = doConnect();
861         if (con == NULL)
862                 exit(1);
863
864         if (PQstatus(con) == CONNECTION_BAD)
865         {
866                 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
867                 fprintf(stderr, "%s", PQerrorMessage(con));
868                 exit(1);
869         }
870
871         /*
872          * get the scaling factor that should be same as count(*) from
873          * branches...
874          */
875         res = PQexec(con, "select count(*) from branches");
876         if (PQresultStatus(res) != PGRES_TUPLES_OK)
877         {
878                 fprintf(stderr, "%s", PQerrorMessage(con));
879                 exit(1);
880         }
881         tps = atoi(PQgetvalue(res, 0, 0));
882         if (tps < 0)
883         {
884                 fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);
885                 exit(1);
886         }
887         PQclear(res);
888
889         if (!is_no_vacuum)
890         {
891                 fprintf(stderr, "starting vacuum...");
892                 res = PQexec(con, "vacuum branches");
893                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
894                 {
895                         fprintf(stderr, "%s", PQerrorMessage(con));
896                         exit(1);
897                 }
898                 PQclear(res);
899
900                 res = PQexec(con, "vacuum tellers");
901                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
902                 {
903                         fprintf(stderr, "%s", PQerrorMessage(con));
904                         exit(1);
905                 }
906                 PQclear(res);
907
908                 res = PQexec(con, "delete from history");
909                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
910                 {
911                         fprintf(stderr, "%s", PQerrorMessage(con));
912                         exit(1);
913                 }
914                 PQclear(res);
915                 res = PQexec(con, "vacuum history");
916                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
917                 {
918                         fprintf(stderr, "%s", PQerrorMessage(con));
919                         exit(1);
920                 }
921                 PQclear(res);
922
923                 fprintf(stderr, "end.\n");
924
925                 if (is_full_vacuum)
926                 {
927                         fprintf(stderr, "starting full vacuum...");
928                         res = PQexec(con, "vacuum analyze accounts");
929                         if (PQresultStatus(res) != PGRES_COMMAND_OK)
930                         {
931                                 fprintf(stderr, "%s", PQerrorMessage(con));
932                                 exit(1);
933                         }
934                         PQclear(res);
935                         fprintf(stderr, "end.\n");
936                 }
937         }
938         PQfinish(con);
939
940         /* set random seed */
941         gettimeofday(&tv1, 0);
942         srand((unsigned int) tv1.tv_usec);
943
944         /* get start up time */
945         gettimeofday(&tv1, 0);
946
947         if (is_connect == 0)
948         {
949                 /* make connections to the database */
950                 for (i = 0; i < nclients; i++)
951                 {
952                         state[i].id = i;
953                         if ((state[i].con = doConnect()) == NULL)
954                                 exit(1);
955                 }
956         }
957
958         /* time after connections set up */
959         gettimeofday(&tv2, 0);
960
961         /* send start up queries in async manner */
962         for (i = 0; i < nclients; i++)
963         {
964                 if (ttype == 0 || ttype == 2)
965                         doOne(state, i, debug, ttype);
966                 else if (ttype == 1)
967                         doSelectOnly(state, i, debug);
968         }
969
970         for (;;)
971         {
972                 if (remains <= 0)
973                 {                                               /* all done ? */
974                         disconnect_all(state);
975                         /* get end time */
976                         gettimeofday(&tv3, 0);
977                         printResults(ttype, state, &tv1, &tv2, &tv3);
978                         if (LOGFILE)
979                                 fclose(LOGFILE);
980                         exit(0);
981                 }
982
983                 FD_ZERO(&input_mask);
984
985                 maxsock = 0;
986                 for (i = 0; i < nclients; i++)
987                 {
988                         if (state[i].con)
989                         {
990                                 int                     sock = PQsocket(state[i].con);
991
992                                 if (sock < 0)
993                                 {
994                                         fprintf(stderr, "Client %d: PQsocket failed\n", i);
995                                         disconnect_all(state);
996                                         exit(1);
997                                 }
998                                 FD_SET(sock, &input_mask);
999                                 if (maxsock < sock)
1000                                         maxsock = sock;
1001                         }
1002                 }
1003
1004                 if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
1005                                                   (fd_set *) NULL, (struct timeval *) NULL)) < 0)
1006                 {
1007                         if (errno == EINTR)
1008                                 continue;
1009                         /* must be something wrong */
1010                         disconnect_all(state);
1011                         fprintf(stderr, "select failed: %s\n", strerror(errno));
1012                         exit(1);
1013                 }
1014                 else if (nsocks == 0)
1015                 {                                               /* timeout */
1016                         fprintf(stderr, "select timeout\n");
1017                         for (i = 0; i < nclients; i++)
1018                         {
1019                                 fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
1020                                                 i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
1021                         }
1022                         exit(0);
1023                 }
1024
1025                 /* ok, backend returns reply */
1026                 for (i = 0; i < nclients; i++)
1027                 {
1028                         if (state[i].con && FD_ISSET(PQsocket(state[i].con), &input_mask))
1029                         {
1030                                 if (ttype == 0 || ttype == 2)
1031                                         doOne(state, i, debug, ttype);
1032                                 else if (ttype == 1)
1033                                         doSelectOnly(state, i, debug);
1034                         }
1035                 }
1036         }
1037 }