]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: track projected rename effect on subtree map
authorSage Weil <sage@newdream.net>
Tue, 26 Jul 2011 21:58:35 +0000 (14:58 -0700)
committerSage Weil <sage.weil@dreamhost.com>
Wed, 27 Jul 2011 03:44:17 +0000 (20:44 -0700)
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 <sage@newdream.net>
src/mds/MDCache.cc
src/mds/MDCache.h
src/mds/Server.cc

index 902d3d6875b13d0759c3a65d68ff9901079826e0..6b57a114e83a831662ffaa515d030fbd4d05d4ad 100644 (file)
@@ -1209,6 +1209,12 @@ void MDCache::verify_subtree_bounds(CDir *dir, const list<dirfrag_t>& 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<CInode*,CDir*>::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<CDir*> 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<dirfrag_t,vector<dirfrag_t> >& subtrees)
+{
+  if (subtrees.count(oldparent)) {
+      vector<dirfrag_t>& v = subtrees[oldparent];
+      dout(10) << " removing " << df << " from " << oldparent << " bounds " << v << dendl;
+      for (vector<dirfrag_t>::iterator it = v.begin(); it != v.end(); ++it)
+       if (*it == df) {
+         v.erase(it);
+         break;
+       }
+    }
+  if (subtrees.count(newparent)) {
+    vector<dirfrag_t>& 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<CInode*,CDir*>::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<CDir*> dfls;
+    diri->get_dirfrags(dfls);
+    for (list<CDir*>::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<CDir*>::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
index 1acb1aef2589228447c041dee57da10f9eacd657..79c740ccb83e224a82346f317a234a57560d63b5 100644 (file)
@@ -536,6 +536,7 @@ public:
   // -- subtrees --
 protected:
   map<CDir*,set<CDir*> > subtrees;   // nested bounds on subtrees.
+  map<CInode*,CDir*> 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<CDir*>& bounds);
   void verify_subtree_bounds(CDir *root, const list<dirfrag_t>& 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<dirfrag_t,vector<dirfrag_t> >& subtrees);
   ESubtreeMap *create_subtree_map();
 
 
index b37a2b12fb3ab7f6814d3ce1c7700d058945b547..81b97aa34bae4b4f0c5b01bba3691f5b924cc630 100644 (file)
@@ -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();
 }