1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Record initial state of data checksums in controlfile

The controlfile records the current state of data checksums, which
also used to be the initial state from initdb when checksums could
not be altered after initialization.  pg_control_init is documented
to return information about cluster initialization state, which it
no longer will if data checksums have been changed either using the
offline tool or with online processing.

Fix by adding a new field in the control file which tracks the init
value of data checksums, and is left read only after initialization.

While this is a regression dating back to when changing checksum
state was made possible offline with pg_checksums, it is a control
file change so it cannot be backpatched.

Backpatch to v19 where online checksums were introduced.

Author: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Discussion: https://postgr.es/m/B87ABFBE-A304-4839-8706-C80D73E6BF5C@yesql.se
Backpatch-through: 19
This commit is contained in:
Daniel Gustafsson
2026-08-18 22:25:42 +02:00
parent cba80d5e74
commit 514fb08f51
6 changed files with 49 additions and 13 deletions

View File

@@ -4283,6 +4283,7 @@ InitControlFile(uint64 sysidentifier, uint32 data_checksum_version)
ControlFile->wal_log_hints = wal_log_hints;
ControlFile->track_commit_timestamp = track_commit_timestamp;
ControlFile->data_checksum_version = data_checksum_version;
ControlFile->data_checksum_version_init = data_checksum_version;
/*
* Set the data_checksum_version value into XLogCtl, which is where all

View File

@@ -254,7 +254,7 @@ pg_control_init(PG_FUNCTION_ARGS)
values[9] = BoolGetDatum(ControlFile->float8ByVal);
nulls[9] = false;
values[10] = Int32GetDatum(ControlFile->data_checksum_version);
values[10] = Int32GetDatum(ControlFile->data_checksum_version_init);
nulls[10] = false;
values[11] = BoolGetDatum(ControlFile->default_char_signedness);

View File

@@ -22,7 +22,7 @@
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 1902
#define PG_CONTROL_VERSION 1903
/* Nonce key length, see below */
#define MOCK_AUTH_NONCE_LEN 32
@@ -228,7 +228,13 @@ typedef struct ControlFileData
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* Are data pages protected by checksums? Zero if no checksum version */
/*
* Data checksum state at cluster initialization. Since the state can be
* changed during runtime, we need to store the initial value for system
* functions which report initdb settings.
*/
uint32 data_checksum_version_init;
/* Current data checksums state */
uint32 data_checksum_version;
/*

View File

@@ -14,24 +14,33 @@ use lib $FindBin::RealBin;
use DataChecksums::Utils;
# Initialize node with checksums disabled.
# Initialize node with checksums enabled to test pg_control_init returning
# 1 for this cluster, the remaining tests will initialize to off to test the
# return value for a cluster initialized without checksums
my $node = PostgreSQL::Test::Cluster->new('basic_node');
$node->init(no_data_checksums => 1);
$node->init;
$node->start;
# Create some content to have un-checksummed data in the cluster
# Create some content to have data in the cluster
$node->safe_psql('postgres',
"CREATE TABLE t AS SELECT generate_series(1,10000) AS a;");
# Ensure that checksums are turned off
test_checksum_state($node, 'off');
# Ensure that checksums are turned on
test_checksum_state($node, 'on');
# Disable data checksums and wait for the state transition to 'off'
disable_data_checksums($node, wait => 'off');
# Make sure pg_control_init reports the initial enabled state
my $result = $node->safe_psql('postgres',
'SELECT data_page_checksum_version FROM pg_control_init();');
is($result, '1', 'ensure pg_control_init reports enabled state');
# Enable data checksums and wait for the state transition to 'on'
enable_data_checksums($node, wait => 'on');
# Run a dummy query just to make sure we can read back data
my $result =
$node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1 ");
$result = $node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1 ");
is($result, '9999', 'ensure checksummed pages can be read back');
# Enable data checksums again which should be a no-op so we explicitly don't

View File

@@ -30,6 +30,11 @@ $node->safe_psql('postgres',
# Ensure that checksums are disabled
test_checksum_state($node, 'off');
# Make sure pg_control_init reports the initial disabled state
$result = $node->safe_psql('postgres',
'SELECT data_page_checksum_version FROM pg_control_init();');
is($result, '0', 'ensure pg_control_init reports disabled state');
SKIP:
{
skip 'Data checksum delay tests not enabled in PG_TEST_EXTRA', 6
@@ -134,9 +139,14 @@ wait_for_checksum_state($node, "off");
$block_session->quit;
# Finish test suite by enabling checksums and make sure all data can be read
# back and no processes are left over
# back, no processes are left over and the initial state is still correctly
# reported
enable_data_checksums($node, wait => 'on');
$result = $node->safe_psql('postgres',
'SELECT data_page_checksum_version FROM pg_control_init();');
is($result, '0', 'ensure pg_control_init still reports disabled state');
$result = $node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1");
is($result, '9999', 'ensure checksummed pages can be read back');

View File

@@ -20,6 +20,11 @@ my $node = PostgreSQL::Test::Cluster->new('offline_node');
$node->init(no_data_checksums => 1);
$node->start;
# Make sure pg_control_init reports the initial state as disabled
my $result = $node->safe_psql('postgres',
'SELECT data_page_checksum_version FROM pg_control_init();');
is($result, '0', 'ensure pg_control_init reports disabled state');
# Create some content to have un-checksummed data in the cluster
$node->safe_psql('postgres',
"CREATE TABLE t AS SELECT generate_series(1,10000) AS a;");
@@ -35,9 +40,14 @@ $node->start;
# Ensure that checksums are enabled
test_checksum_state($node, 'on');
# Make sure pg_control_init still reports the initial state as disabled even
# though the current state has changed.
$result = $node->safe_psql('postgres',
'SELECT data_page_checksum_version FROM pg_control_init();');
is($result, '0', 'ensure pg_control_init still reports disabled state');
# Run a dummy query just to make sure we can read back some data
my $result =
$node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1");
$result = $node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1");
is($result, '9999', 'ensure checksummed pages can be read back');
# Disable checksums offline again using pg_checksums