]> git.proxmox.com Git - ceph.git/blob - ceph/src/osd/osd_internal_types.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / osd / osd_internal_types.h
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"
9 #include "object_state.h"
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 };
28 struct ObjectContext;
29 typedef std::shared_ptr<ObjectContext> ObjectContextRef;
30
31 struct ObjectContext {
32 ObjectState obs;
33
34 SnapSetContext *ssc; // may be null
35
36 Context *destructor_callback;
37
38 public:
39
40 // any entity in obs.oi.watchers MUST be in either watchers or unconnected_watchers.
41 std::map<std::pair<uint64_t, entity_name_t>, WatchRef> watchers;
42
43 // attr cache
44 std::map<std::string, ceph::buffer::list, std::less<>> attr_cache;
45
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
52 // Now we really need to bump up the ref-counter.
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) {
62 waiters.emplace_back(op);
63 rwstate.inc_waiters();
64 }
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();
74 }
75 return false;
76 }
77 void wake(std::list<OpRequestRef> *requeue) {
78 rwstate.release_waiters();
79 requeue->splice(requeue->end(), waiters);
80 }
81 void put_read(std::list<OpRequestRef> *requeue) {
82 if (rwstate.put_read()) {
83 wake(requeue);
84 }
85 }
86 void put_write(std::list<OpRequestRef> *requeue) {
87 if (rwstate.put_write()) {
88 wake(requeue);
89 }
90 }
91 void put_excl(std::list<OpRequestRef> *requeue) {
92 if (rwstate.put_excl()) {
93 wake(requeue);
94 }
95 }
96 bool empty() const { return rwstate.empty(); }
97
98 bool get_lock_type(OpRequestRef& op, RWState::State type) {
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:
107 ceph_abort_msg("invalid lock type");
108 return true;
109 }
110 }
111 bool get_write_greedy(OpRequestRef& op) {
112 return get_write(op, true);
113 }
114 bool get_snaptrimmer_write(bool mark_if_unsuccessful) {
115 return rwstate.get_snaptrimmer_write(mark_if_unsuccessful);
116 }
117 bool get_recovery_read() {
118 return rwstate.get_recovery_read();
119 }
120 bool try_get_read_lock() {
121 return rwstate.get_read_lock();
122 }
123 void drop_recovery_read(std::list<OpRequestRef> *ls) {
124 ceph_assert(rwstate.recovery_read_marker);
125 put_read(ls);
126 rwstate.recovery_read_marker = false;
127 }
128 void put_lock_type(
129 RWState::State type,
130 std::list<OpRequestRef> *to_wake,
131 bool *requeue_recovery,
132 bool *requeue_snaptrimmer) {
133 switch (type) {
134 case RWState::RWWRITE:
135 put_write(to_wake);
136 break;
137 case RWState::RWREAD:
138 put_read(to_wake);
139 break;
140 case RWState::RWEXCL:
141 put_excl(to_wake);
142 break;
143 default:
144 ceph_abort_msg("invalid lock type");
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() {
156 return !rwstate.empty();
157 }
158
159 ObjectContext()
160 : ssc(NULL),
161 destructor_callback(0),
162 blocked(false), requeue_scrub_on_unblock(false) {}
163
164 ~ObjectContext() {
165 ceph_assert(rwstate.empty());
166 if (destructor_callback)
167 destructor_callback->complete(0);
168 }
169
170 void start_block() {
171 ceph_assert(!blocked);
172 blocked = true;
173 }
174 void stop_block() {
175 ceph_assert(blocked);
176 blocked = false;
177 }
178 bool is_blocked() const {
179 return blocked;
180 }
181
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
188 inline std::ostream& operator<<(std::ostream& out, const ObjectState& obs)
189 {
190 out << obs.oi.soid;
191 if (!obs.exists)
192 out << "(dne)";
193 return out;
194 }
195
196 inline std::ostream& operator<<(std::ostream& out, const ObjectContext& obc)
197 {
198 return out << "obc(" << obc.obs << " " << obc.rwstate << ")";
199 }
200
201 class ObcLockManager {
202 struct ObjectLockState {
203 ObjectContextRef obc;
204 RWState::State type;
205 ObjectLockState(
206 ObjectContextRef obc,
207 RWState::State type)
208 : obc(std::move(obc)), type(type) {}
209 };
210 std::map<hobject_t, ObjectLockState> locks;
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(
220 RWState::State type,
221 const hobject_t &hoid,
222 ObjectContextRef& obc,
223 OpRequestRef& op) {
224 ceph_assert(locks.find(hoid) == locks.end());
225 if (obc->get_lock_type(op, type)) {
226 locks.insert(std::make_pair(hoid, ObjectLockState(obc, type)));
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) {
236 ceph_assert(locks.find(hoid) == locks.end());
237 if (obc->rwstate.take_write_lock()) {
238 locks.insert(
239 std::make_pair(
240 hoid, ObjectLockState(obc, RWState::RWWRITE)));
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) {
251 ceph_assert(locks.find(hoid) == locks.end());
252 if (obc->get_snaptrimmer_write(mark_if_unsuccessful)) {
253 locks.insert(
254 std::make_pair(
255 hoid, ObjectLockState(obc, RWState::RWWRITE)));
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) {
266 ceph_assert(locks.find(hoid) == locks.end());
267 if (obc->get_write_greedy(op)) {
268 locks.insert(
269 std::make_pair(
270 hoid, ObjectLockState(obc, RWState::RWWRITE)));
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) {
281 ceph_assert(locks.find(hoid) == locks.end());
282 if (obc->try_get_read_lock()) {
283 locks.insert(
284 std::make_pair(
285 hoid,
286 ObjectLockState(obc, RWState::RWREAD)));
287 return true;
288 } else {
289 return false;
290 }
291 }
292
293 void put_locks(
294 std::list<std::pair<ObjectContextRef, std::list<OpRequestRef> > > *to_requeue,
295 bool *requeue_recovery,
296 bool *requeue_snaptrimmer) {
297 for (auto& p: locks) {
298 std::list<OpRequestRef> _to_requeue;
299 p.second.obc->put_lock_type(
300 p.second.type,
301 &_to_requeue,
302 requeue_recovery,
303 requeue_snaptrimmer);
304 if (to_requeue) {
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));
309 }
310 }
311 locks.clear();
312 }
313 ~ObcLockManager() {
314 ceph_assert(locks.empty());
315 }
316 };
317
318
319
320 #endif