]> git.proxmox.com Git - ceph.git/blob - ceph/src/include/CompatSet.h
update source to Ceph Pacific 16.2.2
[ceph.git] / 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
18 #include <iostream>
19 #include <map>
20 #include <string>
21
22 #include "include/buffer.h"
23 #include "include/encoding.h"
24 #include "include/types.h"
25 #include "common/Formatter.h"
26
27 struct CompatSet {
28
29 struct Feature {
30 uint64_t id;
31 std::string name;
32
33 Feature(uint64_t _id, const std::string& _name) : id(_id), name(_name) {}
34 };
35
36 class FeatureSet {
37 uint64_t mask;
38 std::map<uint64_t, std::string> names;
39
40 public:
41 friend struct CompatSet;
42 friend class CephCompatSet_AllSet_Test;
43 friend class CephCompatSet_other_Test;
44 friend class CephCompatSet_merge_Test;
45 friend std::ostream& operator<<(std::ostream& out, const CompatSet::FeatureSet& fs);
46 friend std::ostream& operator<<(std::ostream& out, const CompatSet& compat);
47 FeatureSet() : mask(1), names() {}
48 void insert(const Feature& f) {
49 ceph_assert(f.id > 0);
50 ceph_assert(f.id < 64);
51 mask |= ((uint64_t)1<<f.id);
52 names[f.id] = f.name;
53 }
54
55 bool contains(const Feature& f) const {
56 return names.count(f.id);
57 }
58 bool contains(uint64_t f) const {
59 return names.count(f);
60 }
61 /**
62 * Getter instead of using name[] to be const safe
63 */
64 std::string get_name(uint64_t const f) const {
65 std::map<uint64_t, std::string>::const_iterator i = names.find(f);
66 ceph_assert(i != names.end());
67 return i->second;
68 }
69
70 void remove(uint64_t f) {
71 if (names.count(f)) {
72 names.erase(f);
73 mask &= ~((uint64_t)1<<f);
74 }
75 }
76 void remove(const Feature& f) {
77 remove(f.id);
78 }
79
80 void encode(ceph::buffer::list& bl) const {
81 using ceph::encode;
82 /* See below, mask always has the lowest bit set in memory, but
83 * unset in the encoding */
84 encode(mask & (~(uint64_t)1), bl);
85 encode(names, bl);
86 }
87
88 void decode(ceph::buffer::list::const_iterator& bl) {
89 using ceph::decode;
90 decode(mask, bl);
91 decode(names, bl);
92 /**
93 * Previously, there was a bug where insert did
94 * mask |= f.id rather than mask |= (1 << f.id).
95 * In FeatureSets from those version, mask always
96 * has the lowest bit set. Since then, masks always
97 * have the lowest bit unset.
98 *
99 * When we encounter such a FeatureSet, we have to
100 * reconstruct the mask from the names map.
101 */
102 if (mask & 1) {
103 mask = 1;
104 std::map<uint64_t, std::string> temp_names;
105 temp_names.swap(names);
106 for (auto i = temp_names.begin(); i != temp_names.end(); ++i) {
107 insert(Feature(i->first, i->second));
108 }
109 } else {
110 mask |= 1;
111 }
112 }
113
114 void dump(ceph::Formatter *f) const {
115 for (auto p = names.cbegin(); p != names.cend(); ++p) {
116 char s[18];
117 snprintf(s, sizeof(s), "feature_%llu", (unsigned long long)p->first);
118 f->dump_string(s, p->second);
119 }
120 }
121 };
122
123 // These features have no impact on the read / write status
124 FeatureSet compat;
125 // If any of these features are missing, read is possible ( as long
126 // as no incompat feature is missing ) but it is not possible to write
127 FeatureSet ro_compat;
128 // If any of these features are missing, read or write is not possible
129 FeatureSet incompat;
130
131 CompatSet(FeatureSet& _compat, FeatureSet& _ro_compat, FeatureSet& _incompat) :
132 compat(_compat), ro_compat(_ro_compat), incompat(_incompat) {}
133
134 CompatSet() : compat(), ro_compat(), incompat() { }
135
136
137 /* does this filesystem implementation have the
138 features required to read the other? */
139 bool readable(CompatSet const& other) const {
140 return !((other.incompat.mask ^ incompat.mask) & other.incompat.mask);
141 }
142
143 /* does this filesystem implementation have the
144 features required to write the other? */
145 bool writeable(CompatSet const& other) const {
146 return readable(other) &&
147 !((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask);
148 }
149
150 /* Compare this CompatSet to another.
151 * CAREFULLY NOTE: This operation is NOT commutative.
152 * a > b DOES NOT imply that b < a.
153 * If returns:
154 * 0: The CompatSets have the same feature set.
155 * 1: This CompatSet's features are a strict superset of the other's.
156 * -1: This CompatSet is missing at least one feature
157 * described in the other. It may still have more features, though.
158 */
159 int compare(const CompatSet& other) {
160 if ((other.compat.mask == compat.mask) &&
161 (other.ro_compat.mask == ro_compat.mask) &&
162 (other.incompat.mask == incompat.mask)) return 0;
163 //okay, they're not the same
164
165 //if we're writeable we have a superset of theirs on incompat and ro_compat
166 if (writeable(other) && !((other.compat.mask ^ compat.mask)
167 & other.compat.mask)) return 1;
168 //if we make it here, we weren't writeable or had a difference compat set
169 return -1;
170 }
171
172 /* Get the features supported by other CompatSet but not this one,
173 * as a CompatSet.
174 */
175 CompatSet unsupported(CompatSet& other) {
176 CompatSet diff;
177 uint64_t other_compat =
178 ((other.compat.mask ^ compat.mask) & other.compat.mask);
179 uint64_t other_ro_compat =
180 ((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask);
181 uint64_t other_incompat =
182 ((other.incompat.mask ^ incompat.mask) & other.incompat.mask);
183 for (int id = 1; id < 64; ++id) {
184 uint64_t mask = (uint64_t)1 << id;
185 if (mask & other_compat) {
186 diff.compat.insert( Feature(id, other.compat.names[id]));
187 }
188 if (mask & other_ro_compat) {
189 diff.ro_compat.insert(Feature(id, other.ro_compat.names[id]));
190 }
191 if (mask & other_incompat) {
192 diff.incompat.insert( Feature(id, other.incompat.names[id]));
193 }
194 }
195 return diff;
196 }
197
198 /* Merge features supported by other CompatSet into this one.
199 * Return: true if some features were merged
200 */
201 bool merge(CompatSet const & other) {
202 uint64_t other_compat =
203 ((other.compat.mask ^ compat.mask) & other.compat.mask);
204 uint64_t other_ro_compat =
205 ((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask);
206 uint64_t other_incompat =
207 ((other.incompat.mask ^ incompat.mask) & other.incompat.mask);
208 if (!other_compat && !other_ro_compat && !other_incompat)
209 return false;
210 for (int id = 1; id < 64; ++id) {
211 uint64_t mask = (uint64_t)1 << id;
212 if (mask & other_compat) {
213 compat.insert( Feature(id, other.compat.get_name(id)));
214 }
215 if (mask & other_ro_compat) {
216 ro_compat.insert(Feature(id, other.ro_compat.get_name(id)));
217 }
218 if (mask & other_incompat) {
219 incompat.insert( Feature(id, other.incompat.get_name(id)));
220 }
221 }
222 return true;
223 }
224
225 void encode(ceph::buffer::list& bl) const {
226 compat.encode(bl);
227 ro_compat.encode(bl);
228 incompat.encode(bl);
229 }
230
231 void decode(ceph::buffer::list::const_iterator& bl) {
232 compat.decode(bl);
233 ro_compat.decode(bl);
234 incompat.decode(bl);
235 }
236
237 void dump(ceph::Formatter *f) const {
238 f->open_object_section("compat");
239 compat.dump(f);
240 f->close_section();
241 f->open_object_section("ro_compat");
242 ro_compat.dump(f);
243 f->close_section();
244 f->open_object_section("incompat");
245 incompat.dump(f);
246 f->close_section();
247 }
248
249 static void generate_test_instances(std::list<CompatSet*>& o) {
250 o.push_back(new CompatSet);
251 o.push_back(new CompatSet);
252 o.back()->compat.insert(Feature(1, "one"));
253 o.back()->compat.insert(Feature(2, "two"));
254 o.back()->ro_compat.insert(Feature(4, "four"));
255 o.back()->incompat.insert(Feature(3, "three"));
256 }
257 };
258 WRITE_CLASS_ENCODER(CompatSet)
259
260 inline std::ostream& operator<<(std::ostream& out, const CompatSet::FeatureSet& fs)
261 {
262 return out << fs.names;
263 }
264
265 inline std::ostream& operator<<(std::ostream& out, const CompatSet& compat)
266 {
267 return out << "compat=" << compat.compat
268 << ",rocompat=" << compat.ro_compat
269 << ",incompat=" << compat.incompat;
270 }
271
272 #endif