From 754b74e8f71e4e7e6b0fb7ca96e3e45a50faa695 Mon Sep 17 00:00:00 2001
From: Alexander Stephan <alexander.stephan@sap.com>
Date: Tue, 30 Dec 2025 10:56:45 +0000
Subject: [PATCH 3/4] BUG/MINOR: mworker/cli: fix show proc pagination using
 reload counter

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.
---
 src/mworker.c | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/src/mworker.c b/src/mworker.c
index 3d6ce3a26..83c438c35 100644
--- a/src/mworker.c
+++ b/src/mworker.c
@@ -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;
 }
 
-- 
2.43.7

