slru-truncate-callbacks.patch
application/octet-stream
Filename: slru-truncate-callbacks.patch
Type: application/octet-stream
Part: 0
Message:
have SLRU truncation use callbacks
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: context
| File | + | − |
|---|---|---|
| src/backend/access/transam/clog.c | 1 | 0 |
| src/backend/access/transam/slru.c | 76 | 0 |
| src/backend/commands/async.c | 7 | 0 |
| src/backend/commands/vacuum.c | 1 | 0 |
| src/include/access/slru.h | 10 | 0 |
*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
***************
*** 606,612 **** TruncateCLOG(TransactionId oldestXact)
cutoffPage = TransactionIdToPage(oldestXact);
/* Check to see if there's any files that could be removed */
! if (!SlruScanDirectory(ClogCtl, cutoffPage, false))
return; /* nothing to remove */
/* Write XLOG record and flush XLOG to disk */
--- 606,612 ----
cutoffPage = TransactionIdToPage(oldestXact);
/* Check to see if there's any files that could be removed */
! if (!SlruScanDirectory(ClogCtl, SlruScanDirCbReportPresence, &cutoffPage))
return; /* nothing to remove */
/* Write XLOG record and flush XLOG to disk */
*** a/src/backend/access/transam/slru.c
--- b/src/backend/access/transam/slru.c
***************
*** 132,137 **** static bool SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno,
--- 132,139 ----
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,1169 **** restart:;
LWLockRelease(shared->ControlLock);
/* Now we can remove the old segment(s) */
! (void) SlruScanDirectory(ctl, cutoffPage, true);
}
/*
! * 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.
*
! * This can be called directly from clog.c, for reasons explained there.
*/
bool
! SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
{
- 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;
!
cldir = AllocateDir(ctl->Dir);
while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
{
--- 1139,1222 ----
LWLockRelease(shared->ControlLock);
/* Now we can remove the old segment(s) */
! (void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
}
/*
! * 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.
*
! * Note that the ordering in which the directory is scanned is not guaranteed.
! *
! * Note that no locking is applied.
*/
bool
! SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
{
DIR *cldir;
struct dirent *clde;
int segno;
int segpage;
! bool retval;
!
cldir = AllocateDir(ctl->Dir);
while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
{
***************
*** 1172,1191 **** 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);
! }
! }
}
}
FreeDir(cldir);
! return found;
}
--- 1225,1239 ----
{
segno = (int) strtol(clde->d_name, NULL, 16);
segpage = segno * SLRU_PAGES_PER_SEGMENT;
!
! 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 retval;
}
*** a/src/backend/commands/async.c
--- b/src/backend/commands/async.c
***************
*** 194,200 **** typedef struct QueuePosition
/* choose logically smaller QueuePosition */
#define QUEUE_POS_MIN(x,y) \
! (asyncQueuePagePrecedesLogically((x).page, (y).page) ? (x) : \
(x).page != (y).page ? (y) : \
(x).offset < (y).offset ? (x) : (y))
--- 194,200 ----
/* choose logically smaller QueuePosition */
#define QUEUE_POS_MIN(x,y) \
! (asyncQueuePagePrecedes((x).page, (y).page) ? (x) : \
(x).page != (y).page ? (y) : \
(x).offset < (y).offset ? (x) : (y))
***************
*** 360,367 **** 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 void queue_listen(ListenActionKind action, const char *channel);
static void Async_UnlistenOnExit(int code, Datum arg);
static void Exec_ListenPreCommit(void);
--- 360,366 ----
bool Trace_notify = false;
/* local function prototypes */
! 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,412 **** 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)
{
int diff;
--- 387,397 ----
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.
*/
static bool
! asyncQueuePagePrecedes(int p, int q)
{
int diff;
***************
*** 484,490 **** AsyncShmemInit(void)
/*
* Set up SLRU management of the pg_notify data.
*/
! AsyncCtl->PagePrecedes = asyncQueuePagePrecedesLogically;
SimpleLruInit(AsyncCtl, "Async Ctl", NUM_ASYNC_BUFFERS, 0,
AsyncCtlLock, "pg_notify");
/* Override default assumption that writes should be fsync'd */
--- 469,475 ----
/*
* Set up SLRU management of the pg_notify data.
*/
! AsyncCtl->PagePrecedes = asyncQueuePagePrecedes;
SimpleLruInit(AsyncCtl, "Async Ctl", NUM_ASYNC_BUFFERS, 0,
AsyncCtlLock, "pg_notify");
/* Override default assumption that writes should be fsync'd */
***************
*** 494,508 **** 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;
/* Now initialize page zero to empty */
LWLockAcquire(AsyncCtlLock, LW_EXCLUSIVE);
--- 479,486 ----
{
/*
* During start or reboot, clean out the pg_notify directory.
*/
! (void) SlruScanDirectory(AsyncCtl, SlruScanDirCbDeleteAll, NULL);
/* Now initialize page zero to empty */
LWLockAcquire(AsyncCtlLock, LW_EXCLUSIVE);
***************
*** 1223,1229 **** asyncQueueIsFull(void)
nexthead = 0; /* wrap around */
boundary = QUEUE_POS_PAGE(QUEUE_TAIL);
boundary -= boundary % SLRU_PAGES_PER_SEGMENT;
! return asyncQueuePagePrecedesLogically(nexthead, boundary);
}
/*
--- 1201,1207 ----
nexthead = 0; /* wrap around */
boundary = QUEUE_POS_PAGE(QUEUE_TAIL);
boundary -= boundary % SLRU_PAGES_PER_SEGMENT;
! return asyncQueuePagePrecedes(nexthead, boundary);
}
/*
***************
*** 2074,2080 **** asyncQueueAdvanceTail(void)
*/
newtailpage = QUEUE_POS_PAGE(min);
boundary = newtailpage - (newtailpage % SLRU_PAGES_PER_SEGMENT);
! if (asyncQueuePagePrecedesLogically(oldtailpage, boundary))
{
/*
* SimpleLruTruncate() will ask for AsyncCtlLock but will also release
--- 2052,2058 ----
*/
newtailpage = QUEUE_POS_PAGE(min);
boundary = newtailpage - (newtailpage % SLRU_PAGES_PER_SEGMENT);
! if (asyncQueuePagePrecedes(oldtailpage, boundary))
{
/*
* SimpleLruTruncate() will ask for AsyncCtlLock but will also release
*** a/src/backend/commands/vacuum.c
--- b/src/backend/commands/vacuum.c
***************
*** 674,680 **** vac_update_datfrozenxid(void)
* Initialize the "min" calculation with GetOldestXmin, which is a
* reasonable approximation to the minimum relfrozenxid for not-yet-
* committed pg_class entries for new tables; see AddNewRelationTuple().
! * Se we cannot produce a wrong minimum by starting with this.
*/
newFrozenXid = GetOldestXmin(true, true);
--- 674,680 ----
* Initialize the "min" calculation with GetOldestXmin, which is a
* reasonable approximation to the minimum relfrozenxid for not-yet-
* committed pg_class entries for new tables; see AddNewRelationTuple().
! * So we cannot produce a wrong minimum by starting with this.
*/
newFrozenXid = GetOldestXmin(true, true);
*** a/src/include/access/slru.h
--- b/src/include/access/slru.h
***************
*** 145,150 **** 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);
#endif /* SLRU_H */
--- 145,159 ----
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruFlush(SlruCtl ctl, bool checkpoint);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
!
! 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 */