On Tue, Aug 30, 2022 at 03:22:43PM -0700, Nathan Bossart wrote: > Okay, will do.
v2 attached. -- Nathan Bossart Amazon Web Services: https://aws.amazon.com
>From df1556c6da69f8c0aae9f8878f24e21907cf4d89 Mon Sep 17 00:00:00 2001 From: Nathan Bossart <nathandboss...@gmail.com> Date: Thu, 11 Aug 2022 16:24:26 -0700 Subject: [PATCH v2 1/1] Introduce bufmgr hooks. These hooks can be used for maintaining a secondary buffer cache outside of the regular shared buffers. In theory, there are many other potential uses. --- src/backend/storage/buffer/bufmgr.c | 35 +++++++++++++++++++++-------- src/include/storage/buf_internals.h | 14 ++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index e898ffad7b..5448716a1d 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -166,6 +166,15 @@ static bool IsForInput; /* local state for LockBufferForCleanup */ static BufferDesc *PinCountWaitBuf = NULL; +/* hook for plugins to get control when reading in a page */ +bufmgr_read_hook_type bufmgr_read_hook = NULL; + +/* hook for plugins to get control when writing a page */ +bufmgr_write_hook_type bufmgr_write_hook = NULL; + +/* hook for plugins to get control when invalidating a page */ +bufmgr_invalidate_hook_type bufmgr_invalidate_hook = NULL; + /* * Backend-Private refcount management: * @@ -482,7 +491,7 @@ static BufferDesc *BufferAlloc(SMgrRelation smgr, BlockNumber blockNum, BufferAccessStrategy strategy, bool *foundPtr); -static void FlushBuffer(BufferDesc *buf, SMgrRelation reln); +static void FlushBuffer(BufferDesc *buf, SMgrRelation reln, bool for_eviction); static void FindAndDropRelationBuffers(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber nForkBlock, @@ -1018,7 +1027,9 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, if (track_io_timing) INSTR_TIME_SET_CURRENT(io_start); - smgrread(smgr, forkNum, blockNum, (char *) bufBlock); + if (!bufmgr_read_hook || + !(*bufmgr_read_hook) (smgr, forkNum, blockNum, (char *) bufBlock)) + smgrread(smgr, forkNum, blockNum, (char *) bufBlock); if (track_io_timing) { @@ -1269,7 +1280,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, smgr->smgr_rlocator.locator.dbOid, smgr->smgr_rlocator.locator.relNumber); - FlushBuffer(buf, NULL); + FlushBuffer(buf, NULL, true); LWLockRelease(BufferDescriptorGetContentLock(buf)); ScheduleBufferTagForWriteback(&BackendWritebackContext, @@ -1544,6 +1555,9 @@ retry: goto retry; } + if (bufmgr_invalidate_hook) + (*bufmgr_invalidate_hook) (buf); + /* * Clear out the buffer's tag and flags. We must do this to ensure that * linear scans of the buffer array don't think the buffer is valid. @@ -2573,7 +2587,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) PinBuffer_Locked(bufHdr); LWLockAcquire(BufferDescriptorGetContentLock(bufHdr), LW_SHARED); - FlushBuffer(bufHdr, NULL); + FlushBuffer(bufHdr, NULL, false); LWLockRelease(BufferDescriptorGetContentLock(bufHdr)); @@ -2823,7 +2837,7 @@ BufferGetTag(Buffer buffer, RelFileLocator *rlocator, ForkNumber *forknum, * as the second parameter. If not, pass NULL. */ static void -FlushBuffer(BufferDesc *buf, SMgrRelation reln) +FlushBuffer(BufferDesc *buf, SMgrRelation reln, bool for_eviction) { XLogRecPtr recptr; ErrorContextCallback errcallback; @@ -2903,6 +2917,9 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln) */ bufToWrite = PageSetChecksumCopy((Page) bufBlock, buf->tag.blockNum); + if (bufmgr_write_hook) + (*bufmgr_write_hook) (reln, buf, bufToWrite, for_eviction); + if (track_io_timing) INSTR_TIME_SET_CURRENT(io_start); @@ -3589,7 +3606,7 @@ FlushRelationBuffers(Relation rel) { PinBuffer_Locked(bufHdr); LWLockAcquire(BufferDescriptorGetContentLock(bufHdr), LW_SHARED); - FlushBuffer(bufHdr, RelationGetSmgr(rel)); + FlushBuffer(bufHdr, RelationGetSmgr(rel), false); LWLockRelease(BufferDescriptorGetContentLock(bufHdr)); UnpinBuffer(bufHdr, true); } @@ -3687,7 +3704,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { PinBuffer_Locked(bufHdr); LWLockAcquire(BufferDescriptorGetContentLock(bufHdr), LW_SHARED); - FlushBuffer(bufHdr, srelent->srel); + FlushBuffer(bufHdr, srelent->srel, false); LWLockRelease(BufferDescriptorGetContentLock(bufHdr)); UnpinBuffer(bufHdr, true); } @@ -3897,7 +3914,7 @@ FlushDatabaseBuffers(Oid dbid) { PinBuffer_Locked(bufHdr); LWLockAcquire(BufferDescriptorGetContentLock(bufHdr), LW_SHARED); - FlushBuffer(bufHdr, NULL); + FlushBuffer(bufHdr, NULL, false); LWLockRelease(BufferDescriptorGetContentLock(bufHdr)); UnpinBuffer(bufHdr, true); } @@ -3924,7 +3941,7 @@ FlushOneBuffer(Buffer buffer) Assert(LWLockHeldByMe(BufferDescriptorGetContentLock(bufHdr))); - FlushBuffer(bufHdr, NULL); + FlushBuffer(bufHdr, NULL, false); } /* diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 406db6be78..ef8b683da3 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -382,6 +382,20 @@ typedef struct CkptSortItem extern PGDLLIMPORT CkptSortItem *CkptBufferIds; +/* hook for plugins to get control when reading in a page */ +typedef bool (*bufmgr_read_hook_type) (SMgrRelation smgr, ForkNumber forknum, + BlockNumber blocknum, char *buffer); +extern PGDLLIMPORT bufmgr_read_hook_type bufmgr_read_hook; + +/* hook for plugins to get control when writing a page */ +typedef void (*bufmgr_write_hook_type) (SMgrRelation smgr, BufferDesc *buf, + char *buffer, bool for_eviction); +extern PGDLLIMPORT bufmgr_write_hook_type bufmgr_write_hook; + +/* hook for plugins to get control when invalidating a page */ +typedef void (*bufmgr_invalidate_hook_type) (BufferDesc *buf); +extern PGDLLIMPORT bufmgr_invalidate_hook_type bufmgr_invalidate_hook; + /* * Internal buffer management routines */ -- 2.25.1