return good;
}
+void CDir::adjust_num_inodes_with_caps(int d)
+{
+ // FIXME: smarter way to decide if adding 'this' to open file table
+ if (num_inodes_with_caps == 0 && d > 0)
+ cache->open_file_table.add_dirfrag(this);
+ else if (num_inodes_with_caps > 0 && num_inodes_with_caps == -d)
+ cache->open_file_table.remove_dirfrag(this);
+
+ num_inodes_with_caps += d;
+ assert(num_inodes_with_caps >= 0);
+}
+
CDentry *CDir::lookup(std::string_view name, snapid_t snap)
{
dout(20) << "lookup (" << snap << ", '" << name << "')" << dendl;
if (in->state_test(CInode::STATE_TRACKEDBYOFT))
inode->mdcache->open_file_table.notify_link(in);
+ if (in->is_any_caps())
+ adjust_num_inodes_with_caps(1);
// adjust auth pin count
if (in->auth_pins + in->nested_auth_pins)
if (in->state_test(CInode::STATE_TRACKEDBYOFT))
inode->mdcache->open_file_table.notify_unlink(in);
+ if (in->is_any_caps())
+ adjust_num_inodes_with_caps(-1);
// unlink auth_pin count
if (in->auth_pins + in->nested_auth_pins)
if (pi->accounted_rstat.rctime > fnode.rstat.rctime)
fnode.rstat.rctime = pi->accounted_rstat.rctime;
+ if (in->is_any_caps())
+ adjust_num_inodes_with_caps(1);
+
// move dirty inode rstat to new dirfrag
if (in->is_dirty_rstat())
dirty_rstat_inodes.push_back(&in->dirty_rstat_item);
num_head_items = num_head_null = 0;
num_snap_items = num_snap_null = 0;
+ adjust_num_inodes_with_caps(-num_inodes_with_caps);
// this mirrors init_fragment_pins()
if (is_auth())
static const unsigned STATE_ASSIMRSTAT = (1<<15); // assimilating inode->frag rstats
static const unsigned STATE_DIRTYDFT = (1<<16); // dirty dirfragtree
static const unsigned STATE_BADFRAG = (1<<17); // bad dirfrag
- static const unsigned STATE_AUXSUBTREE = (1<<18); // no subtree merge
+ static const unsigned STATE_TRACKEDBYOFT = (1<<18); // tracked by open file table
+ static const unsigned STATE_AUXSUBTREE = (1<<19); // no subtree merge
// common states
static const unsigned STATE_CLEAN = 0;
STATE_IMPORTBOUND |
STATE_EXPORTBOUND |
STATE_FROZENTREE |
- STATE_STICKY);
+ STATE_STICKY |
+ STATE_TRACKEDBYOFT);
static const unsigned MASK_STATE_EXPORT_KEPT =
(STATE_EXPORTING |
STATE_IMPORTBOUND |
STATE_EXPORTBOUND |
STATE_FROZENTREE |
STATE_FROZENDIR |
- STATE_STICKY);
+ STATE_STICKY |
+ STATE_TRACKEDBYOFT);
static const unsigned MASK_STATE_FRAGMENT_KEPT =
(STATE_DIRTY |
STATE_EXPORTBOUND |
int num_dirty;
+ int num_inodes_with_caps = 0;
+
// state
version_t committing_version;
version_t committed_version;
return num_dirty;
}
+ void adjust_num_inodes_with_caps(int d);
+
int64_t get_frag_size() const {
return get_projected_fnode()->fragstat.size();
}
*/
#include "mds/CInode.h"
+#include "mds/CDir.h"
#include "mds/MDSRank.h"
#include "mds/MDCache.h"
#include "osdc/Objecter.h"
put_ref(in);
}
+void OpenFileTable::add_dirfrag(CDir *dir)
+{
+ dout(10) << __func__ << " " << *dir << dendl;
+ assert(!dir->state_test(CDir::STATE_TRACKEDBYOFT));
+ dir->state_set(CDir::STATE_TRACKEDBYOFT);
+ auto ret = dirfrags.insert(dir->dirfrag());
+ assert(ret.second);
+ get_ref(dir->get_inode());
+ dirty_items.emplace(dir->ino(), 0);
+}
+
+void OpenFileTable::remove_dirfrag(CDir *dir)
+{
+ dout(10) << __func__ << " " << *dir << dendl;
+ assert(dir->state_test(CDir::STATE_TRACKEDBYOFT));
+ dir->state_clear(CDir::STATE_TRACKEDBYOFT);
+ auto p = dirfrags.find(dir->dirfrag());
+ assert(p != dirfrags.end());
+ dirfrags.erase(p);
+ dirty_items.emplace(dir->ino(), 0);
+ put_ref(dir->get_inode());
+}
+
void OpenFileTable::notify_link(CInode *in)
{
dout(10) << __func__ << " " << *in << dendl;
using ceph::encode;
for (auto& it : dirty_items) {
+ list<frag_t> fgls;
auto p = anchor_map.find(it.first);
+ if (p != anchor_map.end()) {
+ for (auto q = dirfrags.lower_bound(dirfrag_t(it.first, 0));
+ q != dirfrags.end() && q->ino == it.first;
+ ++q)
+ fgls.push_back(q->frag);
+ }
+
if (first_commit) {
auto q = loaded_anchor_map.find(it.first);
if (q != loaded_anchor_map.end()) {
bool same = (p != anchor_map.end() && p->second == q->second);
+ if (same) {
+ auto r = loaded_dirfrags.lower_bound(dirfrag_t(it.first, 0));
+ for (auto fg : fgls) {
+ if (r == loaded_dirfrags.end() || !(*r == dirfrag_t(it.first, fg))) {
+ same = false;
+ break;
+ }
+ ++r;
+ }
+ if (same && r != loaded_dirfrags.end() && r->ino == it.first)
+ same = false;
+ }
loaded_anchor_map.erase(q);
if (same)
continue;
if (p != anchor_map.end()) {
bufferlist bl;
encode(p->second, bl);
+ encode(fgls, bl);
write_size += bl.length() + sizeof(__u32);
-
to_update[key].swap(bl);
} else {
to_remove.emplace(key);
}
}
loaded_anchor_map.clear();
+ loaded_dirfrags.clear();
}
commit_func(true);
if (op_r < 0) {
derr << __func__ << " got " << cpp_strerror(op_r) << dendl;
clear_on_commit = true;
- if (!first)
+ if (!first) {
loaded_anchor_map.clear();
+ loaded_dirfrags.clear();
+ }
goto out;
}
decode(anchor, p);
assert(ino == anchor.ino);
anchor.auth = MDS_RANK_NONE;
+
+ list<frag_t> fgls;
+ decode(fgls, p);
+ for (auto fg : fgls)
+ loaded_dirfrags.insert(loaded_dirfrags.end(), dirfrag_t(anchor.ino, fg));
}
} catch (buffer::error &e) {
derr << __func__ << ": corrupted header/values: " << e.what() << dendl;
clear_on_commit = true;
loaded_anchor_map.clear();
+ loaded_dirfrags.clear();
goto out;
}
num_opening_inodes--;
if (num_opening_inodes == 0) {
if (prefetch_state == DIR_INODES) {
- prefetch_state = FILE_INODES;
- _prefetch_inodes();
+ prefetch_state = DIRFRAGS;
+ _prefetch_dirfrags();
} else if (prefetch_state == FILE_INODES) {
prefetch_state = DONE;
logseg_destroyed_inos.clear();
}
}
+void OpenFileTable::_prefetch_dirfrags()
+{
+ dout(10) << __func__ << dendl;
+ assert(prefetch_state == DIRFRAGS);
+
+ MDCache *mdcache = mds->mdcache;
+ list<CDir*> fetch_queue;
+
+ CInode *last_in = nullptr;
+ for (auto df : loaded_dirfrags) {
+ CInode *diri;
+ if (last_in && last_in->ino() == df.ino) {
+ diri = last_in;
+ } else {
+ diri = mdcache->get_inode(df.ino);
+ if (!diri)
+ continue;
+ last_in = diri;
+ }
+ if (diri->state_test(CInode::STATE_REJOINUNDEF))
+ continue;
+
+ CDir *dir = diri->get_dirfrag(df.frag);
+ if (dir) {
+ if (dir->is_auth() && !dir->is_complete())
+ fetch_queue.push_back(dir);
+ } else {
+ list<frag_t> fgls;
+ diri->dirfragtree.get_leaves_under(df.frag, fgls);
+ for (auto fg : fgls) {
+ if (diri->is_auth()) {
+ dir = diri->get_or_open_dirfrag(mdcache, fg);
+ } else {
+ dir = diri->get_dirfrag(fg);
+ }
+ if (dir && dir->is_auth() && !dir->is_complete())
+ fetch_queue.push_back(dir);
+ }
+ }
+ }
+
+ MDSGatherBuilder gather(g_ceph_context);
+ for (auto dir : fetch_queue) {
+ if (dir->state_test(CDir::STATE_REJOINUNDEF))
+ assert(dir->get_inode()->dirfragtree.is_leaf(dir->get_frag()));
+ dir->fetch(gather.new_sub());
+ }
+
+ auto finish_func = [this](int r) {
+ prefetch_state = FILE_INODES;
+ _prefetch_inodes();
+ };
+ if (gather.has_subs()) {
+ gather.set_finisher(
+ new MDSInternalContextWrapper(mds,
+ new FunctionContext(finish_func)));
+ gather.activate();
+ } else {
+ finish_func(0);
+ }
+}
+
void OpenFileTable::_prefetch_inodes()
{
dout(10) << __func__ << " state " << prefetch_state << dendl;
void add_inode(CInode *in);
void remove_inode(CInode *in);
+ void add_dirfrag(CDir *dir);
+ void remove_dirfrag(CDir *dir);
void notify_link(CInode *in);
void notify_unlink(CInode *in);
bool is_any_dirty() const { return !dirty_items.empty(); }
MDSRank *mds;
map<inodeno_t, Anchor> anchor_map;
+ set<dirfrag_t> dirfrags;
std::map<inodeno_t, unsigned> dirty_items; // ino -> dirty state
static const unsigned DIRTY_NEW = 1;
void _commit_finish(int r, uint64_t log_seq, MDSInternalContextBase *fin);
map<inodeno_t, Anchor> loaded_anchor_map;
+ set<dirfrag_t> loaded_dirfrags;
list<MDSInternalContextBase*> waiting_for_load;
bool load_done = false;
enum {
DIR_INODES = 1,
- FILE_INODES = 2,
- DONE = 3,
+ DIRFRAGS = 2,
+ FILE_INODES = 3,
+ DONE = 4,
};
unsigned prefetch_state = 0;
unsigned num_opening_inodes = 0;
list<MDSInternalContextBase*> waiting_for_prefetch;
void _open_ino_finish(inodeno_t ino, int r);
void _prefetch_inodes();
+ void _prefetch_dirfrags();
std::map<uint64_t, vector<inodeno_t> > logseg_destroyed_inos;
std::set<inodeno_t> destroyed_inos_set;