Hi, On Wed, Aug 12, 2026 at 6:31 PM Peipei YIN <[email protected]> wrote: > > Hi hackers, > > While reviewing relation extension paths, I noticed three places that still > manually perform zero-fill operations using smgrextend(), even though > smgrzeroextend() (and its underlying mdzeroextend()) exists specifically for > this purpose. > > The Problem > Currently, RelationCopyStorageUsingBuffer(), smgr_bulk_flush(), and segment > padding in _mdfd_getseg() manually construct or loop over zeroed buffers to > extend relations. This bypasses the dedicated zero-extension interfaces, > leading to inconsistent code patterns. It also misses out on > platform-specific optimizations like posix_fallocate() or FileZero() that > mdzeroextend() leverages instead of relying on sparse-file hole semantics. > > The Fix > The attached patch refactors these remaining instances to use > smgrzeroextend() (and mdzeroextend() directly in md.c): > > bufmgr.c: Replaces memset() + smgrextend() with a single smgrzeroextend() > call to bulk-extend the destination relation. > bulk_write.c: Eliminates the file-scope zero_buffer and the while loop, > substituting a single smgrzeroextend() call to fill non-sequential write gaps > efficiently. > md.c: Removes the aligned palloc_aligned zero-buffer allocation in > _mdfd_getseg(), replacing it with a direct call to mdzeroextend() to pad > short segments. > > This unifies all zero-fill relation extensions, improves code readability, > and ensures optimized zero-extension paths are used consistently across the > storage manager.
Thanks for sending the patch. I read through the code and commits (4d330a61bb, f94e9141a0b) around smgrextend and smgrzeroextend and did some experimentation. @@ -5405,9 +5404,8 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator, * Bulk extend the destination relation of the same size as the source * relation before starting to copy block by block. */ - memset(buf.data, 0, BLCKSZ); - smgrextend(smgropen(dstlocator, INVALID_PROC_NUMBER), forkNum, nblocks - 1, - buf.data, true); + smgrzeroextend(smgropen(dstlocator, INVALID_PROC_NUMBER), forkNum, 0, + nblocks, true); In the CREATE DATABASE path, smgrextend writes just one block with zeros (out of N relation blocks only the last one gets written zero), so this is already optimized today (which is why with posix_fallocate the patch shows no visible benefit here). However, with smgrzeroextend and file_extend_method=write_zeros (IOW, on platforms where posix_fallocate doesn't exist), this patch increases the disk writes (2x) and slows the query (2x). I did a quick benchmark of CREATE DATABASE with a source database of 7.3GB (pgbench scale 500) on an m5d.4xlarge Amazon EC2 instance with a gp3 (network-attached) data volume. Disk writes were captured from /proc/diskstats sectors-written for the data device. Config used was wal_level=minimal, fsync=on, checkpoint_timeout=24h, and small vm.dirty_bytes=64MB / vm.dirty_background_bytes=32MB so dirty pages are flushed mid-copy once they cross the threshold, rather than the zero pages being overwritten in cache first. I ran each configuration 3 times. The numbers below are the average (variance was under 1%). code exec time (s) disk writes (GB) HEAD 59.2 7.3 patched, posix_fallocate 59.2 7.3 patched, write_zeros 119.1 14.6 I didn't dive deep into the other paths bulk_write.c and md.c changed in this patch, so I'm not sure if they could also hit this problem. -- Bharath Rupireddy Amazon Web Services: https://aws.amazon.com
