diff options
-rw-r--r-- | src/backend/replication/syncrep.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 6a28becdad..77e80f1612 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; @@ -1022,15 +1025,22 @@ SyncRepWakeQueue(bool all, int mode) offsetof(PGPROC, syncRepLinks)); /* - * Set state to complete; see SyncRepWaitForLSN() for discussion of - * the various states. + * Remove thisproc from queue. */ - thisproc->syncRepState = SYNC_REP_WAIT_COMPLETE; + SHMQueueDelete(&(thisproc->syncRepLinks)); /* - * Remove thisproc from queue. + * SyncRepWaitForLSN() reads syncRepState without holding the lock, so + * make sure that it sees the queue link being removed before the + * syncRepState change. */ - SHMQueueDelete(&(thisproc->syncRepLinks)); + pg_write_barrier(); + + /* + * Set state to complete; see SyncRepWaitForLSN() for discussion of + * the various states. + */ + thisproc->syncRepState = SYNC_REP_WAIT_COMPLETE; /* * Wake only when we have set state and removed from queue. |