Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * buf_init.c 4 : * buffer manager initialization routines 5 : * 6 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group 7 : * Portions Copyright (c) 1994, Regents of the University of California 8 : * 9 : * 10 : * IDENTIFICATION 11 : * src/backend/storage/buffer/buf_init.c 12 : * 13 : *------------------------------------------------------------------------- 14 : */ 15 : #include "postgres.h" 16 : 17 : #include "storage/aio.h" 18 : #include "storage/buf_internals.h" 19 : #include "storage/bufmgr.h" 20 : #include "storage/proclist.h" 21 : 22 : BufferDescPadded *BufferDescriptors; 23 : char *BufferBlocks; 24 : ConditionVariableMinimallyPadded *BufferIOCVArray; 25 : WritebackContext BackendWritebackContext; 26 : CkptSortItem *CkptBufferIds; 27 : 28 : 29 : /* 30 : * Data Structures: 31 : * buffers live in a freelist and a lookup data structure. 32 : * 33 : * 34 : * Buffer Lookup: 35 : * Two important notes. First, the buffer has to be 36 : * available for lookup BEFORE an IO begins. Otherwise 37 : * a second process trying to read the buffer will 38 : * allocate its own copy and the buffer pool will 39 : * become inconsistent. 40 : * 41 : * Buffer Replacement: 42 : * see freelist.c. A buffer cannot be replaced while in 43 : * use either by data manager or during IO. 44 : * 45 : * 46 : * Synchronization/Locking: 47 : * 48 : * IO_IN_PROGRESS -- this is a flag in the buffer descriptor. 49 : * It must be set when an IO is initiated and cleared at 50 : * the end of the IO. It is there to make sure that one 51 : * process doesn't start to use a buffer while another is 52 : * faulting it in. see WaitIO and related routines. 53 : * 54 : * refcount -- Counts the number of processes holding pins on a buffer. 55 : * A buffer is pinned during IO and immediately after a BufferAlloc(). 56 : * Pins must be released before end of transaction. For efficiency the 57 : * shared refcount isn't increased if an individual backend pins a buffer 58 : * multiple times. Check the PrivateRefCount infrastructure in bufmgr.c. 59 : */ 60 : 61 : 62 : /* 63 : * Initialize shared buffer pool 64 : * 65 : * This is called once during shared-memory initialization (either in the 66 : * postmaster, or in a standalone backend). 67 : */ 68 : void 69 2280 : BufferManagerShmemInit(void) 70 : { 71 : bool foundBufs, 72 : foundDescs, 73 : foundIOCV, 74 : foundBufCkpt; 75 : 76 : /* Align descriptors to a cacheline boundary. */ 77 2280 : BufferDescriptors = (BufferDescPadded *) 78 2280 : ShmemInitStruct("Buffer Descriptors", 79 : NBuffers * sizeof(BufferDescPadded), 80 : &foundDescs); 81 : 82 : /* Align buffer pool on IO page size boundary. */ 83 2280 : BufferBlocks = (char *) 84 2280 : TYPEALIGN(PG_IO_ALIGN_SIZE, 85 : ShmemInitStruct("Buffer Blocks", 86 : NBuffers * (Size) BLCKSZ + PG_IO_ALIGN_SIZE, 87 : &foundBufs)); 88 : 89 : /* Align condition variables to cacheline boundary. */ 90 2280 : BufferIOCVArray = (ConditionVariableMinimallyPadded *) 91 2280 : ShmemInitStruct("Buffer IO Condition Variables", 92 : NBuffers * sizeof(ConditionVariableMinimallyPadded), 93 : &foundIOCV); 94 : 95 : /* 96 : * The array used to sort to-be-checkpointed buffer ids is located in 97 : * shared memory, to avoid having to allocate significant amounts of 98 : * memory at runtime. As that'd be in the middle of a checkpoint, or when 99 : * the checkpointer is restarted, memory allocation failures would be 100 : * painful. 101 : */ 102 2280 : CkptBufferIds = (CkptSortItem *) 103 2280 : ShmemInitStruct("Checkpoint BufferIds", 104 : NBuffers * sizeof(CkptSortItem), &foundBufCkpt); 105 : 106 2280 : if (foundDescs || foundBufs || foundIOCV || foundBufCkpt) 107 : { 108 : /* should find all of these, or none of them */ 109 : Assert(foundDescs && foundBufs && foundIOCV && foundBufCkpt); 110 : /* note: this path is only taken in EXEC_BACKEND case */ 111 : } 112 : else 113 : { 114 : int i; 115 : 116 : /* 117 : * Initialize all the buffer headers. 118 : */ 119 21189912 : for (i = 0; i < NBuffers; i++) 120 : { 121 21187632 : BufferDesc *buf = GetBufferDescriptor(i); 122 : 123 21187632 : ClearBufferTag(&buf->tag); 124 : 125 21187632 : pg_atomic_init_u64(&buf->state, 0); 126 21187632 : buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; 127 : 128 21187632 : buf->buf_id = i; 129 : 130 21187632 : pgaio_wref_clear(&buf->io_wref); 131 : 132 21187632 : proclist_init(&buf->lock_waiters); 133 21187632 : ConditionVariableInit(BufferDescriptorGetIOCV(buf)); 134 : } 135 : } 136 : 137 : /* Init other shared buffer-management stuff */ 138 2280 : StrategyInitialize(!foundDescs); 139 : 140 : /* Initialize per-backend file flush context */ 141 2280 : WritebackContextInit(&BackendWritebackContext, 142 : &backend_flush_after); 143 2280 : } 144 : 145 : /* 146 : * BufferManagerShmemSize 147 : * 148 : * compute the size of shared memory for the buffer pool including 149 : * data pages, buffer descriptors, hash tables, etc. 150 : */ 151 : Size 152 4254 : BufferManagerShmemSize(void) 153 : { 154 4254 : Size size = 0; 155 : 156 : /* size of buffer descriptors */ 157 4254 : size = add_size(size, mul_size(NBuffers, sizeof(BufferDescPadded))); 158 : /* to allow aligning buffer descriptors */ 159 4254 : size = add_size(size, PG_CACHE_LINE_SIZE); 160 : 161 : /* size of data pages, plus alignment padding */ 162 4254 : size = add_size(size, PG_IO_ALIGN_SIZE); 163 4254 : size = add_size(size, mul_size(NBuffers, BLCKSZ)); 164 : 165 : /* size of stuff controlled by freelist.c */ 166 4254 : size = add_size(size, StrategyShmemSize()); 167 : 168 : /* size of I/O condition variables */ 169 4254 : size = add_size(size, mul_size(NBuffers, 170 : sizeof(ConditionVariableMinimallyPadded))); 171 : /* to allow aligning the above */ 172 4254 : size = add_size(size, PG_CACHE_LINE_SIZE); 173 : 174 : /* size of checkpoint sort array in bufmgr.c */ 175 4254 : size = add_size(size, mul_size(NBuffers, sizeof(CkptSortItem))); 176 : 177 4254 : return size; 178 : }