From 2dbc19b2e4871e636106be30a02e1753d22a0c2a Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Sat, 10 Oct 2026 19:10:50 +0000 Subject: [PATCH v10 4/4] Use WALReadFromBuffers() for WAL summarizer. Commit 91f2cae7a4 introduced WALReadFromBuffers() and the previous commits used it for physical and logical walsenders and for the local WAL readers. This commit lets the WAL summarizer also read WAL from the WAL buffers instead of always going to a file. This reduces read IO and syscalls, especially when the summarizer keeps up with WAL generation. It helps even more with WAL direct IO enabled, where a file read is always a physical disk read without the OS page cache. Author: Bharath Rupireddy Reviewed-by: Michael Paquier Reviewed-by: Kirill Reshke Discussion: https://postgr.es/m/CALj2ACVfF2Uj9NoFy-5m98HNtjHpuD17EDE9twVeJng-jTAe7A%40mail.gmail.com --- src/backend/postmaster/walsummarizer.c | 30 +++++++++++++++++++++++--- src/bin/pg_walsummary/t/002_blocks.pl | 5 +++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c index 8333a4eaaa3..00a48f4c952 100644 --- a/src/backend/postmaster/walsummarizer.c +++ b/src/backend/postmaster/walsummarizer.c @@ -1659,6 +1659,7 @@ summarizer_read_local_xlog_page(XLogReaderState *state, int count; WALReadError errinfo; SummarizerReadLocalXLogPrivate *private_data; + Size rbytes; ProcessWalSummarizerInterrupts(); @@ -1750,9 +1751,32 @@ summarizer_read_local_xlog_page(XLogReaderState *state, } } - if (!WALRead(state, cur_page, targetPagePtr, count, - private_data->tli, &errinfo)) - WALReadRaiseError(&errinfo); + /* attempt to read WAL from WAL buffers first */ + rbytes = WALReadFromBuffers(cur_page, targetPagePtr, count, + private_data->tli); + + /* now read the remaining WAL from WAL file */ + if (rbytes < count) + { + if (!WALRead(state, + cur_page + rbytes, + targetPagePtr + rbytes, + count - rbytes, + private_data->tli, + &errinfo)) + WALReadRaiseError(&errinfo); + } + else if (state->seg.ws_file >= 0 && + !XLByteInSeg(targetPagePtr, state->seg.ws_segno, + state->segcxt.ws_segsize)) + { + /* + * Close the segment when a read that comes entirely from the WAL + * buffers is not in the open segment, so that the next file read + * reopens the correct one. + */ + state->routine.segment_close(state); + } /* Track that we read a page, for sleep time calculation. */ ++pages_read_since_last_sleep; diff --git a/src/bin/pg_walsummary/t/002_blocks.pl b/src/bin/pg_walsummary/t/002_blocks.pl index c5a9649d6ad..ca0bf0002fc 100644 --- a/src/bin/pg_walsummary/t/002_blocks.pl +++ b/src/bin/pg_walsummary/t/002_blocks.pl @@ -58,10 +58,11 @@ command_like( command_like([ 'pg_walsummary', '-q', @summaries ], qr/\A\z/, "-q suppresses all output"); -# The WAL summarizer should have generated some IO statistics. +# The WAL summarizer should have generated some IO statistics (WAL reads from +# buffers and file). $node1->poll_query_until( 'postgres', - q{SELECT sum(reads) > 0 FROM pg_stat_io + q{SELECT sum(hits) + sum(reads) > 0 FROM pg_stat_io WHERE backend_type = 'walsummarizer' AND object = 'wal'}) or die "Timed out while waiting for WAL summarizer to generate statistics for WAL reads"; -- 2.47.3