]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/ScatterLock.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / mds / ScatterLock.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15
16 #ifndef CEPH_SCATTERLOCK_H
17 #define CEPH_SCATTERLOCK_H
18
19 #include "SimpleLock.h"
20
21 #include "MDSContext.h"
22
23 class ScatterLock : public SimpleLock {
24
25 struct more_bits_t {
26 xlist<ScatterLock*>::item item_updated;
27 utime_t update_stamp;
28
29 explicit more_bits_t(ScatterLock *lock) :
30 item_updated(lock)
31 {}
32 };
33
34 mutable std::unique_ptr<more_bits_t> _more;
35
36 more_bits_t *more() {
37 if (!_more)
38 _more.reset(new more_bits_t(this));
39 return _more.get();
40 }
41
42 enum {
43 SCATTER_WANTED = 1 << 8,
44 UNSCATTER_WANTED = 1 << 9,
45 DIRTY = 1 << 10,
46 FLUSHING = 1 << 11,
47 FLUSHED = 1 << 12,
48 };
49
50 public:
51 ScatterLock(MDSCacheObject *o, LockType *lt) :
52 SimpleLock(o, lt) {}
53 ~ScatterLock() override {
54 ceph_assert(!_more);
55 }
56
57 bool is_scatterlock() const override {
58 return true;
59 }
60
61 bool is_sync_and_unlocked() const {
62 return
63 SimpleLock::is_sync_and_unlocked() &&
64 !is_dirty() &&
65 !is_flushing();
66 }
67
68 bool can_scatter_pin(client_t loner) {
69 /*
70 LOCK : NOT okay because it can MIX and force replicas to journal something
71 TSYN : also not okay for same reason
72 EXCL : also not okay
73
74 MIX : okay, replica can stall before sending AC_SYNCACK
75 SYNC : okay, replica can stall before sending AC_MIXACK or AC_LOCKACK
76 */
77 return
78 get_state() == LOCK_SYNC ||
79 get_state() == LOCK_MIX;
80 }
81
82 void set_xlock_snap_sync(MDSContext *c)
83 {
84 ceph_assert(get_type() == CEPH_LOCK_IFILE);
85 ceph_assert(state == LOCK_XLOCK || state == LOCK_XLOCKDONE);
86 state = LOCK_XLOCKSNAP;
87 add_waiter(WAIT_STABLE, c);
88 }
89
90 xlist<ScatterLock*>::item *get_updated_item() { return &more()->item_updated; }
91
92 utime_t get_update_stamp() {
93 return _more ? _more->update_stamp : utime_t();
94 }
95
96 void set_update_stamp(utime_t t) { more()->update_stamp = t; }
97
98 void set_scatter_wanted() {
99 state_flags |= SCATTER_WANTED;
100 }
101 void set_unscatter_wanted() {
102 state_flags |= UNSCATTER_WANTED;
103 }
104 void clear_scatter_wanted() {
105 state_flags &= ~SCATTER_WANTED;
106 }
107 void clear_unscatter_wanted() {
108 state_flags &= ~UNSCATTER_WANTED;
109 }
110 bool get_scatter_wanted() const {
111 return state_flags & SCATTER_WANTED;
112 }
113 bool get_unscatter_wanted() const {
114 return state_flags & UNSCATTER_WANTED;
115 }
116
117 bool is_dirty() const override {
118 return state_flags & DIRTY;
119 }
120 bool is_flushing() const override {
121 return state_flags & FLUSHING;
122 }
123 bool is_flushed() const override {
124 return state_flags & FLUSHED;
125 }
126 bool is_dirty_or_flushing() const {
127 return is_dirty() || is_flushing();
128 }
129
130 void mark_dirty() {
131 if (!is_dirty()) {
132 if (!is_flushing())
133 parent->get(MDSCacheObject::PIN_DIRTYSCATTERED);
134 set_dirty();
135 }
136 }
137 void start_flush() {
138 if (is_dirty()) {
139 set_flushing();
140 clear_dirty();
141 }
142 }
143 void finish_flush() {
144 if (is_flushing()) {
145 clear_flushing();
146 set_flushed();
147 if (!is_dirty()) {
148 parent->put(MDSCacheObject::PIN_DIRTYSCATTERED);
149 parent->clear_dirty_scattered(get_type());
150 }
151 }
152 }
153 void clear_flushed() override {
154 state_flags &= ~FLUSHED;
155 }
156 void remove_dirty() {
157 start_flush();
158 finish_flush();
159 clear_flushed();
160 }
161
162 void infer_state_from_strong_rejoin(int rstate, bool locktoo) {
163 if (rstate == LOCK_MIX ||
164 rstate == LOCK_MIX_LOCK || // replica still has wrlocks?
165 rstate == LOCK_MIX_SYNC)
166 state = LOCK_MIX;
167 else if (locktoo && rstate == LOCK_LOCK)
168 state = LOCK_LOCK;
169 }
170
171 void encode_state_for_rejoin(bufferlist& bl, int rep) {
172 __s16 s = get_replica_state();
173 if (is_gathering(rep)) {
174 // the recovering mds may hold rejoined wrlocks
175 if (state == LOCK_MIX_SYNC)
176 s = LOCK_MIX_SYNC;
177 else
178 s = LOCK_MIX_LOCK;
179 }
180
181 // If there is a recovering mds who replcated an object when it failed
182 // and scatterlock in the object was in MIX state, It's possible that
183 // the recovering mds needs to take wrlock on the scatterlock when it
184 // replays unsafe requests. So this mds should delay taking rdlock on
185 // the scatterlock until the recovering mds finishes replaying unsafe.
186 // Otherwise unsafe requests may get replayed after current request.
187 //
188 // For example:
189 // The recovering mds is auth mds of a dirfrag, this mds is auth mds
190 // of corresponding inode. when 'rm -rf' the direcotry, this mds should
191 // delay the rmdir request until the recovering mds has replayed unlink
192 // requests.
193 if (s == LOCK_MIX || s == LOCK_MIX_LOCK || s == LOCK_MIX_SYNC)
194 mark_need_recover();
195
196 using ceph::encode;
197 encode(s, bl);
198 }
199
200 void decode_state_rejoin(bufferlist::const_iterator& p, MDSContext::vec& waiters, bool survivor) {
201 SimpleLock::decode_state_rejoin(p, waiters, survivor);
202 if (is_flushing()) {
203 set_dirty();
204 clear_flushing();
205 }
206 }
207
208 bool remove_replica(int from, bool rejoin) {
209 if (rejoin &&
210 (state == LOCK_MIX ||
211 state == LOCK_MIX_SYNC ||
212 state == LOCK_MIX_LOCK2 ||
213 state == LOCK_MIX_TSYN ||
214 state == LOCK_MIX_EXCL))
215 return false;
216 return SimpleLock::remove_replica(from);
217 }
218
219 void print(ostream& out) const override {
220 out << "(";
221 _print(out);
222 if (is_dirty())
223 out << " dirty";
224 if (is_flushing())
225 out << " flushing";
226 if (is_flushed())
227 out << " flushed";
228 if (get_scatter_wanted())
229 out << " scatter_wanted";
230 out << ")";
231 }
232
233 private:
234 void set_flushing() {
235 state_flags |= FLUSHING;
236 }
237 void clear_flushing() {
238 state_flags &= ~FLUSHING;
239 }
240 void set_flushed() {
241 state_flags |= FLUSHED;
242 }
243 void set_dirty() {
244 state_flags |= DIRTY;
245 }
246 void clear_dirty() {
247 state_flags &= ~DIRTY;
248 if (_more) {
249 _more->item_updated.remove_myself();
250 _more.reset();
251 }
252 }
253 };
254
255 #endif