]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crush: fix the problem that can not find the define item below the bucket 8141/head
authorsongbaisen <song.baisen@zte.com.cn>
Wed, 16 Mar 2016 02:55:47 +0000 (10:55 +0800)
committersongbaisen <song.baisen@zte.com.cn>
Fri, 20 May 2016 01:22:08 +0000 (09:22 +0800)
Fixes: http://tracker.ceph.com/issues/15154
Signed-off-by: song baisen <song.baisen@zte.com.cn>
src/crush/CrushCompiler.cc
src/crush/CrushCompiler.h
src/test/Makefile.am
src/test/test_crush_bucket.sh [new file with mode: 0755]

index 22e591348992c12c55ae7207240cba0cff0ace11..1ce72fbbcbdc7d9776dc541d7049c15de8b34ab8 100644 (file)
@@ -815,6 +815,54 @@ void CrushCompiler::dump(iter_t const& i, int ind)
     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)
 {
@@ -880,7 +928,11 @@ 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());
index d488735bb9e23c63207f3b235bc00f06d0d357a3..4e1542f5b092a154799ae8f350dd265b40dae7aa 100644 (file)
@@ -52,8 +52,8 @@ class CrushCompiler {
   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)
index 536edbf012619bd2c4ed97b78df4e1f02272d1ff..8ac4aa876967061df3ace0246441c978c0eba849 100644 (file)
@@ -71,6 +71,7 @@ check_SCRIPTS += \
        test/cephtool-test-mds.sh \
        test/cephtool-test-rados.sh \
        test/test_pool_create.sh \
+       test/test_crush_bucket.sh \
        unittest_bufferlist.sh \
        test/encoding/check-generated.sh \
        test/mon/osd-pool-create.sh \
diff --git a/src/test/test_crush_bucket.sh b/src/test/test_crush_bucket.sh
new file mode 100755 (executable)
index 0000000..8ae8972
--- /dev/null
@@ -0,0 +1,51 @@
+#!/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
+