#. ``--reclassify-root <root-name> <device-class>``
- This will take everything in the hierarchy beneath root-name, mark
- all devices with the specified class, and adjust any rules that
- reference that root via a ``take <root-name>`` to instead ``take
- <root-name> class <device-class>``. It renumbers the buckets in
- such a way that the old IDs are instead used for the specified
- class's "shadow tree" so that no data movement takes place.
+ This will take everything in the hierarchy beneath root-name and
+ adjust any rules that reference that root via a ``take
+ <root-name>`` to instead ``take <root-name> class <device-class>``.
+ It renumbers the buckets in such a way that the old IDs are instead
+ used for the specified class's "shadow tree" so that no data
+ movement takes place.
For example, imagine you have an existing rule like::
step emit
}
+#. ``--set-subtree-class <bucket-name> <device-class>``
+
+ This will mark every device in the subtree rooted at *bucket-name*
+ with the specified device class.
+
+ This is normally used in conjunction with the ``--reclassify-root``
+ option to ensure that all devices in that root are labeled with the
+ correct class. In some situations, however, some of those devices
+ (correctly) have a different class and we do not want to relabel
+ them. In such cases, one can exclude the ``--set-subtree-class``
+ option. This means that the remapping process will not be perfect,
+ since the previous rule distributed across devices of multiple
+ classes but the adjusted rules will only map to devices of the
+ specified *device-class*, but that often is an accepted level of
+ data movement when the nubmer of outlier devices is small.
+
#. ``--reclassify-bucket <match-pattern> <device-class> <default-parent>``
This will allow you to merge a parallel type-specific hiearchy with the normal hierarchy. For example, many users have maps like::
$ ceph osd getcrushmap -o original
$ crushtool -i original --reclassify \
+ --set-subtree-class default hdd \
--reclassify-root default hdd \
--reclassify-bucket %-ssd ssd default \
--reclassify-bucket ssd ssd default \
ceph_abort_msg("no available class id");
}
+int CrushWrapper::set_subtree_class(
+ const string& subtree,
+ const string& new_class)
+{
+ if (!name_exists(subtree)) {
+ return -ENOENT;
+ }
+
+ int new_class_id = -1;
+ if (class_exists(new_class)) {
+ new_class_id = get_class_id(new_class);
+ } else {
+ for (new_class_id = 1; class_name.count(new_class_id); ++new_class_id) ;
+ class_name[new_class_id] = new_class;
+ class_rname[new_class] = new_class_id;
+ }
+
+ int id = get_item_id(subtree);
+ list<int> q = { id };
+ while (!q.empty()) {
+ int id = q.front();
+ q.pop_front();
+ crush_bucket *b = get_bucket(id);
+ if (IS_ERR(b)) {
+ return PTR_ERR(b);
+ }
+ for (unsigned i = 0; i < b->size; ++i) {
+ int item = b->items[i];
+ if (item >= 0) {
+ class_map[item] = new_class_id;
+ } else {
+ q.push_back(item);
+ }
+ }
+ }
+ return 0;
+}
+
int CrushWrapper::reclassify(
CephContext *cct,
ostream& out,
if (bucket->items[j] < 0) {
q.push_front(bucket->items[j]);
} else {
- // reclassify device
- class_map[bucket->items[j]] = new_class_id;
+ // we don't reclassify the device here; if the users wants that,
+ // they can pass --set-subtree-class separately.
}
}
}
const map<string,pair<string,string>>& classify_bucket
);
+ int set_subtree_class(const string& name, const string& class_name);
+
void start_choose_profile() {
free(crush->choose_tries);
/*
by adding classes
--reclassify-bucket <bucket-match> <class> <default-parent>
--reclassify-root <bucket-name> <class>
+ --set-subtree-class <bucket-name> <class>
+ set class for all items beneath bucket-name
--compare <otherfile> compare two maps using --test parameters
Options for the output stage
- $ crushtool -i $TESTDIR/crush-classes/a --reclassify --reclassify-bucket %-ssd ssd default --reclassify-bucket ssd ssd default --reclassify-root default hdd -o foo
+ $ crushtool -i $TESTDIR/crush-classes/a --set-subtree-class default hdd --reclassify --reclassify-bucket %-ssd ssd default --reclassify-bucket ssd ssd default --reclassify-root default hdd -o foo
classify_root default (-1) as hdd
- created new class hdd as 1
+ new class hdd exists as 1
renumbering bucket -1 -> -5
renumbering bucket -4 -> -6
renumbering bucket -3 -> -7
rule 1 had 0/10240 mismatched mappings (0)
maps appear equivalent
- $ crushtool -i $TESTDIR/crush-classes/d --reclassify --reclassify-bucket %-ssd ssd default --reclassify-bucket ssd ssd default --reclassify-root default hdd -o foo
+ $ crushtool -i $TESTDIR/crush-classes/d --set-subtree-class default hdd --reclassify --reclassify-bucket %-ssd ssd default --reclassify-bucket ssd ssd default --reclassify-root default hdd -o foo
classify_root default (-1) as hdd
- created new class hdd as 1
+ new class hdd exists as 1
renumbering bucket -1 -> -13
renumbering bucket -6 -> -14
renumbering bucket -5 -> -15
warning: maps are NOT equivalent
[1]
- $ crushtool -i $TESTDIR/crush-classes/beesly --reclassify --reclassify-root 0513-R-0050 hdd --reclassify-root 0513-R-0060 hdd -o foo
+ $ crushtool -i $TESTDIR/crush-classes/beesly --set-subtree-class 0513-R-0060 hdd --set-subtree-class 0513-R-0050 hdd --reclassify --reclassify-root 0513-R-0050 hdd --reclassify-root 0513-R-0060 hdd -o foo
classify_root 0513-R-0050 (-2) as hdd
new class hdd exists as 0
renumbering bucket -2 -> -131
a mess!
$ crushtool -i $TESTDIR/crush-classes/b --compare foo
- rule 0 had 3060/3072 mismatched mappings (0.996094)
+ rule 0 had 3068/3072 mismatched mappings (0.998698)
rule 1 had 4096/4096 mismatched mappings (1)
warning: maps are NOT equivalent
[1]
+
+ $ crushtool -i $TESTDIR/crush-classes/f --reclassify --reclassify-root default hdd -o foo
+ classify_root default (-1) as hdd
+ new class hdd exists as 0
+ renumbering bucket -1 -> -178
+ renumbering bucket -4 -> -179
+ renumbering bucket -25 -> -180
+ renumbering bucket -16 -> -181
+ renumbering bucket -21 -> -182
+ renumbering bucket -19 -> -183
+ renumbering bucket -15 -> -184
+ renumbering bucket -7 -> -185
+ renumbering bucket -47 -> -186
+ renumbering bucket -18 -> -187
+ renumbering bucket -8 -> -188
+ renumbering bucket -6 -> -189
+ renumbering bucket -12 -> -190
+ renumbering bucket -23 -> -191
+ renumbering bucket -22 -> -192
+ renumbering bucket -20 -> -193
+ renumbering bucket -11 -> -194
+ renumbering bucket -10 -> -195
+ renumbering bucket -17 -> -196
+ renumbering bucket -13 -> -197
+ renumbering bucket -9 -> -198
+ renumbering bucket -3 -> -199
+ renumbering bucket -14 -> -200
+ renumbering bucket -5 -> -201
+ renumbering bucket -2 -> -202
+
+We expect some mismatches below because there are some ssd-labeled nodes under
+default that we aren't changing the class on.
+
+ $ crushtool -i $TESTDIR/crush-classes/f --compare foo
+ rule 0 had 627/10240 mismatched mappings (0.0612305)
+ rule 1 had 422/6144 mismatched mappings (0.0686849)
+ warning: maps are NOT equivalent
+ [1]
cout << " by adding classes\n";
cout << " --reclassify-bucket <bucket-match> <class> <default-parent>\n";
cout << " --reclassify-root <bucket-name> <class>\n";
+ cout << " --set-subtree-class <bucket-name> <class>\n";
+ cout << " set class for all items beneath bucket-name\n";
cout << " --compare <otherfile> compare two maps using --test parameters\n";
cout << "\n";
cout << "Options for the output stage\n";
bool reclassify = false;
map<string,pair<string,string>> reclassify_bucket; // %suffix or prefix% -> class, default_root
map<string,string> reclassify_root; // bucket -> class
+ map<string,string> set_subtree_class; // bucket -> class
string compare;
}
reclassify_root[val] = *i;
i = args.erase(i);
+ } else if (ceph_argparse_witharg(args, i, &val, "--set-subtree-class",
+ (char*)NULL)) {
+ if (i == args.end()) {
+ cerr << "expecting additional argument" << std::endl;
+ return EXIT_FAILURE;
+ }
+ set_subtree_class[val] = *i;
+ i = args.erase(i);
} else if (ceph_argparse_flag(args, i, "--tree", (char*)NULL)) {
tree = true;
} else if (ceph_argparse_witharg(args, i, &val, "-f", "--format", (char*)NULL)) {
modified = true;
}
+ for (auto& i : set_subtree_class) {
+ crush.set_subtree_class(i.first, i.second);
+ modified = true;
+ }
if (reclassify) {
int r = crush.reclassify(
g_ceph_context,