]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: implement async truncate (trimtrunc); fix log segment trim vs purge bug
authorSage Weil <sage@newdream.net>
Fri, 30 Jan 2009 00:53:10 +0000 (16:53 -0800)
committerSage Weil <sage@newdream.net>
Fri, 30 Jan 2009 19:44:33 +0000 (11:44 -0800)
Logsegs were allowed to trim even with outstanding purges.. fix.

src/mds/CInode.h
src/mds/LogSegment.h
src/mds/MDCache.cc
src/mds/MDCache.h
src/mds/MDLog.h
src/mds/MDS.cc
src/mds/Server.cc
src/mds/events/EMetaBlob.h
src/mds/journal.cc

index 7a1fe309c06a325c6141b7d2771813073f0625ea..2ada3a01e198f468d36e52edd30820af06b2e100 100644 (file)
@@ -72,6 +72,7 @@ class CInode : public MDSCacheObject {
   static const int PIN_IMPORTINGCAPS =    15;
   static const int PIN_PASTSNAPPARENT =  -16;
   static const int PIN_OPENINGSNAPPARENTS = 17;
+  static const int PIN_TRUNCATING =       18;
 
   const char *pin_name(int p) {
     switch (p) {
@@ -91,6 +92,7 @@ class CInode : public MDSCacheObject {
     case PIN_IMPORTINGCAPS: return "importingcaps";
     case PIN_PASTSNAPPARENT: return "pastsnapparent";
     case PIN_OPENINGSNAPPARENTS: return "openingsnapparents";
+    case PIN_TRUNCATING: return "truncating";
     default: return generic_pin_name(p);
     }
   }
index 80e0af1dda17b823a0b2c4b7afa5499522f46e97..7ad78df59f6b04f08565e242acfc3486a6827e52 100644 (file)
@@ -48,6 +48,7 @@ class LogSegment {
   xlist<MDSlaveUpdate*> slave_updates;
 
   //xlist<CInode*>  purging_inodes;
+  set<CInode*> truncating_inodes;
   map<CInode*, map<loff_t,loff_t> > purging_inodes;
 
   map<int, hash_set<version_t> > pending_commit_tids;  // mdstable
index e4f19269b85e34773a3a42c5b56cf977218997e4..109c8d8352f9b03d3fcc053e9bbe3d25c62fb06e 100644 (file)
@@ -4076,15 +4076,43 @@ void MDCache::set_root(CInode *in)
 
 
 
-
+// ----------------------------
+// truncate
 
 void MDCache::truncate_inode(CInode *in, LogSegment *ls)
 {
   inode_t *pi = in->get_projected_inode();
-  dout(10) << "truncate_inode " << pi->truncate_from << " -> " << pi->truncate_size
+  dout(10) << "truncate_inode "
+          << pi->truncate_from << " -> " << pi->truncate_size
           << " on " << *in
           << dendl;
 
+  ls->truncating_inodes.insert(in);
+  
+  _truncate_inode(in, ls);
+}
+
+struct C_MDC_TruncateFinish : public Context {
+  MDCache *mdc;
+  CInode *in;
+  LogSegment *ls;
+  C_MDC_TruncateFinish(MDCache *c, CInode *i, LogSegment *l) :
+    mdc(c), in(i), ls(l) {}
+  void finish(int r) {
+    mdc->truncate_inode_finish(in, ls);
+  }
+};
+
+void MDCache::_truncate_inode(CInode *in, LogSegment *ls)
+{
+  inode_t *pi = in->get_projected_inode();
+  dout(10) << "_truncate_inode "
+          << pi->truncate_from << " -> " << pi->truncate_size
+          << " on " << *in << dendl;
+
+  in->get(CInode::PIN_TRUNCATING);
+  in->auth_pin(this);
+
   SnapRealm *realm = in->find_snaprealm();
   SnapContext nullsnap;
   const SnapContext *snapc;
@@ -4099,13 +4127,82 @@ void MDCache::truncate_inode(CInode *in, LogSegment *ls)
   dout(10) << "truncate_inode snapc " << snapc << " on " << *in << dendl;
   mds->filer->truncate(in->inode.ino, &in->inode.layout, *snapc,
                       pi->truncate_size, pi->truncate_from-pi->truncate_size, pi->truncate_seq, 0,
-                      0, 0);//new C_MDC_PurgeFinish(this, in, newsize, oldsize));
+                      0, new C_MDC_TruncateFinish(this, in, ls));
+}
+
+struct C_MDC_TruncateLogged : public Context {
+  MDCache *mdc;
+  CInode *in;
+  Mutation *mut;
+  C_MDC_TruncateLogged(MDCache *m, CInode *i, Mutation *mu) : mdc(m), in(i), mut(mu) {}
+  void finish(int r) {
+    mdc->truncate_inode_logged(in, mut);
+  }
+};
+
+void MDCache::truncate_inode_finish(CInode *in, LogSegment *ls)
+{
+  dout(10) << "truncate_inode_finish " << *in << dendl;
+
+  ls->truncating_inodes.erase(in);
+
+  // update
+  inode_t *pi = in->project_inode();
+  pi->version = in->pre_dirty();
+  pi->truncate_from = 0;
+  pi->truncate_size = (__u64)-1ull;
+
+  Mutation *mut = new Mutation;
+  mut->ls = mds->mdlog->get_current_segment();
+  mut->add_projected_inode(in);
+
+  EUpdate *le = new EUpdate(mds->mdlog, "truncate finish");
+  le->metablob.add_dir_context(in->get_parent_dir());
+  le->metablob.add_primary_dentry(in->get_projected_parent_dn(), true, in, pi);
+  le->metablob.add_truncate_finish(in->ino(), ls->offset);
+
+  journal_dirty_inode(mut, &le->metablob, in);
+  mds->mdlog->submit_entry(le, new C_MDC_TruncateLogged(this, in, mut));
+}
+
+void MDCache::truncate_inode_logged(CInode *in, Mutation *mut)
+{
+  dout(10) << "truncate_inode_logged " << *in << dendl;
+  mut->apply();
+  delete mut;
 
+  in->put(CInode::PIN_TRUNCATING);
+  in->auth_unpin(this);
 
+  list<Context*> waiters;
+  in->take_waiting(CInode::WAIT_TRUNC, waiters);
+  mds->queue_waiters(waiters);
 }
 
-// **************
-// Inode purging -- reliably removing deleted file's objects
+
+void MDCache::add_recovered_truncate(CInode *in, LogSegment *ls)
+{
+  ls->truncating_inodes.insert(in);
+}
+
+void MDCache::start_recovered_truncates()
+{
+  dout(10) << "start_recovered_truncates" << dendl;
+  for (map<loff_t,LogSegment*>::iterator p = mds->mdlog->segments.begin();
+       p != mds->mdlog->segments.end();
+       p++) {
+    LogSegment *ls = p->second;
+    for (set<CInode*>::iterator q = ls->truncating_inodes.begin();
+        q != ls->truncating_inodes.end();
+        q++)
+      _truncate_inode(*q, ls);
+  }
+}
+
+
+
+// ----------------------------
+// purge
 
 class C_MDC_PurgeFinish : public Context {
   MDCache *mdc;
index b78ecdeae39733177da44687cb5076a47269424f..d572bc954b6589da73da466215a4c5c1ea209e11 100644 (file)
@@ -825,6 +825,13 @@ public:
  public:
   // truncate
   void truncate_inode(CInode *in, LogSegment *ls);
+  void _truncate_inode(CInode *in, LogSegment *ls);
+  void truncate_inode_finish(CInode *in, LogSegment *ls);
+  void truncate_inode_logged(CInode *in, Mutation *mut);
+
+  void add_recovered_truncate(CInode *in, LogSegment *ls);
+  void remove_recovered_truncate(CInode *in);
+  void start_recovered_truncates();
 
   // inode purging
   void purge_inode(CInode *in, loff_t newsize, loff_t oldsize, LogSegment *ls);
index 83de89ed4dd783462d06acadbccd7ffff06afe59..f78938af97325b180d34120b11987e6fdaa32f72 100644 (file)
@@ -145,6 +145,12 @@ public:
     return segments.empty() ? 0:segments.rbegin()->second; 
   }
 
+  LogSegment *get_segment(__u64 off) {
+    if (segments.count(off))
+      return segments[off];
+    return NULL;
+  }
+
 
   void flush_logger();
 
index 23764fb1d84470853705218ba22912c3ba9f3bee..d07c013ed8144c32c26609ca02dee6fa7f3d0550 100644 (file)
@@ -1030,6 +1030,7 @@ void MDS::recovery_done()
   anchorclient->finish_recovery();
   snapclient->finish_recovery();
   
+  mdcache->start_recovered_truncates();
   mdcache->start_recovered_purges();
   mdcache->do_file_recover();
   
index ba3fd9cefbb4ce6e5e78b6e38b6c54e431fc47a1..41a821848ea78357961bba86dfa088de86596c19 100644 (file)
@@ -4770,16 +4770,6 @@ void Server::handle_slave_rename_prep_ack(MDRequest *mdr, MMDSSlaveRequest *ack)
 // ===================================
 // TRUNCATE, FSYNC
 
-struct DelayTrunc : public Context {
-  MDS *mds;
-  CInode *in;
-  LogSegment *ls;
-  DelayTrunc(MDS *m, CInode *i, LogSegment *l) : mds(m), in(i), ls(l) {}
-  void finish(int r) {
-    mds->mdcache->truncate_inode(in, ls);
-  }
-};
-
 class C_MDS_truncate_logged : public Context {
   MDS *mds;
   MDRequest *mdr;
@@ -4796,8 +4786,7 @@ public:
 
     // notify any clients
     mds->locker->issue_truncate(in);
-    //mds->mdcache->truncate_inode(in, mdr->ls);
-    mds->timer.add_event_after(10.0, new DelayTrunc(mds, in, mdr->ls));
+    mds->mdcache->truncate_inode(in, mdr->ls);
 
     mds->balancer->hit_inode(mdr->now, in, META_POP_IWR);   
 
@@ -4855,7 +4844,6 @@ void Server::handle_client_truncate(MDRequest *mdr)
   mdr->ls = mdlog->get_current_segment();
   EUpdate *le = new EUpdate(mdlog, "truncate");
   le->metablob.add_client_req(mdr->reqid);
-  le->metablob.add_inode_truncate(cur->ino(), req->head.args.truncate.length, cur->inode.size);
   pi = cur->project_inode();
   pi->mtime = ctime;
   pi->ctime = ctime;
@@ -4867,6 +4855,7 @@ void Server::handle_client_truncate(MDRequest *mdr)
     pi->rstat.rbytes = pi->size;
     pi->truncate_size = pi->size;
     pi->truncate_seq++;
+    le->metablob.add_truncate_start(cur->ino());
   } else {
     // truncate to larger size
     pi->size = req->head.args.truncate.length;
@@ -5083,7 +5072,7 @@ void Server::handle_client_opent(MDRequest *mdr)
   mdr->ls = mdlog->get_current_segment();
   EUpdate *le = new EUpdate(mdlog, "open_truncate");
   le->metablob.add_client_req(mdr->reqid);
-  le->metablob.add_inode_truncate(cur->ino(), 0, cur->inode.size);
+  le->metablob.add_inode_purge(cur->ino(), 0, cur->inode.size);
   inode_t *pi = cur->project_inode();
   pi->mtime = ctime;
   pi->ctime = ctime;
index f4511b33a21587d0ee385a9f9d3f17849be8a9db..0d269b8706783e5e38661857489214a7fa047fa2 100644 (file)
@@ -333,7 +333,10 @@ private:
   entity_name_t client_name;          //            session
 
   // inodes i've truncated
-  list< triple<inodeno_t,uint64_t,uint64_t> > truncated_inodes;
+  list<inodeno_t> truncate_start;        // start truncate 
+  map<inodeno_t,__u64> truncate_finish;  // finished truncate (started in segment blah)
+
+  list< triple<inodeno_t,uint64_t,uint64_t> > purging_inodes;
   vector<inodeno_t> destroyed_inodes;
 
   // idempotent op(s)
@@ -351,7 +354,9 @@ private:
     ::encode(client_name, bl);
     ::encode(inotablev, bl);
     ::encode(sessionmapv, bl);
-    ::encode(truncated_inodes, bl);
+    ::encode(truncate_start, bl);
+    ::encode(truncate_finish, bl);
+    ::encode(purging_inodes, bl);
     ::encode(destroyed_inodes, bl);
     ::encode(client_reqs, bl);
   } 
@@ -366,7 +371,9 @@ private:
     ::decode(client_name, bl);
     ::decode(inotablev, bl);
     ::decode(sessionmapv, bl);
-    ::decode(truncated_inodes, bl);
+    ::decode(truncate_start, bl);
+    ::decode(truncate_finish, bl);
+    ::decode(purging_inodes, bl);
     ::decode(destroyed_inodes, bl);
     ::decode(client_reqs, bl);
   }
@@ -415,8 +422,15 @@ private:
     inotablev = iv;
   }
 
