]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crush: automatically kill dead classes 16837/head
authorxie xingguo <xie.xingguo@zte.com.cn>
Sat, 5 Aug 2017 10:25:21 +0000 (18:25 +0800)
committerxie xingguo <xie.xingguo@zte.com.cn>
Sat, 5 Aug 2017 10:53:39 +0000 (18:53 +0800)
If a class is no more referenced by any devices or crush rules,
it shall be considered as dead.

This patch makes Ceph automatically recycles those dead classes,
so user does not to explicitly call 'class rm', which is unsafe
and annoying.

Signed-off-by: xie xingguo <xie.xingguo@zte.com.cn>
qa/standalone/crush/crush-classes.sh
src/crush/CrushWrapper.cc
src/crush/CrushWrapper.h

index 6090835fb36f364ede58dc941695503e2425c82a..24696fcd3193592954266db660e3291850c5340e 100755 (executable)
@@ -162,19 +162,21 @@ function TEST_mon_classes() {
     ceph osd crush tree --show-shadow | grep -q '~ccc' || return 1
     ceph osd crush rm-device-class 0 || return 1
     ceph osd tree | grep -q 'aaa' && return 1
-    ceph osd crush class ls | grep -q 'aaa' || return 1
+    ceph osd crush class ls | grep -q 'aaa' && return 1 # class 'aaa' should gone
     ceph osd crush rm-device-class 1 || return 1
     ceph osd tree | grep -q 'bbb' && return 1
-    ceph osd crush class ls | grep -q 'bbb' || return 1
+    ceph osd crush class ls | grep -q 'bbb' && return 1 # class 'bbb' should gone
     ceph osd crush rm-device-class 2 || return 1
     ceph osd tree | grep -q 'ccc' && return 1
-    ceph osd crush class ls | grep -q 'ccc' || return 1
+    ceph osd crush class ls | grep -q 'ccc' && return 1 # class 'ccc' should gone
     ceph osd crush set-device-class asdf all || return 1
     ceph osd tree | grep -q 'asdf' || return 1
     ceph osd crush dump | grep -q '~asdf' || return 1
     ceph osd crush tree --show-shadow | grep -q '~asdf' || return 1
+    ceph osd crush rule create-replicated asdf-rule default host asdf || return 1
     ceph osd crush rm-device-class all || return 1
     ceph osd tree | grep -q 'asdf' && return 1
+    ceph osd crush class ls | grep -q 'asdf' || return 1 # still referenced by asdf-rule
 
     ceph osd crush set-device-class abc osd.2 || return 1
     ceph osd crush move osd.2 root=foo rack=foo-rack host=foo-host || return 1
index 4bf7cc5df2035b3918e7edf923debb8c1fe3e036..770c472c49a67beb440f503ec806a343c22aca98 100644 (file)
@@ -1889,9 +1889,45 @@ int CrushWrapper::device_class_clone(
   return 0;
 }
 
+bool CrushWrapper::_class_is_dead(int class_id)
+{
+  for (auto &p: class_map) {
+    if (p.first >= 0 && p.second == class_id) {
+      return false;
+    }
+  }
+  for (unsigned i = 0; i < crush->max_rules; ++i) {
+    crush_rule *r = crush->rules[i];
+    if (!r)
+      continue;
+    for (unsigned j = 0; j < r->len; ++j) {
+      if (r->steps[j].op == CRUSH_RULE_TAKE) {
+        int root = r->steps[j].arg1;
+        for (auto &p : class_bucket) {
+          auto& q = p.second;
+          if (q.count(class_id) && q[class_id] == root) {
+            return false;
+          }
+        }
+      }
+    }
+  }
+  // no more referenced by any devices or crush rules
+  return true;
+}
+
+void CrushWrapper::cleanup_dead_classes()
+{
+  for (auto &c: class_name) {
+    if (_class_is_dead(c.first))
+      remove_class_name(c.second);
+  }
+}
+
 int CrushWrapper::rebuild_roots_with_classes()
 {
   std::map<int32_t, map<int32_t, int32_t> > old_class_bucket = class_bucket;
+  cleanup_dead_classes();
   int r = trim_roots_with_class(false);
   if (r < 0)
     return r;
index 7d4f55cac4ab8c4b044028b2147f7d757ab5fbc3..737ba583ececebcd90dd8ae99ddfef6bd8423d43 100644 (file)
@@ -1216,6 +1216,8 @@ public:
     int *clone);
   int populate_classes(
     const std::map<int32_t, map<int32_t, int32_t>>& old_class_bucket);
+  bool _class_is_dead(int class_id);
+  void cleanup_dead_classes();
   int rebuild_roots_with_classes();
   /* remove unused roots generated for class devices */
   int trim_roots_with_class(bool unused);