summaryrefslogtreecommitdiff
path: root/storage/xtradb/os/os0file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/os/os0file.cc')
-rw-r--r--storage/xtradb/os/os0file.cc146
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 */