/// process each of the omap value comparisons according to the same rules as
/// cmpxattr(), and return -ECANCELED if a comparison is unsuccessful. for
/// comparisons with Mode::U64, failure to decode an input value is reported
-/// as -EINVAL, while failure to decode a stored value is reported as -EIO
+/// as -EINVAL, an empty stored value is compared as 0, and failure to decode
+/// a stored value is reported as -EIO
[[nodiscard]] int cmp_vals(librados::ObjectReadOperation& op,
Mode mode, Op comparison, ComparisonMap values,
std::optional<ceph::bufferlist> default_value);
/// process each of the omap value comparisons according to the same rules as
/// cmpxattr(). any key/value pairs that compare successfully are overwritten
/// with the corresponding input value. for comparisons with Mode::U64, failure
-/// to decode an input value is reported as -EINVAL. decode failure of a stored
-/// value is treated as an unsuccessful comparison and is not reported as an
-/// error
+/// to decode an input value is reported as -EINVAL. an empty stored value is
+/// compared as 0, while decode failure of a stored value is treated as an
+/// unsuccessful comparison and is not reported as an error
[[nodiscard]] int cmp_set_vals(librados::ObjectWriteOperation& writeop,
Mode mode, Op comparison, ComparisonMap values,
std::optional<ceph::bufferlist> default_value);
/// process each of the omap value comparisons according to the same rules as
/// cmpxattr(). any key/value pairs that compare successfully are removed. for
/// comparisons with Mode::U64, failure to decode an input value is reported as
-/// -EINVAL. decode failure of a stored value is treated as an unsuccessful
-/// comparison and is not reported as an error
+/// -EINVAL. an empty stored value is compared as 0, while decode failure of a
+/// stored value is treated as an unsuccessful comparison and is not reported
+/// as an error
[[nodiscard]] int cmp_rm_keys(librados::ObjectWriteOperation& writeop,
Mode mode, Op comparison, ComparisonMap values);
ASSERT_EQ(ioctx.create(oid, true), 0);
const std::string key = "key";
const bufferlist input = u64_buffer(0);
- const bufferlist def; // empty buffer can't be decoded as u64
+ const bufferlist def = string_buffer("bbb"); // can't be decoded as u64
EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, input}}, def), -EIO);
EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, input}}, def), -EIO);
EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, input}}, def), -EIO);
EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, input}}, def), -EIO);
}
+TEST_F(CmpOmap, cmp_vals_u64_empty_default)
+{
+ const std::string oid = __PRETTY_FUNCTION__;
+ ASSERT_EQ(ioctx.create(oid, true), 0);
+ const std::string key = "key";
+ const bufferlist input = u64_buffer(1);
+ const bufferlist def; // empty buffer defaults to 0
+ EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, input}}, def), -ECANCELED);
+ EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, input}}, def), 0);
+ EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, input}}, def), 0);
+ EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, input}}, def), 0);
+ EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, input}}, def), -ECANCELED);
+ EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, input}}, def), -ECANCELED);
+}
+
TEST_F(CmpOmap, cmp_vals_u64_invalid_value)
{
const std::string oid = __PRETTY_FUNCTION__;
EXPECT_EQ(cmp_rm_keys(op, Mode::U64, Op::EQ, std::move(comparisons)), -E2BIG);
}
+// test upgrades from empty omap values to u64
+TEST_F(CmpOmap, cmp_rm_keys_u64_empty)
+{
+ const std::string oid = __PRETTY_FUNCTION__;
+ const bufferlist value1; // empty buffer
+ const bufferlist value2 = u64_buffer(42);
+ {
+ std::map<std::string, bufferlist> vals = {
+ {"eq", value1},
+ {"ne", value1},
+ {"gt", value1},
+ {"gte", value1},
+ {"lt", value1},
+ {"lte", value1},
+ };
+ ASSERT_EQ(ioctx.omap_set(oid, vals), 0);
+ }
+
+ ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::EQ, {{"eq", value2}}), 0);
+ ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::NE, {{"ne", value2}}), 0);
+ ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::GT, {{"gt", value2}}), 0);
+ ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::GTE, {{"gte", value2}}), 0);
+ ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::LT, {{"lt", value2}}), 0);
+ ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::LTE, {{"lte", value2}}), 0);
+
+ {
+ std::map<std::string, bufferlist> vals;
+ ASSERT_EQ(get_vals(oid, &vals), 0);
+ EXPECT_EQ(vals.count("eq"), 1);
+ EXPECT_EQ(vals.count("ne"), 0);
+ EXPECT_EQ(vals.count("gt"), 0);
+ EXPECT_EQ(vals.count("gte"), 0);
+ EXPECT_EQ(vals.count("lt"), 1);
+ EXPECT_EQ(vals.count("lte"), 1);
+ }
+}
+
} // namespace cls::cmpomap