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
22 #include "include/buffer.h"
23 #include "include/encoding.h"
24 #include "include/types.h"
25 #include "common/Formatter.h"
33 Feature(uint64_t _id
, const std::string
& _name
) : id(_id
), name(_name
) {}
38 std::map
<uint64_t, std::string
> names
;
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
);
55 bool contains(const Feature
& f
) const {
56 return names
.count(f
.id
);
58 bool contains(uint64_t f
) const {
59 return names
.count(f
);
62 * Getter instead of using name[] to be const safe
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());
70 void remove(uint64_t f
) {
73 mask
&= ~((uint64_t)1<<f
);
76 void remove(const Feature
& f
) {
80 void encode(ceph::buffer::list
& bl
) const {
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
);
88 void decode(ceph::buffer::list::const_iterator
& bl
) {
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.
99 * When we encounter such a FeatureSet, we have to
100 * reconstruct the mask from the names map.
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
));
114 void dump(ceph::Formatter
*f
) const {
115 for (auto p
= names
.cbegin(); p
!= names
.cend(); ++p
) {
117 snprintf(s
, sizeof(s
), "feature_%llu", (unsigned long long)p
->first
);
118 f
->dump_string(s
, p
->second
);
123 // These features have no impact on the read / write status
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
131 CompatSet(FeatureSet
& _compat
, FeatureSet
& _ro_compat
, FeatureSet
& _incompat
) :
132 compat(_compat
), ro_compat(_ro_compat
), incompat(_incompat
) {}
134 CompatSet() : compat(), ro_compat(), incompat() { }
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
);
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
);
150 /* Compare this CompatSet to another.
151 * CAREFULLY NOTE: This operation is NOT commutative.
152 * a > b DOES NOT imply that b < a.
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.
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
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
172 /* Get the features supported by other CompatSet but not this one,
175 CompatSet
unsupported(CompatSet
& other
) {
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
]));
188 if (mask
& other_ro_compat
) {
189 diff
.ro_compat
.insert(Feature(id
, other
.ro_compat
.names
[id
]));
191 if (mask
& other_incompat
) {
192 diff
.incompat
.insert( Feature(id
, other
.incompat
.names
[id
]));
198 /* Merge features supported by other CompatSet into this one.
199 * Return: true if some features were merged
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
)
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
)));
215 if (mask
& other_ro_compat
) {
216 ro_compat
.insert(Feature(id
, other
.ro_compat
.get_name(id
)));
218 if (mask
& other_incompat
) {
219 incompat
.insert( Feature(id
, other
.incompat
.get_name(id
)));
225 void encode(ceph::buffer::list
& bl
) const {
227 ro_compat
.encode(bl
);
231 void decode(ceph::buffer::list::const_iterator
& bl
) {
233 ro_compat
.decode(bl
);
237 void dump(ceph::Formatter
*f
) const {
238 f
->open_object_section("compat");
241 f
->open_object_section("ro_compat");
244 f
->open_object_section("incompat");
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"));
258 WRITE_CLASS_ENCODER(CompatSet
)
260 inline std::ostream
& operator<<(std::ostream
& out
, const CompatSet::FeatureSet
& fs
)
262 return out
<< fs
.names
;
265 inline std::ostream
& operator<<(std::ostream
& out
, const CompatSet
& compat
)
267 return out
<< "compat=" << compat
.compat
268 << ",rocompat=" << compat
.ro_compat
269 << ",incompat=" << compat
.incompat
;