Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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