summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/replication/syncrep.c22
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.