From: Willy Tarreau Date: Wed, 19 Jan 2022 16:11:36 +0000 (+0100) Subject: MEDIUM: cli: yield between each pipelined command X-Git-Tag: v2.6-dev1~123 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fa7b4f6691646dc6bdebdb0d11c9cdf0382aeccb;p=thirdparty%2Fhaproxy.git MEDIUM: cli: yield between each pipelined command 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. --- diff --git a/src/cli.c b/src/cli.c index 119ac53eb5..c5c9a0f79f 100644 --- 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; + } } }