initial code repo
[stor4nfv.git] / src / ceph / src / include / Context.h
diff --git a/src/ceph/src/include/Context.h b/src/ceph/src/include/Context.h
new file mode 100644 (file)
index 0000000..e30c3f6
--- /dev/null
@@ -0,0 +1,501 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software 
+ * Foundation.  See file COPYING.
+ * 
+ */
+
+
+#ifndef CEPH_CONTEXT_H
+#define CEPH_CONTEXT_H
+
+#include "common/dout.h"
+
+#include <boost/function.hpp>
+#include <list>
+#include <set>
+#include <memory>
+
+#include "include/assert.h"
+#include "include/memory.h"
+
+#define mydout(cct, v) lgeneric_subdout(cct, context, v)
+
+/*
+ * GenContext - abstract callback class
+ */
+template <typename T>
+class GenContext {
+  GenContext(const GenContext& other);
+  const GenContext& operator=(const GenContext& other);
+
+ protected:
+  virtual void finish(T t) = 0;
+
+ public:
+  GenContext() {}
+  virtual ~GenContext() {}       // we want a virtual destructor!!!
+
+  template <typename C>
+  void complete(C &&t) {
+    finish(std::forward<C>(t));
+    delete this;
+  }
+};
+
+template <typename T>
+using GenContextURef = std::unique_ptr<GenContext<T> >;
+
+/*
+ * Context - abstract callback class
+ */
+class Context {
+  Context(const Context& other);
+  const Context& operator=(const Context& other);
+
+ protected:
+  virtual void finish(int r) = 0;
+
+ public:
+  Context() {}
+  virtual ~Context() {}       // we want a virtual destructor!!!
+  virtual void complete(int r) {
+    finish(r);
+    delete this;
+  }
+};
+
+/**
+ * Simple context holding a single object
+ */
+template<class T>
+class ContainerContext : public Context {
+  T obj;
+public:
+  ContainerContext(T &obj) : obj(obj) {}
+  void finish(int r) override {}
+};
+template <typename T>
+ContainerContext<T> *make_container_context(T &&t) {
+  return new ContainerContext<T>(std::forward<T>(t));
+}
+
+template <class T>
+struct Wrapper : public Context {
+  Context *to_run;
+  T val;
+  Wrapper(Context *to_run, T val) : to_run(to_run), val(val) {}
+  void finish(int r) override {
+    if (to_run)
+      to_run->complete(r);
+  }
+};
+struct RunOnDelete {
+  Context *to_run;
+  RunOnDelete(Context *to_run) : to_run(to_run) {}
+  ~RunOnDelete() {
+    if (to_run)
+      to_run->complete(0);
+  }
+};
+typedef ceph::shared_ptr<RunOnDelete> RunOnDeleteRef;
+
+template <typename T>
+struct LambdaContext : public Context {
+  T t;
+  LambdaContext(T &&t) : t(std::forward<T>(t)) {}
+  void finish(int) override {
+    t();
+  }
+};
+template <typename T>
+LambdaContext<T> *make_lambda_context(T &&t) {
+  return new LambdaContext<T>(std::move(t));
+}
+
+template <typename F, typename T>
+struct LambdaGenContext : GenContext<T> {
+  F f;
+  LambdaGenContext(F &&f) : f(std::forward<F>(f)) {}
+  void finish(T t) override {
+    f(std::forward<T>(t));
+  }
+};
+template <typename T, typename F>
+GenContextURef<T> make_gen_lambda_context(F &&f) {
+  return GenContextURef<T>(new LambdaGenContext<F, T>(std::move(f)));
+}
+
+/*
+ * finish and destroy a list of Contexts
+ */
+template<class A>
+inline void finish_contexts(CephContext *cct, std::list<A*>& finished, 
+                            int result = 0)
+{
+  if (finished.empty())
+    return;
+
+  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;
+  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);
+  }
+}
+
+inline void finish_contexts(CephContext *cct, std::vector<Context*>& finished, 
+                            int result = 0)
+{
+  if (finished.empty())
+    return;
+
+  vector<Context*> 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::vector<Context*>::iterator it = ls.begin(); 
+       it != ls.end(); 
+       it++) {
+    Context *c = *it;
+    if (cct)
+      mydout(cct,10) << "---- " << c << dendl;
+    c->complete(result);
+  }
+}
+
+class C_NoopContext : public Context {
+public:
+  void finish(int r) override { }
+};
+
+
+struct C_Lock : public Context {
+  Mutex *lock;
+  Context *fin;
+  C_Lock(Mutex *l, Context *c) : lock(l), fin(c) {}
+  ~C_Lock() override {
+    delete fin;
+  }
+  void finish(int r) override {
+    if (fin) {
+      lock->Lock();
+      fin->complete(r);
+      fin = NULL;
+      lock->Unlock();
+    }
+  }
+};
+
+/*
+ * C_Contexts - set of Contexts
+ *
+ * ContextType must be an ancestor class of ContextInstanceType, or the same class.
+ * ContextInstanceType must be default-constructable.
+ */
+template <class ContextType, class ContextInstanceType>
+class C_ContextsBase : public ContextInstanceType {
+public:
+  CephContext *cct;
+  std::list<ContextType*> contexts;
+
+  C_ContextsBase(CephContext *cct_)
+    : cct(cct_)
+  {
+  }
+  ~C_ContextsBase() override {
+    for (auto c : contexts) {
+      delete c;
+    }
+  }
+  void add(ContextType* c) {
+    contexts.push_back(c);
+  }
+  void take(std::list<ContextType*>& ls) {
+    contexts.splice(contexts.end(), ls);
+  }
+  void complete(int r) override {
+    // Neuter any ContextInstanceType custom complete(), because although
+    // I want to look like it, I don't actually want to run its code.
+    Context::complete(r);
+  }
+  void finish(int r) override {
+    finish_contexts(cct, contexts, r);
+  }
+  bool empty() { return contexts.empty(); }
+
+  static ContextType *list_to_context(list<ContextType *> &cs) {
+    if (cs.size() == 0) {
+      return 0;
+    } else if (cs.size() == 1) {
+      ContextType *c = cs.front();
+      cs.clear();
+      return c;
+    } else {
+      C_ContextsBase<ContextType, ContextInstanceType> *c(new C_ContextsBase<ContextType, ContextInstanceType>(0));
+      c->take(cs);
+      return c;
+    }
+  }
+};
+
+typedef C_ContextsBase<Context, Context> C_Contexts;
+
+/*
+ * 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
+ */
+template <class ContextType, class ContextInstanceType>
+class C_GatherBase : public ContextType {
+private:
+  CephContext *cct;
+  int result;
+  ContextType *onfinish;
+#ifdef DEBUG_GATHER
+  std::set<ContextType*> waitfor;
+#endif
+  int sub_created_count;
+  int sub_existing_count;
+  mutable Mutex lock;
+  bool activated;
+
+  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_GatherBase " << this << ".sub_finish(r=" << r << ") " << sub
+#ifdef DEBUG_GATHER
+                   << " (remaining " << waitfor << ")"
+#endif
+                   << dendl;
+    if (r < 0 && result == 0)
+      result = r;
+    if ((activated == false) || (sub_existing_count != 0)) {
+      lock.Unlock();
+      return;
+    }
+    lock.Unlock();
+    delete_me();
+  }
+
+  void delete_me() {
+    if (onfinish) {
+      onfinish->complete(result);
+      onfinish = 0;
+    }
+    delete this;
+  }
+
+  class C_GatherSub : public ContextInstanceType {
+    C_GatherBase *gather;
+  public:
+    C_GatherSub(C_GatherBase *g) : gather(g) {}
+    void complete(int r) override {
+      // 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) override {
+      gather->sub_finish(this, r);
+      gather = 0;
+    }
+    ~C_GatherSub() override {
+      if (gather)
+       gather->sub_finish(this, 0);
+    }
+  };
+
+public:
+  C_GatherBase(CephContext *cct_, ContextType *onfinish_)
+    : cct(cct_), result(0), onfinish(onfinish_),
+      sub_created_count(0), sub_existing_count(0),
+      lock("C_GatherBase::lock", true, false), //disable lockdep
+      activated(false)
+  {
+    mydout(cct,10) << "C_GatherBase " << this << ".new" << dendl;
+  }
+  ~C_GatherBase() override {
+    mydout(cct,10) << "C_GatherBase " << this << ".delete" << dendl;
+  }
+  void set_finisher(ContextType *onfinish_) {
+    Mutex::Locker l(lock);
+    assert(!onfinish);
+    onfinish = onfinish_;
+  }
+  void activate() {
+    lock.Lock();
+    assert(activated == false);
+    activated = true;
+    if (sub_existing_count != 0) {
+      lock.Unlock();
+      return;
+    }
+    lock.Unlock();
+    delete_me();
+  }
+  ContextType *new_sub() {
+    Mutex::Locker l(lock);
+    assert(activated == false);
+    sub_created_count++;
+    sub_existing_count++;
+    ContextType *s = new C_GatherSub(this);
+#ifdef DEBUG_GATHER
+    waitfor.insert(s);
+#endif
+    mydout(cct,10) << "C_GatherBase " << this << ".new_sub is " << sub_created_count << " " << s << dendl;
+    return s;
+  }
+  void finish(int r) override {
+    ceph_abort();    // nobody should ever call me.
+  }
+
+  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;
+  }
+};
+
+/*
+ * The C_GatherBuilder remembers each C_Context created by
+ * C_GatherBuilder.new_sub() in a C_Gather.  When a C_Context created
+ * by new_sub() is complete(), C_Gather forgets about it.  When
+ * C_GatherBuilder notices that there are no C_Context left in
+ * C_Gather, it calls complete() on the C_Context provided as the
+ * second argument of the constructor (finisher).
+ *
+ * How to use C_GatherBuilder:
+ *
+ * 1. Create a C_GatherBuilder on the stack
+ * 2. Call gather_bld.new_sub() as many times as you want to create new subs
+ *    It is safe to call this 0 times, or 100, or anything in between.
+ * 3. If you didn't supply a finisher in the C_GatherBuilder constructor,
+ *    set one with gather_bld.set_finisher(my_finisher)
+ * 4. Call gather_bld.activate()
+ *
+ * Example:
+ *
+ * C_SaferCond all_done;
+ * C_GatherBuilder gb(g_ceph_context, all_done);
+ * j.submit_entry(1, first, 0, gb.new_sub()); // add a C_Context to C_Gather
+ * j.submit_entry(2, first, 0, gb.new_sub()); // add a C_Context to C_Gather
+ * gb.activate(); // consume C_Context as soon as they complete()
+ * all_done.wait(); // all_done is complete() after all new_sub() are complete()
+ *
+ * The finisher may be called at any point after step 4, including immediately
+ * from the activate() function.
+ * The finisher will never be called before activate().
+ *
+ * Note: Currently, subs must be manually freed by the caller (for some reason.)
+ */
+template <class ContextType, class GatherType>
+class C_GatherBuilderBase
+{
+public:
+  C_GatherBuilderBase(CephContext *cct_)
+    : cct(cct_), c_gather(NULL), finisher(NULL), activated(false)
+  {
+  }
+  C_GatherBuilderBase(CephContext *cct_, ContextType *finisher_)
+    : cct(cct_), c_gather(NULL), finisher(finisher_), activated(false)
+  {
+  }
+  ~C_GatherBuilderBase() {
+    if (c_gather) {
+      assert(activated); // Don't forget to activate your C_Gather!
+    }
+    else {
+      delete finisher;
+    }
+  }
+  ContextType *new_sub() {
+    if (!c_gather) {
+      c_gather = new GatherType(cct, finisher);
+    }
+    return c_gather->new_sub();
+  }
+  void activate() {
+    if (!c_gather)
+      return;
+    assert(finisher != NULL);
+    activated = true;
+    c_gather->activate();
+  }
+  void set_finisher(ContextType *finisher_) {
+    finisher = finisher_;
+    if (c_gather)
+      c_gather->set_finisher(finisher);
+  }
+  GatherType *get() const {
+    return c_gather;
+  }
+  bool has_subs() const {
+    return (c_gather != NULL);
+  }
+  int num_subs_created() {
+    assert(!activated);
+    if (c_gather == NULL)
+      return 0;
+    return c_gather->get_sub_created_count();
+  }
+  int num_subs_remaining() {
+    assert(!activated);
+    if (c_gather == NULL)
+      return 0;
+    return c_gather->get_sub_existing_count();
+  }
+
+private:
+  CephContext *cct;
+  GatherType *c_gather;
+  ContextType *finisher;
+  bool activated;
+};
+
+typedef C_GatherBase<Context, Context> C_Gather;
+typedef C_GatherBuilderBase<Context, C_Gather > C_GatherBuilder;
+
+class FunctionContext : public Context {
+public:
+  FunctionContext(boost::function<void(int)> &&callback)
+    : m_callback(std::move(callback))
+  {
+  }
+
+  void finish(int r) override {
+    m_callback(r);
+  }
+private:
+  boost::function<void(int)> m_callback;
+};
+
+#undef mydout
+
+#endif