Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 09e196e

Browse files
committed
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.
1 parent 1a00c0e commit 09e196e

File tree

4 files changed

+94
-59
lines changed

4 files changed

+94
-59
lines changed

src/backend/access/transam/clog.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ TruncateCLOG(TransactionId oldestXact)
606606
cutoffPage = TransactionIdToPage(oldestXact);
607607

608608
/* Check to see if there's any files that could be removed */
609-
if (!SlruScanDirectory(ClogCtl, cutoffPage, false))
609+
if (!SlruScanDirectory(ClogCtl, SlruScanDirCbReportPresence, &cutoffPage))
610610
return; /* nothing to remove */
611611

612612
/* Write XLOG record and flush XLOG to disk */

src/backend/access/transam/slru.c

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ static bool SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno,
132132
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid);
133133
static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
134134

135+
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
136+
int segpage, void *data);
135137

136138
/*
137139
* Initialization of shared memory
@@ -1137,33 +1139,84 @@ restart:;
11371139
LWLockRelease(shared->ControlLock);
11381140

11391141
/* Now we can remove the old segment(s) */
1140-
(void) SlruScanDirectory(ctl, cutoffPage, true);
1142+
(void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
11411143
}
11421144

11431145
/*
1144-
* SimpleLruTruncate subroutine: scan directory for removable segments.
1145-
* Actually remove them iff doDeletions is true. Return TRUE iff any
1146-
* removable segments were found. Note: no locking is needed.
1146+
* SlruScanDirectory callback
1147+
* This callback reports true if there's any segment prior to the one
1148+
* containing the page passed as "data".
1149+
*/
1150+
bool
1151+
SlruScanDirCbReportPresence(SlruCtl ctl, char *filename, int segpage, void *data)
1152+
{
1153+
int cutoffPage = *(int *) data;
1154+
1155+
cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1156+
1157+
if (ctl->PagePrecedes(segpage, cutoffPage))
1158+
return true; /* found one; don't iterate any more */
1159+
1160+
return false; /* keep going */
1161+
}
1162+
1163+
/*
1164+
* SlruScanDirectory callback.
1165+
* This callback deletes segments prior to the one passed in as "data".
1166+
*/
1167+
static bool
1168+
SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
1169+
{
1170+
char path[MAXPGPATH];
1171+
int cutoffPage = *(int *) data;
1172+
1173+
if (ctl->PagePrecedes(segpage, cutoffPage))
1174+
{
1175+
snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
1176+
ereport(DEBUG2,
1177+
(errmsg("removing file \"%s\"", path)));
1178+
unlink(path);
1179+
}
1180+
1181+
return false; /* keep going */
1182+
}
1183+
1184+
/*
1185+
* SlruScanDirectory callback.
1186+
* This callback deletes all segments.
1187+
*/
1188+
bool
1189+
SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int segpage, void *data)
1190+
{
1191+
char path[MAXPGPATH];
1192+
1193+
snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
1194+
ereport(DEBUG2,
1195+
(errmsg("removing file \"%s\"", path)));
1196+
unlink(path);
1197+
1198+
return false; /* keep going */
1199+
}
1200+
1201+
/*
1202+
* Scan the SimpleLRU directory and apply a callback to each file found in it.
1203+
*
1204+
* If the callback returns true, the scan is stopped. The last return value
1205+
* from the callback is returned.
11471206
*
1148-
* This can be called directly from clog.c, for reasons explained there.
1207+
* Note that the ordering in which the directory is scanned is not guaranteed.
1208+
*
1209+
* Note that no locking is applied.
11491210
*/
11501211
bool
1151-
SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
1212+
SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
11521213
{
1153-
bool found = false;
11541214
DIR *cldir;
11551215
struct dirent *clde;
11561216
int segno;
11571217
int segpage;
1158-
char path[MAXPGPATH];
1159-
1160-
/*
1161-
* The cutoff point is the start of the segment containing cutoffPage.
1162-
* (This is redundant when called from SimpleLruTruncate, but not when
1163-
* called directly from clog.c.)
1164-
*/
1165-
cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1166-
1218+
bool retval;
1219+
11671220
cldir = AllocateDir(ctl->Dir);
11681221
while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
11691222
{
@@ -1172,20 +1225,15 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
11721225
{
11731226
segno = (int) strtol(clde->d_name, NULL, 16);
11741227
segpage = segno * SLRU_PAGES_PER_SEGMENT;
1175-
if (ctl->PagePrecedes(segpage, cutoffPage))
1176-
{
1177-
found = true;
1178-
if (doDeletions)
1179-
{
1180-
snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, clde->d_name);
1181-
ereport(DEBUG2,
1182-
(errmsg("removing file \"%s\"", path)));
1183-
unlink(path);
1184-
}
1185-
}
1228+
1229+
elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1230+
ctl->Dir, clde->d_name);
1231+
retval = callback(ctl, clde->d_name, segpage, data);
1232+
if (retval)
1233+
break;
11861234
}
11871235
}
11881236
FreeDir(cldir);
11891237

1190-
return found;
1238+
return retval;
11911239
}

src/backend/commands/async.c

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ typedef struct QueuePosition
194194

