mirror of
https://github.com/ceph/ceph
synced 2025-02-23 02:57:21 +00:00
Merge pull request #3057 from ceph/wip-crush-straw
crush: fix straw bucket scaler bugs Reviewed-by: Greg Farnum <gfarnum@redhat.com>
This commit is contained in:
commit
5439d9ee70
@ -828,6 +828,7 @@ function test_mon_osd()
|
||||
#
|
||||
# osd crush
|
||||
#
|
||||
ceph osd crush reweight-all
|
||||
ceph osd crush tunables legacy
|
||||
ceph osd crush show-tunables | grep argonaut
|
||||
ceph osd crush tunables bobtail
|
||||
@ -835,6 +836,11 @@ function test_mon_osd()
|
||||
ceph osd crush tunables firefly
|
||||
ceph osd crush show-tunables | grep firefly
|
||||
|
||||
ceph osd crush set-tunable straw_calc_version 0
|
||||
ceph osd crush get-tunable straw_calc_version | grep 0
|
||||
ceph osd crush set-tunable straw_calc_version 1
|
||||
ceph osd crush get-tunable straw_calc_version | grep 1
|
||||
|
||||
#
|
||||
# osd scrub
|
||||
#
|
||||
|
@ -191,6 +191,8 @@ int CrushCompiler::decompile(ostream &out)
|
||||
out << "tunable chooseleaf_descend_once " << crush.get_chooseleaf_descend_once() << "\n";
|
||||
if (crush.get_chooseleaf_vary_r() != 0)
|
||||
out << "tunable chooseleaf_vary_r " << crush.get_chooseleaf_vary_r() << "\n";
|
||||
if (crush.get_straw_calc_version() != 0)
|
||||
out << "tunable straw_calc_version " << crush.get_straw_calc_version() << "\n";
|
||||
|
||||
out << "\n# devices\n";
|
||||
for (int i=0; i<crush.get_max_devices(); i++) {
|
||||
@ -368,6 +370,8 @@ int CrushCompiler::parse_tunable(iter_t const& i)
|
||||
crush.set_chooseleaf_descend_once(val);
|
||||
else if (name == "chooseleaf_vary_r")
|
||||
crush.set_chooseleaf_vary_r(val);
|
||||
else if (name == "straw_calc_version")
|
||||
crush.set_straw_calc_version(val);
|
||||
else {
|
||||
err << "tunable " << name << " not recognized" << std::endl;
|
||||
return -1;
|
||||
|
@ -487,18 +487,18 @@ int CrushTester::test()
|
||||
vector<int> out;
|
||||
|
||||
if (use_crush) {
|
||||
if (output_statistics)
|
||||
err << "CRUSH"; // prepend CRUSH to placement output
|
||||
if (output_mappings)
|
||||
err << "CRUSH"; // prepend CRUSH to placement output
|
||||
crush.do_rule(r, x, out, nr, weight);
|
||||
} else {
|
||||
if (output_statistics)
|
||||
err << "RNG"; // prepend RNG to placement output to denote simulation
|
||||
if (output_mappings)
|
||||
err << "RNG"; // prepend RNG to placement output to denote simulation
|
||||
// test our new monte carlo placement generator
|
||||
random_placement(r, out, nr, weight);
|
||||
}
|
||||
|
||||
if (output_statistics)
|
||||
err << " rule " << r << " x " << x << " " << out << std::endl;
|
||||
if (output_mappings)
|
||||
err << " rule " << r << " x " << x << " " << out << std::endl;
|
||||
|
||||
if (output_data_file)
|
||||
write_integer_indexed_vector_data_string(tester_data.placement_information, x, out);
|
||||
@ -539,14 +539,14 @@ int CrushTester::test()
|
||||
|
||||
if (output_statistics)
|
||||
for (unsigned i = 0; i < per.size(); i++) {
|
||||
if (output_utilization && num_batches > 1){
|
||||
if (output_utilization) {
|
||||
if (num_objects_expected[i] > 0 && per[i] > 0) {
|
||||
err << " device " << i << ":\t"
|
||||
<< "\t" << " stored " << ": " << per[i]
|
||||
<< "\t" << " expected " << ": " << num_objects_expected[i]
|
||||
<< std::endl;
|
||||
}
|
||||
} else if (output_utilization_all && num_batches > 1) {
|
||||
} else if (output_utilization_all) {
|
||||
err << " device " << i << ":\t"
|
||||
<< "\t" << " stored " << ": " << per[i]
|
||||
<< "\t" << " expected " << ": " << num_objects_expected[i]
|
||||
|
@ -27,6 +27,7 @@ class CrushTester {
|
||||
bool output_utilization;
|
||||
bool output_utilization_all;
|
||||
bool output_statistics;
|
||||
bool output_mappings;
|
||||
bool output_bad_mappings;
|
||||
bool output_choose_tries;
|
||||
|
||||
@ -176,6 +177,7 @@ public:
|
||||
output_utilization(false),
|
||||
output_utilization_all(false),
|
||||
output_statistics(false),
|
||||
output_mappings(false),
|
||||
output_bad_mappings(false),
|
||||
output_choose_tries(false),
|
||||
output_data_file(false),
|
||||
@ -226,6 +228,13 @@ public:
|
||||
return output_statistics;
|
||||
}
|
||||
|
||||
void set_output_mappings(bool b) {
|
||||
output_mappings = b;
|
||||
}
|
||||
bool get_output_mappings() const {
|
||||
return output_mappings;
|
||||
}
|
||||
|
||||
void set_output_bad_mappings(bool b) {
|
||||
output_bad_mappings = b;
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ int CrushWrapper::remove_item(CephContext *cct, int item, bool unlink_only)
|
||||
if (id == item) {
|
||||
ldout(cct, 5) << "remove_item removing item " << item
|
||||
<< " from bucket " << b->id << dendl;
|
||||
crush_bucket_remove_item(b, item);
|
||||
crush_bucket_remove_item(crush, b, item);
|
||||
adjust_item_weight(cct, b->id, b->weight);
|
||||
ret = 0;
|
||||
}
|
||||
@ -262,7 +262,7 @@ int CrushWrapper::_remove_item_under(CephContext *cct, int item, int ancestor, b
|
||||
int id = b->items[i];
|
||||
if (id == item) {
|
||||
ldout(cct, 5) << "_remove_item_under removing item " << item << " from bucket " << b->id << dendl;
|
||||
crush_bucket_remove_item(b, item);
|
||||
crush_bucket_remove_item(crush, b, item);
|
||||
adjust_item_weight(cct, b->id, b->weight);
|
||||
ret = 0;
|
||||
} else if (id < 0) {
|
||||
@ -584,7 +584,7 @@ int CrushWrapper::insert_item(CephContext *cct, int item, float weight, string n
|
||||
|
||||
ldout(cct, 5) << "insert_item adding " << cur << " weight " << weight
|
||||
<< " to bucket " << id << dendl;
|
||||
int r = crush_bucket_add_item(b, cur, 0);
|
||||
int r = crush_bucket_add_item(crush, b, cur, 0);
|
||||
assert (!r);
|
||||
break;
|
||||
}
|
||||
@ -749,7 +749,7 @@ int CrushWrapper::adjust_item_weight(CephContext *cct, int id, int weight)
|
||||
continue;
|
||||
for (unsigned i = 0; i < b->size; i++) {
|
||||
if (b->items[i] == id) {
|
||||
int diff = crush_bucket_adjust_item_weight(b, id, weight);
|
||||
int diff = crush_bucket_adjust_item_weight(crush, b, id, weight);
|
||||
ldout(cct, 5) << "adjust_item_weight " << id << " diff " << diff << " in bucket " << bidx << dendl;
|
||||
adjust_item_weight(cct, -1 - bidx, b->weight);
|
||||
changed++;
|
||||
@ -775,7 +775,7 @@ int CrushWrapper::adjust_item_weight_in_loc(CephContext *cct, int id, int weight
|
||||
continue;
|
||||
for (unsigned int i = 0; i < b->size; i++) {
|
||||
if (b->items[i] == id) {
|
||||
int diff = crush_bucket_adjust_item_weight(b, id, weight);
|
||||
int diff = crush_bucket_adjust_item_weight(crush, b, id, weight);
|
||||
ldout(cct, 5) << "adjust_item_weight_in_loc " << id << " diff " << diff << " in bucket " << bid << dendl;
|
||||
adjust_item_weight(cct, bid, b->weight);
|
||||
changed++;
|
||||
@ -802,7 +802,7 @@ int CrushWrapper::adjust_subtree_weight(CephContext *cct, int id, int weight)
|
||||
for (unsigned i=0; i<b->size; ++i) {
|
||||
int n = b->items[i];
|
||||
if (n >= 0) {
|
||||
crush_bucket_adjust_item_weight(b, n, weight);
|
||||
crush_bucket_adjust_item_weight(crush, b, n, weight);
|
||||
} else {
|
||||
crush_bucket *sub = get_bucket(n);
|
||||
if (IS_ERR(sub))
|
||||
@ -1105,6 +1105,7 @@ void CrushWrapper::encode(bufferlist& bl, bool lean) const
|
||||
::encode(crush->choose_total_tries, bl);
|
||||
::encode(crush->chooseleaf_descend_once, bl);
|
||||
::encode(crush->chooseleaf_vary_r, bl);
|
||||
::encode(crush->straw_calc_version, bl);
|
||||
}
|
||||
|
||||
static void decode_32_or_64_string_map(map<int32_t,string>& m, bufferlist::iterator& blp)
|
||||
@ -1188,6 +1189,9 @@ void CrushWrapper::decode(bufferlist::iterator& blp)
|
||||
if (!blp.end()) {
|
||||
::decode(crush->chooseleaf_vary_r, blp);
|
||||
}
|
||||
if (!blp.end()) {
|
||||
::decode(crush->straw_calc_version, blp);
|
||||
}
|
||||
finalize();
|
||||
}
|
||||
catch (...) {
|
||||
@ -1371,6 +1375,8 @@ void CrushWrapper::dump_tunables(Formatter *f) const
|
||||
f->dump_int("choose_local_fallback_tries", get_choose_local_fallback_tries());
|
||||
f->dump_int("choose_total_tries", get_choose_total_tries());
|
||||
f->dump_int("chooseleaf_descend_once", get_chooseleaf_descend_once());
|
||||
f->dump_int("chooseleaf_vary_r", get_chooseleaf_vary_r());
|
||||
f->dump_int("straw_calc_version", get_straw_calc_version());
|
||||
|
||||
// be helpful about it
|
||||
if (has_firefly_tunables())
|
||||
|
@ -87,6 +87,8 @@ public:
|
||||
crush_destroy(crush);
|
||||
}
|
||||
|
||||
crush_map *get_crush_map() { return crush; }
|
||||
|
||||
/* building */
|
||||
void create() {
|
||||
if (crush)
|
||||
@ -120,15 +122,25 @@ public:
|
||||
crush->chooseleaf_descend_once = 1;
|
||||
crush->chooseleaf_vary_r = 1;
|
||||
}
|
||||
void set_tunables_hammer() {
|
||||
crush->choose_local_tries = 0;
|
||||
crush->choose_local_fallback_tries = 0;
|
||||
crush->choose_total_tries = 50;
|
||||
crush->chooseleaf_descend_once = 1;
|
||||
crush->chooseleaf_vary_r = 1;
|
||||
}
|
||||
|
||||
void set_tunables_legacy() {
|
||||
set_tunables_argonaut();
|
||||
crush->straw_calc_version = 0;
|
||||
}
|
||||
void set_tunables_optimal() {
|
||||
set_tunables_firefly();
|
||||
set_tunables_hammer();
|
||||
crush->straw_calc_version = 1;
|
||||
}
|
||||
void set_tunables_default() {
|
||||
set_tunables_bobtail();
|
||||
crush->straw_calc_version = 1;
|
||||
}
|
||||
|
||||
int get_choose_local_tries() const {
|
||||
@ -166,13 +178,21 @@ public:
|
||||
crush->chooseleaf_vary_r = n;
|
||||
}
|
||||
|
||||
int get_straw_calc_version() const {
|
||||
return crush->straw_calc_version;
|
||||
}
|
||||
void set_straw_calc_version(int n) {
|
||||
crush->straw_calc_version = n;
|
||||
}
|
||||
|
||||
bool has_argonaut_tunables() const {
|
||||
return
|
||||
crush->choose_local_tries == 2 &&
|
||||
crush->choose_local_fallback_tries == 5 &&
|
||||
crush->choose_total_tries == 19 &&
|
||||
crush->chooseleaf_descend_once == 0 &&
|
||||
crush->chooseleaf_vary_r == 0;
|
||||
crush->chooseleaf_vary_r == 0 &&
|
||||
crush->straw_calc_version == 0;
|
||||
}
|
||||
bool has_bobtail_tunables() const {
|
||||
return
|
||||
@ -180,7 +200,8 @@ public:
|
||||
crush->choose_local_fallback_tries == 0 &&
|
||||
crush->choose_total_tries == 50 &&
|
||||
crush->chooseleaf_descend_once == 1 &&
|
||||
crush->chooseleaf_vary_r == 0;
|
||||
crush->chooseleaf_vary_r == 0 &&
|
||||
crush->straw_calc_version == 0;
|
||||
}
|
||||
bool has_firefly_tunables() const {
|
||||
return
|
||||
@ -188,7 +209,17 @@ public:
|
||||
crush->choose_local_fallback_tries == 0 &&
|
||||
crush->choose_total_tries == 50 &&
|
||||
crush->chooseleaf_descend_once == 1 &&
|
||||
crush->chooseleaf_vary_r == 1;
|
||||
crush->chooseleaf_vary_r == 1 &&
|
||||
crush->straw_calc_version == 0;
|
||||
}
|
||||
bool has_hammer_tunables() const {
|
||||
return
|
||||
crush->choose_local_tries == 0 &&
|
||||
crush->choose_local_fallback_tries == 0 &&
|
||||
crush->choose_total_tries == 50 &&
|
||||
crush->chooseleaf_descend_once == 1 &&
|
||||
crush->chooseleaf_vary_r == 1 &&
|
||||
crush->straw_calc_version == 1;
|
||||
}
|
||||
|
||||
bool has_optimal_tunables() const {
|
||||
@ -781,11 +812,11 @@ private:
|
||||
|
||||
if (!IS_ERR(parent_bucket)) {
|
||||
// zero out the bucket weight
|
||||
crush_bucket_adjust_item_weight(parent_bucket, item, 0);
|
||||
crush_bucket_adjust_item_weight(crush, parent_bucket, item, 0);
|
||||
adjust_item_weight(cct, parent_bucket->id, parent_bucket->weight);
|
||||
|
||||
// remove the bucket from the parent
|
||||
crush_bucket_remove_item(parent_bucket, item);
|
||||
crush_bucket_remove_item(crush, parent_bucket, item);
|
||||
} else if (PTR_ERR(parent_bucket) != -ENOENT) {
|
||||
return PTR_ERR(parent_bucket);
|
||||
}
|
||||
@ -865,7 +896,7 @@ public:
|
||||
int *items, int *weights, int *idout) {
|
||||
if (type == 0)
|
||||
return -EINVAL;
|
||||
crush_bucket *b = crush_make_bucket(alg, hash, type, size, items, weights);
|
||||
crush_bucket *b = crush_make_bucket(crush, alg, hash, type, size, items, weights);
|
||||
assert(b);
|
||||
return crush_add_bucket(crush, bucketno, b, idout);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ struct crush_map *crush_create()
|
||||
m->choose_total_tries = 19;
|
||||
m->chooseleaf_descend_once = 0;
|
||||
m->chooseleaf_vary_r = 0;
|
||||
m->straw_calc_version = 0;
|
||||
return m;
|
||||
}
|
||||
|
||||
@ -404,7 +405,34 @@ err:
|
||||
|
||||
/* straw bucket */
|
||||
|
||||
int crush_calc_straw(struct crush_bucket_straw *bucket)
|
||||
/*
|
||||
* this code was written 8 years ago. i have a vague recollection of
|
||||
* drawing boxes underneath bars of different lengths, where the bar
|
||||
* length represented the probability/weight, and that there was some
|
||||
* trial and error involved in arriving at this implementation.
|
||||
* however, reading the code now after all this time, the intuition
|
||||
* that motivated is lost on me. lame. my only excuse is that I now
|
||||
* know that the approach is fundamentally flawed and am not
|
||||
* particularly motivated to reconstruct the flawed reasoning.
|
||||
*
|
||||
* as best as i can remember, the idea is: sort the weights, and start
|
||||
* with the smallest. arbitrarily scale it at 1.0 (16-bit fixed
|
||||
* point). look at the next larger weight, and calculate the scaling
|
||||
* factor for that straw based on the relative difference in weight so
|
||||
* far. what's not clear to me now is why we are looking at wnext
|
||||
* (the delta to the next bigger weight) for all remaining weights,
|
||||
* and slicing things horizontally instead of considering just the
|
||||
* next item or set of items. or why pow() is used the way it is.
|
||||
*
|
||||
* note that the original version 1 of this function made special
|
||||
* accomodation for the case where straw lengths were identical. this
|
||||
* is also flawed in a non-obvious way; version 2 drops the special
|
||||
* handling and appears to work just as well.
|
||||
*
|
||||
* moral of the story: if you do something clever, write down why it
|
||||
* works.
|
||||
*/
|
||||
int crush_calc_straw(struct crush_map *map, struct crush_bucket_straw *bucket)
|
||||
{
|
||||
int *reverse;
|
||||
int i, j, k;
|
||||
@ -440,41 +468,82 @@ int crush_calc_straw(struct crush_bucket_straw *bucket)
|
||||
|
||||
i=0;
|
||||
while (i < size) {
|
||||
/* zero weight items get 0 length straws! */
|
||||
if (weights[reverse[i]] == 0) {
|
||||
bucket->straws[reverse[i]] = 0;
|
||||
if (map->straw_calc_version == 0) {
|
||||
/* zero weight items get 0 length straws! */
|
||||
if (weights[reverse[i]] == 0) {
|
||||
bucket->straws[reverse[i]] = 0;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set this item's straw */
|
||||
bucket->straws[reverse[i]] = straw * 0x10000;
|
||||
dprintk("item %d at %d weight %d straw %d (%lf)\n",
|
||||
bucket->h.items[reverse[i]],
|
||||
reverse[i], weights[reverse[i]],
|
||||
bucket->straws[reverse[i]], straw);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set this item's straw */
|
||||
bucket->straws[reverse[i]] = straw * 0x10000;
|
||||
/*dprintk("item %d at %d weight %d straw %d (%lf)\n",
|
||||
items[reverse[i]],
|
||||
reverse[i], weights[reverse[i]], bucket->straws[reverse[i]], straw);*/
|
||||
i++;
|
||||
if (i == size) break;
|
||||
|
||||
/* same weight as previous? */
|
||||
if (weights[reverse[i]] == weights[reverse[i-1]]) {
|
||||
/*dprintk("same as previous\n");*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* adjust straw for next guy */
|
||||
wbelow += ((double)weights[reverse[i-1]] - lastw) * numleft;
|
||||
for (j=i; j<size; j++)
|
||||
if (weights[reverse[j]] == weights[reverse[i]])
|
||||
numleft--;
|
||||
else
|
||||
if (i == size)
|
||||
break;
|
||||
wnext = numleft * (weights[reverse[i]] - weights[reverse[i-1]]);
|
||||
pbelow = wbelow / (wbelow + wnext);
|
||||
/*dprintk("wbelow %lf wnext %lf pbelow %lf\n", wbelow, wnext, pbelow);*/
|
||||
|
||||
straw *= pow((double)1.0 / pbelow, (double)1.0 / (double)numleft);
|
||||
/* same weight as previous? */
|
||||
if (weights[reverse[i]] == weights[reverse[i-1]]) {
|
||||
dprintk("same as previous\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
lastw = weights[reverse[i-1]];
|
||||
/* adjust straw for next guy */
|
||||
wbelow += ((double)weights[reverse[i-1]] - lastw) *
|
||||
numleft;
|
||||
for (j=i; j<size; j++)
|
||||
if (weights[reverse[j]] == weights[reverse[i]])
|
||||
numleft--;
|
||||
else
|
||||
break;
|
||||
wnext = numleft * (weights[reverse[i]] -
|
||||
weights[reverse[i-1]]);
|
||||
pbelow = wbelow / (wbelow + wnext);
|
||||
dprintk("wbelow %lf wnext %lf pbelow %lf numleft %d\n",
|
||||
wbelow, wnext, pbelow, numleft);
|
||||
|
||||
straw *= pow((double)1.0 / pbelow, (double)1.0 /
|
||||
(double)numleft);
|
||||
|
||||
lastw = weights[reverse[i-1]];
|
||||
} else if (map->straw_calc_version >= 1) {
|
||||
/* zero weight items get 0 length straws! */
|
||||
if (weights[reverse[i]] == 0) {
|
||||
bucket->straws[reverse[i]] = 0;
|
||||
i++;
|
||||
numleft--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set this item's straw */
|
||||
bucket->straws[reverse[i]] = straw * 0x10000;
|
||||
dprintk("item %d at %d weight %d straw %d (%lf)\n",
|
||||
bucket->h.items[reverse[i]],
|
||||
reverse[i], weights[reverse[i]],
|
||||
bucket->straws[reverse[i]], straw);
|
||||
i++;
|
||||
if (i == size)
|
||||
break;
|
||||
|
||||
/* adjust straw for next guy */
|
||||
wbelow += ((double)weights[reverse[i-1]] - lastw) *
|
||||
numleft;
|
||||
numleft--;
|
||||
wnext = numleft * (weights[reverse[i]] -
|
||||
weights[reverse[i-1]]);
|
||||
pbelow = wbelow / (wbelow + wnext);
|
||||
dprintk("wbelow %lf wnext %lf pbelow %lf numleft %d\n",
|
||||
wbelow, wnext, pbelow, numleft);
|
||||
|
||||
straw *= pow((double)1.0 / pbelow, (double)1.0 /
|
||||
(double)numleft);
|
||||
|
||||
lastw = weights[reverse[i-1]];
|
||||
}
|
||||
}
|
||||
|
||||
free(reverse);
|
||||
@ -482,7 +551,8 @@ int crush_calc_straw(struct crush_bucket_straw *bucket)
|
||||
}
|
||||
|
||||
struct crush_bucket_straw *
|
||||
crush_make_straw_bucket(int hash,
|
||||
crush_make_straw_bucket(struct crush_map *map,
|
||||
int hash,
|
||||
int type,
|
||||
int size,
|
||||
int *items,
|
||||
@ -520,7 +590,7 @@ crush_make_straw_bucket(int hash,
|
||||
bucket->item_weights[i] = weights[i];
|
||||
}
|
||||
|
||||
if (crush_calc_straw(bucket) < 0)
|
||||
if (crush_calc_straw(map, bucket) < 0)
|
||||
goto err;
|
||||
|
||||
return bucket;
|
||||
@ -536,7 +606,8 @@ err:
|
||||
|
||||
|
||||
struct crush_bucket*
|
||||
crush_make_bucket(int alg, int hash, int type, int size,
|
||||
crush_make_bucket(struct crush_map *map,
|
||||
int alg, int hash, int type, int size,
|
||||
int *items,
|
||||
int *weights)
|
||||
{
|
||||
@ -557,7 +628,7 @@ crush_make_bucket(int alg, int hash, int type, int size,
|
||||
return (struct crush_bucket *)crush_make_tree_bucket(hash, type, size, items, weights);
|
||||
|
||||
case CRUSH_BUCKET_STRAW:
|
||||
return (struct crush_bucket *)crush_make_straw_bucket(hash, type, size, items, weights);
|
||||
return (struct crush_bucket *)crush_make_straw_bucket(map, hash, type, size, items, weights);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -696,7 +767,9 @@ int crush_add_tree_bucket_item(struct crush_bucket_tree *bucket, int item, int w
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crush_add_straw_bucket_item(struct crush_bucket_straw *bucket, int item, int weight)
|
||||
int crush_add_straw_bucket_item(struct crush_map *map,
|
||||
struct crush_bucket_straw *bucket,
|
||||
int item, int weight)
|
||||
{
|
||||
int newsize = bucket->h.size + 1;
|
||||
|
||||
@ -729,13 +802,14 @@ int crush_add_straw_bucket_item(struct crush_bucket_straw *bucket, int item, int
|
||||
if (crush_addition_is_unsafe(bucket->h.weight, weight))
|
||||
return -ERANGE;
|
||||
|
||||
bucket->h.weight += weight;
|
||||
bucket->h.size++;
|
||||
bucket->h.weight += weight;
|
||||
bucket->h.size++;
|
||||
|
||||
return crush_calc_straw(bucket);
|
||||
return crush_calc_straw(map, bucket);
|
||||
}
|
||||
|
||||
int crush_bucket_add_item(struct crush_bucket *b, int item, int weight)
|
||||
int crush_bucket_add_item(struct crush_map *map,
|
||||
struct crush_bucket *b, int item, int weight)
|
||||
{
|
||||
/* invalidate perm cache */
|
||||
b->perm_n = 0;
|
||||
@ -748,7 +822,7 @@ int crush_bucket_add_item(struct crush_bucket *b, int item, int weight)
|
||||
case CRUSH_BUCKET_TREE:
|
||||
return crush_add_tree_bucket_item((struct crush_bucket_tree *)b, item, weight);
|
||||
case CRUSH_BUCKET_STRAW:
|
||||
return crush_add_straw_bucket_item((struct crush_bucket_straw *)b, item, weight);
|
||||
return crush_add_straw_bucket_item(map, (struct crush_bucket_straw *)b, item, weight);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -911,7 +985,8 @@ int crush_remove_tree_bucket_item(struct crush_bucket_tree *bucket, int item)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crush_remove_straw_bucket_item(struct crush_bucket_straw *bucket, int item)
|
||||
int crush_remove_straw_bucket_item(struct crush_map *map,
|
||||
struct crush_bucket_straw *bucket, int item)
|
||||
{
|
||||
int newsize = bucket->h.size - 1;
|
||||
unsigned i, j;
|
||||
@ -956,10 +1031,10 @@ int crush_remove_straw_bucket_item(struct crush_bucket_straw *bucket, int item)
|
||||
bucket->straws = _realloc;
|
||||
}
|
||||
|
||||
return crush_calc_straw(bucket);
|
||||
return crush_calc_straw(map, bucket);
|
||||
}
|
||||
|
||||
int crush_bucket_remove_item(struct crush_bucket *b, int item)
|
||||
int crush_bucket_remove_item(struct crush_map *map, struct crush_bucket *b, int item)
|
||||
{
|
||||
/* invalidate perm cache */
|
||||
b->perm_n = 0;
|
||||
@ -972,7 +1047,7 @@ int crush_bucket_remove_item(struct crush_bucket *b, int 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);
|
||||
return crush_remove_straw_bucket_item(map, (struct crush_bucket_straw *)b, item);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -1040,7 +1115,9 @@ int crush_adjust_tree_bucket_item_weight(struct crush_bucket_tree *bucket, int i
|
||||
return diff;
|
||||
}
|
||||
|
||||
int crush_adjust_straw_bucket_item_weight(struct crush_bucket_straw *bucket, int item, int weight)
|
||||
int crush_adjust_straw_bucket_item_weight(struct crush_map *map,
|
||||
struct crush_bucket_straw *bucket,
|
||||
int item, int weight)
|
||||
{
|
||||
unsigned idx;
|
||||
int diff;
|
||||
@ -1056,14 +1133,16 @@ int crush_adjust_straw_bucket_item_weight(struct crush_bucket_straw *bucket, int
|
||||
bucket->item_weights[idx] = weight;
|
||||
bucket->h.weight += diff;
|
||||
|
||||
r = crush_calc_straw(bucket);
|
||||
r = crush_calc_straw(map, bucket);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
int crush_bucket_adjust_item_weight(struct crush_bucket *b, int item, int weight)
|
||||
int crush_bucket_adjust_item_weight(struct crush_map *map,
|
||||
struct crush_bucket *b,
|
||||
int item, int weight)
|
||||
{
|
||||
switch (b->alg) {
|
||||
case CRUSH_BUCKET_UNIFORM:
|
||||
@ -1076,7 +1155,8 @@ int crush_bucket_adjust_item_weight(struct crush_bucket *b, int item, int weight
|
||||
return crush_adjust_tree_bucket_item_weight((struct crush_bucket_tree *)b,
|
||||
item, weight);
|
||||
case CRUSH_BUCKET_STRAW:
|
||||
return crush_adjust_straw_bucket_item_weight((struct crush_bucket_straw *)b,
|
||||
return crush_adjust_straw_bucket_item_weight(map,
|
||||
(struct crush_bucket_straw *)b,
|
||||
item, weight);
|
||||
default:
|
||||
return -1;
|
||||
@ -1178,6 +1258,7 @@ static int crush_reweight_straw_bucket(struct crush_map *crush, struct crush_buc
|
||||
|
||||
bucket->h.weight += bucket->item_weights[i];
|
||||
}
|
||||
crush_calc_straw(crush, bucket);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -16,12 +16,12 @@ extern int crush_get_next_bucket_id(struct crush_map *map);
|
||||
extern int crush_add_bucket(struct crush_map *map,
|
||||
int bucketno,
|
||||
struct crush_bucket *bucket, int *idout);
|
||||
struct crush_bucket *crush_make_bucket(int alg, int hash, int type, int size, int *items, int *weights);
|
||||
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);
|
||||
struct crush_bucket *crush_make_bucket(struct crush_map *map, int alg, int hash, int type, int size, int *items, int *weights);
|
||||
extern int crush_bucket_add_item(struct crush_map *map, struct crush_bucket *bucket, int item, int weight);
|
||||
extern int crush_bucket_adjust_item_weight(struct crush_map *map, 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);
|
||||
extern int crush_bucket_remove_item(struct crush_map *map, struct crush_bucket *bucket, int item);
|
||||
|
||||
struct crush_bucket_uniform *
|
||||
crush_make_uniform_bucket(int hash, int type, int size,
|
||||
@ -36,7 +36,8 @@ crush_make_tree_bucket(int hash, int type, int size,
|
||||
int *items, /* in leaf order */
|
||||
int *weights);
|
||||
struct crush_bucket_straw *
|
||||
crush_make_straw_bucket(int hash, int type, int size,
|
||||
crush_make_straw_bucket(struct crush_map *map,
|
||||
int hash, int type, int size,
|
||||
int *items,
|
||||
int *weights);
|
||||
|
||||
|
@ -191,6 +191,12 @@ struct crush_map {
|
||||
* mappings line up a bit better with previous mappings. */
|
||||
__u8 chooseleaf_vary_r;
|
||||
|
||||
/*
|
||||
* version 0 (original) of straw_calc has various flaws. version 1
|
||||
* fixes a few of them.
|
||||
*/
|
||||
__u8 straw_calc_version;
|
||||
|
||||
__u32 *choose_tries;
|
||||
};
|
||||
|
||||
|
@ -448,6 +448,9 @@ COMMAND("osd crush unlink " \
|
||||
"name=ancestor,type=CephString,req=false,goodchars=[A-Za-z0-9-_.]", \
|
||||
"unlink <name> from crush map (everywhere, or just at <ancestor>)", \
|
||||
"osd", "rw", "cli,rest")
|
||||
COMMAND("osd crush reweight-all",
|
||||
"recalculate the weights for the tree to ensure they sum correctly",
|
||||
"osd", "rw", "cli,rest")
|
||||
COMMAND("osd crush reweight " \
|
||||
"name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \
|
||||
"name=weight,type=CephFloat,range=0.0", \
|
||||
@ -459,8 +462,17 @@ COMMAND("osd crush reweight-subtree " \
|
||||
"change all leaf items beneath <name> to <weight> in crush map", \
|
||||
"osd", "rw", "cli,rest")
|
||||
COMMAND("osd crush tunables " \
|
||||
"name=profile,type=CephChoices,strings=legacy|argonaut|bobtail|firefly|optimal|default", \
|
||||
"name=profile,type=CephChoices,strings=legacy|argonaut|bobtail|firefly|hammer|optimal|default", \
|
||||
"set crush tunables values to <profile>", "osd", "rw", "cli,rest")
|
||||
COMMAND("osd crush set-tunable " \
|
||||
"name=tunable,type=CephChoices,strings=straw_calc_version " \
|
||||
"name=value,type=CephInt",
|
||||
"set crush tunable <tunable> to <value>",
|
||||
"osd", "rw", "cli,rest")
|
||||
COMMAND("osd crush get-tunable " \
|
||||
"name=tunable,type=CephChoices,strings=straw_calc_version",
|
||||
"get crush tunable <tunable>",
|
||||
"osd", "rw", "cli,rest")
|
||||
COMMAND("osd crush show-tunables", \
|
||||
"show current crush tunables", "osd", "r", "cli,rest")
|
||||
COMMAND("osd crush rule create-simple " \
|
||||
|
@ -2692,6 +2692,32 @@ bool OSDMonitor::preprocess_command(MMonCommand *m)
|
||||
f->flush(rdata);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (prefix == "osd crush get-tunable") {
|
||||
string tunable;
|
||||
cmd_getval(g_ceph_context, cmdmap, "tunable", tunable);
|
||||
int value;
|
||||
cmd_getval(g_ceph_context, cmdmap, "value", value);
|
||||
ostringstream rss;
|
||||
if (f)
|
||||
f->open_object_section("tunable");
|
||||
if (tunable == "straw_calc_version") {
|
||||
if (f)
|
||||
f->dump_int(tunable.c_str(), osdmap.crush->get_straw_calc_version());
|
||||
else
|
||||
rss << osdmap.crush->get_straw_calc_version() << "\n";
|
||||
} else {
|
||||
r = -EINVAL;
|
||||
goto reply;
|
||||
}
|
||||
if (f) {
|
||||
f->close_section();
|
||||
f->flush(rdata);
|
||||
} else {
|
||||
rdata.append(rss.str());
|
||||
}
|
||||
r = 0;
|
||||
|
||||
} else if (prefix == "osd pool get") {
|
||||
string poolstr;
|
||||
cmd_getval(g_ceph_context, cmdmap, "pool", poolstr);
|
||||
@ -4482,6 +4508,19 @@ bool OSDMonitor::prepare_command_impl(MMonCommand *m,
|
||||
}
|
||||
} while (false);
|
||||
|
||||
} else if (prefix == "osd crush reweight-all") {
|
||||
// osd crush reweight <name> <weight>
|
||||
CrushWrapper newcrush;
|
||||
_get_pending_crush(newcrush);
|
||||
|
||||
newcrush.reweight(g_ceph_context);
|
||||
pending_inc.crush.clear();
|
||||
newcrush.encode(pending_inc.crush);
|
||||
ss << "reweighted crush hierarchy";
|
||||
getline(ss, rs);
|
||||
wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs,
|
||||
get_last_committed() + 1));
|
||||
return true;
|
||||
} else if (prefix == "osd crush reweight") {
|
||||
// osd crush reweight <name> <weight>
|
||||
CrushWrapper newcrush;
|
||||
@ -4571,6 +4610,8 @@ bool OSDMonitor::prepare_command_impl(MMonCommand *m,
|
||||
newcrush.set_tunables_bobtail();
|
||||
} else if (profile == "firefly") {
|
||||
newcrush.set_tunables_firefly();
|
||||
} else if (profile == "hammer") {
|
||||
newcrush.set_tunables_hammer();
|
||||
} else if (profile == "optimal") {
|
||||
newcrush.set_tunables_optimal();
|
||||
} else if (profile == "default") {
|
||||
@ -4593,6 +4634,46 @@ bool OSDMonitor::prepare_command_impl(MMonCommand *m,
|
||||
wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs,
|
||||
get_last_committed() + 1));
|
||||
return true;
|
||||
} else if (prefix == "osd crush set-tunable") {
|
||||
CrushWrapper newcrush;
|
||||
_get_pending_crush(newcrush);
|
||||
|
||||
err = 0;
|
||||
string tunable;
|
||||
cmd_getval(g_ceph_context, cmdmap, "tunable", tunable);
|
||||
|
||||
int64_t value = -1;
|
||||
if (!cmd_getval(g_ceph_context, cmdmap, "value", value)) {
|
||||
err = -EINVAL;
|
||||
ss << "failed to parse integer value " << cmd_vartype_stringify(cmdmap["value"]);
|
||||
goto reply;
|
||||
}
|
||||
|
||||
if (tunable == "straw_calc_version") {
|
||||
if (value < 0 || value > 2) {
|
||||
ss << "value must be 0 or 1; got " << value;
|
||||
err = -EINVAL;
|
||||
goto reply;
|
||||
}
|
||||
newcrush.set_straw_calc_version(value);
|
||||
} else {
|
||||
ss << "unrecognized tunable '" << tunable << "'";
|
||||
err = -EINVAL;
|
||||
goto reply;
|
||||
}
|
||||
|
||||
if (!validate_crush_against_features(&newcrush, ss)) {
|
||||
err = -EINVAL;
|
||||
goto reply;
|
||||
}
|
||||
|
||||
pending_inc.crush.clear();
|
||||
newcrush.encode(pending_inc.crush);
|
||||
ss << "adjusted tunable " << tunable << " to " << value;
|
||||
getline(ss, rs);
|
||||
wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs,
|
||||
get_last_committed() + 1));
|
||||
return true;
|
||||
|
||||
} else if (prefix == "osd crush rule create-simple") {
|
||||
string name, root, type, mode;
|
||||
|
@ -52,7 +52,7 @@
|
||||
#
|
||||
# crush rulesets are generated using the OSDMap helpers
|
||||
#
|
||||
$ CEPH_ARGS="--debug-crush 0" crushtool --outfn "$map" --build --num_osds 1 root straw 0
|
||||
$ CEPH_ARGS="--debug-crush 0" crushtool --outfn "$map" --set-straw-calc-version 0 --build --num_osds 1 root straw 0
|
||||
$ crushtool -o "$map.txt" -d "$map"
|
||||
$ cat "$map.txt"
|
||||
# begin crush map
|
||||
|
@ -35,6 +35,7 @@
|
||||
--show utilization-all
|
||||
include zero weight items
|
||||
--show-statistics show chi squared statistics
|
||||
--show-mappings show mappings
|
||||
--show-bad-mappings show bad mappings
|
||||
--show-choose-tries show choose tries histogram
|
||||
--set-choose-local-tries N
|
||||
|
@ -1,5 +1,6 @@
|
||||
$ crushtool -c "$TESTDIR/set-choose.crushmap.txt" -o set-choose.crushmap
|
||||
$ crushtool -i set-choose.crushmap --test --show-statistics
|
||||
$ crushtool -i set-choose.crushmap --test --show-mappings --show-statistics --set-straw-calc-version 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 0 (choose), x = 0..1023, numrep = 2..3
|
||||
CRUSH rule 0 x 0 [0,3]
|
||||
CRUSH rule 0 x 1 [0,8]
|
||||
@ -12306,7 +12307,8 @@
|
||||
CRUSH rule 5 x 1022 [1,6,4]
|
||||
CRUSH rule 5 x 1023 [3,2,8]
|
||||
rule 5 (chooseleaf-set) num_rep 3 result size == 3:\t1024/1024 (esc)
|
||||
$ crushtool -i set-choose.crushmap --test --show-statistics --weight 0 0 --weight 1 0 --weight 3 0 --weight 4 0
|
||||
$ crushtool -i set-choose.crushmap --test --show-mappings --show-statistics --weight 0 0 --weight 1 0 --weight 3 0 --weight 4 0 --set-straw-calc-version 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 0 (choose), x = 0..1023, numrep = 2..3
|
||||
CRUSH rule 0 x 0 [2,5]
|
||||
CRUSH rule 0 x 1 [2,8]
|
||||
@ -24618,7 +24620,8 @@
|
||||
CRUSH rule 5 x 1022 [2,6,5]
|
||||
CRUSH rule 5 x 1023 [5,2,8]
|
||||
rule 5 (chooseleaf-set) num_rep 3 result size == 3:\t1024/1024 (esc)
|
||||
$ crushtool -i set-choose.crushmap --test --show-statistics --weight 0 0 --weight 3 0 --weight 4 .5 --weight 5 0 --weight 6 .1 --weight 7 0
|
||||
$ crushtool -i set-choose.crushmap --test --show-mappings --show-statistics --weight 0 0 --weight 3 0 --weight 4 .5 --weight 5 0 --weight 6 .1 --weight 7 0 --set-straw-calc-version 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 0 (choose), x = 0..1023, numrep = 2..3
|
||||
CRUSH rule 0 x 0 [2,4]
|
||||
CRUSH rule 0 x 1 [2,8]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-a.crushmap" --test --show-statistics --rule 0 --set-choose-local-tries 0 --set-choose-local-fallback-tries 0 --set-choose-total-tries 50 --set-chooseleaf-descend-once 1
|
||||
$ crushtool -i "$TESTDIR/test-map-a.crushmap" --test --show-mappings --show-statistics --rule 0 --set-choose-local-tries 0 --set-choose-local-fallback-tries 0 --set-choose-total-tries 50 --set-chooseleaf-descend-once 1
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 0 (data), x = 0..1023, numrep = 1..10
|
||||
CRUSH rule 0 x 0 [36]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-statistics --rule 0 --set-choose-local-tries 0 --set-choose-local-fallback-tries 0 --set-choose-total-tries 50 --set-chooseleaf-descend-once 1 --set-chooseleaf-vary-r 1 --weight 12 0 --weight 20 0 --weight 30 0
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-mappings --show-statistics --rule 0 --set-choose-local-tries 0 --set-choose-local-fallback-tries 0 --set-choose-total-tries 50 --set-chooseleaf-descend-once 1 --set-chooseleaf-vary-r 1 --weight 12 0 --weight 20 0 --weight 30 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 0 (data), x = 0..1023, numrep = 1..10
|
||||
CRUSH rule 0 x 0 [101]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-indep.crushmap" --test --show-statistics --rule 1 --set-choose-local-tries 0 --set-choose-local-fallback-tries 0 --set-choose-total-tries 50 --set-chooseleaf-descend-once 2
|
||||
$ crushtool -i "$TESTDIR/test-map-indep.crushmap" --test --show-mappings --show-statistics --rule 1 --set-choose-local-tries 0 --set-choose-local-fallback-tries 0 --set-choose-total-tries 50 --set-chooseleaf-descend-once 2
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 1 (metadata), x = 0..1023, numrep = 1..10
|
||||
CRUSH rule 1 x 0 [36]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-a.crushmap" --test --show-statistics --rule 0
|
||||
$ crushtool -i "$TESTDIR/test-map-a.crushmap" --test --show-mappings --show-statistics --rule 0
|
||||
rule 0 (data), x = 0..1023, numrep = 1..10
|
||||
CRUSH rule 0 x 0 [36]
|
||||
CRUSH rule 0 x 1 [876]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-tries-vs-retries.crushmap" --test --show-statistics --weight 0 0 --weight 8 0
|
||||
$ crushtool -i "$TESTDIR/test-map-tries-vs-retries.crushmap" --test --show-mappings --show-statistics --weight 0 0 --weight 8 0
|
||||
rule 0 (replicated_ruleset), x = 0..1023, numrep = 1..10
|
||||
CRUSH rule 0 x 0 [7]
|
||||
CRUSH rule 0 x 1 [10]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-statistics --rule 3 --set-chooseleaf-vary-r 0 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-mappings --show-statistics --rule 3 --set-chooseleaf-vary-r 0 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 3 (delltestrule), x = 0..1023, numrep = 2..4
|
||||
CRUSH rule 3 x 0 [94,85]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-statistics --rule 3 --set-chooseleaf-vary-r 1 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-mappings --show-statistics --rule 3 --set-chooseleaf-vary-r 1 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 3 (delltestrule), x = 0..1023, numrep = 2..4
|
||||
CRUSH rule 3 x 0 [94,6]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-statistics --rule 3 --set-chooseleaf-vary-r 2 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-mappings --show-statistics --rule 3 --set-chooseleaf-vary-r 2 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 3 (delltestrule), x = 0..1023, numrep = 2..4
|
||||
CRUSH rule 3 x 0 [94,45]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-statistics --rule 3 --set-chooseleaf-vary-r 3 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-mappings --show-statistics --rule 3 --set-chooseleaf-vary-r 3 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 3 (delltestrule), x = 0..1023, numrep = 2..4
|
||||
CRUSH rule 3 x 0 [94,85]
|
||||
|
@ -1,4 +1,4 @@
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-statistics --rule 3 --set-chooseleaf-vary-r 4 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
$ crushtool -i "$TESTDIR/test-map-vary-r.crushmap" --test --show-mappings --show-statistics --rule 3 --set-chooseleaf-vary-r 4 --weight 0 0 --weight 4 0 --weight 9 0
|
||||
crushtool successfully built or modified map. Use '-o <file>' to write it out.
|
||||
rule 3 (delltestrule), x = 0..1023, numrep = 2..4
|
||||
CRUSH rule 3 x 0 [94,85]
|
||||
|
@ -11,6 +11,7 @@
|
||||
tunable choose_local_fallback_tries 0
|
||||
tunable choose_total_tries 50
|
||||
tunable chooseleaf_descend_once 1
|
||||
tunable straw_calc_version 1
|
||||
|
||||
# devices
|
||||
device 0 osd.0
|
||||
|
@ -10,6 +10,7 @@
|
||||
tunable choose_local_fallback_tries 0
|
||||
tunable choose_total_tries 50
|
||||
tunable chooseleaf_descend_once 1
|
||||
tunable straw_calc_version 1
|
||||
|
||||
# devices
|
||||
device 0 device0
|
||||
|
@ -6,5 +6,5 @@
|
||||
osdmaptool: exported crush map to oc
|
||||
$ osdmaptool --import-crush oc myosdmap
|
||||
osdmaptool: osdmap file 'myosdmap'
|
||||
osdmaptool: imported 486 byte crush map from oc
|
||||
osdmaptool: imported 487 byte crush map from oc
|
||||
osdmaptool: writing epoch 3 to myosdmap
|
||||
|
@ -4,6 +4,7 @@
|
||||
--export-crush <file> write osdmap's crush map to <file>
|
||||
--import-crush <file> replace osdmap's crush map with <file>
|
||||
--test-map-pgs [--pool <poolid>] map all pgs
|
||||
--test-map-pgs-dump [--pool <poolid>] map all pgs
|
||||
--mark-up-in mark osds up and in (but do not persist)
|
||||
--clear-temp clear pg_temp and primary_temp
|
||||
--test-random do random placements
|
||||
|
@ -4,6 +4,7 @@
|
||||
--export-crush <file> write osdmap's crush map to <file>
|
||||
--import-crush <file> replace osdmap's crush map with <file>
|
||||
--test-map-pgs [--pool <poolid>] map all pgs
|
||||
--test-map-pgs-dump [--pool <poolid>] map all pgs
|
||||
--mark-up-in mark osds up and in (but do not persist)
|
||||
--clear-temp clear pg_temp and primary_temp
|
||||
--test-random do random placements
|
||||
|
@ -68,6 +68,166 @@ TEST(CrushWrapper, get_immediate_parent) {
|
||||
delete c;
|
||||
}
|
||||
|
||||
TEST(CrushWrapper, straw_zero) {
|
||||
// zero weight items should have no effect on placement.
|
||||
|
||||
CrushWrapper *c = new CrushWrapper;
|
||||
const int ROOT_TYPE = 1;
|
||||
c->set_type_name(ROOT_TYPE, "root");
|
||||
const int OSD_TYPE = 0;
|
||||
c->set_type_name(OSD_TYPE, "osd");
|
||||
|
||||
int n = 5;
|
||||
int items[n], weights[n];
|
||||
for (int i=0; i <n; ++i) {
|
||||
items[i] = i;
|
||||
weights[i] = 0x10000 * (n-i-1);
|
||||
}
|
||||
|
||||
c->set_max_devices(n);
|
||||
|
||||
string root_name0("root0");
|
||||
int root0;
|
||||
EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1,
|
||||
ROOT_TYPE, n, items, weights, &root0));
|
||||
EXPECT_EQ(0, c->set_item_name(root0, root_name0));
|
||||
|
||||
string name0("rule0");
|
||||
int ruleset0 = c->add_simple_ruleset(name0, root_name0, "osd",
|
||||
"firstn", pg_pool_t::TYPE_REPLICATED);
|
||||
EXPECT_EQ(0, ruleset0);
|
||||
|
||||
string root_name1("root1");
|
||||
int root1;
|
||||
EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1,
|
||||
ROOT_TYPE, n-1, items, weights, &root1));
|
||||
EXPECT_EQ(0, c->set_item_name(root1, root_name1));
|
||||
|
||||
string name1("rule1");
|
||||
int ruleset1 = c->add_simple_ruleset(name1, root_name1, "osd",
|
||||
"firstn", pg_pool_t::TYPE_REPLICATED);
|
||||
EXPECT_EQ(1, ruleset1);
|
||||
|
||||
vector<unsigned> reweight(n, 0x10000);
|
||||
for (int i=0; i<10000; ++i) {
|
||||
vector<int> out0, out1;
|
||||
c->do_rule(ruleset0, i, out0, 1, reweight);
|
||||
ASSERT_EQ(1u, out0.size());
|
||||
c->do_rule(ruleset1, i, out1, 1, reweight);
|
||||
ASSERT_EQ(1u, out1.size());
|
||||
ASSERT_EQ(out0[0], out1[0]);
|
||||
//cout << i << "\t" << out0 << "\t" << out1 << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CrushWrapper, straw_same) {
|
||||
// items with the same weight should map about the same as items
|
||||
// with very similar weights.
|
||||
//
|
||||
// give the 0 vector a paired stair pattern, with dup weights. note
|
||||
// that the original straw flaw does not appear when there are 2 of
|
||||
// the initial weight, but it does when there is just 1.
|
||||
//
|
||||
// give the 1 vector a similar stair pattern, but make the same
|
||||
// steps weights slightly different (no dups). this works.
|
||||
//
|
||||
// compare the result and verify that the resulting mapping is
|
||||
// almost identical.
|
||||
|
||||
CrushWrapper *c = new CrushWrapper;
|
||||
const int ROOT_TYPE = 1;
|
||||
c->set_type_name(ROOT_TYPE, "root");
|
||||
const int OSD_TYPE = 0;
|
||||
c->set_type_name(OSD_TYPE, "osd");
|
||||
|
||||
int n = 10;
|
||||
int items[n], weights[n];
|
||||
for (int i=0; i <n; ++i) {
|
||||
items[i] = i;
|
||||
weights[i] = 0x10000 * ((i+1)/2 + 1);
|
||||
}
|
||||
|
||||
c->set_max_devices(n);
|
||||
|
||||
string root_name0("root0");
|
||||
int root0;
|
||||
EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1,
|
||||
ROOT_TYPE, n, items, weights, &root0));
|
||||
EXPECT_EQ(0, c->set_item_name(root0, root_name0));
|
||||
|
||||
string name0("rule0");
|
||||
int ruleset0 = c->add_simple_ruleset(name0, root_name0, "osd",
|
||||
"firstn", pg_pool_t::TYPE_REPLICATED);
|
||||
EXPECT_EQ(0, ruleset0);
|
||||
|
||||
for (int i=0; i <n; ++i) {
|
||||
items[i] = i;
|
||||
weights[i] = 0x10000 * ((i+1)/2 + 1) + (i%2)*100;
|
||||
}
|
||||
|
||||
string root_name1("root1");
|
||||
int root1;
|
||||
EXPECT_EQ(0, c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1,
|
||||
ROOT_TYPE, n, items, weights, &root1));
|
||||
EXPECT_EQ(0, c->set_item_name(root1, root_name1));
|
||||
|
||||
string name1("rule1");
|
||||
int ruleset1 = c->add_simple_ruleset(name1, root_name1, "osd",
|
||||
"firstn", pg_pool_t::TYPE_REPLICATED);
|
||||
EXPECT_EQ(1, ruleset1);
|
||||
|
||||
if (0) {
|
||||
crush_bucket_straw *sb0 = reinterpret_cast<crush_bucket_straw*>(c->get_crush_map()->buckets[-1-root0]);
|
||||
crush_bucket_straw *sb1 = reinterpret_cast<crush_bucket_straw*>(c->get_crush_map()->buckets[-1-root1]);
|
||||
|
||||
for (int i=0; i<n; ++i) {
|
||||
cout << i
|
||||
<< "\t" << sb0->item_weights[i]
|
||||
<< "\t" << sb1->item_weights[i]
|
||||
<< "\t"
|
||||
<< "\t" << sb0->straws[i]
|
||||
<< "\t" << sb1->straws[i]
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (0) {
|
||||
JSONFormatter jf(true);
|
||||
jf.open_object_section("crush");
|
||||
c->dump(&jf);
|
||||
jf.close_section();
|
||||
jf.flush(cout);
|
||||
}
|
||||
|
||||
vector<int> sum0(n, 0), sum1(n, 0);
|
||||
vector<unsigned> reweight(n, 0x10000);
|
||||
int different = 0;
|
||||
int max = 100000;
|
||||
for (int i=0; i<max; ++i) {
|
||||
vector<int> out0, out1;
|
||||
c->do_rule(ruleset0, i, out0, 1, reweight);
|
||||
ASSERT_EQ(1u, out0.size());
|
||||
c->do_rule(ruleset1, i, out1, 1, reweight);
|
||||
ASSERT_EQ(1u, out1.size());
|
||||
sum0[out0[0]]++;
|
||||
sum1[out1[0]]++;
|
||||
if (out0[0] != out1[0])
|
||||
different++;
|
||||
}
|
||||
for (int i=0; i<n; ++i) {
|
||||
cout << i
|
||||
<< "\t" << ((double)weights[i] / (double)weights[0])
|
||||
<< "\t" << sum0[i] << "\t" << ((double)sum0[i]/(double)sum0[0])
|
||||
<< "\t" << sum1[i] << "\t" << ((double)sum1[i]/(double)sum1[0])
|
||||
<< std::endl;
|
||||
}
|
||||
double ratio = ((double)different / (double)max);
|
||||
cout << different << " of " << max << " = "
|
||||
<< ratio
|
||||
<< " different" << std::endl;
|
||||
ASSERT_LT(ratio, .001);
|
||||
}
|
||||
|
||||
TEST(CrushWrapper, move_bucket) {
|
||||
CrushWrapper *c = new CrushWrapper;
|
||||
|
||||
|
@ -120,6 +120,7 @@ void usage()
|
||||
cout << " --show utilization-all\n";
|
||||
cout << " include zero weight items\n";
|
||||
cout << " --show-statistics show chi squared statistics\n";
|
||||
cout << " --show-mappings show mappings\n";
|
||||
cout << " --show-bad-mappings show bad mappings\n";
|
||||
cout << " --show-choose-tries show choose tries histogram\n";
|
||||
cout << " --set-choose-local-tries N\n";
|
||||
@ -193,6 +194,7 @@ int main(int argc, const char **argv)
|
||||
int choose_total_tries = -1;
|
||||
int chooseleaf_descend_once = -1;
|
||||
int chooseleaf_vary_r = -1;
|
||||
int straw_calc_version = -1;
|
||||
|
||||
CrushWrapper crush;
|
||||
|
||||
@ -236,6 +238,9 @@ int main(int argc, const char **argv)
|
||||
} else if (ceph_argparse_flag(args, i, "--show_statistics", (char*)NULL)) {
|
||||
display = true;
|
||||
tester.set_output_statistics(true);
|
||||
} else if (ceph_argparse_flag(args, i, "--show_mappings", (char*)NULL)) {
|
||||
display = true;
|
||||
tester.set_output_mappings(true);
|
||||
} else if (ceph_argparse_flag(args, i, "--show_bad_mappings", (char*)NULL)) {
|
||||
display = true;
|
||||
tester.set_output_bad_mappings(true);
|
||||
@ -267,6 +272,9 @@ int main(int argc, const char **argv)
|
||||
} else if (ceph_argparse_withint(args, i, &chooseleaf_vary_r, &err,
|
||||
"--set_chooseleaf_vary_r", (char*)NULL)) {
|
||||
adjust = true;
|
||||
} else if (ceph_argparse_withint(args, i, &straw_calc_version, &err,
|
||||
"--set_straw_calc_version", (char*)NULL)) {
|
||||
adjust = true;
|
||||
} else if (ceph_argparse_flag(args, i, "--reweight", (char*)NULL)) {
|
||||
reweight = true;
|
||||
} else if (ceph_argparse_withint(args, i, &add_item, &err, "--add_item", (char*)NULL)) {
|
||||
@ -723,6 +731,10 @@ int main(int argc, const char **argv)
|
||||
crush.set_chooseleaf_vary_r(chooseleaf_vary_r);
|
||||
modified = true;
|
||||
}
|
||||
if (straw_calc_version >= 0) {
|
||||
crush.set_straw_calc_version(straw_calc_version);
|
||||
modified = true;
|
||||
}
|
||||
if (modified) {
|
||||
crush.finalize();
|
||||
|
||||
|
@ -29,6 +29,7 @@ void usage()
|
||||
cout << " --export-crush <file> write osdmap's crush map to <file>" << std::endl;
|
||||
cout << " --import-crush <file> replace osdmap's crush map with <file>" << std::endl;
|
||||
cout << " --test-map-pgs [--pool <poolid>] map all pgs" << std::endl;
|
||||
cout << " --test-map-pgs-dump [--pool <poolid>] map all pgs" << std::endl;
|
||||
cout << " --mark-up-in mark osds up and in (but do not persist)" << std::endl;
|
||||
cout << " --clear-temp clear pg_temp and primary_temp" << std::endl;
|
||||
cout << " --test-random do random placements" << std::endl;
|
||||
@ -69,6 +70,7 @@ int main(int argc, const char **argv)
|
||||
bool mark_up_in = false;
|
||||
bool clear_temp = false;
|
||||
bool test_map_pgs = false;
|
||||
bool test_map_pgs_dump = false;
|
||||
bool test_random = false;
|
||||
|
||||
std::string val;
|
||||
@ -98,6 +100,8 @@ int main(int argc, const char **argv)
|
||||
clear_temp = true;
|
||||
} else if (ceph_argparse_flag(args, i, "--test-map-pgs", (char*)NULL)) {
|
||||
test_map_pgs = true;
|
||||
} else if (ceph_argparse_flag(args, i, "--test-map-pgs-dump", (char*)NULL)) {
|
||||
test_map_pgs_dump = true;
|
||||
} else if (ceph_argparse_flag(args, i, "--test-random", (char*)NULL)) {
|
||||
test_random = true;
|
||||
} else if (ceph_argparse_flag(args, i, "--clobber", (char*)NULL)) {
|
||||
@ -307,7 +311,7 @@ int main(int argc, const char **argv)
|
||||
<< ") acting (" << acting << ", p" << acting_primary << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
if (test_map_pgs) {
|
||||
if (test_map_pgs || test_map_pgs_dump) {
|
||||
if (pool != -1 && !osdmap.have_pg_pool(pool)) {
|
||||
cerr << "There is no pool " << pool << std::endl;
|
||||
exit(1);
|
||||
@ -342,6 +346,9 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
size[osds.size()]++;
|
||||
|
||||
if (test_map_pgs_dump)
|
||||
cout << pgid << "\t" << osds << "\t" << primary << std::endl;
|
||||
|
||||
for (unsigned i=0; i<osds.size(); i++) {
|
||||
//cout << " rep " << i << " on " << osds[i] << std::endl;
|
||||
count[osds[i]]++;
|
||||
@ -446,7 +453,7 @@ int main(int argc, const char **argv)
|
||||
if (!print && !print_json && !tree && !modified &&
|
||||
export_crush.empty() && import_crush.empty() &&
|
||||
test_map_pg.empty() && test_map_object.empty() &&
|
||||
!test_map_pgs) {
|
||||
!test_map_pgs && !test_map_pgs_dump) {
|
||||
cerr << me << ": no action specified?" << std::endl;
|
||||
usage();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user