]>
git.proxmox.com Git - ceph.git/blob - ceph/src/mds/SimpleLock.h
5c625b6af06f2819b80bbd2df7984f038f1c3d34
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
16 #ifndef CEPH_SIMPLELOCK_H
17 #define CEPH_SIMPLELOCK_H
19 #include <boost/intrusive_ptr.hpp>
21 #include "MDSCacheObject.h"
22 #include "MDSContext.h"
36 struct MDLockCacheItem
;
38 typedef boost::intrusive_ptr
<MutationImpl
> MutationRef
;
41 explicit LockType(int t
) : type(t
) {
46 case CEPH_LOCK_IXATTR
:
48 case CEPH_LOCK_IFLOCK
:
49 case CEPH_LOCK_IPOLICY
:
59 case CEPH_LOCK_DVERSION
:
60 case CEPH_LOCK_IVERSION
:
76 static const uint64_t WAIT_RD
= (1<<0); // to read
77 static const uint64_t WAIT_WR
= (1<<1); // to write
78 static const uint64_t WAIT_XLOCK
= (1<<2); // to xlock (** dup)
79 static const uint64_t WAIT_STABLE
= (1<<2); // for a stable state
80 static const uint64_t WAIT_REMOTEXLOCK
= (1<<3); // for a remote xlock
81 static const int WAIT_BITS
= 4;
82 static const uint64_t WAIT_ALL
= ((1<<WAIT_BITS
)-1);
84 static std::string_view
get_state_name(int n
) {
86 case LOCK_UNDEF
: return "UNDEF";
87 case LOCK_SYNC
: return "sync";
88 case LOCK_LOCK
: return "lock";
90 case LOCK_PREXLOCK
: return "prexlock";
91 case LOCK_XLOCK
: return "xlock";
92 case LOCK_XLOCKDONE
: return "xlockdone";
93 case LOCK_XLOCKSNAP
: return "xlocksnap";
94 case LOCK_LOCK_XLOCK
: return "lock->xlock";
96 case LOCK_SYNC_LOCK
: return "sync->lock";
97 case LOCK_LOCK_SYNC
: return "lock->sync";
98 case LOCK_REMOTEXLOCK
: return "remote_xlock";
99 case LOCK_EXCL
: return "excl";
100 case LOCK_EXCL_SYNC
: return "excl->sync";
101 case LOCK_EXCL_LOCK
: return "excl->lock";
102 case LOCK_SYNC_EXCL
: return "sync->excl";
103 case LOCK_LOCK_EXCL
: return "lock->excl";
105 case LOCK_XSYN
: return "xsyn";
106 case LOCK_XSYN_EXCL
: return "xsyn->excl";
107 case LOCK_EXCL_XSYN
: return "excl->xsyn";
108 case LOCK_XSYN_SYNC
: return "xsyn->sync";
109 case LOCK_XSYN_LOCK
: return "xsyn->lock";
110 case LOCK_XSYN_MIX
: return "xsyn->mix";
112 case LOCK_SYNC_MIX
: return "sync->mix";
113 case LOCK_SYNC_MIX2
: return "sync->mix(2)";
114 case LOCK_LOCK_TSYN
: return "lock->tsyn";
116 case LOCK_MIX_LOCK
: return "mix->lock";
117 case LOCK_MIX_LOCK2
: return "mix->lock(2)";
118 case LOCK_MIX
: return "mix";
119 case LOCK_MIX_TSYN
: return "mix->tsyn";
121 case LOCK_TSYN_MIX
: return "tsyn->mix";
122 case LOCK_TSYN_LOCK
: return "tsyn->lock";
123 case LOCK_TSYN
: return "tsyn";
125 case LOCK_MIX_SYNC
: return "mix->sync";
126 case LOCK_MIX_SYNC2
: return "mix->sync(2)";
127 case LOCK_EXCL_MIX
: return "excl->mix";
128 case LOCK_MIX_EXCL
: return "mix->excl";
130 case LOCK_PRE_SCAN
: return "*->scan";
131 case LOCK_SCAN
: return "scan";
133 case LOCK_SNAP_SYNC
: return "snap->sync";
135 default: ceph_abort(); return std::string_view();
139 static std::string_view
get_lock_type_name(int t
) {
141 case CEPH_LOCK_DN
: return "dn";
142 case CEPH_LOCK_DVERSION
: return "dversion";
143 case CEPH_LOCK_IVERSION
: return "iversion";
144 case CEPH_LOCK_IFILE
: return "ifile";
145 case CEPH_LOCK_IAUTH
: return "iauth";
146 case CEPH_LOCK_ILINK
: return "ilink";
147 case CEPH_LOCK_IDFT
: return "idft";
148 case CEPH_LOCK_INEST
: return "inest";
149 case CEPH_LOCK_IXATTR
: return "ixattr";
150 case CEPH_LOCK_ISNAP
: return "isnap";
151 case CEPH_LOCK_IFLOCK
: return "iflock";
152 case CEPH_LOCK_IPOLICY
: return "ipolicy";
153 default: return "unknown";
157 static std::string_view
get_lock_action_name(int a
) {
159 case LOCK_AC_SYNC
: return "sync";
160 case LOCK_AC_MIX
: return "mix";
161 case LOCK_AC_LOCK
: return "lock";
162 case LOCK_AC_LOCKFLUSHED
: return "lockflushed";
164 case LOCK_AC_SYNCACK
: return "syncack";
165 case LOCK_AC_MIXACK
: return "mixack";
166 case LOCK_AC_LOCKACK
: return "lockack";
168 case LOCK_AC_REQSCATTER
: return "reqscatter";
169 case LOCK_AC_REQUNSCATTER
: return "requnscatter";
170 case LOCK_AC_NUDGE
: return "nudge";
171 case LOCK_AC_REQRDLOCK
: return "reqrdlock";
172 default: return "???";
176 SimpleLock(MDSCacheObject
*o
, LockType
*lt
) :
180 virtual ~SimpleLock() {}
182 client_t
get_excl_client() const {
183 return have_more() ? more()->excl_client
: -1;
185 void set_excl_client(client_t c
) {
186 if (c
< 0 && !have_more())
187 return; // default is -1
188 more()->excl_client
= c
;
191 virtual bool is_scatterlock() const {
194 virtual bool is_locallock() const {
199 MDSCacheObject
*get_parent() { return parent
; }
200 int get_type() const { return type
->type
; }
201 const sm_t
* get_sm() const { return type
->sm
; }
203 int get_wait_shift() const;
204 int get_cap_shift() const;
205 int get_cap_mask() const;
207 void decode_locked_state(const ceph::buffer::list
& bl
) {
208 parent
->decode_lock_state(type
->type
, bl
);
210 void encode_locked_state(ceph::buffer::list
& bl
) {
211 parent
->encode_lock_state(type
->type
, bl
);
213 void finish_waiters(uint64_t mask
, int r
=0) {
214 parent
->finish_waiting(mask
<< get_wait_shift(), r
);
216 void take_waiting(uint64_t mask
, MDSContext::vec
& ls
) {
217 parent
->take_waiting(mask
<< get_wait_shift(), ls
);
219 void add_waiter(uint64_t mask
, MDSContext
*c
) {
220 parent
->add_waiter((mask
<< get_wait_shift()) | MDSCacheObject::WAIT_ORDERED
, c
);
222 bool is_waiter_for(uint64_t mask
) const {
223 return parent
->is_waiter_for(mask
<< get_wait_shift());
226 bool is_cached() const {
227 return state_flags
& CACHED
;
229 void add_cache(MDLockCacheItem
& item
);
230 void remove_cache(MDLockCacheItem
& item
);
231 std::vector
<MDLockCache
*> get_active_caches();
234 int get_state() const { return state
; }
235 int set_state(int s
) {
237 //assert(!is_stable() || gather_set.size() == 0); // gather should be empty in stable states.
240 void set_state_rejoin(int s
, MDSContext::vec
& waiters
, bool survivor
) {
241 ceph_assert(!get_parent()->is_auth());
243 // If lock in the replica object was not in SYNC state when auth mds of the object failed.
244 // Auth mds of the object may take xlock on the lock and change the object when replaying
246 if (!survivor
|| state
!= LOCK_SYNC
)
252 take_waiting(SimpleLock::WAIT_ALL
, waiters
);
255 bool is_stable() const {
256 return get_sm()->states
[state
].next
== 0;
258 bool is_unstable_and_locked() const {
261 return is_rdlocked() || is_wrlocked() || is_xlocked();
263 int get_next_state() {
264 return get_sm()->states
[state
].next
;
267 bool is_sync_and_unlocked() const {
269 get_state() == LOCK_SYNC
&&
277 bool fw_rdlock_to_auth() {
278 return get_sm()->states[state].can_rdlock == FW;
281 bool req_rdlock_from_auth() {
282 return get_sm()->states
[state
].can_rdlock
== REQ
;
286 static std::set
<int32_t> empty_gather_set
;
288 // int32_t: <0 is client, >=0 is MDS rank
289 const std::set
<int32_t>& get_gather_set() const {
290 return have_more() ? more()->gather_set
: empty_gather_set
;
294 for (const auto& p
: parent
->get_replicas()) {
295 more()->gather_set
.insert(p
.first
);
298 bool is_gathering() const {
299 return have_more() && !more()->gather_set
.empty();
301 bool is_gathering(int32_t i
) const {
302 return have_more() && more()->gather_set
.count(i
);
304 void clear_gather() {
306 more()->gather_set
.clear();
308 void remove_gather(int32_t i
) {
310 more()->gather_set
.erase(i
);
313 virtual bool is_dirty() const { return false; }
314 virtual bool is_stale() const { return false; }
315 virtual bool is_flushing() const { return false; }
316 virtual bool is_flushed() const { return false; }
317 virtual void clear_flushed() { }
320 bool can_lease(client_t client
) const {
321 return get_sm()->states
[state
].can_lease
== ANY
||
322 (get_sm()->states
[state
].can_lease
== AUTH
&& parent
->is_auth()) ||
323 (get_sm()->states
[state
].can_lease
== XCL
&& client
>= 0 && get_xlock_by_client() == client
);
325 bool can_read(client_t client
) const {
326 return get_sm()->states
[state
].can_read
== ANY
||
327 (get_sm()->states
[state
].can_read
== AUTH
&& parent
->is_auth()) ||
328 (get_sm()->states
[state
].can_read
== XCL
&& client
>= 0 && get_xlock_by_client() == client
);
330 bool can_read_projected(client_t client
) const {
331 return get_sm()->states
[state
].can_read_projected
== ANY
||
332 (get_sm()->states
[state
].can_read_projected
== AUTH
&& parent
->is_auth()) ||
333 (get_sm()->states
[state
].can_read_projected
== XCL
&& client
>= 0 && get_xlock_by_client() == client
);
335 bool can_rdlock(client_t client
) const {
336 return get_sm()->states
[state
].can_rdlock
== ANY
||
337 (get_sm()->states
[state
].can_rdlock
== AUTH
&& parent
->is_auth()) ||
338 (get_sm()->states
[state
].can_rdlock
== XCL
&& client
>= 0 && get_xlock_by_client() == client
);
340 bool can_wrlock(client_t client
) const {
341 return get_sm()->states
[state
].can_wrlock
== ANY
||
342 (get_sm()->states
[state
].can_wrlock
== AUTH
&& parent
->is_auth()) ||
343 (get_sm()->states
[state
].can_wrlock
== XCL
&& client
>= 0 && (get_xlock_by_client() == client
||
344 get_excl_client() == client
));
346 bool can_force_wrlock(client_t client
) const {
347 return get_sm()->states
[state
].can_force_wrlock
== ANY
||
348 (get_sm()->states
[state
].can_force_wrlock
== AUTH
&& parent
->is_auth()) ||
349 (get_sm()->states
[state
].can_force_wrlock
== XCL
&& client
>= 0 && (get_xlock_by_client() == client
||
350 get_excl_client() == client
));
352 bool can_xlock(client_t client
) const {
353 return get_sm()->states
[state
].can_xlock
== ANY
||
354 (get_sm()->states
[state
].can_xlock
== AUTH
&& parent
->is_auth()) ||
355 (get_sm()->states
[state
].can_xlock
== XCL
&& client
>= 0 && get_xlock_by_client() == client
);
359 bool is_rdlocked() const { return num_rdlock
> 0; }
362 parent
->get(MDSCacheObject::PIN_LOCK
);
366 ceph_assert(num_rdlock
>0);
369 parent
->put(MDSCacheObject::PIN_LOCK
);
372 int get_num_rdlocks() const {
377 void get_wrlock(bool force
=false) {
378 //assert(can_wrlock() || force);
379 if (more()->num_wrlock
== 0)
380 parent
->get(MDSCacheObject::PIN_LOCK
);
381 ++more()->num_wrlock
;
384 --more()->num_wrlock
;
385 if (more()->num_wrlock
== 0) {
386 parent
->put(MDSCacheObject::PIN_LOCK
);
390 bool is_wrlocked() const {
391 return have_more() && more()->num_wrlock
> 0;
393 int get_num_wrlocks() const {
394 return have_more() ? more()->num_wrlock
: 0;
398 void get_xlock(MutationRef who
, client_t client
) {
399 ceph_assert(get_xlock_by() == MutationRef());
400 ceph_assert(state
== LOCK_XLOCK
|| is_locallock() ||
401 state
== LOCK_LOCK
/* if we are a peer */);
402 parent
->get(MDSCacheObject::PIN_LOCK
);
404 more()->xlock_by
= who
;
405 more()->xlock_by_client
= client
;
407 void set_xlock_done() {
408 ceph_assert(more()->xlock_by
);
409 ceph_assert(state
== LOCK_XLOCK
|| is_locallock() ||
410 state
== LOCK_LOCK
/* if we are a peer */);
412 state
= LOCK_XLOCKDONE
;
413 more()->xlock_by
.reset();
416 ceph_assert(state
== LOCK_XLOCK
|| state
== LOCK_XLOCKDONE
||
417 state
== LOCK_XLOCKSNAP
|| state
== LOCK_LOCK_XLOCK
||
418 state
== LOCK_LOCK
|| /* if we are a leader of a peer */
421 parent
->put(MDSCacheObject::PIN_LOCK
);
422 if (more()->num_xlock
== 0) {
423 more()->xlock_by
.reset();
424 more()->xlock_by_client
= -1;
428 bool is_xlocked() const {
429 return have_more() && more()->num_xlock
> 0;
431 int get_num_xlocks() const {
432 return have_more() ? more()->num_xlock
: 0;
434 client_t
get_xlock_by_client() const {
435 return have_more() ? more()->xlock_by_client
: -1;
437 bool is_xlocked_by_client(client_t c
) const {
438 return have_more() ? more()->xlock_by_client
== c
: false;
440 MutationRef
get_xlock_by() const {
441 return have_more() ? more()->xlock_by
: MutationRef();
445 bool is_leased() const {
446 return state_flags
& LEASED
;
448 void get_client_lease() {
449 ceph_assert(!is_leased());
450 state_flags
|= LEASED
;
452 void put_client_lease() {
453 ceph_assert(is_leased());
454 state_flags
&= ~LEASED
;
457 bool needs_recover() const {
458 return state_flags
& NEED_RECOVER
;
460 void mark_need_recover() {
461 state_flags
|= NEED_RECOVER
;
463 void clear_need_recover() {
464 state_flags
&= ~NEED_RECOVER
;
468 void encode(ceph::buffer::list
& bl
) const {
469 ENCODE_START(2, 2, bl
);
472 encode(more()->gather_set
, bl
);
474 encode(empty_gather_set
, bl
);
477 void decode(ceph::buffer::list::const_iterator
& p
) {
483 more()->gather_set
.swap(g
);
486 void encode_state_for_replica(ceph::buffer::list
& bl
) const {
487 __s16 s
= get_replica_state();
491 void decode_state(ceph::buffer::list::const_iterator
& p
, bool is_new
=true) {
498 void decode_state_rejoin(ceph::buffer::list::const_iterator
& p
, MDSContext::vec
& waiters
, bool survivor
) {
502 set_state_rejoin(s
, waiters
, survivor
);
506 bool is_loner_mode() const {
507 return get_sm()->states
[state
].loner
;
509 int gcaps_allowed_ever() const {
510 return parent
->is_auth() ? get_sm()->allowed_ever_auth
: get_sm()->allowed_ever_replica
;
512 int gcaps_allowed(int who
, int s
=-1) const {
513 if (s
< 0) s
= state
;
514 if (parent
->is_auth()) {
515 if (get_xlock_by_client() >= 0 && who
== CAP_XLOCKER
)
516 return get_sm()->states
[s
].xlocker_caps
| get_sm()->states
[s
].caps
; // xlocker always gets more
517 else if (is_loner_mode() && who
== CAP_ANY
)
518 return get_sm()->states
[s
].caps
;
520 return get_sm()->states
[s
].loner_caps
| get_sm()->states
[s
].caps
; // loner always gets more
522 return get_sm()->states
[s
].replica_caps
;
524 int gcaps_careful() const {
525 if (get_num_wrlocks())
526 return get_sm()->careful
;
530 int gcaps_xlocker_mask(client_t client
) const {
531 if (client
== get_xlock_by_client())
532 return type
->type
== CEPH_LOCK_IFILE
? 0xf : (CEPH_CAP_GSHARED
|CEPH_CAP_GEXCL
);
536 // simplelock specifics
537 int get_replica_state() const {
538 return get_sm()->states
[state
].replica_state
;
540 void export_twiddle() {
542 state
= get_replica_state();
545 bool remove_replica(int from
) {
546 if (is_gathering(from
)) {
553 bool do_import(int from
, int to
) {
560 if (!is_stable() && !is_gathering())
565 void _print(std::ostream
& out
) const {
566 out
<< get_lock_type_name(get_type()) << " ";
567 out
<< get_state_name(get_state());
568 if (!get_gather_set().empty())
569 out
<< " g=" << get_gather_set();
573 out
<< " r=" << get_num_rdlocks();
575 out
<< " w=" << get_num_wrlocks();
577 out
<< " x=" << get_num_xlocks();
579 out
<< " by " << get_xlock_by();
589 * Write bare values (caller must be in an object section)
590 * to formatter, or nothing if is_sync_and_unlocked.
592 void dump(ceph::Formatter
*f
) const;
594 virtual void print(std::ostream
& out
) const {
603 // parent (what i lock)
604 MDSCacheObject
*parent
;
607 __s16 state
= LOCK_SYNC
;
608 __s16 state_flags
= 0;
612 NEED_RECOVER
= 1 << 1,
617 // XXX not in mempool
618 struct unstable_bits_t
{
623 gather_set
.empty() &&
626 xlock_by
.get() == NULL
&&
627 xlock_by_client
== -1 &&
632 std::set
<__s32
> gather_set
; // auth+rep. >= 0 is mds, < 0 is client
635 int num_wrlock
= 0, num_xlock
= 0;
636 MutationRef xlock_by
;
637 client_t xlock_by_client
= -1;
638 client_t excl_client
= -1;
640 elist
<MDLockCacheItem
*> lock_caches
;
643 bool have_more() const { return _unstable
? true : false; }
644 unstable_bits_t
*more() const {
646 _unstable
.reset(new unstable_bits_t
);
647 return _unstable
.get();
649 void try_clear_more() {
650 if (_unstable
&& _unstable
->empty()) {
657 mutable std::unique_ptr
<unstable_bits_t
> _unstable
;
659 WRITE_CLASS_ENCODER(SimpleLock
)
661 inline std::ostream
& operator<<(std::ostream
& out
, const SimpleLock
& l
)