From a1daeb110aad9d1c2582101cdcfd9eecfc8e51e9 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Sun, 23 Jul 2023 09:28:42 +1200 Subject: [PATCH v5 04/10] Use streaming reads in pg_prewarm. Instead of calling ReadBuffer() repeatedly, use streaming reads. This provides a simple example of such a transformation, and generates fewer system calls. Reviewed-by: Discussion: https://postgr.es/m/CA+hUKGJkOiOCa+mag4BF+zHo7qo=o9CFheB8=g6uT5TUm2gkvA@mail.gmail.com --- contrib/pg_prewarm/pg_prewarm.c | 40 ++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/contrib/pg_prewarm/pg_prewarm.c b/contrib/pg_prewarm/pg_prewarm.c index 8541e4d6e4..9617bf130b 100644 --- a/contrib/pg_prewarm/pg_prewarm.c +++ b/contrib/pg_prewarm/pg_prewarm.c @@ -20,6 +20,7 @@ #include "miscadmin.h" #include "storage/bufmgr.h" #include "storage/smgr.h" +#include "storage/streaming_read.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" @@ -38,6 +39,25 @@ typedef enum static PGIOAlignedBlock blockbuffer; +struct pg_prewarm_streaming_read_private +{ + BlockNumber blocknum; + int64 last_block; +}; + +static BlockNumber +pg_prewarm_streaming_read_next(PgStreamingRead *pgsr, + void *pgsr_private, + void *per_buffer_data) +{ + struct pg_prewarm_streaming_read_private *p = pgsr_private; + + if (p->blocknum <= p->last_block) + return p->blocknum++; + + return InvalidBlockNumber; +} + /* * pg_prewarm(regclass, mode text, fork text, * first_block int8, last_block int8) @@ -183,18 +203,36 @@ pg_prewarm(PG_FUNCTION_ARGS) } else if (ptype == PREWARM_BUFFER) { + struct pg_prewarm_streaming_read_private p; + PgStreamingRead *pgsr; + /* * In buffer mode, we actually pull the data into shared_buffers. */ + + /* Set up the private state for our streaming buffer read callback. */ + p.blocknum = first_block; + p.last_block = last_block; + + pgsr = pg_streaming_read_buffer_alloc(PGSR_FLAG_DEFAULT, + &p, + 0, + NULL, + BMR_REL(rel), + forkNumber, + pg_prewarm_streaming_read_next); + for (block = first_block; block <= last_block; ++block) { Buffer buf; CHECK_FOR_INTERRUPTS(); - buf = ReadBufferExtended(rel, forkNumber, block, RBM_NORMAL, NULL); + buf = pg_streaming_read_buffer_get_next(pgsr, NULL); ReleaseBuffer(buf); ++blocks_done; } + Assert(pg_streaming_read_buffer_get_next(pgsr, NULL) == InvalidBuffer); + pg_streaming_read_free(pgsr); } /* Close relation, release lock. */ -- 2.39.2