]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
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" | |
20effc67 | 21 | #include "rgw_d3n_cacherequest.h" |
9f95a23c TL |
22 | |
23 | namespace rgw { | |
24 | ||
25 | namespace { | |
26 | ||
27 | void cb(librados::completion_t, void* arg); | |
28 | ||
29 | struct state { | |
30 | Aio* aio; | |
31 | librados::AioCompletion* c; | |
32 | ||
33 | state(Aio* aio, AioResult& r) | |
34 | : aio(aio), | |
35 | c(librados::Rados::aio_create_completion(&r, &cb)) {} | |
36 | }; | |
37 | ||
38 | void cb(librados::completion_t, void* arg) { | |
39 | static_assert(sizeof(AioResult::user_data) >= sizeof(state)); | |
40 | static_assert(std::is_trivially_destructible_v<state>); | |
41 | auto& r = *(static_cast<AioResult*>(arg)); | |
42 | auto s = reinterpret_cast<state*>(&r.user_data); | |
43 | r.result = s->c->get_return_value(); | |
44 | s->c->release(); | |
45 | s->aio->put(r); | |
46 | } | |
47 | ||
48 | template <typename Op> | |
49 | Aio::OpFunc aio_abstract(Op&& op) { | |
50 | return [op = std::move(op)] (Aio* aio, AioResult& r) mutable { | |
51 | constexpr bool read = std::is_same_v<std::decay_t<Op>, librados::ObjectReadOperation>; | |
52 | auto s = new (&r.user_data) state(aio, r); | |
53 | if constexpr (read) { | |
54 | r.result = r.obj.aio_operate(s->c, &op, &r.data); | |
55 | } else { | |
56 | r.result = r.obj.aio_operate(s->c, &op); | |
57 | } | |
58 | if (r.result < 0) { | |
59 | s->c->release(); | |
60 | aio->put(r); | |
61 | } | |
62 | }; | |
63 | } | |
64 | ||
9f95a23c TL |
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, | |
20effc67 | 83 | yield_context yield) { |
9f95a23c TL |
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; | |
20effc67 | 88 | async_completion<yield_context, void()> init(yield); |
9f95a23c TL |
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 | } | |
9f95a23c | 96 | |
20effc67 TL |
97 | |
98 | Aio::OpFunc d3n_cache_aio_abstract(const DoutPrefixProvider *dpp, optional_yield y, off_t read_ofs, off_t read_len, std::string& location) { | |
99 | return [dpp, y, read_ofs, read_len, location] (Aio* aio, AioResult& r) mutable { | |
100 | // d3n data cache requires yield context (rgw_beast_enable_async=true) | |
101 | ceph_assert(y); | |
102 | auto& ref = r.obj.get_ref(); | |
103 | auto c = std::make_unique<D3nL1CacheRequest>(); | |
104 | lsubdout(g_ceph_context, rgw_datacache, 20) << "D3nDataCache: d3n_cache_aio_abstract(): libaio Read From Cache, oid=" << ref.obj.oid << dendl; | |
105 | c->file_aio_read_abstract(dpp, y.get_io_context(), y.get_yield_context(), location, read_ofs, read_len, aio, r); | |
106 | }; | |
107 | } | |
108 | ||
109 | ||
9f95a23c TL |
110 | template <typename Op> |
111 | Aio::OpFunc aio_abstract(Op&& op, optional_yield y) { | |
112 | static_assert(std::is_base_of_v<librados::ObjectOperation, std::decay_t<Op>>); | |
113 | static_assert(!std::is_lvalue_reference_v<Op>); | |
114 | static_assert(!std::is_const_v<Op>); | |
9f95a23c TL |
115 | if (y) { |
116 | return aio_abstract(std::forward<Op>(op), y.get_io_context(), | |
117 | y.get_yield_context()); | |
118 | } | |
9f95a23c TL |
119 | return aio_abstract(std::forward<Op>(op)); |
120 | } | |
121 | ||
122 | } // anonymous namespace | |
123 | ||
124 | Aio::OpFunc Aio::librados_op(librados::ObjectReadOperation&& op, | |
125 | optional_yield y) { | |
126 | return aio_abstract(std::move(op), y); | |
127 | } | |
128 | Aio::OpFunc Aio::librados_op(librados::ObjectWriteOperation&& op, | |
129 | optional_yield y) { | |
130 | return aio_abstract(std::move(op), y); | |
131 | } | |
132 | ||
20effc67 TL |
133 | Aio::OpFunc Aio::d3n_cache_op(const DoutPrefixProvider *dpp, optional_yield y, |
134 | off_t read_ofs, off_t read_len, std::string& location) { | |
135 | return d3n_cache_aio_abstract(dpp, y, read_ofs, read_len, location); | |
136 | } | |
137 | ||
9f95a23c | 138 | } // namespace rgw |