195195
/* choose logically smaller QueuePosition */
196196
#define QUEUE_POS_MIN(x,y) \
197-
(asyncQueuePagePrecedesLogically((x).page, (y).page) ? (x) : \
197+
(asyncQueuePagePrecedes((x).page, (y).page) ? (x) : \
198198
(x).page != (y).page ? (y) : \
199199
(x).offset < (y).offset ? (x) : (y))
200200

@@ -360,8 +360,7 @@ static bool backendHasExecutedInitialListen = false;
360360
bool Trace_notify = false;
361361

362362
/* local function prototypes */
363-
static bool asyncQueuePagePrecedesPhysically(int p, int q);
364-
static bool asyncQueuePagePrecedesLogically(int p, int q);
363+
static bool asyncQueuePagePrecedes(int p, int q);
365364
static void queue_listen(ListenActionKind action, const char *channel);
366365
static void Async_UnlistenOnExit(int code, Datum arg);
367366
static void Exec_ListenPreCommit(void);
@@ -388,25 +387,11 @@ static void NotifyMyFrontEnd(const char *channel,
388387
static bool AsyncExistsPendingNotify(const char *channel, const char *payload);
389388
static void ClearPendingActionsAndNotifies(void);
390389

391-
392390
/*
393391
* We will work on the page range of 0..QUEUE_MAX_PAGE.
394-
*
395-
* asyncQueuePagePrecedesPhysically just checks numerically without any magic
396-
* if one page precedes another one. This is wrong for normal operation but
397-
* is helpful when clearing pg_notify/ during startup.
398-
*
399-
* asyncQueuePagePrecedesLogically compares using wraparound logic, as is
400-
* required by slru.c.
401392
*/
402393
static bool
403-
asyncQueuePagePrecedesPhysically(int p, int q)
404-
{
405-
return p < q;
406-
}
407-
408-
static bool
409-
asyncQueuePagePrecedesLogically(int p, int q)
394+
asyncQueuePagePrecedes(int p, int q)
410395
{
411396
int diff;
412397

@@ -484,7 +469,7 @@ AsyncShmemInit(void)
484469
/*
485470
* Set up SLRU management of the pg_notify data.
486471
*/
487-
AsyncCtl->PagePrecedes = asyncQueuePagePrecedesLogically;
472+
AsyncCtl->PagePrecedes = asyncQueuePagePrecedes;
488473
SimpleLruInit(AsyncCtl, "Async Ctl", NUM_ASYNC_BUFFERS, 0,
489474
AsyncCtlLock, "pg_notify");
490475
/* Override default assumption that writes should be fsync'd */
@@ -494,15 +479,8 @@ AsyncShmemInit(void)
494479
{
495480
/*
496481
* During start or reboot, clean out the pg_notify directory.
497-
*
498-
* Since we want to remove every file, we temporarily use
499-
* asyncQueuePagePrecedesPhysically() and pass INT_MAX as the
500-
* comparison value; every file in the directory should therefore
501-
* appear to be less than that.
502482
*/
503-
AsyncCtl->PagePrecedes = asyncQueuePagePrecedesPhysically;
504-
(void) SlruScanDirectory(AsyncCtl, INT_MAX, true);
505-
AsyncCtl->PagePrecedes = asyncQueuePagePrecedesLogically;
483+
(void) SlruScanDirectory(AsyncCtl, SlruScanDirCbDeleteAll, NULL);
506484

507485
/* Now initialize page zero to empty */
508486
LWLockAcquire(AsyncCtlLock, LW_EXCLUSIVE);
@@ -1223,7 +1201,7 @@ asyncQueueIsFull(void)
12231201
nexthead = 0; /* wrap around */
12241202
boundary = QUEUE_POS_PAGE(QUEUE_TAIL);
12251203
boundary -= boundary % SLRU_PAGES_PER_SEGMENT;
1226-
return asyncQueuePagePrecedesLogically(nexthead, boundary);
1204+
return asyncQueuePagePrecedes(nexthead, boundary);
12271205
}
12281206

12291207
/*
@@ -2074,7 +2052,7 @@ asyncQueueAdvanceTail(void)
20742052
*/
20752053
newtailpage = QUEUE_POS_PAGE(min);
20762054
boundary = newtailpage - (newtailpage % SLRU_PAGES_PER_SEGMENT);
2077-
if (asyncQueuePagePrecedesLogically(oldtailpage, boundary))
2055+
if (asyncQueuePagePrecedes(oldtailpage, boundary))
20782056
{
20792057
/*
20802058
* SimpleLruTruncate() will ask for AsyncCtlLock but will also release

src/include/access/slru.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,15 @@ extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
145145
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
146146
extern void SimpleLruFlush(SlruCtl ctl, bool checkpoint);
147147
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
148-
extern bool SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions);
148+
149+
typedef bool (*SlruScanCallback) (SlruCtl ctl, char *filename, int segpage,
150+
void *data);
151+
extern bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data);
152+
153+
/* SlruScanDirectory public callbacks */
154+
extern bool SlruScanDirCbReportPresence(SlruCtl ctl, char *filename,
155+
int segpage, void *data);
156+
extern bool SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int segpage,
157+
void *data);
149158

150159
#endif /* SLRU_H */

0 commit comments

Comments
 (0)