Commit d30e51fa authored by Eugene Kosov's avatar Eugene Kosov

cleanup Linux AIO

Replace all io_context* occurrences with io_context_t

Even in release mode die immediately when some io_* functions return
EINVAL. This always means some programming bug and it's better to fail fast.

LinuxAIOHandler::resubmit(): fix condition. Stop ignoring -1 return code which
corresponds to EPERM and io_submit() really can return this one.

Use io_destroy() to stop leaking io_context_t.

Make m_aio_ctx std::vector instead of C array. I think that internal check
for index overflow might be useful.

Add debug assertions for EFAULT because for me receiving it
looks like a programming bug.
parent 899c5bd5
...@@ -413,7 +413,7 @@ class AIO { ...@@ -413,7 +413,7 @@ class AIO {
/** Accessor for the AIO context /** Accessor for the AIO context
@param[in] segment Segment for which to get the context @param[in] segment Segment for which to get the context
@return the AIO context for the segment */ @return the AIO context for the segment */
io_context* io_ctx(ulint segment) io_context_t io_ctx(ulint segment)
MY_ATTRIBUTE((warn_unused_result)) MY_ATTRIBUTE((warn_unused_result))
{ {
ut_ad(segment < get_n_segments()); ut_ad(segment < get_n_segments());
...@@ -421,7 +421,7 @@ class AIO { ...@@ -421,7 +421,7 @@ class AIO {
return(m_aio_ctx[segment]); return(m_aio_ctx[segment]);
} }
/** Creates an io_context for native linux AIO. /** Creates an io_context_t for native linux AIO.
@param[in] max_events number of events @param[in] max_events number of events
@param[out] io_ctx io_ctx to initialize. @param[out] io_ctx io_ctx to initialize.
@return true on success. */ @return true on success. */
...@@ -622,7 +622,7 @@ class AIO { ...@@ -622,7 +622,7 @@ class AIO {
/** completion queue for IO. There is one such queue per /** completion queue for IO. There is one such queue per
segment. Each thread will work on one ctx exclusively. */ segment. Each thread will work on one ctx exclusively. */
io_context_t* m_aio_ctx; std::vector<io_context_t> m_aio_ctx;
/** The array to collect completed IOs. There is one such /** The array to collect completed IOs. There is one such
event for each possible pending IO. The size of the array event for each possible pending IO. The size of the array
...@@ -1794,8 +1794,9 @@ LinuxAIOHandler::resubmit(Slot* slot) ...@@ -1794,8 +1794,9 @@ LinuxAIOHandler::resubmit(Slot* slot)
/* Resubmit an I/O request */ /* Resubmit an I/O request */
int ret = io_submit(m_array->io_ctx(m_segment), 1, &iocb); int ret = io_submit(m_array->io_ctx(m_segment), 1, &iocb);
ut_a(ret != -EINVAL);
if (ret < -1) { if (ret < 0) {
errno = -ret; errno = -ret;
} }
...@@ -1896,8 +1897,8 @@ LinuxAIOHandler::collect() ...@@ -1896,8 +1897,8 @@ LinuxAIOHandler::collect()
ut_ad(m_array != NULL); ut_ad(m_array != NULL);
ut_ad(m_segment < m_array->get_n_segments()); ut_ad(m_segment < m_array->get_n_segments());
/* Which io_context we are going to use. */ /* Which io_context_t we are going to use. */
io_context* io_ctx = m_array->io_ctx(m_segment); io_context_t io_ctx = m_array->io_ctx(m_segment);
/* Starting point of the m_segment we will be working on. */ /* Starting point of the m_segment we will be working on. */
ulint start_pos = m_segment * m_n_slots; ulint start_pos = m_segment * m_n_slots;
...@@ -1924,6 +1925,8 @@ LinuxAIOHandler::collect() ...@@ -1924,6 +1925,8 @@ LinuxAIOHandler::collect()
int ret; int ret;
ret = io_getevents(io_ctx, 1, m_n_slots, events, &timeout); ret = io_getevents(io_ctx, 1, m_n_slots, events, &timeout);
ut_a(ret != -EINVAL);
ut_ad(ret != -EFAULT);
for (int i = 0; i < ret; ++i) { for (int i = 0; i < ret; ++i) {
...@@ -2150,14 +2153,15 @@ AIO::linux_dispatch(Slot* slot) ...@@ -2150,14 +2153,15 @@ AIO::linux_dispatch(Slot* slot)
/* Find out what we are going to work with. /* Find out what we are going to work with.
The iocb struct is directly in the slot. The iocb struct is directly in the slot.
The io_context is one per segment. */ The io_context_t is one per segment. */
ulint io_ctx_index; ulint io_ctx_index;
struct iocb* iocb = &slot->control; struct iocb* iocb = &slot->control;
io_ctx_index = (slot->pos * m_n_segments) / m_slots.size(); io_ctx_index = (slot->pos * m_n_segments) / m_slots.size();
int ret = io_submit(m_aio_ctx[io_ctx_index], 1, &iocb); int ret = io_submit(io_ctx(io_ctx_index), 1, &iocb);
ut_a(ret != -EINVAL);
/* io_submit() returns number of successfully queued requests /* io_submit() returns number of successfully queued requests
or -errno. */ or -errno. */
...@@ -2169,7 +2173,7 @@ AIO::linux_dispatch(Slot* slot) ...@@ -2169,7 +2173,7 @@ AIO::linux_dispatch(Slot* slot)
return(ret == 1); return(ret == 1);
} }
/** Creates an io_context for native linux AIO. /** Creates an io_context_t for native linux AIO.
@param[in] max_events number of events @param[in] max_events number of events
@param[out] io_ctx io_ctx to initialize. @param[out] io_ctx io_ctx to initialize.
@return true on success. */ @return true on success. */
...@@ -2188,6 +2192,7 @@ AIO::linux_create_io_ctx( ...@@ -2188,6 +2192,7 @@ AIO::linux_create_io_ctx(
IO requests this context will handle. */ IO requests this context will handle. */
int ret = io_setup(max_events, io_ctx); int ret = io_setup(max_events, io_ctx);
ut_a(ret != -EINVAL);
if (ret == 0) { if (ret == 0) {
/* Success. Return now. */ /* Success. Return now. */
...@@ -2282,6 +2287,10 @@ AIO::is_linux_native_aio_supported() ...@@ -2282,6 +2287,10 @@ AIO::is_linux_native_aio_supported()
<< "Unable to create temp file to check" << "Unable to create temp file to check"
" native AIO support."; " native AIO support.";
int ret = io_destroy(io_ctx);
ut_a(ret != -EINVAL);
ut_ad(ret != -EFAULT);
return(false); return(false);
} }
} else { } else {
...@@ -2311,6 +2320,10 @@ AIO::is_linux_native_aio_supported() ...@@ -2311,6 +2320,10 @@ AIO::is_linux_native_aio_supported()
<< " \"" << name << "\" to check native" << " \"" << name << "\" to check native"
<< " AIO read support."; << " AIO read support.";
int ret = io_destroy(io_ctx);
ut_a(ret != EINVAL);
ut_ad(ret != EFAULT);
return(false); return(false);
} }
} }
...@@ -2340,10 +2353,12 @@ AIO::is_linux_native_aio_supported() ...@@ -2340,10 +2353,12 @@ AIO::is_linux_native_aio_supported()
} }
int err = io_submit(io_ctx, 1, &p_iocb); int err = io_submit(io_ctx, 1, &p_iocb);
ut_a(err != -EINVAL);
if (err >= 1) { if (err >= 1) {
/* Now collect the submitted IO request. */ /* Now collect the submitted IO request. */
err = io_getevents(io_ctx, 1, 1, &io_event, NULL); err = io_getevents(io_ctx, 1, 1, &io_event, NULL);
ut_a(err != -EINVAL);
} }
ut_free(buf); ut_free(buf);
...@@ -2351,7 +2366,13 @@ AIO::is_linux_native_aio_supported() ...@@ -2351,7 +2366,13 @@ AIO::is_linux_native_aio_supported()
switch (err) { switch (err) {
case 1: case 1:
return(true); {
int ret = io_destroy(io_ctx);
ut_a(ret != -EINVAL);
ut_ad(ret != -EFAULT);
return(true);
}
case -EINVAL: case -EINVAL:
case -ENOSYS: case -ENOSYS:
...@@ -2371,6 +2392,10 @@ AIO::is_linux_native_aio_supported() ...@@ -2371,6 +2392,10 @@ AIO::is_linux_native_aio_supported()
<< "returned error[" << -err << "]"; << "returned error[" << -err << "]";
} }
int ret = io_destroy(io_ctx);
ut_a(ret != -EINVAL);
ut_ad(ret != -EFAULT);
return(false); return(false);
} }
...@@ -5779,8 +5804,7 @@ AIO::AIO( ...@@ -5779,8 +5804,7 @@ AIO::AIO(
m_n_segments(segments), m_n_segments(segments),
m_n_reserved() m_n_reserved()
# ifdef LINUX_NATIVE_AIO # ifdef LINUX_NATIVE_AIO
,m_aio_ctx(), ,m_events(m_slots.size())
m_events(m_slots.size())
# endif /* LINUX_NATIVE_AIO */ # endif /* LINUX_NATIVE_AIO */
#ifdef WIN_ASYNC_IO #ifdef WIN_ASYNC_IO
,m_completion_port(new_completion_port()) ,m_completion_port(new_completion_port())
...@@ -5836,24 +5860,16 @@ AIO::init_slots() ...@@ -5836,24 +5860,16 @@ AIO::init_slots()
dberr_t dberr_t
AIO::init_linux_native_aio() AIO::init_linux_native_aio()
{ {
/* Initialize the io_context array. One io_context
per segment in the array. */
ut_a(m_aio_ctx == NULL);
m_aio_ctx = static_cast<io_context**>( /* Initialize the io_context_t array. One io_context_t
ut_zalloc_nokey(m_n_segments * sizeof(*m_aio_ctx))); per segment in the array. */
m_aio_ctx.resize(get_n_segments());
if (m_aio_ctx == NULL) {
return(DB_OUT_OF_MEMORY);
}
io_context** ctx = m_aio_ctx;
ulint max_events = slots_per_segment(); ulint max_events = slots_per_segment();
for (ulint i = 0; i < m_n_segments; ++i, ++ctx) { for (ulint i = 0; i < m_aio_ctx.size(); ++i) {
if (!linux_create_io_ctx(max_events, ctx)) { if (!linux_create_io_ctx(max_events, &m_aio_ctx[i])) {
/* If something bad happened during aio setup /* If something bad happened during aio setup
we disable linux native aio. we disable linux native aio.
The disadvantage will be a small memory leak The disadvantage will be a small memory leak
...@@ -5870,8 +5886,13 @@ AIO::init_linux_native_aio() ...@@ -5870,8 +5886,13 @@ AIO::init_linux_native_aio()
<< "try increasing system " << "try increasing system "
<< "fs.aio-max-nr to 1048576 or larger or " << "fs.aio-max-nr to 1048576 or larger or "
<< "setting innodb_use_native_aio = 0 in my.cnf"; << "setting innodb_use_native_aio = 0 in my.cnf";
ut_free(m_aio_ctx);
m_aio_ctx = 0; for (ulint j = 0; j < i; j++) {
int ret = io_destroy(m_aio_ctx[i]);
ut_a(ret != -EINVAL);
}
m_aio_ctx.clear();
srv_use_native_aio = FALSE; srv_use_native_aio = FALSE;
return(DB_SUCCESS); return(DB_SUCCESS);
} }
...@@ -5947,15 +5968,15 @@ AIO::~AIO() ...@@ -5947,15 +5968,15 @@ AIO::~AIO()
#if defined(LINUX_NATIVE_AIO) #if defined(LINUX_NATIVE_AIO)
if (srv_use_native_aio) { if (srv_use_native_aio) {
m_events.clear(); for (ulint i = 0; i < m_aio_ctx.size(); i++) {
ut_free(m_aio_ctx); int ret = io_destroy(m_aio_ctx[i]);
ut_a(ret != -EINVAL);
}
} }
#endif /* LINUX_NATIVE_AIO */ #endif /* LINUX_NATIVE_AIO */
#if defined(WIN_ASYNC_IO) #if defined(WIN_ASYNC_IO)
CloseHandle(m_completion_port); CloseHandle(m_completion_port);
#endif #endif
m_slots.clear();
} }
/** Initializes the asynchronous io system. Creates one array each for ibuf /** Initializes the asynchronous io system. Creates one array each for ibuf
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment