#include <algorithm>
#include <stdlib.h>
#include <boost/lexical_cast.hpp>
+#include <boost/icl/interval_map.hpp>
+#include <boost/algorithm/string/join.hpp>
#include <common/SubProcess.h>
void CrushTester::set_device_weight(int dev, float f)
return true;
}
+static string get_rule_name(CrushWrapper& crush, int rule)
+{
+ if (crush.get_rule_name(rule))
+ return crush.get_rule_name(rule);
+ else
+ return string("rule") + std::to_string(rule);
+}
+
+void CrushTester::check_overlapped_rules() const
+{
+ namespace icl = boost::icl;
+ typedef std::set<string> RuleNames;
+ typedef icl::interval_map<int, RuleNames> Rules;
+ // <ruleset, type> => interval_map<size, {names}>
+ typedef std::map<std::pair<int, int>, Rules> RuleSets;
+ using interval = icl::interval<int>;
+
+ // mimic the logic of crush_find_rule(), but it only return the first matched
+ // one, but I am collecting all of them by the overlapped sizes.
+ RuleSets rulesets;
+ for (int rule = 0; rule < crush.get_max_rules(); rule++) {
+ if (!crush.rule_exists(rule)) {
+ continue;
+ }
+ Rules& rules = rulesets[{crush.get_rule_mask_ruleset(rule),
+ crush.get_rule_mask_type(rule)}];
+ rules += make_pair(interval::closed(crush.get_rule_mask_min_size(rule),
+ crush.get_rule_mask_max_size(rule)),
+ RuleNames{get_rule_name(crush, rule)});
+ }
+ for (auto i : rulesets) {
+ auto ruleset_type = i.first;
+ const Rules& rules = i.second;
+ for (auto r : rules) {
+ const RuleNames& names = r.second;
+ // if there are more than one rules covering the same size range,
+ // print them out.
+ if (names.size() > 1) {
+ err << "overlapped rules in ruleset " << ruleset_type.first << ": "
+ << boost::join(names, ", ") << "\n";
+ }
+ }
+ }
+}
+
int CrushTester::test()
{
if (min_rule < 0 || max_rule < 0) {
--- /dev/null
+device 0 device0
+device 1 device1
+device 2 device2
+device 3 device3
+device 4 device4
+
+type 0 osd
+type 1 host
+
+host host0 {
+ id -1
+ alg straw
+ hash 0
+ item device0 weight 1.000
+ item device1 weight 1.000
+ item device2 weight 1.000
+ item device3 weight 1.000
+ item device4 weight 1.000
+}
+
+rule rule-r0 {
+ ruleset 0
+ type replicated
+ min_size 1
+ max_size 3
+ step take host0
+ step choose firstn 0 type osd
+ step emit
+}
+
+rule rule-r1 {
+ ruleset 0
+ type replicated
+ min_size 1
+ max_size 1
+ step take host0
+ step choose firstn 0 type osd
+ step emit
+}
+
+rule rule-r2 {
+ ruleset 0
+ type replicated
+ min_size 1
+ max_size 2
+ step take host0
+ step choose firstn 0 type osd
+ step emit
+}
+
+rule rule-r3 {
+ ruleset 0
+ type replicated
+ min_size 2
+ max_size 3
+ step take host0
+ step choose indep 0 type osd
+ step emit
+}
+
+rule rule-r4 {
+ ruleset 0
+ type replicated
+ min_size 4
+ max_size 5
+ step take host0
+ step choose indep 0 type osd
+ step emit
+}
+
+rule rule-e0 {
+ ruleset 0
+ type erasure
+ min_size 1
+ max_size 10
+ step take host0
+ step choose indep 0 type osd
+ step emit
+}
+
+rule rule-e1 {
+ ruleset 1
+ type erasure
+ min_size 1
+ max_size 10
+ step take host0
+ step choose indep 0 type osd
+ step emit
+}
--- /dev/null
+ $ crushtool -c "$TESTDIR/check-overlapped-rules.crushmap.txt" -o "$TESTDIR/check-overlapped-rules.crushmap"
+ $ crushtool -i "$TESTDIR/check-overlapped-rules.crushmap" --check
+ overlapped rules in ruleset 0: rule-r0, rule-r1, rule-r2
+ overlapped rules in ruleset 0: rule-r0, rule-r2, rule-r3
+ overlapped rules in ruleset 0: rule-r0, rule-r3
+ $ rm -f "$TESTDIR/check-overlapped-rules.crushmap"