aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/slru.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/slru.c')
-rw-r--r--src/backend/access/transam/slru.c83
1 files changed, 74 insertions, 9 deletions
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5fcea113eaf..90c7cf56e63 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -134,6 +134,7 @@ static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
+static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename);
/*
* Initialization of shared memory
@@ -1075,7 +1076,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
* Flush dirty pages to disk during checkpoint or database shutdown
*/
void
-SimpleLruFlush(SlruCtl ctl, bool checkpoint)
+SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
{
SlruShared shared = ctl->shared;
SlruFlushData fdata;
@@ -1096,11 +1097,11 @@ SimpleLruFlush(SlruCtl ctl, bool checkpoint)
SlruInternalWritePage(ctl, slotno, &fdata);
/*
- * When called during a checkpoint, we cannot assert that the slot is
- * clean now, since another process might have re-dirtied it already.
- * That's okay.
+ * In some places (e.g. checkpoints), we cannot assert that the slot
+ * is clean now, since another process might have re-dirtied it
+ * already. That's okay.
*/
- Assert(checkpoint ||
+ Assert(allow_redirtied ||
shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
(shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno]));
@@ -1210,8 +1211,14 @@ restart:;
(void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
}
-void
-SlruDeleteSegment(SlruCtl ctl, char *filename)
+/*
+ * Delete an individual SLRU segment, identified by the filename.
+ *
+ * NB: This does not touch the SLRU buffers themselves, callers have to ensure
+ * they either can't yet contain anything, or have already been cleaned out.
+ */
+static void
+SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
{
char path[MAXPGPATH];
@@ -1222,6 +1229,64 @@ SlruDeleteSegment(SlruCtl ctl, char *filename)
}
/*
+ * Delete an individual SLRU segment, identified by the segment number.
+ */
+void
+SlruDeleteSegment(SlruCtl ctl, int segno)
+{
+ SlruShared shared = ctl->shared;
+ int slotno;
+ char path[MAXPGPATH];
+ bool did_write;
+
+ /* Clean out any possibly existing references to the segment. */
+ LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+restart:
+ did_write = false;
+ for (slotno = 0; slotno < shared->num_slots; slotno++)
+ {
+ int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
+
+ if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
+ continue;
+
+ /* not the segment we're looking for */
+ if (pagesegno != segno)
+ continue;
+
+ /* If page is clean, just change state to EMPTY (expected case). */
+ if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
+ !shared->page_dirty[slotno])
+ {
+ shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ continue;
+ }
+
+ /* Same logic as SimpleLruTruncate() */
+ if (shared->page_status[slotno] == SLRU_PAGE_VALID)
+ SlruInternalWritePage(ctl, slotno, NULL);
+ else
+ SimpleLruWaitIO(ctl, slotno);
+
+ did_write = true;
+ }
+
+ /*
+ * Be extra careful and re-check. The IO functions release the control
+ * lock, so new pages could have been read in.
+ */
+ if (did_write)
+ goto restart;
+
+ snprintf(path, MAXPGPATH, "%s/%04X", ctl->Dir, segno);
+ ereport(DEBUG2,
+ (errmsg("removing file \"%s\"", path)));
+ unlink(path);
+
+ LWLockRelease(shared->ControlLock);
+}
+
+/*
* SlruScanDirectory callback
* This callback reports true if there's any segment prior to the one
* containing the page passed as "data".
@@ -1249,7 +1314,7 @@ SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
int cutoffPage = *(int *) data;
if (ctl->PagePrecedes(segpage, cutoffPage))
- SlruDeleteSegment(ctl, filename);
+ SlruInternalDeleteSegment(ctl, filename);
return false; /* keep going */
}
@@ -1261,7 +1326,7 @@ SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
bool
SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int segpage, void *data)
{
- SlruDeleteSegment(ctl, filename);
+ SlruInternalDeleteSegment(ctl, filename);
return false; /* keep going */
}