| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * bufmgr.h |
| 4 | * POSTGRES buffer manager definitions. |
| 5 | * |
| 6 | * |
| 7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 8 | * Portions Copyright (c) 1994, Regents of the University of California |
| 9 | * |
| 10 | * src/include/storage/bufmgr.h |
| 11 | * |
| 12 | *------------------------------------------------------------------------- |
| 13 | */ |
| 14 | #ifndef BUFMGR_H |
| 15 | #define BUFMGR_H |
| 16 | |
| 17 | #include "storage/block.h" |
| 18 | #include "storage/buf.h" |
| 19 | #include "storage/bufpage.h" |
| 20 | #include "storage/relfilenode.h" |
| 21 | #include "utils/relcache.h" |
| 22 | #include "utils/snapmgr.h" |
| 23 | |
| 24 | typedef void *Block; |
| 25 | |
| 26 | /* Possible arguments for GetAccessStrategy() */ |
| 27 | typedef enum BufferAccessStrategyType |
| 28 | { |
| 29 | BAS_NORMAL, /* Normal random access */ |
| 30 | BAS_BULKREAD, /* Large read-only scan (hint bit updates are |
| 31 | * ok) */ |
| 32 | BAS_BULKWRITE, /* Large multi-block write (e.g. COPY IN) */ |
| 33 | BAS_VACUUM /* VACUUM */ |
| 34 | } BufferAccessStrategyType; |
| 35 | |
| 36 | /* Possible modes for ReadBufferExtended() */ |
| 37 | typedef enum |
| 38 | { |
| 39 | RBM_NORMAL, /* Normal read */ |
| 40 | RBM_ZERO_AND_LOCK, /* Don't read from disk, caller will |
| 41 | * initialize. Also locks the page. */ |
| 42 | RBM_ZERO_AND_CLEANUP_LOCK, /* Like RBM_ZERO_AND_LOCK, but locks the page |
| 43 | * in "cleanup" mode */ |
| 44 | RBM_ZERO_ON_ERROR, /* Read, but return an all-zeros page on error */ |
| 45 | RBM_NORMAL_NO_LOG /* Don't log page as invalid during WAL |
| 46 | * replay; otherwise same as RBM_NORMAL */ |
| 47 | } ReadBufferMode; |
| 48 | |
| 49 | /* forward declared, to avoid having to expose buf_internals.h here */ |
| 50 | struct WritebackContext; |
| 51 | |
| 52 | /* in globals.c ... this duplicates miscadmin.h */ |
| 53 | extern PGDLLIMPORT int NBuffers; |
| 54 | |
| 55 | /* in bufmgr.c */ |
| 56 | extern bool zero_damaged_pages; |
| 57 | extern int bgwriter_lru_maxpages; |
| 58 | extern double bgwriter_lru_multiplier; |
| 59 | extern bool track_io_timing; |
| 60 | extern int target_prefetch_pages; |
| 61 | |
| 62 | extern int checkpoint_flush_after; |
| 63 | extern int backend_flush_after; |
| 64 | extern int bgwriter_flush_after; |
| 65 | |
| 66 | /* in buf_init.c */ |
| 67 | extern PGDLLIMPORT char *BufferBlocks; |
| 68 | |
| 69 | /* in guc.c */ |
| 70 | extern int effective_io_concurrency; |
| 71 | |
| 72 | /* in localbuf.c */ |
| 73 | extern PGDLLIMPORT int NLocBuffer; |
| 74 | extern PGDLLIMPORT Block *LocalBufferBlockPointers; |
| 75 | extern PGDLLIMPORT int32 *LocalRefCount; |
| 76 | |
| 77 | /* upper limit for effective_io_concurrency */ |
| 78 | #define MAX_IO_CONCURRENCY 1000 |
| 79 | |
| 80 | /* special block number for ReadBuffer() */ |
| 81 | #define P_NEW InvalidBlockNumber /* grow the file to get a new page */ |
| 82 | |
| 83 | /* |
| 84 | * Buffer content lock modes (mode argument for LockBuffer()) |
| 85 | */ |
| 86 | #define BUFFER_LOCK_UNLOCK 0 |
| 87 | #define BUFFER_LOCK_SHARE 1 |
| 88 | #define BUFFER_LOCK_EXCLUSIVE 2 |
| 89 | |
| 90 | /* |
| 91 | * These routines are beaten on quite heavily, hence the macroization. |
| 92 | */ |
| 93 | |
| 94 | /* |
| 95 | * BufferIsValid |
| 96 | * True iff the given buffer number is valid (either as a shared |
| 97 | * or local buffer). |
| 98 | * |
| 99 | * Note: For a long time this was defined the same as BufferIsPinned, |
| 100 | * that is it would say False if you didn't hold a pin on the buffer. |
| 101 | * I believe this was bogus and served only to mask logic errors. |
| 102 | * Code should always know whether it has a buffer reference, |
| 103 | * independently of the pin state. |
| 104 | * |
| 105 | * Note: For a further long time this was not quite the inverse of the |
| 106 | * BufferIsInvalid() macro, in that it also did sanity checks to verify |
| 107 | * that the buffer number was in range. Most likely, this macro was |
| 108 | * originally intended only to be used in assertions, but its use has |
| 109 | * since expanded quite a bit, and the overhead of making those checks |
| 110 | * even in non-assert-enabled builds can be significant. Thus, we've |
| 111 | * now demoted the range checks to assertions within the macro itself. |
| 112 | */ |
| 113 | #define BufferIsValid(bufnum) \ |
| 114 | ( \ |
| 115 | AssertMacro((bufnum) <= NBuffers && (bufnum) >= -NLocBuffer), \ |
| 116 | (bufnum) != InvalidBuffer \ |
| 117 | ) |
| 118 | |
| 119 | /* |
| 120 | * BufferGetBlock |
| 121 | * Returns a reference to a disk page image associated with a buffer. |
| 122 | * |
| 123 | * Note: |
| 124 | * Assumes buffer is valid. |
| 125 | */ |
| 126 | #define BufferGetBlock(buffer) \ |
| 127 | ( \ |
| 128 | AssertMacro(BufferIsValid(buffer)), \ |
| 129 | BufferIsLocal(buffer) ? \ |
| 130 | LocalBufferBlockPointers[-(buffer) - 1] \ |
| 131 | : \ |
| 132 | (Block) (BufferBlocks + ((Size) ((buffer) - 1)) * BLCKSZ) \ |
| 133 | ) |
| 134 | |
| 135 | /* |
| 136 | * BufferGetPageSize |
| 137 | * Returns the page size within a buffer. |
| 138 | * |
| 139 | * Notes: |
| 140 | * Assumes buffer is valid. |
| 141 | * |
| 142 | * The buffer can be a raw disk block and need not contain a valid |
| 143 | * (formatted) disk page. |
| 144 | */ |
| 145 | /* XXX should dig out of buffer descriptor */ |
| 146 | #define BufferGetPageSize(buffer) \ |
| 147 | ( \ |
| 148 | AssertMacro(BufferIsValid(buffer)), \ |
| 149 | (Size)BLCKSZ \ |
| 150 | ) |
| 151 | |
| 152 | /* |
| 153 | * BufferGetPage |
| 154 | * Returns the page associated with a buffer. |
| 155 | * |
| 156 | * When this is called as part of a scan, there may be a need for a nearby |
| 157 | * call to TestForOldSnapshot(). See the definition of that for details. |
| 158 | */ |
| 159 | #define BufferGetPage(buffer) ((Page)BufferGetBlock(buffer)) |
| 160 | |
| 161 | /* |
| 162 | * prototypes for functions in bufmgr.c |
| 163 | */ |
| 164 | extern bool ComputeIoConcurrency(int io_concurrency, double *target); |
| 165 | extern void PrefetchBuffer(Relation reln, ForkNumber forkNum, |
| 166 | BlockNumber blockNum); |
| 167 | extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum); |
| 168 | extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, |
| 169 | BlockNumber blockNum, ReadBufferMode mode, |
| 170 | BufferAccessStrategy strategy); |
| 171 | extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode, |
| 172 | ForkNumber forkNum, BlockNumber blockNum, |
| 173 | ReadBufferMode mode, BufferAccessStrategy strategy); |
| 174 | extern void ReleaseBuffer(Buffer buffer); |
| 175 | extern void UnlockReleaseBuffer(Buffer buffer); |
| 176 | extern void MarkBufferDirty(Buffer buffer); |
| 177 | extern void IncrBufferRefCount(Buffer buffer); |
| 178 | extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, |
| 179 | BlockNumber blockNum); |
| 180 | |
| 181 | extern void InitBufferPool(void); |
| 182 | extern void InitBufferPoolAccess(void); |
| 183 | extern void InitBufferPoolBackend(void); |
| 184 | extern void AtEOXact_Buffers(bool isCommit); |
| 185 | extern void PrintBufferLeakWarning(Buffer buffer); |
| 186 | extern void CheckPointBuffers(int flags); |
| 187 | extern BlockNumber BufferGetBlockNumber(Buffer buffer); |
| 188 | extern BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, |
| 189 | ForkNumber forkNum); |
| 190 | extern void FlushOneBuffer(Buffer buffer); |
| 191 | extern void FlushRelationBuffers(Relation rel); |
| 192 | extern void FlushDatabaseBuffers(Oid dbid); |
| 193 | extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, |
| 194 | ForkNumber forkNum, BlockNumber firstDelBlock); |
| 195 | extern void DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes); |
| 196 | extern void DropDatabaseBuffers(Oid dbid); |
| 197 | |
| 198 | #define RelationGetNumberOfBlocks(reln) \ |
| 199 | RelationGetNumberOfBlocksInFork(reln, MAIN_FORKNUM) |
| 200 | |
| 201 | extern bool BufferIsPermanent(Buffer buffer); |
| 202 | extern XLogRecPtr BufferGetLSNAtomic(Buffer buffer); |
| 203 | |
| 204 | #ifdef NOT_USED |
| 205 | extern void PrintPinnedBufs(void); |
| 206 | #endif |
| 207 | extern Size BufferShmemSize(void); |
| 208 | extern void BufferGetTag(Buffer buffer, RelFileNode *rnode, |
| 209 | ForkNumber *forknum, BlockNumber *blknum); |
| 210 | |
| 211 | extern void MarkBufferDirtyHint(Buffer buffer, bool buffer_std); |
| 212 | |
| 213 | extern void UnlockBuffers(void); |
| 214 | extern void LockBuffer(Buffer buffer, int mode); |
| 215 | extern bool ConditionalLockBuffer(Buffer buffer); |
| 216 | extern void LockBufferForCleanup(Buffer buffer); |
| 217 | extern bool ConditionalLockBufferForCleanup(Buffer buffer); |
| 218 | extern bool IsBufferCleanupOK(Buffer buffer); |
| 219 | extern bool HoldingBufferPinThatDelaysRecovery(void); |
| 220 | |
| 221 | extern void AbortBufferIO(void); |
| 222 | |
| 223 | extern void BufmgrCommit(void); |
| 224 | extern bool BgBufferSync(struct WritebackContext *wb_context); |
| 225 | |
| 226 | extern void AtProcExit_LocalBuffers(void); |
| 227 | |
| 228 | extern void TestForOldSnapshot_impl(Snapshot snapshot, Relation relation); |
| 229 | |
| 230 | /* in freelist.c */ |
| 231 | extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype); |
| 232 | extern void FreeAccessStrategy(BufferAccessStrategy strategy); |
| 233 | |
| 234 | |
| 235 | /* inline functions */ |
| 236 | |
| 237 | /* |
| 238 | * Although this header file is nominally backend-only, certain frontend |
| 239 | * programs like pg_waldump include it. For compilers that emit static |
| 240 | * inline functions even when they're unused, that leads to unsatisfied |
| 241 | * external references; hence hide these with #ifndef FRONTEND. |
| 242 | */ |
| 243 | |
| 244 | #ifndef FRONTEND |
| 245 | |
| 246 | /* |
| 247 | * Check whether the given snapshot is too old to have safely read the given |
| 248 | * page from the given table. If so, throw a "snapshot too old" error. |
| 249 | * |
| 250 | * This test generally needs to be performed after every BufferGetPage() call |
| 251 | * that is executed as part of a scan. It is not needed for calls made for |
| 252 | * modifying the page (for example, to position to the right place to insert a |
| 253 | * new index tuple or for vacuuming). It may also be omitted where calls to |
| 254 | * lower-level functions will have already performed the test. |
| 255 | * |
| 256 | * Note that a NULL snapshot argument is allowed and causes a fast return |
| 257 | * without error; this is to support call sites which can be called from |
| 258 | * either scans or index modification areas. |
| 259 | * |
| 260 | * For best performance, keep the tests that are fastest and/or most likely to |
| 261 | * exclude a page from old snapshot testing near the front. |
| 262 | */ |
| 263 | static inline void |
| 264 | TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page) |
| 265 | { |
| 266 | Assert(relation != NULL); |
| 267 | |
| 268 | if (old_snapshot_threshold >= 0 |
| 269 | && (snapshot) != NULL |
| 270 | && ((snapshot)->snapshot_type == SNAPSHOT_MVCC |
| 271 | || (snapshot)->snapshot_type == SNAPSHOT_TOAST) |
| 272 | && !XLogRecPtrIsInvalid((snapshot)->lsn) |
| 273 | && PageGetLSN(page) > (snapshot)->lsn) |
| 274 | TestForOldSnapshot_impl(snapshot, relation); |
| 275 | } |
| 276 | |
| 277 | #endif /* FRONTEND */ |
| 278 | |
| 279 | #endif /* BUFMGR_H */ |
| 280 | |