diff options
Diffstat (limited to 'src/backend/storage/buffer/bufmgr.c')
-rw-r--r-- | src/backend/storage/buffer/bufmgr.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 06e9ffd2b00..44836751b71 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -6003,3 +6003,66 @@ ResOwnerPrintBufferPin(Datum res) { return DebugPrintBufferRefcount(DatumGetInt32(res)); } + +/* + * Try to evict the current block in a shared buffer. + * + * This function is intended for testing/development use only! + * + * To succeed, the buffer must not be pinned on entry, so if the caller had a + * particular block in mind, it might already have been replaced by some other + * block by the time this function runs. It's also unpinned on return, so the + * buffer might be occupied again by the time control is returned, potentially + * even by the same block. This inherent raciness without other interlocking + * makes the function unsuitable for non-testing usage. + * + * Returns true if the buffer was valid and it has now been made invalid. + * Returns false if it wasn't valid, if it couldn't be evicted due to a pin, + * or if the buffer becomes dirty again while we're trying to write it out. + */ +bool +EvictUnpinnedBuffer(Buffer buf) +{ + BufferDesc *desc; + uint32 buf_state; + bool result; + + /* Make sure we can pin the buffer. */ + ResourceOwnerEnlarge(CurrentResourceOwner); + ReservePrivateRefCountEntry(); + + Assert(!BufferIsLocal(buf)); + desc = GetBufferDescriptor(buf - 1); + + /* Lock the header and check if it's valid. */ + buf_state = LockBufHdr(desc); + if ((buf_state & BM_VALID) == 0) + { + UnlockBufHdr(desc, buf_state); + return false; + } + + /* Check that it's not pinned already. */ + if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) + { + UnlockBufHdr(desc, buf_state); + return false; + } + + PinBuffer_Locked(desc); /* releases spinlock */ + + /* If it was dirty, try to clean it once. */ + if (buf_state & BM_DIRTY) + { + LWLockAcquire(BufferDescriptorGetContentLock(desc), LW_SHARED); + FlushBuffer(desc, NULL, IOOBJECT_RELATION, IOCONTEXT_NORMAL); + LWLockRelease(BufferDescriptorGetContentLock(desc)); + } + + /* This will return false if it becomes dirty or someone else pins it. */ + result = InvalidateVictimBuffer(desc); + + UnpinBuffer(desc); + + return result; +} |