[PATCH] Refactor remaining zero-fill relation extensions to use smgrzeroextend()

From: Peipei YIN <yinpeipei0426(at)gmail(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Subject: [PATCH] Refactor remaining zero-fill relation extensions to use smgrzeroextend()
Date: 2026-08-12 19:24:19
Message-ID: CADkZ2Ka8Ky4bEPJu_BA5zZT-6K_bf58uT_zXWMDz-iC4Tqu9cA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

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):

1. bufmgr.c: Replaces memset() + smgrextend() with a single
smgrzeroextend() call to bulk-extend the destination relation.
2. 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.
3. 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.

Reviewed by: Heikki Linnakangas

*The Broader Vision*
Beyond simple code cleanup, enforcing the responsibility separation of
smgrextend() and smgrzeroextend() opens up a clean way to address a
long-standing data validation challenge.
Today, PostgreSQL can generate all-zero pages during relation extension and
accept an all-zero page into the buffer cache as if it were valid. Because
the engine cannot distinguish whether an all-zero page was created
intentionally or corrupted by an external bug, corrupted pages can enter
the buffer cache undetected. For example, if a valid heap page is
overwritten with zeros, an index scan will not report an error and will
simply, silently return "tuple not found." Once that page is selected for
an insert or update, it gets re-initialized, cementing the silent data
corruption permanently into the WAL stream.
To close this gap, we want to completely eliminate all-zero pages from
regular relation extension so we can accurately detect when an all-zero
page is the result of a bug. While a Proof of Concept (POC) for this
broader change is still in progress, implementing this refactoring is an
important first step.

*Testing Performed*

- Regression Tests: Ran make check-world to ensure relation extension
and bootstrap/creation paths function exactly as expected.
- Compilation: Verified a clean build with no warnings on GCC and Clang.

Feedback and suggestions on both this patch and the upcoming vision are
highly welcome!

Best regards,
Peipei Yin

Attachment Content-Type Size
0001-Use-smgrzeroextend-for-zero-filled-relation-extensio.patch application/octet-stream 4.0 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Zsolt Parragi 2026-08-12 19:36:18 Re: Handle MAXSTRLEN consistently
Previous Message Tomas Vondra 2026-08-12 19:18:20 Re: hashjoins vs. Bloom filters (yet again)