]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_aio.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / rgw / rgw_aio.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 /*
5 * Ceph - scalable distributed file system
6 *
7 * Copyright (C) 2018 Red Hat, Inc.
8 *
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.
13 *
14 */
15
16 #include <type_traits>
17 #include "include/rados/librados.hpp"
18 #include "librados/librados_asio.h"
19
20 #include "rgw_aio.h"
21
22 namespace rgw {
23
24 namespace {
25
26 void cb(librados::completion_t, void* arg);
27
28 struct state {
29 Aio* aio;
30 librados::AioCompletion* c;
31
32 state(Aio* aio, AioResult& r)
33 : aio(aio),
34 c(librados::Rados::aio_create_completion(&r, &cb)) {}
35 };
36
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();
43 s->c->release();
44 s->aio->put(r);
45 }
46
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);
52 if constexpr (read) {
53 r.result = r.obj.aio_operate(s->c, &op, &r.data);
54 } else {
55 r.result = r.obj.aio_operate(s->c, &op);
56 }
57 if (r.result < 0) {
58 s->c->release();
59 aio->put(r);
60 }
61 };
62 }
63
64 #ifdef HAVE_BOOST_CONTEXT
65 struct Handler {
66 Aio* throttle = nullptr;
67 AioResult& r;
68 // write callback
69 void operator()(boost::system::error_code ec) const {
70 r.result = -ec.value();
71 throttle->put(r);
72 }
73 // read callback
74 void operator()(boost::system::error_code ec, bufferlist bl) const {
75 r.result = -ec.value();
76 r.data = std::move(bl);
77 throttle->put(r);
78 }
79 };
80
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);
90
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}));
94 };
95 }
96 #endif // HAVE_BOOST_CONTEXT
97
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
104 if (y) {
105 return aio_abstract(std::forward<Op>(op), y.get_io_context(),
106 y.get_yield_context());
107 }
108 #endif
109 return aio_abstract(std::forward<Op>(op));
110 }
111
112 } // anonymous namespace
113
114 Aio::OpFunc Aio::librados_op(librados::ObjectReadOperation&& op,
115 optional_yield y) {
116 return aio_abstract(std::move(op), y);
117 }
118 Aio::OpFunc Aio::librados_op(librados::ObjectWriteOperation&& op,
119 optional_yield y) {
120 return aio_abstract(std::move(op), y);
121 }
122
123 } // namespace rgw