slru-replacement-fix.patch
application/octet-stream
Filename: slru-replacement-fix.patch
Type: application/octet-stream
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/access/transam/slru.c | 49 | 31 |
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 3049e01..63fd4f2 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -403,12 +403,6 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
/* Acquire per-buffer lock (cannot deadlock, see notes at top) */
LWLockAcquire(shared->buffer_locks[slotno], LW_EXCLUSIVE);
- /*
- * Temporarily mark page as recently-used to discourage
- * SlruSelectLRUPage from selecting it again for someone else.
- */
- SlruRecentlyUsed(shared, slotno);
-
/* Release control lock while doing I/O */
LWLockRelease(shared->ControlLock);
@@ -909,9 +903,12 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
{
int slotno;
int cur_count;
- int bestslot;
- int best_delta;
- int best_page_number;
+ int bestvalidslot = 0; /* keep compiler quiet */
+ int best_valid_delta = -1;
+ int best_valid_page_number = 0; /* keep compiler quiet */
+ int bestinvalidslot = 0; /* keep compiler quiet */
+ int best_invalid_delta = -1;
+ int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
for (slotno = 0; slotno < shared->num_slots; slotno++)
@@ -933,7 +930,8 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
* choosing the furthest-back page.
*
* In no case will we select the slot containing latest_page_number
- * for replacement, even if it appears least recently used.
+ * for replacement, even if it appears least recently used. We also
+ * try hard to avoid selecting a page on which an I/O is in progress.
*
* Notice that this next line forcibly advances cur_lru_count to a
* value that is certainly beyond any value that will be in the
@@ -944,9 +942,6 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
* multiple pages with the same lru_count.
*/
cur_count = (shared->cur_lru_count)++;
- best_delta = -1;
- bestslot = 0; /* no-op, just keeps compiler quiet */
- best_page_number = 0; /* ditto */
for (slotno = 0; slotno < shared->num_slots; slotno++)
{
int this_delta;
@@ -968,34 +963,57 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
this_delta = 0;
}
this_page_number = shared->page_number[slotno];
- if ((this_delta > best_delta ||
- (this_delta == best_delta &&
- ctl->PagePrecedes(this_page_number, best_page_number))) &&
- this_page_number != shared->latest_page_number)
+ if (this_page_number == shared->latest_page_number)
+ continue;
+ if (shared->page_status[slotno] == SLRU_PAGE_VALID)
+ {
+ if (this_delta > best_valid_delta ||
+ (this_delta == best_valid_delta &&
+ ctl->PagePrecedes(this_page_number,
+ best_valid_page_number)))
+ {
+ bestvalidslot = slotno;
+ best_valid_delta = this_delta;
+ best_valid_page_number = this_page_number;
+ }
+ }
+ else
{
- bestslot = slotno;
- best_delta = this_delta;
- best_page_number = this_page_number;
+ if (this_delta > best_invalid_delta ||
+ (this_delta == best_invalid_delta &&
+ ctl->PagePrecedes(this_page_number,
+ best_invalid_page_number)))
+ {
+ bestinvalidslot = slotno;
+ best_invalid_delta = this_delta;
+ best_invalid_page_number = this_page_number;
+ }
}
}
/*
+ * All pages (except possibly the latest one) are I/O busy. We'll have
+ * to wait for an I/O to complete and then retry. We choose to wait
+ * for the I/O on the least recently used slot, on the assumption that
+ * it was likely initiated first of all the I/Os in progress and may
+ * therefore finish first.
+ */
+ if (best_valid_delta < 0)
+ {
+ SimpleLruWaitIO(ctl, bestinvalidslot);
+ continue;
+ }
+
+ /*
* If the selected page is clean, we're set.
*/
- if (shared->page_status[bestslot] == SLRU_PAGE_VALID &&
- !shared->page_dirty[bestslot])
- return bestslot;
+ if (!shared->page_dirty[bestvalidslot])
+ return bestvalidslot;
/*
- * We need to wait for I/O. Normal case is that it's dirty and we
- * must initiate a write, but it's possible that the page is already
- * write-busy, or in the worst case still read-busy. In those cases
- * we wait for the existing I/O to complete.
+ * Write the page.
*/
- if (shared->page_status[bestslot] == SLRU_PAGE_VALID)
- SlruInternalWritePage(ctl, bestslot, NULL);
- else
- SimpleLruWaitIO(ctl, bestslot);
+ SlruInternalWritePage(ctl, bestvalidslot, NULL);
/*
* Now loop back and try again. This is the easiest way of dealing