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

Allow synced slots to have their inactive_since.

This commit does two things:
1) Maintains inactive_since for sync slots whenever the slot is released
just like any other regular slot.

2) Ensures the value is set to the current timestamp during the promotion
of standby to help correctly interpret the time after promotion. We don't
want the slots to appear inactive for a long time after promotion if they
haven't been synchronized recently. This would also avoid the invalidation
of such slots immediately after promotion if tomorrow we have a feature
that invalidates slots based on their inactivity time. Whoever acquires
the slot i.e. makes the slot active will reset it to NULL.

Author: Bharath Rupireddy
Reviewed-by: Bertrand Drouvot, Amit Kapila, Shveta Malik, Masahiko Sawada
Discussion: https://postgr.es/m/CAA4eK1KrPGwfZV9LYGidjxHeW+rxJ=E2ThjXvwRGLO=iLNuo=Q@mail.gmail.com
Discussion: https://postgr.es/m/CALj2ACW4aUe-_uFQOjdWCEN-xXoLGhmvRFnL8SNw_TZ5nJe+aw@mail.gmail.com
Discussion: https://postgr.es/m/CA+Tgmob_Ta-t2ty8QrKHBGnNLrf4ZYcwhGHGFsuUoFrAEDw4sA@mail.gmail.com
This commit is contained in:
Amit Kapila
2024-04-05 09:48:49 +05:30
parent f98dbdeb51
commit 6f132ed693
6 changed files with 160 additions and 39 deletions

View File

@ -150,6 +150,7 @@ typedef struct RemoteSlot
} RemoteSlot;
static void slotsync_failure_callback(int code, Datum arg);
static void update_synced_slots_inactive_since(void);
/*
* If necessary, update the local synced slot's metadata based on the data
@ -584,6 +585,11 @@ synchronize_one_slot(RemoteSlot *remote_slot, Oid remote_dbid)
* overwriting 'invalidated' flag to remote_slot's value. See
* InvalidatePossiblyObsoleteSlot() where it invalidates slot directly
* if the slot is not acquired by other processes.
*
* XXX: If it ever turns out that slot acquire/release is costly for
* cases when none of the slot properties is changed then we can do a
* pre-check to ensure that at least one of the slot properties is
* changed before acquiring the slot.
*/
ReplicationSlotAcquire(remote_slot->name, true);
@ -1355,6 +1361,54 @@ ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len)
Assert(false);
}
/*
* Update the inactive_since property for synced slots.
*
* Note that this function is currently called when we shutdown the slot
* sync machinery.
*/
static void
update_synced_slots_inactive_since(void)
{
TimestampTz now = 0;
/*
* We need to update inactive_since only when we are promoting standby to
* correctly interpret the inactive_since if the standby gets promoted
* without a restart. We don't want the slots to appear inactive for a
* long time after promotion if they haven't been synchronized recently.
* Whoever acquires the slot i.e.makes the slot active will reset it.
*/
if (!StandbyMode)
return;
/* The slot sync worker mustn't be running by now */
Assert(SlotSyncCtx->pid == InvalidPid);
LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
for (int i = 0; i < max_replication_slots; i++)
{
ReplicationSlot *s = &ReplicationSlotCtl->replication_slots[i];
/* Check if it is a synchronized slot */
if (s->in_use && s->data.synced)
{
Assert(SlotIsLogical(s));
/* Use the same inactive_since time for all the slots. */
if (now == 0)
now = GetCurrentTimestamp();
SpinLockAcquire(&s->mutex);
s->inactive_since = now;
SpinLockRelease(&s->mutex);
}
}
LWLockRelease(ReplicationSlotControlLock);
}
/*
* Shut down the slot sync worker.
*/
@ -1368,6 +1422,7 @@ ShutDownSlotSync(void)
if (SlotSyncCtx->pid == InvalidPid)
{
SpinLockRelease(&SlotSyncCtx->mutex);
update_synced_slots_inactive_since();
return;
}
SpinLockRelease(&SlotSyncCtx->mutex);
@ -1400,6 +1455,8 @@ ShutDownSlotSync(void)
}
SpinLockRelease(&SlotSyncCtx->mutex);
update_synced_slots_inactive_since();
}
/*

View File

@ -690,13 +690,10 @@ ReplicationSlotRelease(void)
}
/*
* Set the last inactive time after marking the slot inactive. We don't
* set it for the slots currently being synced from the primary to the
* standby because such slots are typically inactive as decoding is not
* allowed on those.
* Set the time since the slot has become inactive. We get the current
* time beforehand to avoid system call while holding the spinlock.
*/
if (!(RecoveryInProgress() && slot->data.synced))
now = GetCurrentTimestamp();
now = GetCurrentTimestamp();
if (slot->data.persistency == RS_PERSISTENT)
{
@ -2369,16 +2366,11 @@ RestoreSlotFromDisk(const char *name)
slot->active_pid = 0;
/*
* We set the last inactive time after loading the slot from the disk
* into memory. Whoever acquires the slot i.e. makes the slot active
* will reset it. We don't set it for the slots currently being synced
* from the primary to the standby because such slots are typically
* inactive as decoding is not allowed on those.
* Set the time since the slot has become inactive after loading the
* slot from the disk into memory. Whoever acquires the slot i.e.
* makes the slot active will reset it.
*/
if (!(RecoveryInProgress() && slot->data.synced))
slot->inactive_since = GetCurrentTimestamp();
else
slot->inactive_since = 0;
slot->inactive_since = GetCurrentTimestamp();
restored = true;
break;