Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / include / CompatSet.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2009 Sage Weil <sage@newdream.net>
7  *
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.
12  * 
13  */
14
15 #ifndef CEPH_COMPATSET_H
16 #define CEPH_COMPATSET_H
17 #include "include/buffer.h"
18 #include "common/Formatter.h"
19
20 struct CompatSet {
21
22   struct Feature {
23     uint64_t id;
24     string name;
25
26     Feature(uint64_t _id, const string& _name) : id(_id), name(_name) {}
27   };
28
29   class FeatureSet {
30     uint64_t mask;
31     map <uint64_t,string> names;
32
33   public:
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) {
42       assert(f.id > 0);
43       assert(f.id < 64);
44       mask |= ((uint64_t)1<<f.id);
45       names[f.id] = f.name;
46     }
47
48     bool contains(const Feature& f) const {
49       return names.count(f.id);
50     }
51     bool contains(uint64_t f) const {
52       return names.count(f);
53     }
54     /**
55      * Getter instead of using name[] to be const safe
56      */
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());
60       return i->second;
61     }
62
63     void remove(uint64_t f) {
64       if (names.count(f)) {
65         names.erase(f);
66         mask &= ~((uint64_t)1<<f);
67       }
68     }
69     void remove(const Feature& f) {
70       remove(f.id);
71     }
72
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);
77       ::encode(names, bl);
78     }
79
80     void decode(bufferlist::iterator& bl) {
81       ::decode(mask, bl);
82       ::decode(names, bl);
83       /**
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.
89        *
90        * When we encounter such a FeatureSet, we have to
91        * reconstruct the mask from the names map.
92        */
93       if (mask & 1) {
94         mask = 1;
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();
99              ++i) {
100           insert(Feature(i->first, i->second));
101         }
102       } else {
103         mask |= 1;
104       }
105     }
106
107     void dump(Formatter *f) const {
108       for (map<uint64_t,string>::const_iterator p = names.begin();
109            p != names.end();
110            ++p) {
111         char s[18];
112         snprintf(s, sizeof(s), "feature_%lld", (unsigned long long)p->first);
113         f->dump_string(s, p->second);
114       }
115     }
116   };
117
118   // These features have no impact on the read / write status
119   FeatureSet compat;
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
124   FeatureSet incompat;
125
126   CompatSet(FeatureSet& _compat, FeatureSet& _ro_compat, FeatureSet& _incompat) :
127     compat(_compat), ro_compat(_ro_compat), incompat(_incompat) {}
128
129   CompatSet() : compat(), ro_compat(), incompat() { }
130
131
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);
136   }
137
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);
143   }
144
145   /* Compare this CompatSet to another.
146    * CAREFULLY NOTE: This operation is NOT commutative.
147    * a > b DOES NOT imply that b < a.
148    * If returns:
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.
153    */
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
159
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
164     return -1;
165   }
166
167   /* Get the features supported by other CompatSet but not this one,
168    * as a CompatSet.
169    */
170   CompatSet unsupported(CompatSet& other) {
171     CompatSet diff;
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]));
182       }
183       if (mask & other_ro_compat) {
184         diff.ro_compat.insert(Feature(id, other.ro_compat.names[id]));
185       }
186       if (mask & other_incompat) {
187         diff.incompat.insert( Feature(id, other.incompat.names[id]));
188       }
189     }
190     return diff;
191   }
192   
193   /* Merge features supported by other CompatSet into this one.
194    * Return: true if some features were merged
195    */
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)
204       return false;
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)));
209       }
210       if (mask & other_ro_compat) {
211         ro_compat.insert(Feature(id, other.ro_compat.get_name(id)));
212       }
213       if (mask & other_incompat) {
214         incompat.insert( Feature(id, other.incompat.get_name(id)));
215       }
216     }
217     return true;
218   }
219
220   void encode(bufferlist& bl) const {
221     compat.encode(bl);
222     ro_compat.encode(bl);
223     incompat.encode(bl);
224   }
225   
226   void decode(bufferlist::iterator& bl) {
227     compat.decode(bl);
228     ro_compat.decode(bl);
229     incompat.decode(bl);
230   }
231
232   void dump(Formatter *f) const {
233     f->open_object_section("compat");
234     compat.dump(f);
235     f->close_section();
236     f->open_object_section("ro_compat");
237     ro_compat.dump(f);
238     f->close_section();
239     f->open_object_section("incompat");
240     incompat.dump(f);
241     f->close_section();
242   }
243
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"));
251   }
252 };
253 WRITE_CLASS_ENCODER(CompatSet)
254
255 inline ostream& operator<<(ostream& out, const CompatSet::FeatureSet& fs)
256 {
257   return out << fs.names;
258 }
259
260 inline ostream& operator<<(ostream& out, const CompatSet& compat)
261 {
262   return out << "compat=" << compat.compat
263              << ",rocompat=" << compat.ro_compat
264              << ",incompat=" << compat.incompat;
265 }
266
267 #endif