From 77e196ccc1afd1317e53b1422ce000d53ee2fd24 Mon Sep 17 00:00:00 2001 From: Greg Farnum Date: Mon, 11 Jan 2010 16:53:11 -0800 Subject: [PATCH] include: new CompatSet.h --- src/include/CompatSet.h | 193 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 src/include/CompatSet.h diff --git a/src/include/CompatSet.h b/src/include/CompatSet.h new file mode 100644 index 0000000000000..d728845ba35d6 --- /dev/null +++ b/src/include/CompatSet.h @@ -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 + * + * 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 + +struct CompatSet { + set compat, ro_compat, incompat; + vector *> 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::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::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::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::iterator i = other.compat.begin(); + i != other.compat.end(); + ++i) { + if (!compat.count(*i)) difference.compat.insert(*i); + } + for (set::iterator j = other.ro_compat.begin(); + j != other.ro_compat.end(); + ++j) { + if (!ro_compat.count(*j)) difference.ro_compat.insert(*j); + } + for (set::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 *>::iterator feature_it; + set::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 -- 2.39.5