]>
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 | |
3 | ||
4 | #pragma once | |
5 | ||
6 | #include <iterator> | |
7 | #include <map> | |
8 | #include <set> | |
9 | ||
10 | #include <seastar/core/shared_ptr.hh> | |
11 | ||
12 | #include "crimson/net/Connection.h" | |
13 | #include "crimson/osd/object_context.h" | |
20effc67 | 14 | #include "crimson/osd/pg.h" |
9f95a23c TL |
15 | #include "include/denc.h" |
16 | ||
17 | namespace crimson::osd { | |
18 | ||
19 | class Notify; | |
20 | using NotifyRef = seastar::shared_ptr<Notify>; | |
21 | ||
22 | // NOTE: really need to have this public. Otherwise `shared_from_this()` | |
23 | // will abort. According to cppreference.com: | |
24 | // | |
25 | // "The constructors of std::shared_ptr detect the presence | |
26 | // of an unambiguous and accessible (ie. public inheritance | |
27 | // is mandatory) (since C++17) enable_shared_from_this base". | |
28 | // | |
29 | // I expect the `seastar::shared_ptr` shares this behaviour. | |
30 | class Watch : public seastar::enable_shared_from_this<Watch> { | |
31 | // this is a private tag for the public constructor that turns it into | |
32 | // de facto private one. The motivation behind the hack is make_shared | |
33 | // used by create(). | |
34 | struct private_ctag_t{}; | |
35 | ||
20effc67 | 36 | std::set<NotifyRef, std::less<>> in_progress_notifies; |
9f95a23c TL |
37 | crimson::net::ConnectionRef conn; |
38 | crimson::osd::ObjectContextRef obc; | |
39 | ||
40 | watch_info_t winfo; | |
41 | entity_name_t entity_name; | |
1e59de90 | 42 | Ref<PG> pg; |
9f95a23c | 43 | |
20effc67 TL |
44 | seastar::timer<seastar::lowres_clock> timeout_timer; |
45 | ||
9f95a23c TL |
46 | seastar::future<> start_notify(NotifyRef); |
47 | seastar::future<> send_notify_msg(NotifyRef); | |
48 | seastar::future<> send_disconnect_msg(); | |
9f95a23c TL |
49 | |
50 | friend Notify; | |
20effc67 | 51 | friend class WatchTimeoutRequest; |
9f95a23c TL |
52 | |
53 | public: | |
54 | Watch(private_ctag_t, | |
55 | crimson::osd::ObjectContextRef obc, | |
56 | const watch_info_t& winfo, | |
20effc67 TL |
57 | const entity_name_t& entity_name, |
58 | Ref<PG> pg) | |
9f95a23c TL |
59 | : obc(std::move(obc)), |
60 | winfo(winfo), | |
20effc67 | 61 | entity_name(entity_name), |
1e59de90 TL |
62 | pg(std::move(pg)), |
63 | timeout_timer([this] { | |
64 | return do_watch_timeout(); | |
20effc67 | 65 | }) { |
1e59de90 | 66 | assert(this->pg); |
9f95a23c | 67 | } |
20effc67 | 68 | ~Watch(); |
9f95a23c TL |
69 | |
70 | seastar::future<> connect(crimson::net::ConnectionRef, bool); | |
1e59de90 | 71 | void disconnect(); |
9f95a23c TL |
72 | bool is_alive() const { |
73 | return true; | |
74 | } | |
75 | bool is_connected() const { | |
76 | return static_cast<bool>(conn); | |
77 | } | |
20effc67 | 78 | void got_ping(utime_t); |
9f95a23c | 79 | |
1e59de90 TL |
80 | void discard_state(); |
81 | ||
20effc67 | 82 | seastar::future<> remove(); |
9f95a23c TL |
83 | |
84 | /// Call when notify_ack received on notify_id | |
85 | seastar::future<> notify_ack( | |
86 | uint64_t notify_id, ///< [in] id of acked notify | |
87 | const ceph::bufferlist& reply_bl); ///< [in] notify reply buffer | |
88 | ||
89 | template <class... Args> | |
90 | static seastar::shared_ptr<Watch> create(Args&&... args) { | |
91 | return seastar::make_shared<Watch>(private_ctag_t{}, | |
92 | std::forward<Args>(args)...); | |
93 | }; | |
94 | ||
95 | uint64_t get_watcher_gid() const { | |
96 | return entity_name.num(); | |
97 | } | |
1e59de90 TL |
98 | auto get_pg() const { |
99 | return pg; | |
100 | } | |
101 | auto& get_entity() const { | |
102 | return entity_name; | |
103 | } | |
104 | auto& get_cookie() const { | |
9f95a23c TL |
105 | return winfo.cookie; |
106 | } | |
1e59de90 TL |
107 | auto& get_peer_addr() const { |
108 | return winfo.addr; | |
109 | } | |
20effc67 | 110 | void cancel_notify(const uint64_t notify_id); |
1e59de90 | 111 | void do_watch_timeout(); |
9f95a23c TL |
112 | }; |
113 | ||
114 | using WatchRef = seastar::shared_ptr<Watch>; | |
115 | ||
116 | struct notify_reply_t { | |
117 | uint64_t watcher_gid; | |
118 | uint64_t watcher_cookie; | |
119 | ceph::bufferlist bl; | |
120 | ||
121 | bool operator<(const notify_reply_t& rhs) const; | |
122 | DENC(notify_reply_t, v, p) { | |
20effc67 | 123 | // there is no versioning / preamble |
9f95a23c TL |
124 | denc(v.watcher_gid, p); |
125 | denc(v.watcher_cookie, p); | |
126 | denc(v.bl, p); | |
9f95a23c TL |
127 | } |
128 | }; | |
20effc67 | 129 | std::ostream &operator<<(std::ostream &out, const notify_reply_t &rhs); |
9f95a23c | 130 | |
20effc67 | 131 | class Notify : public seastar::enable_shared_from_this<Notify> { |
9f95a23c | 132 | std::set<WatchRef> watchers; |
20effc67 | 133 | const notify_info_t ninfo; |
9f95a23c | 134 | crimson::net::ConnectionRef conn; |
20effc67 TL |
135 | const uint64_t client_gid; |
136 | const uint64_t user_version; | |
137 | bool complete{false}; | |
138 | bool discarded{false}; | |
139 | seastar::timer<seastar::lowres_clock> timeout_timer{ | |
140 | [this] { do_notify_timeout(); } | |
141 | }; | |
9f95a23c TL |
142 | |
143 | /// (gid,cookie) -> reply_bl for everyone who acked the notify | |
144 | std::multiset<notify_reply_t> notify_replies; | |
145 | ||
146 | uint64_t get_id() const { return ninfo.notify_id; } | |
9f95a23c | 147 | |
20effc67 TL |
148 | /// Sends notify completion if watchers.empty() or timeout |
149 | seastar::future<> send_completion( | |
150 | std::set<WatchRef> timedout_watchers = {}); | |
151 | ||
152 | /// Called on Notify timeout | |
153 | void do_notify_timeout(); | |
154 | ||
155 | Notify(crimson::net::ConnectionRef conn, | |
156 | const notify_info_t& ninfo, | |
157 | const uint64_t client_gid, | |
158 | const uint64_t user_version); | |
9f95a23c TL |
159 | template <class WatchIteratorT> |
160 | Notify(WatchIteratorT begin, | |
161 | WatchIteratorT end, | |
162 | crimson::net::ConnectionRef conn, | |
163 | const notify_info_t& ninfo, | |
164 | const uint64_t client_gid, | |
165 | const uint64_t user_version); | |
166 | // this is a private tag for the public constructor that turns it into | |
167 | // de facto private one. The motivation behind the hack is make_shared | |
168 | // used by create_n_propagate factory. | |
169 | struct private_ctag_t{}; | |
170 | ||
20effc67 TL |
171 | using ptr_t = seastar::shared_ptr<Notify>; |
172 | friend bool operator<(const ptr_t& lhs, const ptr_t& rhs) { | |
173 | assert(lhs); | |
174 | assert(rhs); | |
175 | return lhs->get_id() < rhs->get_id(); | |
176 | } | |
177 | friend bool operator<(const ptr_t& ptr, const uint64_t id) { | |
178 | assert(ptr); | |
179 | return ptr->get_id() < id; | |
180 | } | |
181 | friend bool operator<(const uint64_t id, const ptr_t& ptr) { | |
182 | assert(ptr); | |
183 | return id < ptr->get_id(); | |
184 | } | |
185 | ||
9f95a23c TL |
186 | friend Watch; |
187 | ||
188 | public: | |
189 | template <class... Args> | |
190 | Notify(private_ctag_t, Args&&... args) : Notify(std::forward<Args>(args)...) { | |
191 | } | |
192 | ||
193 | template <class WatchIteratorT, class... Args> | |
194 | static seastar::future<> create_n_propagate( | |
195 | WatchIteratorT begin, | |
196 | WatchIteratorT end, | |
197 | Args&&... args); | |
198 | ||
199 | seastar::future<> remove_watcher(WatchRef watch); | |
200 | seastar::future<> complete_watcher(WatchRef watch, | |
201 | const ceph::bufferlist& reply_bl); | |
202 | }; | |
203 | ||
204 | ||
205 | template <class WatchIteratorT> | |
206 | Notify::Notify(WatchIteratorT begin, | |
207 | WatchIteratorT end, | |
208 | crimson::net::ConnectionRef conn, | |
209 | const notify_info_t& ninfo, | |
210 | const uint64_t client_gid, | |
211 | const uint64_t user_version) | |
212 | : watchers(begin, end), | |
213 | ninfo(ninfo), | |
214 | conn(std::move(conn)), | |
215 | client_gid(client_gid), | |
216 | user_version(user_version) { | |
20effc67 TL |
217 | assert(!std::empty(watchers)); |
218 | if (ninfo.timeout) { | |
219 | timeout_timer.arm(std::chrono::seconds{ninfo.timeout}); | |
220 | } | |
9f95a23c TL |
221 | } |
222 | ||
223 | template <class WatchIteratorT, class... Args> | |
224 | seastar::future<> Notify::create_n_propagate( | |
225 | WatchIteratorT begin, | |
226 | WatchIteratorT end, | |
227 | Args&&... args) | |
228 | { | |
229 | static_assert( | |
230 | std::is_same_v<typename std::iterator_traits<WatchIteratorT>::value_type, | |
231 | crimson::osd::WatchRef>); | |
20effc67 TL |
232 | if (begin == end) { |
233 | auto notify = seastar::make_shared<Notify>( | |
234 | private_ctag_t{}, | |
235 | std::forward<Args>(args)...); | |
236 | return notify->send_completion(); | |
237 | } else { | |
238 | auto notify = seastar::make_shared<Notify>( | |
239 | private_ctag_t{}, | |
240 | begin, end, | |
241 | std::forward<Args>(args)...); | |
242 | return seastar::do_for_each(begin, end, [=] (auto& watchref) { | |
243 | return watchref->start_notify(notify); | |
244 | }); | |
245 | } | |
9f95a23c TL |
246 | } |
247 | ||
248 | } // namespace crimson::osd | |
249 | ||
250 | WRITE_CLASS_DENC(crimson::osd::notify_reply_t) | |
1e59de90 TL |
251 | |
252 | #if FMT_VERSION >= 90000 | |
253 | template <> struct fmt::formatter<crimson::osd::notify_reply_t> : fmt::ostream_formatter {}; | |
254 | #endif |