mirror of
https://github.com/postgres/postgres.git
synced 2025-07-26 01:22:12 +03:00
For cascading replication, wake physical and logical walsenders separately
Physical walsenders can't send data until it's been flushed; logical walsenders can't decode and send data until it's been applied. On the standby, the WAL is flushed first, which will only wake up physical walsenders; and then applied, which will only wake up logical walsenders. Previously, all walsenders were awakened when the WAL was flushed. That was fine for logical walsenders on the primary; but on the standby the flushed WAL would have been not applied yet, so logical walsenders were awakened too early. Per idea from Jeff Davis and Amit Kapila. Author: "Drouvot, Bertrand" <bertranddrouvot.pg@gmail.com> Reviewed-By: Jeff Davis <pgsql@j-davis.com> Reviewed-By: Robert Haas <robertmhaas@gmail.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com> Discussion: https://postgr.es/m/CAA4eK1+zO5LUeisabX10c81LU-fWMKO4M9Wyg1cdkbW7Hqh6vQ@mail.gmail.com
This commit is contained in:
@ -2603,6 +2603,23 @@ InitWalSenderSlot(void)
|
||||
walsnd->sync_standby_priority = 0;
|
||||
walsnd->latch = &MyProc->procLatch;
|
||||
walsnd->replyTime = 0;
|
||||
|
||||
/*
|
||||
* The kind assignment is done here and not in StartReplication()
|
||||
* and StartLogicalReplication(). Indeed, the logical walsender
|
||||
* needs to read WAL records (like snapshot of running
|
||||
* transactions) during the slot creation. So it needs to be woken
|
||||
* up based on its kind.
|
||||
*
|
||||
* The kind assignment could also be done in StartReplication(),
|
||||
* StartLogicalReplication() and CREATE_REPLICATION_SLOT but it
|
||||
* seems better to set it on one place.
|
||||
*/
|
||||
if (MyDatabaseId == InvalidOid)
|
||||
walsnd->kind = REPLICATION_KIND_PHYSICAL;
|
||||
else
|
||||
walsnd->kind = REPLICATION_KIND_LOGICAL;
|
||||
|
||||
SpinLockRelease(&walsnd->mutex);
|
||||
/* don't need the lock anymore */
|
||||
MyWalSnd = (WalSnd *) walsnd;
|
||||
@ -3280,30 +3297,46 @@ WalSndShmemInit(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Wake up all walsenders
|
||||
* Wake up physical, logical or both kinds of walsenders
|
||||
*
|
||||
* The distinction between physical and logical walsenders is done, because:
|
||||
* - physical walsenders can't send data until it's been flushed
|
||||
* - logical walsenders on standby can't decode and send data until it's been
|
||||
* applied
|
||||
*
|
||||
* For cascading replication we need to wake up physical walsenders separately
|
||||
* from logical walsenders (see the comment before calling WalSndWakeup() in
|
||||
* ApplyWalRecord() for more details).
|
||||
*
|
||||
* This will be called inside critical sections, so throwing an error is not
|
||||
* advisable.
|
||||
*/
|
||||
void
|
||||
WalSndWakeup(void)
|
||||
WalSndWakeup(bool physical, bool logical)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < max_wal_senders; i++)
|
||||
{
|
||||
Latch *latch;
|
||||
ReplicationKind kind;
|
||||
WalSnd *walsnd = &WalSndCtl->walsnds[i];
|
||||
|
||||
/*
|
||||
* Get latch pointer with spinlock held, for the unlikely case that
|
||||
* pointer reads aren't atomic (as they're 8 bytes).
|
||||
* pointer reads aren't atomic (as they're 8 bytes). While at it, also
|
||||
* get kind.
|
||||
*/
|
||||
SpinLockAcquire(&walsnd->mutex);
|
||||
latch = walsnd->latch;
|
||||
kind = walsnd->kind;
|
||||
SpinLockRelease(&walsnd->mutex);
|
||||
|
||||
if (latch != NULL)
|
||||
if (latch == NULL)
|
||||
continue;
|
||||
|
||||
if ((physical && kind == REPLICATION_KIND_PHYSICAL) ||
|
||||
(logical && kind == REPLICATION_KIND_LOGICAL))
|
||||
SetLatch(latch);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user