agora inbox for pgsql-committers@postgresql.org  
help / color / mirror / Atom feed
pgsql: Online enabling and disabling of data checksums
3+ messages / 2 participants
[nested] [flat]

* pgsql: Online enabling and disabling of data checksums
@ 2026-04-03 21:22  Daniel Gustafsson <dgustafsson@postgresql.org>
  0 siblings, 1 reply; 3+ messages in thread

From: Daniel Gustafsson @ 2026-04-03 21:22 UTC (permalink / raw)
  To: pgsql-committers@lists.postgresql.org

Online enabling and disabling of data checksums

This allows data checksums to be enabled, or disabled, in a running
cluster without restricting access to the cluster during processing.

Data checksums could prior to this only be enabled during initdb or
when the cluster is offline using the pg_checksums app. This commit
introduce functionality to enable, or disable, data checksums while
the cluster is running regardless of how it was initialized.

A background worker launcher process is responsible for launching a
dynamic per-database background worker which will mark all buffers
dirty for all relation with storage in order for them to have data
checksums calculated on write.  Once all relations in all databases
have been processed, the data_checksums state will be set to on and
the cluster will at that point be identical to one which had data
checksums enabled during initialization or via offline processing.

When data checksums are being enabled, concurrent I/O operations
from backends other than the data checksums worker will write the
checksums but not verify them on reading.  Only when all backends
have absorbed the procsignalbarrier for setting data_checksums to
on will they also start verifying checksums on reading.  The same
process is repeated during disabling; all backends write checksums
but do not verify them until the barrier for setting the state to
off has been absorbed by all.  This in-progress state is used to
ensure there are no false negatives (or positives) due to reading
a checksum which is not in sync with the page.

A new testmodule, test_checksums, is introduced with an extensive
set of tests covering both online and offline data checksum mode
changes.  The tests which run concurrent pgbdench during online
processing are gated behind the PG_TEST_EXTRA flag due to being
very expensive to run.  Two levels of PG_TEST_EXTRA flags exist
to turn on a subset of the expensive tests, or the full suite of
multiple runs.

This work is based on an earlier version of this patch which was
reviewed by among others Heikki Linnakangas, Robert Haas, Andres
Freund, Tomas Vondra, Michael Banck and Andrey Borodin.  During
the work on this new version, Tomas Vondra has given invaluable
assistance with not only coding and reviewing but very in-depth
testing.

Author: Daniel Gustafsson <daniel@yesql.se>
Author: Magnus Hagander <magnus@hagander.net>
Co-authored-by: Tomas Vondra <tomas@vondra.me>
Reviewed-by: Tomas Vondra <tomas@vondra.me>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/CABUevExz9hUUOLnJVr2kpw9Cx=o4MCr1SVKwbupzuxP7ckNutA@mail.gmail.com
Discussion: https://postgr.es/m/20181030051643.elbxjww5jjgnjaxg@alap3.anarazel.de
Discussion: https://postgr.es/m/CABUevEwE3urLtwxxqdgd5O2oQz9J717ZzMbh+ziCSa5YLLU_BA@mail.gmail.com

Branch
------
master

Details
-------
https://git.postgresql.org/pg/commitdiff/f19c0eccae9680f5785b11cdc58ef571998caec9

