pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feeddatachecksums: handle invalid and dropped databases during enable
17+ messages / 6 participants
[nested] [flat]
* datachecksums: handle invalid and dropped databases during enable
@ 2026-07-28 10:01 Zsolt Parragi <zsolt.parragi@percona.com>
0 siblings, 1 reply; 17+ messages in thread
From: Zsolt Parragi @ 2026-07-28 10:01 UTC (permalink / raw)
To: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Hello
While testing the online enabling of datachecksums, I discovered some
corner cases that can cause the background process to fail:
* Invalid databases were only discovered when we tried to create
checksums for them, when we could instead discover them before
starting and fail early
* Databases dropped while the checksum process was running also
resulted in errors when it reached them and tried to build checksums
for them. In this case we could continue safely: the database was
dropped, there's no need to create checksums for it.
I attached a patch that adds testcases for these and fixes the issues.
Attachments:
[application/octet-stream] 0001-datachecksums-handle-invalid-and-dropped-databases-d.patch (10.3K, ../../CAN4CZFOGdqxtZ5-6gb4apqmvoH=Z+TNH8RKJ3mVtoR1HirKQWg@mail.gmail.com/2-0001-datachecksums-handle-invalid-and-dropped-databases-d.patch)
download | inline diff:
From 7943ac85ad8c124027bbc2921d35c771cba38d0c Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <zsolt.parragi@percona.com>
Date: Mon, 20 Jul 2026 20:20:40 +0000
Subject: [PATCH] datachecksums: handle invalid and dropped databases during
enable
Enable errors out early with a hint when an invalid database exists,
since the worker cannot connect to it and its files stay on disk.
A worker that started but failed gets the same dropped-database
heuristic as one that failed to start, so a concurrent drop during
processing no longer aborts the whole run. The existence check locks
the database first, otherwise a DROP DATABASE ... WITH (FORCE) which
killed the worker is still only halfway done and the database looks
like it is there to stay.
---
src/backend/postmaster/datachecksum_state.c | 70 +++++++++++
.../modules/test_checksums/t/001_basic.pl | 117 ++++++++++++++++++
2 files changed, 187 insertions(+)
diff --git a/src/backend/postmaster/datachecksum_state.c b/src/backend/postmaster/datachecksum_state.c
index 73dc539836b..ce13c59fde2 100644
--- a/src/backend/postmaster/datachecksum_state.c
+++ b/src/backend/postmaster/datachecksum_state.c
@@ -385,6 +385,7 @@ static void StartDataChecksumsWorkerLauncher(DataChecksumsWorkerOperation op,
int cost_limit);
static void DataChecksumsShmemRequest(void *arg);
static bool DatabaseExists(Oid dboid);
+static void ErrorOnInvalidDatabases(void);
static List *BuildDatabaseList(void);
static List *BuildRelationList(bool temp_relations, bool include_shared);
static void FreeDatabaseList(List *dblist);
@@ -583,6 +584,15 @@ enable_data_checksums(PG_FUNCTION_ARGS)
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cost limit must be greater than zero"));
+ /*
+ * An invalid database cannot be connected to, so the worker would fail to
+ * process it, and unlike a dropped database its files stay around. Error
+ * out early with a hint rather than failing halfway through processing.
+ * A database which turns invalid after this check is handled by the
+ * launcher treating it as concurrently dropped.
+ */
+ ErrorOnInvalidDatabases();
+
StartDataChecksumsWorkerLauncher(ENABLE_DATACHECKSUMS, cost_delay, cost_limit);
PG_RETURN_VOID();
@@ -984,6 +994,16 @@ ProcessDatabase(DataChecksumsWorkerDatabase *db)
DataChecksumState->worker_pid = InvalidPid;
LWLockRelease(DataChecksumsWorkerLock);
+ /*
+ * A worker which started but failed before reporting a result has most
+ * likely FATALed in InitPostgres. If the database was dropped, or was
+ * invalidated by a DROP DATABASE which is bound to remove its files, after
+ * we built the database list then that is the expected outcome and not an
+ * error, so apply the same heuristic as when the worker failed to start.
+ */
+ if (result == DATACHECKSUMSWORKER_FAILED && !DatabaseExists(db->dboid))
+ result = DATACHECKSUMSWORKER_DROPDB;
+
if (result == DATACHECKSUMSWORKER_ABORTED)
ereport(LOG,
errmsg("data checksums processing was aborted in database \"%s\"",
@@ -1410,6 +1430,15 @@ DatabaseExists(Oid dboid)
StartTransactionCommand();
+ /*
+ * DROP DATABASE holds an exclusive lock on the database from before it
+ * terminates the connections to it until it commits, so take a lock which
+ * conflicts with it to wait out a drop which is in flight. Without this
+ * we can see a database whose worker was just killed by DROP DATABASE ...
+ * WITH (FORCE) as still existing, and report a spurious failure.
+ */
+ LockSharedObject(DatabaseRelationId, dboid, 0, AccessShareLock);
+
rel = table_open(DatabaseRelationId, AccessShareLock);
ScanKeyInit(&skey,
Anum_pg_database_oid,
@@ -1436,6 +1465,47 @@ DatabaseExists(Oid dboid)
return found;
}
+/*
+ * ErrorOnInvalidDatabases
+ * Error out if the cluster contains an invalid database
+ *
+ * A database left invalid by an interrupted DROP DATABASE cannot be connected
+ * to, so data checksums can never be enabled in it, while its files remain on
+ * disk where checksum verification will find them. Report it to the caller
+ * so the user can drop it before retrying. Called from a normal backend, so
+ * unlike DatabaseExists we are already in a transaction.
+ *
+ * A cluster can contain more than one invalid database, but only the first one
+ * found is reported; collecting them all is not worth the complexity here. A
+ * user with several of them gets the error again for the next one after
+ * dropping the reported database, which the hint accounts for.
+ */
+static void
+ErrorOnInvalidDatabases(void)
+{
+ Relation rel;
+ TableScanDesc scan;
+ HeapTuple tup;
+
+ rel = table_open(DatabaseRelationId, AccessShareLock);
+ scan = table_beginscan_catalog(rel, 0, NULL);
+
+ while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+ {
+ Form_pg_database pgdb = (Form_pg_database) GETSTRUCT(tup);
+
+ if (database_is_invalid_form(pgdb))
+ ereport(ERROR,
+ errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("cannot enable data checksums in a cluster with invalid database \"%s\"",
+ NameStr(pgdb->datname)),
+ errhint("Use DROP DATABASE to drop invalid databases."));
+ }
+
+ table_endscan(scan);
+ table_close(rel, AccessShareLock);
+}
+
/*
* BuildDatabaseList
* Compile a list of all currently available databases in the cluster
diff --git a/src/test/modules/test_checksums/t/001_basic.pl b/src/test/modules/test_checksums/t/001_basic.pl
index a78118320d5..60ee252d536 100644
--- a/src/test/modules/test_checksums/t/001_basic.pl
+++ b/src/test/modules/test_checksums/t/001_basic.pl
@@ -59,5 +59,122 @@ enable_data_checksums($node, wait => 'on');
$result = $node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1");
is($result, '10000', 'ensure checksummed pages can be read back');
+# Enabling checksums in a cluster which contains an invalid database left
+# behind by an interrupted DROP DATABASE must be refused.
+disable_data_checksums($node, wait => 1);
+
+$node->safe_psql('postgres', "CREATE DATABASE baddb;");
+$node->safe_psql('baddb',
+ "CREATE TABLE bad_t AS SELECT generate_series(1,100) AS a;");
+
+# Mark the database invalid, as an interrupted DROP DATABASE would.
+$node->safe_psql('postgres',
+ "UPDATE pg_database SET datconnlimit = -2 WHERE datname = 'baddb';");
+
+# The request must fail up front with an actionable error, rather than fail
+# halfway through processing.
+my ($ret, $stdout, $stderr) =
+ $node->psql('postgres', "SELECT pg_enable_data_checksums();");
+isnt($ret, 0, 'pg_enable_data_checksums fails with an invalid database');
+like(
+ $stderr,
+ qr/invalid database "baddb"/,
+ 'error message names the invalid database');
+like($stderr, qr/DROP DATABASE/,
+ 'error message hints at dropping the database');
+test_checksum_state($node, 'off');
+
+# Dropping the invalid database clears the way.
+$node->safe_psql('postgres', "DROP DATABASE baddb;");
+enable_data_checksums($node, wait => 'on');
+
+# A database dropped while processing is in progress is not an error, the
+# remaining databases are still processed.
+disable_data_checksums($node, wait => 1);
+
+$node->safe_psql('postgres', "CREATE DATABASE dropme;");
+$node->safe_psql('dropme',
+ "CREATE TABLE dropme_t AS SELECT generate_series(1,10000) AS a;");
+
+# Hold the worker in the "postgres" database by keeping a temporary table
+# around, the worker waits for pre-existing temp tables to disappear before
+# it reports the database as processed. "dropme" was created last, so it is
+# processed after "postgres" and is still untouched while we wait.
+my $bg = $node->background_psql('postgres');
+$bg->query_safe('CREATE TEMP TABLE holdme (a int);');
+
+enable_data_checksums($node);
+
+$node->poll_query_until(
+ 'postgres', qq[
+ SELECT count(*) > 0 FROM pg_stat_activity
+ WHERE backend_type = 'datachecksums worker' AND datname = 'postgres'
+ AND query LIKE 'Waiting for % temp tables to be removed']
+) or die "timed out waiting for worker to wait for temporary tables";
+
+# Verify the assumption that processing has not reached "dropme" yet, without
+# it the test would silently stop covering the concurrent drop.
+my $log = slurp_file($node->logfile);
+unlike(
+ $log,
+ qr/initiating data checksum processing in database "dropme"/,
+ 'processing has not reached the database to drop');
+
+# Not processed yet and nobody is connected to it, so this must succeed.
+$node->safe_psql('postgres', "DROP DATABASE dropme;");
+
+# Let the worker in "postgres" finish, the launcher then moves on to the
+# database which no longer exists.
+$bg->query_safe('DROP TABLE holdme;');
+$bg->quit;
+
+wait_for_checksum_state($node, 'on');
+$node->poll_query_until('postgres',
+ "SELECT count(*) = 0 "
+ . "FROM pg_catalog.pg_stat_activity "
+ . "WHERE backend_type = 'datachecksums launcher';");
+
+# Same thing with DROP DATABASE ... WITH (FORCE), which terminates the
+# checksums worker connected to the database being dropped.
+disable_data_checksums($node, wait => 1);
+
+$node->safe_psql('postgres', "CREATE DATABASE dropmeforce;");
+$node->safe_psql('dropmeforce',
+ "CREATE TABLE dropme_t AS SELECT generate_series(1,10000) AS a;");
+
+# Hold the worker inside "dropmeforce" by keeping a temporary table around
+# there.
+$bg = $node->background_psql('dropmeforce');
+$bg->query_safe('CREATE TEMP TABLE holdme (a int);');
+
+enable_data_checksums($node);
+
+$node->poll_query_until(
+ 'postgres', qq[
+ SELECT count(*) > 0 FROM pg_stat_activity
+ WHERE backend_type = 'datachecksums worker' AND datname = 'dropmeforce'
+ AND query LIKE 'Waiting for % temp tables to be removed']
+) or die "timed out waiting for worker to wait for temporary tables";
+
+# Terminates both the session holding the temp table and the checksums
+# worker connected to the database.
+$node->safe_psql('postgres', "DROP DATABASE dropmeforce WITH (FORCE);");
+$bg->quit;
+
+wait_for_checksum_state($node, 'on');
+$node->poll_query_until('postgres',
+ "SELECT count(*) = 0 "
+ . "FROM pg_catalog.pg_stat_activity "
+ . "WHERE backend_type = 'datachecksums launcher';");
+
+$result = $node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1");
+is($result, '10000', 'ensure checksummed pages can be read back');
+
$node->stop;
+
+# The resulting cluster must also pass offline verification, proving no
+# unchecksummed files were left behind.
+command_ok([ 'pg_checksums', '--check', '-D', $node->data_dir ],
+ 'offline checksum verification passes after enable');
+
done_testing();
--
2.54.0
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-07-28 13:13 Daniel Gustafsson <daniel@yesql.se>
parent: Zsolt Parragi <zsolt.parragi@percona.com>
0 siblings, 3 replies; 17+ messages in thread
From: Daniel Gustafsson @ 2026-07-28 13:13 UTC (permalink / raw)
To: Zsolt Parragi <zsolt.parragi@percona.com>; +Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
> On 28 Jul 2026, at 12:01, Zsolt Parragi <zsolt.parragi@percona.com> wrote:
> While testing the online enabling of datachecksums, I discovered some
> corner cases that can cause the background process to fail:
>
> * Invalid databases were only discovered when we tried to create
> checksums for them, when we could instead discover them before
> starting and fail early
> * Databases dropped while the checksum process was running also
> resulted in errors when it reached them and tried to build checksums
> for them. In this case we could continue safely: the database was
> dropped, there's no need to create checksums for it.
>
> I attached a patch that adds testcases for these and fixes the issues.
Thanks, I've reviewed and tested your patch and intend to push it along with
your other earlier patch shortly.
--
Daniel Gustafsson
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-07-29 12:00 r314tive <tanswis42@gmail.com>
parent: Daniel Gustafsson <daniel@yesql.se>
2 siblings, 1 reply; 17+ messages in thread
From: r314tive @ 2026-07-29 12:00 UTC (permalink / raw)
To: Daniel Gustafsson <daniel@yesql.se>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Hi,
While checking commit 51f55b13a4d, I noticed a regression in repeated
calls to pg_enable_data_checksums().
Before that commit, calling pg_enable_data_checksums() after checksums had
reached the "on" state succeeded as a no-op. The existing basic TAP test
also documents that behavior.
51f55b13a4d added ErrorOnInvalidDatabases() before
StartDataChecksumsWorkerLauncher(). If an invalid database exists, the
same repeated call now fails even though no database processing is needed:
ERROR: cannot enable data checksums in a cluster with invalid database
"baddb"
The attached v1 patch restores that no-op, but does not use a bare
DataChecksumsOn() early return. Such a return could lose a pending disable
request and violate the existing last-request-wins behavior.
Instead, the patch makes the no-op decision under
DataChecksumsWorkerLock and records the requested enable operation and cost
settings atomically. If a disable operation is already running, it keeps
the invalid-database preflight because the subsequent enable may need to
process every database.
The patch adds two tests. The basic test covers repeated enable with an
invalid database while checksums are on, followed by a real enable from the
off state which must still fail. An injection test pauses an active disable
before the visible state changes from on, and verifies that enable still
checks invalid databases in that case.
Tested on origin/master at
33b392eaabdd1c563d40388784df051821e03c6b:
Unpatched master with the new basic test:
expected FAIL, 1 of 24 tests failed, only the new no-op assertion.
Patched default test_checksums suite:
PASS, 9 files and 95 tests.
Patched extended pgbench, standby, and PITR tests:
PASS, 3 files and 102 tests.
Full build, git diff --check, patch apply check, and Perl syntax:
PASS.
I tested master only. My local REL_19_STABLE ref predates the backpatch of
51f55b13a4d, and I did not refresh it while working offline.
This should be backpatched to v19 together with 51f55b13a4d.
Regards,
Ilmar Yunusov
Attachments:
[application/x-patch] v1-0001-Restore-idempotency-of-pg_enable_data_checksums.patch (6.3K, ../../CALCfnuoRtJsT5eRV8tLVD5UinG0cK8h+kFSp2iqe09TpvsqfRw@mail.gmail.com/2-v1-0001-Restore-idempotency-of-pg_enable_data_checksums.patch)
download | inline diff:
From 7eba3fb96c6ad025a9c1673f17c339b38c39f857 Mon Sep 17 00:00:00 2001
From: Ilmar Yunusov <tanswis42@gmail.com>
Date: Wed, 29 Jul 2026 15:55:17 +0500
Subject: [PATCH v1] Restore idempotency of pg_enable_data_checksums()
Commit 51f55b13a4d made ErrorOnInvalidDatabases() run before
StartDataChecksumsWorkerLauncher(). Consequently, a repeated call to
pg_enable_data_checksums() fails when an invalid database exists, even
when checksums are already enabled and no processing is required.
Handle the no-op case while holding DataChecksumsWorkerLock. Record the
enable request and cost settings atomically so pending disable requests
retain last-request-wins semantics. If a disable operation is already
running, keep the invalid-database preflight because re-enabling may
require processing databases.
Extend the TAP tests to cover both a repeated enable with an invalid
database and an enable attempted while disabling is already running.
Backpatch to v19, where 51f55b13a4d was applied.
---
src/backend/postmaster/datachecksum_state.c | 20 ++++++++
.../modules/test_checksums/t/001_basic.pl | 14 ++++--
.../modules/test_checksums/t/005_injection.pl | 48 +++++++++++++++++++
3 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/src/backend/postmaster/datachecksum_state.c b/src/backend/postmaster/datachecksum_state.c
index fc082ac37b9..7d91948edde 100644
--- a/src/backend/postmaster/datachecksum_state.c
+++ b/src/backend/postmaster/datachecksum_state.c
@@ -584,6 +584,25 @@ enable_data_checksums(PG_FUNCTION_ARGS)
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cost limit must be greater than zero"));
+ /*
+ * If checksums are already on and no disable operation is running, this
+ * request can be satisfied without processing any databases. Record the
+ * desired operation while holding the lock, so a pending disable is either
+ * canceled here or ordered after this request.
+ */
+ LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
+ if (DataChecksumsOn() &&
+ (!DataChecksumState->launcher_running ||
+ DataChecksumState->operation == ENABLE_DATACHECKSUMS))
+ {
+ DataChecksumState->launch_operation = ENABLE_DATACHECKSUMS;
+ DataChecksumState->launch_cost_delay = cost_delay;
+ DataChecksumState->launch_cost_limit = cost_limit;
+ LWLockRelease(DataChecksumsWorkerLock);
+ PG_RETURN_VOID();
+ }
+ LWLockRelease(DataChecksumsWorkerLock);
+
/*
* An invalid database cannot be connected to, so the worker would fail to
* process it, and unlike a dropped database its files stay around. Error
@@ -1254,6 +1273,7 @@ again:
pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_PHASE,
PROGRESS_DATACHECKSUMS_PHASE_DISABLING);
+ INJECTION_POINT("datachecksums-disable-checksums-delay", NULL);
SetDataChecksumsOff();
ereport(LOG,
errmsg("data checksums are now disabled"));
diff --git a/src/test/modules/test_checksums/t/001_basic.pl b/src/test/modules/test_checksums/t/001_basic.pl
index 72e0d0df46f..62328c4fb36 100644
--- a/src/test/modules/test_checksums/t/001_basic.pl
+++ b/src/test/modules/test_checksums/t/001_basic.pl
@@ -61,8 +61,6 @@ is($result, '10000', 'ensure checksummed pages can be read back');
# Enabling checksums in a cluster which contains an invalid database left
# behind by an interrupted DROP DATABASE must be refused.
-disable_data_checksums($node, wait => 1);
-
$node->safe_psql('postgres', "CREATE DATABASE baddb;");
$node->safe_psql('baddb',
"CREATE TABLE bad_t AS SELECT generate_series(1,100) AS a;");
@@ -71,9 +69,19 @@ $node->safe_psql('baddb',
$node->safe_psql('postgres',
"UPDATE pg_database SET datconnlimit = -2 WHERE datname = 'baddb';");
+# A repeated enable is still a no-op when checksums are already on.
+my ($ret, $stdout, $stderr) =
+ $node->psql('postgres', "SELECT pg_enable_data_checksums();");
+is(
+ $ret, 0,
+ 'pg_enable_data_checksums is a no-op with an invalid database');
+test_checksum_state($node, 'on');
+
+disable_data_checksums($node, wait => 1);
+
# The request must fail up front with an actionable error, rather than fail
# halfway through processing.
-my ($ret, $stdout, $stderr) =
+($ret, $stdout, $stderr) =
$node->psql('postgres', "SELECT pg_enable_data_checksums();");
isnt($ret, 0, 'pg_enable_data_checksums fails with an invalid database');
like(
diff --git a/src/test/modules/test_checksums/t/005_injection.pl b/src/test/modules/test_checksums/t/005_injection.pl
index 34cd47e6c81..76b57245b9c 100644
--- a/src/test/modules/test_checksums/t/005_injection.pl
+++ b/src/test/modules/test_checksums/t/005_injection.pl
@@ -34,6 +34,54 @@ $node->start;
$node->safe_psql('postgres', 'CREATE EXTENSION test_checksums;');
$node->safe_psql('postgres', 'CREATE EXTENSION injection_points;');
+# ---------------------------------------------------------------------------
+# Test an enable request while disabling is already running
+#
+
+enable_data_checksums($node, wait => 'on');
+$node->safe_psql('postgres', 'CREATE DATABASE invalid_during_disable;');
+$node->safe_psql(
+ 'postgres',
+ "UPDATE pg_database SET datconnlimit = -2 "
+ . "WHERE datname = 'invalid_during_disable';");
+
+$node->safe_psql(
+ 'postgres',
+ "SELECT injection_points_attach("
+ . "'datachecksums-disable-checksums-delay', 'wait');");
+
+disable_data_checksums($node);
+$node->wait_for_event(
+ 'datachecksums launcher',
+ 'datachecksums-disable-checksums-delay');
+test_checksum_state($node, 'on');
+
+my ($enable_ret, $enable_stdout, $enable_stderr) =
+ $node->psql('postgres', 'SELECT pg_enable_data_checksums();');
+isnt(
+ $enable_ret, 0,
+ 'enable rejects invalid databases while disable is running');
+like(
+ $enable_stderr,
+ qr/invalid database "invalid_during_disable"/,
+ 'enable reports the invalid database while disable is running');
+
+$node->safe_psql(
+ 'postgres',
+ "SELECT injection_points_wakeup("
+ . "'datachecksums-disable-checksums-delay');");
+$node->safe_psql(
+ 'postgres',
+ "SELECT injection_points_detach("
+ . "'datachecksums-disable-checksums-delay');");
+
+$node->poll_query_until(
+ 'postgres',
+ "SELECT count(*) = 0 FROM pg_catalog.pg_stat_activity "
+ . "WHERE backend_type = 'datachecksums launcher';");
+test_checksum_state($node, 'off');
+$node->safe_psql('postgres', 'DROP DATABASE invalid_during_disable;');
+
# ---------------------------------------------------------------------------
# Inducing failures and crashes in processing
--
2.52.0
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-07-29 12:24 Daniel Gustafsson <daniel@yesql.se>
parent: r314tive <tanswis42@gmail.com>
0 siblings, 0 replies; 17+ messages in thread
From: Daniel Gustafsson @ 2026-07-29 12:24 UTC (permalink / raw)
To: r314tive <tanswis42@gmail.com>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
> On 29 Jul 2026, at 14:00, r314tive <tanswis42@gmail.com> wrote:
> While checking commit 51f55b13a4d, I noticed a regression in repeated
> calls to pg_enable_data_checksums().
>
> Before that commit, calling pg_enable_data_checksums() after checksums had
> reached the "on" state succeeded as a no-op. The existing basic TAP test
> also documents that behavior.
>
> 51f55b13a4d added ErrorOnInvalidDatabases() before
> StartDataChecksumsWorkerLauncher(). If an invalid database exists, the
> same repeated call now fails even though no database processing is needed:
>
> ERROR: cannot enable data checksums in a cluster with invalid database
> "baddb"
I'm not sure that's inherently wrong though, if the precondition for an
operation isn't met then the operation cannot succeed and erroring out is the
right option. If anything, wouldn't it be better to expand the errhint to
mention that any currently running checksum enabling will fail unless the
database is dropped?
> The attached v1 patch restores that no-op, but does not use a bare
> DataChecksumsOn() early return. Such a return could lose a pending disable
> request and violate the existing last-request-wins behavior.
>
> Instead, the patch makes the no-op decision under
> DataChecksumsWorkerLock and records the requested enable operation and cost
> settings atomically. If a disable operation is already running, it keeps
> the invalid-database preflight because the subsequent enable may need to
> process every database.
I don't think duplicating this logic from StartDataChecksumsWorkerLauncher is
the right move, enable_data_checksums should IMO only validate parameters and
preconditions and leave the decisionmaking to StartDataChecksumsWorkerLauncher.
--
Daniel Gustafsson
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-07-30 17:56 Ayush Tiwari <ayushtiwari.slg01@gmail.com>
parent: Daniel Gustafsson <daniel@yesql.se>
2 siblings, 1 reply; 17+ messages in thread
From: Ayush Tiwari @ 2026-07-30 17:56 UTC (permalink / raw)
To: Daniel Gustafsson <daniel@yesql.se>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Hi,
I think there may be another case to consider here. DROP DATABASE durably
marks the database invalid before it removes the catalog row and files, so
a crash or ERROR after the marker is written leaves an invalid row whose
files are still present. If checksum enabling is running at the same
time, the worker will fail to connect to that database, and since
1df361e3d82 DatabaseExists() returns false for an invalid row. AFAICT
the launcher then classifies the failure as a concurrent drop and skips
the database, potentially letting data_checksums reach "on" while those
files were never processed.
AFAICS nothing else rules this out, so I am attaching a patch along with
a TAP test that uses a new injection point in dropdb() to exercise the
race directly. The patch makes DatabaseExists() return true for any
present row; ISTM that AccessShareLock already waits out an in-flight
drop, so an invalid-but-present row can only be from an interrupted one
whose files still need checksums. I am not sure if the patch needs a
dedicated TAP test, however I've added one.
Apologies if this is expected behaviour, and I missed on some thread
mentioning it.
Regards,
Ayush
Attachments:
[application/octet-stream] 0001-Don-t-skip-invalid-databases-when-enabling-data-chec.patch (8.1K, ../../CAJTYsWWm4S1jkQ4ejQTGnWDSNBBW7Zc8EkkjVD7sNkjQAka3Fg@mail.gmail.com/3-0001-Don-t-skip-invalid-databases-when-enabling-data-chec.patch)
download | inline diff:
From 9a0fae891c9e83bc0694fd2575b8ad79d840440c Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Thu, 30 Jul 2026 20:28:53 +0530
Subject: [PATCH] Don't skip invalid databases when enabling data checksums
When enabling checksums cannot process a database, the launcher uses
DatabaseExists() to tell a concurrent drop (benign) from a real failure.
Since 1df361e3d82 that check also treats a present-but-invalid database
as non-existent. An interrupted DROP DATABASE leaves exactly that: the
invalid marker is flushed before the row and files are removed, so a
crash or ERROR in between leaves an invalid row whose files remain on
disk. Treating it as dropped lets checksums reach "on" with those
files left unchecksummed.
Report a database as existing whenever its catalog row is found. The
AccessShareLock in DatabaseExists() already waits out an in-flight drop,
so an invalid-but-present row can only be an interrupted-drop leftover
whose files still need checksums; enabling then aborts until it is
dropped.
Add a test-only injection point in dropdb() and a TAP test covering it.
Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/CAN4CZFOGdqxtZ5-6gb4apqmvoH=Z+TNH8RKJ3mVtoR1HirKQWg@mail.gmail.com
---
src/backend/commands/dbcommands.c | 2 +
src/backend/postmaster/datachecksum_state.c | 31 ++++-----
.../modules/test_checksums/t/005_injection.pl | 64 +++++++++++++++++++
3 files changed, 77 insertions(+), 20 deletions(-)
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index e9766bcd7ef..a32af9894bf 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -1883,6 +1883,8 @@ dropdb(const char *dbname, bool missing_ok, bool force)
systable_inplace_update_finish(inplace_state, tup);
XLogFlush(XactLastRecEnd);
+ INJECTION_POINT("dropdb-after-invalid-marker", NULL);
+
/*
* Also delete the tuple - transactionally. If this transaction commits,
* the row will be gone, but if we fail, dropdb() can be invoked again.
diff --git a/src/backend/postmaster/datachecksum_state.c b/src/backend/postmaster/datachecksum_state.c
index fc082ac37b9..d525dccce5e 100644
--- a/src/backend/postmaster/datachecksum_state.c
+++ b/src/backend/postmaster/datachecksum_state.c
@@ -587,9 +587,11 @@ enable_data_checksums(PG_FUNCTION_ARGS)
/*
* An invalid database cannot be connected to, so the worker would fail to
* process it, and unlike a dropped database its files stay around. Error
- * out early with a hint rather than failing halfway through processing. A
- * database which turns invalid after this check is handled by the
- * launcher treating it as concurrently dropped.
+ * out early with a hint rather than failing halfway through processing.
+ * A database which turns invalid after this check, for example from an
+ * interrupted DROP DATABASE, instead makes its worker fail; the launcher
+ * then aborts and leaves checksums disabled, since the invalid database's
+ * files would otherwise be left without valid checksums.
*/
ErrorOnInvalidDatabases();
@@ -996,11 +998,9 @@ ProcessDatabase(DataChecksumsWorkerDatabase *db)
/*
* A worker which started but failed before reporting a result has most
- * likely FATALed in InitPostgres. If the database was dropped, or was
- * invalidated by a DROP DATABASE which is bound to remove its files,
- * after we built the database list then that is the expected outcome and
- * not an error, so apply the same heuristic as when the worker failed to
- * start.
+ * likely FATALed in InitPostgres. If the database was dropped after we
+ * built the database list then that is the expected outcome and not an
+ * error, so apply the same heuristic as when the worker failed to start.
*/
if (result == DATACHECKSUMSWORKER_FAILED && !DatabaseExists(db->dboid))
result = DATACHECKSUMSWORKER_DROPDB;
@@ -1415,9 +1415,9 @@ DataChecksumsShmemRequest(void *arg)
* DatabaseExists
*
* Scans the system catalog to check if a database with the given Oid exists
- * and returns true if it is found and valid, else false. Note, we cannot use
- * database_is_invalid_oid here as it will ERROR out, and we want to gracefully
- * handle errors.
+ * and returns true if it is found, even if it is marked invalid. An invalid
+ * database still has files that need checksums, so only a missing catalog row
+ * proves that a concurrent DROP DATABASE completed.
*/
static bool
DatabaseExists(Oid dboid)
@@ -1427,7 +1427,6 @@ DatabaseExists(Oid dboid)
SysScanDesc scan;
bool found;
HeapTuple tuple;
- Form_pg_database pg_database_tuple;
StartTransactionCommand();
@@ -1450,14 +1449,6 @@ DatabaseExists(Oid dboid)
tuple = systable_getnext(scan);
found = HeapTupleIsValid(tuple);
- /* If the Oid exists, ensure that it's not partially dropped */
- if (found)
- {
- pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
- if (database_is_invalid_form(pg_database_tuple))
- found = false;
- }
-
systable_endscan(scan);
table_close(rel, AccessShareLock);
diff --git a/src/test/modules/test_checksums/t/005_injection.pl b/src/test/modules/test_checksums/t/005_injection.pl
index 2387e4399ba..6c49f640e8b 100644
--- a/src/test/modules/test_checksums/t/005_injection.pl
+++ b/src/test/modules/test_checksums/t/005_injection.pl
@@ -79,6 +79,70 @@ SKIP:
);
}
+# ---------------------------------------------------------------------------
+# Test an interrupted DROP DATABASE while checksum enabling is in progress
+#
+
+disable_data_checksums($node, wait => 1);
+
+$node->safe_psql('postgres', 'CREATE DATABASE invalid_dropdb;');
+$node->safe_psql('invalid_dropdb',
+ "CREATE TABLE bad_t AS SELECT generate_series(1,1000) AS a;");
+
+# Hold the worker in "postgres", so invalid_dropdb is still waiting in the
+# launcher's database list when DROP DATABASE is interrupted.
+my $hold = $node->background_psql('postgres');
+$hold->query_safe('CREATE TEMP TABLE holdme (a int);');
+
+my $dropdb_log_offset = -s $node->logfile;
+enable_data_checksums($node);
+$node->poll_query_until(
+ 'postgres', qq[
+ SELECT count(*) > 0 FROM pg_stat_activity
+ WHERE backend_type = 'datachecksums worker' AND datname = 'postgres'
+ AND query LIKE 'Waiting for % temp tables to be removed']
+) or die "timed out waiting for worker to wait for temporary tables";
+
+my $dropdb_log =
+ PostgreSQL::Test::Utils::slurp_file($node->logfile, $dropdb_log_offset);
+unlike(
+ $dropdb_log,
+ qr/initiating data checksum processing in database "invalid_dropdb"/,
+ 'invalid database has not been processed yet');
+
+# Leave the database durably marked invalid, but abort DROP DATABASE before
+# its catalog row and files are removed.
+$node->safe_psql('postgres',
+ "SELECT injection_points_attach('dropdb-after-invalid-marker','error');"
+);
+my ($drop_ret, $drop_stdout, $drop_stderr) =
+ $node->psql('postgres', 'DROP DATABASE invalid_dropdb;');
+isnt($drop_ret, 0, 'DROP DATABASE was interrupted after invalidation');
+like(
+ $drop_stderr,
+ qr/dropdb-after-invalid-marker/,
+ 'DROP DATABASE reached the invalid-marker injection point');
+$node->safe_psql('postgres',
+ "SELECT injection_points_detach('dropdb-after-invalid-marker');");
+
+my $invalid_state = $node->safe_psql('postgres',
+ "SELECT datconnlimit FROM pg_database WHERE datname = 'invalid_dropdb';");
+is($invalid_state, '-2', 'interrupted DROP left an invalid database row');
+
+# Let checksum processing continue. The invalid database must be treated as
+# a processing failure, not as a successfully dropped database.
+$hold->query_safe('DROP TABLE holdme;');
+$hold->quit;
+$node->poll_query_until('postgres',
+ "SELECT count(*) = 0 "
+ . "FROM pg_catalog.pg_stat_activity "
+ . "WHERE backend_type = 'datachecksums launcher';")
+ or die "timed out waiting for datachecksums launcher to exit";
+test_checksum_state($node, 'off');
+
+# Remove the invalid database and continue with the remaining tests.
+$node->safe_psql('postgres', 'DROP DATABASE invalid_dropdb;');
+
# ---------------------------------------------------------------------------
# Test concurrent CREATE DATABASE which use the file_copy strategy
#
--
2.34.1
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-07-30 22:02 Zsolt Parragi <zsolt.parragi@percona.com>
parent: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
0 siblings, 1 reply; 17+ messages in thread
From: Zsolt Parragi @ 2026-07-30 22:02 UTC (permalink / raw)
To: Ayush Tiwari <ayushtiwari.slg01@gmail.com>; +Cc: pgsql-hackers@lists.postgresql.org, Daniel Gustafsson <daniel@yesql.se>
> Apologies if this is expected behaviour, and I missed on some thread
> mentioning it.
It was somewhat intentional, but I agree that it is inconsistent and
maybe we should improve it.
The original code wanted to skip invalid databases, but also failed
because it tried connecting to them before this check. I fixed the
connection failure, but I also added a startup check about having no
invalid databases, because completing checksum enablement while there
are invalid databases didn't seem entirely safe. This seemed like a
good compromise because I wanted to avoid surprise process stops, but
since a failing drop database happening during the processing is
unlikely, handling this properly shouldn't be a real problem.
We could improve this either by adding your patch, or by removing
ErrorOnInvalidDatabases, but adding this patch seems to be safer to
me.
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-03 12:14 Ayush Tiwari <ayushtiwari.slg01@gmail.com>
parent: Zsolt Parragi <zsolt.parragi@percona.com>
0 siblings, 1 reply; 17+ messages in thread
From: Ayush Tiwari @ 2026-08-03 12:14 UTC (permalink / raw)
To: Zsolt Parragi <zsolt.parragi@percona.com>; Daniel Gustafsson <daniel@yesql.se>; +Cc: pgsql-hackers@lists.postgresql.org
Hi,
On Fri, 31 Jul 2026 at 03:32, Zsolt Parragi <zsolt.parragi@percona.com>
wrote:
> > Apologies if this is expected behaviour, and I missed on some thread
> > mentioning it.
>
> It was somewhat intentional, but I agree that it is inconsistent and
> maybe we should improve it.
>
> The original code wanted to skip invalid databases, but also failed
> because it tried connecting to them before this check. I fixed the
> connection failure, but I also added a startup check about having no
> invalid databases, because completing checksum enablement while there
> are invalid databases didn't seem entirely safe. This seemed like a
> good compromise because I wanted to avoid surprise process stops, but
> since a failing drop database happening during the processing is
> unlikely, handling this properly shouldn't be a real problem.
>
> We could improve this either by adding your patch, or by removing
> ErrorOnInvalidDatabases, but adding this patch seems to be safer to
> me.
I lean the same way. ISTM the startup check and this change enforce the
same rule from two ends: don't let enablement finish while an invalid
database still has files on disk, whether it was invalid at startup or
turned invalid during processing. Dropping ErrorOnInvalidDatabases would
lose the early, actionable error for the startup case, so keeping it and
handling the mid-run case seems the more consistent option.
I've added a CF entry to track this [1], probably need to change the title.
Regards,
Ayush
[1] https://commitfest.postgresql.org/patch/7087/
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-03 15:01 Daniel Gustafsson <daniel@yesql.se>
parent: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
0 siblings, 0 replies; 17+ messages in thread
From: Daniel Gustafsson @ 2026-08-03 15:01 UTC (permalink / raw)
To: Ayush Tiwari <ayushtiwari.slg01@gmail.com>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; pgsql-hackers@lists.postgresql.org
> On 3 Aug 2026, at 14:14, Ayush Tiwari <ayushtiwari.slg01@gmail.com> wrote:
> On Fri, 31 Jul 2026 at 03:32, Zsolt Parragi <zsolt.parragi@percona.com <mailto:zsolt.parragi@percona.com>> wrote:
>> We could improve this either by adding your patch, or by removing
>> ErrorOnInvalidDatabases, but adding this patch seems to be safer to
>> me.
>
> I lean the same way.
After looking at this and sleeping on it, I think I agree. The case should be
pretty rare to hit but if done this approach seems like the right one. I'll go
make it so, backpatched to 19.
--
Daniel Gustafsson
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-18 07:00 Alexander Lakhin <exclusion@gmail.com>
parent: Daniel Gustafsson <daniel@yesql.se>
2 siblings, 1 reply; 17+ messages in thread
From: Alexander Lakhin @ 2026-08-18 07:00 UTC (permalink / raw)
To: Daniel Gustafsson <daniel@yesql.se>; Tomas Vondra <tomas@vondra.me>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Hello Daniel and Tomas,
30.07.2026 14:02, Daniel Gustafsson wrote:
>> On 30 Jul 2026, at 10:23, Jonathan Gonzalez V. <jonathan.abdiel@gmail.com> wrote:
>> Daniel Gustafsson <daniel@yesql.se> writes:
>> I've tested your patch and confirm that it fixed the issue
> Thanks for review, pushed and backpatched.
It looks like that that addition to test_checksums/001_basic.pl is not
very stable on machines having slow storage. Buildfarm animal turaco
(Raspberry Pi, presumably with SD card onboard) fails the test pretty
reliably, e.g., [1], [2]:
[21:37:30.016](0.002s) # issuing query 1 via background psql: CREATE TEMP TABLE holdme (a int);
[21:37:30.024](0.009s) # results query 1:
# {
#Â Â 'stderr' => 'background_psql: QUERY_SEPARATOR 1:
# ',
#Â Â 'stdout' => 'background_psql: QUERY_SEPARATOR 1:
# '
# }
[21:37:47.284](17.259s) # die: error running SQL: 'psql:<stdin>:1: ERROR:Â database "dropmeforce" is being accessed by
other users
# DETAIL:Â There is 1 other session using the database.'
# while running 'psql --no-psqlrc --no-align --tuples-only --quiet --dbname port=12278
host=/mnt/data/buildfarm/buildroot/tmp/n3IU4kJupg dbname='postgres' --file - --variable ON_ERROR_STOP=1' with sql 'DROP
DATABASE dropmeforce WITH (FORCE);' at t/001_basic.pl line 163.
[21:37:47.286](0.002s) 1..19
error running SQL: 'psql:<stdin>:1: ERROR:Â database "dropmeforce" is being accessed by other users
DETAIL:Â There is 1 other session using the database.'
while running 'psql --no-psqlrc --no-align --tuples-only --quiet --dbname port=12278
host=/mnt/data/buildfarm/buildroot/tmp/n3IU4kJupg dbname='postgres' --file - --variable ON_ERROR_STOP=1' with sql 'DROP
DATABASE dropmeforce WITH (FORCE);' at t/001_basic.pl line 163.
Probably, it's caused by the storage degradation (the test case was
committed on 2026-07-28, but the first failure was produced on 2026-08-13)
and the given test is just the most demanding (only this test fails there)
for now, but I can reproduce such failures on Orange PI with SD card too,
running 1-3 test instances simultaneously. With the diagnostic logging
added:
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -3787,6 +3787,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
                       else
                       {
                               (*nbackends)++;
+fprintf(stderr, "!!!CountOtherDBBackends[%d]| tries: %d, proc-pid: %d\n", getpid(), tries, proc->pid);
                               if ((statusFlags & PROC_IS_AUTOVACUUM) &&
                                       nautovacs < MAXAUTOVACPIDS)
                                       autovac_pids[nautovacs++] = proc->pid;
I can see the following counts when the test passes:
...
!!!CountOtherDBBackends[129416]| tries: 45, proc-pid: 129391
!!!CountOtherDBBackends[129416]| tries: 46, proc-pid: 129391
!!!CountOtherDBBackends[129416]| tries: 47, proc-pid: 129391
But the count can also reach 50, then the test fails as below:
...
2026-08-18 06:01:56.058 UTC client backend[170284] 001_basic.pl FATAL:Â terminating connection due to administrator command
2026-08-18 06:01:56.058 UTC client backend[170284] 001_basic.pl DETAIL:Â Signal sent by PID 170453, UID 1001.
2026-08-18 06:01:56.058 UTC datachecksums worker[170446] FATAL: terminating connection due to administrator command
2026-08-18 06:01:56.058 UTC datachecksums worker[170446] DETAIL: Signal sent by PID 170453, UID 1001.
2026-08-18 06:01:56.071 UTC postmaster[169264] LOG:Â background worker "datachecksums worker" (PID 170446) exited with
exit code 1
!!!CountOtherDBBackends[170453]| tries: 1, proc-pid: 170284
!!!CountOtherDBBackends[170453]| tries: 2, proc-pid: 170284
...
!!!CountOtherDBBackends[170453]| tries: 47, proc-pid: 170284
!!!CountOtherDBBackends[170453]| tries: 48, proc-pid: 170284
!!!CountOtherDBBackends[170453]| tries: 49, proc-pid: 170284
2026-08-18 06:02:03.632 UTC client backend[170453] 001_basic.pl ERROR:Â database "dropmeforce" is being accessed by
other users
2026-08-18 06:02:03.632 UTC client backend[170453] 001_basic.pl DETAIL:Â There is 1 other session using the database.
2026-08-18 06:02:03.632 UTC client backend[170453] 001_basic.pl STATEMENT:Â DROP DATABASE dropmeforce WITH (FORCE);
Backtrace of the stuck backend 170284:
 Id  Target Id                                  Frame
* 1Â Â Â Thread 0x3fa7dd6020 (LWP 170284) "postgres" 0x0000003fa72ff1c4 in ?? () from /lib/riscv64-linux-gnu/libc.so.6
#0Â 0x0000003fa72ff1c4 in ?? () from /lib/riscv64-linux-gnu/libc.so.6
#1Â 0x0000003fa7308fa0 in ?? () from /lib/riscv64-linux-gnu/libc.so.6
#2Â 0x0000002abde863a6 in PGSemaphoreLock (sema=0x3fa46f3980) at pg_sema.c:320
#3Â 0x0000002abdf8a858 in LWLockAcquireOrWait (lock=0x3f9b6e6b80, mode=LW_EXCLUSIVE) at lwlock.c:1434
#4Â 0x0000002abdaaba08 in XLogFlush (record=188513088) at xlog.c:2874
#5Â 0x0000002abdaa1250 in RecordTransactionCommit () at xact.c:1544
#6Â 0x0000002abdaa2246 in CommitTransaction () at xact.c:2406
#7Â 0x0000002abdaa3150 in CommitTransactionCommandInternal () at xact.c:3254
#8Â 0x0000002abdaa3080 in CommitTransactionCommand () at xact.c:3215
#9Â 0x0000002abdb0ab44 in RemoveTempRelationsCallback (code=1, arg=0) at namespace.c:4708
#10 0x0000002abdf6290c in shmem_exit (code=1) at ipc.c:250
#11 0x0000002abdf6279a in proc_exit_prepare (code=1) at ipc.c:199
#12 0x0000002abdf626d0 in proc_exit (code=1) at ipc.c:112
#13 0x0000002abe1a2ab4 in errfinish (filename=0x2abe40ddd0 "postgres.c", lineno=3518, funcname=0x2abe40fd80 <__func__.6>
"ProcessInterrupts") at elog.c:608
#14 0x0000002abdfab748 in ProcessInterrupts () at postgres.c:3518
#15 0x0000002abdfa7248 in ProcessClientReadInterrupt (blocked=true) at postgres.c:522
#16 0x0000002abdd40de2 in secure_read (port=0x2abe6ee580, ptr=0x2abe696df0 <PqRecvBuffer>, len=8192) at be-secure.c:251
#17 0x0000002abdd4a47a in pq_recvbuf () at pqcomm.c:921
#18 0x0000002abdd4a56c in pq_getbyte () at pqcomm.c:967
#19 0x0000002abdfa6f0e in SocketBackend (inBuf=0x3fcb500e08) at postgres.c:376
#20 0x0000002abdfa71de in ReadCommand (inBuf=0x3fcb500e08) at postgres.c:499
#21 0x0000002abdfad88a in PostgresMain (dbname=0x2abe76ce48 "dropmeforce", username=0x2abe76ce28 "orangepi") at
postgres.c:4878
#22 0x0000002abdfa2ffa in BackendMain (startup_data=0x3fcb501040, startup_data_len=24) at backend_startup.c:124
#23 0x0000002abde94d0c in postmaster_child_launch (child_type=B_BACKEND, child_slot=1, startup_data=0x3fcb501040,
startup_data_len=24, client_sock=0x3fcb501098) at launch_backend.c:268
#24 0x0000002abde9b85a in BackendStartup (client_sock=0x3fcb501098) at postmaster.c:3627
#25 0x0000002abde98bb0 in ServerLoop () at postmaster.c:1728
#26 0x0000002abde984ba in PostmasterMain (argc=4, argv=0x2abe6ec9e0) at postmaster.c:1415
#27 0x0000002abdd53380 in main (argc=4, argv=0x2abe6ec9e0) at main.c:231
Thus, it's not the checksum worker preventing the DROP, but 001_basic.pl
session.
This seems similar to [3], though this time the animal and the code path
are different.
[1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=turaco&dt=2026-08-13%2021%3A07%3A46
[2] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=turaco&dt=2026-08-15%2019%3A27%3A11
[3] https://www.postgresql.org/message-id/ab4Gf2r-Bd6P7BiW%40paquier.xyz
Best regards,
Alexander
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-18 09:11 Zsolt Parragi <zsolt.parragi@percona.com>
parent: Alexander Lakhin <exclusion@gmail.com>
0 siblings, 1 reply; 17+ messages in thread
From: Zsolt Parragi @ 2026-08-18 09:11 UTC (permalink / raw)
To: Alexander Lakhin <exclusion@gmail.com>; +Cc: Daniel Gustafsson <daniel@yesql.se>; Tomas Vondra <tomas@vondra.me>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Thanks for the report and analysis!
I managed to reproduce it locally by SIGSTOPping the backend just
before the DROP, it fails exactly after 5 seconds with the same error.
The session terminated by DROP DATABASE ... WITH (FORCE) still holds
the temporary table the test uses to hold the worker in place. During
exit, RemoveTempRelationsCallback drops the temp table in a new
transaction, and the commit of that transaction calls XLogFlush. That
flush queues on WALWriteLock behind the WAL the checksum workers just
generated, and CountOtherDBBackends only waits 50 * 100ms, so on slow
storage DROP DATABASE gives up before the flush
completes.
0001 fixes the test. The background session now uses
synchronous_commit = off, so its exit-time commit does not flush at
all, and the test checkpoints right before the DROP so the few
remaining exit-time WAL inserts cannot queue behind a large backlog.
While reproducing this I found another issue: When DROP fails this
way, it has already terminated the checksums worker, so the launcher
sees a dead worker and a database which still exists, and that cancels
the whole operation and reverts the checksum state to off:
ERROR: database "dropmeforce" is being accessed by other users
...
ERROR: data checksums failed to get enabled in all databases, aborting
The same happens if an administrator simply terminates the worker with
pg_terminate_backend.
0002 makes the launcher retry the database in this situation. The
worker records in shared memory when it is terminated by SIGTERM, and
if the database still exists the launcher starts a new worker for it
instead of aborting.
A worker failing still aborts the operation as before, and canceling
the launcher also still works.
Attachments:
[application/octet-stream] 0002-Retry-databases-whose-data-checksums-worker-was-term.patch (10.1K, ../../CAN4CZFMnzPFO4upk7MFGhfgjwZFRdXp1a-9Ggw_56stM+yZC_A@mail.gmail.com/2-0002-Retry-databases-whose-data-checksums-worker-was-term.patch)
download | inline diff:
From 3b6df2f9c4acc0ee1b43e98a6379475c0e902acd Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <zsolt.parragi@percona.com>
Date: Tue, 18 Aug 2026 08:04:12 +0000
Subject: [PATCH 2/2] Retry databases whose data checksums worker was
terminated
When enabling data checksums, a worker which exited without reporting
a result is treated as a processing failure, which aborts the whole
operation and reverts the checksum state to off. Commit 51f55b13a4d
made the launcher treat a killed worker whose database is gone as a
concurrent drop, but when a DROP DATABASE ... WITH (FORCE) kills the
worker and then fails to drop the database, for example by exceeding
the five seconds it waits for terminated backends to exit, the
database still exists and the enable is aborted. The same happens
when an administrator terminates a worker by hand. A terminated
worker did not fail to process its database, so throwing away the
whole operation is both surprising and unnecessary.
To fix, record in shared memory when the worker is terminated by
SIGTERM, and make the launcher retry the database rather than abort
when the database still exists. Each retry requires another explicit
termination, so this cannot loop on its own. A worker failing with an
error still aborts the operation, and canceling the launcher still
aborts it as well.
Discussion: https://postgr.es/m/361531e2-52b5-499c-a126-815f277bbef2@gmail.com
---
src/backend/postmaster/datachecksum_state.c | 85 ++++++++++++++++---
.../modules/test_checksums/t/001_basic.pl | 55 ++++++++++++
2 files changed, 127 insertions(+), 13 deletions(-)
diff --git a/src/backend/postmaster/datachecksum_state.c b/src/backend/postmaster/datachecksum_state.c
index f69258bc33d..6088fbcf721 100644
--- a/src/backend/postmaster/datachecksum_state.c
+++ b/src/backend/postmaster/datachecksum_state.c
@@ -290,6 +290,7 @@ typedef enum
DATACHECKSUMSWORKER_ABORTED,
DATACHECKSUMSWORKER_FAILED,
DATACHECKSUMSWORKER_DROPDB,
+ DATACHECKSUMSWORKER_TERMINATED,
} DataChecksumsWorkerResult;
/*
@@ -349,6 +350,14 @@ typedef struct DataChecksumsStateStruct
/* result, set by worker before exiting */
DataChecksumsWorkerResult worker_result;
+ /*
+ * Set by the worker's SIGTERM handler, to let the launcher tell a
+ * terminated worker from one which hit an error. Written from a signal
+ * handler so not protected by the lock; the launcher resets it before
+ * starting a worker and reads it only after the worker has exited.
+ */
+ volatile sig_atomic_t worker_terminated;
+
/*
* Tells the worker process whether it should also process the shared
* catalogs
@@ -394,6 +403,7 @@ static BgwHandleStatus WaitForDataChecksumsWorkerState(BackgroundWorkerHandle *h
static DataChecksumsWorkerResult ProcessDatabase(DataChecksumsWorkerDatabase *db);
static void launcher_exit(int code, Datum arg);
static void launcher_cancel_handler(SIGNAL_ARGS);
+static void worker_terminate_handler(SIGNAL_ARGS);
static void WaitForAllTransactionsToFinish(void);
static bool ProcessAllDatabases(void);
static void DataChecksumsShmemRequest(void *arg);
@@ -961,6 +971,7 @@ ProcessDatabase(DataChecksumsWorkerDatabase *db)
*/
DataChecksumState->worker_result = DATACHECKSUMSWORKER_FAILED;
DataChecksumState->worker_pid = InvalidPid;
+ DataChecksumState->worker_terminated = false;
invocation = ++DataChecksumState->worker_invocation_counter;
DataChecksumState->worker_invocation = invocation;
@@ -1029,12 +1040,17 @@ ProcessDatabase(DataChecksumsWorkerDatabase *db)
/*
* Heuristic to see if the database was dropped, and if it was we can
- * treat it as not an error, else treat as fatal and error out.
+ * treat it as not an error, else treat as fatal and error out. A
+ * worker terminated this early, e.g. by a DROP DATABASE ... WITH
+ * (FORCE) arriving while it was still connecting, is not an error
+ * either but the database has to be retried.
*/
- if (DatabaseExists(db->dboid))
- return DATACHECKSUMSWORKER_FAILED;
- else
+ if (!DatabaseExists(db->dboid))
return DATACHECKSUMSWORKER_DROPDB;
+ else if (DataChecksumState->worker_terminated)
+ return DATACHECKSUMSWORKER_TERMINATED;
+ else
+ return DATACHECKSUMSWORKER_FAILED;
}
/*
@@ -1085,9 +1101,17 @@ ProcessDatabase(DataChecksumsWorkerDatabase *db)
* likely FATALed in InitPostgres. If the database was dropped after we
* built the database list then that is the expected outcome and not an
* error, so apply the same heuristic as when the worker failed to start.
+ *
+ * If the database still exists but the worker was terminated, e.g. by a
+ * DROP DATABASE ... WITH (FORCE) which then failed to drop the database,
+ * the worker did not hit an error either, but the database still has to
+ * be processed. Report that separately so the launcher can retry it.
*/
if (result == DATACHECKSUMSWORKER_FAILED && !DatabaseExists(db->dboid))
result = DATACHECKSUMSWORKER_DROPDB;
+ else if (result == DATACHECKSUMSWORKER_FAILED &&
+ DataChecksumState->worker_terminated)
+ result = DATACHECKSUMSWORKER_TERMINATED;
CHECK_FOR_LAUNCHER_ABORT_REQUEST();
if (abort_requested)
@@ -1166,6 +1190,23 @@ launcher_cancel_handler(SIGNAL_ARGS)
errno = save_errno;
}
+/*
+ * worker_terminate_handler
+ *
+ * SIGTERM handler for the worker process. Record that the worker is being
+ * terminated before performing the normal die() processing, so that the
+ * launcher can tell a terminated worker from one which hit an error: a
+ * terminated worker is not a processing failure and its database is retried,
+ * while an error aborts the whole operation.
+ */
+static void
+worker_terminate_handler(SIGNAL_ARGS)
+{
+ DataChecksumState->worker_terminated = true;
+
+ die(postgres_signal_arg, pg_siginfo);
+}
+
/*
* WaitForAllTransactionsToFinish
* Blocks awaiting all current transactions to finish
@@ -1431,18 +1472,36 @@ ProcessAllDatabases(void)
{
DataChecksumsWorkerResult result;
- result = ProcessDatabase(db);
+ for (;;)
+ {
+ result = ProcessDatabase(db);
#ifdef USE_INJECTION_POINTS
- /* Allow a test process to alter the result of the operation */
- if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fail-db-result"))
- {
- result = DATACHECKSUMSWORKER_FAILED;
- INJECTION_POINT_CACHED("datachecksumsworker-fail-db-result",
- db->dbname);
- }
+ /* Allow a test process to alter the result of the operation */
+ if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fail-db-result"))
+ {
+ result = DATACHECKSUMSWORKER_FAILED;
+ INJECTION_POINT_CACHED("datachecksumsworker-fail-db-result",
+ db->dbname);
+ }
#endif
+ if (result != DATACHECKSUMSWORKER_TERMINATED)
+ break;
+
+ /*
+ * The worker was terminated without hitting an error, and the
+ * database still exists. Start a new worker for it, since the
+ * database has to be processed for the operation to complete.
+ * Each retry requires another explicit termination, so this
+ * cannot loop on its own, and aborting the operation remains
+ * possible by canceling the launcher.
+ */
+ ereport(LOG,
+ errmsg("data checksum processing was interrupted in database \"%s\", retrying",
+ db->dbname));
+ }
+
pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_DBS_DONE,
++cumulative_total);
@@ -1747,7 +1806,7 @@ DataChecksumsWorkerMain(Datum arg)
operation = ENABLE_DATACHECKSUMS;
- pqsignal(SIGTERM, die);
+ pqsignal(SIGTERM, worker_terminate_handler);
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
BackgroundWorkerUnblockSignals();
diff --git a/src/test/modules/test_checksums/t/001_basic.pl b/src/test/modules/test_checksums/t/001_basic.pl
index 53fe8d70dc9..f1618daa04c 100644
--- a/src/test/modules/test_checksums/t/001_basic.pl
+++ b/src/test/modules/test_checksums/t/001_basic.pl
@@ -183,6 +183,61 @@ $node->poll_query_until('postgres',
$result = $node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1");
is($result, '10000', 'ensure checksummed pages can be read back');
+# A worker terminated while its database still exists, for example by a
+# DROP DATABASE ... WITH (FORCE) which then failed to drop the database, did
+# not fail to process it. The launcher must retry the database rather than
+# abort the whole operation.
+disable_data_checksums($node, wait => 1);
+
+$node->safe_psql('postgres', "CREATE DATABASE killme;");
+$node->safe_psql('killme',
+ "CREATE TABLE killme_t AS SELECT generate_series(1,10000) AS a;");
+
+# Hold the worker inside "killme" by keeping a temporary table around.
+$bg = $node->background_psql('killme');
+$bg->query_safe('CREATE TEMP TABLE holdme (a int);');
+
+enable_data_checksums($node);
+
+$node->poll_query_until(
+ 'postgres', qq[
+ SELECT count(*) > 0 FROM pg_stat_activity
+ WHERE backend_type = 'datachecksums worker' AND datname = 'killme'
+ AND query LIKE 'Waiting for % temp tables to be removed']
+) or die "timed out waiting for worker to wait for temporary tables";
+
+my $worker_pid = $node->safe_psql(
+ 'postgres', qq[
+ SELECT pid FROM pg_stat_activity
+ WHERE backend_type = 'datachecksums worker' AND datname = 'killme']);
+$node->safe_psql('postgres', "SELECT pg_terminate_backend($worker_pid);");
+
+# The launcher starts a replacement worker, which waits for the temp table
+# just like the terminated one did.
+$node->poll_query_until(
+ 'postgres', qq[
+ SELECT count(*) > 0 FROM pg_stat_activity
+ WHERE backend_type = 'datachecksums worker' AND datname = 'killme'
+ AND pid <> $worker_pid
+ AND query LIKE 'Waiting for % temp tables to be removed']
+) or die "timed out waiting for replacement worker";
+
+$log = slurp_file($node->logfile);
+like(
+ $log,
+ qr/data checksum processing was interrupted in database "killme", retrying/,
+ 'retry of the terminated worker is logged');
+
+# Release the replacement worker and let the operation complete.
+$bg->query_safe('DROP TABLE holdme;');
+$bg->quit;
+
+wait_for_checksum_state($node, 'on');
+$node->poll_query_until('postgres',
+ "SELECT count(*) = 0 "
+ . "FROM pg_catalog.pg_stat_activity "
+ . "WHERE backend_type = 'datachecksums launcher';");
+
$node->stop;
# The resulting cluster must also pass offline verification, proving no
--
2.54.0
[application/octet-stream] 0001-Stabilize-the-FORCE-drop-test-for-online-data-checks.patch (2.8K, ../../CAN4CZFMnzPFO4upk7MFGhfgjwZFRdXp1a-9Ggw_56stM+yZC_A@mail.gmail.com/3-0001-Stabilize-the-FORCE-drop-test-for-online-data-checks.patch)
download | inline diff:
From c1c82316e2d8e34077b108e8f581b9671a4079ea Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <zsolt.parragi@percona.com>
Date: Tue, 18 Aug 2026 07:44:29 +0000
Subject: [PATCH 1/2] Stabilize the FORCE drop test for online data checksums
Commit 51f55b13a4d added a test where DROP DATABASE ... WITH (FORCE)
terminates a session holding a temporary table in the target database.
While exiting, the terminated session drops its temporary table and
commits, and the commit waits for a WAL flush behind the backlog
generated by the checksum workers. On machines with slow storage this
can exceed the five seconds DROP DATABASE waits for terminated backends
to exit, making the test fail with "database "dropmeforce" is being
accessed by other users", as observed on buildfarm member turaco.
To fix, use asynchronous commit in the terminated session, so that its
exit does not wait for a WAL flush, and checkpoint before the drop so
that the exit-time WAL records do not queue up behind the backlog.
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/361531e2-52b5-499c-a126-815f277bbef2@gmail.com
---
src/test/modules/test_checksums/t/001_basic.pl | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/test/modules/test_checksums/t/001_basic.pl b/src/test/modules/test_checksums/t/001_basic.pl
index 72e0d0df46f..53fe8d70dc9 100644
--- a/src/test/modules/test_checksums/t/001_basic.pl
+++ b/src/test/modules/test_checksums/t/001_basic.pl
@@ -145,8 +145,13 @@ $node->safe_psql('dropmeforce',
"CREATE TABLE dropme_t AS SELECT generate_series(1,10000) AS a;");
# Hold the worker inside "dropmeforce" by keeping a temporary table around
-# there.
+# there. The session is later terminated by DROP DATABASE ... WITH (FORCE)
+# and drops the temp table while exiting; commit that drop asynchronously,
+# otherwise the exit has to flush WAL behind the traffic generated by the
+# checksum workers, which on slow machines can exceed the time DROP DATABASE
+# waits for the session to exit.
$bg = $node->background_psql('dropmeforce');
+$bg->query_safe('SET synchronous_commit = off;');
$bg->query_safe('CREATE TEMP TABLE holdme (a int);');
enable_data_checksums($node);
@@ -158,6 +163,11 @@ $node->poll_query_until(
AND query LIKE 'Waiting for % temp tables to be removed']
) or die "timed out waiting for worker to wait for temporary tables";
+# Write out the WAL backlog from the checksum processing so far, so that the
+# sessions terminated below do not get stuck behind it when writing their
+# final WAL records on slow machines.
+$node->safe_psql('postgres', "CHECKPOINT;");
+
# Terminates both the session holding the temp table and the checksums
# worker connected to the database.
$node->safe_psql('postgres', "DROP DATABASE dropmeforce WITH (FORCE);");
--
2.54.0
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-18 22:12 Daniel Gustafsson <daniel@yesql.se>
parent: Zsolt Parragi <zsolt.parragi@percona.com>
0 siblings, 1 reply; 17+ messages in thread
From: Daniel Gustafsson @ 2026-08-18 22:12 UTC (permalink / raw)
To: Zsolt Parragi <zsolt.parragi@percona.com>; +Cc: Alexander Lakhin <exclusion@gmail.com>; Tomas Vondra <tomas@vondra.me>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
> On 18 Aug 2026, at 11:11, Zsolt Parragi <zsolt.parragi@percona.com> wrote:
>
> Thanks for the report and analysis!
Indeed, thanks Alexander! Stellar work as always.
> 0001 fixes the test. The background session now uses
> synchronous_commit = off, so its exit-time commit does not flush at
> all, and the test checkpoints right before the DROP so the few
> remaining exit-time WAL inserts cannot queue behind a large backlog.
Thanks for the patch, I agree with your fix and have tested it extensively
locally and in CI. After staring at it a bit more, I pushed and backpatched
it.
> 0002 makes the launcher retry the database in this situation. The
> worker records in shared memory when it is terminated by SIGTERM, and
> if the database still exists the launcher starts a new worker for it
> instead of aborting.
> A worker failing still aborts the operation as before, and canceling
> the launcher also still works.
I'm not entirely convinced about the UX around user termination of the worker
so need more time pondering on this one.
--
Daniel Gustafsson
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-25 19:32 Nathan Bossart <nathandbossart@gmail.com>
parent: Daniel Gustafsson <daniel@yesql.se>
0 siblings, 1 reply; 17+ messages in thread
From: Nathan Bossart @ 2026-08-25 19:32 UTC (permalink / raw)
To: Daniel Gustafsson <daniel@yesql.se>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; Alexander Lakhin <exclusion@gmail.com>; Tomas Vondra <tomas@vondra.me>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Does this one deserve a mention on the open items wiki [0]?
[0] https://wiki.postgresql.org/wiki/PostgreSQL_19_Open_Items
--
nathan
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-26 21:48 Daniel Gustafsson <daniel@yesql.se>
parent: Nathan Bossart <nathandbossart@gmail.com>
0 siblings, 1 reply; 17+ messages in thread
From: Daniel Gustafsson @ 2026-08-26 21:48 UTC (permalink / raw)
To: Nathan Bossart <nathandbossart@gmail.com>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; Alexander Lakhin <exclusion@gmail.com>; Tomas Vondra <tomas@vondra.me>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
> On 25 Aug 2026, at 21:32, Nathan Bossart <nathandbossart@gmail.com> wrote:
>
> Does this one deserve a mention on the open items wiki [0]?
I don't think this is an open item; the code as it stands reverts back to a
safe state in the case of a failed DROP. The same goes for if a user
terminates the worker process, maybe there is a UX change to consider in a
future version but it's not broken the way it is (as in, it reverts to a safe
state). Do you agree with this Zsolt or an I missing an active bug?
--
Daniel Gustafsson
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-26 21:59 Nathan Bossart <nathandbossart@gmail.com>
parent: Daniel Gustafsson <daniel@yesql.se>
0 siblings, 2 replies; 17+ messages in thread
From: Nathan Bossart @ 2026-08-26 21:59 UTC (permalink / raw)
To: Daniel Gustafsson <daniel@yesql.se>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; Alexander Lakhin <exclusion@gmail.com>; Tomas Vondra <tomas@vondra.me>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
On Wed, Aug 26, 2026 at 11:48:36PM +0200, Daniel Gustafsson wrote:
>> On 25 Aug 2026, at 21:32, Nathan Bossart <nathandbossart@gmail.com> wrote:
>>
>> Does this one deserve a mention on the open items wiki [0]?
>
> I don't think this is an open item; the code as it stands reverts back to a
> safe state in the case of a failed DROP. The same goes for if a user
> terminates the worker process, maybe there is a UX change to consider in a
> future version but it's not broken the way it is (as in, it reverts to a safe
> state). Do you agree with this Zsolt or an I missing an active bug?
Okay. I added one before you sent this message. Provided Zsolt agrees, I
will remove it.
--
nathan
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-26 22:02 Daniel Gustafsson <daniel@yesql.se>
parent: Nathan Bossart <nathandbossart@gmail.com>
1 sibling, 0 replies; 17+ messages in thread
From: Daniel Gustafsson @ 2026-08-26 22:02 UTC (permalink / raw)
To: Nathan Bossart <nathandbossart@gmail.com>; +Cc: Zsolt Parragi <zsolt.parragi@percona.com>; Alexander Lakhin <exclusion@gmail.com>; Tomas Vondra <tomas@vondra.me>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
> On 26 Aug 2026, at 23:59, Nathan Bossart <nathandbossart@gmail.com> wrote:
>
> On Wed, Aug 26, 2026 at 11:48:36PM +0200, Daniel Gustafsson wrote:
>>> On 25 Aug 2026, at 21:32, Nathan Bossart <nathandbossart@gmail.com> wrote:
>>>
>>> Does this one deserve a mention on the open items wiki [0]?
>>
>> I don't think this is an open item; the code as it stands reverts back to a
>> safe state in the case of a failed DROP. The same goes for if a user
>> terminates the worker process, maybe there is a UX change to consider in a
>> future version but it's not broken the way it is (as in, it reverts to a safe
>> state). Do you agree with this Zsolt or an I missing an active bug?
>
> Okay. I added one before you sent this message. Provided Zsolt agrees, I
> will remove it.
+1, sounds good.
--
Daniel Gustafsson
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-26 22:06 Zsolt Parragi <zsolt.parragi@percona.com>
parent: Nathan Bossart <nathandbossart@gmail.com>
1 sibling, 1 reply; 17+ messages in thread
From: Zsolt Parragi @ 2026-08-26 22:06 UTC (permalink / raw)
To: Nathan Bossart <nathandbossart@gmail.com>; +Cc: Daniel Gustafsson <daniel@yesql.se>; Alexander Lakhin <exclusion@gmail.com>; Tomas Vondra <tomas@vondra.me>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
I agree. It is about automatically continuing instead of stopping in a
very unlikely scenario (DROP DATABASE FORCE failing), and also a more
questionable ux change on how manual process termination behaves. Both
the current and patched versions behave correctly.
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: datachecksums: handle invalid and dropped databases during enable
@ 2026-08-26 22:07 Nathan Bossart <nathandbossart@gmail.com>
parent: Zsolt Parragi <zsolt.parragi@percona.com>
0 siblings, 0 replies; 17+ messages in thread
From: Nathan Bossart @ 2026-08-26 22:07 UTC (permalink / raw)
To: Zsolt Parragi <zsolt.parragi@percona.com>; +Cc: Daniel Gustafsson <daniel@yesql.se>; Alexander Lakhin <exclusion@gmail.com>; Tomas Vondra <tomas@vondra.me>; Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
On Wed, Aug 26, 2026 at 11:06:20PM +0100, Zsolt Parragi wrote:
> I agree. It is about automatically continuing instead of stopping in a
> very unlikely scenario (DROP DATABASE FORCE failing), and also a more
> questionable ux change on how manual process termination behaves. Both
> the current and patched versions behave correctly.
Thanks for chiming in. I've removed the open item.
--
nathan
^ permalink raw reply [nested|flat] 17+ messages in thread
end of thread, other threads:[~2026-08-26 22:07 UTC | newest]
Thread overview: 17+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-07-28 10:01 datachecksums: handle invalid and dropped databases during enable Zsolt Parragi <zsolt.parragi@percona.com>
2026-07-28 13:13 ` Daniel Gustafsson <daniel@yesql.se>
2026-07-29 12:00 ` r314tive <tanswis42@gmail.com>
2026-07-29 12:24 ` Daniel Gustafsson <daniel@yesql.se>
2026-07-30 17:56 ` Ayush Tiwari <ayushtiwari.slg01@gmail.com>
2026-07-30 22:02 ` Zsolt Parragi <zsolt.parragi@percona.com>
2026-08-03 12:14 ` Ayush Tiwari <ayushtiwari.slg01@gmail.com>
2026-08-03 15:01 ` Daniel Gustafsson <daniel@yesql.se>
2026-08-18 07:00 ` Alexander Lakhin <exclusion@gmail.com>
2026-08-18 09:11 ` Zsolt Parragi <zsolt.parragi@percona.com>
2026-08-18 22:12 ` Daniel Gustafsson <daniel@yesql.se>
2026-08-25 19:32 ` Nathan Bossart <nathandbossart@gmail.com>
2026-08-26 21:48 ` Daniel Gustafsson <daniel@yesql.se>
2026-08-26 21:59 ` Nathan Bossart <nathandbossart@gmail.com>
2026-08-26 22:02 ` Daniel Gustafsson <daniel@yesql.se>
2026-08-26 22:06 ` Zsolt Parragi <zsolt.parragi@percona.com>
2026-08-26 22:07 ` Nathan Bossart <nathandbossart@gmail.com>
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox