aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2011-09-28 11:32:38 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2011-10-04 14:03:23 -0300
commit09e196e4539a70c51e828abcfe48dee3efd312d8 (patch)
treea229e227e0e4db185606acafbbd3e8c3c12171aa /src
parent1a00c0ef5368bb7b8ddcb3cf279df36577918ac4 (diff)
downloadpostgresql-09e196e4539a70c51e828abcfe48dee3efd312d8.tar.gz
postgresql-09e196e4539a70c51e828abcfe48dee3efd312d8.zip
Use callbacks in SlruScanDirectory for the actual action
Previously, the code assumed that the only possible action to take was to delete files behind a certain cutoff point. The async notify code was already a crock: it used a different "pagePrecedes" function for truncation than for regular operation. By allowing it to pass a callback to SlruScanDirectory it can do cleanly exactly what it needs to do. The clog.c code also had its own use for SlruScanDirectory, which is made a bit simpler with this.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/clog.c2
-rw-r--r--src/backend/access/transam/slru.c104
-rw-r--r--src/backend/commands/async.c36
-rw-r--r--src/include/access/slru.h11
4 files changed, 94 insertions, 59 deletions
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 3a6c39164ce..ee645f7bd47 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -606,7 +606,7 @@ TruncateCLOG(TransactionId oldestXact)
cutoffPage = TransactionIdToPage(oldestXact);
/* Check to see if there's any files that could be removed */
- if (!SlruScanDirectory(ClogCtl, cutoffPage, false))
+ if (!SlruScanDirectory(ClogCtl, SlruScanDirCbReportPresence, &cutoffPage))
return; /* nothing to remove */
/* Write XLOG record and flush XLOG to disk */
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 69e5245beba..4b838a0dfeb 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -132,6 +132,8 @@ static bool SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno,
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid);
static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
+static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
+ int segpage, void *data);
/*
* Initialization of shared memory
@@ -1137,33 +1139,84 @@ restart:;
LWLockRelease(shared->ControlLock);
/* Now we can remove the old segment(s) */
- (void) SlruScanDirectory(ctl, cutoffPage, true);
+ (void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
}
/*
- * SimpleLruTruncate subroutine: scan directory for removable segments.
- * Actually remove them iff doDeletions is true. Return TRUE iff any
- * removable segments were found. Note: no locking is needed.
+ * SlruScanDirectory callback
+ * This callback reports true if there's any segment prior to the one
+ * containing the page passed as "data".
+ */
+bool
+SlruScanDirCbReportPresence(SlruCtl ctl, char *filename, int segpage, void *data)
+{
+ int cutoffPage = *(int *) data;
+
+ cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
+
+ if (ctl->PagePrecedes(segpage, cutoffPage))
+ return true; /* found one; don't iterate any more */
+
+ return false; /* keep going */
+}
+
+/*
+ * SlruScanDirectory callback.
+ * This callback deletes segments prior to the one passed in as "data".
+ */
+static bool
+SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
+{
+ char path[MAXPGPATH];
+ int cutoffPage = *(int *) data;
+
+ if (ctl->PagePrecedes(segpage, cutoffPage))
+ {
+ snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
+ ereport(DEBUG2,
+ (errmsg("removing file \"%s\"", path)));
+ unlink(path);
+ }
+
+ return false; /* keep going */
+}
+
+/*
+ * SlruScanDirectory callback.
+ * This callback deletes all segments.
+ */
+bool
+SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int segpage, void *data)
+{
+ char path[MAXPGPATH];
+
+ snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
+ ereport(DEBUG2,
+ (errmsg("removing file \"%s\"", path)));
+ unlink(path);
+
+ return false; /* keep going */
+}
+
+/*
+ * Scan the SimpleLRU directory and apply a callback to each file found in it.
+ *
+ * If the callback returns true, the scan is stopped. The last return value
+ * from the callback is returned.
*
- * This can be called directly from clog.c, for reasons explained there.
+ * Note that the ordering in which the directory is scanned is not guaranteed.
+ *
+ * Note that no locking is applied.
*/
bool
-SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
+SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
{
- bool found = false;
DIR *cldir;
struct dirent *clde;
int segno;
int segpage;
- char path[MAXPGPATH];
-
- /*
- * The cutoff point is the start of the segment containing cutoffPage.
- * (This is redundant when called from SimpleLruTruncate, but not when
- * called directly from clog.c.)
- */
- cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
-
+ bool retval;
+
cldir = AllocateDir(ctl->Dir);
while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
{
@@ -1172,20 +1225,15 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
{
segno = (int) strtol(clde->d_name, NULL, 16);
segpage = segno * SLRU_PAGES_PER_SEGMENT;
- if (ctl->PagePrecedes(segpage, cutoffPage))
- {
- found = true;
- if (doDeletions)
- {
- snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, clde->d_name);
- ereport(DEBUG2,
- (errmsg("removing file \"%s\"", path)));
- unlink(path);
- }
- }
+
+ elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
+ ctl->Dir, clde->d_name);
+ retval = callback(ctl, clde->d_name, segpage, data);
+ if (retval)
+ break;
}
}
FreeDir(cldir);
- return found;
+ return retval;
}
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4f20ca2ef73..ca2e7348c97 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -194,7 +194,7 @@ typedef struct QueuePosition
/* choose logically smaller QueuePosition */
#define QUEUE_POS_MIN(x,y) \
- (asyncQueuePagePrecedesLogically((x).page, (y).page) ? (x) : \
+ (asyncQueuePagePrecedes((x).page, (y).page) ? (x) : \
(x).page != (y).page ? (y) : \
(x).offset < (y).offset ? (x) : (y))
@@ -360,8 +360,7 @@ static bool backendHasExecutedInitialListen = false;
bool Trace_notify = false;
/* local function prototypes */
-static bool asyncQueuePagePrecedesPhysically(int p, int q);
-static bool asyncQueuePagePrecedesLogically(int p, int q);
+static bool asyncQueuePagePrecedes(int p, int q);
static void queue_listen(ListenActionKind action, const char *channel);
static void Async_UnlistenOnExit(int code, Datum arg);
static void Exec_ListenPreCommit(void);
@@ -388,25 +387,11 @@ static void NotifyMyFrontEnd(const char *channel,
static bool AsyncExistsPendingNotify(const char *channel, const char *payload);
static void ClearPendingActionsAndNotifies(void);
-
/*
* We will work on the page range of 0..QUEUE_MAX_PAGE.
- *
- * asyncQueuePagePrecedesPhysically just checks numerically without any magic
- * if one page precedes another one. This is wrong for normal operation but
- * is helpful when clearing pg_notify/ during startup.
- *
- * asyncQueuePagePrecedesLogically compares using wraparound logic, as is
- * required by slru.c.
*/
static bool
-asyncQueuePagePrecedesPhysically(int p, int q)
-{
- return p < q;
-}
-
-static bool
-asyncQueuePagePrecedesLogically(int p, int q)
+asyncQueuePagePrecedes(int p, int q)
{
int diff;
@@ -484,7 +469,7 @@ AsyncShmemInit(void)
/*
* Set up SLRU management of the pg_notify data.
*/
- AsyncCtl->PagePrecedes = asyncQueuePagePrecedesLogically;
+ AsyncCtl->PagePrecedes = asyncQueuePagePrecedes;
SimpleLruInit(AsyncCtl, "Async Ctl", NUM_ASYNC_BUFFERS, 0,
AsyncCtlLock, "pg_notify");
/* Override default assumption that writes should be fsync'd */
@@ -494,15 +479,8 @@ AsyncShmemInit(void)
{
/*
* During start or reboot, clean out the pg_notify directory.
- *
- * Since we want to remove every file, we temporarily use
- * asyncQueuePagePrecedesPhysically() and pass INT_MAX as the
- * comparison value; every file in the directory should therefore
- * appear to be less than that.
*/
- AsyncCtl->PagePrecedes = asyncQueuePagePrecedesPhysically;
- (void) SlruScanDirectory(AsyncCtl, INT_MAX, true);
- AsyncCtl->PagePrecedes = asyncQueuePagePrecedesLogically;
+ (void) SlruScanDirectory(AsyncCtl, SlruScanDirCbDeleteAll, NULL);
/* Now initialize page zero to empty */
LWLockAcquire(AsyncCtlLock, LW_EXCLUSIVE);
@@ -1223,7 +1201,7 @@ asyncQueueIsFull(void)
nexthead = 0; /* wrap around */
boundary = QUEUE_POS_PAGE(QUEUE_TAIL);
boundary -= boundary % SLRU_PAGES_PER_SEGMENT;
- return asyncQueuePagePrecedesLogically(nexthead, boundary);
+ return asyncQueuePagePrecedes(nexthead, boundary);
}
/*
@@ -2074,7 +2052,7 @@ asyncQueueAdvanceTail(void)
*/
newtailpage = QUEUE_POS_PAGE(min);
boundary = newtailpage - (newtailpage % SLRU_PAGES_PER_SEGMENT);
- if (asyncQueuePagePrecedesLogically(oldtailpage, boundary))
+ if (asyncQueuePagePrecedes(oldtailpage, boundary))
{
/*
* SimpleLruTruncate() will ask for AsyncCtlLock but will also release
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index c491b7d5f9f..e48743f55d7 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -145,6 +145,15 @@ extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruFlush(SlruCtl ctl, bool checkpoint);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
-extern bool SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions);
+
+typedef bool (*SlruScanCallback) (SlruCtl ctl, char *filename, int segpage,
+ void *data);
+extern bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data);
+
+/* SlruScanDirectory public callbacks */
+extern bool SlruScanDirCbReportPresence(SlruCtl ctl, char *filename,
+ int segpage, void *data);
+extern bool SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int segpage,
+ void *data);
#endif /* SLRU_H */