]> git.proxmox.com Git - ceph.git/blame - ceph/src/crimson/osd/object_context.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / crimson / osd / object_context.h
CommitLineData
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 <map>
7#include <optional>
8#include <utility>
9#include <seastar/core/shared_future.hh>
10#include <seastar/core/shared_ptr.hh>
11
12#include "common/intrusive_lru.h"
13#include "osd/object_state.h"
f67539c2
TL
14#include "crimson/common/exception.h"
15#include "crimson/common/tri_mutex.h"
9f95a23c
TL
16#include "crimson/osd/osd_operation.h"
17
18namespace ceph {
19 class Formatter;
20}
21
22namespace crimson::common {
23 class ConfigProxy;
24}
25
26namespace crimson::osd {
27
28class Watch;
29
30template <typename OBC>
31struct obc_to_hoid {
32 using type = hobject_t;
33 const type &operator()(const OBC &obc) {
34 return obc.obs.oi.soid;
35 }
36};
37
f67539c2 38class ObjectContext : public ceph::common::intrusive_lru_base<
9f95a23c
TL
39 ceph::common::intrusive_lru_config<
40 hobject_t, ObjectContext, obc_to_hoid<ObjectContext>>>
41{
42public:
43 Ref head; // Ref defined as part of ceph::common::intrusive_lru_base
44 ObjectState obs;
45 std::optional<SnapSet> ss;
9f95a23c
TL
46 // the watch / notify machinery rather stays away from the hot and
47 // frequented paths. std::map is used mostly because of developer's
48 // convenience.
49 using watch_key_t = std::pair<uint64_t, entity_name_t>;
50 std::map<watch_key_t, seastar::shared_ptr<crimson::osd::Watch>> watchers;
51
20effc67 52 ObjectContext(hobject_t hoid) : obs(std::move(hoid)) {}
9f95a23c
TL
53
54 const hobject_t &get_oid() const {
55 return obs.oi.soid;
56 }
57
58 bool is_head() const {
59 return get_oid().is_head();
60 }
61
20effc67
TL
62 Ref get_head_obc() const {
63 return head;
64 }
65
66 hobject_t get_head_oid() const {
67 return get_oid().get_head();
68 }
69
9f95a23c
TL
70 const SnapSet &get_ro_ss() const {
71 if (is_head()) {
72 ceph_assert(ss);
73 return *ss;
74 } else {
75 ceph_assert(head);
76 return head->get_ro_ss();
77 }
78 }
79
80 void set_head_state(ObjectState &&_obs, SnapSet &&_ss) {
81 ceph_assert(is_head());
82 obs = std::move(_obs);
83 ss = std::move(_ss);
9f95a23c
TL
84 }
85
86 void set_clone_state(ObjectState &&_obs, Ref &&_head) {
87 ceph_assert(!is_head());
88 obs = std::move(_obs);
89 head = _head;
9f95a23c
TL
90 }
91
f67539c2
TL
92 /// pass the provided exception to any waiting consumers of this ObjectContext
93 template<typename Exception>
94 void interrupt(Exception ex) {
95 lock.abort(std::move(ex));
96 if (recovery_read_marker) {
97 drop_recovery_read();
98 }
99 }
100
9f95a23c 101private:
f67539c2
TL
102 tri_mutex lock;
103 bool recovery_read_marker = false;
104
105 template <typename Lock, typename Func>
106 auto _with_lock(Lock&& lock, Func&& func) {
107 Ref obc = this;
108 return lock.lock().then([&lock, func = std::forward<Func>(func), obc]() mutable {
109 return seastar::futurize_invoke(func).finally([&lock, obc] {
110 lock.unlock();
9f95a23c
TL
111 });
112 });
113 }
114
20effc67
TL
115 boost::intrusive::list_member_hook<> list_hook;
116 uint64_t list_link_cnt = 0;
117
9f95a23c 118public:
20effc67
TL
119
120 template <typename ListType>
121 void append_to(ListType& list) {
122 if (list_link_cnt++ == 0) {
123 list.push_back(*this);
124 }
125 }
126
127 template <typename ListType>
128 void remove_from(ListType&& list) {
129 assert(list_link_cnt > 0);
130 if (--list_link_cnt == 0) {
131 list.erase(std::decay_t<ListType>::s_iterator_to(*this));
132 }
133 }
134
135 using obc_accessing_option_t = boost::intrusive::member_hook<
136 ObjectContext,
137 boost::intrusive::list_member_hook<>,
138 &ObjectContext::list_hook>;
139
140 template<RWState::State Type, typename InterruptCond = void, typename Func>
f67539c2 141 auto with_lock(Func&& func) {
20effc67
TL
142 if constexpr (!std::is_void_v<InterruptCond>) {
143 auto wrapper = ::crimson::interruptible::interruptor<InterruptCond>::wrap_function(std::forward<Func>(func));
144 switch (Type) {
145 case RWState::RWWRITE:
146 return _with_lock(lock.for_write(), std::move(wrapper));
147 case RWState::RWREAD:
148 return _with_lock(lock.for_read(), std::move(wrapper));
149 case RWState::RWEXCL:
150 return _with_lock(lock.for_excl(), std::move(wrapper));
151 case RWState::RWNONE:
152 return seastar::futurize_invoke(std::move(wrapper));
153 default:
154 assert(0 == "noop");
155 }
156 } else {
157 switch (Type) {
158 case RWState::RWWRITE:
159 return _with_lock(lock.for_write(), std::forward<Func>(func));
160 case RWState::RWREAD:
161 return _with_lock(lock.for_read(), std::forward<Func>(func));
162 case RWState::RWEXCL:
163 return _with_lock(lock.for_excl(), std::forward<Func>(func));
164 case RWState::RWNONE:
165 return seastar::futurize_invoke(std::forward<Func>(func));
166 default:
167 assert(0 == "noop");
168 }
9f95a23c
TL
169 }
170 }
20effc67 171 template<RWState::State Type, typename InterruptCond = void, typename Func>
f67539c2 172 auto with_promoted_lock(Func&& func) {
20effc67
TL
173 if constexpr (!std::is_void_v<InterruptCond>) {
174 auto wrapper = ::crimson::interruptible::interruptor<InterruptCond>::wrap_function(std::forward<Func>(func));
175 switch (Type) {
176 case RWState::RWWRITE:
177 return _with_lock(lock.excl_from_write(), std::move(wrapper));
178 case RWState::RWREAD:
179 return _with_lock(lock.excl_from_read(), std::move(wrapper));
180 case RWState::RWEXCL:
181 return _with_lock(lock.excl_from_excl(), std::move(wrapper));
182 case RWState::RWNONE:
183 return _with_lock(lock.for_excl(), std::move(wrapper));
184 default:
185 assert(0 == "noop");
186 }
187 } else {
188 switch (Type) {
189 case RWState::RWWRITE:
190 return _with_lock(lock.excl_from_write(), std::forward<Func>(func));
191 case RWState::RWREAD:
192 return _with_lock(lock.excl_from_read(), std::forward<Func>(func));
193 case RWState::RWEXCL:
194 return _with_lock(lock.excl_from_excl(), std::forward<Func>(func));
195 case RWState::RWNONE:
196 return _with_lock(lock.for_excl(), std::forward<Func>(func));
197 default:
198 assert(0 == "noop");
199 }
9f95a23c
TL
200 }
201 }
202
f67539c2
TL
203 bool empty() const {
204 return !lock.is_acquired();
9f95a23c 205 }
f67539c2
TL
206 bool is_request_pending() const {
207 return lock.is_acquired();
9f95a23c
TL
208 }
209
9f95a23c 210 bool get_recovery_read() {
f67539c2
TL
211 if (lock.try_lock_for_read()) {
212 recovery_read_marker = true;
213 return true;
214 } else {
215 return false;
216 }
217 }
218 void wait_recovery_read() {
219 assert(lock.get_readers() > 0);
220 recovery_read_marker = true;
9f95a23c
TL
221 }
222 void drop_recovery_read() {
f67539c2
TL
223 assert(recovery_read_marker);
224 recovery_read_marker = false;
9f95a23c
TL
225 }
226 bool maybe_get_excl() {
f67539c2 227 return lock.try_lock_for_excl();
9f95a23c
TL
228 }
229};
230using ObjectContextRef = ObjectContext::Ref;
231
232class ObjectContextRegistry : public md_config_obs_t {
233 ObjectContext::lru_t obc_lru;
234
235public:
236 ObjectContextRegistry(crimson::common::ConfigProxy &conf);
20effc67 237 ~ObjectContextRegistry();
9f95a23c
TL
238
239 std::pair<ObjectContextRef, bool> get_cached_obc(const hobject_t &hoid) {
240 return obc_lru.get_or_create(hoid);
241 }
f67539c2
TL
242 ObjectContextRef maybe_get_cached_obc(const hobject_t &hoid) {
243 return obc_lru.get(hoid);
244 }
9f95a23c
TL
245
246 const char** get_tracked_conf_keys() const final;
247 void handle_conf_change(const crimson::common::ConfigProxy& conf,
248 const std::set <std::string> &changed) final;
249};
250
251} // namespace crimson::osd