diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c new file mode 100755 index 1c41428..61fc1e6 *** a/src/backend/storage/buffer/bufmgr.c --- b/src/backend/storage/buffer/bufmgr.c *************** PinBuffer(volatile BufferDesc *buf, Buff *** 1105,1111 **** } else { ! if (buf->usage_count == 0) buf->usage_count = 1; } result = (buf->flags & BM_VALID) != 0; --- 1105,1111 ---- } else { ! if (buf->usage_count <= 0) buf->usage_count = 1; } result = (buf->flags & BM_VALID) != 0; *************** 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..faa8523 *** a/src/backend/storage/buffer/freelist.c --- b/src/backend/storage/buffer/freelist.c *************** 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); --- 178,184 ---- * we'd better check anyway.) */ LockBufHdr(buf); ! if (buf->refcount == 0 && buf->usage_count <= 0) { if (strategy != NULL) AddBufferToRing(strategy, buf); *************** StrategyGetBuffer(BufferAccessStrategy s *** 201,209 **** /* * 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) --- 201,211 ---- /* * If the buffer is pinned or has a nonzero usage_count, we cannot use ! * it; decrement the usage_count (unless pinned) and keep scanning. The ! * buffer header is deliberately not locked during the initial examination ! * of refcount or while usage_count is adjusted in order to minimize ! * spinlock contention while holding the BufFreelistLock. */ 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) --- 215,227 ---- } 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); } } --- 233,240 ---- 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..ed68318 *** 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)