From 1177c54ce37ccc125bed9d96912e8b09296c67b2 Mon Sep 17 00:00:00 2001 From: Andrey Borodin Date: Mon, 6 Jul 2026 12:17:58 +0500 Subject: [PATCH] Make ycmdb.shared_archive runtime-changeable and add space saver Change ycmdb.shared_archive from PGC_POSTMASTER to PGC_SIGHUP so the shared archive behavior can be toggled without a server restart. Add a new GUC ycmdb.shared_archive_space_saver (PGC_SIGHUP). When enabled on a standby it disables the shared-archive WAL retention: the walreceiver forces streamed segments to .done instead of holding them as .ready, and XLogArchiveCheckDone() lets checkpoint recycle such segments during recovery. This lets a disk-usage watcher relieve a standby that would otherwise accumulate unarchived WAL until it fills the disk and fails over (e.g. while the shared archive storage is unavailable). The trade-off is a gap in the archived WAL history; the flag has no effect on a primary. The new SharedArchiveRetentionActive() macro expresses "shared archive is active and retention is not overridden" and is used in the two retention decision points. --- src/backend/access/transam/xlog.c | 3 +++ src/backend/access/transam/xlogarchive.c | 6 +++++- src/backend/replication/walreceiver.c | 6 +++++- src/backend/utils/misc/guc_tables.c | 13 ++++++++++++- src/include/access/xlog.h | 15 +++++++++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 1e069187383..18c75c6ec06 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -122,6 +122,9 @@ int XLOGbuffers = -1; int XLogArchiveTimeout = 0; int XLogArchiveMode = ARCHIVE_MODE_OFF; bool ycmdb_shared_archive = false; /* makes archive_mode=on act as shared */ +bool ycmdb_shared_archive_space_saver = false; /* disable shared WAL + * retention on a standby + * to save disk space */ char *XLogArchiveCommand = NULL; bool EnableHotStandby = false; bool fullPageWrites = true; diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index 72c82e0902b..36bd725f006 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -581,8 +581,12 @@ XLogArchiveCheckDone(const char *xlog) * walreceiver converts the .ready file to .done. We must therefore fall * through to the .done/.ready check below so that checkpoint cannot * delete a segment whose .ready file has not yet become .done. + * + * The space_saver override (ycmdb.shared_archive_space_saver) turns this + * retention off again, allowing checkpoint to recycle .ready segments to + * free disk space (at the cost of a gap in the archived WAL history). */ - if (!XLogArchivingAlways() && !EffectiveArchiveModeIsShared() && + if (!XLogArchivingAlways() && !SharedArchiveRetentionActive() && GetRecoveryState() == RECOVERY_STATE_ARCHIVE) return true; diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index cf1acd4f93f..2d9d101e374 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -1114,12 +1114,16 @@ XLogWalRcvClose(XLogRecPtr recptr, TimeLineID tli) * In 'shared' mode, we optimize by checking if this segment is already * covered by the last archival report from the primary. If so, create * .done directly. Otherwise, create .ready and wait for the next report. + * + * The space_saver override (ycmdb.shared_archive_space_saver) disables the + * shared retention path: we force .done so the segment can be recycled + * immediately instead of waiting for an archival report. */ if (XLogArchiveMode == ARCHIVE_MODE_ALWAYS) { XLogArchiveNotify(xlogfname); } - else if (EffectiveArchiveModeIsShared()) + else if (SharedArchiveRetentionActive()) { /* * In shared mode, check if this segment is already archived on primary. diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index 00a4081eb15..c590e1055e9 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -1193,7 +1193,7 @@ struct config_bool ConfigureNamesBool[] = }, { - {"ycmdb.shared_archive", PGC_POSTMASTER, WAL_ARCHIVING, + {"ycmdb.shared_archive", PGC_SIGHUP, WAL_ARCHIVING, gettext_noop("Makes archive_mode=on behave as shared (for managed service compatibility)."), gettext_noop("When true, archive_mode=on is treated as archive_mode=shared. Does not affect archive_mode=off or archive_mode=always. Used when control plane cannot configure archive_mode=shared directly."), GUC_NOT_IN_SAMPLE @@ -1203,6 +1203,17 @@ struct config_bool ConfigureNamesBool[] = NULL, NULL, NULL }, + { + {"ycmdb.shared_archive_space_saver", PGC_SIGHUP, WAL_ARCHIVING, + gettext_noop("Disables shared archive WAL retention on a standby to save disk space."), + gettext_noop("When true, a standby stops holding not-yet-archived WAL segments as .ready and allows them to be recycled, even in shared archive mode. This prevents the standby from filling its disk (and failing over) while the shared archive storage is unavailable, at the cost of a gap in the archived WAL history. Has no effect on a primary."), + GUC_NOT_IN_SAMPLE + }, + &ycmdb_shared_archive_space_saver, + false, + NULL, NULL, NULL + }, + { {"wal_init_zero", PGC_SUSET, WAL_SETTINGS, gettext_noop("Writes zeroes to new WAL files before first use."), diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 3b2dcd800cd..0f1b36057ce 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -64,6 +64,7 @@ typedef enum ArchiveMode } ArchiveMode; extern PGDLLIMPORT int XLogArchiveMode; extern PGDLLIMPORT bool ycmdb_shared_archive; +extern PGDLLIMPORT bool ycmdb_shared_archive_space_saver; /* * True when shared archive behavior is active: either archive_mode=shared @@ -73,6 +74,20 @@ extern PGDLLIMPORT bool ycmdb_shared_archive; (XLogArchiveMode == ARCHIVE_MODE_SHARED || \ (XLogArchiveMode == ARCHIVE_MODE_ON && ycmdb_shared_archive)) +/* + * True when this node must retain (pin) not-yet-archived WAL because of shared + * archive mode. In shared mode a standby keeps segments as .ready until the + * primary reports them archived, which normally prevents WAL loss on failover. + * + * The ycmdb.shared_archive_space_saver override disables this retention on a + * standby so that WAL can be recycled under disk pressure (e.g. when the shared + * archive storage is unavailable and .ready files would otherwise accumulate + * until the disk fills up and the standby fails over). The trade-off is a gap + * in the archived WAL history for the affected segments. + */ +#define SharedArchiveRetentionActive() \ + (EffectiveArchiveModeIsShared() && !ycmdb_shared_archive_space_saver) + /* WAL levels */ typedef enum WalLevel {