]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #ifndef CEPH_OSD_INTERNAL_TYPES_H | |
5 | #define CEPH_OSD_INTERNAL_TYPES_H | |
6 | ||
7 | #include "osd_types.h" | |
8 | #include "OpRequest.h" | |
9f95a23c | 9 | #include "object_state.h" |
7c673cae FG |
10 | |
11 | /* | |
12 | * keep tabs on object modifications that are in flight. | |
13 | * we need to know the projected existence, size, snapset, | |
14 | * etc., because we don't send writes down to disk until after | |
15 | * replicas ack. | |
16 | */ | |
17 | ||
18 | struct SnapSetContext { | |
19 | hobject_t oid; | |
20 | SnapSet snapset; | |
21 | int ref; | |
22 | bool registered : 1; | |
23 | bool exists : 1; | |
24 | ||
25 | explicit SnapSetContext(const hobject_t& o) : | |
26 | oid(o), ref(0), registered(false), exists(true) { } | |
27 | }; | |
f67539c2 | 28 | struct ObjectContext; |
11fdf7f2 | 29 | typedef std::shared_ptr<ObjectContext> ObjectContextRef; |
7c673cae FG |
30 | |
31 | struct ObjectContext { | |
32 | ObjectState obs; | |
33 | ||
34 | SnapSetContext *ssc; // may be null | |
35 | ||
36 | Context *destructor_callback; | |
37 | ||
7c673cae | 38 | public: |
7c673cae FG |
39 | |
40 | // any entity in obs.oi.watchers MUST be in either watchers or unconnected_watchers. | |
f67539c2 | 41 | std::map<std::pair<uint64_t, entity_name_t>, WatchRef> watchers; |
7c673cae FG |
42 | |
43 | // attr cache | |
20effc67 | 44 | std::map<std::string, ceph::buffer::list, std::less<>> attr_cache; |
7c673cae | 45 | |
9f95a23c TL |
46 | RWState rwstate; |
47 | std::list<OpRequestRef> waiters; ///< ops waiting on state change | |
48 | bool get_read(OpRequestRef& op) { | |
49 | if (rwstate.get_read_lock()) { | |
50 | return true; | |
51 | } // else | |
11fdf7f2 | 52 | // Now we really need to bump up the ref-counter. |
9f95a23c TL |
53 | waiters.emplace_back(op); |
54 | rwstate.inc_waiters(); | |
55 | return false; | |
56 | } | |
57 | bool get_write(OpRequestRef& op, bool greedy=false) { | |
58 | if (rwstate.get_write_lock(greedy)) { | |
59 | return true; | |
60 | } // else | |
61 | if (op) { | |
11fdf7f2 | 62 | waiters.emplace_back(op); |
9f95a23c | 63 | rwstate.inc_waiters(); |
7c673cae | 64 | } |
9f95a23c TL |
65 | return false; |
66 | } | |
67 | bool get_excl(OpRequestRef& op) { | |
68 | if (rwstate.get_excl_lock()) { | |
69 | return true; | |
70 | } // else | |
71 | if (op) { | |
72 | waiters.emplace_back(op); | |
73 | rwstate.inc_waiters(); | |
7c673cae | 74 | } |
9f95a23c TL |
75 | return false; |
76 | } | |
f67539c2 | 77 | void wake(std::list<OpRequestRef> *requeue) { |
9f95a23c TL |
78 | rwstate.release_waiters(); |
79 | requeue->splice(requeue->end(), waiters); | |
80 | } | |
f67539c2 | 81 | void put_read(std::list<OpRequestRef> *requeue) { |
9f95a23c TL |
82 | if (rwstate.put_read()) { |
83 | wake(requeue); | |
7c673cae | 84 | } |
7c673cae | 85 | } |
f67539c2 | 86 | void put_write(std::list<OpRequestRef> *requeue) { |
9f95a23c TL |
87 | if (rwstate.put_write()) { |
88 | wake(requeue); | |
89 | } | |
7c673cae | 90 | } |
f67539c2 | 91 | void put_excl(std::list<OpRequestRef> *requeue) { |
9f95a23c TL |
92 | if (rwstate.put_excl()) { |
93 | wake(requeue); | |
94 | } | |
7c673cae | 95 | } |
9f95a23c TL |
96 | bool empty() const { return rwstate.empty(); } |
97 | ||
11fdf7f2 | 98 | bool get_lock_type(OpRequestRef& op, RWState::State type) { |
7c673cae FG |
99 | switch (type) { |
100 | case RWState::RWWRITE: | |
101 | return get_write(op); | |
102 | case RWState::RWREAD: | |
103 | return get_read(op); | |
104 | case RWState::RWEXCL: | |
105 | return get_excl(op); | |
106 | default: | |
11fdf7f2 | 107 | ceph_abort_msg("invalid lock type"); |
7c673cae FG |
108 | return true; |
109 | } | |
110 | } | |
11fdf7f2 | 111 | bool get_write_greedy(OpRequestRef& op) { |
9f95a23c | 112 | return get_write(op, true); |
7c673cae FG |
113 | } |
114 | bool get_snaptrimmer_write(bool mark_if_unsuccessful) { | |
9f95a23c | 115 | return rwstate.get_snaptrimmer_write(mark_if_unsuccessful); |
7c673cae FG |
116 | } |
117 | bool get_recovery_read() { | |
9f95a23c | 118 | return rwstate.get_recovery_read(); |
7c673cae FG |
119 | } |
120 | bool try_get_read_lock() { | |
121 | return rwstate.get_read_lock(); | |
122 | } | |
f67539c2 | 123 | void drop_recovery_read(std::list<OpRequestRef> *ls) { |
11fdf7f2 | 124 | ceph_assert(rwstate.recovery_read_marker); |
9f95a23c | 125 | put_read(ls); |
7c673cae FG |
126 | rwstate.recovery_read_marker = false; |
127 | } | |
128 | void put_lock_type( | |
9f95a23c | 129 | RWState::State type, |
f67539c2 | 130 | std::list<OpRequestRef> *to_wake, |
7c673cae FG |
131 | bool *requeue_recovery, |
132 | bool *requeue_snaptrimmer) { | |
133 | switch (type) { | |
9f95a23c TL |
134 | case RWState::RWWRITE: |
135 | put_write(to_wake); | |
7c673cae | 136 | break; |
9f95a23c TL |
137 | case RWState::RWREAD: |
138 | put_read(to_wake); | |
7c673cae | 139 | break; |
9f95a23c TL |
140 | case RWState::RWEXCL: |
141 | put_excl(to_wake); | |
7c673cae FG |
142 | break; |
143 | default: | |
11fdf7f2 | 144 | ceph_abort_msg("invalid lock type"); |
7c673cae FG |
145 | } |
146 | if (rwstate.empty() && rwstate.recovery_read_marker) { | |
147 | rwstate.recovery_read_marker = false; | |
148 | *requeue_recovery = true; | |
149 | } | |
150 | if (rwstate.empty() && rwstate.snaptrimmer_write_marker) { | |
151 | rwstate.snaptrimmer_write_marker = false; | |
152 | *requeue_snaptrimmer = true; | |
153 | } | |
154 | } | |
155 | bool is_request_pending() { | |
9f95a23c | 156 | return !rwstate.empty(); |
7c673cae FG |
157 | } |
158 | ||
159 | ObjectContext() | |
160 | : ssc(NULL), | |
161 | destructor_callback(0), | |
7c673cae FG |
162 | blocked(false), requeue_scrub_on_unblock(false) {} |
163 | ||
164 | ~ObjectContext() { | |
11fdf7f2 | 165 | ceph_assert(rwstate.empty()); |
7c673cae FG |
166 | if (destructor_callback) |
167 | destructor_callback->complete(0); | |
168 | } | |
169 | ||
170 | void start_block() { | |
11fdf7f2 | 171 | ceph_assert(!blocked); |
7c673cae FG |
172 | blocked = true; |
173 | } | |
174 | void stop_block() { | |
11fdf7f2 | 175 | ceph_assert(blocked); |
7c673cae FG |
176 | blocked = false; |
177 | } | |
178 | bool is_blocked() const { | |
179 | return blocked; | |
180 | } | |
181 | ||
7c673cae FG |
182 | /// in-progress copyfrom ops for this object |
183 | bool blocked:1; | |
184 | bool requeue_scrub_on_unblock:1; // true if we need to requeue scrub on unblock | |
185 | ||
186 | }; | |
187 | ||
f67539c2 | 188 | inline std::ostream& operator<<(std::ostream& out, const ObjectState& obs) |
7c673cae FG |
189 | { |
190 | out << obs.oi.soid; | |
191 | if (!obs.exists) | |
192 | out << "(dne)"; | |
193 | return out; | |
194 | } | |
195 | ||
f67539c2 | 196 | inline std::ostream& operator<<(std::ostream& out, const ObjectContext& obc) |
7c673cae FG |
197 | { |
198 | return out << "obc(" << obc.obs << " " << obc.rwstate << ")"; | |
199 | } | |
200 | ||
201 | class ObcLockManager { | |
202 | struct ObjectLockState { | |
203 | ObjectContextRef obc; | |
9f95a23c | 204 | RWState::State type; |
7c673cae FG |
205 | ObjectLockState( |
206 | ObjectContextRef obc, | |
9f95a23c | 207 | RWState::State type) |
11fdf7f2 | 208 | : obc(std::move(obc)), type(type) {} |
7c673cae | 209 | }; |
f67539c2 | 210 | std::map<hobject_t, ObjectLockState> locks; |
7c673cae FG |
211 | public: |
212 | ObcLockManager() = default; | |
213 | ObcLockManager(ObcLockManager &&) = default; | |
214 | ObcLockManager(const ObcLockManager &) = delete; | |
215 | ObcLockManager &operator=(ObcLockManager &&) = default; | |
216 | bool empty() const { | |
217 | return locks.empty(); | |
218 | } | |
219 | bool get_lock_type( | |
9f95a23c | 220 | RWState::State type, |
7c673cae | 221 | const hobject_t &hoid, |
11fdf7f2 TL |
222 | ObjectContextRef& obc, |
223 | OpRequestRef& op) { | |
224 | ceph_assert(locks.find(hoid) == locks.end()); | |
7c673cae | 225 | if (obc->get_lock_type(op, type)) { |
f67539c2 | 226 | locks.insert(std::make_pair(hoid, ObjectLockState(obc, type))); |
7c673cae FG |
227 | return true; |
228 | } else { | |
229 | return false; | |
230 | } | |
231 | } | |
232 | /// Get write lock, ignore starvation | |
233 | bool take_write_lock( | |
234 | const hobject_t &hoid, | |
235 | ObjectContextRef obc) { | |
11fdf7f2 | 236 | ceph_assert(locks.find(hoid) == locks.end()); |
7c673cae FG |
237 | if (obc->rwstate.take_write_lock()) { |
238 | locks.insert( | |
f67539c2 | 239 | std::make_pair( |
9f95a23c | 240 | hoid, ObjectLockState(obc, RWState::RWWRITE))); |
7c673cae FG |
241 | return true; |
242 | } else { | |
243 | return false; | |
244 | } | |
245 | } | |
246 | /// Get write lock for snap trim | |
247 | bool get_snaptrimmer_write( | |
248 | const hobject_t &hoid, | |
249 | ObjectContextRef obc, | |
250 | bool mark_if_unsuccessful) { | |
11fdf7f2 | 251 | ceph_assert(locks.find(hoid) == locks.end()); |
7c673cae FG |
252 | if (obc->get_snaptrimmer_write(mark_if_unsuccessful)) { |
253 | locks.insert( | |
f67539c2 | 254 | std::make_pair( |
9f95a23c | 255 | hoid, ObjectLockState(obc, RWState::RWWRITE))); |
7c673cae FG |
256 | return true; |
257 | } else { | |
258 | return false; | |
259 | } | |
260 | } | |
261 | /// Get write lock greedy | |
262 | bool get_write_greedy( | |
263 | const hobject_t &hoid, | |
264 | ObjectContextRef obc, | |
265 | OpRequestRef op) { | |
11fdf7f2 | 266 | ceph_assert(locks.find(hoid) == locks.end()); |
7c673cae FG |
267 | if (obc->get_write_greedy(op)) { |
268 | locks.insert( | |
f67539c2 | 269 | std::make_pair( |
9f95a23c | 270 | hoid, ObjectLockState(obc, RWState::RWWRITE))); |
7c673cae FG |
271 | return true; |
272 | } else { | |
273 | return false; | |
274 | } | |
275 | } | |
276 | ||
277 | /// try get read lock | |
278 | bool try_get_read_lock( | |
279 | const hobject_t &hoid, | |
280 | ObjectContextRef obc) { | |
11fdf7f2 | 281 | ceph_assert(locks.find(hoid) == locks.end()); |
7c673cae FG |
282 | if (obc->try_get_read_lock()) { |
283 | locks.insert( | |
f67539c2 | 284 | std::make_pair( |
7c673cae | 285 | hoid, |
9f95a23c | 286 | ObjectLockState(obc, RWState::RWREAD))); |
7c673cae FG |
287 | return true; |
288 | } else { | |
289 | return false; | |
290 | } | |
291 | } | |
292 | ||
293 | void put_locks( | |
f67539c2 | 294 | std::list<std::pair<ObjectContextRef, std::list<OpRequestRef> > > *to_requeue, |
7c673cae FG |
295 | bool *requeue_recovery, |
296 | bool *requeue_snaptrimmer) { | |
11fdf7f2 | 297 | for (auto& p: locks) { |
f67539c2 | 298 | std::list<OpRequestRef> _to_requeue; |
7c673cae FG |
299 | p.second.obc->put_lock_type( |
300 | p.second.type, | |
301 | &_to_requeue, | |
302 | requeue_recovery, | |
303 | requeue_snaptrimmer); | |
304 | if (to_requeue) { | |
11fdf7f2 TL |
305 | // We can safely std::move here as the whole `locks` is going |
306 | // to die just after the loop. | |
307 | to_requeue->emplace_back(std::move(p.second.obc), | |
308 | std::move(_to_requeue)); | |
7c673cae FG |
309 | } |
310 | } | |
311 | locks.clear(); | |
312 | } | |
313 | ~ObcLockManager() { | |
11fdf7f2 | 314 | ceph_assert(locks.empty()); |
7c673cae FG |
315 | } |
316 | }; | |
317 | ||
318 | ||
319 | ||
320 | #endif |