1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
5 * Ceph - scalable distributed file system
7 * Copyright (C) 2018 Red Hat, Inc.
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
16 #include <type_traits>
17 #include "include/rados/librados.hpp"
18 #include "librados/librados_asio.h"
26 void cb(librados::completion_t
, void* arg
);
30 librados::AioCompletion
* c
;
32 state(Aio
* aio
, AioResult
& r
)
34 c(librados::Rados::aio_create_completion(&r
, &cb
)) {}
37 void cb(librados::completion_t
, void* arg
) {
38 static_assert(sizeof(AioResult::user_data
) >= sizeof(state
));
39 static_assert(std::is_trivially_destructible_v
<state
>);
40 auto& r
= *(static_cast<AioResult
*>(arg
));
41 auto s
= reinterpret_cast<state
*>(&r
.user_data
);
42 r
.result
= s
->c
->get_return_value();
47 template <typename Op
>
48 Aio::OpFunc
aio_abstract(Op
&& op
) {
49 return [op
= std::move(op
)] (Aio
* aio
, AioResult
& r
) mutable {
50 constexpr bool read
= std::is_same_v
<std::decay_t
<Op
>, librados::ObjectReadOperation
>;
51 auto s
= new (&r
.user_data
) state(aio
, r
);
53 r
.result
= r
.obj
.aio_operate(s
->c
, &op
, &r
.data
);
55 r
.result
= r
.obj
.aio_operate(s
->c
, &op
);
64 #ifdef HAVE_BOOST_CONTEXT
66 Aio
* throttle
= nullptr;
69 void operator()(boost::system::error_code ec
) const {
70 r
.result
= -ec
.value();
74 void operator()(boost::system::error_code ec
, bufferlist bl
) const {
75 r
.result
= -ec
.value();
76 r
.data
= std::move(bl
);
81 template <typename Op
>
82 Aio::OpFunc
aio_abstract(Op
&& op
, boost::asio::io_context
& context
,
83 spawn::yield_context yield
) {
84 return [op
= std::move(op
), &context
, yield
] (Aio
* aio
, AioResult
& r
) mutable {
85 // arrange for the completion Handler to run on the yield_context's strand
86 // executor so it can safely call back into Aio without locking
87 using namespace boost::asio
;
88 async_completion
<spawn::yield_context
, void()> init(yield
);
89 auto ex
= get_associated_executor(init
.completion_handler
);
91 auto& ref
= r
.obj
.get_ref();
92 librados::async_operate(context
, ref
.pool
.ioctx(), ref
.obj
.oid
, &op
, 0,
93 bind_executor(ex
, Handler
{aio
, r
}));
96 #endif // HAVE_BOOST_CONTEXT
98 template <typename Op
>
99 Aio::OpFunc
aio_abstract(Op
&& op
, optional_yield y
) {
100 static_assert(std::is_base_of_v
<librados::ObjectOperation
, std::decay_t
<Op
>>);
101 static_assert(!std::is_lvalue_reference_v
<Op
>);
102 static_assert(!std::is_const_v
<Op
>);
103 #ifdef HAVE_BOOST_CONTEXT
105 return aio_abstract(std::forward
<Op
>(op
), y
.get_io_context(),
106 y
.get_yield_context());
109 return aio_abstract(std::forward
<Op
>(op
));
112 } // anonymous namespace
114 Aio::OpFunc
Aio::librados_op(librados::ObjectReadOperation
&& op
,
116 return aio_abstract(std::move(op
), y
);
118 Aio::OpFunc
Aio::librados_op(librados::ObjectWriteOperation
&& op
,
120 return aio_abstract(std::move(op
), y
);