Commit 91a0da83 authored by Dan Melnic's avatar Dan Melnic Committed by Facebook GitHub Bot

io_uring backend error handling

Summary: io_uring backend error handling

Reviewed By: kevin-vigor

Differential Revision: D20737416

fbshipit-source-id: 23eebc98326bcd07ee308e8f71f972c7374f6108
parent 67e4a2af
...@@ -207,7 +207,7 @@ void* IoUringBackend::allocSubmissionEntry() { ...@@ -207,7 +207,7 @@ void* IoUringBackend::allocSubmissionEntry() {
} }
int IoUringBackend::submitOne(IoCb* /*unused*/) { int IoUringBackend::submitOne(IoCb* /*unused*/) {
return submitBusyCheck(); return submitBusyCheck(1, WaitForEventsMode::DONT_WAIT);
} }
int IoUringBackend::cancelOne(IoCb* ioCb) { int IoUringBackend::cancelOne(IoCb* ioCb) {
...@@ -221,7 +221,7 @@ int IoUringBackend::cancelOne(IoCb* ioCb) { ...@@ -221,7 +221,7 @@ int IoUringBackend::cancelOne(IoCb* ioCb) {
rentry->prepPollRemove(sqe, ioCb); // prev entry rentry->prepPollRemove(sqe, ioCb); // prev entry
int ret = submitBusyCheck(); int ret = submitBusyCheck(1, WaitForEventsMode::DONT_WAIT);
if (ret < 0) { if (ret < 0) {
// release the sqe // release the sqe
...@@ -253,21 +253,33 @@ int IoUringBackend::getActiveEvents(WaitForEventsMode waitForEvents) { ...@@ -253,21 +253,33 @@ int IoUringBackend::getActiveEvents(WaitForEventsMode waitForEvents) {
return static_cast<int>(i); return static_cast<int>(i);
} }
int IoUringBackend::submitBusyCheck() { int IoUringBackend::submitBusyCheck(int num, WaitForEventsMode waitForEvents) {
int num; int i = 0;
while ((num = ::io_uring_submit(&ioRing_)) == -EBUSY) { int res;
// if we get EBUSY, try to consume some CQ entries while (i < num) {
getActiveEvents(WaitForEventsMode::DONT_WAIT); res = ::io_uring_submit(&ioRing_);
}; if (res == -EBUSY) {
return num; // if we get EBUSY, try to consume some CQ entries
} getActiveEvents(waitForEvents);
continue;
}
if (res < 0) {
// continue if interrupted
if (errno == EINTR) {
continue;
}
return res;
}
// we do not have any other entries to submit
if (res == 0) {
break;
}
i += res;
}
int IoUringBackend::submitBusyCheckAndWait() {
int num;
while ((num = ::io_uring_submit_and_wait(&ioRing_, 1)) == -EBUSY) {
// if we get EBUSY, try to consume some CQ entries
getActiveEvents(WaitForEventsMode::DONT_WAIT);
};
return num; return num;
} }
...@@ -291,14 +303,12 @@ size_t IoUringBackend::submitList( ...@@ -291,14 +303,12 @@ size_t IoUringBackend::submitList(
(ev->ev_events & EV_PERSIST) != 0); (ev->ev_events & EV_PERSIST) != 0);
i++; i++;
if (ioCbs.empty()) { if (ioCbs.empty()) {
int num = (waitForEvents == WaitForEventsMode::WAIT) int num = submitBusyCheck(i, waitForEvents);
? submitBusyCheckAndWait()
: submitBusyCheck();
CHECK_EQ(num, i); CHECK_EQ(num, i);
ret += i; ret += i;
} else { } else {
if (static_cast<size_t>(i) == maxSubmit_) { if (static_cast<size_t>(i) == maxSubmit_) {
int num = submitBusyCheck(); int num = submitBusyCheck(i, waitForEvents);
CHECK_EQ(num, i); CHECK_EQ(num, i);
ret += i; ret += i;
i = 0; i = 0;
......
...@@ -79,8 +79,7 @@ class IoUringBackend : public PollIoBackend { ...@@ -79,8 +79,7 @@ class IoUringBackend : public PollIoBackend {
int submitOne(IoCb* ioCb) override; int submitOne(IoCb* ioCb) override;
int cancelOne(IoCb* ioCb) override; int cancelOne(IoCb* ioCb) override;
int submitBusyCheck(); int submitBusyCheck(int num, WaitForEventsMode waitForEvents);
int submitBusyCheckAndWait();
struct IoSqe : public PollIoBackend::IoCb { struct IoSqe : public PollIoBackend::IoCb {
explicit IoSqe(PollIoBackend* backend = nullptr, bool poolAlloc = true) explicit IoSqe(PollIoBackend* backend = nullptr, bool poolAlloc = true)
......
...@@ -28,15 +28,16 @@ namespace { ...@@ -28,15 +28,16 @@ namespace {
class EventFD : public folly::EventHandler { class EventFD : public folly::EventHandler {
public: public:
EventFD( EventFD(
bool valid,
uint64_t num, uint64_t num,
uint64_t& total, uint64_t& total,
bool persist, bool persist,
folly::EventBase* eventBase) folly::EventBase* eventBase)
: EventFD(total, createFd(num), persist, eventBase) {} : EventFD(total, valid ? createFd(num) : -1, persist, eventBase) {}
~EventFD() override { ~EventFD() override {
unregisterHandler(); unregisterHandler();
if (fd_ > 0) { if (fd_ >= 0) {
::close(fd_); ::close(fd_);
fd_ = -1; fd_ = -1;
} }
...@@ -114,7 +115,7 @@ void testOverflow(bool overflow, bool persist) { ...@@ -114,7 +115,7 @@ void testOverflow(bool overflow, bool persist) {
eventsVec.reserve(kNumEventFds); eventsVec.reserve(kNumEventFds);
for (size_t i = 0; i < kNumEventFds; i++) { for (size_t i = 0; i < kNumEventFds; i++) {
eventsVec.emplace_back( eventsVec.emplace_back(
std::make_unique<EventFD>(kEventFdCount, total, persist, &evb)); std::make_unique<EventFD>(true, kEventFdCount, total, persist, &evb));
} }
evb.loopForever(); evb.loopForever();
...@@ -123,6 +124,40 @@ void testOverflow(bool overflow, bool persist) { ...@@ -123,6 +124,40 @@ void testOverflow(bool overflow, bool persist) {
CHECK_GE(eventsVec[i]->getNum(), kEventFdCount); CHECK_GE(eventsVec[i]->getNum(), kEventFdCount);
} }
} }
void testInvalidFd(size_t numTotal, size_t numValid, size_t numInvalid) {
static constexpr size_t kBackendCapacity = 128;
static constexpr size_t kBackendMaxSubmit = 64;
auto total = numTotal;
std::unique_ptr<folly::EventBaseBackendBase> backend;
try {
backend = std::make_unique<folly::IoUringBackend>(
kBackendCapacity, kBackendMaxSubmit);
} catch (const folly::IoUringBackend::NotAvailable&) {
}
SKIP_IF(!backend) << "Backend not available";
folly::EventBase evb(std::move(backend));
std::vector<std::unique_ptr<EventFD>> eventsVec;
eventsVec.reserve(numTotal);
for (size_t i = 0; i < numTotal; i++) {
bool valid = (i % (numValid + numInvalid)) < numValid;
eventsVec.emplace_back(
std::make_unique<EventFD>(valid, 1, total, false /*persist*/, &evb));
}
evb.loopForever();
for (size_t i = 0; i < numTotal; i++) {
CHECK_GE(eventsVec[i]->getNum(), 1);
}
}
} // namespace } // namespace
TEST(IoUringBackend, NoOverflowNoPersist) { TEST(IoUringBackend, NoOverflowNoPersist) {
...@@ -141,6 +176,21 @@ TEST(IoUringBackend, OverflowPersist) { ...@@ -141,6 +176,21 @@ TEST(IoUringBackend, OverflowPersist) {
testOverflow(true, true); testOverflow(true, true);
} }
// 9 valid fds followed by an invalid one
TEST(IoUringBackend, Invalid_fd_9_1) {
testInvalidFd(32, 10, 1);
}
// only invalid fds
TEST(IoUringBackend, Invalid_fd_0_10) {
testInvalidFd(32, 0, 10);
}
// equal distribution
TEST(IoUringBackend, Invalid_fd_5_5) {
testInvalidFd(32, 10, 10);
}
TEST(IoUringBackend, RegisteredFds) { TEST(IoUringBackend, RegisteredFds) {
static constexpr size_t kBackendCapacity = 64; static constexpr size_t kBackendCapacity = 64;
static constexpr size_t kBackendMaxSubmit = 32; static constexpr size_t kBackendMaxSubmit = 32;
......
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