-  void add_inode_truncate(inodeno_t ino, uint64_t newsize, uint64_t oldsize) {
-    truncated_inodes.push_back(triple<inodeno_t,uint64_t,uint64_t>(ino, newsize, oldsize));
+  void add_truncate_start(inodeno_t ino) {
+    truncate_start.push_back(ino);
+  }
+  void add_truncate_finish(inodeno_t ino, __u64 segoff) {
+    truncate_finish[ino] = segoff;
+  }
+
+  void add_inode_purge(inodeno_t ino, uint64_t newsize, uint64_t oldsize) {
+    purging_inodes.push_back(triple<inodeno_t,uint64_t,uint64_t>(ino, newsize, oldsize));
   }
   void add_destroyed_inode(inodeno_t ino) {
     destroyed_inodes.push_back(ino);
index d180f7ac11e21a3f32941928bdc3f8cef3dd0a4e..e583008b25de35ee18a275ff8fca168f4173295e 100644 (file)
@@ -230,6 +230,25 @@ C_Gather *LogSegment::try_to_expire(MDS *mds)
     }
   }
 
+  // truncating
+  for (set<CInode*>::iterator p = truncating_inodes.begin();
+       p != truncating_inodes.end();
+       p++) {
+    dout(10) << "try_to_expire waiting for truncate of " << **p << dendl;
+    if (!gather) gather = new C_Gather;
+    (*p)->add_waiter(CInode::WAIT_TRUNC, gather->new_sub());
+  }
+  
+  // purging
+  for (map<CInode*, map<loff_t,loff_t> >::iterator p = purging_inodes.begin();
+       p != purging_inodes.end();
+       ++p) {
+    CInode *in = p->first;
+    dout(10) << "try_to_expire waiting for purge of " << *in << dendl;
+    if (!gather) gather = new C_Gather;
+    mds->mdcache->wait_for_purge(in, p->second.begin()->first, gather->new_sub());
+  }
+
   // FIXME client requests...?
   // audit handling of anchor transactions?
 
