1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-20 05:03:10 +03:00

Change unit of idle_replication_slot_timeout to seconds.

Previously, the idle_replication_slot_timeout parameter used minutes
as its unit, based on the assumption that values would typically exceed
one minute in production environments. However, this caused unexpected
behavior: specifying a value below 30 seconds would round down to 0,
effectively disabling the timeout. This could be surprising to users.

To allow finer-grained control and avoid such confusion, this commit changes
the unit of idle_replication_slot_timeout to seconds. Larger values can
still be specified easily using standard time suffixes, for example,
'24h' for 24 hours.

Back-patch to v18 where idle_replication_slot_timeout was added.

Reported-by: Gunnar Morling <gunnar.morling@googlemail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at>
Reviewed-by: David G. Johnston <david.g.johnston@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CADGJaX_0+FTguWpNSpgVWYQP_7MhoO0D8=cp4XozSQgaZ40Odw@mail.gmail.com
Backpatch-through: 18
This commit is contained in:
Fujii Masao
2025-07-11 08:39:24 +09:00
parent a6c0bf9303
commit 05dedf43d3
5 changed files with 15 additions and 18 deletions

View File

@ -4620,7 +4620,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
<para> <para>
Invalidate replication slots that have remained idle longer than this Invalidate replication slots that have remained idle longer than this
duration. If this value is specified without units, it is taken as duration. If this value is specified without units, it is taken as
minutes. A value of zero (the default) disables the idle timeout seconds. A value of zero (the default) disables the idle timeout
invalidation mechanism. This parameter can only be set in the invalidation mechanism. This parameter can only be set in the
<filename>postgresql.conf</filename> file or on the server command <filename>postgresql.conf</filename> file or on the server command
line. line.

View File

@ -154,7 +154,7 @@ int max_replication_slots = 10; /* the maximum number of replication
* Invalidate replication slots that have remained idle longer than this * Invalidate replication slots that have remained idle longer than this
* duration; '0' disables it. * duration; '0' disables it.
*/ */
int idle_replication_slot_timeout_mins = 0; int idle_replication_slot_timeout_secs = 0;
/* /*
* This GUC lists streaming replication standby server slot names that * This GUC lists streaming replication standby server slot names that
@ -1612,13 +1612,10 @@ ReportSlotInvalidation(ReplicationSlotInvalidationCause cause,
case RS_INVAL_IDLE_TIMEOUT: case RS_INVAL_IDLE_TIMEOUT:
{ {
int minutes = slot_idle_seconds / SECS_PER_MINUTE;
int secs = slot_idle_seconds % SECS_PER_MINUTE;
/* translator: %s is a GUC variable name */ /* translator: %s is a GUC variable name */
appendStringInfo(&err_detail, _("The slot's idle time of %dmin %02ds exceeds the configured \"%s\" duration of %dmin."), appendStringInfo(&err_detail, _("The slot's idle time of %lds exceeds the configured \"%s\" duration of %ds."),
minutes, secs, "idle_replication_slot_timeout", slot_idle_seconds, "idle_replication_slot_timeout",
idle_replication_slot_timeout_mins); idle_replication_slot_timeout_secs);
/* translator: %s is a GUC variable name */ /* translator: %s is a GUC variable name */
appendStringInfo(&err_hint, _("You might need to increase \"%s\"."), appendStringInfo(&err_hint, _("You might need to increase \"%s\"."),
"idle_replication_slot_timeout"); "idle_replication_slot_timeout");
@ -1656,7 +1653,7 @@ ReportSlotInvalidation(ReplicationSlotInvalidationCause cause,
static inline bool static inline bool
CanInvalidateIdleSlot(ReplicationSlot *s) CanInvalidateIdleSlot(ReplicationSlot *s)
{ {
return (idle_replication_slot_timeout_mins != 0 && return (idle_replication_slot_timeout_secs != 0 &&
!XLogRecPtrIsInvalid(s->data.restart_lsn) && !XLogRecPtrIsInvalid(s->data.restart_lsn) &&
s->inactive_since > 0 && s->inactive_since > 0 &&
!(RecoveryInProgress() && s->data.synced)); !(RecoveryInProgress() && s->data.synced));
@ -1717,9 +1714,9 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
if (CanInvalidateIdleSlot(s)) if (CanInvalidateIdleSlot(s))
{ {
/* /*
* We simulate the invalidation due to idle_timeout as the minimum * Simulate the invalidation due to idle_timeout to test the
* time idle time is one minute which makes tests take a long * timeout behavior promptly, without waiting for it to trigger
* time. * naturally.
*/ */
#ifdef USE_INJECTION_POINTS #ifdef USE_INJECTION_POINTS
if (IS_INJECTION_POINT_ATTACHED("slot-timeout-inval")) if (IS_INJECTION_POINT_ATTACHED("slot-timeout-inval"))
@ -1734,7 +1731,7 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
* idle_replication_slot_timeout GUC. * idle_replication_slot_timeout GUC.
*/ */
if (TimestampDifferenceExceedsSeconds(s->inactive_since, now, if (TimestampDifferenceExceedsSeconds(s->inactive_since, now,
idle_replication_slot_timeout_mins * SECS_PER_MINUTE)) idle_replication_slot_timeout_secs))
{ {
*inactive_since = s->inactive_since; *inactive_since = s->inactive_since;
return RS_INVAL_IDLE_TIMEOUT; return RS_INVAL_IDLE_TIMEOUT;

View File

@ -3100,10 +3100,10 @@ struct config_int ConfigureNamesInt[] =
gettext_noop("Sets the duration a replication slot can remain idle before " gettext_noop("Sets the duration a replication slot can remain idle before "
"it is invalidated."), "it is invalidated."),
NULL, NULL,
GUC_UNIT_MIN GUC_UNIT_S
}, },
&idle_replication_slot_timeout_mins, &idle_replication_slot_timeout_secs,
0, 0, INT_MAX / SECS_PER_MINUTE, 0, 0, INT_MAX,
check_idle_replication_slot_timeout, NULL, NULL check_idle_replication_slot_timeout, NULL, NULL
}, },

View File

@ -342,7 +342,7 @@
# (change requires restart) # (change requires restart)
#wal_keep_size = 0 # in megabytes; 0 disables #wal_keep_size = 0 # in megabytes; 0 disables
#max_slot_wal_keep_size = -1 # in megabytes; -1 disables #max_slot_wal_keep_size = -1 # in megabytes; -1 disables
#idle_replication_slot_timeout = 0 # in minutes; 0 disables #idle_replication_slot_timeout = 0 # in seconds; 0 disables
#wal_sender_timeout = 60s # in milliseconds; 0 disables #wal_sender_timeout = 60s # in milliseconds; 0 disables
#track_commit_timestamp = off # collect timestamp of transaction commit #track_commit_timestamp = off # collect timestamp of transaction commit
# (change requires restart) # (change requires restart)

View File

@ -266,7 +266,7 @@ extern PGDLLIMPORT ReplicationSlot *MyReplicationSlot;
/* GUCs */ /* GUCs */
extern PGDLLIMPORT int max_replication_slots; extern PGDLLIMPORT int max_replication_slots;
extern PGDLLIMPORT char *synchronized_standby_slots; extern PGDLLIMPORT char *synchronized_standby_slots;
extern PGDLLIMPORT int idle_replication_slot_timeout_mins; extern PGDLLIMPORT int idle_replication_slot_timeout_secs;
/* shmem initialization functions */ /* shmem initialization functions */
extern Size ReplicationSlotsShmemSize(void); extern Size ReplicationSlotsShmemSize(void);