]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/CDir.h
update sources to v12.2.1
[ceph.git] / ceph / src / mds / CDir.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
17 #ifndef CEPH_CDIR_H
18 #define CEPH_CDIR_H
19
20 #include "include/counter.h"
21 #include "include/types.h"
22 #include "include/buffer_fwd.h"
23 #include "common/bloom_filter.hpp"
24 #include "common/config.h"
25 #include "common/DecayCounter.h"
26
27 #include "MDSCacheObject.h"
28
29 #include <iosfwd>
30
31 #include <list>
32 #include <set>
33 #include <map>
34 #include <string>
35
36
37 #include "CInode.h"
38
39 class CDentry;
40 class MDCache;
41
42 struct ObjectOperation;
43
44 ostream& operator<<(ostream& out, const class CDir& dir);
45 class CDir : public MDSCacheObject, public Counter<CDir> {
46 friend ostream& operator<<(ostream& out, const class CDir& dir);
47
48 public:
49 MEMPOOL_CLASS_HELPERS();
50 // -- pins --
51 static const int PIN_DNWAITER = 1;
52 static const int PIN_INOWAITER = 2;
53 static const int PIN_CHILD = 3;
54 static const int PIN_FROZEN = 4;
55 static const int PIN_SUBTREE = 5;
56 static const int PIN_IMPORTING = 7;
57 static const int PIN_IMPORTBOUND = 9;
58 static const int PIN_EXPORTBOUND = 10;
59 static const int PIN_STICKY = 11;
60 static const int PIN_SUBTREETEMP = 12; // used by MDCache::trim_non_auth()
61 const char *pin_name(int p) const override {
62 switch (p) {
63 case PIN_DNWAITER: return "dnwaiter";
64 case PIN_INOWAITER: return "inowaiter";
65 case PIN_CHILD: return "child";
66 case PIN_FROZEN: return "frozen";
67 case PIN_SUBTREE: return "subtree";
68 case PIN_IMPORTING: return "importing";
69 case PIN_IMPORTBOUND: return "importbound";
70 case PIN_EXPORTBOUND: return "exportbound";
71 case PIN_STICKY: return "sticky";
72 case PIN_SUBTREETEMP: return "subtreetemp";
73 default: return generic_pin_name(p);
74 }
75 }
76
77 // -- state --
78 static const unsigned STATE_COMPLETE = (1<< 1); // the complete contents are in cache
79 static const unsigned STATE_FROZENTREE = (1<< 2); // root of tree (bounded by exports)
80 static const unsigned STATE_FREEZINGTREE = (1<< 3); // in process of freezing
81 static const unsigned STATE_FROZENDIR = (1<< 4);
82 static const unsigned STATE_FREEZINGDIR = (1<< 5);
83 static const unsigned STATE_COMMITTING = (1<< 6); // mid-commit
84 static const unsigned STATE_FETCHING = (1<< 7); // currenting fetching
85 static const unsigned STATE_CREATING = (1<< 8);
86 static const unsigned STATE_IMPORTBOUND = (1<<10);
87 static const unsigned STATE_EXPORTBOUND = (1<<11);
88 static const unsigned STATE_EXPORTING = (1<<12);
89 static const unsigned STATE_IMPORTING = (1<<13);
90 static const unsigned STATE_FRAGMENTING = (1<<14);
91 static const unsigned STATE_STICKY = (1<<15); // sticky pin due to inode stickydirs
92 static const unsigned STATE_DNPINNEDFRAG = (1<<16); // dir is refragmenting
93 static const unsigned STATE_ASSIMRSTAT = (1<<17); // assimilating inode->frag rstats
94 static const unsigned STATE_DIRTYDFT = (1<<18); // dirty dirfragtree
95 static const unsigned STATE_BADFRAG = (1<<19); // bad dirfrag
96 static const unsigned STATE_AUXSUBTREE = (1<<20); // no subtree merge
97
98 // common states
99 static const unsigned STATE_CLEAN = 0;
100 static const unsigned STATE_INITIAL = 0;
101
102 // these state bits are preserved by an import/export
103 // ...except if the directory is hashed, in which case none of them are!
104 static const unsigned MASK_STATE_EXPORTED =
105 (STATE_COMPLETE|STATE_DIRTY|STATE_DIRTYDFT|STATE_BADFRAG);
106 static const unsigned MASK_STATE_IMPORT_KEPT =
107 (
108 STATE_IMPORTING
109 |STATE_IMPORTBOUND|STATE_EXPORTBOUND
110 |STATE_FROZENTREE
111 |STATE_STICKY);
112 static const unsigned MASK_STATE_EXPORT_KEPT =
113 (STATE_EXPORTING
114 |STATE_IMPORTBOUND|STATE_EXPORTBOUND
115 |STATE_FROZENTREE
116 |STATE_FROZENDIR
117 |STATE_STICKY);
118 static const unsigned MASK_STATE_FRAGMENT_KEPT =
119 (STATE_DIRTY|
120 STATE_EXPORTBOUND |
121 STATE_IMPORTBOUND |
122 STATE_AUXSUBTREE |
123 STATE_REJOINUNDEF);
124
125 // -- rep spec --
126 static const int REP_NONE = 0;
127 static const int REP_ALL = 1;
128 static const int REP_LIST = 2;
129
130
131 static const unsigned EXPORT_NONCE = 1;
132
133
134 // -- wait masks --
135 static const uint64_t WAIT_DENTRY = (1<<0); // wait for item to be in cache
136 static const uint64_t WAIT_COMPLETE = (1<<1); // wait for complete dir contents
137 static const uint64_t WAIT_FROZEN = (1<<2); // auth pins removed
138 static const uint64_t WAIT_CREATED = (1<<3); // new dirfrag is logged
139
140 static const int WAIT_DNLOCK_OFFSET = 4;
141
142 static const uint64_t WAIT_ANY_MASK = (uint64_t)(-1);
143 static const uint64_t WAIT_ATFREEZEROOT = (WAIT_UNFREEZE);
144 static const uint64_t WAIT_ATSUBTREEROOT = (WAIT_SINGLEAUTH);
145
146
147
148
149 public:
150 // context
151 MDCache *cache;
152
153 CInode *inode; // my inode
154 frag_t frag; // my frag
155
156 bool is_lt(const MDSCacheObject *r) const override {
157 return dirfrag() < (static_cast<const CDir*>(r))->dirfrag();
158 }
159
160 fnode_t fnode;
161 snapid_t first;
162 compact_map<snapid_t,old_rstat_t> dirty_old_rstat; // [value.first,key]
163
164 // my inodes with dirty rstat data
165 elist<CInode*> dirty_rstat_inodes;
166
167 void resync_accounted_fragstat();
168 void resync_accounted_rstat();
169 void assimilate_dirty_rstat_inodes();
170 void assimilate_dirty_rstat_inodes_finish(MutationRef& mut, EMetaBlob *blob);
171
172 protected:
173 version_t projected_version;
174 std::list<fnode_t*> projected_fnode;
175
176 public:
177 elist<CDir*>::item item_dirty, item_new;
178
179
180 public:
181 version_t get_version() const { return fnode.version; }
182 void set_version(version_t v) {
183 assert(projected_fnode.empty());
184 projected_version = fnode.version = v;
185 }
186 version_t get_projected_version() const { return projected_version; }
187
188 const fnode_t *get_projected_fnode() const {
189 if (projected_fnode.empty())
190 return &fnode;
191 else
192 return projected_fnode.back();
193 }
194
195 fnode_t *get_projected_fnode() {
196 if (projected_fnode.empty())
197 return &fnode;
198 else
199 return projected_fnode.back();
200 }
201 fnode_t *project_fnode();
202
203 void pop_and_dirty_projected_fnode(LogSegment *ls);
204 bool is_projected() const { return !projected_fnode.empty(); }
205 version_t pre_dirty(version_t min=0);
206 void _mark_dirty(LogSegment *ls);
207 void _set_dirty_flag() {
208 if (!state_test(STATE_DIRTY)) {
209 state_set(STATE_DIRTY);
210 get(PIN_DIRTY);
211 }
212 }
213 void mark_dirty(version_t pv, LogSegment *ls);
214 void mark_clean();
215
216 bool is_new() { return item_new.is_on_list(); }
217 void mark_new(LogSegment *ls);
218
219 bool is_bad() { return state_test(STATE_BADFRAG); }
220 private:
221 void log_mark_dirty();
222
223 public:
224 typedef std::map<dentry_key_t, CDentry*> map_t;
225
226 class scrub_info_t {
227 public:
228 /// inodes we contain with dirty scrub stamps
229 map<dentry_key_t,CInode*> dirty_scrub_stamps; // TODO: make use of this!
230 struct scrub_stamps {
231 version_t version;
232 utime_t time;
233 scrub_stamps() : version(0) {}
234 void operator=(const scrub_stamps &o) {
235 version = o.version;
236 time = o.time;
237 }
238 };
239
240 scrub_stamps recursive_start; // when we last started a recursive scrub
241 scrub_stamps last_recursive; // when we last finished a recursive scrub
242 scrub_stamps last_local; // when we last did a local scrub
243
244 bool directory_scrubbing; /// safety check
245 bool need_scrub_local;
246 bool last_scrub_dirty; /// is scrub info dirty or is it flushed to fnode?
247 bool pending_scrub_error;
248
249 /// these are lists of children in each stage of scrubbing
250 set<dentry_key_t> directories_to_scrub;
251 set<dentry_key_t> directories_scrubbing;
252 set<dentry_key_t> directories_scrubbed;
253 set<dentry_key_t> others_to_scrub;
254 set<dentry_key_t> others_scrubbing;
255 set<dentry_key_t> others_scrubbed;
256
257 ScrubHeaderRefConst header;
258
259 scrub_info_t() :
260 directory_scrubbing(false),
261 need_scrub_local(false),
262 last_scrub_dirty(false),
263 pending_scrub_error(false) {}
264 };
265 /**
266 * Call to start this CDir on a new scrub.
267 * @pre It is not currently scrubbing
268 * @pre The CDir is marked complete.
269 * @post It has set up its internal scrubbing state.
270 */
271 void scrub_initialize(const ScrubHeaderRefConst& header);
272 /**
273 * Get the next dentry to scrub. Gives you a CDentry* and its meaning. This
274 * function will give you all directory-representing dentries before any
275 * others.
276 * 0: success, you should scrub this CDentry right now
277 * EAGAIN: is currently fetching the next CDentry into memory for you.
278 * It will activate your callback when done; try again when it does!
279 * ENOENT: there are no remaining dentries to scrub
280 * <0: There was an unexpected error
281 *
282 * @param cb An MDSInternalContext which will be activated only if
283 * we return EAGAIN via rcode, or else ignored
284 * @param dnout CDentry * which you should next scrub, or NULL
285 * @returns a value as described above
286 */
287 int scrub_dentry_next(MDSInternalContext *cb, CDentry **dnout);
288 /**
289 * Get the currently scrubbing dentries. When returned, the passed-in
290 * list will be filled with all CDentry * which have been returned
291 * from scrub_dentry_next() but not sent back via scrub_dentry_finished().
292 */
293 void scrub_dentries_scrubbing(list<CDentry*> *out_dentries);
294 /**
295 * Report to the CDir that a CDentry has been scrubbed. Call this
296 * for every CDentry returned from scrub_dentry_next().
297 * @param dn The CDentry which has been scrubbed.
298 */
299 void scrub_dentry_finished(CDentry *dn);
300 /**
301 * Call this once all CDentries have been scrubbed, according to
302 * scrub_dentry_next's listing. It finalizes the scrub statistics.
303 */
304 void scrub_finished();
305 /**
306 * Tell the CDir to do a local scrub of itself.
307 * @pre The CDir is_complete().
308 * @returns true if the rstats and directory contents match, false otherwise.
309 */
310 bool scrub_local();
311 private:
312 /**
313 * Create a scrub_info_t struct for the scrub_infop pointer.
314 */
315 void scrub_info_create() const;
316 /**
317 * Delete the scrub_infop if it's not got any useful data.
318 */
319 void scrub_maybe_delete_info();
320 /**
321 * Check the given set (presumably one of those in scrub_info_t) for the
322 * next key to scrub and look it up (or fail!).
323 */
324 int _next_dentry_on_set(set<dentry_key_t>& dns, bool missing_okay,
325 MDSInternalContext *cb, CDentry **dnout);
326
327
328 protected:
329 std::unique_ptr<scrub_info_t> scrub_infop;
330
331 // contents of this directory
332 map_t items; // non-null AND null
333 unsigned num_head_items;
334 unsigned num_head_null;
335 unsigned num_snap_items;
336 unsigned num_snap_null;
337
338 int num_dirty;
339
340 // state
341 version_t committing_version;
342 version_t committed_version;
343
344 compact_set<string> stale_items;
345
346 // lock nesting, freeze
347 static int num_frozen_trees;
348 static int num_freezing_trees;
349
350 int dir_auth_pins;
351 int request_pins;
352
353 // cache control (defined for authority; hints for replicas)
354 __s32 dir_rep;
355 compact_set<__s32> dir_rep_by; // if dir_rep == REP_LIST
356
357 // popularity
358 dirfrag_load_vec_t pop_me;
359 dirfrag_load_vec_t pop_nested;
360 dirfrag_load_vec_t pop_auth_subtree;
361 dirfrag_load_vec_t pop_auth_subtree_nested;
362
363 utime_t last_popularity_sample;
364
365 load_spread_t pop_spread;
366
367 // and to provide density
368 int num_dentries_nested;
369 int num_dentries_auth_subtree;
370 int num_dentries_auth_subtree_nested;
371
372
373 // friends
374 friend class Migrator;
375 friend class CInode;
376 friend class MDCache;
377 friend class MDiscover;
378 friend class MDBalancer;
379
380 friend class CDirDiscover;
381 friend class CDirExport;
382 friend class C_IO_Dir_TMAP_Fetched;
383 friend class C_IO_Dir_OMAP_Fetched;
384 friend class C_IO_Dir_OMAP_FetchedMore;
385 friend class C_IO_Dir_Committed;
386
387 std::unique_ptr<bloom_filter> bloom;
388 /* If you set up the bloom filter, you must keep it accurate!
389 * It's deleted when you mark_complete() and is deliberately not serialized.*/
390
391 public:
392 CDir(CInode *in, frag_t fg, MDCache *mdcache, bool auth);
393
394 const scrub_info_t *scrub_info() const {
395 if (!scrub_infop) {
396 scrub_info_create();
397 }
398 return scrub_infop.get();
399 }
400
401
402 // -- accessors --
403 inodeno_t ino() const { return inode->ino(); } // deprecate me?
404 frag_t get_frag() const { return frag; }
405 dirfrag_t dirfrag() const { return dirfrag_t(inode->ino(), frag); }
406
407 CInode *get_inode() { return inode; }
408 const CInode *get_inode() const { return inode; }
409 CDir *get_parent_dir() { return inode->get_parent_dir(); }
410
411 map_t::iterator begin() { return items.begin(); }
412 map_t::iterator end() { return items.end(); }
413 map_t::iterator lower_bound(dentry_key_t key) { return items.lower_bound(key); }
414
415 unsigned get_num_head_items() const { return num_head_items; }
416 unsigned get_num_head_null() const { return num_head_null; }
417 unsigned get_num_snap_items() const { return num_snap_items; }
418 unsigned get_num_snap_null() const { return num_snap_null; }
419 unsigned get_num_any() const { return num_head_items + num_head_null + num_snap_items + num_snap_null; }
420
421 bool check_rstats(bool scrub=false);
422
423 void inc_num_dirty() { num_dirty++; }
424 void dec_num_dirty() {
425 assert(num_dirty > 0);
426 num_dirty--;
427 }
428 int get_num_dirty() const {
429 return num_dirty;
430 }
431
432 int64_t get_frag_size() const {
433 return get_projected_fnode()->fragstat.size();
434 }
435
436 // -- dentries and inodes --
437 public:
438 CDentry* lookup_exact_snap(const std::string& dname, snapid_t last);
439 CDentry* lookup(const std::string& n, snapid_t snap=CEPH_NOSNAP);
440 CDentry* lookup(const char *n, snapid_t snap=CEPH_NOSNAP) {
441 return lookup(std::string(n), snap);
442 }
443
444 CDentry* add_null_dentry(const std::string& dname,
445 snapid_t first=2, snapid_t last=CEPH_NOSNAP);
446 CDentry* add_primary_dentry(const std::string& dname, CInode *in,
447 snapid_t first=2, snapid_t last=CEPH_NOSNAP);
448 CDentry* add_remote_dentry(const std::string& dname, inodeno_t ino, unsigned char d_type,
449 snapid_t first=2, snapid_t last=CEPH_NOSNAP);
450 void remove_dentry( CDentry *dn ); // delete dentry
451 void link_remote_inode( CDentry *dn, inodeno_t ino, unsigned char d_type);
452 void link_remote_inode( CDentry *dn, CInode *in );
453 void link_primary_inode( CDentry *dn, CInode *in );
454 void unlink_inode(CDentry *dn, bool adjust_lru=true);
455 void try_remove_unlinked_dn(CDentry *dn);
456
457 void add_to_bloom(CDentry *dn);
458 bool is_in_bloom(const std::string& name);
459 bool has_bloom() { return (bloom ? true : false); }
460 void remove_bloom() {
461 bloom.reset();
462 }
463 private:
464 void link_inode_work( CDentry *dn, CInode *in );
465 void unlink_inode_work( CDentry *dn );
466 void remove_null_dentries();
467 void purge_stale_snap_data(const std::set<snapid_t>& snaps);
468 public:
469 void try_remove_dentries_for_stray();
470 bool try_trim_snap_dentry(CDentry *dn, const std::set<snapid_t>& snaps);
471
472
473 public:
474 void split(int bits, list<CDir*>& subs, list<MDSInternalContextBase*>& waiters, bool replay);
475 void merge(list<CDir*>& subs, list<MDSInternalContextBase*>& waiters, bool replay);
476
477 bool should_split() const {
478 return (int)get_frag_size() > g_conf->mds_bal_split_size;
479 }
480 bool should_split_fast() const;
481 bool should_merge() const {
482 return (int)get_frag_size() < g_conf->mds_bal_merge_size;
483 }
484
485 private:
486 void prepare_new_fragment(bool replay);
487 void prepare_old_fragment(map<string_snap_t, std::list<MDSInternalContextBase*> >& dentry_waiters, bool replay);
488 void steal_dentry(CDentry *dn); // from another dir. used by merge/split.
489 void finish_old_fragment(list<MDSInternalContextBase*>& waiters, bool replay);
490 void init_fragment_pins();
491
492
493 // -- authority --
494 /*
495 * normal: <parent,unknown> !subtree_root
496 * delegation: <mds,unknown> subtree_root
497 * ambiguous: <mds1,mds2> subtree_root
498 * <parent,mds2> subtree_root
499 */
500 mds_authority_t dir_auth;
501
502 std::string get_path() const;
503
504 public:
505 mds_authority_t authority() const override;
506 mds_authority_t get_dir_auth() const { return dir_auth; }
507 void set_dir_auth(mds_authority_t a);
508 void set_dir_auth(mds_rank_t a) { set_dir_auth(mds_authority_t(a, CDIR_AUTH_UNKNOWN)); }
509 bool is_ambiguous_dir_auth() const {
510 return dir_auth.second != CDIR_AUTH_UNKNOWN;
511 }
512 bool is_full_dir_auth() const {
513 return is_auth() && !is_ambiguous_dir_auth();
514 }
515 bool is_full_dir_nonauth() const {
516 return !is_auth() && !is_ambiguous_dir_auth();
517 }
518
519 bool is_subtree_root() const {
520 return dir_auth != CDIR_AUTH_DEFAULT;
521 }
522
523 bool contains(CDir *x); // true if we are x or an ancestor of x
524
525
526 // for giving to clients
527 void get_dist_spec(std::set<mds_rank_t>& ls, mds_rank_t auth) {
528 if (is_rep()) {
529 list_replicas(ls);
530 if (!ls.empty())
531 ls.insert(auth);
532 }
533 }
534 void encode_dirstat(bufferlist& bl, mds_rank_t whoami) {
535 /*
536 * note: encoding matches struct ceph_client_reply_dirfrag
537 */
538 frag_t frag = get_frag();
539 mds_rank_t auth;
540 std::set<mds_rank_t> dist;
541
542 auth = dir_auth.first;
543 if (is_auth())
544 get_dist_spec(dist, whoami);
545
546 ::encode(frag, bl);
547 ::encode(auth, bl);
548 ::encode(dist, bl);
549 }
550
551 void _encode_base(bufferlist& bl) {
552 ::encode(first, bl);
553 ::encode(fnode, bl);
554 ::encode(dir_rep, bl);
555 ::encode(dir_rep_by, bl);
556 }
557 void _decode_base(bufferlist::iterator& p) {
558 ::decode(first, p);
559 ::decode(fnode, p);
560 ::decode(dir_rep, p);
561 ::decode(dir_rep_by, p);
562 }
563 void encode_replica(mds_rank_t who, bufferlist& bl) {
564 __u32 nonce = add_replica(who);
565 ::encode(nonce, bl);
566 _encode_base(bl);
567 }
568 void decode_replica(bufferlist::iterator& p) {
569 __u32 nonce;
570 ::decode(nonce, p);
571 replica_nonce = nonce;
572 _decode_base(p);
573 }
574
575
576
577 // -- state --
578 bool is_complete() { return state & STATE_COMPLETE; }
579 bool is_exporting() { return state & STATE_EXPORTING; }
580 bool is_importing() { return state & STATE_IMPORTING; }
581 bool is_dirty_dft() { return state & STATE_DIRTYDFT; }
582
583 int get_dir_rep() const { return dir_rep; }
584 bool is_rep() const {
585 if (dir_rep == REP_NONE) return false;
586 return true;
587 }
588
589 // -- fetch --
590 object_t get_ondisk_object() {
591 return file_object_t(ino(), frag);
592 }
593 void fetch(MDSInternalContextBase *c, bool ignore_authpinnability=false);
594 void fetch(MDSInternalContextBase *c, const std::string& want_dn, bool ignore_authpinnability=false);
595 void fetch(MDSInternalContextBase *c, const std::set<dentry_key_t>& keys);
596 protected:
597 compact_set<string> wanted_items;
598
599 void _omap_fetch(MDSInternalContextBase *fin, const std::set<dentry_key_t>& keys);
600 void _omap_fetch_more(
601 bufferlist& hdrbl, std::map<std::string, bufferlist>& omap,
602 MDSInternalContextBase *fin);
603 CDentry *_load_dentry(
604 const std::string &key,
605 const std::string &dname,
606 snapid_t last,
607 bufferlist &bl,
608 int pos,
609 const std::set<snapid_t> *snaps,
610 bool *force_dirty,
611 list<CInode*> *undef_inodes);
612
613 /**
614 * Mark this fragment as BADFRAG (common part of go_bad and go_bad_dentry)
615 */
616 void _go_bad();
617
618 /**
619 * Go bad due to a damaged dentry (register with damagetable and go BADFRAG)
620 */
621 void go_bad_dentry(snapid_t last, const std::string &dname);
622
623 /**
624 * Go bad due to a damaged header (register with damagetable and go BADFRAG)
625 */
626 void go_bad(bool complete);
627
628 void _omap_fetched(bufferlist& hdrbl, std::map<std::string, bufferlist>& omap,
629 bool complete, int r);
630
631 // -- commit --
632 compact_map<version_t, std::list<MDSInternalContextBase*> > waiting_for_commit;
633 void _commit(version_t want, int op_prio);
634 void _omap_commit(int op_prio);
635 void _encode_dentry(CDentry *dn, bufferlist& bl, const std::set<snapid_t> *snaps);
636 void _committed(int r, version_t v);
637 public:
638 #if 0 // unused?
639 void wait_for_commit(Context *c, version_t v=0);
640 #endif
641 void commit_to(version_t want);
642 void commit(version_t want, MDSInternalContextBase *c,
643 bool ignore_authpinnability=false, int op_prio=-1);
644
645 // -- dirtyness --
646 version_t get_committing_version() const { return committing_version; }
647 version_t get_committed_version() const { return committed_version; }
648 void set_committed_version(version_t v) { committed_version = v; }
649
650 void mark_complete();
651
652
653 // -- reference counting --
654 void first_get() override;
655 void last_put() override;
656
657 void request_pin_get() {
658 if (request_pins == 0) get(PIN_REQUEST);
659 request_pins++;
660 }
661 void request_pin_put() {
662 request_pins--;
663 if (request_pins == 0) put(PIN_REQUEST);
664 }
665
666 // -- waiters --
667 protected:
668 compact_map< string_snap_t, std::list<MDSInternalContextBase*> > waiting_on_dentry;
669
670 public:
671 bool is_waiting_for_dentry(const std::string& dname, snapid_t snap) {
672 return waiting_on_dentry.count(string_snap_t(dname, snap));
673 }
674 void add_dentry_waiter(const std::string& dentry, snapid_t snap, MDSInternalContextBase *c);
675 void take_dentry_waiting(const std::string& dentry, snapid_t first, snapid_t last, std::list<MDSInternalContextBase*>& ls);
676 void take_sub_waiting(std::list<MDSInternalContextBase*>& ls); // dentry or ino
677
678 void add_waiter(uint64_t mask, MDSInternalContextBase *c) override;
679 void take_waiting(uint64_t mask, std::list<MDSInternalContextBase*>& ls) override; // may include dentry waiters
680 void finish_waiting(uint64_t mask, int result = 0); // ditto
681
682
683 // -- import/export --
684 void encode_export(bufferlist& bl);
685 void finish_export(utime_t now);
686 void abort_export() {
687 put(PIN_TEMPEXPORTING);
688 }
689 void decode_import(bufferlist::iterator& blp, utime_t now, LogSegment *ls);
690
691 // -- auth pins --
692 bool can_auth_pin() const override { return is_auth() && !(is_frozen() || is_freezing()); }
693 int get_cum_auth_pins() const { return auth_pins + nested_auth_pins; }
694 int get_auth_pins() const { return auth_pins; }
695 int get_nested_auth_pins() const { return nested_auth_pins; }
696 int get_dir_auth_pins() const { return dir_auth_pins; }
697 void auth_pin(void *who) override;
698 void auth_unpin(void *who) override;
699
700 void adjust_nested_auth_pins(int inc, int dirinc, void *by);
701 void verify_fragstat();
702
703 // -- freezing --
704 bool freeze_tree();
705 void _freeze_tree();
706 void unfreeze_tree();
707
708 bool freeze_dir();
709 void _freeze_dir();
710 void unfreeze_dir();
711
712 void maybe_finish_freeze();
713
714 bool is_freezing() const override { return is_freezing_tree() || is_freezing_dir(); }
715 bool is_freezing_tree() const;
716 bool is_freezing_tree_root() const { return state & STATE_FREEZINGTREE; }
717 bool is_freezing_dir() const { return state & STATE_FREEZINGDIR; }
718
719 bool is_frozen() const override { return is_frozen_dir() || is_frozen_tree(); }
720 bool is_frozen_tree() const;
721 bool is_frozen_tree_root() const { return state & STATE_FROZENTREE; }
722 bool is_frozen_dir() const { return state & STATE_FROZENDIR; }
723
724 bool is_freezeable(bool freezing=false) const {
725 // no nested auth pins.
726 if ((auth_pins-freezing) > 0 || nested_auth_pins > 0)
727 return false;
728
729 // inode must not be frozen.
730 if (!is_subtree_root() && inode->is_frozen())
731 return false;
732
733 return true;
734 }
735 bool is_freezeable_dir(bool freezing=false) const {
736 if ((auth_pins-freezing) > 0 || dir_auth_pins > 0)
737 return false;
738
739 // if not subtree root, inode must not be frozen (tree--frozen_dir is okay).
740 if (!is_subtree_root() && inode->is_frozen() && !inode->is_frozen_dir())
741 return false;
742
743 return true;
744 }
745
746 CDir *get_frozen_tree_root();
747
748
749 ostream& print_db_line_prefix(ostream& out) override;
750 void print(ostream& out) override;
751 void dump(Formatter *f) const;
752 };
753
754 #endif