]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
include: generalize C_Contexts and C_Gather*
authorJohn Spray <john.spray@redhat.com>
Wed, 6 Aug 2014 13:31:53 +0000 (14:31 +0100)
committerJohn Spray <john.spray@redhat.com>
Mon, 25 Aug 2014 00:34:17 +0000 (01:34 +0100)
... by making them templates so that they can be
used in places that expect a subclass of Context.

The existing names are now typedefs to template
instantiations using Context.

Signed-off-by: John Spray <john.spray@redhat.com>
src/include/Context.h

index d9533c5b61068c66b15bc22e6492151a64ccbc05..88af79c5d5ce7be83e48df6160aa5c1217852cd2 100644 (file)
@@ -100,21 +100,21 @@ typedef ceph::shared_ptr<RunOnDelete> RunOnDeleteRef;
 /*
  * finish and destroy a list of Contexts
  */
-inline void finish_contexts(CephContext *cct, std::list<Context*>& finished, 
+template<class A>
+inline void finish_contexts(CephContext *cct, std::list<A*>& finished, 
                             int result = 0)
 {
   if (finished.empty())
     return;
 
-  list<Context*> ls;
+  list<A*> ls;
   ls.swap(finished); // swap out of place to avoid weird loops
 
   if (cct)
     mydout(cct, 10) << ls.size() << " contexts to finish with " << result << dendl;
-  for (std::list<Context*>::iterator it = ls.begin(); 
-       it != ls.end(); 
-       it++) {
-    Context *c = *it;
+  typename std::list<A*>::iterator it;
+  for (it = ls.begin(); it != ls.end(); it++) {
+    A *c = *it;
     if (cct)
       mydout(cct,10) << "---- " << c << dendl;
     c->complete(result);
@@ -167,70 +167,91 @@ struct C_Lock : public Context {
 
 /*
  * C_Contexts - set of Contexts
+ *
+ * ContextType must be an ancestor class of ContextInstanceType, or the same class.
+ * ContextInstanceType must be default-constructable.
  */
-class C_Contexts : public Context {
+template <class ContextType, class ContextInstanceType>
+class C_ContextsBase : public ContextInstanceType {
 public:
   CephContext *cct;
-  std::list<Context*> contexts;
+  std::list<ContextType*> contexts;
 
-  C_Contexts(CephContext *cct_)
+  C_ContextsBase(CephContext *cct_)
     : cct(cct_)
   {
   }
 
-  void add(Context* c) {
+  void add(ContextType* c) {
     contexts.push_back(c);
   }
-  void take(std::list<Context*>& ls) {
+  void take(std::list<ContextType*>& ls) {
     contexts.splice(contexts.end(), ls);
   }
+  void complete(int r) {
+    // Neuter any ContextInstanceType custom complete(), because although
+    // I want to look like him, I don't actually want to run his code.
+    Context::complete(r);
+  }
   void finish(int r) {
     finish_contexts(cct, contexts, r);
   }
   bool empty() { return contexts.empty(); }
 
-  static Context *list_to_context(list<Context *> &cs) {
+  static ContextType *list_to_context(list<ContextType *> &cs) {
     if (cs.size() == 0) {
       return 0;
     } else if (cs.size() == 1) {
-      Context *c = cs.front();
+      ContextType *c = cs.front();
       cs.clear();
       return c;
     } else {
-      C_Contexts *c(new C_Contexts(0));
+      C_ContextsBase<ContextType, ContextInstanceType> *c(new C_ContextsBase<ContextType, ContextInstanceType>(0));
       c->take(cs);
       return c;
     }
   }
 };
 
+typedef C_ContextsBase<Context, Context> C_Contexts;
+
+
+// Forward declare GatherBuilder in order
+// to be able to friend it from Gather
+template <class ContextType, class GatherType>
+class C_GatherBuilderBase;
+
 
 /*
  * C_Gather
  *
+ * ContextType must be an ancestor class of ContextInstanceType, or the same class.
+ * ContextInstanceType must be default-constructable.
+ *
  * BUG:? only reports error from last sub to have an error return
  */
-class C_Gather : public Context {
+template <class ContextType, class ContextInstanceType>
+class C_GatherBase : public ContextType {
 private:
   CephContext *cct;
   int result;
-  Context *onfinish;
+  ContextType *onfinish;
 #ifdef DEBUG_GATHER
-  std::set<Context*> waitfor;
+  std::set<ContextType*> waitfor;
 #endif
   int sub_created_count;
   int sub_existing_count;
-  Mutex lock;
+  mutable Mutex lock;
   bool activated;
 
-  void sub_finish(Context* sub, int r) {
+  void sub_finish(ContextType* sub, int r) {
     lock.Lock();
 #ifdef DEBUG_GATHER
     assert(waitfor.count(sub));
     waitfor.erase(sub);
 #endif
     --sub_existing_count;
-    mydout(cct,10) << "C_Gather " << this << ".sub_finish(r=" << r << ") " << sub
+    mydout(cct,10) << "C_GatherBase " << this << ".sub_finish(r=" << r << ") " << sub
 #ifdef DEBUG_GATHER
                    << " (remaining " << waitfor << ")"
 #endif
@@ -253,10 +274,17 @@ private:
     delete this;
   }
 
-  class C_GatherSub : public Context {
-    C_Gather *gather;
+  class C_GatherSub : public ContextInstanceType {
+    C_GatherBase *gather;
   public:
-    C_GatherSub(C_Gather *g) : gather(g) {}
+    C_GatherSub(C_GatherBase *g) : gather(g) {}
+    void complete(int r) {
+      // Cancel any customized complete() functionality
+      // from the Context subclass we're templated for,
+      // we only want to hit that in onfinish, not at each
+      // sub finish.  e.g. MDSInternalContext.
+      Context::complete(r);
+    }
     void finish(int r) {
       gather->sub_finish(this, r);
       gather = 0;
@@ -267,19 +295,19 @@ private:
     }
   };
 
-  C_Gather(CephContext *cct_, Context *onfinish_)
+public:
+  C_GatherBase(CephContext *cct_, ContextType *onfinish_)
     : cct(cct_), result(0), onfinish(onfinish_),
       sub_created_count(0), sub_existing_count(0),
-      lock("C_Gather::lock", true, false), //disable lockdep
+      lock("C_GatherBase::lock", true, false), //disable lockdep
       activated(false)
   {
-    mydout(cct,10) << "C_Gather " << this << ".new" << dendl;
+    mydout(cct,10) << "C_GatherBase " << this << ".new" << dendl;
   }
-public:
-  ~C_Gather() {
-    mydout(cct,10) << "C_Gather " << this << ".delete" << dendl;
+  ~C_GatherBase() {
+    mydout(cct,10) << "C_GatherBase " << this << ".delete" << dendl;
   }
-  void set_finisher(Context *onfinish_) {
+  void set_finisher(ContextType *onfinish_) {
     Mutex::Locker l(lock);
     assert(!onfinish);
     onfinish = onfinish_;
@@ -295,22 +323,31 @@ public:
     lock.Unlock();
     delete_me();
   }
-  Context *new_sub() {
+  ContextType *new_sub() {
     Mutex::Locker l(lock);
     assert(activated == false);
     sub_created_count++;
     sub_existing_count++;
-    Context *s = new C_GatherSub(this);
+    ContextType *s = new C_GatherSub(this);
 #ifdef DEBUG_GATHER
     waitfor.insert(s);
 #endif
-    mydout(cct,10) << "C_Gather " << this << ".new_sub is " << sub_created_count << " " << s << dendl;
+    mydout(cct,10) << "C_GatherBase " << this << ".new_sub is " << sub_created_count << " " << s << dendl;
     return s;
   }
   void finish(int r) {
     assert(0);    // nobody should ever call me.
   }
-  friend class C_GatherBuilder;
+
+  inline int get_sub_existing_count() const {
+    Mutex::Locker l(lock);
+    return sub_existing_count;
+  }
+
+  inline int get_sub_created_count() const {
+    Mutex::Locker l(lock);
+    return sub_created_count;
+  }
 };
 
 /*
@@ -329,18 +366,19 @@ public:
  *
  * Note: Currently, subs must be manually freed by the caller (for some reason.)
  */
-class C_GatherBuilder
+template <class ContextType, class GatherType>
+class C_GatherBuilderBase
 {
 public:
-  C_GatherBuilder(CephContext *cct_)
+  C_GatherBuilderBase(CephContext *cct_)
     : cct(cct_), c_gather(NULL), finisher(NULL), activated(false)
   {
   }
-  C_GatherBuilder(CephContext *cct_, Context *finisher_)
+  C_GatherBuilderBase(CephContext *cct_, ContextType *finisher_)
     : cct(cct_), c_gather(NULL), finisher(finisher_), activated(false)
   {
   }
-  ~C_GatherBuilder() {
+  ~C_GatherBuilderBase() {
     if (c_gather) {
       assert(activated); // Don't forget to activate your C_Gather!
     }
@@ -348,9 +386,9 @@ public:
       delete finisher;
     }
   }
-  Context *new_sub() {
+  ContextType *new_sub() {
     if (!c_gather) {
-      c_gather = new C_Gather(cct, finisher);
+      c_gather = new GatherType(cct, finisher);
     }
     return c_gather->new_sub();
   }
@@ -361,12 +399,12 @@ public:
     activated = true;
     c_gather->activate();
   }
-  void set_finisher(Context *finisher_) {
+  void set_finisher(ContextType *finisher_) {
     finisher = finisher_;
     if (c_gather)
       c_gather->set_finisher(finisher);
   }
-  C_Gather *get() const {
+  GatherType *get() const {
     return c_gather;
   }
   bool has_subs() const {
@@ -376,24 +414,25 @@ public:
     assert(!activated);
     if (c_gather == NULL)
       return 0;
-    Mutex::Locker l(c_gather->lock); 
-    return c_gather->sub_created_count;
+    return c_gather->get_sub_created_count();
   }
   int num_subs_remaining() {
     assert(!activated);
     if (c_gather == NULL)
       return 0;
-    Mutex::Locker l(c_gather->lock);
-    return c_gather->sub_existing_count;
+    return c_gather->get_sub_existing_count();
   }
 
 private:
   CephContext *cct;
-  C_Gather *c_gather;
-  Context *finisher;
+  GatherType *c_gather;
+  ContextType *finisher;
   bool activated;
 };
 
+typedef C_GatherBase<Context, Context> C_Gather;
+typedef C_GatherBuilderBase<Context, C_Gather > C_GatherBuilder;
+
 #undef mydout
 
 #endif