/// comparisons with Mode::U64, failure to decode an input value is reported
/// 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,
+[[nodiscard]] int cmp_vals(librados::ObjectOperation& op,
Mode mode, Op comparison, ComparisonMap values,
std::optional<ceph::bufferlist> default_value);
/// 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
+///
+/// NOTE: This function cannot be used to set different values when Op::EQ
+/// is used. To accomplish this, one may utilize the transactional operation
+/// with librados::ObjectWriteOperation in combination with cmp_vals(). For example,
+///
+/// librados::ObjectWriteOperation op;
+/// // cmp_vals() fails the operation with -ECANCELED if any comparison fails
+/// cls::cmpomap::cmp_vals(op, mode, comparison, cmp_values, std::nullopt);
+/// // write new values on success
+/// op.omap_set(set_values);
[[nodiscard]] int cmp_set_vals(librados::ObjectWriteOperation& writeop,
Mode mode, Op comparison, ComparisonMap values,
std::optional<ceph::bufferlist> default_value);
}
}
+TEST_F(CmpOmap, atomic_omap_set_conditional_match)
+{
+ const std::string oid = __PRETTY_FUNCTION__;
+ const bufferlist value1 = u64_buffer(1);
+ const bufferlist value2 = u64_buffer(42);
+ {
+ std::map<std::string, bufferlist> vals = {
+ {"eq", value1},
+ };
+ ASSERT_EQ(ioctx.omap_set(oid, vals), 0);
+ }
+
+ librados::ObjectWriteOperation op;
+ ASSERT_EQ(cmp_vals(op, Mode::U64, Op::EQ, {{"eq", value1}}, std::nullopt), 0);
+ op.omap_set({{"eq", value2}});
+ ASSERT_EQ(ioctx.operate(oid, &op), 0);
+ {
+ std::map<std::string, bufferlist> vals;
+ ASSERT_EQ(get_vals(oid, &vals), 0);
+ ASSERT_EQ(vals.size(), 1);
+ EXPECT_EQ(value2, vals["eq"]);
+ }
+}
+
+TEST_F(CmpOmap, atomic_omap_set_conditional_mismatch)
+{
+ const std::string oid = __PRETTY_FUNCTION__;
+ const bufferlist value1 = u64_buffer(1);
+ const bufferlist value2 = u64_buffer(2);
+ const bufferlist value3 = u64_buffer(42);
+ {
+ std::map<std::string, bufferlist> vals = {
+ {"eq", value1},
+ };
+ ASSERT_EQ(ioctx.omap_set(oid, vals), 0);
+ }
+
+ librados::ObjectWriteOperation op;
+ ASSERT_EQ(cmp_vals(op, Mode::U64, Op::EQ, {{"eq", value2}}, std::nullopt), 0);
+ op.omap_set({{"eq", value3}});
+ ASSERT_EQ(ioctx.operate(oid, &op), -ECANCELED);
+ {
+ std::map<std::string, bufferlist> vals;
+ ASSERT_EQ(get_vals(oid, &vals), 0);
+ ASSERT_EQ(vals.size(), 1);
+ EXPECT_EQ(value1, vals["eq"]); // Nothing is changed
+ }
+}
+
TEST_F(CmpOmap, cmp_set_vals_u64)
{
const std::string oid = __PRETTY_FUNCTION__;