Fix busy-wait in pgbench, with --rate.
authorHeikki Linnakangas
Sun, 1 Oct 2017 06:29:27 +0000 (09:29 +0300)
committerHeikki Linnakangas
Sun, 1 Oct 2017 06:29:27 +0000 (09:29 +0300)
If --rate was used to throttle pgbench, it failed to sleep when it had
nothing to do, leading to a busy-wait with 100% CPU usage. This bug was
introduced in the refactoring in v10. Before that, sleep() was called with
a timeout, even when there were no file descriptors to wait for.

Reported by Jeff Janes, patch by Fabien COELHO. Backpatch to v10.

Discussion: https://www.postgresql.org/message-id/CAMkU%3D1x5hoX0pLLKPRnXCy0T8uHoDvXdq%2B7kAM9eoC9_z72ucw%40mail.gmail.com

src/bin/pgbench/pgbench.c

index f0394136902b162fc5eabf58dd18ef420faa86a0..5d8a01c72cf639878f59f07e1171da385ab1824b 100644 (file)
@@ -4578,20 +4578,30 @@ threadRun(void *arg)
         * or it's time to print a progress report.  Update input_mask to show
         * which client(s) received data.
         */
-       if (min_usec > 0 && maxsock != -1)
+       if (min_usec > 0)
        {
-           int         nsocks; /* return from select(2) */
+           int         nsocks = 0; /* return from select(2) if called */
 
            if (min_usec != PG_INT64_MAX)
            {
-               struct timeval timeout;
+               if (maxsock != -1)
+               {
+                   struct timeval timeout;
 
-               timeout.tv_sec = min_usec / 1000000;
-               timeout.tv_usec = min_usec % 1000000;
-               nsocks = select(maxsock + 1, &input_mask, NULL, NULL, &timeout);
+                   timeout.tv_sec = min_usec / 1000000;
+                   timeout.tv_usec = min_usec % 1000000;
+                   nsocks = select(maxsock + 1, &input_mask, NULL, NULL, &timeout);
+               }
+               else /* nothing active, simple sleep */
+               {
+                   pg_usleep(min_usec);
+               }
            }
-           else
+           else /* no explicit delay, select without timeout */
+           {
                nsocks = select(maxsock + 1, &input_mask, NULL, NULL, NULL);
+           }
+
            if (nsocks < 0)
            {
                if (errno == EINTR)
@@ -4604,7 +4614,7 @@ threadRun(void *arg)
                goto done;
            }
        }
-       else
+       else /* min_usec == 0, i.e. something needs to be executed */
        {
            /* If we didn't call select(), don't try to read any data */
            FD_ZERO(&input_mask);