v1-0001-Fix-lag-columns-in-pg_stat_replication-not-advanc.patch
application/octet-stream
Filename: v1-0001-Fix-lag-columns-in-pg_stat_replication-not-advanc.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v1-0001
Subject: Fix lag columns in pg_stat_replication not advancing when replay LSN stalls.
| File | + | − |
|---|---|---|
| src/backend/replication/walsender.c | 28 | 17 |
From 47995afe3af628c5f33eba2dbdbabd50f9f7a4d7 Mon Sep 17 00:00:00 2001
From: Fujii Masao <fujii@postgresql.org>
Date: Fri, 17 Oct 2025 12:52:18 +0900
Subject: [PATCH v1] Fix lag columns in pg_stat_replication not advancing when
replay LSN stalls.
---
src/backend/replication/walsender.c | 45 ++++++++++++++++++-----------
1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 59822f22b8d..d3ef136129f 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -233,6 +233,7 @@ typedef struct
int write_head;
int read_heads[NUM_SYNC_REP_WAIT_MODE];
WalTimeSample last_read[NUM_SYNC_REP_WAIT_MODE];
+ WalTimeSample overflowed[NUM_SYNC_REP_WAIT_MODE];
} LagTracker;
static LagTracker *lag_tracker;
@@ -4207,7 +4208,6 @@ WalSndKeepaliveIfNecessary(void)
static void
LagTrackerWrite(XLogRecPtr lsn, TimestampTz local_flush_time)
{
- bool buffer_full;
int new_write_head;
int i;
@@ -4229,25 +4229,19 @@ LagTrackerWrite(XLogRecPtr lsn, TimestampTz local_flush_time)
* of space.
*/
new_write_head = (lag_tracker->write_head + 1) % LAG_TRACKER_BUFFER_SIZE;
- buffer_full = false;
for (i = 0; i < NUM_SYNC_REP_WAIT_MODE; ++i)
{
+ /*
+ * If the buffer is full, move the slowest reader to a separate
+ * overflow entry and free its space in the buffer so the write head
+ * can advance.
+ */
if (new_write_head == lag_tracker->read_heads[i])
- buffer_full = true;
- }
-
- /*
- * If the buffer is full, for now we just rewind by one slot and overwrite
- * the last sample, as a simple (if somewhat uneven) way to lower the
- * sampling rate. There may be better adaptive compaction algorithms.
- */
- if (buffer_full)
- {
- new_write_head = lag_tracker->write_head;
- if (lag_tracker->write_head > 0)
- lag_tracker->write_head--;
- else
- lag_tracker->write_head = LAG_TRACKER_BUFFER_SIZE - 1;
+ {
+ lag_tracker->overflowed[i] =
+ lag_tracker->buffer[lag_tracker->read_heads[i]];
+ lag_tracker->read_heads[i] = -1;
+ }
}
/* Store a sample at the current write head position. */
@@ -4274,6 +4268,23 @@ LagTrackerRead(int head, XLogRecPtr lsn, TimestampTz now)
{
TimestampTz time = 0;
+ /*
+ * If 'lsn' has not passed the WAL position stored in the overflow entry,
+ * return the elapsed time (in microseconds) since the saved local flush
+ * time. Otherwise, resume using the buffer to control the read head and
+ * compute the elapsed time.
+ */
+ if (lag_tracker->read_heads[head] == -1)
+ {
+ if (lag_tracker->overflowed[head].lsn > lsn)
+ return now - lag_tracker->overflowed[head].time;
+
+ time = lag_tracker->overflowed[head].time;
+ lag_tracker->last_read[head] = lag_tracker->overflowed[head];
+ lag_tracker->read_heads[head] =
+ (lag_tracker->write_head + 1) % LAG_TRACKER_BUFFER_SIZE;
+ }
+
/* Read all unread samples up to this LSN or end of buffer. */
while (lag_tracker->read_heads[head] != lag_tracker->write_head &&
lag_tracker->buffer[lag_tracker->read_heads[head]].lsn <= lsn)
--
2.50.1