*out = oss.str();
}
-static snapid_t snap_id_from_key(const string &key)
-{
+static snapid_t snap_id_from_key(const string &key) {
istringstream iss(key);
uint64_t id;
iss.ignore(strlen(RBD_SNAP_KEY_PREFIX)) >> std::hex >> id;
std::vector<cls::rbd::GroupImageStatus> res;
bool more;
do {
- int r = cls_cxx_map_get_vals(hctx, last_read,cls::rbd::RBD_GROUP_IMAGE_KEY_PREFIX,
- max_read, &vals, &more);
+ int r = cls_cxx_map_get_vals(hctx, last_read,
+ cls::rbd::RBD_GROUP_IMAGE_KEY_PREFIX,
+ max_read, &vals, &more);
if (r < 0)
return r;
return 0;
}
+
+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(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;
+}
+
+static int check_duplicate_snap_id(cls_method_context_t hctx,
+ std::string snap_key)
+{
+ bufferlist bl;
+ int r = cls_cxx_map_get_val(hctx, snap_key, &bl);
+ if (r == -ENOENT) {
+ return 0;
+ } else {
+ return -EEXIST;
+ }
+}
+
+}
+
+/**
+ * Save initial snapshot record.
+ *
+ * Input:
+ * @param GroupSnapshot
+ *
+ * Output:
+ * @return 0 on success, negative error code on failure
+ */
+int group_snap_add(cls_method_context_t hctx,
+ bufferlist *in, bufferlist *out)
+{
+ CLS_LOG(20, "group_snap_add");
+ cls::rbd::GroupSnapshot group_snap;
+ try {
+ bufferlist::iterator iter = in->begin();
+ ::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;
+ }
+
+ r = group::check_duplicate_snap_id(hctx, group::snap_key(group_snap.id));
+ if (r < 0) {
+ return r;
+ }
+
+ std::string key = group::snap_key(group_snap.id);
+
+ bufferlist obl;
+ ::encode(group_snap, obl);
+ r = cls_cxx_map_set_val(hctx, key, &obl);
+ return r;
+}
+
+/**
+ * Update snapshot record.
+ *
+ * Input:
+ * @param GroupSnapshot
+ *
+ * Output:
+ * @return 0 on success, negative error code on failure
+ */
+int group_snap_update(cls_method_context_t hctx,
+ bufferlist *in, bufferlist *out)
+{
+ CLS_LOG(20, "group_snap_update");
+ cls::rbd::GroupSnapshot group_snap;
+ try {
+ bufferlist::iterator iter = in->begin();
+ ::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;
+ }
+
+ int r = group::check_duplicate_snap_name(hctx, group_snap.name, group_snap.id);
+ if (r < 0) {
+ return r;
+ }
+
+ if (group_snap.id.empty()) {
+ CLS_ERR("group snapshot id is empty");
+ return -EINVAL;
+ }
+
+ std::string key = group::snap_key(group_snap.id);
+
+ bufferlist obl;
+ ::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);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ cls::rbd::GroupSnapshot group_snap;
+ group_snap.id = snap_id;
+ std::string snap_key = group::snap_key(group_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(snap_id, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ cls::rbd::GroupSnapshot group_snap;
+ group_snap.id = snap_id;
+
+ bufferlist snapbl;
+
+ int r = cls_cxx_map_get_val(hctx, group::snap_key(group_snap.id), &snapbl);
+ if (r < 0) {
+ return r;
+ }
+
+ bufferlist::iterator iter = snapbl.begin();
+ try {
+ ::decode(group_snap, iter);
+ } catch (const buffer::error &err) {
+ CLS_ERR("error decoding snapshot: %s", snap_id.c_str());
+ return -EIO;
+ }
+
+ ::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();
+ ::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_");
} catch (const buffer::error &err) {
return -EINVAL;
}
-
CLS_LOG(20, "trash_get_image id=%s", id.c_str());
cls_method_handle_t h_image_add_group;
cls_method_handle_t h_image_remove_group;
cls_method_handle_t h_image_get_group;
+ cls_method_handle_t h_group_snap_add;
+ cls_method_handle_t h_group_snap_update;
+ cls_method_handle_t h_group_snap_remove;
+ cls_method_handle_t h_group_snap_get_by_id;
+ cls_method_handle_t h_group_snap_list;
cls_method_handle_t h_trash_add;
cls_method_handle_t h_trash_remove;
cls_method_handle_t h_trash_list;
CLS_METHOD_WR, mirror_image_map_remove,
&h_mirror_image_map_remove);
/* methods for the consistency groups feature */
- cls_register_cxx_method(h_class, "group_create",
- CLS_METHOD_RD | CLS_METHOD_WR,
- group_create, &h_group_create);
cls_register_cxx_method(h_class, "group_dir_list",
CLS_METHOD_RD,
group_dir_list, &h_group_dir_list);
cls_register_cxx_method(h_class, "image_get_group",
CLS_METHOD_RD,
image_get_group, &h_image_get_group);
+ cls_register_cxx_method(h_class, "group_snap_add",
+ CLS_METHOD_RD | CLS_METHOD_WR,
+ group_snap_add, &h_group_snap_add);
+ cls_register_cxx_method(h_class, "group_snap_update",
+ CLS_METHOD_RD | CLS_METHOD_WR,
+ group_snap_update, &h_group_snap_update);
+ 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_get_by_id",
+ CLS_METHOD_RD,
+ group_snap_get_by_id, &h_group_snap_get_by_id);
+ cls_register_cxx_method(h_class, "group_snap_list",
+ CLS_METHOD_RD,
+ group_snap_list, &h_group_snap_list);
/* rbd_trash object methods */
cls_register_cxx_method(h_class, "trash_add",
};
WRITE_CLASS_ENCODER(cls_rbd_snap)
+namespace group {
+
+ static const string RBD_GROUP_SNAP_KEY_PREFIX = "snapshot_";
+
+ std::string snap_key(std::string snap_id) {
+ ostringstream oss;
+ oss << RBD_GROUP_SNAP_KEY_PREFIX << snap_id;
+ return oss.str();
+ }
+}
+
#endif
}
// Consistency groups functions
- int group_create(librados::IoCtx *ioctx, const std::string &oid)
- {
- bufferlist bl, bl2;
-
- return ioctx->exec(oid, "rbd", "group_create", bl, bl2);
- }
-
int group_dir_list(librados::IoCtx *ioctx, const std::string &oid,
const std::string &start, uint64_t max_return,
map<string, string> *cgs)
return image_get_group_finish(&iter, group_spec);
}
+ int group_snap_add(librados::IoCtx *ioctx, const std::string &oid,
+ const cls::rbd::GroupSnapshot &snapshot)
+ {
+
+ bufferlist inbl, outbl;
+
+ ::encode(snapshot, inbl);
+ int r = ioctx->exec(oid, "rbd", "group_snap_add", inbl, outbl);
+ return r;
+ }
+
+ int group_snap_update(librados::IoCtx *ioctx, const std::string &oid,
+ const cls::rbd::GroupSnapshot &snapshot)
+ {
+
+ bufferlist inbl, outbl;
+
+ ::encode(snapshot, inbl);
+ int r = ioctx->exec(oid, "rbd", "group_snap_update", inbl, outbl);
+ return r;
+ }
+
+ int group_snap_remove(librados::IoCtx *ioctx, const std::string &oid,
+ const std::string &snap_id)
+ {
+ bufferlist inbl, outbl;
+ ::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)
+ {
+ bufferlist inbl, outbl;
+ ::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 {
+ ::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)
+ {
+ bufferlist inbl, outbl;
+ ::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,
return 0;
}
-
int trash_list(librados::IoCtx *ioctx,
const std::string &start, uint64_t max_return,
map<string, cls::rbd::TrashImageSpec> *entries)
if (r < 0) {
return r;
}
-
bufferlist::iterator iter = out_bl.begin();
return trash_list_finish(&iter, entries);
}
return 0;
}
-
int trash_get(librados::IoCtx *ioctx, const std::string &id,
cls::rbd::TrashImageSpec *trash_spec)
{
const std::string &global_image_id);
// Consistency groups functions
- int group_create(librados::IoCtx *ioctx, const std::string &oid);
int group_dir_list(librados::IoCtx *ioctx, const std::string &oid,
const std::string &start, uint64_t max_return,
map<string, string> *groups);
cls::rbd::GroupSpec *group_spec);
int image_get_group(librados::IoCtx *ioctx, const std::string &oid,
cls::rbd::GroupSpec *group_spec);
+ int group_snap_add(librados::IoCtx *ioctx, const std::string &oid,
+ const cls::rbd::GroupSnapshot &snapshot);
+ int group_snap_update(librados::IoCtx *ioctx, const std::string &oid,
+ const cls::rbd::GroupSnapshot &snapshot);
+ int group_snap_remove(librados::IoCtx *ioctx, const std::string &oid,
+ const std::string &snap_id);
+ int group_snap_get_by_id(librados::IoCtx *ioctx, const std::string &oid,
+ const std::string &snap_id,
+ cls::rbd::GroupSnapshot *snapshot);
+ 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);
// operations on rbd_trash object
void trash_add(librados::ObjectWriteOperation *op,
}
}
+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);
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);
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(snapshot_id, bl);
+ ::encode(group_snapshot_id, bl);
}
void GroupSnapshotNamespace::decode(bufferlist::iterator& it) {
::decode(group_pool, it);
::decode(group_id, it);
- ::decode(snapshot_id, it);
+ ::decode(group_snapshot_id, it);
}
void GroupSnapshotNamespace::dump(Formatter *f) const {
f->dump_int("group_pool", group_pool);
f->dump_string("group_id", group_id);
- f->dump_int("snapshot_id", snapshot_id);
+ f->dump_string("group_snapshot_id", group_snapshot_id);
}
class EncodeSnapshotNamespaceVisitor : public boost::static_visitor<void> {
}
};
-
-SnapshotNamespaceType SnapshotNamespaceOnDisk::get_namespace_type() const {
+SnapshotNamespaceType get_namespace_type(const SnapshotNamespace& snapshot_namespace) {
return static_cast<SnapshotNamespaceType>(boost::apply_visitor(GetTypeVisitor(),
snapshot_namespace));
}
void SnapshotNamespaceOnDisk::generate_test_instances(std::list<SnapshotNamespaceOnDisk *> &o) {
o.push_back(new SnapshotNamespaceOnDisk(UserSnapshotNamespace()));
- o.push_back(new SnapshotNamespaceOnDisk(GroupSnapshotNamespace(0, "10152ae8944a", 1)));
- o.push_back(new SnapshotNamespaceOnDisk(GroupSnapshotNamespace(5, "1018643c9869", 3)));
+ o.push_back(new SnapshotNamespaceOnDisk(GroupSnapshotNamespace(0, "10152ae8944a", "2118643c9732")));
+ o.push_back(new SnapshotNamespaceOnDisk(GroupSnapshotNamespace(5, "1018643c9869", "33352be8933c")));
}
std::ostream& operator<<(std::ostream& os, const UserSnapshotNamespace& ns) {
os << "[group"
<< " group_pool=" << ns.group_pool
<< " group_id=" << ns.group_id
- << " snapshot_id=" << ns.snapshot_id << "]";
+ << " group_snapshot_id=" << ns.group_snapshot_id << "]";
return os;
}
return os;
}
+void ImageSnapshotSpec::encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ ::encode(pool, bl);
+ ::encode(image_id, bl);
+ ::encode(snap_id, bl);
+ ENCODE_FINISH(bl);
+}
+
+void ImageSnapshotSpec::decode(bufferlist::iterator& it) {
+ DECODE_START(1, it);
+ ::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 {
+ ENCODE_START(1, 1, bl);
+ ::encode(id, bl);
+ ::encode(name, bl);
+ ::encode(state, bl);
+ ::encode(snaps, bl);
+ ENCODE_FINISH(bl);
+}
+
+void GroupSnapshot::decode(bufferlist::iterator& it) {
+ 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_PENDING));
+ 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);
void decode(bufferlist::iterator &it);
void dump(Formatter *f) const;
+ static void generate_test_instances(std::list<GroupImageSpec*> &o);
+
std::string image_key();
};
void decode(bufferlist::iterator &it);
void dump(Formatter *f) const;
+ static void generate_test_instances(std::list<GroupImageStatus*> &o);
+
std::string state_to_string() const;
};
void decode(bufferlist::iterator &it);
void dump(Formatter *f) const;
bool is_valid() const;
+
+ static void generate_test_instances(std::list<GroupSpec *> &o);
};
WRITE_CLASS_ENCODER(GroupSpec);
enum SnapshotNamespaceType {
SNAPSHOT_NAMESPACE_TYPE_USER = 0,
- SNAPSHOT_NAMESPACE_TYPE_GROUP = 1
+ SNAPSHOT_NAMESPACE_TYPE_GROUP = 1,
+ SNAPSHOT_NAMESPACE_TYPE_UNKNOWN = -1,
};
struct UserSnapshotNamespace {
- static const uint32_t SNAPSHOT_NAMESPACE_TYPE = SNAPSHOT_NAMESPACE_TYPE_USER;
+ static const SnapshotNamespaceType SNAPSHOT_NAMESPACE_TYPE = SNAPSHOT_NAMESPACE_TYPE_USER;
UserSnapshotNamespace() {}
std::ostream& operator<<(std::ostream& os, const UserSnapshotNamespace& ns);
struct GroupSnapshotNamespace {
- static const uint32_t SNAPSHOT_NAMESPACE_TYPE = SNAPSHOT_NAMESPACE_TYPE_GROUP;
+ static const SnapshotNamespaceType SNAPSHOT_NAMESPACE_TYPE = SNAPSHOT_NAMESPACE_TYPE_GROUP;
GroupSnapshotNamespace() {}
GroupSnapshotNamespace(int64_t _group_pool,
const string &_group_id,
- snapid_t _snapshot_id)
- : group_id(_group_id), group_pool(_group_pool), snapshot_id(_snapshot_id) {
- }
+ const string &_group_snapshot_id) :group_pool(_group_pool),
+ group_id(_group_id),
+ group_snapshot_id(_group_snapshot_id) {}
- std::string group_id;
int64_t group_pool = 0;
- snapid_t snapshot_id = CEPH_NOSNAP;
+ string group_id;
+ string group_snapshot_id;
void encode(bufferlist& bl) const;
void decode(bufferlist::iterator& it);
inline bool operator==(const GroupSnapshotNamespace& gsn) const {
return group_pool == gsn.group_pool &&
group_id == gsn.group_id &&
- snapshot_id == gsn.snapshot_id;
+ group_snapshot_id == gsn.group_snapshot_id;
}
inline bool operator<(const GroupSnapshotNamespace& gsn) const {
} else if (group_id < gsn.group_id) {
return true;
} else {
- return snapshot_id < gsn.snapshot_id;
+ return (group_snapshot_id < gsn.group_snapshot_id);
}
+ return false;
}
};
std::ostream& operator<<(std::ostream& os, const GroupSnapshotNamespace& ns);
struct UnknownSnapshotNamespace {
- static const uint32_t SNAPSHOT_NAMESPACE_TYPE = static_cast<uint32_t>(-1);
+ static const SnapshotNamespaceType SNAPSHOT_NAMESPACE_TYPE = SNAPSHOT_NAMESPACE_TYPE_UNKNOWN;
UnknownSnapshotNamespace() {}
return true;
}
- inline bool operator<(const UnknownSnapshotNamespace& usn) const {
+ inline bool operator<(const UnknownSnapshotNamespace& gsn) const {
return false;
}
};
std::ostream& operator<<(std::ostream& os, const UnknownSnapshotNamespace& ns);
-typedef boost::variant<UserSnapshotNamespace, GroupSnapshotNamespace, UnknownSnapshotNamespace> SnapshotNamespace;
+typedef boost::variant<UserSnapshotNamespace,
+ GroupSnapshotNamespace,
+ UnknownSnapshotNamespace> SnapshotNamespace;
struct SnapshotNamespaceOnDisk {
SnapshotNamespace snapshot_namespace;
- SnapshotNamespaceType get_namespace_type() const;
-
void encode(bufferlist& bl) const;
void decode(bufferlist::iterator& it);
void dump(Formatter *f) const;
};
WRITE_CLASS_ENCODER(SnapshotNamespaceOnDisk);
+SnapshotNamespaceType get_namespace_type(const SnapshotNamespace& snapshot_namespace);
+
+enum GroupSnapshotState {
+ GROUP_SNAPSHOT_STATE_PENDING = 0,
+ GROUP_SNAPSHOT_STATE_COMPLETE = 1,
+};
+
+inline void encode(const GroupSnapshotState &state, bufferlist& bl, uint64_t features=0)
+{
+ ::encode(static_cast<uint8_t>(state), bl);
+}
+
+inline void decode(GroupSnapshotState &state, bufferlist::iterator& it)
+{
+ 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;
+
+ 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
TEST_F(TestClsRbd, snapshots_namespaces)
{
- cls::rbd::SnapshotNamespace groupSnapNamespace = cls::rbd::GroupSnapshotNamespace(5, "1018643c9869", 3);
+ cls::rbd::SnapshotNamespace groupSnapNamespace = cls::rbd::GroupSnapshotNamespace(5, "1018643c9869", "3338524f9933");
cls::rbd::SnapshotNamespace userSnapNamespace = cls::rbd::UserSnapshotNamespace();
librados::IoCtx ioctx;
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
ASSERT_EQ(0U, instance_ids.size());
}
-TEST_F(TestClsRbd, group_create) {
- librados::IoCtx ioctx;
- ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
-
- string group_id = "group_id";
- ASSERT_EQ(0, group_create(&ioctx, group_id));
-
- uint64_t psize;
- time_t pmtime;
- ASSERT_EQ(0, ioctx.stat(group_id, &psize, &pmtime));
-}
-
TEST_F(TestClsRbd, group_dir_list) {
librados::IoCtx ioctx;
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
auto it = keys.begin();
- ASSERT_EQ(2U, keys.size());
+ ASSERT_EQ(1U, keys.size());
string image_key = cls::rbd::GroupImageSpec(image_id, pool_id).image_key();
ASSERT_EQ(image_key, *it);
- ++it;
- ASSERT_EQ("snap_seq", *it);
}
TEST_F(TestClsRbd, group_image_add) {
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
string group_id = "group_id";
- ASSERT_EQ(0, group_create(&ioctx, group_id));
+ ASSERT_EQ(0, ioctx.create(group_id, true));
int64_t pool_id = ioctx.get_id();
string image_id = "image_id";
librados::IoCtx ioctx;
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
- string group_id = "group_id";
- ASSERT_EQ(0, group_create(&ioctx, group_id));
+ string group_id = "group_id1";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
int64_t pool_id = ioctx.get_id();
string image_id = "image_id";
ASSERT_EQ(0, group_image_remove(&ioctx, group_id, spec));
set<string> keys;
ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
- ASSERT_EQ(1U, keys.size());
- ASSERT_EQ("snap_seq", *(keys.begin()));
+ ASSERT_EQ(0U, keys.size());
}
TEST_F(TestClsRbd, group_image_list) {
librados::IoCtx ioctx;
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
- string group_id = "group_id";
- ASSERT_EQ(0, group_create(&ioctx, group_id));
+ string group_id = "group_id2";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
int64_t pool_id = ioctx.get_id();
string image_id = "imageid"; // Image id shouldn't contain underscores
librados::IoCtx ioctx;
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
- string group_id = "group_id1";
- ASSERT_EQ(0, group_create(&ioctx, group_id));
+ string group_id = "group_id3";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
int64_t pool_id = ioctx.get_id();
string image_id = "image_id";
ASSERT_EQ(pool_id, spec.pool_id);
}
+TEST_F(TestClsRbd, group_snap_add_empty_name) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_add_emtpy_name";
+
+ string group_id = "group_id_snap_add_empty_name";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id, "", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(-EINVAL, group_snap_add(&ioctx, group_id, snap));
+}
+
+TEST_F(TestClsRbd, group_snap_add_empty_id) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_add_empty_id";
+
+ string group_id = "group_id_snap_add_empty_id";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {"", "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(-EINVAL, group_snap_add(&ioctx, group_id, snap));
+}
+
+TEST_F(TestClsRbd, group_snap_add_duplicate_id) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_add_duplicate_id";
+
+ string group_id = "group_id_snap_add_duplicate_id";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+
+ cls::rbd::GroupSnapshot snap1 = {snap_id, "snap_name1", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(-EEXIST, group_snap_add(&ioctx, group_id, snap1));
+}
+
+TEST_F(TestClsRbd, group_snap_add_duplicate_name) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_add_duplicate_name";
+
+ string group_id = "group_id_snap_add_duplicate_name";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id1 = "snap_id1";
+ cls::rbd::GroupSnapshot snap = {snap_id1, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+
+ string snap_id2 = "snap_id2";
+ cls::rbd::GroupSnapshot snap1 = {snap_id2, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(-EEXIST, group_snap_add(&ioctx, group_id, snap1));
+}
+
+TEST_F(TestClsRbd, group_snap_add) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_add";
+
+ string group_id = "group_id_snap_add";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+
+ set<string> keys;
+ ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
+
+ auto it = keys.begin();
+ ASSERT_EQ(1U, keys.size());
+
+ string snap_key = group::snap_key(snap.id);
+ ASSERT_EQ(snap_key, *it);
+}
+
+TEST_F(TestClsRbd, group_snap_list) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_list";
+
+ string group_id = "group_id_snap_list";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id1 = "snap_id1";
+ cls::rbd::GroupSnapshot snap1 = {snap_id1, "test_snapshot1", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap1));
+
+ string snap_id2 = "snap_id2";
+ cls::rbd::GroupSnapshot snap2 = {snap_id2, "test_snapshot2", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap2));
+
+ std::vector<cls::rbd::GroupSnapshot> snapshots;
+ ASSERT_EQ(0, group_snap_list(&ioctx, group_id, cls::rbd::GroupSnapshot(), 10, &snapshots));
+ ASSERT_EQ(2U, snapshots.size());
+ ASSERT_EQ(snap_id1, snapshots[0].id);
+ ASSERT_EQ(snap_id2, snapshots[1].id);
+}
+
+static std::string hexify(int v) {
+ ostringstream oss;
+ oss << std::setw(8) << std::setfill('0') << std::hex << v;
+ //oss << v;
+ return oss.str();
+}
+
+TEST_F(TestClsRbd, group_snap_list_max_return) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_list_max_return";
+
+ string group_id = "group_id_snap_list_max_return";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ for (int i = 0; i < 15; ++i) {
+ string snap_id = "snap_id" + hexify(i);
+ cls::rbd::GroupSnapshot snap = {snap_id,
+ "test_snapshot" + hexify(i),
+ cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+ }
+
+ std::vector<cls::rbd::GroupSnapshot> snapshots;
+ ASSERT_EQ(0, group_snap_list(&ioctx, group_id, cls::rbd::GroupSnapshot(), 10, &snapshots));
+ ASSERT_EQ(10U, snapshots.size());
+
+ for (int i = 0; i < 10; ++i) {
+ string snap_id = "snap_id" + hexify(i);
+ ASSERT_EQ(snap_id, snapshots[i].id);
+ }
+
+ cls::rbd::GroupSnapshot last_snap = *snapshots.rbegin();
+
+ ASSERT_EQ(0, group_snap_list(&ioctx, group_id, last_snap, 10, &snapshots));
+ ASSERT_EQ(5U, snapshots.size());
+ for (int i = 10; i < 15; ++i) {
+ string snap_id = "snap_id" + hexify(i);
+ ASSERT_EQ(snap_id, snapshots[i - 10].id);
+ }
+}
+
+TEST_F(TestClsRbd, group_snap_update) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_update";
+
+ string group_id = "group_id_snap_update";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+
+ snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+
+ ASSERT_EQ(0, group_snap_update(&ioctx, group_id, snap));
+
+ std::vector<cls::rbd::GroupSnapshot> snapshots;
+ ASSERT_EQ(0, group_snap_list(&ioctx, group_id, cls::rbd::GroupSnapshot(), 10, &snapshots));
+ ASSERT_EQ(1U, snapshots.size());
+ ASSERT_EQ(snap_id, snapshots[0].id);
+ ASSERT_EQ(cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE, snapshots[0].state);
+}
+
+TEST_F(TestClsRbd, group_snap_update_empty_name) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_update_empty_name";
+
+ string group_id = "group_id_snap_update_empty_name";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+
+ snap.name = "";
+ snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+
+ ASSERT_EQ(-EINVAL, group_snap_update(&ioctx, group_id, snap));
+}
+
+TEST_F(TestClsRbd, group_snap_update_empty_id) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_update_empty_id";
+
+ string group_id = "group_id_snap_update_empty_id";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+
+ snap.id = "";
+ snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+
+ ASSERT_EQ(-EINVAL, group_snap_update(&ioctx, group_id, snap));
+}
+
+TEST_F(TestClsRbd, group_snap_remove) {
+ librados::IoCtx ioctx;
+
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_remove";
+
+ string group_id = "group_id_snap_remove";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+
+ set<string> keys;
+ ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
+
+ auto it = keys.begin();
+ ASSERT_EQ(1U, keys.size());
+
+ string snap_key = group::snap_key(snap.id);
+ ASSERT_EQ(snap_key, *it);
+
+ // Remove the snapshot
+
+ ASSERT_EQ(0, group_snap_remove(&ioctx, group_id, snap_id));
+
+ ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
+
+ ASSERT_EQ(0U, keys.size());
+}
+
+TEST_F(TestClsRbd, group_snap_get_by_id) {
+ librados::IoCtx ioctx;
+
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string image_id = "image_id_snap_get_by_id";
+
+ string group_id = "group_id_snap_get_by_id";
+ ASSERT_EQ(0, ioctx.create(group_id, true));
+
+ string snap_id = "snap_id";
+ cls::rbd::GroupSnapshot snap = {snap_id,
+ "test_snapshot",
+ cls::rbd::GROUP_SNAPSHOT_STATE_PENDING};
+ ASSERT_EQ(0, group_snap_add(&ioctx, group_id, snap));
+
+ cls::rbd::GroupSnapshot received_snap;
+ ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &received_snap));
+
+ ASSERT_EQ(snap.id, received_snap.id);
+ ASSERT_EQ(snap.name, received_snap.name);
+ ASSERT_EQ(snap.state, received_snap.state);
+}
TEST_F(TestClsRbd, trash_methods)
{
librados::IoCtx ioctx;
ioctx.close();
}
-
TYPE(cls::rbd::MirrorPeer)
TYPE(cls::rbd::MirrorImage)
TYPE(cls::rbd::MirrorImageMap)
+TYPE(cls::rbd::MirrorImageStatus)
+TYPE(cls::rbd::GroupImageSpec)
+TYPE(cls::rbd::GroupImageStatus)
+TYPE(cls::rbd::GroupSpec)
+TYPE(cls::rbd::SnapshotNamespaceOnDisk)
+TYPE(cls::rbd::ImageSnapshotSpec)
+TYPE(cls::rbd::GroupSnapshot)
#endif
#include "cls/lock/cls_lock_types.h"