PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
aio_funcs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * aio_funcs.c
4 * AIO - SQL interface for AIO
5 *
6 *
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 * IDENTIFICATION
11 * src/backend/storage/aio/aio_funcs.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include "fmgr.h"
19#include "funcapi.h"
20#include "nodes/execnodes.h"
21#include "port/atomics.h"
23#include "storage/lock.h"
24#include "storage/proc.h"
25#include "storage/procnumber.h"
26#include "utils/builtins.h"
27#include "utils/fmgrprotos.h"
28#include "utils/tuplestore.h"
29
30
31/*
32 * Byte length of an iovec.
33 */
34static size_t
35iov_byte_length(const struct iovec *iov, int cnt)
36{
37 size_t len = 0;
38
39 for (int i = 0; i < cnt; i++)
40 {
41 len += iov[i].iov_len;
42 }
43
44 return len;
45}
46
49{
50 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
51
52 InitMaterializedSRF(fcinfo, 0);
53
54#define PG_GET_AIOS_COLS 15
55
56 for (uint64 i = 0; i < pgaio_ctl->io_handle_count; i++)
57 {
58 PgAioHandle *live_ioh = &pgaio_ctl->io_handles[i];
59 uint32 ioh_id = pgaio_io_get_id(live_ioh);
61 bool nulls[PG_GET_AIOS_COLS] = {0};
62 ProcNumber owner;
63 PGPROC *owner_proc;
64 int32 owner_pid;
65 PgAioHandleState start_state;
66 uint64 start_generation;
67 PgAioHandle ioh_copy;
68 struct iovec iov_copy[PG_IOV_MAX];
69
70
71 /*
72 * There is no lock that could prevent the state of the IO to advance
73 * concurrently - and we don't want to introduce one, as that would
74 * introduce atomics into a very common path. Instead we
75 *
76 * 1) Determine the state + generation of the IO.
77 *
78 * 2) Copy the IO to local memory.
79 *
80 * 3) Check if state or generation of the IO changed. If the state
81 * changed, retry, if the generation changed don't display the IO.
82 */
83
84 /* 1) from above */
85 start_generation = live_ioh->generation;
86
87 /*
88 * Retry at this point, so we can accept changing states, but not
89 * changing generations.
90 */
91retry:
93 start_state = live_ioh->state;
94
95 if (start_state == PGAIO_HS_IDLE)
96 continue;
97
98 /* 2) from above */
99 memcpy(&ioh_copy, live_ioh, sizeof(PgAioHandle));
100
101 /*
102 * Safe to copy even if no iovec is used - we always reserve the
103 * required space.
104 */
105 memcpy(&iov_copy, &pgaio_ctl->iovecs[ioh_copy.iovec_off],
106 PG_IOV_MAX * sizeof(struct iovec));
107
108 /*
109 * Copy information about owner before 3) below, if the process exited
110 * it'd have to wait for the IO to finish first, which we would detect
111 * in 3).
112 */
113 owner = ioh_copy.owner_procno;
114 owner_proc = GetPGProcByNumber(owner);
115 owner_pid = owner_proc->pid;
116
117 /* 3) from above */
119
120 /*
121 * The IO completed and a new one was started with the same ID. Don't
122 * display it - it really started after this function was called.
123 * There be a risk of a livelock if we just retried endlessly, if IOs
124 * complete very quickly.
125 */
126 if (live_ioh->generation != start_generation)
127 continue;
128
129 /*
130 * The IO's state changed while we were "rendering" it. Just start
131 * from scratch. There's no risk of a livelock here, as an IO has a
132 * limited sets of states it can be in, and state changes go only in a
133 * single direction.
134 */
135 if (live_ioh->state != start_state)
136 goto retry;
137
138 /*
139 * Now that we have copied the IO into local memory and checked that
140 * it's still in the same state, we are not allowed to access "live"
141 * memory anymore. To make it slightly easier to catch such cases, set
142 * the "live" pointers to NULL.
143 */
144 live_ioh = NULL;
145 owner_proc = NULL;
146
147
148 /* column: owning pid */
149 if (owner_pid != 0)
150 values[0] = Int32GetDatum(owner_pid);
151 else
152 nulls[0] = false;
153
154 /* column: IO's id */
155 values[1] = ioh_id;
156
157 /* column: IO's generation */
158 values[2] = Int64GetDatum(start_generation);
159
160 /* column: IO's state */
162
163 /*
164 * If the IO is in PGAIO_HS_HANDED_OUT state, none of the following
165 * fields are valid yet (or are in the process of being set).
166 * Therefore we don't want to display any other columns.
167 */
168 if (start_state == PGAIO_HS_HANDED_OUT)
169 {
170 memset(nulls + 4, 1, (lengthof(nulls) - 4) * sizeof(bool));
171 goto display;
172 }
173
174 /* column: IO's operation */
176
177 /* columns: details about the IO's operation (offset, length) */
178 switch (ioh_copy.op)
179 {
180 case PGAIO_OP_INVALID:
181 nulls[5] = true;
182 nulls[6] = true;
183 break;
184 case PGAIO_OP_READV:
185 values[5] = Int64GetDatum(ioh_copy.op_data.read.offset);
186 values[6] =
188 break;
189 case PGAIO_OP_WRITEV:
190 values[5] = Int64GetDatum(ioh_copy.op_data.write.offset);
191 values[6] =
193 break;
194 }
195
196 /* column: IO's target */
198
199 /* column: length of IO's data array */
200 values[8] = Int16GetDatum(ioh_copy.handle_data_len);
201
202 /* column: raw result (i.e. some form of syscall return value) */
203 if (start_state == PGAIO_HS_COMPLETED_IO
204 || start_state == PGAIO_HS_COMPLETED_SHARED
205 || start_state == PGAIO_HS_COMPLETED_LOCAL)
206 values[9] = Int32GetDatum(ioh_copy.result);
207 else
208 nulls[9] = true;
209
210 /*
211 * column: result in the higher level representation (unknown if not
212 * finished)
213 */
214 values[10] =
216
217 /* column: target description */
219
220 /* columns: one for each flag */
223 values[14] = BoolGetDatum(ioh_copy.flags & PGAIO_HF_BUFFERED);
224
225display:
226 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
227 }
228
229 return (Datum) 0;
230}
int pgaio_io_get_id(PgAioHandle *ioh)
Definition: aio.c:330
const char * pgaio_result_status_string(PgAioResultStatus rs)
Definition: aio.c:836
PgAioCtl * pgaio_ctl
Definition: aio.c:81
const char * pgaio_io_get_state_name(PgAioHandle *ioh)
Definition: aio.c:830
@ PGAIO_OP_WRITEV
Definition: aio.h:93
@ PGAIO_OP_INVALID
Definition: aio.h:90
@ PGAIO_OP_READV
Definition: aio.h:92
@ PGAIO_HF_SYNCHRONOUS
Definition: aio.h:70
@ PGAIO_HF_REFERENCES_LOCAL
Definition: aio.h:60
@ PGAIO_HF_BUFFERED
Definition: aio.h:77
static size_t iov_byte_length(const struct iovec *iov, int cnt)
Definition: aio_funcs.c:35
#define PG_GET_AIOS_COLS
Datum pg_get_aios(PG_FUNCTION_ARGS)
Definition: aio_funcs.c:48
PgAioHandleState
Definition: aio_internal.h:44
@ PGAIO_HS_COMPLETED_SHARED
Definition: aio_internal.h:82
@ PGAIO_HS_IDLE
Definition: aio_internal.h:46
@ PGAIO_HS_HANDED_OUT
Definition: aio_internal.h:53
@ PGAIO_HS_COMPLETED_IO
Definition: aio_internal.h:72
@ PGAIO_HS_COMPLETED_LOCAL
Definition: aio_internal.h:89
const char * pgaio_io_get_op_name(PgAioHandle *ioh)
Definition: aio_io.c:175
const char * pgaio_io_get_target_name(PgAioHandle *ioh)
Definition: aio_target.c:50
char * pgaio_io_get_target_description(PgAioHandle *ioh)
Definition: aio_target.c:83
#define pg_read_barrier()
Definition: atomics.h:156
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
int32_t int32
Definition: c.h:498
uint64_t uint64
Definition: c.h:503
uint32_t uint32
Definition: c.h:502
#define lengthof(array)
Definition: c.h:759
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
int i
Definition: isn.c:77
const void size_t len
#define PG_IOV_MAX
Definition: pg_iovec.h:41
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
#define GetPGProcByNumber(n)
Definition: proc.h:424
int ProcNumber
Definition: procnumber.h:24
Definition: proc.h:163
int pid
Definition: proc.h:183
struct iovec * iovecs
Definition: aio_internal.h:234
PgAioHandle * io_handles
Definition: aio_internal.h:246
uint32 io_handle_count
Definition: aio_internal.h:245
int32 owner_procno
Definition: aio_internal.h:125
PgAioResult distilled_result
Definition: aio_internal.h:156
uint8 handle_data_len
Definition: aio_internal.h:122
PgAioOp op
Definition: aio_internal.h:105
PgAioOpData op_data
Definition: aio_internal.h:174
uint32 iovec_off
Definition: aio_internal.h:164
uint64 generation
Definition: aio_internal.h:146
PgAioHandleState state
Definition: aio_internal.h:99
uint32 status
Definition: aio_types.h:108
TupleDesc setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
uint64 offset
Definition: aio.h:140
uint16 iov_length
Definition: aio.h:139
struct PgAioOpData::@123 write
struct PgAioOpData::@122 read