[block-cache] FIx some bugs in the io engine

This commit is contained in:
Joe Thornber 2016-06-14 16:26:37 +01:00
parent e5f969817e
commit 0f778a0a38
2 changed files with 60 additions and 23 deletions

View File

@ -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) control_block_set::control_block_set(unsigned nr)
: cbs_(nr) : cbs_(nr)
{ {
@ -77,7 +70,7 @@ aio_engine::~aio_engine()
aio_engine::handle aio_engine::handle
aio_engine::open_file(std::string const &path, mode m, sharing s) 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) if (s == EXCLUSIVE)
flags |= O_EXCL; flags |= O_EXCL;
int fd = ::open(path.c_str(), O_DIRECT | flags); 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.buf = data;
cb->u.c.offset = b << SECTOR_SHIFT; cb->u.c.offset = b << SECTOR_SHIFT;
cb->u.c.nbytes = (e - 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); int r = io_submit(aio_context_, 1, &cb);
return r == 1; return r == 1;
} }
std::pair<bool, io_engine::handle> optional<io_engine::wait_result>
aio_engine::wait() aio_engine::wait()
{
return wait_(NULL);
}
optional<io_engine::wait_result>
aio_engine::wait(unsigned &microsec)
{
timespec start = micro_to_ts(microsec);
timespec stop = start;
auto r = wait_(&stop);
microsec = ts_to_micro(stop) - microsec;
return r;
}
boost::optional<io_engine::wait_result>
aio_engine::wait_(timespec *ts)
{ {
int r; int r;
struct io_event event; struct io_event event;
memset(&event, 0, sizeof(event)); memset(&event, 0, sizeof(event));
r = io_getevents(aio_context_, 1, 1, &event, ts);
r = io_getevents(aio_context_, 1, 1, &event, NULL);
if (r < 0) { if (r < 0) {
std::ostringstream out; std::ostringstream out;
out << "io_getevents failed: " << r; out << "io_getevents failed: " << r;
throw std::runtime_error(out.str()); throw std::runtime_error(out.str());
} }
if (r == 0) {
return optional<wait_result>();
}
iocb *cb = reinterpret_cast<iocb *>(event.obj); iocb *cb = reinterpret_cast<iocb *>(event.obj);
unsigned context = cbs_.context(cb); unsigned context = cbs_.context(cb);
if (event.res == cb->u.c.nbytes) { if (event.res == cb->u.c.nbytes) {
cbs_.free(cb); cbs_.free(cb);
return make_pair(true, context); return optional<wait_result>(make_pair(true, context));
} else if (static_cast<int>(event.res) < 0) { } else if (static_cast<int>(event.res) < 0) {
cbs_.free(cb); cbs_.free(cb);
return make_pair(false, context); return optional<wait_result>(make_pair(false, context));
} else { } else {
cbs_.free(cb); cbs_.free(cb);
return make_pair(false, context); return optional<wait_result>(make_pair(false, context));
} }
// shouldn't get here // shouldn't get here
return make_pair(false, 0); return optional<wait_result>(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;
} }
//---------------------------------------------------------------- //----------------------------------------------------------------

View File

@ -14,17 +14,20 @@
namespace bcache { namespace bcache {
using sector_t = uint64_t; using sector_t = uint64_t;
unsigned const SECTOR_SHIFT = 9;
unsigned const PAGE_SIZE = 4096;
// Virtual base class to aid unit testing // Virtual base class to aid unit testing
class io_engine { class io_engine {
public: public:
enum mode { enum mode {
READ_ONLY, M_READ_ONLY,
READ_WRITE M_READ_WRITE
}; };
enum dir { enum dir {
READ, D_READ,
WRITE D_WRITE
}; };
enum sharing { enum sharing {
@ -46,7 +49,8 @@ namespace bcache {
// returns (success, context) // returns (success, context)
using wait_result = std::pair<bool, unsigned>; using wait_result = std::pair<bool, unsigned>;
virtual wait_result wait() = 0; virtual boost::optional<wait_result> wait() = 0;
virtual boost::optional<wait_result> wait(unsigned &microsec) = 0;
private: private:
io_engine(io_engine const &) = delete; io_engine(io_engine const &) = delete;
@ -90,10 +94,14 @@ namespace bcache {
// Returns false if queueing the io failed // 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); virtual bool issue_io(handle h, dir d, sector_t b, sector_t e, void *data, unsigned context);
// returns (success, context) virtual boost::optional<wait_result> wait();
virtual wait_result wait(); virtual boost::optional<wait_result> wait(unsigned &microsec);
private: private:
static struct timespec micro_to_ts(unsigned micro);
static unsigned ts_to_micro(timespec const &ts);
boost::optional<io_engine::wait_result> wait_(timespec *ts);
std::list<base::unique_fd> descriptors_; std::list<base::unique_fd> descriptors_;
io_context_t aio_context_; io_context_t aio_context_;