From 17f34ed4f364857efcb5b8506fc5291ba1fad387 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Sat, 10 Oct 2026 18:53:49 +0000 Subject: [PATCH v10 3/4] Use WALReadFromBuffers() for local WAL reads. Commit 91f2cae7a4 introduced WALReadFromBuffers() and the previous commits used it for physical and logical walsenders. This commit lets the callers of read_local_xlog_page(), such as logical decoding SQL functions, 2PC, concurrent repack workers and pg_walinspect, also read WAL from the WAL buffers instead of always going to a file. This reduces read IO and syscalls, especially when these callers keep 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. The 2PC WAL read happens in the checkpointer, so pg_stat_io now reports hits on object wal for it as well. Author: Bharath Rupireddy Reviewed-by: Michael Paquier Reviewed-by: Kirill Reshke Discussion: https://postgr.es/m/CALj2ACVfF2Uj9NoFy-5m98HNtjHpuD17EDE9twVeJng-jTAe7A%40mail.gmail.com --- src/backend/access/transam/xlogutils.c | 29 +++++++++++++++++++++++--- src/backend/utils/activity/pgstat_io.c | 5 +++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index ff71e14015d..e59d59c03fb 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -903,6 +903,7 @@ read_local_xlog_page_guts(XLogReaderState *state, XLogRecPtr targetPagePtr, int count; WALReadError errinfo; TimeLineID currTLI; + Size rbytes; loc = targetPagePtr + reqLen; @@ -1034,9 +1035,31 @@ read_local_xlog_page_guts(XLogReaderState *state, XLogRecPtr targetPagePtr, count = read_upto - targetPagePtr; } - if (!WALRead(state, cur_page, targetPagePtr, count, tli, - &errinfo)) - WALReadRaiseError(&errinfo); + /* attempt to read WAL from WAL buffers first */ + rbytes = WALReadFromBuffers(cur_page, targetPagePtr, count, tli); + + /* now read the remaining WAL from WAL file */ + if (rbytes < count) + { + if (!WALRead(state, + cur_page + rbytes, + targetPagePtr + rbytes, + count - rbytes, + 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); + } /* number of valid bytes in the buffer */ return count; diff --git a/src/backend/utils/activity/pgstat_io.c b/src/backend/utils/activity/pgstat_io.c index 3c8fcb20aba..7b63d805999 100644 --- a/src/backend/utils/activity/pgstat_io.c +++ b/src/backend/utils/activity/pgstat_io.c @@ -516,8 +516,9 @@ pgstat_tracks_io_op(BackendType bktype, IOObject io_object, return false; if (bktype == B_CHECKPOINTER && - ((io_object != IOOBJECT_WAL && io_op == IOOP_READ) || - (io_op == IOOP_EVICT || io_op == IOOP_HIT))) + ((io_object != IOOBJECT_WAL && + (io_op == IOOP_READ || io_op == IOOP_HIT)) || + io_op == IOOP_EVICT)) return false; if ((bktype == B_BG_WRITER || bktype == B_CHECKPOINTER) && -- 2.47.3