]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
crushtool: --remove-item name
authorSage Weil <sage@newdream.net>
Fri, 20 May 2011 23:45:57 +0000 (16:45 -0700)
committerSage Weil <sage@newdream.net>
Fri, 20 May 2011 23:45:41 +0000 (16:45 -0700)
Signed-off-by: Sage Weil <sage@newdream.net>
src/crush/CrushWrapper.cc
src/crush/CrushWrapper.h
src/crush/builder.c
src/crush/builder.h
src/crushtool.cc

index fe08748fcdee0beb1031fd46a6fc2b168ad83525..ba1d5932082dbe3f20350307518c8f19b9e27052 100644 (file)
@@ -17,6 +17,60 @@ void CrushWrapper::find_roots(set<int>& roots) const
 }
 
 
+int CrushWrapper::remove_device(int item)
+{
+  cout << "remove_device item" << std::endl;
+
+  crush_bucket *was_bucket = 0;
+  int ret = -ENOENT;
+
+  set<int> roots;
+  find_roots(roots);
+  for (set<int>::iterator p = roots.begin(); p != roots.end(); ++p) {
+    list<int> q;
+    q.push_back(*p);
+    while (!q.empty()) {
+      int id = q.front();
+      q.pop_front();
+
+      if (id >= 0)
+       continue;  // it's a leaf.
+
+      crush_bucket *b = get_bucket(id);
+      if (!b) {
+       cout << "remove_device warning: bad reference to bucket " << id << std::endl;
+       continue;
+      }
+
+      for (unsigned i=0; i<b->size; ++i) {
+       int id = b->items[i];
+       if (id == item) {
+         if (item < 0) {
+           crush_bucket *t = get_bucket(item);
+           if (t && t->size) {
+             cout << "remove_device bucket " << item << " has " << t->size << " items, not empty" << std::endl;
+             return -ENOTEMPTY;
+           }       
+           was_bucket = t;
+         }
+         cout << "remove_device removing item " << item << " from bucket " << b->id << std::endl;
+         crush_bucket_remove_item(b, item);
+         ret = 0;
+       }
+       if (id < 0)
+         q.push_front(id);
+      }
+    }
+  }
+
+  if (was_bucket) {
+    cout << "remove_device removing bucket " << item << std::endl;
+    crush_remove_bucket(crush, was_bucket);
+  }
+  
+  return ret;
+}
+
 int CrushWrapper::insert_device(int item, int weight, string name,
                                map<string,string>& loc)  // typename -> bucketname
 {
@@ -63,7 +117,7 @@ int CrushWrapper::insert_device(int item, int weight, string name,
       
     cout << "insert_device adding " << item << " weight " << weight
            << " to bucket " << id << std::endl;
-    crush_bucket *b = (crush_bucket *)get_bucket(id);
+    crush_bucket *b = get_bucket(id);
     assert(b);
     crush_bucket_add_item(b, item, 0);
     adjust_item_weight(item, weight);
@@ -97,7 +151,7 @@ void CrushWrapper::reweight()
   for (set<int>::iterator p = roots.begin(); p != roots.end(); p++) {
     if (*p >= 0)
       continue;
-    crush_bucket *b = (struct crush_bucket *)get_bucket(*p);
+    crush_bucket *b = get_bucket(*p);
     cout << "reweight bucket " << *p << std::endl;
     crush_reweight_bucket(crush, b);
   }
index 193b7c8507de99b508e3f82957e867df7493920e..62203df89caa0535765e0c2db2261b9f49bff61c 100644 (file)
@@ -155,6 +155,7 @@ public:
 
   void find_roots(set<int>& roots) const;
   int insert_device(int id, int weight, string name, map<string,string>& loc);
+  int remove_device(int id);
   void adjust_item_weight(int id, int weight);
   void reweight();
 
@@ -284,6 +285,18 @@ private:
       return (crush_bucket *)(-ENOENT);
     return ret;
   }
+  crush_bucket *get_bucket(int id) {
+    if (!crush)
+      return (crush_bucket *)(-EINVAL);
+    unsigned int pos = (unsigned int)(-1 - id);
+    unsigned int max_buckets = crush->max_buckets;
+    if (pos >= max_buckets)
+      return (crush_bucket *)(-ENOENT);
+    crush_bucket *ret = crush->buckets[pos];
+    if (ret == NULL)
+      return (crush_bucket *)(-ENOENT);
+    return ret;
+  }
 
 public:
   int get_max_buckets() const {
@@ -349,7 +362,7 @@ public:
     crush_bucket *b = crush_make_bucket(alg, hash, type, size, items, weights);
     return crush_add_bucket(crush, bucketno, b);
   }
-
+  
   void finalize() {
     assert(crush);
     crush_finalize(crush);
index 9a6588a1bf7d8b7af3d2b5e6fd44c3f885821753..28fa3cb5b2f41e03df7aa499b6c66e4b64fe7514 100644 (file)
@@ -5,6 +5,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <assert.h>
+#include <errno.h>
 
 #include "builder.h"
 #include "hash.h"
@@ -145,6 +146,15 @@ int crush_add_bucket(struct crush_map *map,
        return id;
 }
 
+int crush_remove_bucket(struct crush_map *map, struct crush_bucket *bucket)
+{
+       int pos = -1 - bucket->id;
+
+       map->buckets[pos] = NULL;
+       crush_destroy_bucket(bucket);
+       return 0;
+}
+
 
 /* uniform bucket */
 
@@ -535,6 +545,161 @@ int crush_bucket_add_item(struct crush_bucket *b, int item, int weight)
        return 0;
 }
 
+/************************************************/
+
+int crush_remove_uniform_bucket_item(struct crush_bucket_uniform *bucket, int item)
+{
+       int i, j;
+       int newsize;
+       
+       for (i = 0; i < bucket->h.size; i++)
+               if (bucket->h.items[i] == item)
+                       break;
+       if (i == bucket->h.size)
+               return -ENOENT;
+
+       for (j = i; j < bucket->h.size; j++)
+               bucket->h.items[j] = bucket->h.items[j+1];
+       newsize = --bucket->h.size;
+       bucket->h.weight -= bucket->item_weight;
+
+       bucket->h.items = realloc(bucket->h.items, sizeof(__u32)*newsize);
+       bucket->h.perm = realloc(bucket->h.perm, sizeof(__u32)*newsize);
+       return 0;
+}
+
+int crush_remove_list_bucket_item(struct crush_bucket_list *bucket, int item)
+{
+       int i, j;
+       int newsize;
+       int weight;
+
+       for (i = 0; i < bucket->h.size; i++)
+               if (bucket->h.items[i] == item)
+                       break;
+       if (i == bucket->h.size)
+               return -ENOENT;
+
+       weight = bucket->item_weights[i];
+       for (j = i; j < bucket->h.size; j++) {
+               bucket->h.items[j] = bucket->h.items[j+1];
+               bucket->item_weights[j] = bucket->item_weights[j+1];
+               bucket->sum_weights[j] = bucket->sum_weights[j+1] - weight;
+       }
+       bucket->h.weight -= weight;
+       newsize = --bucket->h.size;
+       
+       bucket->h.items = realloc(bucket->h.items, sizeof(__u32)*newsize);
+       bucket->h.perm = realloc(bucket->h.perm, sizeof(__u32)*newsize);
+       bucket->item_weights = realloc(bucket->item_weights, sizeof(__u32)*newsize);
+       bucket->sum_weights = realloc(bucket->sum_weights, sizeof(__u32)*newsize);
+       return 0;
+}
+
+int crush_remove_tree_bucket_item(struct crush_bucket_tree *bucket, int item)
+{
+       int i;
+       int newsize;
+
+       for (i = 0; i < bucket->h.size; i++) {
+               int node;
+               int weight;
+               int j;
+               int depth = calc_depth(bucket->h.size);
+
+               if (bucket->h.items[i] != item)
+                       continue;
+               
+               node = crush_calc_tree_node(i);
+               weight = bucket->node_weights[node];
+               bucket->node_weights[node] = 0;
+
+               for (j = 1; j < depth; j++) {
+                       node = parent(node);
+                       bucket->node_weights[node] -= weight;
+                       printf(" node %d weight %d\n", node, bucket->node_weights[node]);
+               }
+               bucket->h.weight -= weight;
+               break;
+       }
+       if (i == bucket->h.size)
+               return -ENOENT;
+
+       newsize = bucket->h.size;
+       while (newsize > 0) {
+               int node = crush_calc_tree_node(newsize - 1);
+               if (bucket->node_weights[node])
+                       break;
+               --newsize;
+       }
+
+       if (newsize != bucket->h.size) {
+               int olddepth, newdepth;
+
+               bucket->h.items = realloc(bucket->h.items, sizeof(__u32)*newsize);
+               bucket->h.perm = realloc(bucket->h.perm, sizeof(__u32)*newsize);
+
+               olddepth = calc_depth(bucket->h.size);
+               newdepth = calc_depth(newsize);
+               if (olddepth != newdepth) {
+                       bucket->num_nodes = 1 << newdepth;
+                       bucket->node_weights = realloc(bucket->node_weights,
+                                                      sizeof(__u32)*bucket->num_nodes);
+               }
+
+               bucket->h.size = newsize;
+       }
+       return 0;
+}
+
+int crush_remove_straw_bucket_item(struct crush_bucket_straw *bucket, int item)
+{
+       int newsize = bucket->h.size - 1;
+       int i, j;
+
+       for (i = 0; i < bucket->h.size; i++) {
+               if (bucket->h.items[i] == item) {
+                       bucket->h.size--;
+                       bucket->h.weight -= bucket->item_weights[i];
+                       for (j = i; j < bucket->h.size; j++) {
+                               bucket->h.items[j] = bucket->h.items[j+1];
+                               bucket->item_weights[j] = bucket->item_weights[j+1];
+                       }
+                       break;
+               }
+       }
+       if (i == bucket->h.size)
+               return -ENOENT;
+       
+       bucket->h.items = realloc(bucket->h.items, sizeof(__u32)*newsize);
+       bucket->h.perm = realloc(bucket->h.perm, sizeof(__u32)*newsize);
+       bucket->item_weights = realloc(bucket->item_weights, sizeof(__u32)*newsize);
+       bucket->straws = realloc(bucket->straws, sizeof(__u32)*newsize);
+
+       return crush_calc_straw(bucket);
+}
+
+int crush_bucket_remove_item(struct crush_bucket *b, int item)
+{
+       /* invalidate perm cache */
+       b->perm_n = 0;
+
+       switch (b->alg) {
+       case CRUSH_BUCKET_UNIFORM:
+               return crush_remove_uniform_bucket_item((struct crush_bucket_uniform *)b, item);
+       case CRUSH_BUCKET_LIST:
+               return crush_remove_list_bucket_item((struct crush_bucket_list *)b, item);
+       case CRUSH_BUCKET_TREE:
+               return crush_remove_tree_bucket_item((struct crush_bucket_tree *)b, item);
+       case CRUSH_BUCKET_STRAW:
+               return crush_remove_straw_bucket_item((struct crush_bucket_straw *)b, item);
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+
 /************************************************/
 
 int crush_adjust_uniform_bucket_item_weight(struct crush_bucket_uniform *bucket, int item, int weight)
@@ -731,3 +896,6 @@ int crush_reweight_bucket(struct crush_map *crush, struct crush_bucket *b)
        }
        return 0;
 }
+
+/***************************/
+
index 245cfb378b3b437931fba0298399ea45512bb48a..16533a6445991f77a6c3242ee39568608a6319e9 100644 (file)
@@ -20,6 +20,8 @@ struct crush_bucket *crush_make_bucket(int alg, int hash, int type, int size, in
 extern int crush_bucket_add_item(struct crush_bucket *bucket, int item, int weight);
 extern int crush_bucket_adjust_item_weight(struct crush_bucket *bucket, int item, int weight);
 extern int crush_reweight_bucket(struct crush_map *crush, struct crush_bucket *bucket);
+extern int crush_remove_bucket(struct crush_map *map, struct crush_bucket *bucket);
+extern int crush_bucket_remove_item(struct crush_bucket *bucket, int item);
 
 struct crush_bucket_uniform *
 crush_make_uniform_bucket(int hash, int type, int size,
index bae229e7e89b0bbc64a8736d730064bbff27a3d3..af8dcf783585b8ee827ab660a75bce9a650c4abf 100644 (file)
@@ -805,6 +805,7 @@ int main(int argc, const char **argv)
   float add_weight = 0;
   const char *add_name = 0;
   map<string,string> add_loc;
+  const char *remove_name = 0;
 
   int build = 0;
   int num_osds =0;
@@ -841,6 +842,8 @@ int main(int argc, const char **argv)
       CEPH_ARGPARSE_SET_ARG_VAL(&type, OPT_STR);
       CEPH_ARGPARSE_SET_ARG_VAL(&name, OPT_STR);
       add_loc[type] = name;
+    } else if (CEPH_ARGPARSE_EQ("remove_item", '\0')) {
+      CEPH_ARGPARSE_SET_ARG_VAL(&remove_name, OPT_STR);
     } else if (CEPH_ARGPARSE_EQ("verbose", 'v')) {
       verbose++;
     } else if (CEPH_ARGPARSE_EQ("build", '\0')) {
@@ -886,7 +889,7 @@ int main(int argc, const char **argv)
   }
   if (decompile + compile + build > 1)
     usage();
-  if (!compile && !decompile && !build && !test && !reweight && add_item < 0)
+  if (!compile && !decompile && !build && !test && !reweight && add_item < 0 && !remove_name)
     usage();
 
   /*
@@ -1040,6 +1043,23 @@ int main(int argc, const char **argv)
     modified = true;
   }
 
+  if (remove_name) {
+    cout << me << " removing item " << remove_name << std::endl;
+    int r;
+    if (!crush.name_exists(remove_name)) {
+      cerr << " name " << remove_name << " dne" << std::endl;
+      r = -ENOENT;
+    } else {
+      int remove_item = crush.get_item_id(remove_name);
+      r = crush.remove_device(remove_item);
+    }
+    if (r == 0)
+      modified = true;
+    else {
+      cerr << me << " " << cpp_strerror(r) << std::endl;
+      return r;
+    }
+  }
   if (add_item >= 0) {
     cout << me << " adding item " << add_item << " weight " << add_weight
         << " at " << add_loc << std::endl;