1/*-------------------------------------------------------------------------
4 * AIO - Functionality related to callbacks that can be registered on IO
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/storage/aio/aio_callback.c
13 *-------------------------------------------------------------------------
25/* just to have something to put into aio_handle_cbs */
35 * Callback definition for the callbacks that can be registered on an IO
36 * handle. See PgAioHandleCallbackID's definition for an explanation for why
37 * callbacks are not identified by a pointer.
40#define CALLBACK_ENTRY(id, callback) [id] = {.cb = &callback, .name = #callback}
53/* --------------------------------------------------------------------------------
54 * Public callback related functions operating on IO Handles
55 * --------------------------------------------------------------------------------
59 * Register callback for the IO handle.
61 * Only a limited number (PGAIO_HANDLE_MAX_CALLBACKS) of callbacks can be
62 * registered for each IO.
64 * Callbacks need to be registered before [indirectly] calling
65 * pgaio_io_start_*(), as the IO may be executed immediately.
67 * A callback can be passed a small bit of data, e.g. to indicate whether to
68 * zero a buffer if it is invalid.
71 * Note that callbacks are executed in critical sections. This is necessary
72 * to be able to execute IO in critical sections (consider e.g. WAL
73 * logging). To perform AIO we first need to acquire a handle, which, if there
74 * are no free handles, requires waiting for IOs to complete and to execute
75 * their completion callbacks.
77 * Callbacks may be executed in the issuing backend but also in another
78 * backend (because that backend is waiting for the IO) or in IO workers (if
79 * io_method=worker is used).
82 * See PgAioHandleCallbackID's definition for an explanation for why
83 * callbacks are not identified by a pointer.
93 elog(
ERROR,
"callback %d is out of range", cb_id);
96 elog(
ERROR,
"callback %d does not have a completion callback", cb_id);
98 elog(
PANIC,
"too many callbacks, the max is %d",
104 "adding cb #%d, id %d/%s",
112 * Associate an array of data with the Handle. This is e.g. useful to the
113 * transport knowledge about which buffers a multi-block IO affects to
114 * completion callbacks.
116 * Right now this can be done only once for each IO, even though multiple
117 * callbacks can be registered. There aren't any known usecases requiring more
118 * and the required amount of shared memory does add up, so it doesn't seem
119 * worth multiplying memory usage by PGAIO_HANDLE_MAX_CALLBACKS.
129 for (
int i = 0;
i <
len;
i++)
135 * Convenience version of pgaio_io_set_handle_data_64() that converts a 32bit
136 * array to a 64bit array. Without it callers would end up needing to
137 * open-code equivalent code.
147 for (
int i = 0;
i <
len;
i++)
153 * Return data set with pgaio_io_set_handle_data_*().
167/* --------------------------------------------------------------------------------
168 * Public IO Result related functions
169 * --------------------------------------------------------------------------------
182 elog(
ERROR,
"callback %d/%s does not have report callback",
185 ce->
cb->
report(result, target_data, elevel);
190/* --------------------------------------------------------------------------------
191 * Internal callback related functions operating on IO Handles
192 * --------------------------------------------------------------------------------
196 * Internal function which invokes ->stage for all the registered callbacks.
214 "calling cb #%d %d/%s->stage(%u)",
215 i, cb_id, ce->
name, cb_data);
221 * Internal function which invokes ->complete_shared for all the registered
240 * Call callbacks with the last registered (innermost) callback first.
241 * Each callback can modify the result forwarded to the next callback.
253 "calling cb #%d, id %d/%s->complete_shared(%u) with distilled result: (status %s, id %u, error_data %d, result %d)",
260 /* the callback should never transition to unknown */
267 "after shared completion: distilled result: (status %s, id %u, error_data: %d, result %d), raw_result: %d",
276 * Internal function which invokes ->complete_local for all the registered
279 * Returns ioh->distilled_result after, possibly, being modified by local
282 * XXX: It'd be nice to deduplicate with pgaio_io_call_complete_shared().
294 /* start with distilled result from shared callback */
308 "calling cb #%d, id %d/%s->complete_local(%u) with distilled result: status %s, id %u, error_data %d, result %d",
309 i, cb_id, ce->
name, cb_data,
314 /* the callback should never transition to unknown */
319 * Note that we don't save the result in ioh->distilled_result, the local
320 * callback's result should not ever matter to other waiters. However, the
321 * local backend does care, so we return the result as modified by local
322 * callbacks, which then can be passed to ioh->report_return->result.
325 "after local completion: result: (status %s, id %u, error_data %d, result %d), raw_result: %d",
const char * pgaio_result_status_string(PgAioResultStatus rs)
@ PGAIO_HCB_LOCAL_BUFFER_READV
@ PGAIO_HCB_SHARED_BUFFER_READV
#define PGAIO_HANDLE_MAX_CALLBACKS
void pgaio_io_call_stage(PgAioHandle *ioh)
static const PgAioHandleCallbacksEntry aio_handle_cbs[]
void pgaio_io_set_handle_data_32(PgAioHandle *ioh, uint32 *data, uint8 len)
PgAioResult pgaio_io_call_complete_local(PgAioHandle *ioh)
void pgaio_io_register_callbacks(PgAioHandle *ioh, PgAioHandleCallbackID cb_id, uint8 cb_data)
void pgaio_io_call_complete_shared(PgAioHandle *ioh)
uint64 * pgaio_io_get_handle_data(PgAioHandle *ioh, uint8 *len)
void pgaio_io_set_handle_data_64(PgAioHandle *ioh, uint64 *data, uint8 len)
static const PgAioHandleCallbacks aio_invalid_cb
struct PgAioHandleCallbacksEntry PgAioHandleCallbacksEntry
#define CALLBACK_ENTRY(id, callback)
void pgaio_result_report(PgAioResult result, const PgAioTargetData *target_data, int elevel)
#define pgaio_debug_io(elevel, ioh, msg,...)
const PgAioHandleCallbacks aio_shared_buffer_readv_cb
const PgAioHandleCallbacks aio_local_buffer_readv_cb
Assert(PointerIsAligned(start, uint64))
const PgAioHandleCallbacks aio_md_readv_cb
#define START_CRIT_SECTION()
#define END_CRIT_SECTION()
const PgAioHandleCallbacks *const cb
PgAioHandleCallbackComplete complete_shared
PgAioHandleCallbackStage stage
PgAioHandleCallbackReport report
PgAioHandleCallbackComplete complete_local
PgAioResult distilled_result
uint8 callbacks[PGAIO_HANDLE_MAX_CALLBACKS]
uint8 callbacks_data[PGAIO_HANDLE_MAX_CALLBACKS]