bgwritter_or_checkpoint_proc_moving_buf_to_freelist.2.patch
text/plain
Filename: bgwritter_or_checkpoint_proc_moving_buf_to_freelist.2.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/storage/buffer/bufmgr.c | 113 | 1 |
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index dba19eb..87446cb 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -955,6 +955,88 @@ retry:
StrategyFreeBuffer(buf);
}
+
+/*
+ * MoveBufferToFreeList -- mark a shared buffer invalid and return it to the
+ * freelist. which is similar to InvalidateBuffer function.
+ */
+static void
+MoveBufferToFreeList(volatile BufferDesc *buf)
+{
+ BufferTag oldTag;
+ uint32 oldHash; /* hash value for oldTag */
+ LWLockId oldPartitionLock; /* buffer partition lock for it */
+ BufFlags oldFlags;
+
+ /* Save the original buffer tag before dropping the spinlock */
+ oldTag = buf->tag;
+
+ UnlockBufHdr(buf);
+
+ /*
+ * Need to compute the old tag's hashcode and partition lock ID. XXX is it
+ * worth storing the hashcode in BufferDesc so we need not recompute it
+ * here? Probably not.
+ */
+ oldHash = BufTableHashCode(&oldTag);
+ oldPartitionLock = BufMappingPartitionLock(oldHash);
+
+
+ /*
+ * Acquire exclusive mapping lock in preparation for changing the buffer's
+ * association.
+ */
+ LWLockAcquire(oldPartitionLock, LW_EXCLUSIVE);
+
+ /* Re-lock the buffer header */
+ LockBufHdr(buf);
+
+ /* If it's changed while we were waiting for lock, do nothing */
+ if (!BUFFERTAGS_EQUAL(buf->tag, oldTag))
+ {
+ UnlockBufHdr(buf);
+ LWLockRelease(oldPartitionLock);
+ return;
+ }
+
+ /*
+ * Validate wheather we can add the buffer into freelist or not
+ */
+ if ((buf->refcount != 0) || (buf->usage_count != 0))
+ {
+ UnlockBufHdr(buf);
+ LWLockRelease(oldPartitionLock);
+ return;
+ }
+
+ /*
+ * Clear out the buffer's tag and flags. We must do this to ensure that
+ * linear scans of the buffer array don't think the buffer is valid.
+ */
+ oldFlags = buf->flags;
+ CLEAR_BUFFERTAG(buf->tag);
+ buf->flags = 0;
+ buf->usage_count = 0;
+
+ UnlockBufHdr(buf);
+
+ /*
+ * Remove the buffer from the lookup hashtable, if it was in there.
+ */
+ if (oldFlags & BM_TAG_VALID)
+ BufTableDelete(&oldTag, oldHash);
+
+ /*
+ * Done with mapping lock.
+ */
+ LWLockRelease(oldPartitionLock);
+
+ /*
+ * Insert the buffer at the head of the list of free buffers.
+ */
+ StrategyFreeBuffer(buf);
+}
+
/*
* MarkBufferDirty
*
@@ -1658,12 +1740,29 @@ SyncOneBuffer(int buf_id, bool skip_recently_used)
return result;
}
- if (!(bufHdr->flags & BM_VALID) || !(bufHdr->flags & BM_DIRTY))
+ 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)
+ && (bufHdr->freeNext == FREENEXT_NOT_IN_LIST))
+ {
+ MoveBufferToFreeList (bufHdr);
+ }
+ else
+ {
+ UnlockBufHdr(bufHdr);
+ }
+ return result;
+ }
/*
* Pin it, share-lock it, write it. (FlushBuffer will do nothing if the
@@ -1677,6 +1776,19 @@ SyncOneBuffer(int buf_id, bool skip_recently_used)
LWLockRelease(bufHdr->content_lock);
UnpinBuffer(bufHdr, true);
+ /*
+ * Buffer is unused then move it to freelist
+ */
+ LockBufHdr(bufHdr);
+ if (bufHdr->refcount == 0 && bufHdr->usage_count == 0)
+ {
+ MoveBufferToFreeList (bufHdr);
+ }
+ else
+ {
+ UnlockBufHdr(bufHdr);
+ }
+
return result | BUF_WRITTEN;
}