Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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     int state_flags;
25     utime_t last_scatter;
26     xlist<ScatterLock*>::item item_updated;
27     utime_t update_stamp;
28
29     explicit more_bits_t(ScatterLock *lock) :
30       state_flags(0),
31       item_updated(lock)
32     {}
33
34     bool empty() const {
35       return
36         !state_flags &&
37         !item_updated.is_on_list();
38     }
39   };
40   more_bits_t *_more;
41
42   bool have_more() const { return _more ? true : false; }
43   void try_clear_more() {
44     if (_more && _more->empty()) {
45       delete _more;
46       _more = NULL;
47     }
48   }
49   more_bits_t *more() {
50     if (!_more)
51       _more = new more_bits_t(this);
52     return _more;
53   }
54
55   enum flag_values {  // flag values for more_bits_t state
56     SCATTER_WANTED   = 1 << 0,
57     UNSCATTER_WANTED = 1 << 1,
58     DIRTY            = 1 << 2,
59     FLUSHING         = 1 << 3,
60     FLUSHED          = 1 << 4,
61     REJOIN_MIX       = 1 << 5, // no rdlock until the recovering mds become active
62   };
63
64 public:
65   ScatterLock(MDSCacheObject *o, LockType *lt) : 
66     SimpleLock(o, lt), _more(NULL)
67   {}
68   ~ScatterLock() override {
69     if (_more) {
70       _more->item_updated.remove_myself();   // FIXME this should happen sooner, i think...
71       delete _more;
72     }
73   }
74
75   bool is_scatterlock() const override {
76     return true;
77   }
78
79   bool is_sync_and_unlocked() const {
80     return
81       SimpleLock::is_sync_and_unlocked() && 
82       !is_dirty() &&
83       !is_flushing();
84   }
85
86   bool can_scatter_pin(client_t loner) {
87     /*
88       LOCK : NOT okay because it can MIX and force replicas to journal something
89       TSYN : also not okay for same reason
90       EXCL : also not okay
91
92       MIX  : okay, replica can stall before sending AC_SYNCACK
93       SYNC : okay, replica can stall before sending AC_MIXACK or AC_LOCKACK
94     */   
95     return
96       get_state() == LOCK_SYNC ||
97       get_state() == LOCK_MIX;
98   }
99
100   void set_xlock_snap_sync(MDSInternalContextBase *c)
101   {
102     assert(get_type() == CEPH_LOCK_IFILE);
103     assert(state == LOCK_XLOCK || state == LOCK_XLOCKDONE);
104     state = LOCK_XLOCKSNAP;
105     add_waiter(WAIT_STABLE, c);
106   }
107
108   xlist<ScatterLock*>::item *get_updated_item() { return &more()->item_updated; }
109
110   utime_t get_update_stamp() {
111     return more()->update_stamp;
112   }
113
114   void set_update_stamp(utime_t t) { more()->update_stamp = t; }
115
116   void set_scatter_wanted() {
117     more()->state_flags |= SCATTER_WANTED;
118   }
119   void set_unscatter_wanted() {
120     more()->state_flags |= UNSCATTER_WANTED;
121   }
122   void clear_scatter_wanted() {
123     if (have_more())
124       _more->state_flags &= ~SCATTER_WANTED;
125     try_clear_more();
126   }
127   void clear_unscatter_wanted() {
128     if (have_more())
129       _more->state_flags &= ~UNSCATTER_WANTED;
130     try_clear_more();
131   }
132   bool get_scatter_wanted() const {
133     return have_more() ? _more->state_flags & SCATTER_WANTED : false;
134   }
135   bool get_unscatter_wanted() const {
136     return have_more() ? _more->state_flags & UNSCATTER_WANTED : false;
137   }
138
139   bool is_dirty() const override {
140     return have_more() ? _more->state_flags & DIRTY : false;
141   }
142   bool is_flushing() const override {
143     return have_more() ? _more->state_flags & FLUSHING: false;
144   }
145   bool is_flushed() const override {
146     return have_more() ? _more->state_flags & FLUSHED: false;
147   }
148   bool is_dirty_or_flushing() const {
149     return have_more() ? (is_dirty() || is_flushing()) : false;
150   }
151   bool is_rejoin_mix() const {
152     return have_more() ? _more->state_flags & REJOIN_MIX : false;
153   }
154
155   void mark_dirty() { 
156     if (!is_dirty()) {
157       if (!is_flushing())
158         parent->get(MDSCacheObject::PIN_DIRTYSCATTERED);
159       set_dirty();
160     }
161   }
162   void start_flush() {
163     if (is_dirty()) {
164       set_flushing();
165       clear_dirty();
166     }
167   }
168   void finish_flush() {
169     if (is_flushing()) {
170       clear_flushing();
171       set_flushed();
172       if (!is_dirty()) {
173         parent->put(MDSCacheObject::PIN_DIRTYSCATTERED);
174         parent->clear_dirty_scattered(get_type());
175       }
176     }
177   }
178   void remove_dirty() {
179     start_flush();
180     finish_flush();
181   }
182   void clear_flushed() override {
183     if (have_more()) {
184       _more->state_flags &= ~FLUSHED;
185       try_clear_more();
186     }
187   }
188
189   void clear_rejoin_mix() {
190     if (have_more()) {
191       _more->state_flags &= ~REJOIN_MIX;
192       try_clear_more();
193     }
194   }
195
196   void set_last_scatter(utime_t t) { more()->last_scatter = t; }
197   utime_t get_last_scatter() {
198     return more()->last_scatter;
199   }
200
201   void infer_state_from_strong_rejoin(int rstate, bool locktoo) {
202     if (rstate == LOCK_MIX || 
203         rstate == LOCK_MIX_LOCK || // replica still has wrlocks?
204         rstate == LOCK_MIX_SYNC)
205       state = LOCK_MIX;
206     else if (locktoo && rstate == LOCK_LOCK)
207       state = LOCK_LOCK;
208   }
209
210   void encode_state_for_rejoin(bufferlist& bl, int rep) {
211     __s16 s = get_replica_state();
212     if (is_gathering(rep)) {
213       // the recovering mds may hold rejoined wrlocks
214       if (state == LOCK_MIX_SYNC)
215         s = LOCK_MIX_SYNC;
216       else
217         s = LOCK_MIX_LOCK;
218     }
219
220     if (s == LOCK_MIX || s == LOCK_MIX_LOCK || s == LOCK_MIX_SYNC)
221       more()->state_flags |= REJOIN_MIX;
222
223     ::encode(s, bl);
224   }
225
226   void decode_state_rejoin(bufferlist::iterator& p, list<MDSInternalContextBase*>& waiters) {
227     SimpleLock::decode_state_rejoin(p, waiters);
228     if (is_flushing()) {
229       set_dirty();
230       clear_flushing();
231     }
232   }
233
234   bool remove_replica(int from, bool rejoin) {
235     if (rejoin &&
236         (state == LOCK_MIX ||
237          state == LOCK_MIX_SYNC ||
238          state == LOCK_MIX_LOCK2 ||
239          state == LOCK_MIX_TSYN ||
240          state == LOCK_MIX_EXCL))
241       return false;
242     return SimpleLock::remove_replica(from);
243   }
244
245   void print(ostream& out) const override {
246     out << "(";
247     _print(out);
248     if (is_dirty())
249       out << " dirty";
250     if (is_flushing())
251       out << " flushing";
252     if (is_flushed())
253       out << " flushed";
254     if (get_scatter_wanted())
255       out << " scatter_wanted";
256     out << ")";
257   }
258
259 private:
260   void set_flushing() {
261     more()->state_flags |= FLUSHING;
262   }
263   void clear_flushing() {
264     if (have_more()) {
265       _more->state_flags &= ~FLUSHING;
266     }
267   }
268   void set_flushed() {
269     more()->state_flags |= FLUSHED;
270   }
271   void set_dirty() {
272     more()->state_flags |= DIRTY;
273   }
274   void clear_dirty() {
275     if (have_more()) {
276       _more->state_flags &= ~DIRTY;
277     }
278   }
279 };
280
281 #endif