• os_aio_array_t
  • os_aio_slot_t
  1. os_aio_slot_t {
  2. ibool is_read; /*!< TRUE if a read operation */
  3. ulint pos; // os_aio_array_t数组中所在的位置
  4. ibool reserved; // TRUE表示该Slot已经被别的IO请求占用了
  5. time_t reservation_time; // 占用的时间
  6. ulint len; // io请求的长度
  7. byte* buf; // 数据读取或者需要写入的buffer,通常指向buffer pool的一个页面,压缩页面有特殊处理
  8. ulint type; /* 请求类型,即读还是写IO请求 */
  9. os_offset_t offset; /*!< file offset in bytes */
  10. os_file_t file; /*!< file where to read or write */
  11. const char* name; /*!< 需要读取的文件及路径信息 */
  12. ibool io_already_done; /* TRUE表示IO已经完成了
  13. fil_node_t* message1; /* 该aio操作的innodb文件描述符(f_node_t)*/
  14. void* message2; /* 用来记录完成IO请求所对应的具体buffer pool bpage页 */
  15. \#ifdef WIN_ASYNC_IO
  16. HANDLE handle; /*!< handle object we need in the
  17. OVERLAPPED struct */
  18. OVERLAPPED control; /*!< Windows control block for the
  19. aio request */
  20. \#elif defined(LINUX_NATIVE_AIO)
  21. struct iocb control; /* 该slot使用的aio请求控制块iocb */
  22. int n_bytes; /* 读写bytes */
  23. int ret; /* AIO return code */
  24. \#endif /* WIN_ASYNC_IO */
  25. }
  • 物理数据页操作入口函数os_aio_func
  1. static
  2. ibool
  3. /*==================*/
  4. os_aio_array_t* array, /* IO请求函数 */
  5. os_aio_slot_t* slot, /* 申请好的slot */
  6. ibool should_buffer) // 是否需要缓存aio 请求,该变量主要对预读起作用
  7. {
  8. ...
  9. /* Find out what we are going to work with.
  10. The iocb struct is directly in the slot.
  11. The io_context is one per segment. */
  12. // 每个segment包含的slot个数,Linux下每个segment包含256个slot
  13. slots_per_segment = array->n_slots / array->n_segments;
  14. iocb = &slot->control;
  15. io_ctx_index = slot->pos / slots_per_segment;
  16. if (should_buffer) {
  17. /* 这里也可以看到aio请求缓存只对读请求起作用 */
  18. ut_ad(array == os_aio_read_array);
  19. ulint n;
  20. ulint count;
  21. os_mutex_enter(array->mutex);
  22. /* There are array->n_slots elements in array->pending, which is divided into
  23. * array->n_segments area of equal size. The iocb of each segment are
  24. * buffered in its corresponding area in the pending array consecutively as
  25. * they come. array->count[i] records the number of buffered aio requests in
  26. * the ith segment.*/
  27. n = io_ctx_index * slots_per_segment
  28. + array->count[io_ctx_index];
  29. array->pending[n] = iocb;
  30. array->count[io_ctx_index] ++;
  31. count = array->count[io_ctx_index];
  32. os_mutex_exit(array->mutex);
  33. // 如果当前segment的slot都已经被占用了,就需要提交一次异步aio请求
  34. if (count == slots_per_segment) {
  35. os_aio_linux_dispatch_read_array_submit(); //no cover line
  36. }
  37. // 否则就直接返回
  38. return (TRUE);
  39. }
  40. // 直接提交IO请求到内核
  41. ret = io_submit(array->aio_ctx[io_ctx_index], 1, &iocb);
  42. ...
  43. }
  • IO线程负责监控aio请求的主函数fil_aio_wait
  • IO线程负责处理native IO请求的函数os_aio_linux_handle
  1. ibool
  2. os_aio_linux_handle(ulint global_seg, // 属于哪个segment
  3. fil_node_t**message1, /* 该aio操作的innodb文件描述符(f_node_t)*/
  4. void** message2, /* 用来记录完成IO请求所对应的具体buffer pool bpage页 */
  5. segment = os_aio_get_array_and_local_segment(&array, global_seg);
  6. n = array->n_slots / array->n_segments; //获得一个线程可监控的io event数
  7. /* Loop until we have found a completed request. */
  8. for (;;) {
  9. ibool any_reserved = FALSE;
  10. os_mutex_enter(array->mutex);
  11. for (i = 0; i < n; ++i) { // 遍历该线程所发起的所有aio请求
  12. slot = os_aio_array_get_nth_slot(
  13. array, i + segment * n);
  14. if (!slot->reserved) { // 该slot是否被占用
  15. continue;
  16. } else if (slot->io_already_done) { // IO请求已经完成,可以通知主线程返回数据了
  17. /* Something for us to work on. */
  18. goto found;
  19. } else {
  20. any_reserved = TRUE;
  21. }
  22. }
  23. os_mutex_exit(array->mutex);
  24. // 到这里说明没有找到一个完成的io,则再去collect
  25. os_aio_linux_collect(array, segment, n);
  26. found: // 找到一个完成的io,将内容返回
  27. *message1 = slot->message1;
  28. *message2 = slot->message2; // 返回完成IO所对应的bpage页
  29. *type = slot->type;
  30. if (slot->ret == 0 && slot->n_bytes == (long) slot->len) {
  31. if (slot->page_encrypt
  32. && slot->type == OS_FILE_READ) {
  33. os_decrypt_page(slot->buf, slot->len, slot->page_size, FALSE);
  34. }
  35. ret = TRUE;
  36. } else {
  37. errno = -slot->ret;
  38. /* os_file_handle_error does tell us if we should retry
  39. this IO. As it stands now, we don't do this retry when
  40. reaping requests from a different context than
  41. the dispatcher. This non-retry logic is the same for
  42. windows and linux native AIO.
  43. We should probably look into this to transparently
  44. re-submit the IO. */
  45. os_file_handle_error(slot->name, "Linux aio");
  46. ret = FALSE;
  47. }
  48. os_mutex_exit(array->mutex);
  49. os_aio_array_free_slot(array, slot);
  50. }
  • 等待native IO请求完成os_aio_linux_collect