initial code repo
[stor4nfv.git] / src / ceph / src / mds / ScatterLock.h
diff --git a/src/ceph/src/mds/ScatterLock.h b/src/ceph/src/mds/ScatterLock.h
new file mode 100644 (file)
index 0000000..618ced9
--- /dev/null
@@ -0,0 +1,281 @@
+// -*- 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_SCATTERLOCK_H
+#define CEPH_SCATTERLOCK_H
+
+#include "SimpleLock.h"
+
+class ScatterLock : public SimpleLock {
+
+  struct more_bits_t {
+    int state_flags;
+    utime_t last_scatter;
+    xlist<ScatterLock*>::item item_updated;
+    utime_t update_stamp;
+
+    explicit more_bits_t(ScatterLock *lock) :
+      state_flags(0),
+      item_updated(lock)
+    {}
+
+    bool empty() const {
+      return
+       !state_flags &&
+       !item_updated.is_on_list();
+    }
+  };
+  more_bits_t *_more;
+
+  bool have_more() const { return _more ? true : false; }
+  void try_clear_more() {
+    if (_more && _more->empty()) {
+      delete _more;
+      _more = NULL;
+    }
+  }
+  more_bits_t *more() {
+    if (!_more)
+      _more = new more_bits_t(this);
+    return _more;
+  }
+
+  enum flag_values {  // flag values for more_bits_t state
+    SCATTER_WANTED   = 1 << 0,
+    UNSCATTER_WANTED = 1 << 1,
+    DIRTY            = 1 << 2,
+    FLUSHING         = 1 << 3,
+    FLUSHED          = 1 << 4,
+    REJOIN_MIX      = 1 << 5, // no rdlock until the recovering mds become active
+  };
+
+public:
+  ScatterLock(MDSCacheObject *o, LockType *lt) : 
+    SimpleLock(o, lt), _more(NULL)
+  {}
+  ~ScatterLock() override {
+    if (_more) {
+      _more->item_updated.remove_myself();   // FIXME this should happen sooner, i think...
+      delete _more;
+    }
+  }
+
+  bool is_scatterlock() const override {
+    return true;
+  }
+
+  bool is_sync_and_unlocked() const {
+    return
+      SimpleLock::is_sync_and_unlocked() && 
+      !is_dirty() &&
+      !is_flushing();
+  }
+
+  bool can_scatter_pin(client_t loner) {
+    /*
+      LOCK : NOT okay because it can MIX and force replicas to journal something
+      TSYN : also not okay for same reason
+      EXCL : also not okay
+
+      MIX  : okay, replica can stall before sending AC_SYNCACK
+      SYNC : okay, replica can stall before sending AC_MIXACK or AC_LOCKACK
+    */   
+    return
+      get_state() == LOCK_SYNC ||
+      get_state() == LOCK_MIX;
+  }
+
+  void set_xlock_snap_sync(MDSInternalContextBase *c)
+  {
+    assert(get_type() == CEPH_LOCK_IFILE);
+    assert(state == LOCK_XLOCK || state == LOCK_XLOCKDONE);
+    state = LOCK_XLOCKSNAP;
+    add_waiter(WAIT_STABLE, c);
+  }
+
+  xlist<ScatterLock*>::item *get_updated_item() { return &more()->item_updated; }
+
+  utime_t get_update_stamp() {
+    return more()->update_stamp;
+  }
+
+  void set_update_stamp(utime_t t) { more()->update_stamp = t; }
+
+  void set_scatter_wanted() {
+    more()->state_flags |= SCATTER_WANTED;
+  }
+  void set_unscatter_wanted() {
+    more()->state_flags |= UNSCATTER_WANTED;
+  }
+  void clear_scatter_wanted() {
+    if (have_more())
+      _more->state_flags &= ~SCATTER_WANTED;
+    try_clear_more();
+  }
+  void clear_unscatter_wanted() {
+    if (have_more())
+      _more->state_flags &= ~UNSCATTER_WANTED;
+    try_clear_more();
+  }
+  bool get_scatter_wanted() const {
+    return have_more() ? _more->state_flags & SCATTER_WANTED : false;
+  }
+  bool get_unscatter_wanted() const {
+    return have_more() ? _more->state_flags & UNSCATTER_WANTED : false;
+  }
+
+  bool is_dirty() const override {
+    return have_more() ? _more->state_flags & DIRTY : false;
+  }
+  bool is_flushing() const override {
+    return have_more() ? _more->state_flags & FLUSHING: false;
+  }
+  bool is_flushed() const override {
+    return have_more() ? _more->state_flags & FLUSHED: false;
+  }
+  bool is_dirty_or_flushing() const {
+    return have_more() ? (is_dirty() || is_flushing()) : false;
+  }
+  bool is_rejoin_mix() const {
+    return have_more() ? _more->state_flags & REJOIN_MIX : false;
+  }
+
+  void mark_dirty() { 
+    if (!is_dirty()) {
+      if (!is_flushing())
+       parent->get(MDSCacheObject::PIN_DIRTYSCATTERED);
+      set_dirty();
+    }
+  }
+  void start_flush() {
+    if (is_dirty()) {
+      set_flushing();
+      clear_dirty();
+    }
+  }
+  void finish_flush() {
+    if (is_flushing()) {
+      clear_flushing();
+      set_flushed();
+      if (!is_dirty()) {
+       parent->put(MDSCacheObject::PIN_DIRTYSCATTERED);
+       parent->clear_dirty_scattered(get_type());
+      }
+    }
+  }
+  void remove_dirty() {
+    start_flush();
+    finish_flush();
+  }
+  void clear_flushed() override {
+    if (have_more()) {
+      _more->state_flags &= ~FLUSHED;
+      try_clear_more();
+    }
+  }
+
+  void clear_rejoin_mix() {
+    if (have_more()) {
+      _more->state_flags &= ~REJOIN_MIX;
+      try_clear_more();
+    }
+  }
+
+  void set_last_scatter(utime_t t) { more()->last_scatter = t; }
+  utime_t get_last_scatter() {
+    return more()->last_scatter;
+  }
+
+  void infer_state_from_strong_rejoin(int rstate, bool locktoo) {
+    if (rstate == LOCK_MIX || 
+       rstate == LOCK_MIX_LOCK || // replica still has wrlocks?
+       rstate == LOCK_MIX_SYNC)
+      state = LOCK_MIX;
+    else if (locktoo && rstate == LOCK_LOCK)
+      state = LOCK_LOCK;
+  }
+
+  void encode_state_for_rejoin(bufferlist& bl, int rep) {
+    __s16 s = get_replica_state();
+    if (is_gathering(rep)) {
+      // the recovering mds may hold rejoined wrlocks
+      if (state == LOCK_MIX_SYNC)
+       s = LOCK_MIX_SYNC;
+      else
+       s = LOCK_MIX_LOCK;
+    }
+
+    if (s == LOCK_MIX || s == LOCK_MIX_LOCK || s == LOCK_MIX_SYNC)
+      more()->state_flags |= REJOIN_MIX;
+
+    ::encode(s, bl);
+  }
+
+  void decode_state_rejoin(bufferlist::iterator& p, list<MDSInternalContextBase*>& waiters) {
+    SimpleLock::decode_state_rejoin(p, waiters);
+    if (is_flushing()) {
+      set_dirty();
+      clear_flushing();
+    }
+  }
+
+  bool remove_replica(int from, bool rejoin) {
+    if (rejoin &&
+       (state == LOCK_MIX ||
+        state == LOCK_MIX_SYNC ||
+        state == LOCK_MIX_LOCK2 ||
+        state == LOCK_MIX_TSYN ||
+        state == LOCK_MIX_EXCL))
+      return false;
+    return SimpleLock::remove_replica(from);
+  }
+
+  void print(ostream& out) const override {
+    out << "(";
+    _print(out);
+    if (is_dirty())
+      out << " dirty";
+    if (is_flushing())
+      out << " flushing";
+    if (is_flushed())
+      out << " flushed";
+    if (get_scatter_wanted())
+      out << " scatter_wanted";
+    out << ")";
+  }
+
+private:
+  void set_flushing() {
+    more()->state_flags |= FLUSHING;
+  }
+  void clear_flushing() {
+    if (have_more()) {
+      _more->state_flags &= ~FLUSHING;
+    }
+  }
+  void set_flushed() {
+    more()->state_flags |= FLUSHED;
+  }
+  void set_dirty() {
+    more()->state_flags |= DIRTY;
+  }
+  void clear_dirty() {
+    if (have_more()) {
+      _more->state_flags &= ~DIRTY;
+    }
+  }
+};
+
+#endif