]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: add scatterpins
authorSage Weil <sage@newdream.net>
Wed, 22 Sep 2010 22:41:24 +0000 (15:41 -0700)
committerSage Weil <sage@newdream.net>
Thu, 23 Sep 2010 23:44:47 +0000 (16:44 -0700)
src/mds/CInode.cc
src/mds/CInode.h
src/mds/Locker.cc
src/mds/Locker.h
src/mds/ScatterLock.h
src/mds/SimpleLock.h

index f8799cf6122260932544814037f99b36280bbf62..cea9981f38c4a204eaed3a6e2e5db49f2095a2db 100644 (file)
@@ -152,6 +152,9 @@ ostream& operator<<(ostream& out, CInode& in)
     out << " need_snapflush=" << in.client_need_snapflush;
 
 
+  if (in.scatter_pins > 0)
+    out << " scatter_pins=" << in.scatter_pins;
+
   // locks
   if (!in.authlock.is_sync_and_unlocked())
     out << " " << in.authlock;
@@ -1511,6 +1514,20 @@ void CInode::finish_scatter_gather_update_accounted(int type, Mutation *mut, EMe
   }
 }
 
+void CInode::put_scatter_pin(list<Context*>& ls)
+{
+  assert(scatter_pins > 0);
+  scatter_pins--;
+  if (scatter_pins == 0) {
+    dirfragtreelock.take_waiting(SimpleLock::WAIT_ALL, ls);
+    filelock.take_waiting(SimpleLock::WAIT_ALL, ls);
+    nestlock.take_waiting(SimpleLock::WAIT_ALL, ls);
+    ls.push_back(new Locker::C_EvalScatterGathers(mdcache->mds->locker, this));
+  }
+}
+
+
+
 // waiting
 
 bool CInode::is_frozen()
index cacd9a6a13de7fe88a5b0745f4a6c1dfb40b0ade..98c36748aa9e0eca23b656f2d2dc4d5193a4f8d7 100644 (file)
@@ -400,6 +400,7 @@ private:
     snaplock(this, &snaplock_type),
     nestlock(this, &nestlock_type),
     flocklock(this, &flocklock_type),
+    scatter_pins(0),
     loner_cap(-1), want_loner_cap(-1)
   {
     g_num_ino++;
@@ -584,6 +585,8 @@ public:
   ScatterLock nestlock;
   SimpleLock flocklock;
 
+  int scatter_pins;
+
   SimpleLock* get_lock(int type) {
     switch (type) {
     case CEPH_LOCK_IFILE: return &filelock;
@@ -608,6 +611,21 @@ public:
   void finish_scatter_gather_update(int type);
   void finish_scatter_gather_update_accounted(int type, Mutation *mut, EMetaBlob *metablob);
 
+  // scatter pins prevent either a scatter or unscatter on _any_
+  // scatterlock for this inode.
+  bool is_scatter_pinned() {
+    return scatter_pins > 0;
+  }
+  bool can_scatter_pin() {
+    return 
+      dirfragtreelock.can_scatter_pin(get_loner()) &&
+      filelock.can_scatter_pin(get_loner()) &&
+      nestlock.can_scatter_pin(get_loner());
+  }
+  void get_scatter_pin() {
+    scatter_pins++;
+  }
+  void put_scatter_pin(list<Context*>& ls);
 
   // -- snap --
   void open_snaprealm(bool no_split=false);
index 4a7da21e43943aa0c6fbb2dfead22db249539cd6..4203aefc50a9de1faf289b67e45713e59bf036dd 100644 (file)
@@ -452,6 +452,7 @@ void Locker::eval_gather(SimpleLock *lock, bool first, bool *pneed_issue, list<C
       (IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_wrlock, auth) || !lock->is_wrlocked()) &&
       (IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_xlock, auth) || !lock->is_xlocked()) &&
       (IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_lease, auth) || !lock->is_leased()) &&
+      (!in || !in->is_scatter_pinned() || !lock->is_scatterlock()) &&
       (!caps || ((~lock->gcaps_allowed(CAP_ANY, next) & other_issued) == 0 &&
                 (~lock->gcaps_allowed(CAP_LONER, next) & loner_issued) == 0 &&
                 (~lock->gcaps_allowed(CAP_XLOCKER, next) & xlocker_issued) == 0)) &&
@@ -705,6 +706,27 @@ void Locker::eval_cap_gather(CInode *in)
   finish_contexts(finishers);
 }
 
