1414#ifndef LIBRADOS_ASIO_H
1515#define LIBRADOS_ASIO_H
1616
17+ #include < boost/asio/associated_cancellation_slot.hpp>
18+ #include < boost/asio/cancellation_type.hpp>
19+
1720#include " include/rados/librados.hpp"
1821#include " common/async/completion.h"
1922#include " librados/AioCompletionImpl.h"
@@ -74,6 +77,7 @@ struct Invoker<void> {
7477template <typename Result>
7578struct AsyncOp : Invoker<Result> {
7679 unique_aio_completion_ptr aio_completion;
80+ boost::asio::cancellation_slot slot;
7781
7882 using Signature = typename Invoker<Result>::Signature;
7983 using Completion = ceph::async::Completion<Signature, AsyncOp<Result>>;
@@ -83,6 +87,7 @@ struct AsyncOp : Invoker<Result> {
8387 auto p = std::unique_ptr<Completion>{static_cast <Completion*>(arg)};
8488 // move result out of Completion memory being freed
8589 auto op = std::move (p->user_data );
90+ op.slot .clear (); // clear our cancellation handler
8691 // access AioCompletionImpl directly to avoid locking
8792 const librados::AioCompletionImpl* pc = op.aio_completion ->pc ;
8893 const int ret = pc->rval ;
@@ -94,11 +99,46 @@ struct AsyncOp : Invoker<Result> {
9499 op.dispatch (std::move (p), ec, ver);
95100 }
96101
102+ struct op_cancellation {
103+ AioCompletion* completion = nullptr ;
104+ bool is_read = false ;
105+
106+ void operator ()(boost::asio::cancellation_type type) {
107+ if (completion == nullptr ) {
108+ return ; // no AioCompletion attached
109+ } else if (type == boost::asio::cancellation_type::none) {
110+ return ; // no cancellation requested
111+ } else if (is_read) {
112+ // read operations produce no side effects, so can satisfy the
113+ // requirements of 'total' cancellation. the weaker requirements
114+ // of 'partial' and 'terminal' are also satisfied
115+ completion->cancel ();
116+ } else if (type == boost::asio::cancellation_type::terminal) {
117+ // write operations only support 'terminal' cancellation because we
118+ // can't guarantee that no osd has succeeded (or will succeed) in
119+ // applying the write
120+ completion->cancel ();
121+ }
122+ }
123+ };
124+
97125 template <typename Executor1, typename CompletionHandler>
98- static auto create (const Executor1& ex1, CompletionHandler&& handler) {
126+ static auto create (const Executor1& ex1, bool is_read,
127+ CompletionHandler&& handler) {
128+ op_cancellation* cancel_handler = nullptr ;
129+ auto slot = boost::asio::get_associated_cancellation_slot (handler);
130+ if (slot.is_connected ()) {
131+ cancel_handler = &slot.template emplace <op_cancellation>();
132+ }
133+
99134 auto p = Completion::create (ex1, std::move (handler));
100135 p->user_data .aio_completion .reset (
101136 Rados::aio_create_completion (p.get (), aio_dispatch));
137+ if (cancel_handler) {
138+ cancel_handler->completion = p->user_data .aio_completion .get ();
139+ cancel_handler->is_read = is_read;
140+ p->user_data .slot = std::move (slot);
141+ }
102142 return p;
103143 }
104144};
@@ -117,7 +157,8 @@ auto async_read(ExecutionContext& ctx, IoCtx& io, const std::string& oid,
117157 return boost::asio::async_initiate<CompletionToken, Signature>(
118158 [] (auto handler, auto ex, IoCtx& io, const std::string& oid,
119159 size_t len, uint64_t off) {
120- auto p = Op::create (ex, std::move (handler));
160+ constexpr bool is_read = true ;
161+ auto p = Op::create (ex, is_read, std::move (handler));
121162 auto & op = p->user_data ;
122163
123164 int ret = io.aio_read (oid, op.aio_completion .get (), &op.result , len, off);
@@ -142,7 +183,8 @@ auto async_write(ExecutionContext& ctx, IoCtx& io, const std::string& oid,
142183 return boost::asio::async_initiate<CompletionToken, Signature>(
143184 [] (auto handler, auto ex, IoCtx& io, const std::string& oid,
144185 const bufferlist &bl, size_t len, uint64_t off) {
145- auto p = Op::create (ex, std::move (handler));
186+ constexpr bool is_read = false ;
187+ auto p = Op::create (ex, is_read, std::move (handler));
146188 auto & op = p->user_data ;
147189
148190 int ret = io.aio_write (oid, op.aio_completion .get (), bl, len, off);
@@ -167,7 +209,8 @@ auto async_operate(ExecutionContext& ctx, IoCtx& io, const std::string& oid,
167209 return boost::asio::async_initiate<CompletionToken, Signature>(
168210 [] (auto handler, auto ex, IoCtx& io, const std::string& oid,
169211 ObjectReadOperation *read_op, int flags) {
170- auto p = Op::create (ex, std::move (handler));
212+ constexpr bool is_read = true ;
213+ auto p = Op::create (ex, is_read, std::move (handler));
171214 auto & op = p->user_data ;
172215
173216 int ret = io.aio_operate (oid, op.aio_completion .get (), read_op,
@@ -194,7 +237,8 @@ auto async_operate(ExecutionContext& ctx, IoCtx& io, const std::string& oid,
194237 [] (auto handler, auto ex, IoCtx& io, const std::string& oid,
195238 ObjectWriteOperation *write_op, int flags,
196239 const jspan_context* trace_ctx) {
197- auto p = Op::create (ex, std::move (handler));
240+ constexpr bool is_read = false ;
241+ auto p = Op::create (ex, is_read, std::move (handler));
198242 auto & op = p->user_data ;
199243
200244 int ret = io.aio_operate (oid, op.aio_completion .get (), write_op, flags, trace_ctx);
@@ -218,7 +262,8 @@ auto async_notify(ExecutionContext& ctx, IoCtx& io, const std::string& oid,
218262 return boost::asio::async_initiate<CompletionToken, Signature>(
219263 [] (auto handler, auto ex, IoCtx& io, const std::string& oid,
220264 bufferlist& bl, uint64_t timeout_ms) {
221- auto p = Op::create (ex, std::move (handler));
265+ constexpr bool is_read = false ;
266+ auto p = Op::create (ex, is_read, std::move (handler));
222267 auto & op = p->user_data ;
223268
224269 int ret = io.aio_notify (oid, op.aio_completion .get (),
0 commit comments