return 0;
}
- ::decode(snap, iter);
+
+namespace group {
+
+static int group_snap_list(cls_method_context_t hctx,
+ cls::rbd::GroupSnapshot start_after,
+ uint64_t max_return,
+ std::vector<cls::rbd::GroupSnapshot> *group_snaps)
+{
+ int max_read = RBD_MAX_KEYS_READ;
+ std::map<string, bufferlist> vals;
+ string last_read = snap_key(start_after.id);
+
+ group_snaps->clear();
+
+ bool more;
+ do {
+ int r = cls_cxx_map_get_vals(hctx, last_read,
+ RBD_GROUP_SNAP_KEY_PREFIX,
+ max_read, &vals, &more);
+ if (r < 0)
+ return r;
+
+ for (map<string, bufferlist>::iterator it = vals.begin();
+ it != vals.end() && group_snaps->size() < max_return; ++it) {
+
+ bufferlist::iterator iter = it->second.begin();
+ cls::rbd::GroupSnapshot snap;
+ try {
- ::decode(group_snap, iter);
++ decode(snap, iter);
+ } catch (const buffer::error &err) {
+ CLS_ERR("error decoding snapshot: %s", it->first.c_str());
+ return -EIO;
+ }
+ CLS_LOG(20, "Discovered snapshot %s %s",
+ snap.name.c_str(),
+ snap.id.c_str());
+ group_snaps->push_back(snap);
+ }
+
+ } while (more && (group_snaps->size() < max_return));
+
+ return 0;
+}
+
+static int check_duplicate_snap_name(cls_method_context_t hctx,
+ std::string snap_name,
+ std::string snap_id)
+{
+ const int max_read = 1024;
+ cls::rbd::GroupSnapshot snap_last;
+ std::vector<cls::rbd::GroupSnapshot> page;
+
+ for (;;) {
+ int r = group_snap_list(hctx, snap_last, max_read, &page);
+ if (r < 0) {
+ return r;
+ }
+ for (auto& snap: page) {
+ if (snap.name == snap_name && snap.id != snap_id) {
+ return -EEXIST;
+ }
+ }
+
+ if (page.size() < max_read) {
+ break;
+ }
+
+ snap_last = *page.rbegin();
+ }
+
+ return 0;
+}
+
+}
+
+/**
+ * Save initial snapshot record.
+ *
+ * Input:
+ * @param GroupSnapshot
+ *
+ * Output:
+ * @return 0 on success, negative error code on failure
+ */
+int group_snap_set(cls_method_context_t hctx,
+ bufferlist *in, bufferlist *out)
+{
+ CLS_LOG(20, "group_snap_set");
+ cls::rbd::GroupSnapshot group_snap;
+ try {
+ bufferlist::iterator iter = in->begin();
- ::encode(group_snap, obl);
++ decode(group_snap, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ if (group_snap.name.empty()) {
+ CLS_ERR("group snapshot name is empty");
+ return -EINVAL;
+ }
+ if (group_snap.id.empty()) {
+ CLS_ERR("group snapshot id is empty");
+ return -EINVAL;
+ }
+
+ int r = group::check_duplicate_snap_name(hctx, group_snap.name,
+ group_snap.id);
+ if (r < 0) {
+ return r;
+ }
+
+ std::string key = group::snap_key(group_snap.id);
+ if (group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ bufferlist snap_bl;
+ r = cls_cxx_map_get_val(hctx, key, &snap_bl);
+ if (r < 0 && r != -ENOENT) {
+ return r;
+ } else if (r >= 0) {
+ return -EEXIST;
+ }
+ }
+
+ bufferlist obl;
- ::decode(snap_id, iter);
++ encode(group_snap, obl);
+ r = cls_cxx_map_set_val(hctx, key, &obl);
+ return r;
+}
+
+/**
+ * Remove snapshot record.
+ *
+ * Input:
+ * @param id Snapshot id
+ *
+ * Output:
+ * @return 0 on success, negative error code on failure
+ */
+int group_snap_remove(cls_method_context_t hctx,
+ bufferlist *in, bufferlist *out)
+{
+ CLS_LOG(20, "group_snap_remove");
+ std::string snap_id;
+ try {
+ bufferlist::iterator iter = in->begin();
- ::decode(snap_id, iter);
++ decode(snap_id, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ std::string snap_key = group::snap_key(snap_id);
+
+ CLS_LOG(20, "removing snapshot with key %s", snap_key.c_str());
+ int r = cls_cxx_map_remove_key(hctx, snap_key);
+ return r;
+}
+
+/**
+ * Get consistency group's snapshot by id.
+ *
+ * Input:
+ * @param snapshot_id the id of the snapshot to look for.
+ *
+ * Output:
+ * @param GroupSnapshot the requested snapshot
+ * @return 0 on success, negative error code on failure
+ */
+int group_snap_get_by_id(cls_method_context_t hctx,
+ bufferlist *in, bufferlist *out)
+{
+ CLS_LOG(20, "group_snap_get_by_id");
+
+ std::string snap_id;
+ try {
+ bufferlist::iterator iter = in->begin();
- ::decode(group_snap, iter);
++ decode(snap_id, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ bufferlist snapbl;
+
+ int r = cls_cxx_map_get_val(hctx, group::snap_key(snap_id), &snapbl);
+ if (r < 0) {
+ return r;
+ }
+
+ cls::rbd::GroupSnapshot group_snap;
+ bufferlist::iterator iter = snapbl.begin();
+ try {
- ::encode(group_snap, *out);
++ decode(group_snap, iter);
+ } catch (const buffer::error &err) {
+ CLS_ERR("error decoding snapshot: %s", snap_id.c_str());
+ return -EIO;
+ }
+
- ::decode(start_after, iter);
- ::decode(max_return, iter);
++ encode(group_snap, *out);
+
+ return 0;
+}
+
+/**
+ * List consistency group's snapshots.
+ *
+ * Input:
+ * @param start_after which name to begin listing after
+ * (use the empty string to start at the beginning)
+ * @param max_return the maximum number of snapshots to list
+ *
+ * Output:
+ * @param list of snapshots
+ * @return 0 on success, negative error code on failure
+ */
+int group_snap_list(cls_method_context_t hctx,
+ bufferlist *in, bufferlist *out)
+{
+ CLS_LOG(20, "group_snap_list");
+
+ cls::rbd::GroupSnapshot start_after;
+ uint64_t max_return;
+ try {
+ bufferlist::iterator iter = in->begin();
- ::encode(group_snaps, *out);
++ decode(start_after, iter);
++ decode(max_return, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+ std::vector<cls::rbd::GroupSnapshot> group_snaps;
+ group::group_snap_list(hctx, start_after, max_return, &group_snaps);
+
++ encode(group_snaps, *out);
+
+ return 0;
+}
+
namespace trash {
static const std::string IMAGE_KEY_PREFIX("id_");
return image_get_group_finish(&iter, group_spec);
}
-
+ int group_snap_set(librados::IoCtx *ioctx, const std::string &oid,
+ const cls::rbd::GroupSnapshot &snapshot)
+ {
-
- ::encode(snapshot, inbl);
++ using ceph::encode;
+ bufferlist inbl, outbl;
- ::encode(snap_id, inbl);
-
++ encode(snapshot, inbl);
+ int r = ioctx->exec(oid, "rbd", "group_snap_set", inbl, outbl);
+ return r;
+ }
+
+ int group_snap_remove(librados::IoCtx *ioctx, const std::string &oid,
+ const std::string &snap_id)
+ {
++ using ceph::encode;
+ bufferlist inbl, outbl;
- ::encode(snap_id, inbl);
++ encode(snap_id, inbl);
+ return ioctx->exec(oid, "rbd", "group_snap_remove", inbl, outbl);
+ }
+
+ int group_snap_get_by_id(librados::IoCtx *ioctx, const std::string &oid,
+ const std::string &snap_id,
+ cls::rbd::GroupSnapshot *snapshot)
+ {
++ using ceph::encode;
++ using ceph::decode;
+ bufferlist inbl, outbl;
- ::decode(*snapshot, iter);
+
++ encode(snap_id, inbl);
+ int r = ioctx->exec(oid, "rbd", "group_snap_get_by_id", inbl, outbl);
+ if (r < 0) {
+ return r;
+ }
+
+ bufferlist::iterator iter = outbl.begin();
+ try {
- ::encode(start, inbl);
- ::encode(max_return, inbl);
++ decode(*snapshot, iter);
+ } catch (const buffer::error &err) {
+ return -EBADMSG;
+ }
+
+ return 0;
+ }
+ int group_snap_list(librados::IoCtx *ioctx, const std::string &oid,
+ const cls::rbd::GroupSnapshot &start,
+ uint64_t max_return,
+ std::vector<cls::rbd::GroupSnapshot> *snapshots)
+ {
++ using ceph::encode;
++ using ceph::decode;
+ bufferlist inbl, outbl;
- ::decode(*snapshots, iter);
++ encode(start, inbl);
++ encode(max_return, inbl);
+
+ int r = ioctx->exec(oid, "rbd", "group_snap_list", inbl, outbl);
+ if (r < 0) {
+ return r;
+ }
+ bufferlist::iterator iter = outbl.begin();
+ try {
++ decode(*snapshots, iter);
+ } catch (const buffer::error &err) {
+ return -EBADMSG;
+ }
+
+ return 0;
+ }
+
// rbd_trash functions
void trash_add(librados::ObjectWriteOperation *op,
const std::string &id,
}
}
+void GroupImageSpec::generate_test_instances(std::list<GroupImageSpec*> &o) {
+ o.push_back(new GroupImageSpec("10152ae8944a", 0));
+ o.push_back(new GroupImageSpec("1018643c9869", 3));
+}
+
void GroupImageStatus::encode(bufferlist &bl) const {
ENCODE_START(1, 1, bl);
- ::encode(spec, bl);
- ::encode(state, bl);
+ encode(spec, bl);
+ encode(state, bl);
ENCODE_FINISH(bl);
}
f->dump_string("state", state_to_string());
}
+void GroupImageStatus::generate_test_instances(std::list<GroupImageStatus*> &o) {
+ o.push_back(new GroupImageStatus(GroupImageSpec("10152ae8944a", 0), GROUP_IMAGE_LINK_STATE_ATTACHED));
+ o.push_back(new GroupImageStatus(GroupImageSpec("1018643c9869", 3), GROUP_IMAGE_LINK_STATE_ATTACHED));
+ o.push_back(new GroupImageStatus(GroupImageSpec("10152ae8944a", 0), GROUP_IMAGE_LINK_STATE_INCOMPLETE));
+ o.push_back(new GroupImageStatus(GroupImageSpec("1018643c9869", 3), GROUP_IMAGE_LINK_STATE_INCOMPLETE));
+}
+
+
void GroupSpec::encode(bufferlist &bl) const {
ENCODE_START(1, 1, bl);
- ::encode(pool_id, bl);
- ::encode(group_id, bl);
+ encode(pool_id, bl);
+ encode(group_id, bl);
ENCODE_FINISH(bl);
}
return (!group_id.empty()) && (pool_id != -1);
}
+void GroupSpec::generate_test_instances(std::list<GroupSpec *> &o) {
+ o.push_back(new GroupSpec("10152ae8944a", 0));
+ o.push_back(new GroupSpec("1018643c9869", 3));
+}
+
void GroupSnapshotNamespace::encode(bufferlist& bl) const {
- ::encode(group_pool, bl);
- ::encode(group_id, bl);
- ::encode(group_snapshot_id, bl);
+ using ceph::encode;
+ encode(group_pool, bl);
+ encode(group_id, bl);
- encode(snapshot_id, bl);
++ encode(group_snapshot_id, bl);
}
void GroupSnapshotNamespace::decode(bufferlist::iterator& it) {
- ::decode(group_pool, it);
- ::decode(group_id, it);
- ::decode(group_snapshot_id, it);
+ using ceph::decode;
+ decode(group_pool, it);
+ decode(group_id, it);
- decode(snapshot_id, it);
++ decode(group_snapshot_id, it);
}
void GroupSnapshotNamespace::dump(Formatter *f) const {
return os;
}
- ::encode(pool, bl);
- ::encode(image_id, bl);
- ::encode(snap_id, bl);
+void ImageSnapshotSpec::encode(bufferlist& bl) const {
++ using ceph::encode;
+ ENCODE_START(1, 1, bl);
- ::decode(pool, it);
- ::decode(image_id, it);
- ::decode(snap_id, it);
++ encode(pool, bl);
++ encode(image_id, bl);
++ encode(snap_id, bl);
+ ENCODE_FINISH(bl);
+}
+
+void ImageSnapshotSpec::decode(bufferlist::iterator& it) {
++ using ceph::decode;
+ DECODE_START(1, it);
- ::encode(id, bl);
- ::encode(name, bl);
- ::encode(state, bl);
- ::encode(snaps, bl);
++ decode(pool, it);
++ decode(image_id, it);
++ decode(snap_id, it);
+ DECODE_FINISH(it);
+}
+
+void ImageSnapshotSpec::dump(Formatter *f) const {
+ f->dump_int("pool", pool);
+ f->dump_string("image_id", image_id);
+ f->dump_int("snap_id", snap_id);
+}
+
+void ImageSnapshotSpec::generate_test_instances(std::list<ImageSnapshotSpec *> &o) {
+ o.push_back(new ImageSnapshotSpec(0, "myimage", 2));
+ o.push_back(new ImageSnapshotSpec(1, "testimage", 7));
+}
+
+void GroupSnapshot::encode(bufferlist& bl) const {
++ using ceph::encode;
+ ENCODE_START(1, 1, bl);
- ::decode(id, it);
- ::decode(name, it);
- ::decode(state, it);
- ::decode(snaps, it);
++ encode(id, bl);
++ encode(name, bl);
++ encode(state, bl);
++ encode(snaps, bl);
+ ENCODE_FINISH(bl);
+}
+
+void GroupSnapshot::decode(bufferlist::iterator& it) {
++ using ceph::decode;
+ DECODE_START(1, it);
++ decode(id, it);
++ decode(name, it);
++ decode(state, it);
++ decode(snaps, it);
+ DECODE_FINISH(it);
+}
+
+void GroupSnapshot::dump(Formatter *f) const {
+ f->dump_string("id", id);
+ f->dump_string("name", name);
+ f->dump_int("state", state);
+}
+
+void GroupSnapshot::generate_test_instances(std::list<GroupSnapshot *> &o) {
+ o.push_back(new GroupSnapshot("10152ae8944a", "groupsnapshot1", GROUP_SNAPSHOT_STATE_INCOMPLETE));
+ o.push_back(new GroupSnapshot("1018643c9869", "groupsnapshot2", GROUP_SNAPSHOT_STATE_COMPLETE));
+}
void TrashImageSpec::encode(bufferlist& bl) const {
ENCODE_START(1, 1, bl);
- ::encode(source, bl);
- ::encode(name, bl);
- ::encode(deletion_time, bl);
- ::encode(deferment_end_time, bl);
+ encode(source, bl);
+ encode(name, bl);
+ encode(deletion_time, bl);
+ encode(deferment_end_time, bl);
ENCODE_FINISH(bl);
}
};
WRITE_CLASS_ENCODER(SnapshotNamespaceOnDisk);
- ::encode(static_cast<uint8_t>(state), bl);
+SnapshotNamespaceType get_snap_namespace_type(const SnapshotNamespace& snapshot_namespace);
+
+enum GroupSnapshotState {
+ GROUP_SNAPSHOT_STATE_INCOMPLETE = 0,
+ GROUP_SNAPSHOT_STATE_COMPLETE = 1,
+};
+
+inline void encode(const GroupSnapshotState &state, bufferlist& bl, uint64_t features=0)
+{
- ::decode(int_state, it);
++ using ceph::encode;
++ encode(static_cast<uint8_t>(state), bl);
+}
+
+inline void decode(GroupSnapshotState &state, bufferlist::iterator& it)
+{
++ using ceph::decode;
+ uint8_t int_state;
++ decode(int_state, it);
+ state = static_cast<GroupSnapshotState>(int_state);
+}
+
+struct ImageSnapshotSpec {
+ int64_t pool;
+ string image_id;
+ snapid_t snap_id;
+
+ ImageSnapshotSpec() {}
+ ImageSnapshotSpec(int64_t _pool,
+ string _image_id,
+ snapid_t _snap_id) : pool(_pool),
+ image_id(_image_id),
+ snap_id(_snap_id) {}
+
+ void encode(bufferlist& bl) const;
+ void decode(bufferlist::iterator& it);
+
+ void dump(Formatter *f) const;
+
+ static void generate_test_instances(std::list<ImageSnapshotSpec *> &o);
+};
+WRITE_CLASS_ENCODER(ImageSnapshotSpec);
+
+struct GroupSnapshot {
+ std::string id;
+ std::string name;
+ GroupSnapshotState state = GROUP_SNAPSHOT_STATE_INCOMPLETE;
+
+ GroupSnapshot() {}
+ GroupSnapshot(std::string _id,
+ std::string _name,
+ GroupSnapshotState _state) : id(_id),
+ name(_name),
+ state(_state) {}
+
+ vector<ImageSnapshotSpec> snaps;
+
+ void encode(bufferlist& bl) const;
+ void decode(bufferlist::iterator& it);
+ void dump(Formatter *f) const;
+
+ static void generate_test_instances(std::list<GroupSnapshot *> &o);
+};
+WRITE_CLASS_ENCODER(GroupSnapshot);
enum TrashImageSource {
TRASH_IMAGE_SOURCE_USER = 0,
TRASH_IMAGE_SOURCE_MIRRORING = 1