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