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 : #include "storage/shmem.h"
22 : #include "storage/subsystems.h"
23 :
24 : BufferDescPadded *BufferDescriptors;
25 : char *BufferBlocks;
26 : ConditionVariableMinimallyPadded *BufferIOCVArray;
27 : WritebackContext BackendWritebackContext;
28 : CkptSortItem *CkptBufferIds;
29 :
30 : static void BufferManagerShmemRequest(void *arg);
31 : static void BufferManagerShmemInit(void *arg);
32 : static void BufferManagerShmemAttach(void *arg);
33 :
34 : const ShmemCallbacks BufferManagerShmemCallbacks = {
35 : .request_fn = BufferManagerShmemRequest,
36 : .init_fn = BufferManagerShmemInit,
37 : .attach_fn = BufferManagerShmemAttach,
38 : };
39 :
40 : /*
41 : * Data Structures:
42 : * buffers live in a freelist and a lookup data structure.
43 : *
44 : *
45 : * Buffer Lookup:
46 : * Two important notes. First, the buffer has to be
47 : * available for lookup BEFORE an IO begins. Otherwise
48 : * a second process trying to read the buffer will
49 : * allocate its own copy and the buffer pool will
50 : * become inconsistent.
51 : *
52 : * Buffer Replacement:
53 : * see freelist.c. A buffer cannot be replaced while in
54 : * use either by data manager or during IO.
55 : *
56 : *
57 : * Synchronization/Locking:
58 : *
59 : * IO_IN_PROGRESS -- this is a flag in the buffer descriptor.
60 : * It must be set when an IO is initiated and cleared at
61 : * the end of the IO. It is there to make sure that one
62 : * process doesn't start to use a buffer while another is
63 : * faulting it in. see WaitIO and related routines.
64 : *
65 : * refcount -- Counts the number of processes holding pins on a buffer.
66 : * A buffer is pinned during IO and immediately after a BufferAlloc().
67 : * Pins must be released before end of transaction. For efficiency the
68 : * shared refcount isn't increased if an individual backend pins a buffer
69 : * multiple times. Check the PrivateRefCount infrastructure in bufmgr.c.
70 : */
71 :
72 :
73 : /*
74 : * Register shared memory area for the buffer pool.
75 : */
76 : static void
77 1234 : BufferManagerShmemRequest(void *arg)
78 : {
79 1234 : ShmemRequestStruct(.name = "Buffer Descriptors",
80 : .size = NBuffers * sizeof(BufferDescPadded),
81 : /* Align descriptors to a cacheline boundary. */
82 : .alignment = PG_CACHE_LINE_SIZE,
83 : .ptr = (void **) &BufferDescriptors,
84 : );
85 :
86 1234 : ShmemRequestStruct(.name = "Buffer Blocks",
87 : .size = NBuffers * (Size) BLCKSZ,
88 : /* Align buffer pool on IO page size boundary. */
89 : .alignment = PG_IO_ALIGN_SIZE,
90 : .ptr = (void **) &BufferBlocks,
91 : );
92 :
93 1234 : ShmemRequestStruct(.name = "Buffer IO Condition Variables",
94 : .size = NBuffers * sizeof(ConditionVariableMinimallyPadded),
95 : /* Align descriptors to a cacheline boundary. */
96 : .alignment = PG_CACHE_LINE_SIZE,
97 : .ptr = (void **) &BufferIOCVArray,
98 : );
99 :
100 : /*
101 : * The array used to sort to-be-checkpointed buffer ids is located in
102 : * shared memory, to avoid having to allocate significant amounts of
103 : * memory at runtime. As that'd be in the middle of a checkpoint, or when
104 : * the checkpointer is restarted, memory allocation failures would be
105 : * painful.
106 : */
107 1234 : ShmemRequestStruct(.name = "Checkpoint BufferIds",
108 : .size = NBuffers * sizeof(CkptSortItem),
109 : .ptr = (void **) &CkptBufferIds,
110 : );
111 1234 : }
112 :
113 : /*
114 : * Initialize shared buffer pool
115 : *
116 : * This is called once during shared-memory initialization (either in the
117 : * postmaster, or in a standalone backend).
118 : */
119 : static void
120 1231 : BufferManagerShmemInit(void *arg)
121 : {
122 : /*
123 : * Initialize all the buffer headers.
124 : */
125 11814871 : for (int i = 0; i < NBuffers; i++)
126 : {
127 11813640 : BufferDesc *buf = GetBufferDescriptor(i);
128 :
129 11813640 : ClearBufferTag(&buf->tag);
130 :
131 11813640 : pg_atomic_init_u64(&buf->state, 0);
132 11813640 : buf->wait_backend_pgprocno = INVALID_PROC_NUMBER;
133 :
134 11813640 : buf->buf_id = i;
135 :
136 11813640 : pgaio_wref_clear(&buf->io_wref);
137 :
138 11813640 : proclist_init(&buf->lock_waiters);
139 11813640 : ConditionVariableInit(BufferDescriptorGetIOCV(buf));
140 : }
141 :
142 : /* Initialize per-backend file flush context */
143 1231 : WritebackContextInit(&BackendWritebackContext,
144 : &backend_flush_after);
145 1231 : }
146 :
147 : static void
148 0 : BufferManagerShmemAttach(void *arg)
149 : {
150 : /* Initialize per-backend file flush context */
151 0 : WritebackContextInit(&BackendWritebackContext,
152 : &backend_flush_after);
153 0 : }
|