From c50d0f17e223e9e85421bc2bc897291383cba74d Mon Sep 17 00:00:00 2001 From: Nazir Bilal Yavuz Date: Mon, 31 Mar 2025 12:21:27 +0300 Subject: [PATCH v7 2/2] Count free buffers at the start of the autoprewarm Streamified version of the autoprewarm code may do unnecessary I/O and buffer evicting. To prevent it at least a little bit, count the number of free buffers in the buffer pool and queue buffers up to that number in the callback function of the autoprewarm. --- contrib/pg_prewarm/autoprewarm.c | 7 +++++-- src/backend/storage/buffer/freelist.c | 17 +++++++++++++++++ src/include/storage/buf_internals.h | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index 68c99664de5..df10e02358d 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -518,6 +518,7 @@ void autoprewarm_database_main(Datum main_arg) { int pos; + int stop_idx; BlockInfoRecord *block_info; Relation rel = NULL; dsm_segment *seg; @@ -539,11 +540,13 @@ autoprewarm_database_main(Datum main_arg) BackgroundWorkerInitializeConnectionByOid(apw_state->database, InvalidOid, 0); block_info = (BlockInfoRecord *) dsm_segment_address(seg); pos = apw_state->prewarm_start_idx; + stop_idx = Min(apw_state->prewarm_stop_idx, + pos + get_number_of_free_buffers()); cur_database = block_info[pos].database; /* Loop until we run out of blocks to prewarm. */ - while (pos < apw_state->prewarm_stop_idx) + while (pos < stop_idx) { BlockInfoRecord *blk = &block_info[pos]; @@ -616,7 +619,7 @@ autoprewarm_database_main(Datum main_arg) nblocks_in_fork = RelationGetNumberOfBlocksInFork(rel, blk->forknum); nblocks_processed = autoprewarm_prewarm_relation(rel, pos, - apw_state->prewarm_stop_idx, + stop_idx, nblocks_in_fork, block_info); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 336715b6c63..9f26e940426 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -180,6 +180,23 @@ have_free_buffer(void) return false; } +/* + * get_number_of_free_buffers -- a lockless way to get the number of free + * buffers in buffer pool. + * + * Note that result continuously changes as free buffers are moved out by other + * operations. + */ +int +get_number_of_free_buffers(void) +{ + /* All the buffers are free. */ + if (StrategyControl->firstFreeBuffer < 0) + return NBuffers; + else + return StrategyControl->lastFreeBuffer - StrategyControl->firstFreeBuffer; +} + /* * StrategyGetBuffer * diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 9327f60c44c..197d2db49f5 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -445,6 +445,7 @@ extern void StrategyNotifyBgWriter(int bgwprocno); extern Size StrategyShmemSize(void); extern void StrategyInitialize(bool init); extern bool have_free_buffer(void); +extern int get_number_of_free_buffers(void); /* buf_table.c */ extern Size BufTableShmemSize(int size); -- 2.43.0