[block-cache] FIx some bugs in the io engine
This commit is contained in:
parent
e5f969817e
commit
0f778a0a38
@ -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 µsec)
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
@ -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 µsec) = 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 µsec);
|
||||||
|
|
||||||
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_;
|
||||||
|
Loading…
Reference in New Issue
Block a user