Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * aio_init.c
4 : * AIO - Subsystem Initialization
5 : *
6 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * IDENTIFICATION
10 : * src/backend/storage/aio/aio_init.c
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 :
15 : #include "postgres.h"
16 :
17 : #include "miscadmin.h"
18 : #include "storage/aio.h"
19 : #include "storage/aio_internal.h"
20 : #include "storage/aio_subsys.h"
21 : #include "storage/bufmgr.h"
22 : #include "storage/io_worker.h"
23 : #include "storage/ipc.h"
24 : #include "storage/proc.h"
25 : #include "storage/shmem.h"
26 : #include "storage/subsystems.h"
27 : #include "utils/guc.h"
28 :
29 :
30 : static void AioShmemRequest(void *arg);
31 : static void AioShmemInit(void *arg);
32 : static void AioShmemAttach(void *arg);
33 :
34 : const ShmemCallbacks AioShmemCallbacks = {
35 : .request_fn = AioShmemRequest,
36 : .init_fn = AioShmemInit,
37 : .attach_fn = AioShmemAttach,
38 : };
39 :
40 : static PgAioBackend *AioBackendShmemPtr;
41 : static PgAioHandle *AioHandleShmemPtr;
42 : static struct iovec *AioHandleIOVShmemPtr;
43 : static uint64 *AioHandleDataShmemPtr;
44 :
45 : static uint32
46 193344 : AioProcs(void)
47 : {
48 : /*
49 : * While AIO workers don't need their own AIO context, we can't currently
50 : * guarantee that nothing gets assigned to an IO worker's ProcNumber if we
51 : * just subtracted MAX_IO_WORKERS.
52 : */
53 193344 : return MaxBackends + NUM_AUXILIARY_PROCS;
54 : }
55 :
56 : static Size
57 1233 : AioBackendShmemSize(void)
58 : {
59 1233 : return mul_size(AioProcs(), sizeof(PgAioBackend));
60 : }
61 :
62 : static Size
63 1233 : AioHandleShmemSize(void)
64 : {
65 : Size sz;
66 :
67 : /* verify AioChooseMaxConcurrency() did its thing */
68 : Assert(io_max_concurrency > 0);
69 :
70 : /* io handles */
71 1233 : sz = mul_size(AioProcs(),
72 : mul_size(io_max_concurrency, sizeof(PgAioHandle)));
73 :
74 1233 : return sz;
75 : }
76 :
77 : static Size
78 1233 : AioHandleIOVShmemSize(void)
79 : {
80 : /* each IO handle can have up to io_max_combine_limit iovec objects */
81 1233 : return mul_size(sizeof(struct iovec),
82 1233 : mul_size(mul_size(io_max_combine_limit, AioProcs()),
83 : io_max_concurrency));
84 : }
85 :
86 : static Size
87 1233 : AioHandleDataShmemSize(void)
88 : {
89 : /* each buffer referenced by an iovec can have associated data */
90 1233 : return mul_size(sizeof(uint64),
91 1233 : mul_size(mul_size(io_max_combine_limit, AioProcs()),
92 : io_max_concurrency));
93 : }
94 :
95 : /*
96 : * Choose a suitable value for io_max_concurrency.
97 : *
98 : * It's unlikely that we could have more IOs in flight than buffers that we
99 : * would be allowed to pin.
100 : *
101 : * On the upper end, apply a cap too - just because shared_buffers is large,
102 : * it doesn't make sense have millions of buffers undergo IO concurrently.
103 : */
104 : static int
105 1227 : AioChooseMaxConcurrency(void)
106 : {
107 : uint32 max_backends;
108 : int max_proportional_pins;
109 :
110 : /* Similar logic to LimitAdditionalPins() */
111 1227 : max_backends = MaxBackends + NUM_AUXILIARY_PROCS;
112 1227 : max_proportional_pins = NBuffers / max_backends;
113 :
114 1227 : max_proportional_pins = Max(max_proportional_pins, 1);
115 :
116 : /* apply upper limit */
117 1227 : return Min(max_proportional_pins, 64);
118 : }
119 :
120 : /*
121 : * Register AIO subsystem's shared memory needs.
122 : */
123 : static void
124 1233 : AioShmemRequest(void *arg)
125 : {
126 : /*
127 : * Resolve io_max_concurrency if not already done
128 : *
129 : * We prefer to report this value's source as PGC_S_DYNAMIC_DEFAULT.
130 : * However, if the DBA explicitly set io_max_concurrency = -1 in the
131 : * config file, then PGC_S_DYNAMIC_DEFAULT will fail to override that and
132 : * we must force the matter with PGC_S_OVERRIDE.
133 : */
134 1233 : if (io_max_concurrency == -1)
135 : {
136 : char buf[32];
137 :
138 1227 : snprintf(buf, sizeof(buf), "%d", AioChooseMaxConcurrency());
139 1227 : SetConfigOption("io_max_concurrency", buf, PGC_POSTMASTER,
140 : PGC_S_DYNAMIC_DEFAULT);
141 1227 : if (io_max_concurrency == -1) /* failed to apply it? */
142 0 : SetConfigOption("io_max_concurrency", buf, PGC_POSTMASTER,
143 : PGC_S_OVERRIDE);
144 : }
145 :
146 1233 : ShmemRequestStruct(.name = "AioCtl",
147 : .size = sizeof(PgAioCtl),
148 : .ptr = (void **) &pgaio_ctl,
149 : );
150 :
151 1233 : ShmemRequestStruct(.name = "AioBackend",
152 : .size = AioBackendShmemSize(),
153 : .ptr = (void **) &AioBackendShmemPtr,
154 : );
155 :
156 1233 : ShmemRequestStruct(.name = "AioHandle",
157 : .size = AioHandleShmemSize(),
158 : .ptr = (void **) &AioHandleShmemPtr,
159 : );
160 :
161 1233 : ShmemRequestStruct(.name = "AioHandleIOV",
162 : .size = AioHandleIOVShmemSize(),
163 : .ptr = (void **) &AioHandleIOVShmemPtr,
164 : );
165 :
166 1233 : ShmemRequestStruct(.name = "AioHandleData",
167 : .size = AioHandleDataShmemSize(),
168 : .ptr = (void **) &AioHandleDataShmemPtr,
169 : );
170 :
171 1233 : if (pgaio_method_ops->shmem_callbacks.request_fn)
172 1226 : pgaio_method_ops->shmem_callbacks.request_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
173 1233 : }
174 :
175 : /*
176 : * Initialize AIO shared memory during postmaster startup.
177 : */
178 : static void
179 1230 : AioShmemInit(void *arg)
180 : {
181 1230 : uint32 io_handle_off = 0;
182 1230 : uint32 iovec_off = 0;
183 1230 : uint32 per_backend_iovecs = io_max_concurrency * io_max_combine_limit;
184 :
185 1230 : pgaio_ctl->io_handle_count = AioProcs() * io_max_concurrency;
186 1230 : pgaio_ctl->iovec_count = AioProcs() * per_backend_iovecs;
187 :
188 1230 : pgaio_ctl->backend_state = AioBackendShmemPtr;
189 1230 : pgaio_ctl->io_handles = AioHandleShmemPtr;
190 1230 : pgaio_ctl->iovecs = AioHandleIOVShmemPtr;
191 1230 : pgaio_ctl->handle_data = AioHandleDataShmemPtr;
192 :
193 163161 : for (int procno = 0; procno < AioProcs(); procno++)
194 : {
195 161931 : PgAioBackend *bs = &pgaio_ctl->backend_state[procno];
196 :
197 161931 : bs->io_handle_off = io_handle_off;
198 161931 : io_handle_off += io_max_concurrency;
199 :
200 161931 : dclist_init(&bs->idle_ios);
201 161931 : memset(bs->staged_ios, 0, sizeof(PgAioHandle *) * PGAIO_SUBMIT_BATCH_SIZE);
202 161931 : dclist_init(&bs->in_flight_ios);
203 :
204 : /* initialize per-backend IOs */
205 7853829 : for (int i = 0; i < io_max_concurrency; i++)
206 : {
207 7691898 : PgAioHandle *ioh = &pgaio_ctl->io_handles[bs->io_handle_off + i];
208 :
209 7691898 : ioh->generation = 1;
210 7691898 : ioh->owner_procno = procno;
211 7691898 : ioh->iovec_off = iovec_off;
212 7691898 : ioh->handle_data_len = 0;
213 7691898 : ioh->report_return = NULL;
214 7691898 : ioh->resowner = NULL;
215 7691898 : ioh->num_callbacks = 0;
216 7691898 : ioh->distilled_result.status = PGAIO_RS_UNKNOWN;
217 7691898 : ioh->flags = 0;
218 :
219 7691898 : ConditionVariableInit(&ioh->cv);
220 :
221 7691898 : dclist_push_tail(&bs->idle_ios, &ioh->node);
222 7691898 : iovec_off += io_max_combine_limit;
223 : }
224 : }
225 :
226 1230 : if (pgaio_method_ops->shmem_callbacks.init_fn)
227 1223 : pgaio_method_ops->shmem_callbacks.init_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
228 1230 : }
229 :
230 : static void
231 0 : AioShmemAttach(void *arg)
232 : {
233 0 : if (pgaio_method_ops->shmem_callbacks.attach_fn)
234 0 : pgaio_method_ops->shmem_callbacks.attach_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
235 0 : }
236 :
237 : void
238 24714 : pgaio_init_backend(void)
239 : {
240 : /* shouldn't be initialized twice */
241 : Assert(!pgaio_my_backend);
242 :
243 24714 : if (MyBackendType == B_IO_WORKER)
244 1923 : return;
245 :
246 22791 : if (MyProc == NULL || MyProcNumber >= AioProcs())
247 0 : elog(ERROR, "aio requires a normal PGPROC");
248 :
249 22791 : pgaio_my_backend = &pgaio_ctl->backend_state[MyProcNumber];
250 :
251 22791 : if (pgaio_method_ops->init_backend)
252 0 : pgaio_method_ops->init_backend();
253 :
254 22791 : before_shmem_exit(pgaio_shutdown, 0);
255 : }
|