Age Owner Branch data TLA 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
414 andres@anarazel.de 46 :CBC 193133 : 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 : 193133 : return MaxBackends + NUM_AUXILIARY_PROCS;
54 : : }
55 : :
56 : : static Size
57 : 1244 : AioBackendShmemSize(void)
58 : : {
59 : 1244 : return mul_size(AioProcs(), sizeof(PgAioBackend));
60 : : }
61 : :
62 : : static Size
63 : 1244 : AioHandleShmemSize(void)
64 : : {
65 : : Size sz;
66 : :
67 : : /* verify AioChooseMaxConcurrency() did its thing */
68 [ - + ]: 1244 : Assert(io_max_concurrency > 0);
69 : :
70 : : /* io handles */
71 : 1244 : sz = mul_size(AioProcs(),
72 : : mul_size(io_max_concurrency, sizeof(PgAioHandle)));
73 : :
74 : 1244 : return sz;
75 : : }
76 : :
77 : : static Size
78 : 1244 : AioHandleIOVShmemSize(void)
79 : : {
80 : : /* each IO handle can have up to io_max_combine_limit iovec objects */
81 : 1244 : return mul_size(sizeof(struct iovec),
412 tmunro@postgresql.or 82 : 1244 : mul_size(mul_size(io_max_combine_limit, AioProcs()),
83 : : io_max_concurrency));
84 : : }
85 : :
86 : : static Size
414 andres@anarazel.de 87 : 1244 : AioHandleDataShmemSize(void)
88 : : {
89 : : /* each buffer referenced by an iovec can have associated data */
90 : 1244 : return mul_size(sizeof(uint64),
412 tmunro@postgresql.or 91 : 1244 : 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
414 andres@anarazel.de 105 : 1238 : AioChooseMaxConcurrency(void)
106 : : {
107 : : uint32 max_backends;
108 : : int max_proportional_pins;
109 : :
110 : : /* Similar logic to LimitAdditionalPins() */
111 : 1238 : max_backends = MaxBackends + NUM_AUXILIARY_PROCS;
112 : 1238 : max_proportional_pins = NBuffers / max_backends;
113 : :
114 : 1238 : max_proportional_pins = Max(max_proportional_pins, 1);
115 : :
116 : : /* apply upper limit */
117 : 1238 : return Min(max_proportional_pins, 64);
118 : : }
119 : :
120 : : /*
121 : : * Register AIO subsystem's shared memory needs.
122 : : */
123 : : static void
29 heikki.linnakangas@i 124 :GNC 1244 : 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 : : */
414 andres@anarazel.de 134 [ + + ]:CBC 1244 : if (io_max_concurrency == -1)
135 : : {
136 : : char buf[32];
137 : :
138 : 1238 : snprintf(buf, sizeof(buf), "%d", AioChooseMaxConcurrency());
139 : 1238 : SetConfigOption("io_max_concurrency", buf, PGC_POSTMASTER,
140 : : PGC_S_DYNAMIC_DEFAULT);
141 [ - + ]: 1238 : if (io_max_concurrency == -1) /* failed to apply it? */
414 andres@anarazel.de 142 :UBC 0 : SetConfigOption("io_max_concurrency", buf, PGC_POSTMASTER,
143 : : PGC_S_OVERRIDE);
144 : : }
145 : :
29 heikki.linnakangas@i 146 :GNC 1244 : ShmemRequestStruct(.name = "AioCtl",
147 : : .size = sizeof(PgAioCtl),
148 : : .ptr = (void **) &pgaio_ctl,
149 : : );
150 : :
151 : 1244 : ShmemRequestStruct(.name = "AioBackend",
152 : : .size = AioBackendShmemSize(),
153 : : .ptr = (void **) &AioBackendShmemPtr,
154 : : );
155 : :
156 : 1244 : ShmemRequestStruct(.name = "AioHandle",
157 : : .size = AioHandleShmemSize(),
158 : : .ptr = (void **) &AioHandleShmemPtr,
159 : : );
160 : :
161 : 1244 : ShmemRequestStruct(.name = "AioHandleIOV",
162 : : .size = AioHandleIOVShmemSize(),
163 : : .ptr = (void **) &AioHandleIOVShmemPtr,
164 : : );
165 : :
166 : 1244 : ShmemRequestStruct(.name = "AioHandleData",
167 : : .size = AioHandleDataShmemSize(),
168 : : .ptr = (void **) &AioHandleDataShmemPtr,
169 : : );
170 : :
171 [ + + ]: 1244 : if (pgaio_method_ops->shmem_callbacks.request_fn)
172 : 1237 : pgaio_method_ops->shmem_callbacks.request_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
414 andres@anarazel.de 173 :GIC 1244 : }
174 : :
175 : : /*
176 : : * Initialize AIO shared memory during postmaster startup.
177 : : */
178 : : static void
29 heikki.linnakangas@i 179 :GNC 1241 : AioShmemInit(void *arg)
180 : : {
414 andres@anarazel.de 181 :CBC 1241 : uint32 io_handle_off = 0;
182 : 1241 : uint32 iovec_off = 0;
412 tmunro@postgresql.or 183 : 1241 : uint32 per_backend_iovecs = io_max_concurrency * io_max_combine_limit;
184 : :
414 andres@anarazel.de 185 : 1241 : pgaio_ctl->io_handle_count = AioProcs() * io_max_concurrency;
186 : 1241 : pgaio_ctl->iovec_count = AioProcs() * per_backend_iovecs;
187 : :
29 heikki.linnakangas@i 188 :GNC 1241 : pgaio_ctl->backend_state = AioBackendShmemPtr;
189 : 1241 : pgaio_ctl->io_handles = AioHandleShmemPtr;
190 : 1241 : pgaio_ctl->iovecs = AioHandleIOVShmemPtr;
191 : 1241 : pgaio_ctl->handle_data = AioHandleDataShmemPtr;
192 : :
414 andres@anarazel.de 193 [ + + ]:CBC 164024 : for (int procno = 0; procno < AioProcs(); procno++)
194 : : {
195 : 162783 : PgAioBackend *bs = &pgaio_ctl->backend_state[procno];
196 : :
197 : 162783 : bs->io_handle_off = io_handle_off;
198 : 162783 : io_handle_off += io_max_concurrency;
199 : :
200 : 162783 : dclist_init(&bs->idle_ios);
201 : 162783 : memset(bs->staged_ios, 0, sizeof(PgAioHandle *) * PGAIO_SUBMIT_BATCH_SIZE);
202 : 162783 : dclist_init(&bs->in_flight_ios);
203 : :
204 : : /* initialize per-backend IOs */
205 [ + + ]: 7868952 : for (int i = 0; i < io_max_concurrency; i++)
206 : : {
207 : 7706169 : PgAioHandle *ioh = &pgaio_ctl->io_handles[bs->io_handle_off + i];
208 : :
209 : 7706169 : ioh->generation = 1;
210 : 7706169 : ioh->owner_procno = procno;
211 : 7706169 : ioh->iovec_off = iovec_off;
212 : 7706169 : ioh->handle_data_len = 0;
213 : 7706169 : ioh->report_return = NULL;
214 : 7706169 : ioh->resowner = NULL;
215 : 7706169 : ioh->num_callbacks = 0;
409 216 : 7706169 : ioh->distilled_result.status = PGAIO_RS_UNKNOWN;
414 217 : 7706169 : ioh->flags = 0;
218 : :
219 : 7706169 : ConditionVariableInit(&ioh->cv);
220 : :
221 : 7706169 : dclist_push_tail(&bs->idle_ios, &ioh->node);
412 tmunro@postgresql.or 222 : 7706169 : iovec_off += io_max_combine_limit;
223 : : }
224 : : }
225 : :
29 heikki.linnakangas@i 226 [ + + ]:GNC 1241 : if (pgaio_method_ops->shmem_callbacks.init_fn)
227 : 1234 : pgaio_method_ops->shmem_callbacks.init_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
228 : 1241 : }
229 : :
230 : : static void
29 heikki.linnakangas@i 231 :UNC 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);
414 andres@anarazel.de 235 :LBC (1070) : }
236 : :
237 : : void
414 andres@anarazel.de 238 :CBC 22963 : pgaio_init_backend(void)
239 : : {
240 : : /* shouldn't be initialized twice */
241 [ - + ]: 22963 : Assert(!pgaio_my_backend);
242 : :
413 243 [ + + ]: 22963 : if (MyBackendType == B_IO_WORKER)
244 : 1312 : return;
245 : :
414 246 [ + - - + ]: 21651 : if (MyProc == NULL || MyProcNumber >= AioProcs())
414 andres@anarazel.de 247 [ # # ]:UBC 0 : elog(ERROR, "aio requires a normal PGPROC");
248 : :
414 andres@anarazel.de 249 :CBC 21651 : pgaio_my_backend = &pgaio_ctl->backend_state[MyProcNumber];
250 : :
251 [ + + ]: 21651 : if (pgaio_method_ops->init_backend)
252 : 68 : pgaio_method_ops->init_backend();
253 : :
254 : 21651 : before_shmem_exit(pgaio_shutdown, 0);
255 : : }
|