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