From: Sage Weil Date: Fri, 20 May 2011 23:45:57 +0000 (-0700) Subject: crushtool: --remove-item name X-Git-Tag: v0.29~42^2~14 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=cc1737bd8191faa159aac15daf1899c5978183bd;p=ceph.git crushtool: --remove-item name Signed-off-by: Sage Weil --- diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index fe08748fcdee..ba1d5932082d 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -17,6 +17,60 @@ void CrushWrapper::find_roots(set& roots) const } +int CrushWrapper::remove_device(int item) +{ + cout << "remove_device item" << std::endl; + + crush_bucket *was_bucket = 0; + int ret = -ENOENT; + + set roots; + find_roots(roots); + for (set::iterator p = roots.begin(); p != roots.end(); ++p) { + list 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; isize; ++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& 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::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); } diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index 193b7c8507de..62203df89caa 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -155,6 +155,7 @@ public: void find_roots(set& roots) const; int insert_device(int id, int weight, string name, map& 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); diff --git a/src/crush/builder.c b/src/crush/builder.c index 9a6588a1bf7d..28fa3cb5b2f4 100644 --- a/src/crush/builder.c +++ b/src/crush/builder.c @@ -5,6 +5,7 @@ #include #include #include +#include #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; } + +/***************************/ + diff --git a/src/crush/builder.h b/src/crush/builder.h index 245cfb378b3b..16533a644599 100644 --- a/src/crush/builder.h +++ b/src/crush/builder.h @@ -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, diff --git a/src/crushtool.cc b/src/crushtool.cc index bae229e7e89b..af8dcf783585 100644 --- a/src/crushtool.cc +++ b/src/crushtool.cc @@ -805,6 +805,7 @@ int main(int argc, const char **argv) float add_weight = 0; const char *add_name = 0; map 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;