From 43d39d350a0e3bb3681fda1391f50b516e6777cf Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Sun, 11 Oct 2026 09:25:36 -0400 Subject: [PATCH v1 2/2] Test incremental backup after a visibility map truncation Add a truncation case to 012_vm_consistency.pl. The test cluster now runs without data checksums and wal_log_hints, since either of them hides the problem. --- .../pg_combinebackup/t/012_vm_consistency.pl | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/bin/pg_combinebackup/t/012_vm_consistency.pl b/src/bin/pg_combinebackup/t/012_vm_consistency.pl index 6bf47ebec37..737efee40de 100644 --- a/src/bin/pg_combinebackup/t/012_vm_consistency.pl +++ b/src/bin/pg_combinebackup/t/012_vm_consistency.pl @@ -3,7 +3,8 @@ # Test that heap operations clearing visibility map bits (INSERT, UPDATE, # DELETE, SELECT FOR UPDATE, COPY) correctly register visibility map buffers, # since incremental backups rely on the WAL summarizer, which only tracks -# registered buffers. +# registered buffers. Also test that the WAL summarizer tracks the VM page +# whose tail bits are cleared by a heap truncation. use strict; use warnings FATAL => 'all'; @@ -14,12 +15,15 @@ use Test::More; my $tempdir = PostgreSQL::Test::Utils::tempdir_short(); my $mode = $ENV{PG_TEST_PG_COMBINEBACKUP_MODE} || '--copy'; -# Set up primary with WAL summarization enabled. +# Set up primary with WAL summarization enabled. Data checksums and +# wal_log_hints are off because with either of them truncation logs an image +# of the VM page it modifies, which would hide what the TRUNCATE test checks. my $primary = PostgreSQL::Test::Cluster->new('primary'); -$primary->init(allows_streaming => 1); +$primary->init(allows_streaming => 1, extra => ['--no-data-checksums']); $primary->append_conf('postgresql.conf', <start; @@ -93,6 +97,25 @@ my @tests = ( visible_op => '<', frozen_op => '<', }, + { + label => 'TRUNCATE', + table => 'vm_truncate_test', + # vacuum_truncate = off keeps the empty tail around until the + # explicit VACUUM (TRUNCATE), so that the truncation is the only + # change to the VM between the two backups. + setup => q{CREATE TABLE vm_truncate_test (id int) + WITH (vacuum_truncate = off); + INSERT INTO vm_truncate_test SELECT generate_series(1, 2000); + DELETE FROM vm_truncate_test WHERE id > 1000;}, + modify => q{VACUUM (TRUNCATE) vm_truncate_test}, + # Extend the restored table again with rows nobody can see. Stale VM + # bits for the truncated blocks would cover these new pages. + post_restore => q{BEGIN; + INSERT INTO vm_truncate_test SELECT generate_series(1, 1000); + ROLLBACK;}, + visible_op => '<', + frozen_op => '<', + }, ); sub get_vm_summary @@ -162,6 +185,9 @@ sub validate_restored_vm is($restored_frozen, $primary_frozen, "$test->{label} test: restored all_frozen count matches primary"); + $restored->safe_psql('postgres', $test->{post_restore}) + if defined $test->{post_restore}; + my $corrupt_tids = $restored->safe_psql('postgres', "SELECT count(*) FROM pg_check_visible('$test->{table}')"); is($corrupt_tids, '0', -- 2.37.1 (Apple Git-137.1)