The device classes are implemented by modifying:
- the argument of step TAKE in rules
- cloning bucket trees when required by a rule step
This happens (via populate_classes):
- before compiling a rule step TAKE
When the crush map is encoded, the device class information is stored
with it, independently from the rules and the buckets, as a map of
classes for each device & bucket and a map of classes for each rule step
TAKE.
The extra buckets created but not used by any rule do not need to be
preserved and they are removed (via cleanup_classes):
- before decompilation
- after compilation
- after decoding
The client and daemons that are not aware of the device classes are
compatible because the crushmap modified with the new buckets is fully
functional. The invalid names used in the for the generated
buckets (bucket~class) can be CrushWrapper::decode by any existing
client because there is no verification of the name validity during
decoding. It can also be CrushWrapper::dump or CrushCompiler::decompile
via ceph osd dump or crushtool. It cannot, however, be compiled again
because CrushCompiler::compile will try to set the name with
CrushWrapper::set_item_name and it will fail with EINVAL because of the
~.
Fixes: http://tracker.ceph.com/issues/18943
Signed-off-by: Loic Dachary <ldachary@redhat.com>
int CrushCompiler::decompile(ostream &out)
{
+ crush.cleanup_classes();
+
out << "# begin crush map\n";
// only dump tunables if they differ from the defaults
int CrushCompiler::parse_rule(iter_t const& i)
{
+ crush.populate_classes();
+
int start; // rule name is optional!
string rname = string_node(i->children[1]);
}
//err << "max_devices " << crush.get_max_devices() << std::endl;
+ crush.cleanup_classes();
crush.finalize();
return 0;
for (auto &c : class_name)
class_rname[c.second] = c.first;
::decode(class_bucket, blp);
+ cleanup_classes();
}
finalize();
}