Modified Files
--------------
doc/src/sgml/config.sgml                           |    1 +
doc/src/sgml/func/func-admin.sgml                  |   78 +
doc/src/sgml/glossary.sgml                         |   24 +
doc/src/sgml/images/Makefile                       |    1 +
doc/src/sgml/images/datachecksums.gv               |   14 +
doc/src/sgml/images/datachecksums.svg              |   81 +
doc/src/sgml/monitoring.sgml                       |  228 ++-
doc/src/sgml/ref/pg_checksums.sgml                 |    6 +
doc/src/sgml/regress.sgml                          |   14 +
doc/src/sgml/wal.sgml                              |  126 +-
src/backend/access/rmgrdesc/xlogdesc.c             |   58 +-
src/backend/access/transam/xlog.c                  |  502 +++++-
src/backend/backup/basebackup.c                    |   31 +-
src/backend/bootstrap/bootstrap.c                  |    1 +
src/backend/catalog/system_views.sql               |   19 +
src/backend/commands/dbcommands.c                  |    7 +
src/backend/postmaster/Makefile                    |    1 +
src/backend/postmaster/auxprocess.c                |   19 +
src/backend/postmaster/bgworker.c                  |   10 +-
src/backend/postmaster/datachecksum_state.c        | 1612 ++++++++++++++++++++
src/backend/postmaster/meson.build                 |    1 +
src/backend/postmaster/postmaster.c                |    5 +
src/backend/replication/logical/decode.c           |   16 +
src/backend/storage/buffer/bufmgr.c                |    7 +
src/backend/storage/ipc/ipci.c                     |    3 +
src/backend/storage/ipc/procsignal.c               |    8 +
src/backend/storage/page/README                    |    4 +-
src/backend/storage/page/bufpage.c                 |   23 +-
src/backend/utils/activity/pgstat_backend.c        |    2 +
src/backend/utils/activity/pgstat_io.c             |    2 +
src/backend/utils/activity/wait_event_names.txt    |    3 +
src/backend/utils/adt/pgstatfuncs.c                |    8 +-
src/backend/utils/init/miscinit.c                  |    3 +-
src/backend/utils/init/postinit.c                  |   20 +-
src/backend/utils/misc/guc_parameters.dat          |    5 +-
src/backend/utils/misc/guc_tables.c                |    9 +-
src/backend/utils/misc/postgresql.conf.sample      |   10 +-
src/bin/pg_checksums/pg_checksums.c                |    4 +-
src/bin/pg_controldata/pg_controldata.c            |    2 +
src/bin/pg_upgrade/controldata.c                   |    9 +
src/bin/pg_waldump/t/001_basic.pl                  |    3 +-
src/include/access/rmgrlist.h                      |    1 +
src/include/access/xlog.h                          |   17 +-
src/include/access/xlog_internal.h                 |    8 +
src/include/catalog/catversion.h                   |    2 +-
src/include/catalog/pg_control.h                   |    8 +-
src/include/catalog/pg_proc.dat                    |   14 +
src/include/commands/progress.h                    |   16 +
src/include/miscadmin.h                            |    6 +
src/include/postmaster/datachecksum_state.h        |   58 +
src/include/postmaster/proctypelist.h              |    2 +
src/include/replication/decode.h                   |    1 +
src/include/storage/bufpage.h                      |    2 +-
src/include/storage/checksum.h                     |   16 +
src/include/storage/lwlocklist.h                   |    1 +
src/include/storage/procsignal.h                   |    4 +
src/include/utils/backend_progress.h               |    1 +
src/test/modules/Makefile                          |    1 +
src/test/modules/meson.build                       |    1 +
src/test/modules/test_checksums/.gitignore         |    2 +
src/test/modules/test_checksums/Makefile           |   40 +
src/test/modules/test_checksums/README             |   30 +
src/test/modules/test_checksums/meson.build        |   38 +
src/test/modules/test_checksums/t/001_basic.pl     |   63 +
src/test/modules/test_checksums/t/002_restarts.pl  |  110 ++
.../test_checksums/t/003_standby_restarts.pl       |  114 ++
src/test/modules/test_checksums/t/004_offline.pl   |   82 +
src/test/modules/test_checksums/t/005_injection.pl |   74 +
.../modules/test_checksums/t/006_pgbench_single.pl |  275 ++++
.../test_checksums/t/007_pgbench_standby.pl        |  400 +++++
src/test/modules/test_checksums/t/008_pitr.pl      |  189 +++
src/test/modules/test_checksums/t/009_fpi.pl       |   64 +
.../test_checksums/t/DataChecksums/Utils.pm        |  262 ++++
.../modules/test_checksums/test_checksums--1.0.sql |   24 +
src/test/modules/test_checksums/test_checksums.c   |  184 +++
.../modules/test_checksums/test_checksums.control  |    4 +
src/test/perl/PostgreSQL/Test/Cluster.pm           |   36 +
src/test/regress/expected/rules.out                |   35 +
src/test/regress/expected/stats.out                |   18 +-
src/tools/pgindent/typedefs.list                   |    7 +
80 files changed, 5132 insertions(+), 58 deletions(-)



^ permalink  raw  reply  [nested|flat] 3+ messages in thread

