From: Sage Weil Date: Fri, 14 Jul 2017 17:12:02 +0000 (-0400) Subject: crush/CrushWrapper: make a compat/default choose_args X-Git-Tag: v12.1.2~150^2~34 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=87f64a951d3d98f92c19593cd926270cf54f9494;p=ceph.git crush/CrushWrapper: make a compat/default choose_args 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 --- diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index 857d2d13dcf89..91eddd6cdf0ae 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -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) { diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index 8095a7fb10648..1bcbb474d48f9 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -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 type_map; /* bucket/device type names */ std::map name_map; /* bucket/device names */ std::map rule_name_map; @@ -58,7 +65,7 @@ public: std::map class_name; /* class id -> class name */ std::map class_rname; /* class name -> class id */ std::map > class_bucket; /* bucket[id][class] == id */ - std::map choose_args; + std::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) diff --git a/src/test/crush/CrushWrapper.cc b/src/test/crush/CrushWrapper.cc index f4752f17a83f9..e57fdea77a222 100644 --- a/src/test/crush/CrushWrapper.cc +++ b/src/test/crush/CrushWrapper.cc @@ -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();