[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)
: 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<bool, io_engine::handle>
optional<io_engine::wait_result>
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;
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<wait_result>();
}
iocb *cb = reinterpret_cast<iocb *>(event.obj);
unsigned context = cbs_.context(cb);
if (event.res == cb->u.c.nbytes) {
cbs_.free(cb);
return make_pair(true, context);
return optional<wait_result>(make_pair(true, context));
} else if (static_cast<int>(event.res) < 0) {
cbs_.free(cb);
return make_pair(false, context);
return optional<wait_result>(make_pair(false, context));
} else {
cbs_.free(cb);
return make_pair(false, context);
return optional<wait_result>(make_pair(false, context));
}
// 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 {
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<bool, unsigned>;
virtual wait_result wait() = 0;
virtual boost::optional<wait_result> wait() = 0;
virtual boost::optional<wait_result> wait(unsigned &microsec) = 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_result> wait();
virtual boost::optional<wait_result> wait(unsigned &microsec);
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_;
io_context_t aio_context_;