diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c index 4f446aa..7d60f31 100644 --- a/src/backend/storage/ipc/sinvaladt.c +++ b/src/backend/storage/ipc/sinvaladt.c @@ -499,11 +499,31 @@ SIGetDataEntries(SharedInvalidationMessage *data, int datasize) int max; int n; - LWLockAcquire(SInvalReadLock, LW_SHARED); - segP = shmInvalBuffer; stateP = &segP->procState[MyBackendId - 1]; + /* + * Before starting to take locks, do a quick, unlocked test to see whether + * there can possibly be anything to read. On a multiprocessor system, + * it's possible these loads could migrate backwards and occur before we + * actually enter this function, so we might miss a sinval message that + * was just added by some other processor. But they can't migrate + * backwards over a preceding lock acquisition, so it should be OK. If + * we haven't acquired a lock preventing against further relevant + * invalidations, any such occurrence is not much different than if the + * invalidation had arrived slightly later in the first place. + * + * It's important that we don't use the value read here to actually + * read from the queue. On machines with weak memory ordering, the + * maxMsgNum bump could become visible before the queue entries themselves. + * But the locking below will take care of that before rereading the + * value. + */ + if (stateP->nextMsgNum == segP->maxMsgNum && !stateP->resetState) + return 0; + + LWLockAcquire(SInvalReadLock, LW_SHARED); + /* Fetch current value of maxMsgNum using spinlock */ { /* use volatile pointer to prevent code rearrangement */