首页 > 应用开发 > IT综合 > Linux libaio 异步I/O
最近准备仔细看看innodb 异步I/O的实现,而在LINUX平台下Innodb中一般我们使用的都是libaio叫做LINUX NATIVE AIO,这有别于POSIX实现的AIO,因为以前对异步I/O并不熟悉,因为在很多LINUX 系统编程书籍上都没有介绍,而网上也是资料不多。当然其好处还是非常明显的,能够在使用O_DIRECT 打开文件的情况下,保证性能而不是消耗CPU资源在等待I/O落盘上,在MYSQL中如果使用了O_DIRECT打开了数据文件那么异步I/O将会发挥作用。当然MYSQL有一个自己模拟的异步I/O但是在现在支持LIBAIO的LINUX中一般都是 NATIVE AIO了。所以我仔细看了一下LINUX NATIVE AIO。
我主要参考如下文章:
http://www.360doc.com/content/14/0109/14/9008018_343854180.shtml
应该是谷歌的工程师写的,他最后列子我也详细的研究了一遍并且进行了修改/编译加上了中文注释。
吐槽一把Linux系统编程久了不用好多都模糊了,明年一定要好好复习一下。
简书地址
http://www.jianshu.com/p/f6371735e520
void* data;
short aio_lio_opcode;
int aio_fildes;
union
{
strcut
{
void* buf;
unsigned long nbytes;
long long offset;
} c;
} u;
data:是一个用户定义传入数据
aio_lio_opcode:是一个标示可以取
IO_CMD_PREAD:读 IO_CMD_PWRITE:写 或者其他支持的标志
aio_fileds:是iocb读取或者写入的文件描述符fd
u.c.buf:是一个读取或者写入的内存数据指针
u.c.nbytes:内存数据字节长度
u.c.offset:读取文件的偏移量
其次union u中实际包含其他的可能的I/O类型如下,有兴趣的需要在看看
union {
struct io_iocb_common c;
struct io_iocb_vector v;
struct io_iocb_poll poll;
struct io_iocb_sockaddr saddr;
} u;
iocb应该使用io_prep_pread和io_prep_pwrite进行初始化如下:
void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset); void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset);
我们发现 int fd,void *buf, size_t count, long long offset 刚好对应了
aio_fileds: u.c.buf: u.c.nbytes: u.c.offset:
而aio_lio_opcode可以从调用方式(io_prep_pread/io_prep_pwrite)看出来。
void* data:和iocb中的用户数据同一指针
struct iocb *obj:也就是iocb
long loing res:读或者写的字节数
1、建立一个io_context_t上下文
int io_setup(unsigned nr_events, io_context_t *ctxp);
nr_events:本io_context_t支持的最大event最大队列,注意和后面的io_getevents的nr兼容.
ctxp:一根指针io_context_t用于初始化,但是这个io_context_t必须提前建立好并且赋值为0.
LINUX MAIN PAGE:
DESCRIPTION
io_setup() creates an asynchronous I/O context capable of receiving at least nr_events. ctxp must not point to an AIO context that already
exists, and must be initialized to 0 prior to the call. On successful creation of the AIO context, *ctxp is filled in with the resulting han-
dle.
RETURN VALUE
On success, io_setup() returns 0. For the failure return, see NOTES.
ERRORS
EAGAIN The specified nr_events exceeds the user's limit of available events.
EFAULT An invalid pointer is passed for ctxp.
EINVAL ctxp is not initialized, or the specified nr_events exceeds internal limits. nr_events should be greater than 0.
ENOMEM Insufficient kernel resources are available.
ENOSYS io_setup() is not implemented on this architecture.
DESCRIPTION
io_destroy() removes the asynchronous I/O context from the list of I/O contexts and then destroys it. io_destroy() can also cancel any out-
standing asynchronous I/O actions on ctx and block on completion.
RETURN VALUE
On success, io_destroy() returns 0. For the failure return, see NOTES.
ERRORS
EFAULT The context pointed to is invalid.
EINVAL The AIO context specified by ctx is invalid.
ENOSYS io_destroy() is not implemented on this architecture.
3、提交异步I/O操作
int io_submit(io_context_t ctx_id, long nr, struct iocb **iocbpp);
ctx_id:异步I/O上下文
nr:后面iocb数组的长度
iocbpp:也就是iocb的数组
我们可以发现一个io_submit可以提交多个iocb异步I/O需求,但是它们之间是没有顺序的,如果提交多个iocb需求可以显著的提高性能,正常情况下其不会被堵塞,如果被堵塞可能由于没有使用O_DIRECT打开文件导致
LINUX MAIN PAGE:
DESCRIPTION
io_submit() queues nr I/O request blocks for processing in the AIO context ctx_id. iocbpp should be an array of nr AIO control blocks, which
will be submitted to context ctx_id.
RETURN VALUE
On success, io_submit() returns the number of iocbs submitted (which may be 0 if nr is zero). For the failure return, see NOTES.
ERRORS
EAGAIN Insufficient resources are available to queue any iocbs.
EBADF The file descriptor specified in the first iocb is invalid.
EFAULT One of the data structures points to invalid data.
EINVAL The aio_context specified by ctx_id is invalid. nr is less than 0. The iocb at *iocbpp[0] is not properly initialized, or the operation
specified is invalid for the file descriptor in the iocb.
ENOSYS io_submit() is not implemented on this architecture.
4、获取I/O完成状态
int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);
ctx_id:上下文
min_nr:io_getevents函数调用在达到min_nr将会返回结果io_events
nr:最大的io_event返回个数
events:它是一个返回io_event的一个数组
timeout:调用io_getevents堵塞的最大时间,如果达到这个值io_getevents函数调用 ,将会提前结束,返回实际的events数组和个数,可能会少于nr。
LINUX MAIN PAGE:
DESCRIPTION
io_getevents() attempts to read at least min_nr events and up to nr events from the completion queue of the AIO context specified by ctx_id.
timeout specifies the amount of time to wait for events, where a NULL timeout waits until at least min_nr events have been seen. Note that
timeout is relative and will be updated if not NULL and the operation blocks.
RETURN VALUE
On success, io_getevents() returns the number of events read: 0 if no events are available, or less than min_nr if the timeout has elapsed. For
the failure return, see NOTES.
ERRORS
EFAULT Either events or timeout is an invalid pointer.
EINVAL ctx_id is invalid. min_nr is out of range or nr is out of range.
EINTR Interrupted by a signal handler; see signal(7).
ENOSYS io_getevents() is not implemented on this architecture.
如果要明白呢一个系统函数的使用最重要的还是看看它的使用套路,下面的列子最好能够好好看看
点击(此处)折叠或打开
<length) {="" doreap(1);="" }="" ~aioadder()="" printf("closing="" aio="" context="" and="" file");="" io_destroy(ioctx);="" colse(fd);="" int="" sum()="" printf("writing="" consecutive="" integers="" to="" writefile();="" printf("rriting="" readfile();="" return="" sum;="" };="" main()="" aioadder="" adder(10000);="" adder.init();="" *="" 文件预先分配大小="" adder.writefile();="" adder.readfile();="" }
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/7728585/viewspace-2147684/ ,如需转载,请注明出处,否则将追究法律责任。