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-2025, 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 "utils/guc.h"
27 : :
28 : :
29 : :
30 : : static Size
173 andres@anarazel.de 31 :CBC 3967 : AioCtlShmemSize(void)
32 : : {
33 : : Size sz;
34 : :
35 : : /* pgaio_ctl itself */
36 : 3967 : sz = offsetof(PgAioCtl, io_handles);
37 : :
38 : 3967 : return sz;
39 : : }
40 : :
41 : : static uint32
42 : 165457 : AioProcs(void)
43 : : {
44 : : /*
45 : : * While AIO workers don't need their own AIO context, we can't currently
46 : : * guarantee nothing gets assigned to the a ProcNumber for an IO worker if
47 : : * we just subtracted MAX_IO_WORKERS.
48 : : */
49 : 165457 : return MaxBackends + NUM_AUXILIARY_PROCS;
50 : : }
51 : :
52 : : static Size
53 : 2938 : AioBackendShmemSize(void)
54 : : {
55 : 2938 : return mul_size(AioProcs(), sizeof(PgAioBackend));
56 : : }
57 : :
58 : : static Size
59 : 2938 : AioHandleShmemSize(void)
60 : : {
61 : : Size sz;
62 : :
63 : : /* verify AioChooseMaxConcurrency() did its thing */
64 [ - + ]: 2938 : Assert(io_max_concurrency > 0);
65 : :
66 : : /* io handles */
67 : 2938 : sz = mul_size(AioProcs(),
68 : : mul_size(io_max_concurrency, sizeof(PgAioHandle)));
69 : :
70 : 2938 : return sz;
71 : : }
72 : :
73 : : static Size
74 : 2938 : AioHandleIOVShmemSize(void)
75 : : {
76 : : /* each IO handle can have up to io_max_combine_limit iovec objects */
77 : 2938 : return mul_size(sizeof(struct iovec),
171 tmunro@postgresql.or 78 : 2938 : mul_size(mul_size(io_max_combine_limit, AioProcs()),
79 : : io_max_concurrency));
80 : : }
81 : :
82 : : static Size
173 andres@anarazel.de 83 : 2938 : AioHandleDataShmemSize(void)
84 : : {
85 : : /* each buffer referenced by an iovec can have associated data */
86 : 2938 : return mul_size(sizeof(uint64),
171 tmunro@postgresql.or 87 : 2938 : mul_size(mul_size(io_max_combine_limit, AioProcs()),
88 : : io_max_concurrency));
89 : : }
90 : :
91 : : /*
92 : : * Choose a suitable value for io_max_concurrency.
93 : : *
94 : : * It's unlikely that we could have more IOs in flight than buffers that we
95 : : * would be allowed to pin.
96 : : *
97 : : * On the upper end, apply a cap too - just because shared_buffers is large,
98 : : * it doesn't make sense have millions of buffers undergo IO concurrently.
99 : : */
100 : : static int
173 andres@anarazel.de 101 : 1027 : AioChooseMaxConcurrency(void)
102 : : {
103 : : uint32 max_backends;
104 : : int max_proportional_pins;
105 : :
106 : : /* Similar logic to LimitAdditionalPins() */
107 : 1027 : max_backends = MaxBackends + NUM_AUXILIARY_PROCS;
108 : 1027 : max_proportional_pins = NBuffers / max_backends;
109 : :
110 : 1027 : max_proportional_pins = Max(max_proportional_pins, 1);
111 : :
112 : : /* apply upper limit */
113 : 1027 : return Min(max_proportional_pins, 64);
114 : : }
115 : :
116 : : Size
117 : 1909 : AioShmemSize(void)
118 : : {
119 : 1909 : Size sz = 0;
120 : :
121 : : /*
122 : : * We prefer to report this value's source as PGC_S_DYNAMIC_DEFAULT.
123 : : * However, if the DBA explicitly set io_max_concurrency = -1 in the
124 : : * config file, then PGC_S_DYNAMIC_DEFAULT will fail to override that and
125 : : * we must force the matter with PGC_S_OVERRIDE.
126 : : */
127 [ + + ]: 1909 : if (io_max_concurrency == -1)
128 : : {
129 : : char buf[32];
130 : :
131 : 1027 : snprintf(buf, sizeof(buf), "%d", AioChooseMaxConcurrency());
132 : 1027 : SetConfigOption("io_max_concurrency", buf, PGC_POSTMASTER,
133 : : PGC_S_DYNAMIC_DEFAULT);
134 [ - + ]: 1027 : if (io_max_concurrency == -1) /* failed to apply it? */
173 andres@anarazel.de 135 :UBC 0 : SetConfigOption("io_max_concurrency", buf, PGC_POSTMASTER,
136 : : PGC_S_OVERRIDE);
137 : : }
138 : :
173 andres@anarazel.de 139 :CBC 1909 : sz = add_size(sz, AioCtlShmemSize());
140 : 1909 : sz = add_size(sz, AioBackendShmemSize());
141 : 1909 : sz = add_size(sz, AioHandleShmemSize());
142 : 1909 : sz = add_size(sz, AioHandleIOVShmemSize());
143 : 1909 : sz = add_size(sz, AioHandleDataShmemSize());
144 : :
145 : : /* Reserve space for method specific resources. */
146 [ + + ]: 1909 : if (pgaio_method_ops->shmem_size)
147 : 1902 : sz = add_size(sz, pgaio_method_ops->shmem_size());
148 : :
149 : 1909 : return sz;
150 : : }
151 : :
152 : : void
153 : 1029 : AioShmemInit(void)
154 : : {
155 : : bool found;
156 : 1029 : uint32 io_handle_off = 0;
157 : 1029 : uint32 iovec_off = 0;
171 tmunro@postgresql.or 158 : 1029 : uint32 per_backend_iovecs = io_max_concurrency * io_max_combine_limit;
159 : :
173 andres@anarazel.de 160 : 1029 : pgaio_ctl = (PgAioCtl *)
161 : 1029 : ShmemInitStruct("AioCtl", AioCtlShmemSize(), &found);
162 : :
163 [ - + ]: 1029 : if (found)
173 andres@anarazel.de 164 :UBC 0 : goto out;
165 : :
173 andres@anarazel.de 166 :CBC 1029 : memset(pgaio_ctl, 0, AioCtlShmemSize());
167 : :
168 : 1029 : pgaio_ctl->io_handle_count = AioProcs() * io_max_concurrency;
169 : 1029 : pgaio_ctl->iovec_count = AioProcs() * per_backend_iovecs;
170 : :
171 : 2058 : pgaio_ctl->backend_state = (PgAioBackend *)
172 : 1029 : ShmemInitStruct("AioBackend", AioBackendShmemSize(), &found);
173 : :
174 : 2058 : pgaio_ctl->io_handles = (PgAioHandle *)
175 : 1029 : ShmemInitStruct("AioHandle", AioHandleShmemSize(), &found);
176 : :
177 : 2058 : pgaio_ctl->iovecs = (struct iovec *)
178 : 1029 : ShmemInitStruct("AioHandleIOV", AioHandleIOVShmemSize(), &found);
179 : 2058 : pgaio_ctl->handle_data = (uint64 *)
180 : 1029 : ShmemInitStruct("AioHandleData", AioHandleDataShmemSize(), &found);
181 : :
182 [ + + ]: 134389 : for (int procno = 0; procno < AioProcs(); procno++)
183 : : {
184 : 133360 : PgAioBackend *bs = &pgaio_ctl->backend_state[procno];
185 : :
186 : 133360 : bs->io_handle_off = io_handle_off;
187 : 133360 : io_handle_off += io_max_concurrency;
188 : :
189 : 133360 : dclist_init(&bs->idle_ios);
190 : 133360 : memset(bs->staged_ios, 0, sizeof(PgAioHandle *) * PGAIO_SUBMIT_BATCH_SIZE);
191 : 133360 : dclist_init(&bs->in_flight_ios);
192 : :
193 : : /* initialize per-backend IOs */
194 [ + + ]: 6300670 : for (int i = 0; i < io_max_concurrency; i++)
195 : : {
196 : 6167310 : PgAioHandle *ioh = &pgaio_ctl->io_handles[bs->io_handle_off + i];
197 : :
198 : 6167310 : ioh->generation = 1;
199 : 6167310 : ioh->owner_procno = procno;
200 : 6167310 : ioh->iovec_off = iovec_off;
201 : 6167310 : ioh->handle_data_len = 0;
202 : 6167310 : ioh->report_return = NULL;
203 : 6167310 : ioh->resowner = NULL;
204 : 6167310 : ioh->num_callbacks = 0;
168 205 : 6167310 : ioh->distilled_result.status = PGAIO_RS_UNKNOWN;
173 206 : 6167310 : ioh->flags = 0;
207 : :
208 : 6167310 : ConditionVariableInit(&ioh->cv);
209 : :
210 : 6167310 : dclist_push_tail(&bs->idle_ios, &ioh->node);
171 tmunro@postgresql.or 211 : 6167310 : iovec_off += io_max_combine_limit;
212 : : }
213 : : }
214 : :
173 andres@anarazel.de 215 : 1029 : out:
216 : : /* Initialize IO method specific resources. */
217 [ + + ]: 1029 : if (pgaio_method_ops->shmem_init)
218 : 1024 : pgaio_method_ops->shmem_init(!found);
219 : 1029 : }
220 : :
221 : : void
222 : 18760 : pgaio_init_backend(void)
223 : : {
224 : : /* shouldn't be initialized twice */
225 [ - + ]: 18760 : Assert(!pgaio_my_backend);
226 : :
172 227 [ + + ]: 18760 : if (MyBackendType == B_IO_WORKER)
228 : 1502 : return;
229 : :
173 230 [ + - - + ]: 17258 : if (MyProc == NULL || MyProcNumber >= AioProcs())
173 andres@anarazel.de 231 [ # # ]:UBC 0 : elog(ERROR, "aio requires a normal PGPROC");
232 : :
173 andres@anarazel.de 233 :CBC 17258 : pgaio_my_backend = &pgaio_ctl->backend_state[MyProcNumber];
234 : :
235 [ + + ]: 17258 : if (pgaio_method_ops->init_backend)
236 : 31 : pgaio_method_ops->init_backend();
237 : :
238 : 17258 : before_shmem_exit(pgaio_shutdown, 0);
239 : : }
|