diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index a3ab2eea72..dd2492f043 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -120,6 +120,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 2e0e07dc6c..cdb8a2a7de 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -617,8 +617,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 79044106c6..21b5edab98 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -1093,12 +1093,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.c b/src/backend/utils/misc/guc.c index 48171d578f..4ff97703a3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1385,7 +1385,7 @@ static 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 @@ -1395,6 +1395,17 @@ static 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 ac38aba3a0..07aa959cd3 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 {