*** a/src/backend/storage/buffer/bufmgr.c --- b/src/backend/storage/buffer/bufmgr.c *************** *** 1674,1685 **** SyncOneBuffer(int buf_id, bool skip_recently_used) return result; } ! if (!(bufHdr->flags & BM_VALID) || !(bufHdr->flags & BM_DIRTY)) { /* It's clean, so nothing to do */ UnlockBufHdr(bufHdr); return result; } /* * Pin it, share-lock it, write it. (FlushBuffer will do nothing if the --- 1674,1703 ---- return result; } ! if (!(bufHdr->flags & BM_VALID)) { /* It's clean, so nothing to do */ UnlockBufHdr(bufHdr); return result; } + else if (!(bufHdr->flags & BM_DIRTY)) + { + /* + * It's clean, so nothing to flush; + * if buffer is unused then move it to freelist + */ + if (bufHdr->refcount == 0 && bufHdr->usage_count == 0) + { + UnlockBufHdr(bufHdr); + StrategyMoveBufferToFreeListEnd (bufHdr); + } + else + { + UnlockBufHdr(bufHdr); + } + return result; + } + /* * Pin it, share-lock it, write it. (FlushBuffer will do nothing if the *************** *** 1693,1698 **** SyncOneBuffer(int buf_id, bool skip_recently_used) --- 1711,1730 ---- LWLockRelease(bufHdr->content_lock); UnpinBuffer(bufHdr, true); + /* + * check if buffer is not used actively by any backend, then move it to freelist + */ + LockBufHdr(bufHdr); + if (bufHdr->refcount == 0 && bufHdr->usage_count == 0) + { + UnlockBufHdr(bufHdr); + StrategyMoveBufferToFreeListEnd (bufHdr); + } + else + { + UnlockBufHdr(bufHdr); + } + return result | BUF_WRITTEN; } *** a/src/backend/storage/buffer/freelist.c --- b/src/backend/storage/buffer/freelist.c *************** *** 259,264 **** StrategyFreeBuffer(volatile BufferDesc *buf) --- 259,298 ---- } /* + * StrategyMoveBufferToFreeListEnd: put a buffer on the end of freelist + */ + void + StrategyMoveBufferToFreeListEnd(volatile BufferDesc *buf) + { + LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); + + /* + * It is possible that we are told to put something in the freelist that + * is already in it; don't screw up the list if so. + */ + if (buf->freeNext == FREENEXT_NOT_IN_LIST) + { + /* + * put the buffer on end of list and if list is empty then + * assign first and last freebuffer with this buffer id. + */ + buf->freeNext = FREENEXT_END_OF_LIST; + if (StrategyControl->firstFreeBuffer < 0) + { + StrategyControl->firstFreeBuffer = buf->buf_id; + StrategyControl->lastFreeBuffer = buf->buf_id; + LWLockRelease(BufFreelistLock); + return; + } + BufferDescriptors[StrategyControl->lastFreeBuffer].freeNext = buf->buf_id; + StrategyControl->lastFreeBuffer = buf->buf_id; + } + + LWLockRelease(BufFreelistLock); + } + + + /* * StrategySyncStart -- tell BufferSync where to start syncing * * The result is the buffer index of the best buffer to sync first. *** a/src/include/storage/buf_internals.h --- b/src/include/storage/buf_internals.h *************** *** 185,190 **** extern BufferDesc *LocalBufferDescriptors; --- 185,191 ---- extern volatile BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held); extern void StrategyFreeBuffer(volatile BufferDesc *buf); + extern void StrategyMoveBufferToFreeListEnd(volatile BufferDesc *buf); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, volatile BufferDesc *buf);