diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c new file mode 100755 index 1c41428..699b0ec *** a/src/backend/storage/buffer/bufmgr.c --- b/src/backend/storage/buffer/bufmgr.c *************** SyncOneBuffer(int buf_id, bool skip_rece *** 1665,1671 **** */ LockBufHdr(bufHdr); ! if (bufHdr->refcount == 0 && bufHdr->usage_count == 0) result |= BUF_REUSABLE; else if (skip_recently_used) { --- 1665,1671 ---- */ LockBufHdr(bufHdr); ! if (bufHdr->refcount == 0 && bufHdr->usage_count <= 0) result |= BUF_REUSABLE; else if (skip_recently_used) { diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c new file mode 100755 index c76aaf7..a081069 *** a/src/backend/storage/buffer/freelist.c --- b/src/backend/storage/buffer/freelist.c *************** typedef struct *** 28,34 **** int nextVictimBuffer; int firstFreeBuffer; /* Head of list of unused buffers */ ! int lastFreeBuffer; /* Tail of list of unused buffers */ /* * NOTE: lastFreeBuffer is undefined when firstFreeBuffer is -1 (that is, --- 28,35 ---- int nextVictimBuffer; int firstFreeBuffer; /* Head of list of unused buffers */ ! int lastFreeBuffer; /* Tail of list of unused buffers */ ! slock_t mutex; /* Protects all of these, except sometimes not nextVictimBuffer */ /* * NOTE: lastFreeBuffer is undefined when firstFreeBuffer is -1 (that is, *************** typedef struct *** 49,55 **** } BufferStrategyControl; /* Pointers to shared state */ ! static BufferStrategyControl *StrategyControl = NULL; /* * Private (non-shared) state for managing a ring of shared buffers to re-use. --- 50,56 ---- } BufferStrategyControl; /* Pointers to shared state */ ! static volatile BufferStrategyControl *StrategyControl = NULL; /* * Private (non-shared) state for managing a ring of shared buffers to re-use. *************** static void AddBufferToRing(BufferAccess *** 101,112 **** * strategy is a BufferAccessStrategy object, or NULL for default strategy. * * To ensure that no one else can pin the buffer before we do, we must ! * return the buffer with the buffer header spinlock still held. If ! * *lock_held is set on exit, we have returned with the BufFreelistLock ! * still held, as well; the caller must release that lock once the spinlock ! * is dropped. We do it that way because releasing the BufFreelistLock ! * might awaken other processes, and it would be bad to do the associated ! * kernel calls while holding the buffer header spinlock. */ volatile BufferDesc * StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held) --- 102,113 ---- * strategy is a BufferAccessStrategy object, or NULL for default strategy. * * To ensure that no one else can pin the buffer before we do, we must ! * return the buffer with the buffer header spinlock still held. To avoid ! * excessive spinning during the clock sweep loop on highly contended ! * buffers, the buffer header lock is aquired without spinning. Also, all ! * manipulation of usage_count is done without holding the buffer header ! * spinlock on the basis that it advisory; this avoids excessive cache line ! * locking while sweeping. */ volatile BufferDesc * StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held) *************** StrategyGetBuffer(BufferAccessStrategy s *** 114,119 **** --- 115,121 ---- volatile BufferDesc *buf; Latch *bgwriterLatch; int trycounter; + *lock_held = false; /* * If given a strategy object, see whether it can select a buffer. We *************** StrategyGetBuffer(BufferAccessStrategy s *** 124,143 **** buf = GetBufferFromRing(strategy); if (buf != NULL) { - *lock_held = false; return buf; } } - /* Nope, so lock the freelist */ - *lock_held = true; - LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); - /* * We count buffer allocation requests so that the bgwriter can estimate * the rate of buffer consumption. Note that buffers recycled by a * strategy object are intentionally not counted here. */ StrategyControl->numBufferAllocs++; /* --- 126,142 ---- buf = GetBufferFromRing(strategy); if (buf != NULL) { return buf; } } /* * We count buffer allocation requests so that the bgwriter can estimate * the rate of buffer consumption. Note that buffers recycled by a * strategy object are intentionally not counted here. + * This is now done without a lock, and so updates can be lost */ + StrategyControl->numBufferAllocs++; /* *************** StrategyGetBuffer(BufferAccessStrategy s *** 150,158 **** if (bgwriterLatch) { StrategyControl->bgwriterLatch = NULL; - LWLockRelease(BufFreelistLock); SetLatch(bgwriterLatch); - LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); } /* --- 149,155 ---- *************** StrategyGetBuffer(BufferAccessStrategy s *** 163,168 **** --- 160,171 ---- */ while (StrategyControl->firstFreeBuffer >= 0) { + SpinLockAcquire(&StrategyControl->mutex); + if (StrategyControl->firstFreeBuffer<0) + { + SpinLockRelease(&StrategyControl->mutex); + break; + } buf = &BufferDescriptors[StrategyControl->firstFreeBuffer]; Assert(buf->freeNext != FREENEXT_NOT_IN_LIST); *************** StrategyGetBuffer(BufferAccessStrategy s *** 170,175 **** --- 173,180 ---- StrategyControl->firstFreeBuffer = buf->freeNext; buf->freeNext = FREENEXT_NOT_IN_LIST; + SpinLockRelease(&StrategyControl->mutex); + /* * If the buffer is pinned or has a nonzero usage_count, we cannot use * it; discard it and retry. (This can only happen if VACUUM put a *************** StrategyGetBuffer(BufferAccessStrategy s *** 178,184 **** * we'd better check anyway.) */ LockBufHdr(buf); ! if (buf->refcount == 0 && buf->usage_count == 0) { if (strategy != NULL) AddBufferToRing(strategy, buf); --- 183,189 ---- * we'd better check anyway.) */ LockBufHdr(buf); ! if (buf->refcount == 0 && buf->usage_count <= 0) { if (strategy != NULL) AddBufferToRing(strategy, buf); *************** StrategyGetBuffer(BufferAccessStrategy s *** 191,209 **** trycounter = NBuffers; for (;;) { ! buf = &BufferDescriptors[StrategyControl->nextVictimBuffer]; if (++StrategyControl->nextVictimBuffer >= NBuffers) { ! StrategyControl->nextVictimBuffer = 0; ! StrategyControl->completePasses++; } /* * If the buffer is pinned or has a nonzero usage_count, we cannot use * it; decrement the usage_count (unless pinned) and keep scanning. */ - LockBufHdr(buf); if (buf->refcount == 0) { if (buf->usage_count > 0) --- 196,222 ---- trycounter = NBuffers; for (;;) { ! ! int localVictim=StrategyControl->nextVictimBuffer; ! if (localVictim >= NBuffers) localVictim=0; ! ! buf = &BufferDescriptors[localVictim]; if (++StrategyControl->nextVictimBuffer >= NBuffers) { ! SpinLockAcquire(&StrategyControl->mutex); ! if (StrategyControl->nextVictimBuffer >= NBuffers) ! { ! StrategyControl->nextVictimBuffer = 0; ! StrategyControl->completePasses++; ! }; ! SpinLockRelease(&StrategyControl->mutex); } /* * If the buffer is pinned or has a nonzero usage_count, we cannot use * it; decrement the usage_count (unless pinned) and keep scanning. */ if (buf->refcount == 0) { if (buf->usage_count > 0) *************** StrategyGetBuffer(BufferAccessStrategy s *** 213,222 **** } else { ! /* Found a usable buffer */ ! if (strategy != NULL) ! AddBufferToRing(strategy, buf); ! return buf; } } else if (--trycounter == 0) --- 226,238 ---- } else { ! /* Found a usable buffer. But is it truly unpinned? */ ! if (TryLockBufHdr(buf)) ! { ! if (strategy != NULL) ! AddBufferToRing(strategy, buf); ! return buf; ! } } } else if (--trycounter == 0) *************** StrategyGetBuffer(BufferAccessStrategy s *** 228,237 **** * probably better to fail than to risk getting stuck in an * infinite loop. */ - UnlockBufHdr(buf); elog(ERROR, "no unpinned buffers available"); } - UnlockBufHdr(buf); } } --- 244,251 ---- *************** StrategyGetBuffer(BufferAccessStrategy s *** 241,247 **** void StrategyFreeBuffer(volatile BufferDesc *buf) { ! LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); /* * It is possible that we are told to put something in the freelist that --- 255,261 ---- void StrategyFreeBuffer(volatile BufferDesc *buf) { ! SpinLockAcquire(&StrategyControl->mutex); /* * It is possible that we are told to put something in the freelist that *************** StrategyFreeBuffer(volatile BufferDesc * *** 255,261 **** StrategyControl->firstFreeBuffer = buf->buf_id; } ! LWLockRelease(BufFreelistLock); } /* --- 269,275 ---- StrategyControl->firstFreeBuffer = buf->buf_id; } ! SpinLockRelease(&StrategyControl->mutex); } /* *************** StrategySyncStart(uint32 *complete_passe *** 274,281 **** { int result; ! LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); result = StrategyControl->nextVictimBuffer; if (complete_passes) *complete_passes = StrategyControl->completePasses; if (num_buf_alloc) --- 288,296 ---- { int result; ! SpinLockAcquire(&StrategyControl->mutex); result = StrategyControl->nextVictimBuffer; + if (result >= NBuffers) result=0; if (complete_passes) *complete_passes = StrategyControl->completePasses; if (num_buf_alloc) *************** StrategySyncStart(uint32 *complete_passe *** 283,289 **** *num_buf_alloc = StrategyControl->numBufferAllocs; StrategyControl->numBufferAllocs = 0; } ! LWLockRelease(BufFreelistLock); return result; } --- 298,304 ---- *num_buf_alloc = StrategyControl->numBufferAllocs; StrategyControl->numBufferAllocs = 0; } ! SpinLockRelease(&StrategyControl->mutex); return result; } *************** StrategyInitialize(bool init) *** 376,381 **** --- 391,397 ---- */ StrategyControl->firstFreeBuffer = 0; StrategyControl->lastFreeBuffer = NBuffers - 1; + SpinLockInit(&StrategyControl->mutex); /* Initialize the clock sweep pointer */ StrategyControl->nextVictimBuffer = 0; diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h new file mode 100755 index f0e5144..943215c *** a/src/include/storage/buf_internals.h --- b/src/include/storage/buf_internals.h *************** typedef struct sbufdesc *** 168,173 **** --- 168,174 ---- */ #define LockBufHdr(bufHdr) SpinLockAcquire(&(bufHdr)->buf_hdr_lock) #define UnlockBufHdr(bufHdr) SpinLockRelease(&(bufHdr)->buf_hdr_lock) + #define TryLockBufHdr(bufHdr) TrySpinLockAcquire(&(bufHdr)->buf_hdr_lock) /* in buf_init.c */ diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h new file mode 100755 index f459b90..909ecd5 *** a/src/include/storage/spin.h --- b/src/include/storage/spin.h *************** *** 63,68 **** --- 63,70 ---- #define SpinLockAcquire(lock) S_LOCK(lock) + #define TrySpinLockAcquire(lock) !(TAS_SPIN(lock)) + #define SpinLockRelease(lock) S_UNLOCK(lock) #define SpinLockFree(lock) S_LOCK_FREE(lock)