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 1159 : BufferManagerShmemInit(void)
70 : {
71 : bool foundBufs,
72 : foundDescs,
73 : foundIOCV,
74 : foundBufCkpt;
75 :
76 : /* Align descriptors to a cacheline boundary. */
77 1159 : BufferDescriptors = (BufferDescPadded *)
78 1159 : ShmemInitStruct("Buffer Descriptors",
79 : NBuffers * sizeof(BufferDescPadded),
80 : &foundDescs);
81 :
82 : /* Align buffer pool on IO page size boundary. */
83 1159 : BufferBlocks = (char *)
84 1159 : 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 1159 : BufferIOCVArray = (ConditionVariableMinimallyPadded *)
91 1159 : 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 1159 : CkptBufferIds = (CkptSortItem *)
103 1159 : ShmemInitStruct("Checkpoint BufferIds",
104 : NBuffers * sizeof(CkptSortItem), &foundBufCkpt);
105 :
106 1159 : 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 10873759 : for (i = 0; i < NBuffers; i++)
120 : {
121 10872600 : BufferDesc *buf = GetBufferDescriptor(i);
122 :
123 10872600 : ClearBufferTag(&buf->tag);
124 :
125 10872600 : pg_atomic_init_u64(&buf->state, 0);
126 10872600 : buf->wait_backend_pgprocno = INVALID_PROC_NUMBER;
127 :
128 10872600 : buf->buf_id = i;
129 :
130 10872600 : pgaio_wref_clear(&buf->io_wref);
131 :
132 10872600 : proclist_init(&buf->lock_waiters);
133 10872600 : ConditionVariableInit(BufferDescriptorGetIOCV(buf));
134 : }
135 : }
136 :
137 : /* Init other shared buffer-management stuff */
138 1159 : StrategyInitialize(!foundDescs);
139 :
140 : /* Initialize per-backend file flush context */
141 1159 : WritebackContextInit(&BackendWritebackContext,
142 : &backend_flush_after);
143 1159 : }
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 2165 : BufferManagerShmemSize(void)
153 : {
154 2165 : Size size = 0;
155 :
156 : /* size of buffer descriptors */
157 2165 : size = add_size(size, mul_size(NBuffers, sizeof(BufferDescPadded)));
158 : /* to allow aligning buffer descriptors */
159 2165 : size = add_size(size, PG_CACHE_LINE_SIZE);
160 :
161 : /* size of data pages, plus alignment padding */
162 2165 : size = add_size(size, PG_IO_ALIGN_SIZE);
163 2165 : size = add_size(size, mul_size(NBuffers, BLCKSZ));
164 :
165 : /* size of stuff controlled by freelist.c */
166 2165 : size = add_size(size, StrategyShmemSize());
167 :
168 : /* size of I/O condition variables */
169 2165 : size = add_size(size, mul_size(NBuffers,
170 : sizeof(ConditionVariableMinimallyPadded)));
171 : /* to allow aligning the above */
172 2165 : size = add_size(size, PG_CACHE_LINE_SIZE);
173 :
174 : /* size of checkpoint sort array in bufmgr.c */
175 2165 : size = add_size(size, mul_size(NBuffers, sizeof(CkptSortItem)));
176 :
177 2165 : return size;
178 : }
|