return 0;
}
+/**
+ * Unlink image snapshot from group snapshot.
+ *
+ * Input:
+ * @param id Snapshot id
+ * @param image_snap ImageSnapshotSpec
+ *
+ * Output:
+ * @return 0 on success, negative error code on failure
+ */
+int group_snap_unlink(cls_method_context_t hctx,
+ bufferlist *in, bufferlist *out)
+{
+ CLS_LOG(20, "group_snap_unlink");
+ std::string group_snap_id;
+ cls::rbd::ImageSnapshotSpec image_snap;
+ try {
+ auto iter = in->cbegin();
+ decode(group_snap_id, iter);
+ decode(image_snap, iter);
+ } catch (const ceph::buffer::error &err) {
+ return -EINVAL;
+ }
+
+ std::string group_snap_key = group::snap_key(group_snap_id);
+ bufferlist bl;
+ int r = cls_cxx_map_get_val(hctx, group_snap_key, &bl);
+ if (r < 0) {
+ return r;
+ }
+ cls::rbd::GroupSnapshot group_snap;
+ auto iter = bl.cbegin();
+ try {
+ decode(group_snap, iter);
+ } catch (const ceph::buffer::error &err) {
+ CLS_ERR("error decoding snapshot: %s", group_snap_id.c_str());
+ return -EIO;
+ }
+ if (group_snap.state != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ CLS_LOG(20, "snap %s not complete", group_snap_id.c_str());
+ return -ENOENT;
+ }
+
+ auto &snaps = group_snap.snaps;
+ snaps.erase(std::remove(snaps.begin(), snaps.end(), image_snap), snaps.end());
+
+ if (snaps.empty()) {
+ CLS_LOG(20, "group_snap_unlink: removing snapshot with key %s",
+ group_snap_key.c_str());
+ r = cls_cxx_map_remove_key(hctx, group_snap_key);
+ } else {
+ CLS_LOG(20, "group_snap_unlink: updating snapshot with key %s",
+ group_snap_key.c_str());
+ bl.clear();
+ encode(group_snap, bl);
+ r = cls_cxx_map_set_val(hctx, group_snap_key, &bl);
+ }
+ return r;
+}
+
/**
* Get group's snapshot by id.
*
cls_method_handle_t h_image_group_get;
cls_method_handle_t h_group_snap_set;
cls_method_handle_t h_group_snap_remove;
+ cls_method_handle_t h_group_snap_unlink;
cls_method_handle_t h_group_snap_get_by_id;
cls_method_handle_t h_group_snap_list;
cls_method_handle_t h_group_snap_list_order;
cls_register_cxx_method(h_class, "group_snap_remove",
CLS_METHOD_RD | CLS_METHOD_WR,
group_snap_remove, &h_group_snap_remove);
+ cls_register_cxx_method(h_class, "group_snap_unlink",
+ CLS_METHOD_RD | CLS_METHOD_WR,
+ group_snap_unlink, &h_group_snap_unlink);
cls_register_cxx_method(h_class, "group_snap_get_by_id",
CLS_METHOD_RD,
group_snap_get_by_id, &h_group_snap_get_by_id);
return ioctx->operate(oid, &op);
}
+void group_snap_unlink(librados::ObjectWriteOperation *op,
+ const std::string &group_snap_id,
+ const cls::rbd::ImageSnapshotSpec &image_snap) {
+ bufferlist bl;
+ encode(group_snap_id, bl);
+ encode(image_snap, bl);
+ op->exec("rbd", "group_snap_unlink", bl);
+}
+
+int group_snap_unlink(librados::IoCtx *ioctx, const std::string &oid,
+ const std::string &group_snap_id,
+ const cls::rbd::ImageSnapshotSpec &image_snap) {
+ librados::ObjectWriteOperation op;
+ group_snap_unlink(&op, group_snap_id, image_snap);
+
+ return ioctx->operate(oid, &op);
+}
+
int group_snap_get_by_id(librados::IoCtx *ioctx, const std::string &oid,
const std::string &snap_id,
cls::rbd::GroupSnapshot *snapshot) {
const cls::rbd::GroupSnapshot &snapshot);
int group_snap_remove(librados::IoCtx *ioctx, const std::string &oid,
const std::string &snap_id);
+void group_snap_unlink(librados::ObjectWriteOperation *op,
+ const std::string &group_snap_id,
+ const cls::rbd::ImageSnapshotSpec &image_snap);
+int group_snap_unlink(librados::IoCtx *ioctx, const std::string &oid,
+ const std::string &group_snap_id,
+ const cls::rbd::ImageSnapshotSpec &image_snap);
int group_snap_get_by_id(librados::IoCtx *ioctx, const std::string &oid,
const std::string &snap_id,
cls::rbd::GroupSnapshot *snapshot);
void dump(ceph::Formatter *f) const;
+ inline bool operator==(const ImageSnapshotSpec& rhs) const {
+ return pool == rhs.pool &&
+ image_id == rhs.image_id &&
+ snap_id == rhs.snap_id;
+ }
+ inline bool operator<(const ImageSnapshotSpec& rhs) const {
+ if (pool != rhs.pool) {
+ return pool < rhs.pool;
+ }
+ if (image_id != rhs.image_id) {
+ return image_id < rhs.image_id;
+ }
+ return snap_id < rhs.snap_id;
+ }
+
static void generate_test_instances(std::list<ImageSnapshotSpec *> &o);
};
WRITE_CLASS_ENCODER(ImageSnapshotSpec);
ASSERT_EQ("snap_max_order", *keys.begin());
}
+TEST_F(TestClsRbd, group_snap_unlink) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_unlink";
+
+ string group_id = "group_id_snap_unlink";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id,
+ cls::rbd::UserGroupSnapshotNamespace{},
+ "test_snapshot",
+ cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
+ ASSERT_EQ(-ENOENT, group_snap_unlink(&ioctx, group_id, snap_id, {}));
+
+ cls::rbd::GroupSnapshot read_snap;
+ ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap));
+ ASSERT_EQ(read_snap, snap);
+
+ snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
+ ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, {}));
+ ASSERT_EQ(-ENOENT, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap));
+
+ cls::rbd::ImageSnapshotSpec image_snap1 = {1, "image_id1", 1};
+ cls::rbd::ImageSnapshotSpec image_snap2 = {1, "image_id2", 2};
+ snap.snaps = {image_snap1, image_snap2};
+ ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
+
+ ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, {}));
+ ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap));
+ ASSERT_EQ(read_snap, snap);
+
+ ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, image_snap1));
+ ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap));
+ ASSERT_EQ(read_snap.snaps, std::vector<cls::rbd::ImageSnapshotSpec>{image_snap2});
+
+ ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, image_snap1));
+ ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap));
+ ASSERT_EQ(read_snap.snaps, std::vector<cls::rbd::ImageSnapshotSpec>{image_snap2});
+
+ ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, image_snap2));
+ ASSERT_EQ(-ENOENT, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap));
+}
+
TEST_F(TestClsRbd, group_snap_get_by_id) {
librados::IoCtx ioctx;