Index: src/backend/storage/buffer/freelist.c =================================================================== *** src/backend/storage/buffer/freelist.c (HEAD) --- src/backend/storage/buffer/freelist.c (working copy) *************** typedef struct *** 29,34 **** --- 29,35 ---- int firstFreeBuffer; /* Head of list of unused buffers */ int lastFreeBuffer; /* Tail of list of unused buffers */ + int numFreeBuffers; /* Number of unused buffers */ /* * NOTE: lastFreeBuffer is undefined when firstFreeBuffer is -1 (that is, *************** volatile BufferDesc * *** 59,64 **** --- 60,67 ---- StrategyGetBuffer(void) { volatile BufferDesc *buf; + volatile int *freeBuffer; + int lastBuffer; int trycounter; LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); *************** StrategyGetBuffer(void) *** 69,82 **** * individual buffer spinlocks, so it's OK to manipulate them without * holding the spinlock. */ ! while (StrategyControl->firstFreeBuffer >= 0) { ! buf = &BufferDescriptors[StrategyControl->firstFreeBuffer]; Assert(buf->freeNext != FREENEXT_NOT_IN_LIST); /* Unconditionally remove buffer from freelist */ ! StrategyControl->firstFreeBuffer = buf->freeNext; buf->freeNext = FREENEXT_NOT_IN_LIST; /* * If the buffer is pinned or has a nonzero usage_count, we cannot use --- 72,108 ---- * individual buffer spinlocks, so it's OK to manipulate them without * holding the spinlock. */ ! lastBuffer = FREENEXT_END_OF_LIST; ! freeBuffer = &StrategyControl->firstFreeBuffer; ! while (*freeBuffer >= 0) { ! bool unused; ! ! buf = &BufferDescriptors[*freeBuffer]; Assert(buf->freeNext != FREENEXT_NOT_IN_LIST); + LockBufHdr(buf); + unused = (buf->refcount == 0 && buf->usage_count == 0); + + /* + * We don't reuse dirty buffers except there are more than + * FREELIST_BUFFERS buffers in freelist to avoid WAL traffic. + */ + if ((buf->flags & BM_DIRTY) && unused && + StrategyControl->numFreeBuffers < FREELIST_BUFFERS) + { + lastBuffer = *freeBuffer; + freeBuffer = &buf->freeNext; + UnlockBufHdr(buf); + continue; + } + /* Unconditionally remove buffer from freelist */ ! *freeBuffer = buf->freeNext; buf->freeNext = FREENEXT_NOT_IN_LIST; + StrategyControl->numFreeBuffers--; + if (*freeBuffer == FREENEXT_END_OF_LIST) + StrategyControl->lastFreeBuffer = lastBuffer; /* * If the buffer is pinned or has a nonzero usage_count, we cannot use *************** StrategyGetBuffer(void) *** 84,91 **** * valid buffer in the freelist and then someone else used it before * we got to it.) */ ! LockBufHdr(buf); ! if (buf->refcount == 0 && buf->usage_count == 0) return buf; UnlockBufHdr(buf); } --- 110,116 ---- * valid buffer in the freelist and then someone else used it before * we got to it.) */ ! if (unused) return buf; UnlockBufHdr(buf); } *************** StrategyGetBuffer(void) *** 104,110 **** * it; decrement the usage_count and keep scanning. */ LockBufHdr(buf); ! if (buf->refcount == 0 && buf->usage_count == 0) return buf; if (buf->usage_count > 0) { --- 129,136 ---- * it; decrement the usage_count and keep scanning. */ LockBufHdr(buf); ! if (buf->refcount == 0 && buf->usage_count == 0 && ! buf->freeNext == FREENEXT_NOT_IN_LIST) return buf; if (buf->usage_count > 0) { *************** StrategyFreeBuffer(volatile BufferDesc * *** 164,169 **** --- 190,196 ---- BufferDescriptors[StrategyControl->lastFreeBuffer].freeNext = buf->buf_id; StrategyControl->lastFreeBuffer = buf->buf_id; } + StrategyControl->numFreeBuffers++; } LWLockRelease(BufFreelistLock); *************** StrategyInitialize(bool init) *** 267,272 **** --- 294,300 ---- */ StrategyControl->firstFreeBuffer = 0; StrategyControl->lastFreeBuffer = NBuffers - 1; + StrategyControl->numFreeBuffers = NBuffers; /* Initialize the clock sweep pointer */ StrategyControl->nextVictimBuffer = 0; Index: src/include/storage/buf_internals.h =================================================================== *** src/include/storage/buf_internals.h (HEAD) --- src/include/storage/buf_internals.h (working copy) *************** typedef struct sbufdesc *** 149,154 **** --- 149,160 ---- #define FREENEXT_NOT_IN_LIST (-2) /* + * Dirty buffers in freelist are not reused except there are more than the + * following number. + */ + #define FREELIST_BUFFERS 32 + + /* * Macros for acquiring/releasing a shared buffer header's spinlock. * Do not apply these to local buffers! *