@@ -548,13 +567,32 @@ void EMetaBlob::replay(MDS *mds, LogSegment *logseg)
     }
   }
 
-  // truncated inodes
-  for (list< triple<inodeno_t,uint64_t,uint64_t> >::iterator p = truncated_inodes.begin();
-       p != truncated_inodes.end();
+  // truncating inodes
+  for (list<inodeno_t>::iterator p = truncate_start.begin();
+       p != truncate_start.end();
+       p++) {
+    CInode *in = mds->mdcache->get_inode(*p);
+    assert(in);
+    mds->mdcache->add_recovered_truncate(in, logseg);
+  }
+  for (map<inodeno_t,__u64>::iterator p = truncate_finish.begin();
+       p != truncate_finish.end();
+       p++) {
+    LogSegment *ls = mds->mdlog->get_segment(p->second);
+    if (ls) {
+      CInode *in = mds->mdcache->get_inode(p->first);
+      assert(in);
+      ls->truncating_inodes.erase(in);
+    }
+  }
+
+  // purging inodes
+  for (list< triple<inodeno_t,uint64_t,uint64_t> >::iterator p = purging_inodes.begin();
+       p != purging_inodes.end();
        ++p) {
     CInode *in = mds->mdcache->get_inode(p->first);
     assert(in);
-    dout(10) << "EMetaBlob.replay will purge truncated " 
+    dout(10) << "EMetaBlob.replay will purging " 
             << p->third << " -> " << p->second
             << " on " << *in << dendl;
     mds->mdcache->add_recovered_purge(in, p->second, p->third, logseg);