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>
- ``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
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.
.. 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
"|scrub_priority"
"|set_pool_flags"
"|size"
- "|supports_omap"
"|target_max_bytes"
"|target_max_objects"
"|target_size_bytes"
}
}
- // 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;
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;
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;
}
}
}
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) {
} 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;
#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"
}
}
+// 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:
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));
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
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));
}
}
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;
}
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;
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) {
return oss.str();
}
- if (optimised_ec) {
+ if (fast_ec) {
bufferlist inbl;
ret = cluster.mon_command(
"{\"prefix\": \"osd pool set\", \"pool\": \"" + pool_name +
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();
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,
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;
}
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";
}
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) {
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