Use read streams in CREATE DATABASE when STRATEGY=WAL_LOG.
authorNoah Misch <[email protected]>
Sat, 20 Jul 2024 11:22:12 +0000 (04:22 -0700)
committerNoah Misch <[email protected]>
Sat, 20 Jul 2024 11:22:12 +0000 (04:22 -0700)
While this doesn't significantly change runtime now, it arranges for
STRATEGY=WAL_LOG to benefit automatically from future optimizations to
the read_stream subsystem.  For large tables in the template database,
this does read 16x as many bytes per system call.  Platforms with high
per-call overhead, if any, may see an immediate benefit.

Nazir Bilal Yavuz

Discussion: https://postgr.es/m/CAN55FZ0JKL6vk1xQp6rfOXiNFV1u1H0tJDPPGHWoiO3ea2Wc=A@mail.gmail.com

src/backend/storage/buffer/bufmgr.c

index bdb36e5a30ec4bc3bc3f6da2043528d77c6f36b1..a6aeecdf534e0348b2c7be2d422e7c3443bcbb25 100644 (file)
@@ -54,6 +54,7 @@
 #include "storage/ipc.h"
 #include "storage/lmgr.h"
 #include "storage/proc.h"
+#include "storage/read_stream.h"
 #include "storage/smgr.h"
 #include "storage/standby.h"
 #include "utils/memdebug.h"
@@ -135,6 +136,33 @@ typedef struct SMgrSortArray
    SMgrRelation srel;
 } SMgrSortArray;
 
+/*
+ * Helper struct for read stream object used in
+ * RelationCopyStorageUsingBuffer() function.
+ */
+struct copy_storage_using_buffer_read_stream_private
+{
+   BlockNumber blocknum;
+   BlockNumber last_block;
+};
+
+/*
+ * Callback function to get next block for read stream object used in
+ * RelationCopyStorageUsingBuffer() function.
+ */
+static BlockNumber
+copy_storage_using_buffer_read_stream_next_block(ReadStream *stream,
+                                                void *callback_private_data,
+                                                void *per_buffer_data)
+{
+   struct copy_storage_using_buffer_read_stream_private *p = callback_private_data;
+
+   if (p->blocknum < p->last_block)
+       return p->blocknum++;
+
+   return InvalidBlockNumber;
+}
+
 /* GUC variables */
 bool       zero_damaged_pages = false;
 int            bgwriter_lru_maxpages = 100;
@@ -4685,6 +4713,9 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
    PGIOAlignedBlock buf;
    BufferAccessStrategy bstrategy_src;
    BufferAccessStrategy bstrategy_dst;
+   struct copy_storage_using_buffer_read_stream_private p;
+   ReadStream *src_stream;
+   SMgrRelation src_smgr;
 
    /*
     * In general, we want to write WAL whenever wal_level > 'minimal', but we
@@ -4713,19 +4744,31 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
    bstrategy_src = GetAccessStrategy(BAS_BULKREAD);
    bstrategy_dst = GetAccessStrategy(BAS_BULKWRITE);
 
+   /* Initalize streaming read */
+   p.blocknum = 0;
+   p.last_block = nblocks;
+   src_smgr = smgropen(srclocator, INVALID_PROC_NUMBER);
+   src_stream = read_stream_begin_smgr_relation(READ_STREAM_FULL,
+                                                bstrategy_src,
+                                                src_smgr,
+                                                permanent ? RELPERSISTENCE_PERMANENT : RELPERSISTENCE_UNLOGGED,
+                                                forkNum,
+                                                copy_storage_using_buffer_read_stream_next_block,
+                                                &p,
+                                                0);
+
    /* Iterate over each block of the source relation file. */
    for (blkno = 0; blkno < nblocks; blkno++)
    {
        CHECK_FOR_INTERRUPTS();
 
        /* Read block from source relation. */
-       srcBuf = ReadBufferWithoutRelcache(srclocator, forkNum, blkno,
-                                          RBM_NORMAL, bstrategy_src,
-                                          permanent);
+       srcBuf = read_stream_next_buffer(src_stream, NULL);
        LockBuffer(srcBuf, BUFFER_LOCK_SHARE);
        srcPage = BufferGetPage(srcBuf);
 
-       dstBuf = ReadBufferWithoutRelcache(dstlocator, forkNum, blkno,
+       dstBuf = ReadBufferWithoutRelcache(dstlocator, forkNum,
+                                          BufferGetBlockNumber(srcBuf),
                                           RBM_ZERO_AND_LOCK, bstrategy_dst,
                                           permanent);
        dstPage = BufferGetPage(dstBuf);
@@ -4745,6 +4788,8 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
        UnlockReleaseBuffer(dstBuf);
        UnlockReleaseBuffer(srcBuf);
    }
+   Assert(read_stream_next_buffer(src_stream, NULL) == InvalidBuffer);
+   read_stream_end(src_stream);
 
    FreeAccessStrategy(bstrategy_src);
    FreeAccessStrategy(bstrategy_dst);