MINOR: stream: add an "epoch" to figure which streams appeared when

The "show sess" CLI command currently lists all streams and needs to
stop at a given position to avoid dumping forever. Since 2.2 with
commit c6e7a1b8e ("MINOR: cli: make "show sess" stop at the last known
session"), a hack consists in unlinking the stream running the applet
and linking it again at the current end of the list, in order to serve
as a delimiter. But this forces the stream list to be global, which
affects scalability.

This patch introduces an epoch, which is a global 32-bit counter that
is incremented by the "show sess" command, and which is copied by newly
created streams. This way any stream can know whether any other one is
newer or older than itself.

For now it's only stored and not exploited.

(cherry picked from commit b981318c11ce8c1969b931b01d51be38dbbaa4a7)
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/src/stream.c b/src/stream.c
index 411849c..61cb5ec 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -63,6 +63,8 @@
 DECLARE_POOL(pool_head_stream, "stream", sizeof(struct stream));
 DECLARE_POOL(pool_head_uniqueid, "uniqueid", UNIQUEID_LEN);
 
+/* incremented by each "show sess" to fix a delimiter between streams */
+unsigned stream_epoch = 0;
 struct list streams = LIST_HEAD_INIT(streams);
 __decl_spinlock(streams_lock);
 
@@ -385,6 +387,7 @@
 	s->si[0].flags = SI_FL_NONE;
 	s->si[1].flags = SI_FL_ISBACK;
 
+	s->stream_epoch = _HA_ATOMIC_LOAD(&stream_epoch);
 	s->uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
 
 	/* OK, we're keeping the stream, so let's properly initialize the stream */
@@ -2849,9 +2852,9 @@
 		}
 
 		chunk_appendf(&trash,
-			     "  flags=0x%x, conn_retries=%d, srv_conn=%p, pend_pos=%p waiting=%d\n",
+			     "  flags=0x%x, conn_retries=%d, srv_conn=%p, pend_pos=%p waiting=%d epoch=%#x\n",
 			     strm->flags, strm->si[1].conn_retries, strm->srv_conn, strm->pend_pos,
-			     LIST_ADDED(&strm->buffer_wait.list));
+			     LIST_ADDED(&strm->buffer_wait.list), strm->stream_epoch);
 
 		chunk_appendf(&trash,
 			     "  frontend=%s (id=%u mode=%s), listener=%s (id=%u)",
@@ -3149,6 +3152,11 @@
 	appctx->ctx.sess.section = 0; /* start with stream status */
 	appctx->ctx.sess.pos = 0;
 
+	/* let's set our own stream's epoch to the current one and increment
+	 * it so that we know which streams were already there before us.
+	 */
+	si_strm(appctx->owner)->stream_epoch = _HA_ATOMIC_XADD(&stream_epoch, 1);
+
 	/* we need to put an end marker into the streams list. We're just moving
 	 * ourselves there, so that once we found ourselves we know we've reached
 	 * the end. Without this we can run forever if new streams arrive faster
@@ -3266,8 +3274,8 @@
 			}
 
 			chunk_appendf(&trash,
-				     " ts=%02x age=%s calls=%u rate=%u cpu=%llu lat=%llu",
-				     curr_strm->task->state,
+				     " ts=%02x epoch=%#x age=%s calls=%u rate=%u cpu=%llu lat=%llu",
+			             curr_strm->task->state, curr_strm->stream_epoch,
 				     human_time(now.tv_sec - curr_strm->logs.tv_accept.tv_sec, 1),
 			             curr_strm->task->calls, read_freq_ctr(&curr_strm->call_rate),
 			             (unsigned long long)curr_strm->task->cpu_time, (unsigned long long)curr_strm->task->lat_time);