initial code repo
[stor4nfv.git] / src / ceph / src / mds / MDSCacheObject.h
diff --git a/src/ceph/src/mds/MDSCacheObject.h b/src/ceph/src/mds/MDSCacheObject.h
new file mode 100644 (file)
index 0000000..9a90a1d
--- /dev/null
@@ -0,0 +1,413 @@
+#ifndef CEPH_MDSCACHEOBJECT_H
+#define CEPH_MDSCACHEOBJECT_H
+
+#include <ostream>
+
+#include "common/config.h"
+
+#include "include/Context.h"
+#include "include/alloc_ptr.h"
+#include "include/assert.h"
+#include "include/mempool.h"
+#include "include/types.h"
+#include "include/xlist.h"
+
+#include "mdstypes.h"
+
+#define MDS_REF_SET      // define me for improved debug output, sanity checking
+//#define MDS_AUTHPIN_SET  // define me for debugging auth pin leaks
+//#define MDS_VERIFY_FRAGSTAT    // do (slow) sanity checking on frags
+
+
+class MLock;
+class SimpleLock;
+class MDSCacheObject;
+class MDSInternalContextBase;
+
+/*
+ * for metadata leases to clients
+ */
+struct ClientLease {
+  client_t client;
+  MDSCacheObject *parent;
+
+  ceph_seq_t seq;
+  utime_t ttl;
+  xlist<ClientLease*>::item item_session_lease; // per-session list
+  xlist<ClientLease*>::item item_lease;         // global list
+
+  ClientLease(client_t c, MDSCacheObject *p) : 
+    client(c), parent(p), seq(0),
+    item_session_lease(this),
+    item_lease(this) { }
+};
+
+
+// print hack
+struct mdsco_db_line_prefix {
+  MDSCacheObject *object;
+  explicit mdsco_db_line_prefix(MDSCacheObject *o) : object(o) {}
+};
+std::ostream& operator<<(std::ostream& out, const mdsco_db_line_prefix& o);
+
+// printer
+std::ostream& operator<<(std::ostream& out, const MDSCacheObject &o);
+
+class MDSCacheObject {
+ public:
+  // -- pins --
+  const static int PIN_REPLICATED =  1000;
+  const static int PIN_DIRTY      =  1001;
+  const static int PIN_LOCK       = -1002;
+  const static int PIN_REQUEST    = -1003;
+  const static int PIN_WAITER     =  1004;
+  const static int PIN_DIRTYSCATTERED = -1005;
+  static const int PIN_AUTHPIN    =  1006;
+  static const int PIN_PTRWAITER  = -1007;
+  const static int PIN_TEMPEXPORTING = 1008;  // temp pin between encode_ and finish_export
+  static const int PIN_CLIENTLEASE = 1009;
+  static const int PIN_DISCOVERBASE = 1010;
+
+  const char *generic_pin_name(int p) const {
+    switch (p) {
+    case PIN_REPLICATED: return "replicated";
+    case PIN_DIRTY: return "dirty";
+    case PIN_LOCK: return "lock";
+    case PIN_REQUEST: return "request";
+    case PIN_WAITER: return "waiter";
+    case PIN_DIRTYSCATTERED: return "dirtyscattered";
+    case PIN_AUTHPIN: return "authpin";
+    case PIN_PTRWAITER: return "ptrwaiter";
+    case PIN_TEMPEXPORTING: return "tempexporting";
+    case PIN_CLIENTLEASE: return "clientlease";
+    case PIN_DISCOVERBASE: return "discoverbase";
+    default: ceph_abort(); return 0;
+    }
+  }
+
+  // -- state --
+  const static int STATE_AUTH      = (1<<30);
+  const static int STATE_DIRTY     = (1<<29);
+  const static int STATE_NOTIFYREF = (1<<28); // notify dropping ref drop through _put()
+  const static int STATE_REJOINING = (1<<27);  // replica has not joined w/ primary copy
+  const static int STATE_REJOINUNDEF = (1<<26);  // contents undefined.
+
+
+  // -- wait --
+  const static uint64_t WAIT_ORDERED    = (1ull<<61);
+  const static uint64_t WAIT_SINGLEAUTH  = (1ull<<60);
+  const static uint64_t WAIT_UNFREEZE    = (1ull<<59); // pka AUTHPINNABLE
+
+
+  // ============================================
+  // cons
+ public:
+  MDSCacheObject() :
+    state(0), 
+    ref(0),
+    auth_pins(0), nested_auth_pins(0),
+    replica_nonce(0)
+  {}
+  virtual ~MDSCacheObject() {}
+
+  // printing
+  virtual void print(std::ostream& out) = 0;
+  virtual std::ostream& print_db_line_prefix(std::ostream& out) { 
+    return out << "mdscacheobject(" << this << ") "; 
+  }
+  
+  // --------------------------------------------
+  // state
+ protected:
+  __u32 state;     // state bits
+
+ public:
+  unsigned get_state() const { return state; }
+  unsigned state_test(unsigned mask) const { return (state & mask); }
+  void state_clear(unsigned mask) { state &= ~mask; }
+  void state_set(unsigned mask) { state |= mask; }
+  void state_reset(unsigned s) { state = s; }
+
+  bool is_auth() const { return state_test(STATE_AUTH); }
+  bool is_dirty() const { return state_test(STATE_DIRTY); }
+  bool is_clean() const { return !is_dirty(); }
+  bool is_rejoining() const { return state_test(STATE_REJOINING); }
+
+  // --------------------------------------------
+  // authority
+  virtual mds_authority_t authority() const = 0;
+  bool is_ambiguous_auth() const {
+    return authority().second != CDIR_AUTH_UNKNOWN;
+  }
+
+  // --------------------------------------------
+  // pins
+protected:
+  __s32      ref;       // reference count
+#ifdef MDS_REF_SET
+  mempool::mds_co::map<int,int> ref_map;
+#endif
+
+ public:
+  int get_num_ref(int by = -1) const {
+#ifdef MDS_REF_SET
+    if (by >= 0) {
+      if (ref_map.find(by) == ref_map.end()) {
+       return 0;
+      } else {
+        return ref_map.find(by)->second;
+      }
+    }
+#endif
+    return ref;
+  }
+  virtual const char *pin_name(int by) const = 0;
+  //bool is_pinned_by(int by) { return ref_set.count(by); }
+  //multiset<int>& get_ref_set() { return ref_set; }
+
+  virtual void last_put() {}
+  virtual void bad_put(int by) {
+#ifdef MDS_REF_SET
+    assert(ref_map[by] > 0);
+#endif
+    assert(ref > 0);
+  }
+  virtual void _put() {}
+  void put(int by) {
+#ifdef MDS_REF_SET
+    if (ref == 0 || ref_map[by] == 0) {
+#else
+    if (ref == 0) {
+#endif
+      bad_put(by);
+    } else {
+      ref--;
+#ifdef MDS_REF_SET
+      ref_map[by]--;
+#endif
+      if (ref == 0)
+       last_put();
+      if (state_test(STATE_NOTIFYREF))
+       _put();
+    }
+  }
+
+  virtual void first_get() {}
+  virtual void bad_get(int by) {
+#ifdef MDS_REF_SET
+    assert(by < 0 || ref_map[by] == 0);
+#endif
+    ceph_abort();
+  }
+  void get(int by) {
+    if (ref == 0)
+      first_get();
+    ref++;
+#ifdef MDS_REF_SET
+    if (ref_map.find(by) == ref_map.end())
+      ref_map[by] = 0;
+    ref_map[by]++;
+#endif
+  }
+
+  void print_pin_set(std::ostream& out) const {
+#ifdef MDS_REF_SET
+    std::map<int, int>::const_iterator it = ref_map.begin();
+    while (it != ref_map.end()) {
+      out << " " << pin_name(it->first) << "=" << it->second;
+      ++it;
+    }
+#else
+    out << " nref=" << ref;
+#endif
+  }
+
+  protected:
+  int auth_pins;
+  int nested_auth_pins;
+#ifdef MDS_AUTHPIN_SET
+  mempool::mds_co::multiset<void*> auth_pin_set;
+#endif
+
+  public:
+  bool is_auth_pinned() const { return auth_pins || nested_auth_pins; }
+  int get_num_auth_pins() const { return auth_pins; }
+  int get_num_nested_auth_pins() const { return nested_auth_pins; }
+
+  void dump_states(Formatter *f) const;
+  void dump(Formatter *f) const;
+
+  // --------------------------------------------
+  // auth pins
+  virtual bool can_auth_pin() const = 0;
+  virtual void auth_pin(void *who) = 0;
+  virtual void auth_unpin(void *who) = 0;
+  virtual bool is_frozen() const = 0;
+  virtual bool is_freezing() const = 0;
+  virtual bool is_freezing_or_frozen() const {
+    return is_frozen() || is_freezing();
+  }
+
+
+  // --------------------------------------------
+  // replication (across mds cluster)
+ protected:
+  unsigned             replica_nonce; // [replica] defined on replica
+  typedef compact_map<mds_rank_t,unsigned> replica_map_type;
+  replica_map_type replica_map;   // [auth] mds -> nonce
+
+ public:
+  bool is_replicated() const { return !get_replicas().empty(); }
+  bool is_replica(mds_rank_t mds) const { return get_replicas().count(mds); }
+  int num_replicas() const { return get_replicas().size(); }
+  unsigned add_replica(mds_rank_t mds) {
+    if (get_replicas().count(mds))
+      return ++get_replicas()[mds];  // inc nonce
+    if (get_replicas().empty())
+      get(PIN_REPLICATED);
+    return get_replicas()[mds] = 1;
+  }
+  void add_replica(mds_rank_t mds, unsigned nonce) {
+    if (get_replicas().empty())
+      get(PIN_REPLICATED);
+    get_replicas()[mds] = nonce;
+  }
+  unsigned get_replica_nonce(mds_rank_t mds) {
+    assert(get_replicas().count(mds));
+    return get_replicas()[mds];
+  }
+  void remove_replica(mds_rank_t mds) {
+    assert(get_replicas().count(mds));
+    get_replicas().erase(mds);
+    if (get_replicas().empty()) {
+      put(PIN_REPLICATED);
+    }
+  }
+  void clear_replica_map() {
+    if (!get_replicas().empty())
+      put(PIN_REPLICATED);
+    replica_map.clear();
+  }
+  replica_map_type& get_replicas() { return replica_map; }
+  const replica_map_type& get_replicas() const { return replica_map; }
+  void list_replicas(std::set<mds_rank_t>& ls) const {
+    for (const auto &p : get_replicas()) {
+      ls.insert(p.first);
+    }
+  }
+
+  unsigned get_replica_nonce() const { return replica_nonce; }
+  void set_replica_nonce(unsigned n) { replica_nonce = n; }
+
+
+  // ---------------------------------------------
+  // waiting
+ private:
+  alloc_ptr<mempool::mds_co::multimap<uint64_t, std::pair<uint64_t, MDSInternalContextBase*>>> waiting;
+  static uint64_t last_wait_seq;
+
+ public:
+  bool is_waiter_for(uint64_t mask, uint64_t min=0) {
+    if (!min) {
+      min = mask;
+      while (min & (min-1))  // if more than one bit is set
+        min &= min-1;        //  clear LSB
+    }
+    if (waiting) {
+      for (auto p = waiting->lower_bound(min); p != waiting->end(); ++p) {
+        if (p->first & mask) return true;
+        if (p->first > mask) return false;
+      }
+    }
+    return false;
+  }
+  virtual void add_waiter(uint64_t mask, MDSInternalContextBase *c) {
+    if (waiting->empty())
+      get(PIN_WAITER);
+
+    uint64_t seq = 0;
+    if (mask & WAIT_ORDERED) {
+      seq = ++last_wait_seq;
+      mask &= ~WAIT_ORDERED;
+    }
+    waiting->insert(pair<uint64_t, pair<uint64_t, MDSInternalContextBase*> >(
+                           mask,
+                           pair<uint64_t, MDSInternalContextBase*>(seq, c)));
+//    pdout(10,g_conf->debug_mds) << (mdsco_db_line_prefix(this)) 
+//                            << "add_waiter " << hex << mask << dec << " " << c
+//                            << " on " << *this
+//                            << dendl;
+    
+  }
+  virtual void take_waiting(uint64_t mask, std::list<MDSInternalContextBase*>& ls) {
+    if (!waiting || waiting->empty()) return;
+
+    // process ordered waiters in the same order that they were added.
+    std::map<uint64_t, MDSInternalContextBase*> ordered_waiters;
+
+    for (auto it = waiting->begin(); it != waiting->end(); ) {
+      if (it->first & mask) {
+           if (it->second.first > 0) {
+             ordered_waiters.insert(it->second);
+           } else {
+             ls.push_back(it->second.second);
+        }
+//     pdout(10,g_conf->debug_mds) << (mdsco_db_line_prefix(this))
+//                                << "take_waiting mask " << hex << mask << dec << " took " << it->second
+//                                << " tag " << hex << it->first << dec
+//                                << " on " << *this
+//                                << dendl;
+        waiting->erase(it++);
+      } else {
+//     pdout(10,g_conf->debug_mds) << "take_waiting mask " << hex << mask << dec << " SKIPPING " << it->second
+//                                << " tag " << hex << it->first << dec
+//                                << " on " << *this 
+//                                << dendl;
+             ++it;
+      }
+    }
+    for (auto it = ordered_waiters.begin(); it != ordered_waiters.end(); ++it) {
+      ls.push_back(it->second);
+    }
+    if (waiting->empty()) {
+      put(PIN_WAITER);
+      waiting.release();
+    }
+  }
+  void finish_waiting(uint64_t mask, int result = 0);
+
+  // ---------------------------------------------
+  // locking
+  // noop unless overloaded.
+  virtual SimpleLock* get_lock(int type) { ceph_abort(); return 0; }
+  virtual void set_object_info(MDSCacheObjectInfo &info) { ceph_abort(); }
+  virtual void encode_lock_state(int type, bufferlist& bl) { ceph_abort(); }
+  virtual void decode_lock_state(int type, bufferlist& bl) { ceph_abort(); }
+  virtual void finish_lock_waiters(int type, uint64_t mask, int r=0) { ceph_abort(); }
+  virtual void add_lock_waiter(int type, uint64_t mask, MDSInternalContextBase *c) { ceph_abort(); }
+  virtual bool is_lock_waiting(int type, uint64_t mask) { ceph_abort(); return false; }
+
+  virtual void clear_dirty_scattered(int type) { ceph_abort(); }
+
+  // ---------------------------------------------
+  // ordering
+  virtual bool is_lt(const MDSCacheObject *r) const = 0;
+  struct ptr_lt {
+    bool operator()(const MDSCacheObject* l, const MDSCacheObject* r) const {
+      return l->is_lt(r);
+    }
+  };
+
+};
+
+inline std::ostream& operator<<(std::ostream& out, MDSCacheObject &o) {
+  o.print(out);
+  return out;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const mdsco_db_line_prefix& o) {
+  o.object->print_db_line_prefix(out);
+  return out;
+}
+
+#endif