*
*/
-#ifndef CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H
-#define CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H
+#pragma once
-#include <atomic>
-#include <condition_variable>
-#include <mutex>
-#include <optional>
-#include <type_traits>
+#include <exception>
#include <boost/asio/async_result.hpp>
#include <boost/system/system_error.hpp>
#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.
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();
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
return;
}
};
-}
-#endif // !CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H
+template<typename ReturnType>
+class async_result<librados::AioCompletion*,
+ ReturnType(std::exception_ptr)> {
+public:
+ using completion_handler_type = ceph::async::detail::librados_handler;
+ explicit async_result(completion_handler_type&) {};
+ using return_type = void;
+ void get() {
+ return;
+ }
+};
+
+template<typename ReturnType>
+class async_result<librados::AioCompletion*,
+ ReturnType(int)> {
+public:
+ using completion_handler_type = ceph::async::detail::librados_handler;
+ explicit async_result(completion_handler_type&) {};
+ using return_type = void;
+ void get() {
+ return;
+ }
+};
+}
--- /dev/null
+// -*- 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 <boost/system/detail/errc.hpp>
+#include <gtest/gtest.h>
+
+#include <boost/asio/awaitable.hpp>
+#include <boost/asio/co_spawn.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/strand.hpp>
+#include <boost/asio/use_awaitable.hpp>
+
+#include <boost/system/error_code.hpp>
+#include <boost/system/errc.hpp>
+#include <boost/system/system_error.hpp>
+
+#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<void> {
+ 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<void> {
+ 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<void> {
+ 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);
+}