From: John Spray Date: Wed, 6 Aug 2014 13:31:53 +0000 (+0100) Subject: include: generalize C_Contexts and C_Gather* X-Git-Tag: v0.86~213^2~38 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=dcdcfd306504643f73b90467775b372dcaa98d83;p=ceph.git include: generalize C_Contexts and C_Gather* ... 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 --- diff --git a/src/include/Context.h b/src/include/Context.h index d9533c5b610..88af79c5d5c 100644 --- a/src/include/Context.h +++ b/src/include/Context.h @@ -100,21 +100,21 @@ typedef ceph::shared_ptr RunOnDeleteRef; /* * finish and destroy a list of Contexts */ -inline void finish_contexts(CephContext *cct, std::list& finished, +template +inline void finish_contexts(CephContext *cct, std::list& finished, int result = 0) { if (finished.empty()) return; - list ls; + list 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::iterator it = ls.begin(); - it != ls.end(); - it++) { - Context *c = *it; + typename std::list::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 C_ContextsBase : public ContextInstanceType { public: CephContext *cct; - std::list contexts; + std::list 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& ls) { + void take(std::list& 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 &cs) { + static ContextType *list_to_context(list &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 *c(new C_ContextsBase(0)); c->take(cs); return c; } } }; +typedef C_ContextsBase C_Contexts; + + +// Forward declare GatherBuilder in order +// to be able to friend it from Gather +template +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 C_GatherBase : public ContextType { private: CephContext *cct; int result; - Context *onfinish; + ContextType *onfinish; #ifdef DEBUG_GATHER - std::set waitfor; + std::set 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 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 C_Gather; +typedef C_GatherBuilderBase C_GatherBuilder; + #undef mydout #endif