From eca7c17e04d1e7ec798a4af571dfc4c3c8d445fe Mon Sep 17 00:00:00 2001 From: Adam Emerson Date: Tue, 14 May 2024 15:09:14 -0400 Subject: [PATCH] common/async: Use AioCompletion as a completion for coroutines I forgot I had this already. Just extend it so we can handle things like coroutines that return an `exception_ptr` rather than an `error_code`. Signed-off-by: Adam Emerson --- src/common/async/librados_completion.h | 57 +++++++--- src/test/common/CMakeLists.txt | 7 +- src/test/common/test_librados_completion.cc | 109 ++++++++++++++++++++ 3 files changed, 158 insertions(+), 15 deletions(-) create mode 100644 src/test/common/test_librados_completion.cc diff --git a/src/common/async/librados_completion.h b/src/common/async/librados_completion.h index 2fa5555e77475..7bb380895e80b 100644 --- a/src/common/async/librados_completion.h +++ b/src/common/async/librados_completion.h @@ -13,14 +13,9 @@ * */ -#ifndef CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H -#define CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H +#pragma once -#include -#include -#include -#include -#include +#include #include @@ -28,13 +23,17 @@ #include #include "include/rados/librados.hpp" + +#include "common/error_code.h" + #include "librados/AioCompletionImpl.h" // Allow librados::AioCompletion to be provided as a completion // handler. This is only allowed with a signature of -// (boost::system::error_code) or (). On completion the AioCompletion -// is completed with the error_code converted to an int with -// ceph::from_error_code. +// (int), (boost::system::error_code), (std::exception_ptr), or (). On +// completion the AioCompletion is completed with the error_code +// converted to an int with ceph::from_error_code. Exceptions we can't +// handle any other way are converted to -EIO. // // async_result::return_type is void. @@ -65,9 +64,9 @@ struct librados_handler { rhs.pc = nullptr; } - void operator()(bs::error_code ec) { + void operator()(int r) { pc->lock.lock(); - pc->rval = ceph::from_error_code(ec); + pc->rval = r; pc->complete = true; pc->lock.unlock(); @@ -89,9 +88,17 @@ struct librados_handler { pc = nullptr; } + void operator()(bs::error_code ec) { + (*this)(ceph::from_error_code(ec)); + } + void operator ()() { (*this)(bs::error_code{}); } + + void operator ()(std::exception_ptr e) { + (*this)(ceph::from_exception(e)); + } }; } // namespace detail } // namespace ceph::async @@ -120,6 +127,28 @@ public: return; } }; -} -#endif // !CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H +template +class async_result { +public: + using completion_handler_type = ceph::async::detail::librados_handler; + explicit async_result(completion_handler_type&) {}; + using return_type = void; + void get() { + return; + } +}; + +template +class async_result { +public: + using completion_handler_type = ceph::async::detail::librados_handler; + explicit async_result(completion_handler_type&) {}; + using return_type = void; + void get() { + return; + } +}; +} diff --git a/src/test/common/CMakeLists.txt b/src/test/common/CMakeLists.txt index 1402fa24fd3ff..590f66f55c196 100644 --- a/src/test/common/CMakeLists.txt +++ b/src/test/common/CMakeLists.txt @@ -484,6 +484,11 @@ set_tests_properties(unittest_decode_start_v_checker_expect_failure PROPERTIES WILL_FAIL TRUE) add_executable(unittest_async_call test_async_call.cc) -target_link_libraries(unittest_async_call librados ceph-common Boost::system +target_link_libraries(unittest_async_call ceph-common Boost::system GTest::GTest) add_ceph_unittest(unittest_async_call) + +add_executable(unittest_librados_completion test_librados_completion.cc) +target_link_libraries(unittest_librados_completion librados ceph-common + Boost::system GTest::GTest) +add_ceph_unittest(unittest_librados_completion) diff --git a/src/test/common/test_librados_completion.cc b/src/test/common/test_librados_completion.cc new file mode 100644 index 0000000000000..d87f7ea70911d --- /dev/null +++ b/src/test/common/test_librados_completion.cc @@ -0,0 +1,109 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2024 IBM + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/async/librados_completion.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "include/rados/librados.hpp" + +#include "common/async/async_call.h" + +namespace asio = boost::asio; +namespace sys = boost::system; +namespace async = ceph::async; + +TEST(CoroSucc, AioComplete) +{ + auto lrc = librados::Rados::aio_create_completion(); + asio::io_context c; + asio::co_spawn(c.get_executor(), + []() -> asio::awaitable { + co_return; + }(), lrc); + c.run(); + lrc->wait_for_complete(); + auto r = lrc->get_return_value(); + ASSERT_EQ(0, r); +} + +TEST(CoroExcept, AioComplete) +{ + auto lrc = librados::Rados::aio_create_completion(); + asio::io_context c; + asio::co_spawn(c.get_executor(), + []() -> asio::awaitable { + throw sys::system_error{ENOENT, sys::generic_category()}; + co_return; + }(), lrc); + c.run(); + lrc->wait_for_complete(); + auto r = lrc->get_return_value(); + ASSERT_EQ(-ENOENT, r); +} + +TEST(CoroUnknownExcept, AioComplete) +{ + auto lrc = librados::Rados::aio_create_completion(); + asio::io_context c; + asio::co_spawn(c.get_executor(), + []() -> asio::awaitable { + throw std::exception{}; + co_return; + }(), lrc); + c.run(); + lrc->wait_for_complete(); + auto r = lrc->get_return_value(); + ASSERT_EQ(-EIO, r); +} + +TEST(Int, AioComplete) +{ + auto lrc = librados::Rados::aio_create_completion(); + asio::io_context c; + async::async_dispatch(c.get_executor(), + []() { + return -42; + }, lrc); + c.run(); + lrc->wait_for_complete(); + auto r = lrc->get_return_value(); + ASSERT_EQ(-42, r); +} + +TEST(EC, AioComplete) +{ + auto lrc = librados::Rados::aio_create_completion(); + asio::io_context c; + async::async_dispatch(c.get_executor(), + []() { + return sys::error_code(ENOENT, + sys::generic_category()); + }, lrc); + c.run(); + lrc->wait_for_complete(); + auto r = lrc->get_return_value(); + ASSERT_EQ(-ENOENT, r); +} -- 2.39.5