X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcrush%2FCrushCompiler.cc;fp=src%2Fceph%2Fsrc%2Fcrush%2FCrushCompiler.cc;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=946a6b037b9fef48c5f4510b9cd3881357639440;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/crush/CrushCompiler.cc b/src/ceph/src/crush/CrushCompiler.cc deleted file mode 100644 index 946a6b0..0000000 --- a/src/ceph/src/crush/CrushCompiler.cc +++ /dev/null @@ -1,1265 +0,0 @@ - -#include "CrushCompiler.h" - -#if defined(_AIX) -#define EBADE ECORRUPT -#endif - -#ifndef EBADE -#define EBADE EFTYPE -#endif -#include -#include "common/errno.h" -#include - -// ------------- - -static void print_type_name(ostream& out, int t, CrushWrapper &crush) -{ - const char *name = crush.get_type_name(t); - if (name) - out << name; - else if (t == 0) - out << "device"; - else - out << "type" << t; -} - -static void print_item_name(ostream& out, int t, CrushWrapper &crush) -{ - const char *name = crush.get_item_name(t); - if (name) - out << name; - else if (t >= 0) - out << "device" << t; - else - out << "bucket" << (-1-t); -} - -static void print_bucket_class_ids(ostream& out, int t, CrushWrapper &crush) -{ - if (crush.class_bucket.count(t) == 0) - return; - auto &class_to_id = crush.class_bucket[t]; - for (auto &i : class_to_id) { - int c = i.first; - int cid = i.second; - const char* class_name = crush.get_class_name(c); - assert(class_name); - out << "\tid " << cid << " class " << class_name << "\t\t# do not change unnecessarily\n"; - } -} - -static void print_item_class(ostream& out, int t, CrushWrapper &crush) -{ - const char *c = crush.get_item_class(t); - if (c) - out << " class " << c; -} - -static void print_class(ostream& out, int t, CrushWrapper &crush) -{ - const char *c = crush.get_class_name(t); - if (c) - out << " class " << c; - else - out << " # unexpected class " << t; -} - -static void print_rule_name(ostream& out, int t, CrushWrapper &crush) -{ - const char *name = crush.get_rule_name(t); - if (name) - out << name; - else - out << "rule" << t; -} - -static void print_fixedpoint(ostream& out, int i) -{ - char s[20]; - snprintf(s, sizeof(s), "%.3f", (float)i / (float)0x10000); - out << s; -} - -int CrushCompiler::decompile_bucket_impl(int i, ostream &out) -{ - const char *name = crush.get_item_name(i); - if (name && !crush.is_valid_crush_name(name)) - return 0; - int type = crush.get_bucket_type(i); - print_type_name(out, type, crush); - out << " "; - print_item_name(out, i, crush); - out << " {\n"; - out << "\tid " << i << "\t\t# do not change unnecessarily\n"; - print_bucket_class_ids(out, i, crush); - - out << "\t# weight "; - print_fixedpoint(out, crush.get_bucket_weight(i)); - out << "\n"; - - int n = crush.get_bucket_size(i); - - int alg = crush.get_bucket_alg(i); - out << "\talg " << crush_bucket_alg_name(alg); - - // notate based on alg type - bool dopos = false; - switch (alg) { - case CRUSH_BUCKET_UNIFORM: - out << "\t# do not change bucket size (" << n << ") unnecessarily"; - dopos = true; - break; - case CRUSH_BUCKET_LIST: - out << "\t# add new items at the end; do not change order unnecessarily"; - break; - case CRUSH_BUCKET_TREE: - out << "\t# do not change pos for existing items unnecessarily"; - dopos = true; - break; - } - out << "\n"; - - int hash = crush.get_bucket_hash(i); - out << "\thash " << hash << "\t# " << crush_hash_name(hash) << "\n"; - - for (int j=0; j& dcb_states, - ostream &out) -{ - if ((cur == 0) || (!crush.bucket_exists(cur))) - return 0; - - std::map::iterator c = dcb_states.find(cur); - if (c == dcb_states.end()) { - // Mark this bucket as "in progress." - std::map::value_type val(cur, DCB_STATE_IN_PROGRESS); - std::pair ::iterator, bool> rval - (dcb_states.insert(val)); - assert(rval.second); - c = rval.first; - } - else if (c->second == DCB_STATE_DONE) { - // We already did this bucket. - return 0; - } - else if (c->second == DCB_STATE_IN_PROGRESS) { - err << "decompile_crush_bucket: logic error: tried to decompile " - "a bucket that is already being decompiled" << std::endl; - return -EBADE; - } - else { - err << "decompile_crush_bucket: logic error: illegal bucket state! " - << c->second << std::endl; - return -EBADE; - } - - int bsize = crush.get_bucket_size(cur); - for (int i = 0; i < bsize; ++i) { - int item = crush.get_bucket_item(cur, i); - std::map::iterator d = dcb_states.find(item); - if (d == dcb_states.end()) { - int ret = decompile_bucket(item, dcb_states, out); - if (ret) - return ret; - } - else if (d->second == DCB_STATE_IN_PROGRESS) { - err << "decompile_crush_bucket: error: while trying to output bucket " - << cur << ", we found out that it contains one of the buckets that " - << "contain it. This is not allowed. The buckets must form a " - << "directed acyclic graph." << std::endl; - return -EINVAL; - } - else if (d->second != DCB_STATE_DONE) { - err << "decompile_crush_bucket: logic error: illegal bucket state " - << d->second << std::endl; - return -EBADE; - } - } - decompile_bucket_impl(cur, out); - c->second = DCB_STATE_DONE; - return 0; -} - -int CrushCompiler::decompile_weight_set_weights(crush_weight_set weight_set, - ostream &out) -{ - out << " [ "; - for (__u32 i = 0; i < weight_set.size; i++) { - print_fixedpoint(out, weight_set.weights[i]); - out << " "; - } - out << "]\n"; - return 0; -} - -int CrushCompiler::decompile_weight_set(crush_weight_set *weight_set, - __u32 size, - ostream &out) -{ - out << " weight_set [\n"; - for (__u32 i = 0; i < size; i++) { - int r = decompile_weight_set_weights(weight_set[i], out); - if (r < 0) - return r; - } - out << " ]\n"; - return 0; -} - -int CrushCompiler::decompile_ids(__s32 *ids, - __u32 size, - ostream &out) -{ - out << " ids [ "; - for (__u32 i = 0; i < size; i++) - out << ids[i] << " "; - out << "]\n"; - return 0; -} - -int CrushCompiler::decompile_choose_arg(crush_choose_arg *arg, - int bucket_id, - ostream &out) -{ - int r; - out << " {\n"; - out << " bucket_id " << bucket_id << "\n"; - if (arg->weight_set_size > 0) { - r = decompile_weight_set(arg->weight_set, arg->weight_set_size, out); - if (r < 0) - return r; - } - if (arg->ids_size > 0) { - r = decompile_ids(arg->ids, arg->ids_size, out); - if (r < 0) - return r; - } - out << " }\n"; - return 0; -} - -int CrushCompiler::decompile_choose_arg_map(crush_choose_arg_map arg_map, - ostream &out) -{ - for (__u32 i = 0; i < arg_map.size; i++) { - if ((arg_map.args[i].ids_size == 0) && - (arg_map.args[i].weight_set_size == 0)) - continue; - int r = decompile_choose_arg(&arg_map.args[i], -1-i, out); - if (r < 0) - return r; - } - return 0; -} - -int CrushCompiler::decompile_choose_args(const std::pair &i, - ostream &out) -{ - out << "choose_args " << i.first << " {\n"; - int r = decompile_choose_arg_map(i.second, out); - if (r < 0) - return r; - out << "}\n"; - return 0; -} - -int CrushCompiler::decompile(ostream &out) -{ - out << "# begin crush map\n"; - - // only dump tunables if they differ from the defaults - if (crush.get_choose_local_tries() != 2) - out << "tunable choose_local_tries " << crush.get_choose_local_tries() << "\n"; - if (crush.get_choose_local_fallback_tries() != 5) - out << "tunable choose_local_fallback_tries " << crush.get_choose_local_fallback_tries() << "\n"; - if (crush.get_choose_total_tries() != 19) - out << "tunable choose_total_tries " << crush.get_choose_total_tries() << "\n"; - if (crush.get_chooseleaf_descend_once() != 0) - out << "tunable chooseleaf_descend_once " << crush.get_chooseleaf_descend_once() << "\n"; - if (crush.get_chooseleaf_vary_r() != 0) - out << "tunable chooseleaf_vary_r " << crush.get_chooseleaf_vary_r() << "\n"; - if (crush.get_chooseleaf_stable() != 0) - out << "tunable chooseleaf_stable " << crush.get_chooseleaf_stable() << "\n"; - if (crush.get_straw_calc_version() != 0) - out << "tunable straw_calc_version " << crush.get_straw_calc_version() << "\n"; - if (crush.get_allowed_bucket_algs() != CRUSH_LEGACY_ALLOWED_BUCKET_ALGS) - out << "tunable allowed_bucket_algs " << crush.get_allowed_bucket_algs() - << "\n"; - - out << "\n# devices\n"; - for (int i=0; i dcb_states; - for (int bucket = -1; bucket > -1-crush.get_max_buckets(); --bucket) { - int ret = decompile_bucket(bucket, dcb_states, out); - if (ret) - return ret; - } - - out << "\n# rules\n"; - for (int i=0; i= 0) - step_item = original_item; - print_item_name(out, step_item, crush); - if (c >= 0) - print_class(out, c, crush); - } - out << "\n"; - break; - case CRUSH_RULE_EMIT: - out << "\tstep emit\n"; - break; - case CRUSH_RULE_SET_CHOOSE_TRIES: - out << "\tstep set_choose_tries " << crush.get_rule_arg1(i, j) - << "\n"; - break; - case CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES: - out << "\tstep set_choose_local_tries " << crush.get_rule_arg1(i, j) - << "\n"; - break; - case CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES: - out << "\tstep set_choose_local_fallback_tries " << crush.get_rule_arg1(i, j) - << "\n"; - break; - case CRUSH_RULE_SET_CHOOSELEAF_TRIES: - out << "\tstep set_chooseleaf_tries " << crush.get_rule_arg1(i, j) - << "\n"; - break; - case CRUSH_RULE_SET_CHOOSELEAF_VARY_R: - out << "\tstep set_chooseleaf_vary_r " << crush.get_rule_arg1(i, j) - << "\n"; - break; - case CRUSH_RULE_SET_CHOOSELEAF_STABLE: - out << "\tstep set_chooseleaf_stable " << crush.get_rule_arg1(i, j) - << "\n"; - break; - case CRUSH_RULE_CHOOSE_FIRSTN: - out << "\tstep choose firstn " - << crush.get_rule_arg1(i, j) - << " type "; - print_type_name(out, crush.get_rule_arg2(i, j), crush); - out << "\n"; - break; - case CRUSH_RULE_CHOOSE_INDEP: - out << "\tstep choose indep " - << crush.get_rule_arg1(i, j) - << " type "; - print_type_name(out, crush.get_rule_arg2(i, j), crush); - out << "\n"; - break; - case CRUSH_RULE_CHOOSELEAF_FIRSTN: - out << "\tstep chooseleaf firstn " - << crush.get_rule_arg1(i, j) - << " type "; - print_type_name(out, crush.get_rule_arg2(i, j), crush); - out << "\n"; - break; - case CRUSH_RULE_CHOOSELEAF_INDEP: - out << "\tstep chooseleaf indep " - << crush.get_rule_arg1(i, j) - << " type "; - print_type_name(out, crush.get_rule_arg2(i, j), crush); - out << "\n"; - break; - } - } - out << "}\n"; - } - if (crush.choose_args.size() > 0) { - out << "\n# choose_args\n"; - for (auto i : crush.choose_args) { - int ret = decompile_choose_args(i, out); - if (ret) - return ret; - } - } - out << "\n# end crush map" << std::endl; - return 0; -} - - -// ================================================================ - -string CrushCompiler::string_node(node_t &node) -{ - return boost::trim_copy(string(node.value.begin(), node.value.end())); -} - -int CrushCompiler::int_node(node_t &node) -{ - string str = string_node(node); - return strtol(str.c_str(), 0, 10); -} - -float CrushCompiler::float_node(node_t &node) -{ - string s = string_node(node); - return strtof(s.c_str(), 0); -} - -int CrushCompiler::parse_device(iter_t const& i) -{ - int id = int_node(i->children[1]); - - string name = string_node(i->children[2]); - crush.set_item_name(id, name.c_str()); - if (item_id.count(name)) { - err << "item " << name << " defined twice" << std::endl; - return -1; - } - item_id[name] = id; - id_item[id] = name; - - if (verbose) err << "device " << id << " '" << name << "'"; - - if (i->children.size() > 3) { - string c = string_node(i->children[4]); - crush.set_item_class(id, c); - if (verbose) err << " class" << " '" << c << "'" << std::endl; - } else { - if (verbose) err << std::endl; - } - return 0; -} - -int CrushCompiler::parse_tunable(iter_t const& i) -{ - string name = string_node(i->children[1]); - int val = int_node(i->children[2]); - - if (name == "choose_local_tries") - crush.set_choose_local_tries(val); - else if (name == "choose_local_fallback_tries") - crush.set_choose_local_fallback_tries(val); - else if (name == "choose_total_tries") - crush.set_choose_total_tries(val); - else if (name == "chooseleaf_descend_once") - crush.set_chooseleaf_descend_once(val); - else if (name == "chooseleaf_vary_r") - crush.set_chooseleaf_vary_r(val); - else if (name == "chooseleaf_stable") - crush.set_chooseleaf_stable(val); - else if (name == "straw_calc_version") - crush.set_straw_calc_version(val); - else if (name == "allowed_bucket_algs") - crush.set_allowed_bucket_algs(val); - else { - err << "tunable " << name << " not recognized" << std::endl; - return -1; - } - - /* - - current crop of tunables are all now "safe". re-enable this when we - add new ones that are ... new. - - if (!unsafe_tunables) { - err << "tunables are NOT FULLY IMPLEMENTED; enable with --enable-unsafe-tunables to enable this feature" << std::endl; - return -1; - } - */ - - if (verbose) err << "tunable " << name << " " << val << std::endl; - return 0; -} - -int CrushCompiler::parse_bucket_type(iter_t const& i) -{ - int id = int_node(i->children[1]); - string name = string_node(i->children[2]); - if (verbose) err << "type " << id << " '" << name << "'" << std::endl; - type_id[name] = id; - crush.set_type_name(id, name.c_str()); - return 0; -} - -int CrushCompiler::parse_bucket(iter_t const& i) -{ - string tname = string_node(i->children[0]); - if (!type_id.count(tname)) { - err << "bucket type '" << tname << "' is not defined" << std::endl; - return -1; - } - int type = type_id[tname]; - - string name = string_node(i->children[1]); - if (item_id.count(name)) { - err << "bucket or device '" << name << "' is already defined" << std::endl; - return -1; - } - - int id = 0; // none, yet! - int alg = -1; - int hash = 0; - set used_items; - int size = 0; - map class_id; - - for (unsigned p=3; pchildren.size()-1; p++) { - iter_t sub = i->children.begin() + p; - string tag = string_node(sub->children[0]); - //err << "tag " << tag << std::endl; - if (tag == "id") { - int maybe_id = int_node(sub->children[1]); - if (verbose) err << "bucket " << name << " id " << maybe_id; - if (sub->children.size() > 2) { - string class_name = string_node(sub->children[3]); - // note that we do not verify class existence here, - // as this bucket might come from an empty shadow tree - // which currently has no OSDs but is still referenced by a rule! - int cid = crush.get_or_create_class_id(class_name); - if (class_id.count(cid) != 0) { - err << "duplicate device class " << class_name << " for bucket " << name << std::endl; - return -ERANGE; - } - class_id[cid] = maybe_id; - if (verbose) err << " class" << " '" << class_name << "'" << std::endl; - } else { - id = maybe_id; - if (verbose) err << std::endl; - } - } else if (tag == "alg") { - string a = string_node(sub->children[1]); - if (a == "uniform") - alg = CRUSH_BUCKET_UNIFORM; - else if (a == "list") - alg = CRUSH_BUCKET_LIST; - else if (a == "tree") - alg = CRUSH_BUCKET_TREE; - else if (a == "straw") - alg = CRUSH_BUCKET_STRAW; - else if (a == "straw2") - alg = CRUSH_BUCKET_STRAW2; - else { - err << "unknown bucket alg '" << a << "'" << std::endl << std::endl; - return -EINVAL; - } - } - else if (tag == "hash") { - string a = string_node(sub->children[1]); - if (a == "rjenkins1") - hash = CRUSH_HASH_RJENKINS1; - else - hash = atoi(a.c_str()); - } - else if (tag == "item") { - // first, just determine which item pos's are already used - size++; - for (unsigned q = 2; q < sub->children.size(); q++) { - string tag = string_node(sub->children[q++]); - if (tag == "pos") { - int pos = int_node(sub->children[q]); - if (used_items.count(pos)) { - err << "item '" << string_node(sub->children[1]) << "' in bucket '" << name << "' has explicit pos " << pos << ", which is occupied" << std::endl; - return -1; - } - used_items.insert(pos); - } - } - } - else ceph_abort(); - } - - // now do the items. - if (!used_items.empty()) - size = MAX(size, *used_items.rbegin()); - vector items(size); - vector weights(size); - - int curpos = 0; - unsigned bucketweight = 0; - bool have_uniform_weight = false; - unsigned uniform_weight = 0; - for (unsigned p=3; pchildren.size()-1; p++) { - iter_t sub = i->children.begin() + p; - string tag = string_node(sub->children[0]); - if (tag == "item") { - - string iname = string_node(sub->children[1]); - if (!item_id.count(iname)) { - err << "item '" << iname << "' in bucket '" << name << "' is not defined" << std::endl; - return -1; - } - int itemid = item_id[iname]; - - unsigned weight = 0x10000; - if (item_weight.count(itemid)) - weight = item_weight[itemid]; - - int pos = -1; - for (unsigned q = 2; q < sub->children.size(); q++) { - string tag = string_node(sub->children[q++]); - if (tag == "weight") { - weight = float_node(sub->children[q]) * (float)0x10000; - if (weight > CRUSH_MAX_DEVICE_WEIGHT && itemid >= 0) { - err << "device weight limited to " << CRUSH_MAX_DEVICE_WEIGHT / 0x10000 << std::endl; - return -ERANGE; - } - else if (weight > CRUSH_MAX_BUCKET_WEIGHT && itemid < 0) { - err << "bucket weight limited to " << CRUSH_MAX_BUCKET_WEIGHT / 0x10000 - << " to prevent overflow" << std::endl; - return -ERANGE; - } - } - else if (tag == "pos") - pos = int_node(sub->children[q]); - else - ceph_abort(); - - } - if (alg == CRUSH_BUCKET_UNIFORM) { - if (!have_uniform_weight) { - have_uniform_weight = true; - uniform_weight = weight; - } else { - if (uniform_weight != weight) { - err << "item '" << iname << "' in uniform bucket '" << name << "' has weight " << weight - << " but previous item(s) have weight " << (float)uniform_weight/(float)0x10000 - << "; uniform bucket items must all have identical weights." << std::endl; - return -1; - } - } - } - - if (pos >= size) { - err << "item '" << iname << "' in bucket '" << name << "' has pos " << pos << " >= size " << size << std::endl; - return -1; - } - if (pos < 0) { - while (used_items.count(curpos)) curpos++; - pos = curpos++; - } - //err << " item " << iname << " (" << itemid << ") pos " << pos << " weight " << weight << std::endl; - items[pos] = itemid; - weights[pos] = weight; - - if (crush_addition_is_unsafe(bucketweight, weight)) { - err << "oh no! our bucket weights are overflowing all over the place, better lower the item weights" << std::endl; - return -ERANGE; - } - - bucketweight += weight; - } - } - - if (id == 0) { - for (id=-1; id_item.count(id); id--) ; - //err << "assigned id " << id << std::endl; - } - - for (auto &i : class_id) - class_bucket[id][i.first] = i.second; - - if (verbose) err << "bucket " << name << " (" << id << ") " << size << " items and weight " - << (float)bucketweight / (float)0x10000 << std::endl; - id_item[id] = name; - item_id[name] = id; - item_weight[id] = bucketweight; - - assert(id != 0); - int idout; - int r = crush.add_bucket(id, alg, hash, type, size, - &items[0], &weights[0], &idout); - if (r < 0) { - if (r == -EEXIST) - err << "Duplicate bucket id " << id << std::endl; - else - err << "add_bucket failed " << cpp_strerror(r) << std::endl; - return r; - } - r = crush.set_item_name(id, name.c_str()); - return r; -} - -int CrushCompiler::parse_rule(iter_t const& i) -{ - int start; // rule name is optional! - - string rname = string_node(i->children[1]); - if (rname != "{") { - if (rule_id.count(rname)) { - err << "rule name '" << rname << "' already defined\n" << std::endl; - return -1; - } - start = 4; - } else { - rname = string(); - start = 3; - } - - int ruleno = int_node(i->children[start]); - - string tname = string_node(i->children[start+2]); - int type; - if (tname == "replicated") - type = CEPH_PG_TYPE_REPLICATED; - else if (tname == "erasure") - type = CEPH_PG_TYPE_ERASURE; - else - ceph_abort(); - - int minsize = int_node(i->children[start+4]); - int maxsize = int_node(i->children[start+6]); - - int steps = i->children.size() - start - 8; - //err << "num steps " << steps << std::endl; - - if (crush.rule_exists(ruleno)) { - err << "rule " << ruleno << " already exists" << std::endl; - return -1; - } - int r = crush.add_rule(ruleno, steps, type, minsize, maxsize); - if (r != ruleno) { - err << "unable to add rule id " << ruleno << " for rule '" << rname - << "'" << std::endl; - return -1; - } - if (rname.length()) { - crush.set_rule_name(ruleno, rname.c_str()); - rule_id[rname] = ruleno; - } - - int step = 0; - for (iter_t p = i->children.begin() + start + 7; step < steps; p++) { - iter_t s = p->children.begin() + 1; - int stepid = s->value.id().to_long(); - switch (stepid) { - case crush_grammar::_step_take: - { - string item = string_node(s->children[1]); - if (!item_id.count(item)) { - err << "in rule '" << rname << "' item '" << item << "' not defined" << std::endl; - return -1; - } - int id = item_id[item]; - int c = -1; - string class_name; - if (s->children.size() > 2) { - class_name = string_node(s->children[3]); - c = crush.get_class_id(class_name); - if (c < 0) - return c; - if (crush.class_bucket.count(id) == 0) { - err << "in rule '" << rname << "' step take " << item - << " has no class information" << std::endl; - return -EINVAL; - } - if (crush.class_bucket[id].count(c) == 0) { - err << "in rule '" << rname << "' step take " << item - << " no matching bucket for class " << class_name << std::endl; - return -EINVAL; - } - id = crush.class_bucket[id][c]; - } - if (verbose) { - err << "rule " << rname << " take " << item; - if (c < 0) - err << std::endl; - else - err << " remapped to " << crush.get_item_name(id) << std::endl; - } - - crush.set_rule_step_take(ruleno, step++, id); - } - break; - - case crush_grammar::_step_set_choose_tries: - { - int val = int_node(s->children[1]); - crush.set_rule_step_set_choose_tries(ruleno, step++, val); - } - break; - - case crush_grammar::_step_set_choose_local_tries: - { - int val = int_node(s->children[1]); - crush.set_rule_step_set_choose_local_tries(ruleno, step++, val); - } - break; - - case crush_grammar::_step_set_choose_local_fallback_tries: - { - int val = int_node(s->children[1]); - crush.set_rule_step_set_choose_local_fallback_tries(ruleno, step++, val); - } - break; - - case crush_grammar::_step_set_chooseleaf_tries: - { - int val = int_node(s->children[1]); - crush.set_rule_step_set_chooseleaf_tries(ruleno, step++, val); - } - break; - - case crush_grammar::_step_set_chooseleaf_vary_r: - { - int val = int_node(s->children[1]); - crush.set_rule_step_set_chooseleaf_vary_r(ruleno, step++, val); - } - break; - - case crush_grammar::_step_set_chooseleaf_stable: - { - int val = int_node(s->children[1]); - crush.set_rule_step_set_chooseleaf_stable(ruleno, step++, val); - } - break; - - case crush_grammar::_step_choose: - case crush_grammar::_step_chooseleaf: - { - string type = string_node(s->children[4]); - if (!type_id.count(type)) { - err << "in rule '" << rname << "' type '" << type << "' not defined" << std::endl; - return -1; - } - string choose = string_node(s->children[0]); - string mode = string_node(s->children[1]); - if (choose == "choose") { - if (mode == "firstn") - crush.set_rule_step_choose_firstn(ruleno, step++, int_node(s->children[2]), type_id[type]); - else if (mode == "indep") - crush.set_rule_step_choose_indep(ruleno, step++, int_node(s->children[2]), type_id[type]); - else ceph_abort(); - } else if (choose == "chooseleaf") { - if (mode == "firstn") - crush.set_rule_step_choose_leaf_firstn(ruleno, step++, int_node(s->children[2]), type_id[type]); - else if (mode == "indep") - crush.set_rule_step_choose_leaf_indep(ruleno, step++, int_node(s->children[2]), type_id[type]); - else ceph_abort(); - } else ceph_abort(); - } - break; - - case crush_grammar::_step_emit: - crush.set_rule_step_emit(ruleno, step++); - break; - - default: - err << "bad crush step " << stepid << std::endl; - return -1; - } - } - assert(step == steps); - return 0; -} - -int CrushCompiler::parse_weight_set_weights(iter_t const& i, int bucket_id, crush_weight_set *weight_set) -{ - // -2 for the enclosing [ ] - __u32 size = i->children.size() - 2; - __u32 bucket_size = crush.get_bucket_size(bucket_id); - if (size != bucket_size) { - err << bucket_id << " needs exactly " << bucket_size - << " weights but got " << size << std::endl; - return -1; - } - weight_set->size = size; - weight_set->weights = (__u32 *)calloc(weight_set->size, sizeof(__u32)); - __u32 pos = 0; - for (iter_t p = i->children.begin() + 1; p != i->children.end(); p++, pos++) - if (pos < size) - weight_set->weights[pos] = float_node(*p) * (float)0x10000; - return 0; -} - -int CrushCompiler::parse_weight_set(iter_t const& i, int bucket_id, crush_choose_arg *arg) -{ - // -3 stands for the leading "weight_set" keyword and the enclosing [ ] - arg->weight_set_size = i->children.size() - 3; - arg->weight_set = (crush_weight_set *)calloc(arg->weight_set_size, sizeof(crush_weight_set)); - __u32 pos = 0; - for (iter_t p = i->children.begin(); p != i->children.end(); p++) { - int r = 0; - switch((int)p->value.id().to_long()) { - case crush_grammar::_weight_set_weights: - if (pos < arg->weight_set_size) { - r = parse_weight_set_weights(p, bucket_id, &arg->weight_set[pos]); - pos++; - } else { - err << "invalid weight_set syntax" << std::endl; - r = -1; - } - } - if (r < 0) - return r; - } - return 0; -} - -int CrushCompiler::parse_choose_arg_ids(iter_t const& i, int bucket_id, crush_choose_arg *arg) -{ - // -3 for the leading "ids" keyword and the enclosing [ ] - __u32 size = i->children.size() - 3; - __u32 bucket_size = crush.get_bucket_size(bucket_id); - if (size != bucket_size) { - err << bucket_id << " needs exactly " << bucket_size - << " ids but got " << size << std::endl; - return -1; - } - arg->ids_size = size; - arg->ids = (__s32 *)calloc(arg->ids_size, sizeof(__s32)); - __u32 pos = 0; - for (iter_t p = i->children.begin() + 2; pos < size; p++, pos++) - arg->ids[pos] = int_node(*p); - return 0; -} - -int CrushCompiler::parse_choose_arg(iter_t const& i, crush_choose_arg *args) -{ - int bucket_id = int_node(i->children[2]); - if (-1-bucket_id < 0 || -1-bucket_id >= crush.get_max_buckets()) { - err << bucket_id << " is out of range" << std::endl; - return -1; - } - if (!crush.bucket_exists(bucket_id)) { - err << bucket_id << " does not exist" << std::endl; - return -1; - } - crush_choose_arg *arg = &args[-1-bucket_id]; - for (iter_t p = i->children.begin(); p != i->children.end(); p++) { - int r = 0; - switch((int)p->value.id().to_long()) { - case crush_grammar::_weight_set: - r = parse_weight_set(p, bucket_id, arg); - break; - case crush_grammar::_choose_arg_ids: - r = parse_choose_arg_ids(p, bucket_id, arg); - break; - } - if (r < 0) - return r; - } - return 0; -} - -int CrushCompiler::parse_choose_args(iter_t const& i) -{ - int choose_arg_index = int_node(i->children[1]); - if (crush.choose_args.find(choose_arg_index) != crush.choose_args.end()) { - err << choose_arg_index << " duplicated" << std::endl; - return -1; - } - crush_choose_arg_map arg_map; - arg_map.size = crush.get_max_buckets(); - arg_map.args = (crush_choose_arg *)calloc(arg_map.size, sizeof(crush_choose_arg)); - for (iter_t p = i->children.begin() + 2; p != i->children.end(); p++) { - int r = 0; - switch((int)p->value.id().to_long()) { - case crush_grammar::_choose_arg: - r = parse_choose_arg(p, arg_map.args); - break; - } - if (r < 0) { - crush.destroy_choose_args(arg_map); - return r; - } - } - crush.choose_args[choose_arg_index] = arg_map; - return 0; -} - -void CrushCompiler::find_used_bucket_ids(iter_t const& i) -{ - for (iter_t p = i->children.begin(); p != i->children.end(); p++) { - if ((int)p->value.id().to_long() == crush_grammar::_bucket) { - iter_t firstline = p->children.begin() + 3; - string tag = string_node(firstline->children[0]); - if (tag == "id") { - int id = int_node(firstline->children[1]); - //err << "saw bucket id " << id << std::endl; - id_item[id] = string(); - } - } - } -} - -int CrushCompiler::parse_crush(iter_t const& i) -{ - find_used_bucket_ids(i); - bool saw_rule = false; - for (iter_t p = i->children.begin(); p != i->children.end(); p++) { - int r = 0; - switch (p->value.id().to_long()) { - case crush_grammar::_tunable: - r = parse_tunable(p); - break; - case crush_grammar::_device: - r = parse_device(p); - break; - case crush_grammar::_bucket_type: - r = parse_bucket_type(p); - break; - case crush_grammar::_bucket: - if (saw_rule) { - err << "buckets must be defined before rules" << std::endl; - return -1; - } - r = parse_bucket(p); - break; - case crush_grammar::_crushrule: - if (!saw_rule) { - saw_rule = true; - crush.populate_classes(class_bucket); - } - r = parse_rule(p); - break; - case crush_grammar::_choose_args: - r = parse_choose_args(p); - break; - default: - ceph_abort(); - } - if (r < 0) { - return r; - } - } - - //err << "max_devices " << crush.get_max_devices() << std::endl; - crush.finalize(); - - return 0; -} - -// squash runs of whitespace to one space, excepting newlines -string CrushCompiler::consolidate_whitespace(string in) -{ - string out; - - bool white = false; - for (unsigned p=0; p 3) - err << " \"" << in << "\" -> \"" << out << "\"" << std::endl; - return out; -} - -void CrushCompiler::dump(iter_t const& i, int ind) -{ - err << "dump"; - for (int j=0; jvalue.id().to_long(); - err << id << "\t"; - err << "'" << string(i->value.begin(), i->value.end()) - << "' " << i->children.size() << " children" << std::endl; - for (unsigned int j = 0; j < i->children.size(); j++) - dump(i->children.begin() + j, ind+1); -} - -/** -* This function fix the problem like below -* rack using_foo { item foo } -* host foo { ... } -* -* if an item being used by a bucket is defined after that bucket. -* CRUSH compiler will create a map by which we can -* not identify that item when selecting in that bucket. -**/ -int CrushCompiler::adjust_bucket_item_place(iter_t const &i) -{ - map > bucket_items; - map bucket_itrer; - vector buckets; - for (iter_t p = i->children.begin(); p != i->children.end(); ++p) { - if ((int)p->value.id().to_long() == crush_grammar::_bucket) { - string name = string_node(p->children[1]); - buckets.push_back(name); - bucket_itrer[name] = p; - //skip non-bucket-item children in the bucket's parse tree - for (unsigned q=3; q < p->children.size()-1; ++q) { - iter_t sub = p->children.begin() + q; - if ((int)sub->value.id().to_long() - == crush_grammar::_bucket_item) { - string iname = string_node(sub->children[1]); - bucket_items[name].insert(iname); - } - } - } - } - - //adjust the bucket - for (unsigned i=0; i < buckets.size(); ++i) { - for (unsigned j=i+1; j < buckets.size(); ++j) { - if (bucket_items[buckets[i]].count(buckets[j])) { - if (bucket_items[buckets[j]].count(buckets[i])) { - err << "bucket '" << buckets[i] << "' and bucket '" - << buckets[j] << "' are included each other" << std::endl; - return -1; - } else { - std::iter_swap(bucket_itrer[buckets[i]], bucket_itrer[buckets[j]]); - } - } - } - } - - return 0; -} - -int CrushCompiler::compile(istream& in, const char *infn) -{ - if (!infn) - infn = ""; - - // always start with legacy tunables, so that the compiled result of - // a given crush file is fixed for all time. - crush.set_tunables_legacy(); - - string big; - string str; - int line = 1; - map line_pos; // pos -> line - map line_val; - while (getline(in, str)) { - // remove newline - int l = str.length(); - if (l && str[l - 1] == '\n') - str.erase(l-1, 1); - - line_val[line] = str; - - // strip comment - int n = str.find("#"); - if (n >= 0) - str.erase(n, str.length()-n); - - if (verbose>1) err << line << ": " << str << std::endl; - - // work around spirit crankiness by removing extraneous - // whitespace. there is probably a more elegant solution, but - // this only broke with the latest spirit (with the switchover to - // "classic"), i don't want to spend too much time figuring it - // out. - string stripped = consolidate_whitespace(str); - if (stripped.length() && big.length() && big[big.length()-1] != ' ') big += " "; - - line_pos[big.length()] = line; - line++; - big += stripped; - } - - if (verbose > 2) err << "whole file is: \"" << big << "\"" << std::endl; - - crush_grammar crushg; - const char *start = big.c_str(); - //tree_parse_info info = ast_parse(start, crushg, space_p); - tree_parse_info<> info = ast_parse(start, crushg, space_p); - - // parse error? - if (!info.full) { - int cpos = info.stop - start; - //out << "cpos " << cpos << std::endl; - //out << " linemap " << line_pos << std::endl; - assert(!line_pos.empty()); - map::iterator p = line_pos.upper_bound(cpos); - if (p != line_pos.begin()) - --p; - int line = p->second; - int pos = cpos - p->first; - err << infn << ":" << line //<< ":" << (pos+1) - << " error: parse error at '" << line_val[line].substr(pos) << "'" << std::endl; - return -1; - } - - int r = adjust_bucket_item_place(info.trees.begin()); - if (r < 0) { - return r; - } - //out << "parsing succeeded\n"; - //dump(info.trees.begin()); - return parse_crush(info.trees.begin()); -}