+void Locker::eval_scatter_gathers(CInode *in)
+{
+  bool need_issue = false;
+  list<Context*> finishers;
+
+  dout(10) << "eval_scatter_gathers " << *in << dendl;
+
+  // kick locks now
+  if (!in->filelock.is_stable())
+    eval_gather(&in->filelock, false, &need_issue, &finishers);
+  if (!in->nestlock.is_stable())
+    eval_gather(&in->nestlock, false, &need_issue, &finishers);
+  if (!in->dirfragtreelock.is_stable())
+    eval_gather(&in->dirfragtreelock, false, &need_issue, &finishers);
+  
+  if (need_issue && in->is_head())
+    issue_caps(in);
+  
+  finish_contexts(finishers);
+}
+
 void Locker::eval(SimpleLock *lock, bool *need_issue)
 {
   switch (lock->get_type()) {
@@ -3125,6 +3147,8 @@ void Locker::scatter_writebehind(ScatterLock *lock)
   CInode *in = (CInode*)lock->get_parent();
   dout(10) << "scatter_writebehind " << in->inode.mtime << " on " << *lock << " on " << *in << dendl;
 
+  assert(!in->is_scatter_pinned());
+
   // journal
   Mutation *mut = new Mutation;
   mut->ls = mds->mdlog->get_current_segment();
@@ -3233,6 +3257,15 @@ void Locker::scatter_nudge(ScatterLock *lock, Context *c, bool forcelockchange)
 {
   CInode *p = (CInode *)lock->get_parent();
 
+  if (p->is_scatter_pinned()) {
+    dout(10) << "scatter_nudge waiting for scatter pin release on " << *p << dendl;
+    if (c) 
+      p->filelock.add_waiter(SimpleLock::WAIT_RD, c);
+    else
+      // just requeue.  not ideal.. starvation prone..
+      updated_scatterlocks.push_back(lock->get_updated_item());
+    return;
+  }
   if (p->is_frozen() || p->is_freezing()) {
     dout(10) << "scatter_nudge waiting for unfreeze on " << *p << dendl;
     if (c) 
index 7bf36b358d7ff796068f90be9c4f82b1041c1f4d..63a4628ce9020675a5382ef6e215dded8fe98d3d 100644 (file)
@@ -99,6 +99,20 @@ public:
       eval(lock, need_issue);
   }
 
+  class C_EvalScatterGathers : public Context {
+    Locker *locker;
+    CInode *in;
+  public:
+    C_EvalScatterGathers(Locker *l, CInode *i) : locker(l), in(i) {
+      in->get(CInode::PIN_PTRWAITER);    
+    }
+    void finish(int r) {
+      in->put(CInode::PIN_PTRWAITER);
+      locker->eval_scatter_gathers(in);
+    }
+  };
+  void eval_scatter_gathers(CInode *in);
+
   void eval_cap_gather(CInode *in);
 
   bool eval(CInode *in, int mask);
index ea593e41eb99cbaff74f81b3793aceacc95b9df8..ad1c0aa96b8a1c9aaca54f2873bea42eba2468b2 100644 (file)
@@ -64,6 +64,10 @@ public:
     }
   }
 
+  bool is_scatterlock() const {
+    return true;
+  }
+
   bool is_sync_and_unlocked() const {
     return
       SimpleLock::is_sync_and_unlocked() && 
@@ -71,6 +75,9 @@ public:
       !is_flushing();
   }
 
+  bool can_scatter_pin(client_t loner) {
+    return can_rdlock(-1) || can_wrlock(loner);
+  }
 
   xlist<ScatterLock*>::item *get_updated_item() { return &more()->item_updated; }
   utime_t get_update_stamp() { return more()->update_stamp; }
index 2e06b279d7331a85d62127a2d52f834943a62802..a5c2390153cbaac940a531aa046885616136af0e 100644 (file)
@@ -220,6 +220,10 @@ public:
     delete _unstable;
   }
 
+  virtual bool is_scatterlock() const {
+    return false;
+  }
+
   // parent
   MDSCacheObject *get_parent() { return parent; }
   int get_type() { return type->type; }