Skip to content

Commit 15e22a2

Browse files
melanieplagemannbyavuz
authored and
Commitfest Bot
committed
Use streaming read I/O in autoprewarm
Make a read stream for each valid fork of each valid relation represented in the autoprewarm dump file and prewarm those blocks through the read stream API instead of by directly invoking ReadBuffer(). Co-authored-by: Nazir Bilal Yavuz <[email protected]> Co-authored-by: Melanie Plageman <[email protected]> Reviewed-by: Heikki Linnakangas <[email protected]> Reviewed-by: Daniel Gustafsson <[email protected]> Reviewed-by: Andrey M. Borodin <[email protected]> (earlier versions) Reviewed-by: Kirill Reshke <[email protected]> (earlier versions) Reviewed-by: Matheus Alcantara <[email protected]> (earlier versions) Discussion: https://postgr.es/m/flat/CAN55FZ3n8Gd%2BhajbL%3D5UkGzu_aHGRqnn%2BxktXq2fuds%3D1AOR6Q%40mail.gmail.com
1 parent 98d3496 commit 15e22a2

File tree

2 files changed

+103
-23
lines changed

2 files changed

+103
-23
lines changed

contrib/pg_prewarm/autoprewarm.c

+102-23
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "storage/latch.h"
4242
#include "storage/lwlock.h"
4343
#include "storage/procsignal.h"
44+
#include "storage/read_stream.h"
4445
#include "storage/smgr.h"
4546
#include "tcop/tcopprot.h"
4647
#include "utils/guc.h"
@@ -75,6 +76,28 @@ typedef struct AutoPrewarmSharedState
7576
int prewarmed_blocks;
7677
} AutoPrewarmSharedState;
7778

79+
/*
80+
* Private data passed through the read stream API for our use in the
81+
* callback.
82+
*/
83+
typedef struct AutoPrewarmReadStreamData
84+
{
85+
/* The array of records containing the blocks we should prewarm. */
86+
BlockInfoRecord *block_info;
87+
88+
/*
89+
* pos is the read stream callback's index into block_info. Because the
90+
* read stream may read ahead, pos is likely to be ahead of the index in
91+
* the main loop in autoprewarm_database_main().
92+
*/
93+
int pos;
94+
Oid tablespace;
95+
RelFileNumber filenumber;
96+
ForkNumber forknum;
97+
BlockNumber nblocks;
98+
} AutoPrewarmReadStreamData;
99+
100+
78101
PGDLLEXPORT void autoprewarm_main(Datum main_arg);
79102
PGDLLEXPORT void autoprewarm_database_main(Datum main_arg);
80103

@@ -422,6 +445,54 @@ apw_load_buffers(void)
422445
apw_state->prewarmed_blocks, num_elements)));
423446
}
424447

448+
/*
449+
* Return the next block number of a specific relation and fork to read
450+
* according to the array of BlockInfoRecord.
451+
*/
452+
static BlockNumber
453+
apw_read_stream_next_block(ReadStream *stream,
454+
void *callback_private_data,
455+
void *per_buffer_data)
456+
{
457+
AutoPrewarmReadStreamData *p = callback_private_data;
458+
459+
CHECK_FOR_INTERRUPTS();
460+
461+
while (p->pos < apw_state->prewarm_stop_idx)
462+
{
463+
BlockInfoRecord blk = p->block_info[p->pos];
464+
465+
if (!have_free_buffer())
466+
{
467+
p->pos = apw_state->prewarm_stop_idx;
468+
return InvalidBlockNumber;
469+
}
470+
471+
if (blk.tablespace != p->tablespace)
472+
return InvalidBlockNumber;
473+
474+
if (blk.filenumber != p->filenumber)
475+
return InvalidBlockNumber;
476+
477+
if (blk.forknum != p->forknum)
478+
return InvalidBlockNumber;
479+
480+
p->pos++;
481+
482+
/*
483+
* Check whether blocknum is valid and within fork file size.
484+
* Fast-forward through any invalid blocks. We want p->pos to reflect
485+
* the location of the next relation or fork before ending the stream.
486+
*/
487+
if (blk.blocknum >= p->nblocks)
488+
continue;
489+
490+
return blk.blocknum;
491+
}
492+
493+
return InvalidBlockNumber;
494+
}
495+
425496
/*
426497
* Prewarm all blocks for one database (and possibly also global objects, if
427498
* those got grouped with this database).
@@ -462,8 +533,6 @@ autoprewarm_database_main(Datum main_arg)
462533
Oid reloid;
463534
Relation rel;
464535

465-
CHECK_FOR_INTERRUPTS();
466-
467536
/*
468537
* All blocks between prewarm_start_idx and prewarm_stop_idx should
469538
* belong either to global objects or the same database.
@@ -510,6 +579,8 @@ autoprewarm_database_main(Datum main_arg)
510579
{
511580
ForkNumber forknum = blk.forknum;
512581
BlockNumber nblocks;
582+
struct AutoPrewarmReadStreamData p;
583+
ReadStream *stream;
513584
Buffer buf;
514585

515586
/*
@@ -540,32 +611,40 @@ autoprewarm_database_main(Datum main_arg)
540611

541612
nblocks = RelationGetNumberOfBlocksInFork(rel, blk.forknum);
542613

543-
/* Prewarm buffers. */
544-
while (i < apw_state->prewarm_stop_idx &&
545-
blk.tablespace == tablespace &&
546-
blk.filenumber == filenumber &&
547-
blk.forknum == forknum &&
548-
have_free_buffer())
614+
p = (struct AutoPrewarmReadStreamData)
549615
{
550-
CHECK_FOR_INTERRUPTS();
551-
552-
/* Check whether blocknum is valid and within fork file size. */
553-
if (blk.blocknum >= nblocks)
554-
{
555-
blk = block_info[++i];
556-
continue;
557-
}
558-
559-
buf = ReadBufferExtended(rel, blk.forknum, blk.blocknum, RBM_NORMAL,
560-
NULL);
561-
562-
blk = block_info[++i];
563-
if (!BufferIsValid(buf))
564-
break;
616+
.block_info = block_info,
617+
.pos = i,
618+
.tablespace = tablespace,
619+
.filenumber = filenumber,
620+
.forknum = forknum,
621+
.nblocks = nblocks,
622+
};
623+
624+
stream = read_stream_begin_relation(READ_STREAM_FULL,
625+
NULL,
626+
rel,
627+
p.forknum,
628+
apw_read_stream_next_block,
629+
&p,
630+
0);
565631

632+
/*
633+
* Loop until we've prewarmed all the blocks from this fork. The
634+
* read stream callback will check that we still have free buffers
635+
* before requesting each block from the read stream API.
636+
*/
637+
while ((buf = read_stream_next_buffer(stream, NULL)) != InvalidBuffer)
638+
{
566639
apw_state->prewarmed_blocks++;
567640
ReleaseBuffer(buf);
568641
}
642+
643+
read_stream_end(stream);
644+
645+
/* Advance i past all the blocks just prewarmed. */
646+
i = p.pos;
647+
blk = block_info[i];
569648
}
570649

571650
relation_close(rel, AccessShareLock);

src/tools/pgindent/typedefs.list

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ AttributeOpts
175175
AuthRequest
176176
AuthToken
177177
AutoPrewarmSharedState
178+
AutoPrewarmReadStreamData
178179
AutoVacOpts
179180
AutoVacuumShmemStruct
180181
AutoVacuumWorkItem

0 commit comments

Comments
 (0)