out << " inode=" << dn.get_linkage()->get_inode();
- if (dn.is_new()) out << " state=new";
+ out << " state=" << dn.get_state();
+ if (dn.is_new()) out << "|new";
+ if (dn.state_test(CDentry::STATE_BOTTOMLRU)) out << "|bottomlru";
if (dn.get_num_ref()) {
out << " |";
static const int STATE_BADREMOTEINO = (1<<3);
static const int STATE_EVALUATINGSTRAY = (1<<4);
static const int STATE_PURGINGPINNED = (1<<5);
+ static const int STATE_BOTTOMLRU = (1<<6);
// stray dentry needs notification of releasing reference
static const int STATE_STRAY = STATE_NOTIFYREF;
+ static const int MASK_STATE_IMPORT_KEPT = STATE_BOTTOMLRU;
// -- pins --
static const int PIN_INODEPIN = 1; // linked inode is pinned
::decode(replica_map, blp);
// twiddle
- state = 0;
+ state &= MASK_STATE_IMPORT_KEPT;
state_set(CDentry::STATE_AUTH);
if (nstate & STATE_DIRTY)
_mark_dirty(ls);
CDentry* dn = new CDentry(dname, inode->hash_dentry_name(dname), first, last);
if (is_auth())
dn->state_set(CDentry::STATE_AUTH);
- cache->lru.lru_insert_mid(dn);
+
+ cache->bottom_lru.lru_insert_mid(dn);
+ dn->state_set(CDentry::STATE_BOTTOMLRU);
dn->dir = this;
dn->version = get_projected_version();
CDentry* dn = new CDentry(dname, inode->hash_dentry_name(dname), first, last);
if (is_auth())
dn->state_set(CDentry::STATE_AUTH);
- cache->lru.lru_insert_mid(dn);
+ if (is_auth() || !inode->is_stray()) {
+ cache->lru.lru_insert_mid(dn);
+ } else {
+ cache->bottom_lru.lru_insert_mid(dn);
+ dn->state_set(CDentry::STATE_BOTTOMLRU);
+ }
dn->dir = this;
dn->version = get_projected_version();
if (dn->is_dirty())
dn->mark_clean();
- cache->lru.lru_remove(dn);
+ if (dn->state_test(CDentry::STATE_BOTTOMLRU))
+ cache->bottom_lru.lru_remove(dn);
+ else
+ cache->lru.lru_remove(dn);
delete dn;
// unpin?
dn->get_linkage()->set_remote(ino, d_type);
+ if (dn->state_test(CDentry::STATE_BOTTOMLRU)) {
+ cache->bottom_lru.lru_remove(dn);
+ cache->lru.lru_insert_mid(dn);
+ dn->state_clear(CDentry::STATE_BOTTOMLRU);
+ }
+
if (dn->last == CEPH_NOSNAP) {
num_head_items++;
num_head_null--;
in->set_primary_parent(dn);
link_inode_work(dn, in);
+
+ if (dn->state_test(CDentry::STATE_BOTTOMLRU) &&
+ (is_auth() || !inode->is_stray())) {
+ cache->bottom_lru.lru_remove(dn);
+ cache->lru.lru_insert_mid(dn);
+ dn->state_clear(CDentry::STATE_BOTTOMLRU);
+ }
if (dn->last == CEPH_NOSNAP) {
num_head_items++;
in->move_to_realm(inode->find_snaprealm());
}
-void CDir::unlink_inode(CDentry *dn)
+void CDir::unlink_inode(CDentry *dn, bool adjust_lru)
{
if (dn->get_linkage()->is_primary()) {
dout(12) << "unlink_inode " << *dn << " " << *dn->get_linkage()->get_inode() << dendl;
unlink_inode_work(dn);
+ if (adjust_lru && !dn->state_test(CDentry::STATE_BOTTOMLRU)) {
+ cache->lru.lru_remove(dn);
+ cache->bottom_lru.lru_insert_mid(dn);
+ dn->state_set(CDentry::STATE_BOTTOMLRU);
+ }
+
if (dn->last == CEPH_NOSNAP) {
num_head_items--;
num_head_null++;
mark_clean();
}
-void CDir::touch_dentries_bottom() {
- dout(12) << "touch_dentries_bottom " << *this << dendl;
-
- for (CDir::map_t::iterator p = items.begin();
- p != items.end();
- ++p)
- inode->mdcache->touch_dentry_bottom(p->second);
-}
-
bool CDir::try_trim_snap_dentry(CDentry *dn, const set<snapid_t>& snaps)
{
assert(dn->last != CEPH_NOSNAP);
void link_remote_inode( CDentry *dn, inodeno_t ino, unsigned char d_type);
void link_remote_inode( CDentry *dn, CInode *in );
void link_primary_inode( CDentry *dn, CInode *in );
- void unlink_inode( CDentry *dn );
+ void unlink_inode(CDentry *dn, bool adjust_lru=true);
void try_remove_unlinked_dn(CDentry *dn);
void add_to_bloom(CDentry *dn);
void remove_null_dentries();
void purge_stale_snap_data(const std::set<snapid_t>& snaps);
public:
- void touch_dentries_bottom();
void try_remove_dentries_for_stray();
bool try_trim_snap_dentry(CDentry *dn, const std::set<snapid_t>& snaps);
lru.lru_set_max(g_conf->mds_cache_size);
lru.lru_set_midpoint(g_conf->mds_cache_mid);
+ bottom_lru.lru_set_max(0);
+ bottom_lru.lru_set_midpoint(0);
+
decayrate.set_halflife(g_conf->mds_decay_halflife);
did_shutdown_log_cap = false;
CDentry::linkage_t *dnl = dn->get_linkage();
if (dnl->is_primary()) {
CInode *tin = dnl->get_inode();
- subdir->unlink_inode(dn);
+ subdir->unlink_inode(dn, false);
remove_inode_recursive(tin);
}
subdir->remove_dentry(dn);
if (max <= 0)
return false;
}
- dout(7) << "trim max=" << max << " cur=" << lru.lru_get_size() << dendl;
+ dout(7) << "trim max=" << max << " cur=" << lru.lru_get_size()
+ << "/" << bottom_lru.lru_get_size() << dendl;
// process delayed eval_stray()
stray_manager.advance_delayed();
int unexpirable = 0;
list<CDentry*> unexpirables;
+ for (;;) {
+ CDentry *dn = static_cast<CDentry*>(bottom_lru.lru_expire());
+ if (!dn)
+ break;
+ if (trim_dentry(dn, expiremap)) {
+ unexpirables.push_back(dn);
+ ++unexpirable;
+ }
+ }
+
+ for(auto dn : unexpirables)
+ bottom_lru.lru_insert_mid(dn);
+ unexpirables.clear();
+
// trim dentries from the LRU: only enough to satisfy `max`,
- // unless we see null dentries at the bottom of the LRU,
- // in which case trim all those.
- bool trimming_nulls = true;
- while (trimming_nulls || lru.lru_get_size() + unexpirable > (unsigned)max) {
+ while (lru.lru_get_size() + unexpirable > (unsigned)max) {
CDentry *dn = static_cast<CDentry*>(lru.lru_expire());
if (!dn) {
break;
}
- if (!dn->get_linkage()->is_null()) {
- trimming_nulls = false;
- if (lru.lru_get_size() + unexpirable < (unsigned)max) {
- unexpirables.push_back(dn);
- break;
- }
- }
if ((is_standby_replay && dn->get_linkage()->inode &&
dn->get_linkage()->inode->item_open_file.is_on_list()) ||
trim_dentry(dn, expiremap)) {
++unexpirable;
}
}
- for(list<CDentry*>::iterator i = unexpirables.begin();
- i != unexpirables.end();
- ++i)
- lru.lru_insert_mid(*i);
+ for(auto dn : unexpirables)
+ lru.lru_insert_mid(dn);
+ unexpirables.clear();
// trim non-auth, non-bound subtrees
for (map<CDir*, set<CDir*> >::iterator p = subtrees.begin();
// unlink the dentry
if (dnl->is_remote()) {
// just unlink.
- dir->unlink_inode(dn);
+ dir->unlink_inode(dn, false);
} else if (dnl->is_primary()) {
// expire the inode, too.
CInode *in = dnl->get_inode();
// unlink
if (dn)
- dn->get_dir()->unlink_inode(dn);
+ dn->get_dir()->unlink_inode(dn, false);
remove_inode(in);
return false;
}
CDentry *first_auth = 0;
// trim non-auth items from the lru
- while (lru.lru_get_size() > 0) {
- CDentry *dn = static_cast<CDentry*>(lru.lru_expire());
- if (!dn) break;
+ for (;;) {
+ CDentry *dn = NULL;
+ if (bottom_lru.lru_get_size() > 0)
+ dn = static_cast<CDentry*>(bottom_lru.lru_expire());
+ if (!dn && lru.lru_get_size() > 0)
+ dn = static_cast<CDentry*>(lru.lru_expire());
+ if (!dn)
+ break;
+
CDentry::linkage_t *dnl = dn->get_linkage();
if (dn->is_auth()) {
// add back into lru (at the top)
- lru.lru_insert_top(dn);
+ if (dn->state_test(CDentry::STATE_BOTTOMLRU))
+ bottom_lru.lru_insert_mid(dn);
+ else
+ lru.lru_insert_top(dn);
if (dnl->is_remote() && dnl->get_inode() && !dnl->get_inode()->is_auth())
dn->unlink_remote(dnl);
// unlink the dentry
dout(10) << " removing " << *dn << dendl;
if (dnl->is_remote()) {
- dir->unlink_inode(dn);
+ dir->unlink_inode(dn, false);
}
else if (dnl->is_primary()) {
CInode *in = dnl->get_inode();
assert(!subdir->is_subtree_root());
in->close_dirfrag(subdir->dirfrag().frag);
}
- dir->unlink_inode(dn);
+ dir->unlink_inode(dn, false);
remove_inode(in);
}
else {
++p)
p->first->put(CDir::PIN_SUBTREETEMP);
- if (lru.lru_get_size() == 0) {
+ if (lru.lru_get_size() == 0 &&
+ bottom_lru.lru_get_size() == 0) {
// root, stray, etc.?
ceph::unordered_map<vinodeno_t,CInode*>::iterator p = inode_map.begin();
while (p != inode_map.end()) {
}
if (!keep_inode) { // remove it!
dout(20) << "trim_non_auth_subtree(" << dir << ") removing inode " << in << " with dentry" << dn << dendl;
- dir->unlink_inode(dn);
+ dir->unlink_inode(dn, false);
remove_inode(in);
assert(!dir->has_bloom());
dir->remove_dentry(dn);
} else { // just remove it
dout(20) << "trim_non_auth_subtree(" << dir << ") removing dentry " << dn << dendl;
if (dnl->is_remote())
- dir->unlink_inode(dn);
+ dir->unlink_inode(dn, false);
dir->remove_dentry(dn);
}
}
mds->timer.add_event_after(g_conf->mds_shutdown_check, new C_MDC_ShutdownCheck(this));
// this
- dout(0) << "lru size now " << lru.lru_get_size() << dendl;
+ dout(0) << "lru size now " << lru.lru_get_size() << "/" << bottom_lru.lru_get_size() << dendl;
dout(0) << "log len " << mds->mdlog->get_num_events() << dendl;
// trim cache
trim(0);
- dout(5) << "lru size now " << lru.lru_get_size() << dendl;
+ dout(5) << "lru size now " << lru.lru_get_size() << "/" << bottom_lru.lru_get_size() << dendl;
// SUBTREES
int num_auth_subtree = 0;
}
// trim what we can from the cache
- if (lru.lru_get_size() > 0) {
- dout(7) << "there's still stuff in the cache: " << lru.lru_get_size() << dendl;
+ if (lru.lru_get_size() > 0 || bottom_lru.lru_get_size() > 0) {
+ dout(7) << "there's still stuff in the cache: " << lru.lru_get_size() << "/" << bottom_lru.lru_get_size() << dendl;
show_cache();
//dump();
return false;
!in->state_test(CInode::STATE_EXPORTINGCAPS))
migrator->export_caps(in);
- touch_dentry_bottom(straydn); // move stray to end of lru
straydn = NULL;
} else {
assert(!straydn);
dn->dir->unlink_inode(dn);
}
assert(dnl->is_null());
-
- // move to bottom of lru
- touch_dentry_bottom(dn);
}
}
// -- my cache --
LRU lru; // dentry lru for expiring items from cache
+ LRU bottom_lru; // dentries that should be trimmed ASAP
protected:
ceph::unordered_map<vinodeno_t,CInode*> inode_map; // map of inodes by ino
CInode *root; // root inode
}
public:
void touch_dentry(CDentry *dn) {
- // touch ancestors
- if (dn->get_dir()->get_inode()->get_projected_parent_dn())
- touch_dentry(dn->get_dir()->get_inode()->get_projected_parent_dn());
-
- // touch me
- if (dn->is_auth())
- lru.lru_touch(dn);
- else
- lru.lru_midtouch(dn);
+ if (dn->state_test(CDentry::STATE_BOTTOMLRU)) {
+ bottom_lru.lru_midtouch(dn);
+ } else {
+ if (dn->is_auth())
+ lru.lru_touch(dn);
+ else
+ lru.lru_midtouch(dn);
+ }
}
void touch_dentry_bottom(CDentry *dn) {
+ if (dn->state_test(CDentry::STATE_BOTTOMLRU))
+ return;
lru.lru_bottouch(dn);
- if (dn->get_projected_linkage()->is_primary() &&
- dn->get_dir()->inode->is_stray()) {
- CInode *in = dn->get_projected_linkage()->get_inode();
- if (in->has_dirfrags()) {
- list<CDir*> ls;
- in->get_dirfrags(ls);
- for (list<CDir*>::iterator p = ls.begin(); p != ls.end(); ++p)
- (*p)->touch_dentries_bottom();
- }
- }
}
protected:
// empty?
if (journaler->get_read_pos() == journaler->get_write_pos()) {
dout(10) << "replay - journal empty, done." << dendl;
- mds->mdcache->trim(-1);
+ mds->mdcache->trim();
if (c) {
c->complete(0);
}
in->finish_export(now);
finish_export_inode_caps(in, peer, peer_imported);
-
- // *** other state too?
-
- // move to end of LRU so we drop out of cache quickly!
- if (in->get_parent_dn())
- cache->lru.lru_bottouch(in->get_parent_dn());
-
}
uint64_t Migrator::encode_export_dir(bufferlist& exportbl,
mdcache->predirty_journal_parents(mdr, &le->metablob, targeti, dn->get_dir(), PREDIRTY_DIR, -1);
mdcache->journal_cow_dentry(mdr.get(), &le->metablob, dn);
le->metablob.add_null_dentry(dn, true);
+ dn->push_projected_linkage();
}
journal_and_reply(mdr, targeti, dn, le, new C_MDS_link_remote_finish(this, mdr, inc, dn, targeti));
} else {
// unlink main dentry
dn->get_dir()->unlink_inode(dn);
+ dn->pop_projected_linkage();
dn->mark_dirty(dn->get_projected_version(), mdr->ls); // dirty old dentry
}
if (destdnl->is_primary()) {
assert(straydn);
dout(10) << "straydn is " << *straydn << dendl;
- destdn->get_dir()->unlink_inode(destdn);
+ destdn->get_dir()->unlink_inode(destdn, false);
straydn->pop_projected_linkage();
if (mdr->is_slave() && !mdr->more()->slave_update_journaled)
//oldin->open_snaprealm(); might be sufficient..
}
} else if (destdnl->is_remote()) {
- destdn->get_dir()->unlink_inode(destdn);
+ destdn->get_dir()->unlink_inode(destdn, false);
if (oldin->is_auth())
oldin->pop_and_dirty_projected_inode(mdr->ls);
}
} else { // primary
if (linkmerge) {
dout(10) << "merging primary onto remote link" << dendl;
- destdn->get_dir()->unlink_inode(destdn);
+ destdn->get_dir()->unlink_inode(destdn, false);
}
destdnl = destdn->pop_projected_linkage();
if (mdr->is_slave() && !mdr->more()->slave_update_journaled)
assert(!in->state_test(CInode::STATE_RECOVERING));
+ bool new_dn = dn->is_new();
+
// unlink
assert(dn->get_projected_linkage()->is_null());
- dn->dir->unlink_inode(dn);
+ dn->dir->unlink_inode(dn, !new_dn);
dn->pop_projected_linkage();
dn->mark_dirty(pdv, ls);
dn->put(CDentry::PIN_PURGING);
// drop dentry?
- if (dn->is_new()) {
+ if (new_dn) {
dout(20) << " dn is new, removing" << dendl;
dn->mark_clean();
dn->dir->remove_dentry(dn);
- } else {
- in->mdcache->touch_dentry_bottom(dn); // drop dn as quickly as possible.
}
// drop inode
assert(!dn->state_test(CDentry::STATE_PURGING));
if (!dn->is_auth()) {
- // has to be mine
- // move to bottom of lru so that we trim quickly!
-
- in->mdcache->touch_dentry_bottom(dn);
return false;
}
dout(0) << ss.str() << dendl;
mds->clog->warn(ss);
}
- dir->unlink_inode(dn);
- mds->mdcache->touch_dentry_bottom(dn);
+ dir->unlink_inode(dn, false);
}
if (unlinked.count(in))
linked.insert(in);
if (dn->get_linkage()->get_inode() != in && in->get_parent_dn()) {
dout(10) << "EMetaBlob.replay unlinking " << *in << dendl;
unlinked[in] = in->get_parent_dir();
- CDentry *unlinked_dn = in->get_parent_dn();
in->get_parent_dir()->unlink_inode(in->get_parent_dn());
- mds->mdcache->touch_dentry_bottom(unlinked_dn);
}
if (dn->get_linkage()->get_inode() != in) {
if (!dn->get_linkage()->is_null()) { // note: might be remote. as with stray reintegration.
dout(0) << ss.str() << dendl;
mds->clog->warn(ss);
}
- dir->unlink_inode(dn);
- mds->mdcache->touch_dentry_bottom(dn);
+ dir->unlink_inode(dn, false);
}
if (unlinked.count(in))
linked.insert(in);
<< " " << *dn->get_linkage()->get_inode() << " should be remote " << p->ino;
dout(0) << ss.str() << dendl;
}
- dir->unlink_inode(dn);
- mds->mdcache->touch_dentry_bottom(dn);
+ dir->unlink_inode(dn, false);
}
dir->link_remote_inode(dn, p->ino, p->d_type);
dn->set_version(p->dnv);
if (dn->get_linkage()->is_primary())
unlinked[in] = dir;
dir->unlink_inode(dn);
- mds->mdcache->touch_dentry_bottom(dn);
}
}
dn->set_version(p->dnv);
// Make null dentries the first things we trim
dout(10) << "EMetaBlob.replay pushing to bottom of lru " << *dn << dendl;
- mds->mdcache->touch_dentry_bottom(dn);
}
}
if (parent) {
dout(10) << "EMetaBlob.replay unlinked from dentry " << *parent << dendl;
assert(parent->get_linkage()->is_null());
- mds->mdcache->touch_dentry_bottom(parent);
}
} else {
dout(10) << "EMetaBlob.replay destroyed " << *p << ", not in cache" << dendl;