1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
10 #include <seastar/core/shared_ptr.hh>
12 #include "crimson/net/Connection.h"
13 #include "crimson/osd/object_context.h"
14 #include "crimson/osd/pg.h"
15 #include "include/denc.h"
17 namespace crimson::osd
{
20 using NotifyRef
= seastar::shared_ptr
<Notify
>;
22 // NOTE: really need to have this public. Otherwise `shared_from_this()`
23 // will abort. According to cppreference.com:
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".
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
34 struct private_ctag_t
{};
36 std::set
<NotifyRef
, std::less
<>> in_progress_notifies
;
37 crimson::net::ConnectionRef conn
;
38 crimson::osd::ObjectContextRef obc
;
41 entity_name_t entity_name
;
44 seastar::timer
<seastar::lowres_clock
> timeout_timer
;
46 seastar::future
<> start_notify(NotifyRef
);
47 seastar::future
<> send_notify_msg(NotifyRef
);
48 seastar::future
<> send_disconnect_msg();
51 friend class WatchTimeoutRequest
;
55 crimson::osd::ObjectContextRef obc
,
56 const watch_info_t
& winfo
,
57 const entity_name_t
& entity_name
,
59 : obc(std::move(obc
)),
61 entity_name(entity_name
),
63 timeout_timer([this] {
64 return do_watch_timeout();
70 seastar::future
<> connect(crimson::net::ConnectionRef
, bool);
72 bool is_alive() const {
75 bool is_connected() const {
76 return static_cast<bool>(conn
);
78 void got_ping(utime_t
);
82 seastar::future
<> remove();
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
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
)...);
95 uint64_t get_watcher_gid() const {
96 return entity_name
.num();
101 auto& get_entity() const {
104 auto& get_cookie() const {
107 auto& get_peer_addr() const {
110 void cancel_notify(const uint64_t notify_id
);
111 void do_watch_timeout();
114 using WatchRef
= seastar::shared_ptr
<Watch
>;
116 struct notify_reply_t
{
117 uint64_t watcher_gid
;
118 uint64_t watcher_cookie
;
121 bool operator<(const notify_reply_t
& rhs
) const;
122 DENC(notify_reply_t
, v
, p
) {
123 // there is no versioning / preamble
124 denc(v
.watcher_gid
, p
);
125 denc(v
.watcher_cookie
, p
);
129 std::ostream
&operator<<(std::ostream
&out
, const notify_reply_t
&rhs
);
131 class Notify
: public seastar::enable_shared_from_this
<Notify
> {
132 std::set
<WatchRef
> watchers
;
133 const notify_info_t ninfo
;
134 crimson::net::ConnectionRef conn
;
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(); }
143 /// (gid,cookie) -> reply_bl for everyone who acked the notify
144 std::multiset
<notify_reply_t
> notify_replies
;
146 uint64_t get_id() const { return ninfo
.notify_id
; }
148 /// Sends notify completion if watchers.empty() or timeout
149 seastar::future
<> send_completion(
150 std::set
<WatchRef
> timedout_watchers
= {});
152 /// Called on Notify timeout
153 void do_notify_timeout();
155 Notify(crimson::net::ConnectionRef conn
,
156 const notify_info_t
& ninfo
,
157 const uint64_t client_gid
,
158 const uint64_t user_version
);
159 template <class WatchIteratorT
>
160 Notify(WatchIteratorT begin
,
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
{};
171 using ptr_t
= seastar::shared_ptr
<Notify
>;
172 friend bool operator<(const ptr_t
& lhs
, const ptr_t
& rhs
) {
175 return lhs
->get_id() < rhs
->get_id();
177 friend bool operator<(const ptr_t
& ptr
, const uint64_t id
) {
179 return ptr
->get_id() < id
;
181 friend bool operator<(const uint64_t id
, const ptr_t
& ptr
) {
183 return id
< ptr
->get_id();
189 template <class... Args
>
190 Notify(private_ctag_t
, Args
&&... args
) : Notify(std::forward
<Args
>(args
)...) {
193 template <class WatchIteratorT
, class... Args
>
194 static seastar::future
<> create_n_propagate(
195 WatchIteratorT begin
,
199 seastar::future
<> remove_watcher(WatchRef watch
);
200 seastar::future
<> complete_watcher(WatchRef watch
,
201 const ceph::bufferlist
& reply_bl
);
205 template <class WatchIteratorT
>
206 Notify::Notify(WatchIteratorT begin
,
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
),
214 conn(std::move(conn
)),
215 client_gid(client_gid
),
216 user_version(user_version
) {
217 assert(!std::empty(watchers
));
219 timeout_timer
.arm(std::chrono::seconds
{ninfo
.timeout
});
223 template <class WatchIteratorT
, class... Args
>
224 seastar::future
<> Notify::create_n_propagate(
225 WatchIteratorT begin
,
230 std::is_same_v
<typename
std::iterator_traits
<WatchIteratorT
>::value_type
,
231 crimson::osd::WatchRef
>);
233 auto notify
= seastar::make_shared
<Notify
>(
235 std::forward
<Args
>(args
)...);
236 return notify
->send_completion();
238 auto notify
= seastar::make_shared
<Notify
>(
241 std::forward
<Args
>(args
)...);
242 return seastar::do_for_each(begin
, end
, [=] (auto& watchref
) {
243 return watchref
->start_notify(notify
);
248 } // namespace crimson::osd
250 WRITE_CLASS_DENC(crimson::osd::notify_reply_t
)
252 #if FMT_VERSION >= 90000
253 template <> struct fmt::formatter
<crimson::osd::notify_reply_t
> : fmt::ostream_formatter
{};