diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 6a28becdad5..77e80f16123 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -293,8 +293,11 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit) * WalSender has checked our LSN and has removed us from queue. Clean up * state and leave. It's OK to reset these shared memory fields without * holding SyncRepLock, because any walsenders will ignore us anyway when - * we're not on the queue. + * we're not on the queue. We need a read barrier to make sure we see + * the changes to the queue link (this might be unnecessary without + * assertions, but better safe than sorry). */ + pg_read_barrier(); Assert(SHMQueueIsDetached(&(MyProc->syncRepLinks))); MyProc->syncRepState = SYNC_REP_NOT_WAITING; MyProc->waitLSN = 0; @@ -1021,17 +1024,24 @@ SyncRepWakeQueue(bool all, int mode) &(proc->syncRepLinks), offsetof(PGPROC, syncRepLinks)); + /* + * Remove thisproc from queue. + */ + SHMQueueDelete(&(thisproc->syncRepLinks)); + + /* + * SyncRepWaitForLSN() reads syncRepState without holding the lock, so + * make sure that it sees the queue link being removed before the + * syncRepState change. + */ + pg_write_barrier(); + /* * Set state to complete; see SyncRepWaitForLSN() for discussion of * the various states. */ thisproc->syncRepState = SYNC_REP_WAIT_COMPLETE; - /* - * Remove thisproc from queue. - */ - SHMQueueDelete(&(thisproc->syncRepLinks)); - /* * Wake only when we have set state and removed from queue. */