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.
24 #include <string_view>
26 #include "common/bloom_filter.hpp"
27 #include "common/config.h"
28 #include "include/buffer_fwd.h"
29 #include "include/counter.h"
30 #include "include/types.h"
33 #include "MDSCacheObject.h"
34 #include "MDSContext.h"
35 #include "cephfs_features.h"
36 #include "SessionMap.h"
37 #include "messages/MClientReply.h"
42 std::ostream
& operator<<(std::ostream
& out
, const class CDir
& dir
);
44 class CDir
: public MDSCacheObject
, public Counter
<CDir
> {
46 MEMPOOL_CLASS_HELPERS();
48 typedef mempool::mds_co::map
<dentry_key_t
, CDentry
*> dentry_key_map
;
49 typedef mempool::mds_co::set
<dentry_key_t
> dentry_key_set
;
51 using fnode_ptr
= std::shared_ptr
<fnode_t
>;
52 using fnode_const_ptr
= std::shared_ptr
<const fnode_t
>;
54 template <typename
...Args
>
55 static fnode_ptr
allocate_fnode(Args
&& ...args
) {
56 static mempool::mds_co::pool_allocator
<fnode_t
> allocator
;
57 return std::allocate_shared
<fnode_t
>(allocator
, std::forward
<Args
>(args
)...);
60 struct dentry_commit_item
{
63 bool is_remote
= false;
67 mempool::mds_co::string alternate_name
;
69 bool snaprealm
= false;
72 mempool::mds_co::string symlink
;
75 CInode::inode_const_ptr inode
;
76 CInode::xattr_map_const_ptr xattrs
;
77 CInode::old_inode_map_const_ptr old_inodes
;
79 damage_flags_t damage_flags
;
83 struct freeze_tree_state_t
{
84 CDir
*dir
; // freezing/frozen tree root
87 freeze_tree_state_t(CDir
*d
) : dir(d
) {}
92 MEMPOOL_CLASS_HELPERS();
94 version_t version
= 0;
100 scrub_stamps last_recursive
; // when we last finished a recursive scrub
101 scrub_stamps last_local
; // when we last did a local scrub
103 bool directory_scrubbing
= false; /// safety check
104 bool last_scrub_dirty
= false; /// is scrub info dirty or is it flushed to fnode?
106 ScrubHeaderRef header
;
110 static const int PIN_DNWAITER
= 1;
111 static const int PIN_INOWAITER
= 2;
112 static const int PIN_CHILD
= 3;
113 static const int PIN_FROZEN
= 4;
114 static const int PIN_SUBTREE
= 5;
115 static const int PIN_IMPORTING
= 7;
116 static const int PIN_IMPORTBOUND
= 9;
117 static const int PIN_EXPORTBOUND
= 10;
118 static const int PIN_STICKY
= 11;
119 static const int PIN_SUBTREETEMP
= 12; // used by MDCache::trim_non_auth()
122 static const unsigned STATE_COMPLETE
= (1<< 0); // the complete contents are in cache
123 static const unsigned STATE_FROZENTREE
= (1<< 1); // root of tree (bounded by exports)
124 static const unsigned STATE_FREEZINGTREE
= (1<< 2); // in process of freezing
125 static const unsigned STATE_FROZENDIR
= (1<< 3);
126 static const unsigned STATE_FREEZINGDIR
= (1<< 4);
127 static const unsigned STATE_COMMITTING
= (1<< 5); // mid-commit
128 static const unsigned STATE_FETCHING
= (1<< 6); // currenting fetching
129 static const unsigned STATE_CREATING
= (1<< 7);
130 static const unsigned STATE_IMPORTBOUND
= (1<< 8);
131 static const unsigned STATE_EXPORTBOUND
= (1<< 9);
132 static const unsigned STATE_EXPORTING
= (1<<10);
133 static const unsigned STATE_IMPORTING
= (1<<11);
134 static const unsigned STATE_FRAGMENTING
= (1<<12);
135 static const unsigned STATE_STICKY
= (1<<13); // sticky pin due to inode stickydirs
136 static const unsigned STATE_DNPINNEDFRAG
= (1<<14); // dir is refragmenting
137 static const unsigned STATE_ASSIMRSTAT
= (1<<15); // assimilating inode->frag rstats
138 static const unsigned STATE_DIRTYDFT
= (1<<16); // dirty dirfragtree
139 static const unsigned STATE_BADFRAG
= (1<<17); // bad dirfrag
140 static const unsigned STATE_TRACKEDBYOFT
= (1<<18); // tracked by open file table
141 static const unsigned STATE_AUXSUBTREE
= (1<<19); // no subtree merge
144 static const unsigned STATE_CLEAN
= 0;
146 // these state bits are preserved by an import/export
147 // ...except if the directory is hashed, in which case none of them are!
148 static const unsigned MASK_STATE_EXPORTED
=
149 (STATE_COMPLETE
|STATE_DIRTY
|STATE_DIRTYDFT
|STATE_BADFRAG
);
150 static const unsigned MASK_STATE_IMPORT_KEPT
=
158 static const unsigned MASK_STATE_EXPORT_KEPT
=
166 static const unsigned MASK_STATE_FRAGMENT_KEPT
=
174 static const int REP_NONE
= 0;
175 static const int REP_ALL
= 1;
176 static const int REP_LIST
= 2;
178 static const unsigned EXPORT_NONCE
= 1;
181 static const uint64_t WAIT_DENTRY
= (1<<0); // wait for item to be in cache
182 static const uint64_t WAIT_COMPLETE
= (1<<1); // wait for complete dir contents
183 static const uint64_t WAIT_FROZEN
= (1<<2); // auth pins removed
184 static const uint64_t WAIT_CREATED
= (1<<3); // new dirfrag is logged
186 static const int WAIT_DNLOCK_OFFSET
= 4;
188 static const uint64_t WAIT_ANY_MASK
= (uint64_t)(-1);
189 static const uint64_t WAIT_ATSUBTREEROOT
= (WAIT_SINGLEAUTH
);
192 static const int DUMP_PATH
= (1 << 0);
193 static const int DUMP_DIRFRAG
= (1 << 1);
194 static const int DUMP_SNAPID_FIRST
= (1 << 2);
195 static const int DUMP_VERSIONS
= (1 << 3);
196 static const int DUMP_REP
= (1 << 4);
197 static const int DUMP_DIR_AUTH
= (1 << 5);
198 static const int DUMP_STATES
= (1 << 6);
199 static const int DUMP_MDS_CACHE_OBJECT
= (1 << 7);
200 static const int DUMP_ITEMS
= (1 << 8);
201 static const int DUMP_ALL
= (-1);
202 static const int DUMP_DEFAULT
= DUMP_ALL
& (~DUMP_ITEMS
);
204 CDir(CInode
*in
, frag_t fg
, MDCache
*mdc
, bool auth
);
206 std::string_view
pin_name(int p
) const override
{
208 case PIN_DNWAITER
: return "dnwaiter";
209 case PIN_INOWAITER
: return "inowaiter";
210 case PIN_CHILD
: return "child";
211 case PIN_FROZEN
: return "frozen";
212 case PIN_SUBTREE
: return "subtree";
213 case PIN_IMPORTING
: return "importing";
214 case PIN_IMPORTBOUND
: return "importbound";
215 case PIN_EXPORTBOUND
: return "exportbound";
216 case PIN_STICKY
: return "sticky";
217 case PIN_SUBTREETEMP
: return "subtreetemp";
218 default: return generic_pin_name(p
);
222 bool is_lt(const MDSCacheObject
*r
) const override
{
223 return dirfrag() < (static_cast<const CDir
*>(r
))->dirfrag();
226 void resync_accounted_fragstat();
227 void resync_accounted_rstat();
228 void assimilate_dirty_rstat_inodes(MutationRef
& mut
);
229 void assimilate_dirty_rstat_inodes_finish(EMetaBlob
*blob
);
231 void mark_exporting() {
232 state_set(CDir::STATE_EXPORTING
);
233 inode
->num_exporting_dirs
++;
235 void clear_exporting() {
236 state_clear(CDir::STATE_EXPORTING
);
237 inode
->num_exporting_dirs
--;
240 version_t
get_version() const { return fnode
->version
; }
241 void update_projected_version() {
242 ceph_assert(projected_fnode
.empty());
243 projected_version
= fnode
->version
;
245 version_t
get_projected_version() const { return projected_version
; }
247 void reset_fnode(fnode_const_ptr
&& ptr
) {
248 fnode
= std::move(ptr
);
250 void set_fresh_fnode(fnode_const_ptr
&& ptr
);
252 const fnode_const_ptr
& get_fnode() const {
256 // only used for updating newly allocated CDir
257 fnode_t
* _get_fnode() {
258 if (fnode
== empty_fnode
)
259 reset_fnode(allocate_fnode());
260 return const_cast<fnode_t
*>(fnode
.get());
263 const fnode_const_ptr
& get_projected_fnode() const {
264 if (projected_fnode
.empty())
267 return projected_fnode
.back();
270 // fnode should have already been projected in caller's context
271 fnode_t
* _get_projected_fnode() {
272 ceph_assert(!projected_fnode
.empty());
273 return const_cast<fnode_t
*>(projected_fnode
.back().get());
276 fnode_ptr
project_fnode(const MutationRef
& mut
);
278 void pop_and_dirty_projected_fnode(LogSegment
*ls
, const MutationRef
& mut
);
279 bool is_projected() const { return !projected_fnode
.empty(); }
280 version_t
pre_dirty(version_t min
=0);
281 void _mark_dirty(LogSegment
*ls
);
282 void _set_dirty_flag() {
283 if (!state_test(STATE_DIRTY
)) {
284 state_set(STATE_DIRTY
);
288 void mark_dirty(LogSegment
*ls
, version_t pv
=0);
291 bool is_new() { return item_new
.is_on_list(); }
292 void mark_new(LogSegment
*ls
);
294 bool is_bad() { return state_test(STATE_BADFRAG
); }
297 * Call to start this CDir on a new scrub.
298 * @pre It is not currently scrubbing
299 * @pre The CDir is marked complete.
300 * @post It has set up its internal scrubbing state.
302 void scrub_initialize(const ScrubHeaderRef
& header
);
303 const ScrubHeaderRef
& get_scrub_header() {
304 static const ScrubHeaderRef nullref
;
305 return scrub_infop
? scrub_infop
->header
: nullref
;
308 bool scrub_is_in_progress() const {
309 return (scrub_infop
&& scrub_infop
->directory_scrubbing
);
313 * Call this once all CDentries have been scrubbed, according to
314 * scrub_dentry_next's listing. It finalizes the scrub statistics.
316 void scrub_finished();
318 void scrub_aborted();
320 * Tell the CDir to do a local scrub of itself.
321 * @pre The CDir is_complete().
322 * @returns true if the rstats and directory contents match, false otherwise.
326 const scrub_info_t
*scrub_info() const {
329 return scrub_infop
.get();
333 inodeno_t
ino() const { return inode
->ino(); } // deprecate me?
334 frag_t
get_frag() const { return frag
; }
335 dirfrag_t
dirfrag() const { return dirfrag_t(inode
->ino(), frag
); }
337 CInode
*get_inode() { return inode
; }
338 const CInode
*get_inode() const { return inode
; }
339 CDir
*get_parent_dir() { return inode
->get_parent_dir(); }
341 dentry_key_map::iterator
begin() { return items
.begin(); }
342 dentry_key_map::iterator
end() { return items
.end(); }
343 dentry_key_map::iterator
lower_bound(dentry_key_t key
) { return items
.lower_bound(key
); }
345 unsigned get_num_head_items() const { return num_head_items
; }
346 unsigned get_num_head_null() const { return num_head_null
; }
347 unsigned get_num_snap_items() const { return num_snap_items
; }
348 unsigned get_num_snap_null() const { return num_snap_null
; }
349 unsigned get_num_any() const { return num_head_items
+ num_head_null
+ num_snap_items
+ num_snap_null
; }
351 bool check_rstats(bool scrub
=false);
353 void inc_num_dirty() { num_dirty
++; }
354 void dec_num_dirty() {
355 ceph_assert(num_dirty
> 0);
358 int get_num_dirty() const {
362 void adjust_num_inodes_with_caps(int d
);
364 int64_t get_frag_size() const {
365 return get_projected_fnode()->fragstat
.size();
368 // -- dentries and inodes --
369 CDentry
* lookup_exact_snap(std::string_view dname
, snapid_t last
);
370 CDentry
* lookup(std::string_view n
, snapid_t snap
=CEPH_NOSNAP
);
372 CDentry
* add_null_dentry(std::string_view dname
,
373 snapid_t first
=2, snapid_t last
=CEPH_NOSNAP
);
374 CDentry
* add_primary_dentry(std::string_view dname
, CInode
*in
, mempool::mds_co::string alternate_name
,
375 snapid_t first
=2, snapid_t last
=CEPH_NOSNAP
);
376 CDentry
* add_remote_dentry(std::string_view dname
, inodeno_t ino
, unsigned char d_type
,
377 mempool::mds_co::string alternate_name
,
378 snapid_t first
=2, snapid_t last
=CEPH_NOSNAP
);
379 void remove_dentry( CDentry
*dn
); // delete dentry
380 void link_remote_inode( CDentry
*dn
, inodeno_t ino
, unsigned char d_type
);
381 void link_remote_inode( CDentry
*dn
, CInode
*in
);
382 void link_primary_inode( CDentry
*dn
, CInode
*in
);
383 void unlink_inode(CDentry
*dn
, bool adjust_lru
=true);
384 void try_remove_unlinked_dn(CDentry
*dn
);
386 void add_to_bloom(CDentry
*dn
);
387 bool is_in_bloom(std::string_view name
);
388 bool has_bloom() { return (bloom
? true : false); }
389 void remove_bloom() {
393 void try_remove_dentries_for_stray();
394 bool try_trim_snap_dentry(CDentry
*dn
, const std::set
<snapid_t
>& snaps
);
396 void split(int bits
, std::vector
<CDir
*>* subs
, MDSContext::vec
& waiters
, bool replay
);
397 void merge(const std::vector
<CDir
*>& subs
, MDSContext::vec
& waiters
, bool replay
);
399 bool should_split() const {
400 return g_conf()->mds_bal_split_size
> 0 &&
401 (int)get_frag_size() > g_conf()->mds_bal_split_size
;
403 bool should_split_fast() const;
404 bool should_merge() const;
406 mds_authority_t
authority() const override
;
407 mds_authority_t
get_dir_auth() const { return dir_auth
; }
408 void set_dir_auth(const mds_authority_t
&a
);
409 void set_dir_auth(mds_rank_t a
) { set_dir_auth(mds_authority_t(a
, CDIR_AUTH_UNKNOWN
)); }
410 bool is_ambiguous_dir_auth() const {
411 return dir_auth
.second
!= CDIR_AUTH_UNKNOWN
;
413 bool is_full_dir_auth() const {
414 return is_auth() && !is_ambiguous_dir_auth();
416 bool is_full_dir_nonauth() const {
417 return !is_auth() && !is_ambiguous_dir_auth();
420 bool is_subtree_root() const {
421 return dir_auth
!= CDIR_AUTH_DEFAULT
;
424 bool contains(CDir
*x
); // true if we are x or an ancestor of x
426 // for giving to clients
427 void get_dist_spec(std::set
<mds_rank_t
>& ls
, mds_rank_t auth
) {
435 static void encode_dirstat(ceph::buffer::list
& bl
, const session_info_t
& info
, const DirStat
& ds
);
437 void _encode_base(ceph::buffer::list
& bl
) {
438 ENCODE_START(1, 1, bl
);
442 encode(dir_rep_by
, bl
);
445 void _decode_base(ceph::buffer::list::const_iterator
& p
) {
449 auto _fnode
= allocate_fnode();
451 reset_fnode(std::move(_fnode
));
454 decode(dir_rep_by
, p
);
459 bool is_complete() { return state
& STATE_COMPLETE
; }
460 bool is_exporting() { return state
& STATE_EXPORTING
; }
461 bool is_importing() { return state
& STATE_IMPORTING
; }
462 bool is_dirty_dft() { return state
& STATE_DIRTYDFT
; }
464 int get_dir_rep() const { return dir_rep
; }
465 bool is_rep() const {
466 if (dir_rep
== REP_NONE
) return false;
469 bool can_rep() const;
472 object_t
get_ondisk_object() {
473 return file_object_t(ino(), frag
);
475 void fetch(MDSContext
*c
, bool ignore_authpinnability
=false);
476 void fetch(MDSContext
*c
, std::string_view want_dn
, bool ignore_authpinnability
=false);
477 void fetch(MDSContext
*c
, const std::set
<dentry_key_t
>& keys
);
480 void wait_for_commit(Context
*c
, version_t v
=0);
482 void commit_to(version_t want
);
483 void commit(version_t want
, MDSContext
*c
,
484 bool ignore_authpinnability
=false, int op_prio
=-1);
487 version_t
get_committing_version() const { return committing_version
; }
488 version_t
get_committed_version() const { return committed_version
; }
489 void set_committed_version(version_t v
) { committed_version
= v
; }
491 void mark_complete();
493 // -- reference counting --
494 void first_get() override
;
495 void last_put() override
;
497 bool is_waiting_for_dentry(std::string_view dname
, snapid_t snap
) {
498 return waiting_on_dentry
.count(string_snap_t(dname
, snap
));
500 void add_dentry_waiter(std::string_view dentry
, snapid_t snap
, MDSContext
*c
);
501 void take_dentry_waiting(std::string_view dentry
, snapid_t first
, snapid_t last
, MDSContext::vec
& ls
);
502 void take_sub_waiting(MDSContext::vec
& ls
); // dentry or ino
504 void add_waiter(uint64_t mask
, MDSContext
*c
) override
;
505 void take_waiting(uint64_t mask
, MDSContext::vec
& ls
) override
; // may include dentry waiters
506 void finish_waiting(uint64_t mask
, int result
= 0); // ditto
508 // -- import/export --
509 mds_rank_t
get_export_pin(bool inherit
=true) const;
510 bool is_exportable(mds_rank_t dest
) const;
512 void encode_export(ceph::buffer::list
& bl
);
513 void finish_export();
514 void abort_export() {
515 put(PIN_TEMPEXPORTING
);
517 void decode_import(ceph::buffer::list::const_iterator
& blp
, LogSegment
*ls
);
521 bool can_auth_pin(int *err_ret
=nullptr) const override
;
522 int get_auth_pins() const { return auth_pins
; }
523 int get_dir_auth_pins() const { return dir_auth_pins
; }
524 void auth_pin(void *who
) override
;
525 void auth_unpin(void *who
) override
;
527 void adjust_nested_auth_pins(int dirinc
, void *by
);
528 void verify_fragstat();
530 void _walk_tree(std::function
<bool(CDir
*)> cb
);
534 void unfreeze_tree();
535 void adjust_freeze_after_rename(CDir
*dir
);
541 void maybe_finish_freeze();
543 std::pair
<bool,bool> is_freezing_or_frozen_tree() const {
544 if (freeze_tree_state
) {
545 if (freeze_tree_state
->frozen
)
546 return std::make_pair(false, true);
547 return std::make_pair(true, false);
549 return std::make_pair(false, false);
552 bool is_freezing() const override
{ return is_freezing_dir() || is_freezing_tree(); }
553 bool is_freezing_tree() const {
554 if (!num_freezing_trees
)
556 return is_freezing_or_frozen_tree().first
;
558 bool is_freezing_tree_root() const { return state
& STATE_FREEZINGTREE
; }
559 bool is_freezing_dir() const { return state
& STATE_FREEZINGDIR
; }
561 bool is_frozen() const override
{ return is_frozen_dir() || is_frozen_tree(); }
562 bool is_frozen_tree() const {
563 if (!num_frozen_trees
)
565 return is_freezing_or_frozen_tree().second
;
567 bool is_frozen_tree_root() const { return state
& STATE_FROZENTREE
; }
568 bool is_frozen_dir() const { return state
& STATE_FROZENDIR
; }
570 bool is_freezeable(bool freezing
=false) const {
571 // no nested auth pins.
572 if (auth_pins
- (freezing
? 1 : 0) > 0 ||
573 (freeze_tree_state
&& freeze_tree_state
->auth_pins
!= auth_pins
))
576 // inode must not be frozen.
577 if (!is_subtree_root() && inode
->is_frozen())
583 bool is_freezeable_dir(bool freezing
=false) const {
584 if ((auth_pins
- freezing
) > 0 || dir_auth_pins
> 0)
587 // if not subtree root, inode must not be frozen (tree--frozen_dir is okay).
588 if (!is_subtree_root() && inode
->is_frozen() && !inode
->is_frozen_dir())
594 bool is_any_freezing_or_frozen_inode() const {
595 return num_frozen_inodes
|| !freezing_inodes
.empty();
597 bool is_auth_pinned_by_lock_cache() const {
598 return frozen_inode_suppressed
;
600 void disable_frozen_inode() {
601 ceph_assert(num_frozen_inodes
== 0);
602 frozen_inode_suppressed
++;
604 void enable_frozen_inode();
606 std::ostream
& print_db_line_prefix(std::ostream
& out
) override
;
607 void print(std::ostream
& out
) override
;
608 void dump(ceph::Formatter
*f
, int flags
= DUMP_DEFAULT
) const;
609 void dump_load(ceph::Formatter
*f
);
614 CInode
*inode
; // my inode
615 frag_t frag
; // my frag
618 mempool::mds_co::compact_map
<snapid_t
,old_rstat_t
> dirty_old_rstat
; // [value.first,key]
620 // my inodes with dirty rstat data
621 elist
<CInode
*> dirty_rstat_inodes
;
623 elist
<CDentry
*> dirty_dentries
;
624 elist
<CDir
*>::item item_dirty
, item_new
;
626 // lock caches that auth-pin me
627 elist
<MDLockCache::DirItem
*> lock_caches_with_auth_pins
;
629 // all dirfrags within freezing/frozen tree reference the 'state'
630 std::shared_ptr
<freeze_tree_state_t
> freeze_tree_state
;
634 friend class Migrator
;
636 friend class MDCache
;
637 friend class MDiscover
;
638 friend class MDBalancer
;
640 friend class CDirDiscover
;
641 friend class CDirExport
;
642 friend class C_IO_Dir_TMAP_Fetched
;
643 friend class C_IO_Dir_OMAP_Fetched
;
644 friend class C_IO_Dir_OMAP_FetchedMore
;
645 friend class C_IO_Dir_Committed
;
646 friend class C_IO_Dir_Commit_Ops
;
648 void _omap_fetch(MDSContext
*fin
, const std::set
<dentry_key_t
>& keys
);
649 void _omap_fetch_more(version_t omap_version
, bufferlist
& hdrbl
,
650 std::map
<std::string
, bufferlist
>& omap
, MDSContext
*fin
);
651 CDentry
*_load_dentry(
652 std::string_view key
,
653 std::string_view dname
,
655 ceph::buffer::list
&bl
,
657 const std::set
<snapid_t
> *snaps
,
658 double rand_threshold
,
662 * Go bad due to a damaged dentry (register with damagetable and go BADFRAG)
664 void go_bad_dentry(snapid_t last
, std::string_view dname
);
667 * Go bad due to a damaged header (register with damagetable and go BADFRAG)
669 void go_bad(bool complete
);
671 void _omap_fetched(ceph::buffer::list
& hdrbl
, std::map
<std::string
, ceph::buffer::list
>& omap
,
672 bool complete
, int r
);
675 void _commit(version_t want
, int op_prio
);
676 void _omap_commit_ops(int r
, int op_prio
, int64_t metapool
, version_t version
, bool _new
,
677 std::vector
<dentry_commit_item
> &to_set
, bufferlist
&dfts
,
678 std::vector
<std::string
> &to_remove
,
679 mempool::mds_co::compact_set
<mempool::mds_co::string
> &_stale
);
680 void _encode_primary_inode_base(dentry_commit_item
&item
, bufferlist
&dfts
,
682 void _omap_commit(int op_prio
);
683 void _parse_dentry(CDentry
*dn
, dentry_commit_item
&item
,
684 const std::set
<snapid_t
> *snaps
, bufferlist
&bl
);
685 void _committed(int r
, version_t v
);
687 static fnode_const_ptr empty_fnode
;
688 // fnode is a pointer to constant fnode_t, the constant fnode_t can be shared
689 // by CDir and log events. To update fnode, read-copy-update should be used.
691 fnode_const_ptr fnode
= empty_fnode
;
693 version_t projected_version
= 0;
694 mempool::mds_co::list
<fnode_const_ptr
> projected_fnode
;
696 std::unique_ptr
<scrub_info_t
> scrub_infop
;
698 // contents of this directory
699 dentry_key_map items
; // non-null AND null
700 unsigned num_head_items
= 0;
701 unsigned num_head_null
= 0;
702 unsigned num_snap_items
= 0;
703 unsigned num_snap_null
= 0;
707 int num_inodes_with_caps
= 0;
710 version_t committing_version
= 0;
711 version_t committed_version
= 0;
713 mempool::mds_co::compact_set
<mempool::mds_co::string
> stale_items
;
715 // lock nesting, freeze
716 static int num_frozen_trees
;
717 static int num_freezing_trees
;
719 // freezing/frozen inodes in this dirfrag
720 int num_frozen_inodes
= 0;
721 int frozen_inode_suppressed
= 0;
722 elist
<CInode
*> freezing_inodes
;
724 int dir_auth_pins
= 0;
726 // cache control (defined for authority; hints for replicas)
728 mempool::mds_co::compact_set
<__s32
> dir_rep_by
; // if dir_rep == REP_LIST
731 dirfrag_load_vec_t pop_me
;
732 dirfrag_load_vec_t pop_nested
;
733 dirfrag_load_vec_t pop_auth_subtree
;
734 dirfrag_load_vec_t pop_auth_subtree_nested
;
736 ceph::coarse_mono_time last_popularity_sample
= ceph::coarse_mono_clock::zero();
738 load_spread_t pop_spread
;
740 elist
<CInode
*> pop_lru_subdirs
;
742 std::unique_ptr
<bloom_filter
> bloom
; // XXX not part of mempool::mds_co
743 /* If you set up the bloom filter, you must keep it accurate!
744 * It's deleted when you mark_complete() and is deliberately not serialized.*/
746 mempool::mds_co::compact_set
<mempool::mds_co::string
> wanted_items
;
747 mempool::mds_co::compact_map
<version_t
, MDSContext::vec_alloc
<mempool::mds_co::pool_allocator
> > waiting_for_commit
;
750 mempool::mds_co::compact_map
< string_snap_t
, MDSContext::vec_alloc
<mempool::mds_co::pool_allocator
> > waiting_on_dentry
; // FIXME string_snap_t not in mempool
753 friend std::ostream
& operator<<(std::ostream
& out
, const class CDir
& dir
);
755 void log_mark_dirty();
758 * Create a scrub_info_t struct for the scrub_infop pointer.
760 void scrub_info_create() const;
762 * Delete the scrub_infop if it's not got any useful data.
764 void scrub_maybe_delete_info();
766 void link_inode_work( CDentry
*dn
, CInode
*in
);
767 void unlink_inode_work( CDentry
*dn
);
768 void remove_null_dentries();
769 void purge_stale_snap_data(const std::set
<snapid_t
>& snaps
);
771 void prepare_new_fragment(bool replay
);
772 void prepare_old_fragment(std::map
<string_snap_t
, MDSContext::vec
>& dentry_waiters
, bool replay
);
773 void steal_dentry(CDentry
*dn
); // from another dir. used by merge/split.
774 void finish_old_fragment(MDSContext::vec
& waiters
, bool replay
);
775 void init_fragment_pins();
776 std::string
get_path() const;
780 * normal: <parent,unknown> !subtree_root
781 * delegation: <mds,unknown> subtree_root
782 * ambiguous: <mds1,mds2> subtree_root
783 * <parent,mds2> subtree_root
785 mds_authority_t dir_auth
;