]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
include: new CompatSet.h
authorGreg Farnum <gregf@hq.newdream.net>
Tue, 12 Jan 2010 00:53:11 +0000 (16:53 -0800)
committerGreg Farnum <gregf@hq.newdream.net>
Tue, 19 Jan 2010 22:02:45 +0000 (14:02 -0800)
src/include/CompatSet.h [new file with mode: 0644]

diff --git a/src/include/CompatSet.h b/src/include/CompatSet.h
new file mode 100644 (file)
index 0000000..d728845
--- /dev/null
@@ -0,0 +1,193 @@
+// -*- 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) 2009 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_COMPATSET_H
+#define __CEPH_COMPATSET_H
+#include "include/buffer.h"
+#include <vector>
+
+struct CompatSet {
+  set<string> compat, ro_compat, incompat;
+  vector<set<string> *> all_features;
+  
+  CompatSet(const char **compat_a, int c_size,
+           const char **ro_compat_a, int ro_size,
+           const char **incompat_a, int inc_size) :
+    compat(), ro_compat(), incompat(){
+    for (int i = 0; i < c_size; ++i)
+      compat.insert(string(compat_a[i]));
+    for (int j = 0; j < ro_size; ++j)
+      ro_compat.insert(string(ro_compat_a[j]));
+    for (int k = 0; k < inc_size; ++k)
+      incompat.insert(string(incompat_a[k]));
+    all_features.push_back(&compat);
+    all_features.push_back(&ro_compat);
+    all_features.push_back(&incompat);
+  }
+  
+  CompatSet() : compat(), ro_compat(), incompat() {
+    all_features.push_back(&compat);
+    all_features.push_back(&ro_compat);
+    all_features.push_back(&incompat);
+  }
+  
+  /* does this filesystem implementation have the
+     features required to read the other? */
+  bool readable(CompatSet other) {
+    //make sure other's incompat string is a subset of ours
+    for ( set<string>::iterator i = other.incompat.begin();
+         i != other.incompat.end();
+         ++i) {
+      if (!incompat.count(*i)) return false; //we don't have that flag!
+    }
+    return true;
+  }
+  
+  /* does this filesystem implementation have the
+     features required to write the other? */
+  bool writeable(CompatSet other) {
+    if (!readable(other)) return false;
+    for (set<string>::iterator i = other.ro_compat.begin();
+        i != other.ro_compat.end();
+        ++i) {
+      if (!ro_compat.count(*i))        return false;
+    }
+    return true;
+  }
+  
+  /* Compare this CompatSet to another.
+   * CAREFULLY NOTE: This operation is NOT commutative.
+   * a > b DOES NOT imply that b < a.
+   * If returns:
+   * 0: The CompatSets have the same feature set.
+   * 1: This CompatSet's features are a strict superset of the other's.
+   * -1: This CompatSet is missing at least one feature
+   *     described in the other. It may still have more features, though.
+   */
+  int compare(CompatSet other) {
+    //check sizes, that's fast and easy
+    if (other.compat.size() > compat.size() ||
+       other.ro_compat.size() > ro_compat.size() ||
+       other.incompat.size() > incompat.size() ) {
+      return -1;
+    }
+    //well, we have at least as many features, let's compare them all
+    if (!writeable(other)) return -1; //compares ro_compat and incompat
+    for (set<string>::iterator i = other.compat.begin();
+        i != other.compat.end();
+        ++i) {
+      if (!compat.count(*i)) return -1;
+    }
+    //if we make it this far we have all the features other does
+    //do we have more?
+    if (other.compat.size() < compat.size() ||
+       other.ro_compat.size() < ro_compat.size() ||
+       other.incompat.size() < incompat.size() ) {
+      return 1;
+    }
+    //apparently we have the exact same feature set
+    return 0;
+  }
+  
+  /* Get the features supported by other CompatSet but not this one,
+   * as a CompatSet.
+   */
+  CompatSet unsupported(CompatSet other) {
+    CompatSet difference;
+    for (set<string>::iterator i = other.compat.begin();
+        i != other.compat.end();
+        ++i) {
+      if (!compat.count(*i)) difference.compat.insert(*i);
+    }
+    for (set<string>::iterator j = other.ro_compat.begin();
+        j != other.ro_compat.end();
+        ++j) {
+      if (!ro_compat.count(*j))        difference.ro_compat.insert(*j);
+    }
+    for (set<string>::iterator k = other.incompat.begin();
+        k != other.incompat.end();
+        ++k) {
+      if (!incompat.count(*k)) difference.incompat.insert(*k);
+    }
+    return difference;
+  }
+  
+  class iterator {
+  private:
+    friend class CompatSet;
+    CompatSet *cset;
+    vector<set<string> *>::iterator feature_it;
+    set<string>::iterator it;
+  public:
+    iterator(CompatSet *comset) : cset(comset){
+      feature_it = cset->all_features.begin();
+      it = (*feature_it)->begin();
+    }
+    
+    string operator*() {
+      //check that we actually have contents, here
+      if ( cset->all_features.end() != feature_it) { //if not at end
+       return (*it);
+      }
+      return string();
+    }
+    
+    iterator& operator++() {
+      if (feature_it == cset->all_features.end()) return *this;//at end
+      if (it != (*feature_it)->end()) { //if not at end of cur stringset
+       if (++it != (*feature_it)->end()) return *this; //move along current set
+      }
+      if (++feature_it != cset->all_features.end()) { //move to next set
+       it = (*feature_it)->begin(); //start it over in new set
+       if ((*feature_it)->end() == it) return operator++(); //damn, keep moving
+       return *this; //yay, done
+      }
+      return *this; //at full end now, returning end iterator
+    }
+    
+    bool operator==(const iterator& other) const {
+      return (other.cset == cset
+             && other.feature_it == feature_it
+             && other.it == it);
+    }
+    
+    bool operator!=(const iterator& other) const { return !operator==(other);}
+  };
+  
+  iterator begin() {
+    iterator it(this);
+    if ((*it.feature_it)->end() == it.it) ++it;
+    return it;
+  }
+  
+  iterator end() {
+    iterator it(this);
+    it.feature_it = all_features.end();
+    it.it = all_features[2]->end();
+    return it;
+  }
+  
+  void encode(bufferlist& bl) const {
+    ::encode(compat, bl);
+    ::encode(ro_compat, bl);
+    ::encode(incompat, bl);
+  }
+  
+  void decode(bufferlist::iterator& bl) {
+    ::decode(compat, bl);
+    ::decode(ro_compat, bl);
+    ::decode(incompat, bl);
+  }
+};
+#endif