From 0f778a0a38e6ef81f76629fec2428745fccbf33a Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 14 Jun 2016 16:26:37 +0100 Subject: [PATCH] [block-cache] FIx some bugs in the io engine --- block-cache/io_engine.cc | 61 +++++++++++++++++++++++++++++----------- block-cache/io_engine.h | 22 ++++++++++----- 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/block-cache/io_engine.cc b/block-cache/io_engine.cc index a4211cb..2fe4082 100644 --- a/block-cache/io_engine.cc +++ b/block-cache/io_engine.cc @@ -14,13 +14,6 @@ using namespace std; //---------------------------------------------------------------- -namespace { - unsigned const SECTOR_SHIFT = 9; - unsigned const PAGE_SIZE = 4096; -} - -//---------------------------------------------------------------- - control_block_set::control_block_set(unsigned nr) : cbs_(nr) { @@ -77,7 +70,7 @@ aio_engine::~aio_engine() aio_engine::handle aio_engine::open_file(std::string const &path, mode m, sharing s) { - int flags = (m == READ_ONLY) ? O_RDONLY : O_RDWR; + int flags = (m == M_READ_ONLY) ? O_RDONLY : O_RDWR; if (s == EXCLUSIVE) flags |= O_EXCL; int fd = ::open(path.c_str(), O_DIRECT | flags); @@ -126,45 +119,81 @@ aio_engine::issue_io(handle h, dir d, sector_t b, sector_t e, void *data, unsign cb->u.c.buf = data; cb->u.c.offset = b << SECTOR_SHIFT; cb->u.c.nbytes = (e - b) << SECTOR_SHIFT; - cb->aio_lio_opcode = (d == READ) ? IO_CMD_PREAD : IO_CMD_PWRITE; + cb->aio_lio_opcode = (d == D_READ) ? IO_CMD_PREAD : IO_CMD_PWRITE; int r = io_submit(aio_context_, 1, &cb); return r == 1; } -std::pair +optional aio_engine::wait() +{ + return wait_(NULL); +} + +optional +aio_engine::wait(unsigned µsec) +{ + timespec start = micro_to_ts(microsec); + timespec stop = start; + auto r = wait_(&stop); + microsec = ts_to_micro(stop) - microsec; + return r; +} + +boost::optional +aio_engine::wait_(timespec *ts) { int r; struct io_event event; memset(&event, 0, sizeof(event)); - - r = io_getevents(aio_context_, 1, 1, &event, NULL); + r = io_getevents(aio_context_, 1, 1, &event, ts); if (r < 0) { std::ostringstream out; out << "io_getevents failed: " << r; throw std::runtime_error(out.str()); } + if (r == 0) { + return optional(); + } + iocb *cb = reinterpret_cast(event.obj); unsigned context = cbs_.context(cb); if (event.res == cb->u.c.nbytes) { cbs_.free(cb); - return make_pair(true, context); + return optional(make_pair(true, context)); } else if (static_cast(event.res) < 0) { cbs_.free(cb); - return make_pair(false, context); + return optional(make_pair(false, context)); } else { cbs_.free(cb); - return make_pair(false, context); + return optional(make_pair(false, context)); } // shouldn't get here - return make_pair(false, 0); + return optional(make_pair(false, 0)); +} + +struct timespec +aio_engine::micro_to_ts(unsigned micro) +{ + timespec ts; + ts.tv_sec = micro / 1000000u; + ts.tv_nsec = (micro % 1000000) * 1000; + return ts; +} + +unsigned +aio_engine::ts_to_micro(timespec const &ts) +{ + unsigned micro = ts.tv_sec * 1000000; + micro += ts.tv_nsec / 1000; + return micro; } //---------------------------------------------------------------- diff --git a/block-cache/io_engine.h b/block-cache/io_engine.h index f9e4c9c..fd902c1 100644 --- a/block-cache/io_engine.h +++ b/block-cache/io_engine.h @@ -14,17 +14,20 @@ namespace bcache { using sector_t = uint64_t; + unsigned const SECTOR_SHIFT = 9; + unsigned const PAGE_SIZE = 4096; + // Virtual base class to aid unit testing class io_engine { public: enum mode { - READ_ONLY, - READ_WRITE + M_READ_ONLY, + M_READ_WRITE }; enum dir { - READ, - WRITE + D_READ, + D_WRITE }; enum sharing { @@ -46,7 +49,8 @@ namespace bcache { // returns (success, context) using wait_result = std::pair; - virtual wait_result wait() = 0; + virtual boost::optional wait() = 0; + virtual boost::optional wait(unsigned µsec) = 0; private: io_engine(io_engine const &) = delete; @@ -90,10 +94,14 @@ namespace bcache { // Returns false if queueing the io failed virtual bool issue_io(handle h, dir d, sector_t b, sector_t e, void *data, unsigned context); - // returns (success, context) - virtual wait_result wait(); + virtual boost::optional wait(); + virtual boost::optional wait(unsigned µsec); private: + static struct timespec micro_to_ts(unsigned micro); + static unsigned ts_to_micro(timespec const &ts); + boost::optional wait_(timespec *ts); + std::list descriptors_; io_context_t aio_context_;