]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: Enable omaps in Fast EC pools 69267/head
authorMatty Williams <Matty.Williams@ibm.com>
Fri, 5 Jun 2026 15:22:26 +0000 (16:22 +0100)
committerMatty Williams <Matty.Williams@ibm.com>
Fri, 12 Jun 2026 08:54:04 +0000 (09:54 +0100)
Enable supports_omap flag in Fast EC pools.
Enable testing of omap operations in Fast EC pools.

Fixes: https://tracker.ceph.com/issues/77329
Signed-off-by: Matty Williams <Matty.Williams@ibm.com>
12 files changed:
doc/dev/osd_internals/erasure_coding/client_support.rst
doc/glossary.rst
doc/rados/operations/pools.rst
src/mon/MonCommands.h
src/mon/OSDMonitor.cc
src/test/librados/misc_cxx.cc
src/test/librados/omap_cxx.cc
src/test/librados/test_cxx.cc
src/test/librados/test_cxx.h
src/test/librados/test_pool_types.h
src/test/librados/testcase_cxx.cc
src/test/librados/testcase_cxx.h

index 96c84bd7432921d3cf9fb5b7eebbcb300a4926d8..f899c98e51a0638ca28c0fa6f6a5c3d9e8428a3a 100644 (file)
@@ -908,7 +908,8 @@ To enable the new features, the following OSDMap pool settings are required:
 
 - ``allows_ec_overwrites = true`
 - ``allows_ec_optimizations = true``
-- ``supports_omap = true``
 
 These settings can be configured per-pool. The cluster will enforce that all
-OSDs are at the Umbrella release before allowing omap support to be enabled.
\ No newline at end of file
+OSDs are at the Umbrella release before allowing omap support to be enabled.
+
+The `supports_omap` pool flag is automatically enabled in pools with EC optimizations enabled.
\ No newline at end of file
index 0df78710717ece13969fee95881ab06258ce8e9f..a965b68cd8a1529525b71bc21661f5293961fb34 100644 (file)
                 reduce the time it takes to read data from and to write to the
                 Ceph cluster. RGW bucket indexes are stored as omaps.
                 Erasure-coded pools, by default, cannot store RADOS omap data
-                structures. This functionality can be enabled in erasure-coded
-                pools with optimizations enabled by setting the
-                ``supports_omap`` flag to true.
+                structures. This functionality can be enabled in non-Crimson
+                erasure-coded pools by enabling EC optimizations.
                
                 Run the command ``ceph osd df`` to see the storage space used by
                 omaps on each OSD.
index dca87534d2323f90eb5ef9fc74d4d3d846edc849..f00156d02f42b011247e6b0d0d034ecf18908699 100644 (file)
@@ -461,7 +461,7 @@ You may set values for the following keys:
 
 .. describe:: supports_omap
 
-    :Description: Determines whether omap operations can be performed on a pool. On by default for replicated pools, off by default for erasure coded pools. The flag can be enabled for erasure coded pools that allow ec optimizations.
+    :Description: Determines whether omap operations can be performed on a pool. On for replicated and erasure-coded pools with EC optimizations enabled (excluding Crimson pools), off for all other erasure-coded pools.
     :Type: Boolean
 
 .. describe:: hashpspool
index 3c7f13db567b37a6f751f740ddcd292152f2d48b..8891d1f8dc8dc9873dec129474794c84d915f735 100644 (file)
@@ -1292,7 +1292,6 @@ COMMAND("osd pool set "
           "|scrub_priority"
           "|set_pool_flags"
           "|size"
-          "|supports_omap"
           "|target_max_bytes"
           "|target_max_objects"
           "|target_size_bytes"
index c27879fcd442bf6fce9c04d954106d2ff5226fa0..87ee9f8a1f5d45377a0778e10fdca145b04e23dc 100644 (file)
@@ -1996,9 +1996,12 @@ void OSDMonitor::encode_pending(MonitorDBStore::TransactionRef t)
         }
       }
 
-      // Auto-enable omap support for replicated pools
+      // Auto-enable omap support for replicated and fast EC pools
+      // Omap is not supported by EC pools in crimson
       for (auto& [pool_id, pool] : tmp.get_pools()) {
-        if (!pool.has_flag(pg_pool_t::FLAG_OMAP) && pool.is_replicated()) {
+        if (!pool.has_flag(pg_pool_t::FLAG_OMAP) &&
+            (pool.is_replicated() ||
+             (pool.allows_ecoptimizations() && !pool.is_crimson()))) {
           pg_pool_t p = pool;
           p.flags |= pg_pool_t::FLAG_OMAP;
           pending_inc.new_pools[pool_id] = p;
@@ -8351,10 +8354,6 @@ int OSDMonitor::prepare_new_pool(string& name,
   if (crimson) {
     pi->set_flag(pg_pool_t::FLAG_CRIMSON);
   }
-  if (pool_type == pg_pool_t::TYPE_REPLICATED
-      && osdmap.require_osd_release >= ceph_release_t::umbrella) {
-    pi->set_flag(pg_pool_t::FLAG_OMAP);
-  }
 
   pi->size = size;
   pi->min_size = min_size;
@@ -8455,6 +8454,14 @@ int OSDMonitor::prepare_new_pool(string& name,
 
   maybe_enable_pool_split_ops(*pi);
 
+  // Auto-enable omap support for replicated and fast EC pools
+  // Omap is not supported by EC pools in crimson
+  if (osdmap.require_osd_release >= ceph_release_t::umbrella &&
+      (pool_type == pg_pool_t::TYPE_REPLICATED ||
+       (pi->allows_ecoptimizations() && !crimson))) {
+    pi->set_flag(pg_pool_t::FLAG_OMAP);
+  }
+
   pending_inc.new_pool_names[pool] = name;
   return 0;
 }
@@ -8546,6 +8553,12 @@ int OSDMonitor::enable_pool_ec_optimizations(pg_pool_t &p,
       }
     }
     p.flags |= pg_pool_t::FLAG_EC_OPTIMIZATIONS;
+
+    // Automatically enable omap support in fast EC pools
+    // Omap is not supported by EC pools in crimson
+    if (!p.is_crimson() && osdmap.require_osd_release >= ceph_release_t::umbrella) {
+      p.flags |= pg_pool_t::FLAG_OMAP;
+    }
   } else {
     if ((p.flags & pg_pool_t::FLAG_EC_OPTIMIZATIONS) != 0) {
       if (ss) {
@@ -9149,25 +9162,6 @@ int OSDMonitor::prepare_command_pool_set(const cmdmap_t& cmdmap,
     } else {
       p.unset_flag(n);
     }
-  } else if (var == "supports_omap") {
-    if ((val == "true") && osdmap.require_osd_release < ceph_release_t::umbrella) {
-      ss << "supports_omap cannot be enabled until require_osd_release is set to umbrella or later";
-      return -EPERM;
-    }
-    // Disabling omap support will leave omap data in RocksDB which cannot be cleaned up
-    // It will also break any services that depend on this pool to store metadata
-    if ((val == "false") && (p.has_flag(pg_pool_t::FLAG_OMAP))) {
-      ss << "supports_omap cannot be disabled once enabled";
-      return -EINVAL;
-    }
-    // This restriction is temporary until omap support is well tested in Fast EC pools
-    if ((val == "true") && p.is_erasure()) {
-      ss << "supports_omap cannot be enabled in ec pools";
-      return -EINVAL;
-    }
-    if (val == "true") {
-      p.flags |= pg_pool_t::FLAG_OMAP;
-    }
   } else if (var == "target_max_objects") {
     if (interr.length()) {
       ss << "error parsing int '" << val << "': " << interr;
index f3f34655bccabbbc1c136bdeb39ffbae25f6c71e..14c785e248636c7220d989bc54e3ae1e4e62127d 100644 (file)
@@ -18,6 +18,7 @@
 #include "include/stringify.h"
 #include "common/Checksummer.h"
 #include "common/config_proxy.h" // for class ConfigProxy
+#include "common/ceph_json.h"
 #include "mds/mdstypes.h"
 #include "global/global_context.h"
 #include "test/librados/testcase_cxx.h"
@@ -472,6 +473,56 @@ TEST_P(LibRadosMiscPP, CopyPP) {
   }
 }
 
+// Helper function to check if a pool supports omap operations
+// This function will cause the test to fail if it cannot determine the pool's omap support
+static bool supports_omap(librados::IoCtx& ioctx, librados::Rados& cluster) {
+  std::string pool_name = ioctx.get_pool_name();
+  
+  bufferlist inbl, outbl;
+  std::ostringstream cmd;
+  cmd << "{\"prefix\": \"osd pool get\", "
+      << "\"pool\": \"" << pool_name << "\", "
+      << "\"var\": \"supports_omap\", "
+      << "\"format\": \"json\"}";
+  
+  // Send command to determine omap support for the pool
+  int ret = cluster.mon_command(cmd.str(), std::move(inbl), &outbl, nullptr);
+  EXPECT_EQ(0, ret);
+  if (ret != 0) {
+    return false;
+  }
+  
+  // Parse JSON response safely
+  std::string outstr = outbl.to_str();
+  EXPECT_FALSE(outstr.empty());
+  if (outstr.empty()) {
+    return false;
+  }
+  
+  JSONParser parser;
+  bool parse_success = parser.parse(outstr.c_str(), outstr.length());
+  EXPECT_TRUE(parse_success);
+  if (!parse_success) {
+    return false;
+  }
+  
+  // Extract supports_omap value from JSON
+  bool supports_omap_value = false;
+  bool decode_success = false;
+  try {
+    JSONDecoder::decode_json("supports_omap", supports_omap_value, &parser);
+    decode_success = true;
+  } catch (const JSONDecoder::err& e) {
+    // Will be caught by EXPECT below
+  }
+  EXPECT_TRUE(decode_success);
+  if (!decode_success) {
+    return false;
+  }
+  
+  return supports_omap_value;
+}
+
 class LibRadosTwoPoolsECPP : public RadosTestECPP
 {
 public:
@@ -533,6 +584,9 @@ TEST_P(LibRadosTwoPoolsECPP, CopyFrom) {
   bufferlist b;
   b.append("copyfrom");
 
+  // Check if target pool supports omap
+  bool target_supports_omap = supports_omap(ioctx, cluster);
+
   // create big object w/ omapheader
   {
     ASSERT_EQ(0, src_ioctx.write_full("foo", z));
@@ -540,7 +594,8 @@ TEST_P(LibRadosTwoPoolsECPP, CopyFrom) {
     version_t uv = src_ioctx.get_last_version();
     ObjectWriteOperation op;
     op.copy_from("foo", src_ioctx, uv, 0);
-    ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("foo.copy", &op));
+    int expected = target_supports_omap ? 0 : -EOPNOTSUPP;
+    ASSERT_EQ(expected, ioctx.operate("foo.copy", &op));
   }
 
   // same with small object
@@ -549,7 +604,8 @@ TEST_P(LibRadosTwoPoolsECPP, CopyFrom) {
     version_t uv = src_ioctx.get_last_version();
     ObjectWriteOperation op;
     op.copy_from("bar", src_ioctx, uv, 0);
-    ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("bar.copy", &op));
+    int expected = target_supports_omap ? 0 : -EOPNOTSUPP;
+    ASSERT_EQ(expected, ioctx.operate("bar.copy", &op));
   }
 }
 
index eff925454b8c55ef15e3cf0813458d6dfd21e44b..be6e88ea3342e90ae980d4822cf3f5e036a7aad4 100644 (file)
@@ -46,41 +46,21 @@ protected:
 
   void SetUp() override {
     SKIP_IF_CRIMSON();
-    // Skip EC pools before creating resources
-    if (GetParam() == PoolType::FAST_EC) {
-      GTEST_SKIP() << "EC pools do not support omap yet";
-    }
+
     // Call base class SetUp to create pool and ioctx
     PoolTypeTestFixture::SetUp();
     
     nspace = get_temp_pool_name();
     ioctx.set_namespace(nspace);
-    
-    // Enable omap for EC pools
-    if (pool_type == PoolType::FAST_EC) {
-      enable_omap();
-    }
   }
   
   void TearDown() override {
     SKIP_IF_CRIMSON();
-    if (GetParam() == PoolType::FAST_EC) {
-      GTEST_SKIP() << "EC pools do not support omap yet";
-    }
+    
     // Call base class TearDown to clean up pool
     PoolTypeTestFixture::TearDown();
   }
 
-  // Helper methods
-  void enable_omap() {
-    bufferlist inbl, outbl;
-    std::ostringstream oss;
-    oss << "{\"prefix\": \"osd pool set\", \"pool\": \"" << pool_name
-        << "\", \"var\": \"supports_omap\", \"val\": \"true\"}";
-    int ret = rados.mon_command(oss.str(), std::move(inbl), &outbl, nullptr);
-    ASSERT_EQ(0, ret);
-  }
-
   void turn_balancing_off() {
     int rc;
     std::ostringstream oss;
index 8d153739015304f458a6a4ca315908b1d6e82d2d..1f9f34c070554f3250ac40da6f2b83902030dc1d 100644 (file)
@@ -108,13 +108,13 @@ int destroy_ec_profile_and_rule_pp(Rados &cluster,
 }
 
 std::string create_one_ec_pool_pp(const std::string &pool_name,
-  Rados &cluster, bool optimised_ec, bool enable_omap)
+  Rados &cluster, bool fast_ec)
 {
   std::string err = connect_cluster_pp(cluster);
   if (err.length())
     return err;
 
-  err = create_ec_pool_pp(pool_name, cluster, optimised_ec, enable_omap);
+  err = create_ec_pool_pp(pool_name, cluster, fast_ec);
   if (err.length()) {
     cluster.shutdown();
     return err;
@@ -145,7 +145,7 @@ std::string create_pool_pp(const std::string &pool_name, Rados &cluster) {
   return "";
 }
 
-std::string create_ec_pool_pp(const std::string &pool_name, Rados &cluster, bool optimised_ec, bool enable_omap) {
+std::string create_ec_pool_pp(const std::string &pool_name, Rados &cluster, bool fast_ec) {
   std::ostringstream oss;
   int ret = destroy_ec_profile_and_rule_pp(cluster, pool_name, oss);
   if (ret) {
@@ -170,7 +170,7 @@ std::string create_ec_pool_pp(const std::string &pool_name, Rados &cluster, bool
     return oss.str();
   }
 
-  if (optimised_ec) {
+  if (fast_ec) {
     bufferlist inbl;
     ret = cluster.mon_command(
       "{\"prefix\": \"osd pool set\", \"pool\": \"" + pool_name +
@@ -182,20 +182,6 @@ std::string create_ec_pool_pp(const std::string &pool_name, Rados &cluster, bool
       oss << "rados_mon_command osd pool set failed with error " << ret;
       return oss.str();
     }
-
-    if (enable_omap) {
-      bufferlist inbl, outbl;
-      std::ostringstream oss;
-      oss << "{\"prefix\": \"osd pool set\", \"pool\": \"" << pool_name
-          << "\", \"var\": \"supports_omap\", \"val\": \"true\"}";
-      ret = cluster.mon_command(oss.str(), std::move(inbl), &outbl, nullptr);
-      if (ret) {
-        destroy_one_ec_pool_pp(pool_name, cluster);
-        destroy_ec_profile_pp(cluster, pool_name, oss);
-        oss << "rados_mon_command osd pool set failed with error " << ret;
-        return oss.str();
-      }
-    }
   }
 
   cluster.wait_for_latest_osdmap();
index c36ac847882ad9578b540306d4551f11417d1e9d..4bedfa4bd40cc9e052fe0dc7f9aa3624a39c6aa0 100644 (file)
@@ -14,13 +14,11 @@ std::string create_one_pool_pp(const std::string &pool_name,
 std::string create_one_ec_pool_pp(
   const std::string &pool_name,
   librados::Rados &cluster,
-  bool optimised_ec = false,
-  bool enable_omap = false);
+  bool fast_ec = false);
 std::string create_ec_pool_pp(
   const std::string &pool_name,
   librados::Rados &cluster,
-  bool optimised_ec = false,
-  bool enable_omap = false);
+  bool fast_ec = false);
 std::string create_pool_pp(const std::string &pool_name,
                             librados::Rados &cluster);
 std::string set_allow_ec_overwrites_pp(const std::string &pool_name,
index 54175df9dc7fd861b539d3e94044360fe8edbd51..cfe5554a65cd4f9446fbce1598d07fe4525c8a95 100644 (file)
@@ -41,7 +41,7 @@ inline std::string create_pool_by_type(
     case PoolType::REPLICATED:
       return create_one_pool_pp(pool_name, cluster);
     case PoolType::FAST_EC: {
-      std::string result = create_one_ec_pool_pp(pool_name, cluster, true, true);
+      std::string result = create_one_ec_pool_pp(pool_name, cluster, true);
       if (result != "") {
         return result;
       }
@@ -50,7 +50,7 @@ inline std::string create_pool_by_type(
       return result;
     }
     case PoolType::LEGACY_EC:
-      return create_one_ec_pool_pp(pool_name, cluster, false, false);
+      return create_one_ec_pool_pp(pool_name, cluster, false);
     default:
       return "Unknown pool type";
   }
index 8a8a52a64fef0815320f822a11f3257fe8d41ed5..45e7e99fdffc284118fdb5cce6d0cf1ff72d619d 100644 (file)
@@ -753,16 +753,6 @@ void RadosTestECOptimisedPP::turn_balancing_on()
   EXPECT_EQ(rc, 0);
 }
 
-void RadosTestECOptimisedPP::enable_omap()
-{
-  bufferlist inbl, outbl;
-  std::ostringstream oss;
-  oss << "{\"prefix\": \"osd pool set\", \"pool\": \"" << pool_name
-      << "\", \"var\": \"supports_omap\", \"val\": \"true\"}";
-  int ret = cluster.mon_command(oss.str(), std::move(inbl), &outbl, nullptr);
-  EXPECT_EQ(ret, 0);
-}
-
 int RadosTestECOptimisedPP::request_osd_map(
     std::string oid,
     ceph::messaging::osd::OSDMapReply* reply) {
index 42e70c2746272bc57eeb92968a38e5a9d48f1861..89bd50799272d64f8d78004263e158497762f13f 100644 (file)
@@ -226,7 +226,6 @@ protected:
   static std::string pool_name;
   void turn_balancing_off();
   void turn_balancing_on();
-  void enable_omap();
   int request_osd_map(
     std::string oid,
     ceph::messaging::osd::OSDMapReply* reply