]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crush/CrushWrapper: make a compat/default choose_args
authorSage Weil <sage@redhat.com>
Fri, 14 Jul 2017 17:12:02 +0000 (13:12 -0400)
committerSage Weil <sage@redhat.com>
Fri, 21 Jul 2017 17:50:50 +0000 (13:50 -0400)
We can make a backward-compatible crush map for legacy clients only if we
have a single global choose_args for the whole map.  Add a special
slot to store that of -1.  (Normally the index is the pool id, so -1 is
unused by ceph.)

Signed-off-by: Sage Weil <sage@redhat.com>
src/crush/CrushWrapper.cc
src/crush/CrushWrapper.h
src/test/crush/CrushWrapper.cc

index 857d2d13dcf89a37fa16d400428b7eddd16308e3..91eddd6cdf0aee354789b47f7db4827ff2b961fd 100644 (file)
@@ -187,6 +187,8 @@ bool CrushWrapper::has_incompat_choose_args() const
     return false;
   if (choose_args.size() > 1)
     return true;
+  if (choose_args.begin()->first != DEFAULT_CHOOSE_ARGS)
+    return true;
   crush_choose_arg_map arg_map = choose_args.begin()->second;
   for (__u32 i = 0; i < arg_map.size; i++) {
     crush_choose_arg *arg = &arg_map.args[i];
@@ -1843,6 +1845,7 @@ void CrushWrapper::encode(bufferlist& bl, uint64_t features) const
     ::encode(class_name, bl);
     ::encode(class_bucket, bl);
 
+    // choose args
     __u32 size = (__u32)choose_args.size();
     ::encode(size, bl);
     for (auto c : choose_args) {
index 8095a7fb1064810799445821c0971ca6b07ae1a8..1bcbb474d48f95b23fdc2a2382cc50fb3a081fcf 100644 (file)
@@ -51,6 +51,13 @@ inline static void decode(crush_rule_step &s, bufferlist::iterator &p)
 using namespace std;
 class CrushWrapper {
 public:
+  // magic value used by OSDMap for a "default" fallback choose_args, used if
+  // the choose_arg_map passed to do_rule does not exist.  if this also
+  // doesn't exist, fall back to canonical weights.
+  enum {
+    DEFAULT_CHOOSE_ARGS = -1
+  };
+
   std::map<int32_t, string> type_map; /* bucket/device type names */
   std::map<int32_t, string> name_map; /* bucket/device names */
   std::map<int32_t, string> rule_name_map;
@@ -58,7 +65,7 @@ public:
   std::map<int32_t, string> class_name; /* class id -> class name */
   std::map<string, int32_t> class_rname; /* class name -> class id */
   std::map<int32_t, map<int32_t, int32_t> > class_bucket; /* bucket[id][class] == id */
-  std::map<uint64_t, crush_choose_arg_map> choose_args;
+  std::map<int64_t, crush_choose_arg_map> choose_args;
 
 private:
   struct crush_map *crush;
@@ -1326,6 +1333,21 @@ public:
     return choose_args.count(choose_args_index);
   }
 
+  crush_choose_arg_map choose_args_get_with_fallback(
+    uint64_t choose_args_index) const {
+    auto i = choose_args.find(choose_args_index);
+    if (i == choose_args.end()) {
+      i = choose_args.find(DEFAULT_CHOOSE_ARGS);
+    }
+    if (i == choose_args.end()) {
+      crush_choose_arg_map arg_map;
+      arg_map.args = NULL;
+      arg_map.size = 0;
+      return arg_map;
+    } else {
+      return i->second;
+    }
+  }
   crush_choose_arg_map choose_args_get(uint64_t choose_args_index) const {
     auto i = choose_args.find(choose_args_index);
     if (i == choose_args.end()) {
@@ -1366,7 +1388,8 @@ public:
     int rawout[maxout];
     char work[crush_work_size(crush, maxout)];
     crush_init_workspace(crush, work);
-    crush_choose_arg_map arg_map = choose_args_get(choose_args_index);
+    crush_choose_arg_map arg_map = choose_args_get_with_fallback(
+      choose_args_index);
     int numrep = crush_do_rule(crush, rule, x, rawout, maxout, &weight[0],
                               weight.size(), work, arg_map.args);
     if (numrep < 0)
index f4752f17a83f9d19fa2c4d5d2617a9bcb0fa0782..e57fdea77a222178bf8bcf4b7054cef9d65ce153 100644 (file)
@@ -1053,24 +1053,25 @@ TEST(CrushWrapper, choose_args_compat) {
   arg_map.args = choose_args;
 
   uint64_t features = CEPH_FEATURE_CRUSH_TUNABLES5|CEPH_FEATURE_INCARNATION_2;
+  int64_t caid = CrushWrapper::DEFAULT_CHOOSE_ARGS;
 
   // if the client is capable, encode choose_args
   {
-    c.choose_args[0] = arg_map;
+    c.choose_args[caid] = arg_map;
     bufferlist bl;
     c.encode(bl, features|CEPH_FEATURE_CRUSH_CHOOSE_ARGS);
     bufferlist::iterator i(bl.begin());
     CrushWrapper c_new;
     c_new.decode(i);
     ASSERT_EQ(1u, c_new.choose_args.size());
-    ASSERT_EQ(1u, c_new.choose_args[0].args[-1-id].weight_set_size);
-    ASSERT_EQ(weights, c_new.choose_args[0].args[-1-id].weight_set[0].weights[0]);
+    ASSERT_EQ(1u, c_new.choose_args[caid].args[-1-id].weight_set_size);
+    ASSERT_EQ(weights, c_new.choose_args[caid].args[-1-id].weight_set[0].weights[0]);
     ASSERT_EQ(weight, c_new.get_bucket_item_weightf(id, 0));
   }
 
   // if the client is not compatible, copy choose_arg in the weights
   {
-    c.choose_args[0] = arg_map;
+    c.choose_args[caid] = arg_map;
     bufferlist bl;
     c.encode(bl, features);
     c.choose_args.clear();