* Re: pgsql: Online enabling and disabling of data checksums
@ 2026-04-06 14:39  Aleksander Alekseev <aleksander@tigerdata.com>
  parent: Daniel Gustafsson <dgustafsson@postgresql.org>
  0 siblings, 1 reply; 3+ messages in thread

From: Aleksander Alekseev @ 2026-04-06 14:39 UTC (permalink / raw)
  To: pgsql-committers@lists.postgresql.org; +Cc: Daniel Gustafsson <dgustafsson@postgresql.org>

Hi Daniel,

> Online enabling and disabling of data checksums
>
> [...]

I noticed a little mistake:

```
/*
 * Await state transition to "on" in all backends. When done we know that
 * data data checksums are both written and verified in all backends.
 */
```

The word "data" is repeated twice.

Also there are inconsistencies in the way
XLogCtlData->data_checksum_version,
ControlFileData->data_checksum_version and certain variables are
assigned. Sometimes a hardcoded 0 is used and sometimes
PG_DATA_CHECKSUM_OFF. I suggest using values of the enum
ChecksumStateType for readability / consistency.

Here are corresponding patches.

--
Best regards,
Aleksander Alekseev

Attachments:

  [text/x-patch] v1-0002-Use-PG_DATA_CHECKSUM_OFF-instead-of-hardcoded-zer.patch (6.6K, ../../CAJ7c6TPRTnQFXXX1CRcYoTLXw2swtDH==uSz1MYoMKdLrKZHjA@mail.gmail.com/2-v1-0002-Use-PG_DATA_CHECKSUM_OFF-instead-of-hardcoded-zer.patch)
  download | inline diff:
From 14b1fb7baba5775e20dc7f50c8659250d1c667b2 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@tigerdata.com>
Date: Mon, 6 Apr 2026 17:11:28 +0300
Subject: [PATCH v1 2/2] Use PG_DATA_CHECKSUM_OFF instead of hardcoded zeroes

This is more readable and also more consistent with the rest of the code.

Author: Aleksander Alekseev <aleksander@tigerdata.com>
Discussion: https://postgr.es/m/E1w8lyI-002o2A-2f%40gemulon.postgresql.org
---
 src/backend/access/transam/xlog.c           |  8 ++++----
 src/backend/bootstrap/bootstrap.c           |  2 +-
 src/bin/pg_checksums/pg_checksums.c         |  4 ++--
 src/bin/pg_combinebackup/pg_combinebackup.c |  4 ++--
 src/bin/pg_upgrade/controldata.c            | 10 +++++-----
 src/bin/pg_upgrade/file.c                   |  2 +-
 6 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index fea479afaa9..260fc801ce2 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -4864,7 +4864,7 @@ SetDataChecksumsOff(void)
 	SpinLockAcquire(&XLogCtl->info_lck);
 
 	/* If data checksums are already disabled there is nothing to do */
-	if (XLogCtl->data_checksum_version == 0)
+	if (XLogCtl->data_checksum_version == PG_DATA_CHECKSUM_OFF)
 	{
 		SpinLockRelease(&XLogCtl->info_lck);
 		return;
@@ -4931,7 +4931,7 @@ SetDataChecksumsOff(void)
 	XLogChecksums(PG_DATA_CHECKSUM_OFF);
 
 	SpinLockAcquire(&XLogCtl->info_lck);
-	XLogCtl->data_checksum_version = 0;
+	XLogCtl->data_checksum_version = PG_DATA_CHECKSUM_OFF;
 	SpinLockRelease(&XLogCtl->info_lck);
 
 	barrier = EmitProcSignalBarrier(PROCSIGNAL_BARRIER_CHECKSUM_OFF);
@@ -6605,7 +6605,7 @@ StartupXLOG(void)
 		XLogChecksums(PG_DATA_CHECKSUM_OFF);
 
 		SpinLockAcquire(&XLogCtl->info_lck);
-		XLogCtl->data_checksum_version = 0;
+		XLogCtl->data_checksum_version = PG_DATA_CHECKSUM_OFF;
 		SetLocalDataChecksumState(XLogCtl->data_checksum_version);
 		SpinLockRelease(&XLogCtl->info_lck);
 
@@ -6625,7 +6625,7 @@ StartupXLOG(void)
 		XLogChecksums(PG_DATA_CHECKSUM_OFF);
 
 		SpinLockAcquire(&XLogCtl->info_lck);
-		XLogCtl->data_checksum_version = 0;
+		XLogCtl->data_checksum_version = PG_DATA_CHECKSUM_OFF;
 		SetLocalDataChecksumState(XLogCtl->data_checksum_version);
 		SpinLockRelease(&XLogCtl->info_lck);
 	}
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 63378ab3d8c..a4af7bf8fad 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -241,7 +241,7 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	pg_getopt_ctx optctx;
 	int			flag;
 	char	   *userDoption = NULL;
