]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: mworker/cli: fix show proc pagination using reload counter
authorAlexander Stephan <alexander.stephan@sap.com>
Tue, 30 Dec 2025 10:56:45 +0000 (10:56 +0000)
committerWilliam Lallemand <wlallemand@haproxy.com>
Mon, 5 Jan 2026 07:59:34 +0000 (08:59 +0100)
After commit 594408cd612b5 ("BUG/MINOR: mworker/cli: 'show proc' is limited
by buffer size"), related to ticket #3204, the "show proc" logic
has been fixed to be able to print more than 202 processes. However, this
fix can lead to the omission of entries in case they have the same
timestamp.

To fix this, we use the unique reload counter instead of the timestamp.
On partial flush, set ctx->next_reload = child->reloads.
On resume skip entries with child->reloads >= ctx->next_reload.
Finally, we clear ctx->next_reload at the end of a complete dump so
subsequent show proc starts from the top.

Could be backported in all stable branches.

src/mworker.c

index 3d6ce3a26e6e011a3c98029bfa07b6e05a47f17b..83c438c350ce8c4ab2c3ad902e5f9b7b744a5771 100644 (file)
@@ -807,7 +807,7 @@ void mworker_cleanup_proc()
 
 struct cli_showproc_ctx {
        int debug;
-       int next_uptime; /* uptime must be greater than this value */
+       int next_reload; /* reload number to resume from, 0 = from the beginning  */
 };
 
 /*  Displays workers and processes  */
@@ -825,7 +825,7 @@ static int cli_io_handler_show_proc(struct appctx *appctx)
 
        chunk_reset(&trash);
 
-       if (ctx->next_uptime == 0) {
+       if (ctx->next_reload == 0) {
                memprintf(&reloadtxt, "%d [failed: %d]", proc_self->reloads, proc_self->failedreloads);
                chunk_printf(&trash, "#%-14s %-15s %-15s %-15s %-15s", "<PID>", "<type>", "<reloads>", "<uptime>", "<version>");
                if (ctx->debug)
@@ -843,12 +843,12 @@ static int cli_io_handler_show_proc(struct appctx *appctx)
        ha_free(&uptime);
 
        /* displays current processes */
-       if (ctx->next_uptime == 0)
+       if (ctx->next_reload == 0)
                chunk_appendf(&trash, "# workers\n");
        list_for_each_entry(child, &proc_list, list) {
 
                /* don't display current worker if we only need the next ones */
-               if (ctx->next_uptime != 0)
+               if (ctx->next_reload != 0)
                        continue;
 
                up = date.tv_sec - child->timestamp;
@@ -874,15 +874,16 @@ static int cli_io_handler_show_proc(struct appctx *appctx)
                return 0;
 
        /* displays old processes */
-       if (old || ctx->next_uptime) { /* there's more */
-               if (ctx->next_uptime == 0)
+       if (old || ctx->next_reload) { /* there's more */
+               if (ctx->next_reload == 0)
                        chunk_appendf(&trash, "# old workers\n");
                list_for_each_entry(child, &proc_list, list) {
                        up = date.tv_sec - child->timestamp;
                        if (up <= 0) /* must never be negative because of clock drift */
                                up = 0;
 
-                       if (child->timestamp < ctx->next_uptime)
+                       /* If we're resuming, skip entries that were already printed (reload >= ctx->next_reload) */
+                       if (ctx->next_reload && child->reloads >= ctx->next_reload)
                                continue;
 
                        if (!(child->options & PROC_O_TYPE_WORKER))
@@ -895,17 +896,21 @@ static int cli_io_handler_show_proc(struct appctx *appctx)
                                        chunk_appendf(&trash, "\t\t %-15d %-15d", child->ipc_fd[0], child->ipc_fd[1]);
                                chunk_appendf(&trash, "\n");
                                ha_free(&uptime);
-                       }
 
-                       /* start from there if there's not enough place */
-                       ctx->next_uptime = child->timestamp;
+                               /* Try to flush so we can resume after this reload on next page if the buffer is full. */
+                               if (applet_putchk(appctx, &trash) == -1) {
+                                       /* resume at this reload (exclude it on next pass) */
+                                       ctx->next_reload = child->reloads; /* resume after entries >= this reload */
+                                       return 0;
+                               }
+                               chunk_reset(&trash);
+                       }
 
-                       if (applet_putchk(appctx, &trash) == -1)
-                               return 0;
                }
        }
 
-       /* dump complete */
+       /* dump complete: reset resume cursor so next 'show proc' starts from the top */
+       ctx->next_reload = 0;
        return 1;
 }