Commit 88b49f3e authored by Lucian Grijincu's avatar Lucian Grijincu Committed by Jordan DeLong

folly: AsyncIO: add debuging helper

Summary: Change State to enum class, and add debugging helper to AsyncIOOp and AsyncIO.

Test Plan: n/a

Reviewed By: philipp@fb.com

FB internal diff: D715676
parent feca2a76
......@@ -16,12 +16,15 @@
#include "folly/experimental/io/AsyncIO.h"
#include <unistd.h>
#include <cerrno>
#include <string>
#include <boost/intrusive/parent_from_member.hpp>
#include <glog/logging.h>
#include "folly/Exception.h"
#include "folly/Format.h"
#include "folly/Likely.h"
#include "folly/String.h"
#include "folly/eventfd.h"
......@@ -30,31 +33,31 @@ namespace folly {
AsyncIOOp::AsyncIOOp(NotificationCallback cb)
: cb_(std::move(cb)),
state_(UNINITIALIZED),
state_(State::UNINITIALIZED),
result_(-EINVAL) {
memset(&iocb_, 0, sizeof(iocb_));
}
void AsyncIOOp::reset(NotificationCallback cb) {
CHECK_NE(state_, PENDING);
CHECK_NE(state_, State::PENDING);
cb_ = std::move(cb);
state_ = UNINITIALIZED;
state_ = State::UNINITIALIZED;
result_ = -EINVAL;
memset(&iocb_, 0, sizeof(iocb_));
}
AsyncIOOp::~AsyncIOOp() {
CHECK_NE(state_, PENDING);
CHECK_NE(state_, State::PENDING);
}
void AsyncIOOp::start() {
DCHECK_EQ(state_, INITIALIZED);
state_ = PENDING;
DCHECK_EQ(state_, State::INITIALIZED);
state_ = State::PENDING;
}
void AsyncIOOp::complete(ssize_t result) {
DCHECK_EQ(state_, PENDING);
state_ = COMPLETED;
DCHECK_EQ(state_, State::PENDING);
state_ = State::COMPLETED;
result_ = result;
if (cb_) {
cb_(this);
......@@ -62,7 +65,7 @@ void AsyncIOOp::complete(ssize_t result) {
}
ssize_t AsyncIOOp::result() const {
CHECK_EQ(state_, COMPLETED);
CHECK_EQ(state_, State::COMPLETED);
return result_;
}
......@@ -95,8 +98,8 @@ void AsyncIOOp::pwritev(int fd, const iovec* iov, int iovcnt, off_t start) {
}
void AsyncIOOp::init() {
CHECK_EQ(state_, UNINITIALIZED);
state_ = INITIALIZED;
CHECK_EQ(state_, State::UNINITIALIZED);
state_ = State::INITIALIZED;
}
AsyncIO::AsyncIO(size_t capacity, PollMode pollMode)
......@@ -133,7 +136,7 @@ void AsyncIO::initializeContext() {
}
void AsyncIO::submit(Op* op) {
CHECK_EQ(op->state(), Op::INITIALIZED);
CHECK_EQ(op->state(), Op::State::INITIALIZED);
CHECK_LT(pending_, capacity_) << "too many pending requests";
initializeContext(); // on demand
iocb* cb = &op->iocb_;
......@@ -243,5 +246,85 @@ void AsyncIOQueue::maybeDequeue() {
}
}
// debugging helpers:
namespace {
#define X(c) case c: return #c
const char* asyncIoOpStateToString(AsyncIOOp::State state) {
switch (state) {
X(AsyncIOOp::State::UNINITIALIZED);
X(AsyncIOOp::State::INITIALIZED);
X(AsyncIOOp::State::PENDING);
X(AsyncIOOp::State::COMPLETED);
}
return "<INVALID AsyncIOOp::State>";
}
const char* iocbCmdToString(short int cmd_short) {
io_iocb_cmd cmd = static_cast<io_iocb_cmd>(cmd_short);
switch (cmd) {
X(IO_CMD_PREAD);
X(IO_CMD_PWRITE);
X(IO_CMD_FSYNC);
X(IO_CMD_FDSYNC);
X(IO_CMD_POLL);
X(IO_CMD_NOOP);
X(IO_CMD_PREADV);
X(IO_CMD_PWRITEV);
};
return "<INVALID io_iocb_cmd>";
}
#undef X
std::string fd2name(int fd) {
std::string path = folly::to<std::string>("/proc/self/fd/", fd);
char link[PATH_MAX];
const ssize_t length =
std::max<ssize_t>(readlink(path.c_str(), link, PATH_MAX), 0);
return path.assign(link, length);
}
std::ostream& operator<<(std::ostream& os, const iocb& cb) {
os << folly::format(
"data={}, key={}, opcode={}, reqprio={}, fd={}, f={}, ",
cb.data, cb.key, iocbCmdToString(cb.aio_lio_opcode),
cb.aio_reqprio, cb.aio_fildes, fd2name(cb.aio_fildes));
switch (cb.aio_lio_opcode) {
case IO_CMD_PREAD:
case IO_CMD_PWRITE:
os << folly::format("buf={}, off={}, size={}, ",
cb.u.c.buf, cb.u.c.nbytes, cb.u.c.offset);
default:
os << "[TODO: write debug string for "
<< iocbCmdToString(cb.aio_lio_opcode) << "] ";
}
return os;
}
} // anonymous namespace
std::ostream& operator<<(std::ostream& os, const AsyncIOOp& op) {
os << "{" << op.state_ << ", ";
if (op.state_ != AsyncIOOp::State::UNINITIALIZED) {
os << op.iocb_;
}
if (op.state_ == AsyncIOOp::State::COMPLETED) {
os << "result=" << op.result_ << ", ";
}
return os << "}";
}
std::ostream& operator<<(std::ostream& os, AsyncIOOp::State state) {
return os << asyncIoOpStateToString(state);
}
} // namespace folly
......@@ -24,6 +24,7 @@
#include <cstdint>
#include <deque>
#include <functional>
#include <ostream>
#include <utility>
#include <vector>
......@@ -42,6 +43,7 @@ namespace folly {
*/
class AsyncIOOp : private boost::noncopyable {
friend class AsyncIO;
friend std::ostream& operator<<(std::ostream& stream, const AsyncIOOp& o);
public:
typedef std::function<void(AsyncIOOp*)> NotificationCallback;
......@@ -51,7 +53,7 @@ class AsyncIOOp : private boost::noncopyable {
// There would be a cancel() method here if Linux AIO actually implemented
// it. But let's not get your hopes up.
enum State {
enum class State {
UNINITIALIZED,
INITIALIZED,
PENDING,
......@@ -108,6 +110,9 @@ class AsyncIOOp : private boost::noncopyable {
ssize_t result_;
};
std::ostream& operator<<(std::ostream& stream, const AsyncIOOp& o);
std::ostream& operator<<(std::ostream& stream, AsyncIOOp::State state);
/**
* C++ interface around Linux Async IO.
*/
......
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