]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common/async: Add handler for librados::AioCompletion
authorAdam C. Emerson <aemerson@redhat.com>
Tue, 5 May 2020 22:32:59 +0000 (18:32 -0400)
committerAdam C. Emerson <aemerson@redhat.com>
Wed, 9 Sep 2020 02:09:40 +0000 (22:09 -0400)
Support using a librados::AioCompletion as a completion handler in
Boost.Asio when the arguments are void or only an error code.

(To support more arguments we'd have to wrap up the AioCompletion with
pointers to hold them.)

Signed-off-by: Adam C. Emerson <aemerson@redhat.com>
src/common/async/librados_completion.h [new file with mode: 0644]

diff --git a/src/common/async/librados_completion.h b/src/common/async/librados_completion.h
new file mode 100644 (file)
index 0000000..2fa5555
--- /dev/null
@@ -0,0 +1,125 @@
+// -*- 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) 2020 Red Hat
+ * Author: Adam C. Emerson <aemerson@redhat.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H
+#define CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <optional>
+#include <type_traits>
+
+#include <boost/asio/async_result.hpp>
+
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+
+#include "include/rados/librados.hpp"
+#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.
+//
+// async_result::return_type is void.
+
+namespace ceph::async {
+
+namespace bs = boost::system;
+namespace lr = librados;
+
+namespace detail {
+
+struct librados_handler {
+  lr::AioCompletionImpl* pc;
+
+  explicit librados_handler(lr::AioCompletion* c) : pc(c->pc) {
+    pc->get();
+  }
+  ~librados_handler() {
+    if (pc) {
+      pc->put();
+      pc = nullptr;
+    }
+  }
+
+  librados_handler(const librados_handler&) = delete;
+  librados_handler& operator =(const librados_handler&) = delete;
+  librados_handler(librados_handler&& rhs) {
+    pc = rhs.pc;
+    rhs.pc = nullptr;
+  }
+
+  void operator()(bs::error_code ec) {
+    pc->lock.lock();
+    pc->rval = ceph::from_error_code(ec);
+    pc->complete = true;
+    pc->lock.unlock();
+
+    auto cb_complete = pc->callback_complete;
+    auto cb_complete_arg = pc->callback_complete_arg;
+    if (cb_complete)
+      cb_complete(pc, cb_complete_arg);
+
+    auto cb_safe = pc->callback_safe;
+    auto cb_safe_arg = pc->callback_safe_arg;
+    if (cb_safe)
+      cb_safe(pc, cb_safe_arg);
+
+    pc->lock.lock();
+    pc->callback_complete = NULL;
+    pc->callback_safe = NULL;
+    pc->cond.notify_all();
+    pc->put_unlock();
+    pc = nullptr;
+  }
+
+  void operator ()() {
+    (*this)(bs::error_code{});
+  }
+};
+} // namespace detail
+} // namespace ceph::async
+
+
+namespace boost::asio {
+template<typename ReturnType>
+class async_result<librados::AioCompletion*, ReturnType()> {
+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(boost::system::error_code)> {
+public:
+  using completion_handler_type = ceph::async::detail::librados_handler;
+  explicit async_result(completion_handler_type&) {};
+  using return_type = void;
+  void get() {
+    return;
+  }
+};
+}
+
+#endif // !CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H