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