]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: cli: yield between each pipelined command
authorWilly Tarreau <w@1wt.eu>
Wed, 19 Jan 2022 16:11:36 +0000 (17:11 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 19 Jan 2022 18:16:47 +0000 (19:16 +0100)
Pipelining commands on the CLI is sometimes needed for batched operations
such as map deletion etc, but it causes two problems:
  - some possibly long-running commands will be run in series without
    yielding, possibly causing extremely long latencies that will affect
    quality of service and even trigger the watchdog, as seen in github
    issue #1515.

  - short commands that end on a buffer size boundary, when not run in
    interactive mode, will often cause the socket to be closed when
    the last command is parsed, because the buffer is empty.

This patch proposes a small change to this: by yielding in the CLI applet
after processing a command when there are data left, we significantly
reduce the latency, since only one command is executed per call, and
we leave an opportunity for the I/O layers to refill the request buffer
with more commands, hence to execute all of them much more often.

With this change there's no more watchdog triggered on long series of
"del map" on large map files, and the operations are much less disturbed.
It would be desirable to backport this patch to stable versions after some
period of observation in recent versions.

src/cli.c

index 119ac53eb5c2e1867dfb0469ae815fac4c425dcb..c5c9a0f79f4faa9fedbd0ecb75cb296dda69c8a0 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -1077,6 +1077,17 @@ static void cli_io_handler(struct appctx *appctx)
                        appctx->st0 = CLI_ST_GETREQ;
                        /* reactivate the \n at the end of the response for the next command */
                        appctx->st1 &= ~APPCTX_CLI_ST1_NOLF;
+
+                       /* this forces us to yield between pipelined commands and
+                        * avoid extremely long latencies (e.g. "del map" etc). In
+                        * addition this increases the likelihood that the stream
+                        * refills the buffer with new bytes in non-interactive
+                        * mode, avoiding to close on apparently empty commands.
+                        */
+                       if (co_data(si_oc(si))) {
+                               appctx_wakeup(appctx);
+                               goto out;
+                       }
                }
        }