AgensGraph provides an Asynchronous and Direct IO (AIO) subsystem to improve throughput and reduce latency, particularly for WAL writes and large buffer reads. Using Direct IO avoids the CPU overhead of copying data between the kernel's page cache and the postgres buffer pool by using DMA, and avoids double buffering.
To use AIO, you typically interact with PgAioHandle and PgAioWaitRef objects. A common pattern involves:
- Acquiring an AIO handle via
pgaio_io_acquire. - Registering completion callbacks (e.g.,
PGAIO_HCB_SHARED_BUFFER_READV) so that buffer descriptors are updated automatically when the IO completes. - Associating buffer data with the handle using
pgaio_io_set_handle_data_32. - Passing the handle to a storage manager function like
smgrstartreadv. - Performing other work to hide latency.
- Waiting for completion using
pgaio_wref_wait. - Checking the result status via
PgAioReturn and reporting errors with pgaio_result_report.
/* Example of reading a buffer into shared buffers using AIO */
PgAioReturn ioret;
PgAioHandle *ioh = pgaio_io_acquire(CurrentResourceOwner, &ioret);
PgAioWaitRef iow;
pgaio_io_get_wref(ioh, &iow);
pgaio_io_register_callbacks(ioh, PGAIO_HCB_SHARED_BUFFER_READV, 0);
pgaio_io_set_handle_data_32(ioh, (uint32 *) buffer, 1);
smgrstartreadv(ioh, operation->smgr, forknum, blkno, BufferGetBlock(buffer), 1);
perform_other_work();
pgaio_wref_wait(&iow);
if (ioret.result.status == PGAIO_RS_ERROR)
pgaio_result_report(ioret.result, &ioret.target_data, ERROR);
if (ioret.result.status != PGAIO_RS_OK)
pgaio_result_report(ioret.result, &ioret.target_data, ERROR);