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<string,set<string> > bucket_items;
+ map<string,iter_t> bucket_itrer;
+ vector<string> 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)
{
<< " 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());
void find_used_bucket_ids(iter_t const& i);
int parse_crush(iter_t const& i);
void dump(iter_t const& i, int ind=1);
-
string consolidate_whitespace(string in);
+ int adjust_bucket_item_place(iter_t const &i);
public:
CrushCompiler(CrushWrapper& c, ostream& eo, int verbosity=0)
--- /dev/null
+#!/bin/bash
+
+
+#Generic test_crush_bucket test
+#
+
+# Includes
+source ../qa/workunits/ceph-helpers.sh
+function run() {
+ local dir=$1
+ shift
+
+ export CEPH_MON="127.0.0.1:17119"
+ export CEPH_ARGS
+ CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none "
+ CEPH_ARGS+="--mon-host=$CEPH_MON "
+
+ local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')}
+ for func in $funcs ; do
+ $func $dir || return 1
+ done
+}
+
+function TEST_crush_bucket() {
+ local dir=$1
+ setup $dir || return 1
+ run_mon $dir a || return 1
+ run_osd $dir 0 || return 1
+ run_osd $dir 1 || return 1
+ run_osd $dir 2 || return 1
+
+
+ ceph osd getcrushmap -o "$dir/map1" || return 1
+ crushtool -d "$dir/map1" -o "$dir/map1.txt"|| return 1
+ local var=`ceph osd crush dump|grep -w id|grep '-'|grep -Eo '[0-9]+'|sort|uniq|sed -n '$p'`
+ local id=`expr $var + 1`
+ local item=`sed -n '/^root/,/}/p' $dir/map1.txt|grep 'item'|head -1`
+ local weight=`sed -n '/^root/,/}/p' $dir/map1.txt|grep 'item'|head -1|awk '{print $4}'`
+ local bucket="host test {\n id -$id\n # weight $weight\n alg straw \n hash 0 # rjenkins1 \n $item\n}\n"
+ sed -i "/# buckets/a\ $bucket" "$dir/map1.txt"
+ crushtool -c "$dir/map1.txt" -o "$dir/map1.bin" 2>"$dir/rev"
+ local result=$(cat "$dir/rev")
+ if [ "$result" != "" ];
+ then
+ return 1
+ fi
+
+}
+
+main testcrushbucket
+