diff options
Diffstat (limited to 'storage/xtradb/os/os0file.cc')
-rw-r--r-- | storage/xtradb/os/os0file.cc | 146 |
1 files changed, 140 insertions, 6 deletions
diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 8b0fa059100..634ebb2af49 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -296,6 +296,16 @@ struct os_aio_array_t{ There is one such event for each possible pending IO. The size of the array is equal to n_slots. */ + struct iocb** pending; + /* Array to buffer the not-submitted aio + requests. The array length is n_slots. + It is divided into n_segments segments. + pending requests on each segment are buffered + separately.*/ + ulint* count; + /* Array of length n_segments. Each element + counts the number of not-submitted aio + request on that segment.*/ #endif /* LINUX_NATIV_AIO */ }; @@ -4276,6 +4286,13 @@ os_aio_array_create( memset(io_event, 0x0, sizeof(*io_event) * n); array->aio_events = io_event; + array->pending = static_cast<struct iocb**>( + ut_malloc(n * sizeof(struct iocb*))); + memset(array->pending, 0x0, sizeof(struct iocb*) * n); + array->count = static_cast<ulint*>( + ut_malloc(n_segments * sizeof(ulint))); + memset(array->count, 0x0, sizeof(ulint) * n_segments); + skip_native_aio: #endif /* LINUX_NATIVE_AIO */ for (ulint i = 0; i < n; i++) { @@ -4310,6 +4327,16 @@ os_aio_array_free( if (srv_use_native_aio) { ut_free(array->aio_events); ut_free(array->aio_ctx); + +#ifdef UNIV_DEBUG + for (size_t idx = 0; idx < array->n_slots; ++idx) + ut_ad(array->pending[idx] == NULL); + for (size_t idx = 0; idx < array->n_segments; ++idx) + ut_ad(array->count[idx] == 0); +#endif + + ut_free(array->pending); + ut_free(array->count); } #endif /* LINUX_NATIVE_AIO */ @@ -4957,6 +4984,83 @@ readahead requests. */ } #endif /* _WIN32 */ +/** Submit buffered AIO requests on the given segment to the kernel +(low level function). +@param acquire_mutex specifies whether to lock array mutex +*/ +static +void +os_aio_dispatch_read_array_submit_low(bool acquire_mutex MY_ATTRIBUTE((unused))) +{ + if (!srv_use_native_aio) { + return; + } +#if defined(LINUX_NATIVE_AIO) + os_aio_array_t* array = os_aio_read_array; + ulint total_submitted = 0; + if (acquire_mutex) + os_mutex_enter(array->mutex); + /* Submit aio requests buffered on all segments. */ + for (ulint i = 0; i < array->n_segments; i++) { + const int count = array->count[i]; + int offset = 0; + while (offset != count) { + struct iocb** const iocb_array = array->pending + + i * array->n_slots / array->n_segments + + offset; + const int partial_count = count - offset; + /* io_submit() returns number of successfully queued + requests or (-errno). + It returns 0 only if the number of iocb blocks passed + is also 0. */ + const int submitted = io_submit(array->aio_ctx[i], + partial_count, iocb_array); + + /* This assertion prevents infinite loop in both + debug and release modes. */ + ut_a(submitted != 0); + + if (submitted < 0) { + /* Terminating with fatal error */ + const char* errmsg = + strerror(-submitted); + ib_logf(IB_LOG_LEVEL_FATAL, + "Trying to sumbit %d aio requests, " + "io_submit() set errno to %d: %s", + partial_count, -submitted, + errmsg ? errmsg : "<unknown>"); + } + ut_ad(submitted <= partial_count); + if (submitted < partial_count) + { + ib_logf(IB_LOG_LEVEL_WARN, + "Trying to sumbit %d aio requests, " + "io_submit() submitted only %d", + partial_count, submitted); + } + offset += submitted; + } + total_submitted += count; + } + /* Reset the aio request buffer. */ + memset(array->pending, 0x0, sizeof(struct iocb*) * array->n_slots); + memset(array->count, 0x0, sizeof(ulint) * array->n_segments); + + if (acquire_mutex) + os_mutex_exit(array->mutex); + + srv_stats.n_aio_submitted.add(total_submitted); +#endif +} + +/** Submit buffered AIO requests on the given segment to the kernel. */ +UNIV_INTERN +void +os_aio_dispatch_read_array_submit() +{ + os_aio_dispatch_read_array_submit_low(true); +} + #if defined(LINUX_NATIVE_AIO) /*******************************************************************//** Dispatch an AIO request to the kernel. @@ -4966,10 +5070,11 @@ ibool os_aio_linux_dispatch( /*==================*/ os_aio_array_t* array, /*!< in: io request array. */ - os_aio_slot_t* slot) /*!< in: an already reserved slot. */ + os_aio_slot_t* slot, /*!< in: an already reserved slot. */ + bool should_buffer) /*!< in: should buffer the request + rather than submit. */ { int ret; - ulint io_ctx_index; struct iocb* iocb; ut_ad(slot != NULL); @@ -4981,9 +5086,31 @@ os_aio_linux_dispatch( The iocb struct is directly in the slot. The io_context is one per segment. */ + ulint slots_per_segment = array->n_slots / array->n_segments; iocb = &slot->control; - io_ctx_index = (slot->pos * array->n_segments) / array->n_slots; + ulint io_ctx_index = slot->pos / slots_per_segment; + if (should_buffer) { + ut_ad(array == os_aio_read_array); + os_mutex_enter(array->mutex); + /* There are array->n_slots elements in array->pending, + which is divided into array->n_segments area of equal size. + The iocb of each segment are buffered in its corresponding area + in the pending array consecutively as they come. + array->count[i] records the number of buffered aio requests + in the ith segment.*/ + ulint& count = array->count[io_ctx_index]; + ut_ad(count != slots_per_segment); + ulint n = io_ctx_index * slots_per_segment + count; + array->pending[n] = iocb; + ++count; + if (count == slots_per_segment) { + os_aio_dispatch_read_array_submit_low(false); + } + os_mutex_exit(array->mutex); + return(TRUE); + } + /* Submit the given request. */ ret = io_submit(array->aio_ctx[io_ctx_index], 1, &iocb); #if defined(UNIV_AIO_DEBUG) @@ -5046,11 +5173,17 @@ os_aio_func( OS_AIO_SYNC */ ulint space_id, trx_t* trx, - ulint* write_size)/*!< in/out: Actual write size initialized + ulint* write_size,/*!< in/out: Actual write size initialized after fist successfull trim operation for this page and if initialized we do not trim again if actual page size does not decrease. */ + bool should_buffer) + /*!< in: Whether to buffer an aio request. + AIO read ahead uses this. If you plan to + use this parameter, make sure you remember + to call os_aio_dispatch_read_array_submit() + when you're ready to commit all your requests.*/ { os_aio_array_t* array; os_aio_slot_t* slot; @@ -5168,7 +5301,8 @@ try_again: goto err_exit; #elif defined(LINUX_NATIVE_AIO) - if (!os_aio_linux_dispatch(array, slot)) { + if (!os_aio_linux_dispatch(array, slot, + should_buffer)) { goto err_exit; } #endif /* WIN_ASYNC_IO */ @@ -5192,7 +5326,7 @@ try_again: if(!ret && GetLastError() != ERROR_IO_PENDING) goto err_exit; #elif defined(LINUX_NATIVE_AIO) - if (!os_aio_linux_dispatch(array, slot)) { + if (!os_aio_linux_dispatch(array, slot, false)) { goto err_exit; } #endif /* WIN_ASYNC_IO */ |