| /*------------------------------------------------------------------------- |
| * |
| * bufmgr.h |
| * POSTGRES buffer manager definitions. |
| * |
| * |
| * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group |
| * Portions Copyright (c) 1994, Regents of the University of California |
| * |
| * src/include/storage/bufmgr.h |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #ifndef BUFMGR_H |
| #define BUFMGR_H |
| |
| #include "storage/block.h" |
| #include "storage/buf.h" |
| #include "storage/bufpage.h" |
| #include "storage/relfilenode.h" |
| #include "storage/smgr.h" |
| #include "utils/relcache.h" |
| #include "utils/snapmgr.h" |
| |
| typedef void *Block; |
| |
| /* Possible arguments for GetAccessStrategy() */ |
| typedef enum BufferAccessStrategyType |
| { |
| BAS_NORMAL, /* Normal random access */ |
| BAS_BULKREAD, /* Large read-only scan (hint bit updates are |
| * ok) */ |
| BAS_BULKWRITE, /* Large multi-block write (e.g. COPY IN) */ |
| BAS_VACUUM /* VACUUM */ |
| } BufferAccessStrategyType; |
| |
| /* Possible modes for ReadBufferExtended() */ |
| typedef enum |
| { |
| RBM_NORMAL, /* Normal read */ |
| RBM_ZERO_AND_LOCK, /* Don't read from disk, caller will |
| * initialize. Also locks the page. */ |
| RBM_ZERO_AND_CLEANUP_LOCK, /* Like RBM_ZERO_AND_LOCK, but locks the page |
| * in "cleanup" mode */ |
| RBM_ZERO_ON_ERROR, /* Read, but return an all-zeros page on error */ |
| RBM_NORMAL_NO_LOG /* Don't log page as invalid during WAL |
| * replay; otherwise same as RBM_NORMAL */ |
| } ReadBufferMode; |
| |
| /* |
| * Type returned by PrefetchBuffer(). |
| */ |
| typedef struct PrefetchBufferResult |
| { |
| Buffer recent_buffer; /* If valid, a hit (recheck needed!) */ |
| bool initiated_io; /* If true, a miss resulting in async I/O */ |
| } PrefetchBufferResult; |
| |
| /* forward declared, to avoid having to expose buf_internals.h here */ |
| struct WritebackContext; |
| |
| /* forward declared, to avoid including smgr.h here */ |
| struct SMgrRelationData; |
| |
| /* in globals.c ... this duplicates miscadmin.h */ |
| extern PGDLLIMPORT int NBuffers; |
| |
| /* in bufmgr.c */ |
| extern bool zero_damaged_pages; |
| extern int bgwriter_lru_maxpages; |
| extern double bgwriter_lru_multiplier; |
| extern bool track_io_timing; |
| extern int effective_io_concurrency; |
| extern int maintenance_io_concurrency; |
| |
| extern int checkpoint_flush_after; |
| extern int backend_flush_after; |
| extern int bgwriter_flush_after; |
| |
| /* in buf_init.c */ |
| extern PGDLLIMPORT char *BufferBlocks; |
| |
| /* in localbuf.c */ |
| extern PGDLLIMPORT int NLocBuffer; |
| extern PGDLLIMPORT Block *LocalBufferBlockPointers; |
| extern PGDLLIMPORT int32 *LocalRefCount; |
| |
| /* upper limit for effective_io_concurrency */ |
| #define MAX_IO_CONCURRENCY 1000 |
| |
| /* special block number for ReadBuffer() */ |
| #define P_NEW InvalidBlockNumber /* grow the file to get a new page */ |
| |
| /* |
| * Buffer content lock modes (mode argument for LockBuffer()) |
| */ |
| #define BUFFER_LOCK_UNLOCK 0 |
| #define BUFFER_LOCK_SHARE 1 |
| #define BUFFER_LOCK_EXCLUSIVE 2 |
| |
| /* |
| * These routines are beaten on quite heavily, hence the macroization. |
| */ |
| |
| /* |
| * BufferIsValid |
| * True iff the given buffer number is valid (either as a shared |
| * or local buffer). |
| * |
| * Note: For a long time this was defined the same as BufferIsPinned, |
| * that is it would say False if you didn't hold a pin on the buffer. |
| * I believe this was bogus and served only to mask logic errors. |
| * Code should always know whether it has a buffer reference, |
| * independently of the pin state. |
| * |
| * Note: For a further long time this was not quite the inverse of the |
| * BufferIsInvalid() macro, in that it also did sanity checks to verify |
| * that the buffer number was in range. Most likely, this macro was |
| * originally intended only to be used in assertions, but its use has |
| * since expanded quite a bit, and the overhead of making those checks |
| * even in non-assert-enabled builds can be significant. Thus, we've |
| * now demoted the range checks to assertions within the macro itself. |
| */ |
| #define BufferIsValid(bufnum) \ |
| ( \ |
| AssertMacro((bufnum) <= NBuffers && (bufnum) >= -NLocBuffer), \ |
| (bufnum) != InvalidBuffer \ |
| ) |
| |
| /* |
| * BufferGetBlock |
| * Returns a reference to a disk page image associated with a buffer. |
| * |
| * Note: |
| * Assumes buffer is valid. |
| */ |
| #define BufferGetBlock(buffer) \ |
| ( \ |
| AssertMacro(BufferIsValid(buffer)), \ |
| BufferIsLocal(buffer) ? \ |
| LocalBufferBlockPointers[-(buffer) - 1] \ |
| : \ |
| (Block) (BufferBlocks + ((Size) ((buffer) - 1)) * BLCKSZ) \ |
| ) |
| |
| /* |
| * BufferGetPageSize |
| * Returns the page size within a buffer. |
| * |
| * Notes: |
| * Assumes buffer is valid. |
| * |
| * The buffer can be a raw disk block and need not contain a valid |
| * (formatted) disk page. |
| */ |
| /* XXX should dig out of buffer descriptor */ |
| #define BufferGetPageSize(buffer) \ |
| ( \ |
| AssertMacro(BufferIsValid(buffer)), \ |
| (Size)BLCKSZ \ |
| ) |
| |
| /* |
| * BufferGetPage |
| * Returns the page associated with a buffer. |
| * |
| * When this is called as part of a scan, there may be a need for a nearby |
| * call to TestForOldSnapshot(). See the definition of that for details. |
| */ |
| #define BufferGetPage(buffer) ((Page)BufferGetBlock(buffer)) |
| |
| typedef Buffer (*ReadBuffer_hook_type)(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, |
| BlockNumber blockNum, ReadBufferMode mode, |
| BufferAccessStrategy strategy, bool *hit); |
| extern PGDLLIMPORT ReadBuffer_hook_type ReadBuffer_hook; |
| |
| /* |
| * prototypes for functions in bufmgr.c |
| */ |
| extern PrefetchBufferResult PrefetchSharedBuffer(struct SMgrRelationData *smgr_reln, |
| ForkNumber forkNum, |
| BlockNumber blockNum); |
| extern PrefetchBufferResult PrefetchBuffer(Relation reln, ForkNumber forkNum, |
| BlockNumber blockNum); |
| extern bool ReadRecentBuffer(RelFileNode rnode, ForkNumber forkNum, |
| BlockNumber blockNum, Buffer recent_buffer); |
| extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum); |
| extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, |
| BlockNumber blockNum, ReadBufferMode mode, |
| BufferAccessStrategy strategy); |
| extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode, |
| ForkNumber forkNum, BlockNumber blockNum, |
| ReadBufferMode mode, BufferAccessStrategy strategy); |
| extern void ReleaseBuffer(Buffer buffer); |
| extern void UnlockReleaseBuffer(Buffer buffer); |
| extern void MarkBufferDirty(Buffer buffer); |
| extern void IncrBufferRefCount(Buffer buffer); |
| extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, |
| BlockNumber blockNum); |
| |
| extern void InitBufferPool(void); |
| extern void InitBufferPoolAccess(void); |
| extern void InitBufferPoolBackend(void); |
| extern void AtEOXact_Buffers(bool isCommit); |
| extern void PrintBufferLeakWarning(Buffer buffer); |
| extern void CheckPointBuffers(int flags); |
| extern BlockNumber BufferGetBlockNumber(Buffer buffer); |
| extern BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, |
| ForkNumber forkNum); |
| extern void FlushOneBuffer(Buffer buffer); |
| extern void FlushRelationBuffers(Relation rel); |
| extern void FlushRelationsAllBuffers(struct SMgrRelationData **smgrs, int nrels); |
| extern void FlushDatabaseBuffers(Oid dbid); |
| extern void DropRelFileNodeBuffers(struct SMgrRelationData *smgr_reln, ForkNumber *forkNum, |
| int nforks, BlockNumber *firstDelBlock); |
| extern void DropRelFileNodesAllBuffers(struct SMgrRelationData **smgr_reln, int nnodes); |
| extern void DropDatabaseBuffers(Oid dbid); |
| |
| /* |
| * GPDB: it is possible to need to calculate the number of blocks from the table |
| * size. An example use case is when we are the dispatcher and we need to |
| * acquire the number of blocks from all segments. |
| * |
| * Use the same calculation that RelationGetNumberOfBlocksInFork is using. |
| */ |
| static inline BlockNumber |
| RelationGuessNumberOfBlocksFromSize(uint64 szbytes) |
| { |
| return (szbytes + (BLCKSZ - 1)) / BLCKSZ; |
| } |
| |
| #define RelationGetNumberOfBlocks(reln) \ |
| RelationGetNumberOfBlocksInFork(reln, MAIN_FORKNUM) |
| |
| extern BlockNumber AcquireNumberOfBlocks(Relation onerel); |
| extern BlockNumber AcquireNumberOfAllVisibleBlocks(Relation onerel); |
| |
| extern bool BufferIsPermanent(Buffer buffer); |
| extern XLogRecPtr BufferGetLSNAtomic(Buffer buffer); |
| |
| #ifdef NOT_USED |
| extern void PrintPinnedBufs(void); |
| #endif |
| extern Size BufferShmemSize(void); |
| extern void BufferGetTag(Buffer buffer, RelFileNode *rnode, |
| ForkNumber *forknum, BlockNumber *blknum); |
| |
| extern void MarkBufferDirtyHint(Buffer buffer, bool buffer_std); |
| |
| extern void UnlockBuffers(void); |
| extern void LockBuffer(Buffer buffer, int mode); |
| extern bool ConditionalLockBuffer(Buffer buffer); |
| extern void LockBufferForCleanup(Buffer buffer); |
| extern bool ConditionalLockBufferForCleanup(Buffer buffer); |
| extern bool IsBufferCleanupOK(Buffer buffer); |
| extern bool HoldingBufferPinThatDelaysRecovery(void); |
| |
| extern void AbortBufferIO(void); |
| |
| extern void BufmgrCommit(void); |
| extern bool BgBufferSync(struct WritebackContext *wb_context); |
| |
| extern void AtProcExit_LocalBuffers(void); |
| |
| extern void TestForOldSnapshot_impl(Snapshot snapshot, Relation relation); |
| |
| /* in freelist.c */ |
| extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype); |
| extern void FreeAccessStrategy(BufferAccessStrategy strategy); |
| |
| |
| /* inline functions */ |
| |
| /* |
| * Although this header file is nominally backend-only, certain frontend |
| * programs like pg_waldump include it. For compilers that emit static |
| * inline functions even when they're unused, that leads to unsatisfied |
| * external references; hence hide these with #ifndef FRONTEND. |
| */ |
| |
| #ifndef FRONTEND |
| |
| /* |
| * Check whether the given snapshot is too old to have safely read the given |
| * page from the given table. If so, throw a "snapshot too old" error. |
| * |
| * This test generally needs to be performed after every BufferGetPage() call |
| * that is executed as part of a scan. It is not needed for calls made for |
| * modifying the page (for example, to position to the right place to insert a |
| * new index tuple or for vacuuming). It may also be omitted where calls to |
| * lower-level functions will have already performed the test. |
| * |
| * Note that a NULL snapshot argument is allowed and causes a fast return |
| * without error; this is to support call sites which can be called from |
| * either scans or index modification areas. |
| * |
| * For best performance, keep the tests that are fastest and/or most likely to |
| * exclude a page from old snapshot testing near the front. |
| */ |
| static inline void |
| TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page) |
| { |
| Assert(relation != NULL); |
| |
| if (old_snapshot_threshold >= 0 |
| && (snapshot) != NULL |
| && ((snapshot)->snapshot_type == SNAPSHOT_MVCC |
| || (snapshot)->snapshot_type == SNAPSHOT_TOAST) |
| && !XLogRecPtrIsInvalid((snapshot)->lsn) |
| && PageGetLSN(page) > (snapshot)->lsn) |
| TestForOldSnapshot_impl(snapshot, relation); |
| } |
| |
| #endif /* FRONTEND */ |
| |
| #endif /* BUFMGR_H */ |