From 4c00be3428a54d1ad18ad9f9a09270b5f35ba2c5 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 30 May 2017 18:18:41 -0400 Subject: [PATCH] common: ceph_release_[from_]features Map releases to client features (and back again). Signed-off-by: Sage Weil --- src/common/ceph_strings.cc | 63 ++++++++++++++++++++++++++++++++++++++ src/include/rados.h | 3 ++ src/mon/mon_types.h | 2 ++ src/test/CMakeLists.txt | 7 +++++ src/test/test_features.cc | 44 ++++++++++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 src/test/test_features.cc diff --git a/src/common/ceph_strings.cc b/src/common/ceph_strings.cc index 422ccace66129..29ca0c5868a6b 100644 --- a/src/common/ceph_strings.cc +++ b/src/common/ceph_strings.cc @@ -2,6 +2,7 @@ * Ceph string constants */ #include "include/types.h" +#include "include/ceph_features.h" const char *ceph_entity_type_name(int type) { @@ -88,6 +89,9 @@ int ceph_release_from_name(const char *s) if (!s) { return -1; } + if (strcmp(s, "mimic") == 0) { + return CEPH_RELEASE_MIMIC; + } if (strcmp(s, "luminous") == 0) { return CEPH_RELEASE_LUMINOUS; } @@ -127,6 +131,65 @@ int ceph_release_from_name(const char *s) return -1; } +uint64_t ceph_release_features(int r) +{ + uint64_t req = 0; + + req |= CEPH_FEATURE_CRUSH_TUNABLES; + if (r <= CEPH_RELEASE_CUTTLEFISH) + return req; + + req |= CEPH_FEATURE_CRUSH_TUNABLES2 | + CEPH_FEATURE_OSDHASHPSPOOL; + if (r <= CEPH_RELEASE_EMPEROR) + return req; + + req |= CEPH_FEATURE_CRUSH_TUNABLES3 | + CEPH_FEATURE_OSD_PRIMARY_AFFINITY | + CEPH_FEATURE_OSD_CACHEPOOL; + if (r <= CEPH_RELEASE_GIANT) + return req; + + req |= CEPH_FEATURE_CRUSH_V4; + if (r <= CEPH_RELEASE_INFERNALIS) + return req; + + req |= CEPH_FEATURE_CRUSH_TUNABLES5; + if (r <= CEPH_RELEASE_JEWEL) + return req; + + req |= CEPH_FEATURE_MSG_ADDR2; + if (r <= CEPH_RELEASE_KRAKEN) + return req; + + req |= CEPH_FEATUREMASK_CRUSH_CHOOSE_ARGS; // and overlaps + if (r <= CEPH_RELEASE_LUMINOUS) + return req; + + return req; +} + +/* return oldest/first release that supports these features */ +int ceph_release_from_features(uint64_t features) +{ + int r = 1; + while (true) { + uint64_t need = ceph_release_features(r); + if ((need & features) != need || + r == CEPH_RELEASE_MAX) { + r--; + need = ceph_release_features(r); + /* we want the first release that looks like this */ + while (r > 1 && ceph_release_features(r - 1) == need) { + r--; + } + break; + } + ++r; + } + return r; +} + const char *ceph_osd_watch_op_name(int o) { switch (o) { diff --git a/src/include/rados.h b/src/include/rados.h index 426ba45308d2b..56ab69d165cd5 100644 --- a/src/include/rados.h +++ b/src/include/rados.h @@ -176,9 +176,12 @@ extern const char *ceph_osd_state_name(int s); #define CEPH_RELEASE_KRAKEN 11 #define CEPH_RELEASE_LUMINOUS 12 #define CEPH_RELEASE_MIMIC 13 +#define CEPH_RELEASE_MAX 14 /* highest + 1 */ extern const char *ceph_release_name(int r); extern int ceph_release_from_name(const char *s); +extern uint64_t ceph_release_features(int r); +extern int ceph_release_from_features(uint64_t features); /* * The error code to return when an OSD can't handle a write diff --git a/src/mon/mon_types.h b/src/mon/mon_types.h index ede5aac0aeba5..2d3ee68594298 100644 --- a/src/mon/mon_types.h +++ b/src/mon/mon_types.h @@ -96,6 +96,8 @@ struct FeatureMap { for (auto& q : p.second) { f->open_object_section("group"); f->dump_unsigned("features", q.first); + f->dump_string("release", ceph_release_name( + ceph_release_from_features(q.first))); f->dump_unsigned("num", q.second); f->close_section(); } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 9b62b29ce2ffd..9473ad79f8287 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -728,6 +728,13 @@ add_executable(unittest_mempool add_ceph_unittest(unittest_mempool ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest_mempool) target_link_libraries(unittest_mempool global) +# unittest_features +add_executable(unittest_features + test_features.cc + ) +add_ceph_unittest(unittest_features ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest_features) +target_link_libraries(unittest_features global) + # unittest_crypto add_executable(unittest_crypto crypto.cc diff --git a/src/test/test_features.cc b/src/test/test_features.cc new file mode 100644 index 0000000000000..eca067cb7531d --- /dev/null +++ b/src/test/test_features.cc @@ -0,0 +1,44 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +#include + +#include "global/global_init.h" +#include "common/ceph_argparse.h" +#include "global/global_context.h" +#include "gtest/gtest.h" +#include "include/ceph_features.h" +#include "include/rados.h" + + +TEST(features, release_features) +{ + for (int r = 1; r < CEPH_RELEASE_MAX; ++r) { + const char *name = ceph_release_name(r); + ASSERT_NE(string("unknown"), name); + ASSERT_EQ(r, ceph_release_from_name(name)); + uint64_t features = ceph_release_features(r); + int rr = ceph_release_from_features(features); + cout << r << " " << name << " features 0x" << std::hex << features + << std::dec << " looks like " << ceph_release_name(rr) << std::endl; + EXPECT_LE(rr, r); + } +} + +TEST(features, release_from_features) { + ASSERT_EQ(CEPH_RELEASE_JEWEL, ceph_release_from_features(575862587619852283)); + ASSERT_EQ(CEPH_RELEASE_LUMINOUS, + ceph_release_from_features(1152323339925389307)); +} + +int main(int argc, char **argv) +{ + vector args; + argv_to_vec(argc, (const char **)argv, args); + + auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, + CODE_ENVIRONMENT_UTILITY, 0); + common_init_finish(g_ceph_context); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} -- 2.39.5