/*-------------------------------------------------------------------------
 *
 * aio_types.h
 *    AIO related types that are useful to include separately, to reduce the
 *    "include burden".
 *
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/storage/aio_types.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef AIO_TYPES_H
#define AIO_TYPES_H

#include "storage/block.h"
#include "storage/relfilelocator.h"


typedef struct PgAioHandle PgAioHandle;
typedef struct PgAioHandleCallbacks PgAioHandleCallbacks;
typedef struct PgAioTargetInfo PgAioTargetInfo;

/*
 * A reference to an IO that can be used to wait for the IO (using
 * pgaio_wref_wait()) to complete.
 *
 * These can be passed across process boundaries.
 */
typedef struct PgAioWaitRef
{
	/* internal ID identifying the specific PgAioHandle */
	uint32		aio_index;

	/*
	 * IO handles are reused. To detect if a handle was reused, and thereby
	 * avoid unnecessarily waiting for a newer IO, each time the handle is
	 * reused a generation number is increased.
	 *
	 * To avoid requiring alignment sufficient for an int64, split the
	 * generation into two.
	 */
	uint32		generation_upper;
	uint32		generation_lower;
} PgAioWaitRef;


/*
 * Information identifying what the IO is being performed on.
 *
 * This needs sufficient information to
 *
 * a) Reopen the file for the IO if the IO is executed in a context that
 *    cannot use the FD provided initially (e.g. because the IO is executed in
 *    a worker process).
 *
 * b) Describe the object the IO is performed on in log / error messages.
 */
typedef union PgAioTargetData
{
	struct
	{
		RelFileLocator rlocator;	/* physical relation identifier */
		BlockNumber blockNum;	/* blknum relative to begin of reln */
		BlockNumber nblocks;
		ForkNumber	forkNum:8;	/* don't waste 4 byte for four values */
		bool		is_temp:1;	/* proc can be inferred by owning AIO */
		bool		skip_fsync:1;
	}			smgr;
} PgAioTargetData;


/*
 * The status of an AIO operation.
 */
typedef enum PgAioResultStatus
{
	PGAIO_RS_UNKNOWN,			/* not yet completed / uninitialized */
	PGAIO_RS_OK,
	PGAIO_RS_PARTIAL,			/* did not fully succeed, no warning/error */
	PGAIO_RS_WARNING,			/* [partially] succeeded, with a warning */
	PGAIO_RS_ERROR,				/* failed entirely */
} PgAioResultStatus;


/*
 * Result of IO operation, visible only to the initiator of IO.
 *
 * We need to be careful about the size of PgAioResult, as it is embedded in
 * every PgAioHandle, as well as every PgAioReturn. Currently we assume we can
 * fit it into one 8 byte value, restricting the space for per-callback error
 * data to PGAIO_RESULT_ERROR_BITS.
 */
#define PGAIO_RESULT_ID_BITS 6
#define PGAIO_RESULT_STATUS_BITS 3
#define PGAIO_RESULT_ERROR_BITS 23
typedef struct PgAioResult
{
	/*
	 * This is of type PgAioHandleCallbackID, but can't use a bitfield of an
	 * enum, because some compilers treat enums as signed.
	 */
	uint32		id:PGAIO_RESULT_ID_BITS;

	/* of type PgAioResultStatus, see above */
	uint32		status:PGAIO_RESULT_STATUS_BITS;

	/* meaning defined by callback->error */
	uint32		error_data:PGAIO_RESULT_ERROR_BITS;

	int32		result;
} PgAioResult;


StaticAssertDecl(PGAIO_RESULT_ID_BITS +
				 PGAIO_RESULT_STATUS_BITS +
				 PGAIO_RESULT_ERROR_BITS == 32,
				 "PgAioResult bits divided up incorrectly");
StaticAssertDecl(sizeof(PgAioResult) == 8,
				 "PgAioResult has unexpected size");

/*
 * Combination of PgAioResult with minimal metadata about the IO.
 *
 * Contains sufficient information to be able, in case the IO [partially]
 * fails, to log/raise an error under control of the IO issuing code.
 */
typedef struct PgAioReturn
{
	PgAioResult result;
	PgAioTargetData target_data;
} PgAioReturn;


#endif							/* AIO_TYPES_H */
