]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librados/asio: take ref arguments as cref from async_initiate()
authorCasey Bodley <cbodley@redhat.com>
Fri, 25 Oct 2024 14:16:49 +0000 (10:16 -0400)
committerCasey Bodley <cbodley@redhat.com>
Thu, 9 Jan 2025 16:36:47 +0000 (11:36 -0500)
when called with 'use_awaitable' for c++20 coroutines, these functions
fail to compile because async_initiate() tries to pass the IoCtx
argument by rvalue reference, but our lambda expects lvalue reference:

> src/librados/librados_asio.h:196:7: note:   template argument deduction/substitution failed:
> boost/asio/impl/use_awaitable.hpp:276:26: note:   cannot convert ‘std::move<librados::v14_2_0::IoCtx&>((* & args#1))’ (type ‘std::remove_reference<librados::v14_2_0::IoCtx&>::type’ {aka ‘librados::v14_2_0::IoCtx’}) to type ‘librados::v14_2_0::IoCtx&’
>  276 |     std::move(initiation)(std::move(handler), std::move(args)...);
>      |     ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

async_initiate() for 'deferred' shows the same issue:

> src/librados/librados_asio.h:196:7: note:   template argument deduction/substitution failed:
> boost/asio/async_result.hpp:322:9: note:   cannot convert ‘args#1’ (type ‘const librados::v14_2_0::IoCtx’) to type ‘librados::v14_2_0::IoCtx&’
>  322 |         static_cast<Args&&>(args)...);
>      |         ^~~~~~~~~~~~~~~~~~~~~~~~~

in both cases, async_initiate() has to copy the arguments for
deferred/lazy initiation, then move them into our lambda when invoked

because our lambdas take mutable references, they won't accept these
rvalue references. taking them as const references instead allows the
caller to pass either lvalue- or rvalue references

this requires internal const_casts to convert them back to mutable
references. while casting away const risks undefined behavior, these
casts are safe because:
- in the deferred/lazy case, the arguments were decay-copied (const
  removed) into temporary storage
- in the normal case, the initial arguments were passed as mutable refs

Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/librados/librados_asio.h

index 4484859b3c0510a89047b6ef712183ca02c0e6f8..7d767603b63849244173095e56a36bd8bcb8da52 100644 (file)
@@ -159,12 +159,13 @@ auto async_read(IoExecutor ex, IoCtx& io, const std::string& oid,
   using Op = detail::AsyncOp<bufferlist>;
   using Signature = typename Op::Signature;
   return boost::asio::async_initiate<CompletionToken, Signature>(
-      [] (auto handler, IoExecutor ex, IoCtx& io, const std::string& oid,
-          size_t len, uint64_t off) {
+      [] (auto handler, IoExecutor ex, const IoCtx& i,
+          const std::string& oid, size_t len, uint64_t off) {
         constexpr bool is_read = true;
         auto p = Op::create(ex, is_read, std::move(handler));
         auto& op = p->user_data;
 
+        IoCtx& io = const_cast<IoCtx&>(i);
         int ret = io.aio_read(oid, op.aio_completion.get(), &op.result, len, off);
         if (ret < 0) {
           auto ec = boost::system::error_code{-ret, librados::detail::err_category()};
@@ -188,12 +189,13 @@ auto async_write(IoExecutor ex, IoCtx& io, const std::string& oid,
   using Op = detail::AsyncOp<void>;
   using Signature = typename Op::Signature;
   return boost::asio::async_initiate<CompletionToken, Signature>(
-      [] (auto handler, IoExecutor ex, IoCtx& io, const std::string& oid,
+      [] (auto handler, IoExecutor ex, const IoCtx& i, const std::string& oid,
           const bufferlist &bl, size_t len, uint64_t off) {
         constexpr bool is_read = false;
         auto p = Op::create(ex, is_read, std::move(handler));
         auto& op = p->user_data;
 
+        IoCtx& io = const_cast<IoCtx&>(i);
         int ret = io.aio_write(oid, op.aio_completion.get(), bl, len, off);
         if (ret < 0) {
           auto ec = boost::system::error_code{-ret, librados::detail::err_category()};
@@ -217,12 +219,13 @@ auto async_operate(IoExecutor ex, IoCtx& io, const std::string& oid,
   using Op = detail::AsyncOp<bufferlist>;
   using Signature = typename Op::Signature;
   return boost::asio::async_initiate<CompletionToken, Signature>(
-      [] (auto handler, IoExecutor ex, IoCtx& io, const std::string& oid,
+      [] (auto handler, IoExecutor ex, const IoCtx& i, const std::string& oid,
           ObjectReadOperation *read_op, int flags) {
         constexpr bool is_read = true;
         auto p = Op::create(ex, is_read, std::move(handler));
         auto& op = p->user_data;
 
+        IoCtx& io = const_cast<IoCtx&>(i);
         int ret = io.aio_operate(oid, op.aio_completion.get(), read_op,
                                  flags, &op.result);
         if (ret < 0) {
@@ -247,13 +250,14 @@ auto async_operate(IoExecutor ex, IoCtx& io, const std::string& oid,
   using Op = detail::AsyncOp<void>;
   using Signature = typename Op::Signature;
   return boost::asio::async_initiate<CompletionToken, Signature>(
-      [] (auto handler, IoExecutor ex, IoCtx& io, const std::string& oid,
+      [] (auto handler, IoExecutor ex, const IoCtx& i, const std::string& oid,
           ObjectWriteOperation *write_op, int flags,
           const jspan_context* trace_ctx) {
         constexpr bool is_read = false;
         auto p = Op::create(ex, is_read, std::move(handler));
         auto& op = p->user_data;
 
+        IoCtx& io = const_cast<IoCtx&>(i);
         int ret = io.aio_operate(oid, op.aio_completion.get(), write_op, flags, trace_ctx);
         if (ret < 0) {
           auto ec = boost::system::error_code{-ret, librados::detail::err_category()};
@@ -276,12 +280,14 @@ auto async_notify(IoExecutor ex, IoCtx& io, const std::string& oid,
   using Op = detail::AsyncOp<bufferlist>;
   using Signature = typename Op::Signature;
   return boost::asio::async_initiate<CompletionToken, Signature>(
-      [] (auto handler, IoExecutor ex, IoCtx& io, const std::string& oid,
-          bufferlist& bl, uint64_t timeout_ms) {
+      [] (auto handler, IoExecutor ex, const IoCtx& i, const std::string& oid,
+          const bufferlist& b, uint64_t timeout_ms) {
         constexpr bool is_read = false;
         auto p = Op::create(ex, is_read, std::move(handler));
         auto& op = p->user_data;
 
+        IoCtx& io = const_cast<IoCtx&>(i);
+        bufferlist& bl = const_cast<bufferlist&>(b);
         int ret = io.aio_notify(oid, op.aio_completion.get(),
                                 bl, timeout_ms, &op.result);
         if (ret < 0) {