From 854ab3b0d4eebe9dd642c27796a24b071fe24566 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 26 Jul 2011 14:58:35 -0700 Subject: [PATCH] mds: track projected rename effect on subtree map Renames can effect the subtree map. We don't actually update it until the rename commits, but while it is in flight to the jouranl we may journal an ESubtreeMap event, which should reflect the change. Adjust all callers (that journal) to project their change. Mirror the logic in adjust_subtree_after_rename() in the subtree map journaling code. Be a bit careful, because we only journal subtrees that we are auth for, so there are some additional checks to get a consistent result. Signed-off-by: Sage Weil --- src/mds/MDCache.cc | 97 ++++++++++++++++++++++++++++++++++++++++++++-- src/mds/MDCache.h | 4 ++ src/mds/Server.cc | 15 ++++++- 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 902d3d6875b13..6b57a114e83a8 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -1209,6 +1209,12 @@ void MDCache::verify_subtree_bounds(CDir *dir, const list& bounds) assert(failed == 0); } +void MDCache::project_subtree_rename(CInode *diri, CDir *newdir) +{ + dout(10) << "project_subtree_rename " << *diri << " to " << *newdir << dendl; + projected_subtree_renames[diri] = newdir; +} + void MDCache::adjust_subtree_after_rename(CInode *diri, CDir *olddir, bool imported) { @@ -1216,6 +1222,16 @@ void MDCache::adjust_subtree_after_rename(CInode *diri, CDir *olddir, //show_subtrees(); + CDir *newdir = diri->get_parent_dir(); + + map::iterator p = projected_subtree_renames.find(diri); + if (p != projected_subtree_renames.end()) { + assert(p->second == newdir); + projected_subtree_renames.erase(p); + } else { + //assert(mds->is_any_replay()); or unlink notification + } + // adjust subtree list dfls; diri->get_dirfrags(dfls); @@ -1225,7 +1241,7 @@ void MDCache::adjust_subtree_after_rename(CInode *diri, CDir *olddir, dout(10) << "dirfrag " << *dir << dendl; CDir *oldparent = get_subtree_root(olddir); dout(10) << " old parent " << *oldparent << dendl; - CDir *newparent = get_subtree_root(diri->get_parent_dir()); + CDir *newparent = get_subtree_root(newdir); dout(10) << " new parent " << *newparent << dendl; if (oldparent == newparent) { @@ -2173,16 +2189,35 @@ void MDCache::_logged_slave_commit(int from, metareqid_t reqid) // ==================================================================== // import map, recovery +void MDCache::_move_subtree_map_bound(dirfrag_t df, dirfrag_t oldparent, dirfrag_t newparent, + map >& subtrees) +{ + if (subtrees.count(oldparent)) { + vector& v = subtrees[oldparent]; + dout(10) << " removing " << df << " from " << oldparent << " bounds " << v << dendl; + for (vector::iterator it = v.begin(); it != v.end(); ++it) + if (*it == df) { + v.erase(it); + break; + } + } + if (subtrees.count(newparent)) { + vector& v = subtrees[newparent]; + dout(10) << " adding " << df << " to " << newparent << " bounds " << v << dendl; + v.push_back(df); + } +} ESubtreeMap *MDCache::create_subtree_map() { dout(10) << "create_subtree_map " << num_subtrees() << " subtrees, " << num_subtrees_fullauth() << " fullauth" << dendl; - + + show_subtrees(); + ESubtreeMap *le = new ESubtreeMap(); mds->mdlog->start_entry(le); - CDir *mydir = 0; if (myin) { @@ -2233,6 +2268,62 @@ ESubtreeMap *MDCache::create_subtree_map() } } + // apply projected renames + for (map::iterator p = projected_subtree_renames.begin(); + p != projected_subtree_renames.end(); + ++p) { + CInode *diri = p->first; + CDir *olddir = diri->get_parent_dir(); + CDir *newdir = p->second; + dout(10) << " adjusting for projected rename of " << *diri << " to " << *newdir << dendl; + + list dfls; + diri->get_dirfrags(dfls); + for (list::iterator p = dfls.begin(); p != dfls.end(); ++p) { + CDir *dir = *p; + dout(10) << "dirfrag " << dir->dirfrag() << " " << *dir << dendl; + CDir *oldparent = get_subtree_root(olddir); + dout(10) << " old parent " << oldparent->dirfrag() << " " << *oldparent << dendl; + CDir *newparent = get_subtree_root(newdir); + dout(10) << " new parent " << newparent->dirfrag() << " " << *newparent << dendl; + + if (oldparent == newparent) { + dout(10) << "parent unchanged for " << dir->dirfrag() << " at " + << oldparent->dirfrag() << dendl; + continue; + } + + if (dir->is_subtree_root()) { + // children are fine. change parent. + _move_subtree_map_bound(dir->dirfrag(), oldparent->dirfrag(), newparent->dirfrag(), + le->subtrees); + } else { + // mid-subtree. + + if (oldparent->get_dir_auth() != newparent->get_dir_auth() && + oldparent->get_dir_auth().first == mds->whoami) { + dout(10) << " creating subtree for " << dir->dirfrag() << dendl; + if (le->subtrees.count(newparent->dirfrag())) + le->subtrees[newparent->dirfrag()].push_back(dir->dirfrag()); + le->subtrees[dir->dirfrag()].clear(); + newparent = dir; + } + + // see if any old bounds move to the new parent. + for (set::iterator p = subtrees[oldparent].begin(); + p != subtrees[oldparent].end(); + ++p) { + CDir *bound = *p; + CDir *broot = get_subtree_root(bound->get_parent_dir()); + if (broot != oldparent) { + _move_subtree_map_bound(bound->dirfrag(), oldparent->dirfrag(), newparent->dirfrag(), + le->subtrees); + } + } + } + } + } + // simplify the journaled map. our in memory map may have more // subtrees than needed due to migrations that are just getting // started or just completing. but on replay, the "live" map will diff --git a/src/mds/MDCache.h b/src/mds/MDCache.h index 1acb1aef25892..79c740ccb83e2 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -536,6 +536,7 @@ public: // -- subtrees -- protected: map > subtrees; // nested bounds on subtrees. + map projected_subtree_renames; // renamed ino -> target dir // adjust subtree auth specification // dir->dir_auth @@ -576,6 +577,7 @@ public: void verify_subtree_bounds(CDir *root, const set& bounds); void verify_subtree_bounds(CDir *root, const list& bounds); + void project_subtree_rename(CInode *diri, CDir *olddir); void adjust_subtree_after_rename(CInode *diri, CDir *olddir, bool imported = false); @@ -723,6 +725,8 @@ public: void send_resolve_later(int who); void maybe_send_pending_resolves(); + void _move_subtree_map_bound(dirfrag_t df, dirfrag_t oldparent, dirfrag_t newparent, + map >& subtrees); ESubtreeMap *create_subtree_map(); diff --git a/src/mds/Server.cc b/src/mds/Server.cc index b37a2b12fb3ab..81b97aa34bae4 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -4531,6 +4531,9 @@ void Server::_unlink_local(MDRequest *mdr, CDentry *dn, CDentry *straydn) dn->push_projected_linkage(); + if (in->is_dir()) + mds->mdcache->project_subtree_rename(in, straydn->get_dir()); + journal_and_reply(mdr, 0, dn, le, new C_MDS_unlink_local_finish(mds, mdr, dn, straydn)); } @@ -4662,6 +4665,8 @@ void Server::handle_slave_rmdir_prep(MDRequest *mdr) dout(10) << " noting renamed (unlinked) dir ino " << in->ino() << " in metablob" << dendl; le->commit.renamed_dirino = in->ino(); + mds->mdcache->project_subtree_rename(in, straydn->get_dir()); + mdlog->submit_entry(le, new C_MDS_SlaveRmdirPrep(this, mdr, dn, straydn)); mdlog->flush(); } @@ -4784,6 +4789,8 @@ void Server::do_rmdir_rollback(bufferlist &rbl, int master, MDRequest *mdr) dout(10) << " noting renamed (unlinked) dir ino " << in->ino() << " in metablob" << dendl; le->commit.renamed_dirino = in->ino(); + mdcache->project_subtree_rename(in, dn->get_dir()); + mdlog->submit_entry(le, new C_MDS_LoggedRmdirRollback(this, mdr, rollback.reqid, dn, straydn)); mdlog->flush(); } @@ -5672,6 +5679,9 @@ void Server::_rename_prepare(MDRequest *mdr, metablob->add_table_transaction(TABLE_ANCHOR, mdr->more()->src_reanchor_atid); if (mdr->more()->dst_reanchor_atid) metablob->add_table_transaction(TABLE_ANCHOR, mdr->more()->dst_reanchor_atid); + + if (srci->is_dir()) + mdcache->project_subtree_rename(srci, destdn->get_dir()); } @@ -6324,9 +6334,12 @@ void Server::do_rename_rollback(bufferlist &rbl, int master, MDRequest *mdr) le->commit.add_dir_context(straydir); le->commit.add_null_dentry(straydn, true); } + + if (in->is_dir()) + mdcache->project_subtree_rename(in, srcdir); mdlog->submit_entry(le, new C_MDS_LoggedRenameRollback(this, mut, mdr, - srcdnl->get_inode(), destdn->get_dir())); + srcdnl->get_inode(), destdir)); mdlog->flush(); } -- 2.39.5