1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-26 01:22:12 +03:00

Avoid updating inactive_since for invalid replication slots.

It is possible for the inactive_since value of an invalid replication slot
to be updated multiple times, which is unexpected behavior like during the
release of the slot or at the time of restart. This is harmless because
invalid slots are not allowed to be accessed but it is not prudent to
update invalid slots. We are planning to invalidate slots due to other
reasons like idle time and it will look odd that the slot's inactive_since
displays the recent time in this field after invalidated due to idle time.
So, this patch ensures that the inactive_since field of slots is not
updated for invalid slots.

In the passing, ensure to use the same inactive_since time for all the
slots at restart while restoring them from the disk.

Author: Nisha Moond <nisha.moond412@gmail.com>
Author: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Vignesh C <vignesh21@gmail.com>
Reviewed-by: Peter Smith <smithpb2250@gmail.com>
Reviewed-by: Hou Zhijie <houzj.fnst@fujitsu.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/CABdArM7QdifQ_MHmMA=Cc4v8+MeckkwKncm2Nn6tX9wSCQ-+iw@mail.gmail.com
This commit is contained in:
Amit Kapila
2025-02-05 08:56:14 +05:30
parent b2bdb972c0
commit 0ec3c295e7
4 changed files with 30 additions and 15 deletions

View File

@ -2566,7 +2566,8 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
</para> </para>
<para> <para>
The time when the slot became inactive. <literal>NULL</literal> if the The time when the slot became inactive. <literal>NULL</literal> if the
slot is currently being streamed. slot is currently being streamed. If the slot becomes invalid,
this value will never be updated.
Note that for slots on the standby that are being synced from a Note that for slots on the standby that are being synced from a
primary server (whose <structfield>synced</structfield> field is primary server (whose <structfield>synced</structfield> field is
<literal>true</literal>), the <structfield>inactive_since</structfield> <literal>true</literal>), the <structfield>inactive_since</structfield>

View File

@ -1541,9 +1541,7 @@ update_synced_slots_inactive_since(void)
if (now == 0) if (now == 0)
now = GetCurrentTimestamp(); now = GetCurrentTimestamp();
SpinLockAcquire(&s->mutex); ReplicationSlotSetInactiveSince(s, now, true);
s->inactive_since = now;
SpinLockRelease(&s->mutex);
} }
} }

View File

@ -644,9 +644,7 @@ retry:
* Reset the time since the slot has become inactive as the slot is active * Reset the time since the slot has become inactive as the slot is active
* now. * now.
*/ */
SpinLockAcquire(&s->mutex); ReplicationSlotSetInactiveSince(s, 0, true);
s->inactive_since = 0;
SpinLockRelease(&s->mutex);
if (am_walsender) if (am_walsender)
{ {
@ -720,16 +718,12 @@ ReplicationSlotRelease(void)
*/ */
SpinLockAcquire(&slot->mutex); SpinLockAcquire(&slot->mutex);
slot->active_pid = 0; slot->active_pid = 0;
slot->inactive_since = now; ReplicationSlotSetInactiveSince(slot, now, false);
SpinLockRelease(&slot->mutex); SpinLockRelease(&slot->mutex);
ConditionVariableBroadcast(&slot->active_cv); ConditionVariableBroadcast(&slot->active_cv);
} }
else else
{ ReplicationSlotSetInactiveSince(slot, now, true);
SpinLockAcquire(&slot->mutex);
slot->inactive_since = now;
SpinLockRelease(&slot->mutex);
}
MyReplicationSlot = NULL; MyReplicationSlot = NULL;
@ -2218,6 +2212,7 @@ RestoreSlotFromDisk(const char *name)
bool restored = false; bool restored = false;
int readBytes; int readBytes;
pg_crc32c checksum; pg_crc32c checksum;
TimestampTz now = 0;
/* no need to lock here, no concurrent access allowed yet */ /* no need to lock here, no concurrent access allowed yet */
@ -2408,9 +2403,13 @@ RestoreSlotFromDisk(const char *name)
/* /*
* Set the time since the slot has become inactive after loading the * Set the time since the slot has become inactive after loading the
* slot from the disk into memory. Whoever acquires the slot i.e. * slot from the disk into memory. Whoever acquires the slot i.e.
* makes the slot active will reset it. * makes the slot active will reset it. Use the same inactive_since
* time for all the slots.
*/ */
slot->inactive_since = GetCurrentTimestamp(); if (now == 0)
now = GetCurrentTimestamp();
ReplicationSlotSetInactiveSince(slot, now, false);
restored = true; restored = true;
break; break;

View File

@ -228,6 +228,23 @@ typedef struct ReplicationSlotCtlData
ReplicationSlot replication_slots[1]; ReplicationSlot replication_slots[1];
} ReplicationSlotCtlData; } ReplicationSlotCtlData;
/*
* Set slot's inactive_since property unless it was previously invalidated.
*/
static inline void
ReplicationSlotSetInactiveSince(ReplicationSlot *s, TimestampTz ts,
bool acquire_lock)
{
if (acquire_lock)
SpinLockAcquire(&s->mutex);
if (s->data.invalidated == RS_INVAL_NONE)
s->inactive_since = ts;
if (acquire_lock)
SpinLockRelease(&s->mutex);
}
/* /*
* Pointers to shared memory * Pointers to shared memory
*/ */