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