1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2009 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #ifndef CEPH_COMPATSET_H
16 #define CEPH_COMPATSET_H
17 #include "include/buffer.h"
18 #include "common/Formatter.h"
26 Feature(uint64_t _id, const string& _name) : id(_id), name(_name) {}
31 map <uint64_t,string> names;
34 friend struct CompatSet;
35 friend class CephCompatSet_AllSet_Test;
36 friend class CephCompatSet_other_Test;
37 friend class CephCompatSet_merge_Test;
38 friend ostream& operator<<(ostream& out, const CompatSet::FeatureSet& fs);
39 friend ostream& operator<<(ostream& out, const CompatSet& compat);
40 FeatureSet() : mask(1), names() {}
41 void insert(const Feature& f) {
44 mask |= ((uint64_t)1<<f.id);
48 bool contains(const Feature& f) const {
49 return names.count(f.id);
51 bool contains(uint64_t f) const {
52 return names.count(f);
55 * Getter instead of using name[] to be const safe
57 std::string get_name(uint64_t const f) const {
58 std::map<uint64_t, std::string>::const_iterator i = names.find(f);
59 assert(i != names.end());
63 void remove(uint64_t f) {
66 mask &= ~((uint64_t)1<<f);
69 void remove(const Feature& f) {
73 void encode(bufferlist& bl) const {
74 /* See below, mask always has the lowest bit set in memory, but
75 * unset in the encoding */
76 ::encode(mask & (~(uint64_t)1), bl);
80 void decode(bufferlist::iterator& bl) {
84 * Previously, there was a bug where insert did
85 * mask |= f.id rather than mask |= (1 << f.id).
86 * In FeatureSets from those version, mask always
87 * has the lowest bit set. Since then, masks always
88 * have the lowest bit unset.
90 * When we encounter such a FeatureSet, we have to
91 * reconstruct the mask from the names map.
95 map<uint64_t, string> temp_names;
96 temp_names.swap(names);
97 for (map<uint64_t, string>::iterator i = temp_names.begin();
98 i != temp_names.end();
100 insert(Feature(i->first, i->second));
107 void dump(Formatter *f) const {
108 for (map<uint64_t,string>::const_iterator p = names.begin();
112 snprintf(s, sizeof(s), "feature_%lld", (unsigned long long)p->first);
113 f->dump_string(s, p->second);
118 // These features have no impact on the read / write status
120 // If any of these features are missing, read is possible ( as long
121 // as no incompat feature is missing ) but it is not possible to write
122 FeatureSet ro_compat;
123 // If any of these features are missing, read or write is not possible
126 CompatSet(FeatureSet& _compat, FeatureSet& _ro_compat, FeatureSet& _incompat) :
127 compat(_compat), ro_compat(_ro_compat), incompat(_incompat) {}
129 CompatSet() : compat(), ro_compat(), incompat() { }
132 /* does this filesystem implementation have the
133 features required to read the other? */
134 bool readable(CompatSet const& other) const {
135 return !((other.incompat.mask ^ incompat.mask) & other.incompat.mask);
138 /* does this filesystem implementation have the
139 features required to write the other? */
140 bool writeable(CompatSet const& other) const {
141 return readable(other) &&
142 !((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask);
145 /* Compare this CompatSet to another.
146 * CAREFULLY NOTE: This operation is NOT commutative.
147 * a > b DOES NOT imply that b < a.
149 * 0: The CompatSets have the same feature set.
150 * 1: This CompatSet's features are a strict superset of the other's.
151 * -1: This CompatSet is missing at least one feature
152 * described in the other. It may still have more features, though.
154 int compare(const CompatSet& other) {
155 if ((other.compat.mask == compat.mask) &&
156 (other.ro_compat.mask == ro_compat.mask) &&
157 (other.incompat.mask == incompat.mask)) return 0;
158 //okay, they're not the same
160 //if we're writeable we have a superset of theirs on incompat and ro_compat
161 if (writeable(other) && !((other.compat.mask ^ compat.mask)
162 & other.compat.mask)) return 1;
163 //if we make it here, we weren't writeable or had a difference compat set
167 /* Get the features supported by other CompatSet but not this one,
170 CompatSet unsupported(CompatSet& other) {
172 uint64_t other_compat =
173 ((other.compat.mask ^ compat.mask) & other.compat.mask);
174 uint64_t other_ro_compat =
175 ((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask);
176 uint64_t other_incompat =
177 ((other.incompat.mask ^ incompat.mask) & other.incompat.mask);
178 for (int id = 1; id < 64; ++id) {
179 uint64_t mask = (uint64_t)1 << id;
180 if (mask & other_compat) {
181 diff.compat.insert( Feature(id, other.compat.names[id]));
183 if (mask & other_ro_compat) {
184 diff.ro_compat.insert(Feature(id, other.ro_compat.names[id]));
186 if (mask & other_incompat) {
187 diff.incompat.insert( Feature(id, other.incompat.names[id]));
193 /* Merge features supported by other CompatSet into this one.
194 * Return: true if some features were merged
196 bool merge(CompatSet const & other) {
197 uint64_t other_compat =
198 ((other.compat.mask ^ compat.mask) & other.compat.mask);
199 uint64_t other_ro_compat =
200 ((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask);
201 uint64_t other_incompat =
202 ((other.incompat.mask ^ incompat.mask) & other.incompat.mask);
203 if (!other_compat && !other_ro_compat && !other_incompat)
205 for (int id = 1; id < 64; ++id) {
206 uint64_t mask = (uint64_t)1 << id;
207 if (mask & other_compat) {
208 compat.insert( Feature(id, other.compat.get_name(id)));
210 if (mask & other_ro_compat) {
211 ro_compat.insert(Feature(id, other.ro_compat.get_name(id)));
213 if (mask & other_incompat) {
214 incompat.insert( Feature(id, other.incompat.get_name(id)));
220 void encode(bufferlist& bl) const {
222 ro_compat.encode(bl);
226 void decode(bufferlist::iterator& bl) {
228 ro_compat.decode(bl);
232 void dump(Formatter *f) const {
233 f->open_object_section("compat");
236 f->open_object_section("ro_compat");
239 f->open_object_section("incompat");
244 static void generate_test_instances(list<CompatSet*>& o) {
245 o.push_back(new CompatSet);
246 o.push_back(new CompatSet);
247 o.back()->compat.insert(Feature(1, "one"));
248 o.back()->compat.insert(Feature(2, "two"));
249 o.back()->ro_compat.insert(Feature(4, "four"));
250 o.back()->incompat.insert(Feature(3, "three"));
253 WRITE_CLASS_ENCODER(CompatSet)
255 inline ostream& operator<<(ostream& out, const CompatSet::FeatureSet& fs)
257 return out << fs.names;
260 inline ostream& operator<<(ostream& out, const CompatSet& compat)
262 return out << "compat=" << compat.compat
263 << ",rocompat=" << compat.ro_compat
264 << ",incompat=" << compat.incompat;