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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user