-	uint32		bootstrap_data_checksum_version = 0;	/* No checksum */
+	uint32		bootstrap_data_checksum_version = PG_DATA_CHECKSUM_OFF;
 	yyscan_t	scanner;
 
 	Assert(!IsUnderPostmaster);
diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index 2a38f1d688b..cfacd1300fc 100644
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -589,7 +589,7 @@ main(int argc, char *argv[])
 		mode == PG_MODE_CHECK)
 		pg_fatal("data checksums are not enabled in cluster");
 
-	if (ControlFile->data_checksum_version == 0 &&
+	if (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_OFF &&
 		mode == PG_MODE_DISABLE)
 		pg_fatal("data checksums are already disabled in cluster");
 
@@ -645,7 +645,7 @@ main(int argc, char *argv[])
 	if (mode == PG_MODE_ENABLE || mode == PG_MODE_DISABLE)
 	{
 		ControlFile->data_checksum_version =
-			(mode == PG_MODE_ENABLE) ? PG_DATA_CHECKSUM_VERSION : 0;
+			(mode == PG_MODE_ENABLE) ? PG_DATA_CHECKSUM_VERSION : PG_DATA_CHECKSUM_OFF;
 
 		if (do_sync)
 		{
diff --git a/src/bin/pg_combinebackup/pg_combinebackup.c b/src/bin/pg_combinebackup/pg_combinebackup.c
index ac7eb0940d5..d13bf63eb1e 100644
--- a/src/bin/pg_combinebackup/pg_combinebackup.c
+++ b/src/bin/pg_combinebackup/pg_combinebackup.c
@@ -615,7 +615,7 @@ check_control_files(int n_backups, char **backup_dirs)
 {
 	int			i;
 	uint64		system_identifier = 0;	/* placate compiler */
-	uint32		data_checksum_version = 0;	/* placate compiler */
+	uint32		data_checksum_version = PG_DATA_CHECKSUM_OFF;	/* placate compiler */
 	bool		data_checksum_mismatch = false;
 
 	/* Try to read each control file in turn, last to first. */
@@ -652,7 +652,7 @@ check_control_files(int n_backups, char **backup_dirs)
 		 */
 		if (i == n_backups - 1)
 			data_checksum_version = control_file->data_checksum_version;
-		else if (data_checksum_version != 0 &&
+		else if (data_checksum_version != PG_DATA_CHECKSUM_OFF &&
 				 data_checksum_version != control_file->data_checksum_version)
 			data_checksum_mismatch = true;
 
diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c
index 79053d22dcc..e18687226ae 100644
--- a/src/bin/pg_upgrade/controldata.c
+++ b/src/bin/pg_upgrade/controldata.c
@@ -206,7 +206,7 @@ get_control_data(ClusterInfo *cluster)
 	/* Only in <= 9.2 */
 	if (GET_MAJOR_VERSION(cluster->major_version) <= 902)
 	{
-		cluster->controldata.data_checksum_version = 0;
+		cluster->controldata.data_checksum_version = PG_DATA_CHECKSUM_OFF;
 		got_data_checksum_version = true;
 	}
 
@@ -749,11 +749,11 @@ check_control_data(ControlData *oldctrl,
 	 * We might eventually allow upgrades from checksum to no-checksum
 	 * clusters.
 	 */
-	if (oldctrl->data_checksum_version == 0 &&
-		newctrl->data_checksum_version != 0)
+	if (oldctrl->data_checksum_version == PG_DATA_CHECKSUM_OFF &&
+		newctrl->data_checksum_version != PG_DATA_CHECKSUM_OFF)
 		pg_fatal("old cluster does not use data checksums but the new one does");
-	else if (oldctrl->data_checksum_version != 0 &&
-			 newctrl->data_checksum_version == 0)
+	else if (oldctrl->data_checksum_version != PG_DATA_CHECKSUM_OFF &&
+			 newctrl->data_checksum_version == PG_DATA_CHECKSUM_OFF)
 		pg_fatal("old cluster uses data checksums but the new one does not");
 	else if (oldctrl->data_checksum_version != newctrl->data_checksum_version)
 		pg_fatal("old and new cluster pg_controldata checksum versions do not match");
diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index 4692e896326..5b276008614 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -331,7 +331,7 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile,
 				break;
 
 			/* Set new checksum for visibility map page, if enabled */
-			if (new_cluster.controldata.data_checksum_version != 0)
+			if (new_cluster.controldata.data_checksum_version != PG_DATA_CHECKSUM_OFF)
 				((PageHeader) new_vmbuf.data)->pd_checksum =
 					pg_checksum_page(new_vmbuf.data, new_blkno);
 
-- 
2.43.0



  [text/x-patch] v1-0001-Fix-doubled-word-in-a-comment-introduced-by-commi.patch (1003B, ../../CAJ7c6TPRTnQFXXX1CRcYoTLXw2swtDH==uSz1MYoMKdLrKZHjA@mail.gmail.com/3-v1-0001-Fix-doubled-word-in-a-comment-introduced-by-commi.patch)
  download | inline diff:
From 071cc93a34deebfab5cff6dbd26913d74f810166 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@tigerdata.com>
Date: Mon, 6 Apr 2026 16:36:25 +0300
Subject: [PATCH v1 1/2] Fix doubled word in a comment introduced by commit
 f19c0eccae96

Author: Aleksander Alekseev <aleksander@tigerdata.com>
Discussion: https://postgr.es/m/E1w8lyI-002o2A-2f%40gemulon.postgresql.org
---
 src/backend/access/transam/xlog.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b82af9a85c0..fea479afaa9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -4836,7 +4836,7 @@ SetDataChecksumsOn(void)
 
 	/*
 	 * Await state transition to "on" in all backends. When done we know that
-	 * data data checksums are both written and verified in all backends.
+	 * data checksums are both written and verified in all backends.
 	 */
 	WaitForProcSignalBarrier(barrier);
 }
-- 
2.43.0



^ permalink  raw  reply  [nested|flat] 3+ messages in thread

* Re: pgsql: Online enabling and disabling of data checksums
@ 2026-04-06 14:57  Daniel Gustafsson <dgustafsson@postgresql.org>
  parent: Aleksander Alekseev <aleksander@tigerdata.com>
  0 siblings, 0 replies; 3+ messages in thread

From: Daniel Gustafsson @ 2026-04-06 14:57 UTC (permalink / raw)
  To: Aleksander Alekseev <aleksander@tigerdata.com>; +Cc: pgsql-committers@lists.postgresql.org

> On 6 Apr 2026, at 16:39, Aleksander Alekseev <aleksander@tigerdata.com> wrote:
> 
> Hi Daniel,
> 
>> Online enabling and disabling of data checksums
>> 
>> [...]
> 
> I noticed a little mistake:

Thanks for looking!

> ```
> /*
> * Await state transition to "on" in all backends. When done we know that
> * data data checksums are both written and verified in all backends.
> */
> ```
> 
> The word "data" is repeated twice.

Ugh.

> Also there are inconsistencies in the way
> XLogCtlData->data_checksum_version,
> ControlFileData->data_checksum_version and certain variables are
> assigned. Sometimes a hardcoded 0 is used and sometimes
> PG_DATA_CHECKSUM_OFF. I suggest using values of the enum
> ChecksumStateType for readability / consistency.

PG_DATA_CHECKSUM_OFF didn't exist until quite late in the lifetime of the
patch, and clearly not all uses of 0 were ported over.

> Here are corresponding patches.

I will take another look later today when I have more time, and commit them.

--
Daniel Gustafsson






^ permalink  raw  reply  [nested|flat] 3+ messages in thread


end of thread, other threads:[~2026-04-06 14:57 UTC | newest]

Thread overview: 3+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-04-03 21:22 pgsql: Online enabling and disabling of data checksums Daniel Gustafsson <dgustafsson@postgresql.org>
2026-04-06 14:39 ` Aleksander Alekseev <aleksander@tigerdata.com>
2026-04-06 14:57   ` Daniel Gustafsson <dgustafsson@postgresql.org>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox