static const std::string IMAGE_KEY_PREFIX("image_");
static const std::string GLOBAL_KEY_PREFIX("global_");
static const std::string STATUS_GLOBAL_KEY_PREFIX("status_global_");
+static const std::string INSTANCE_KEY_PREFIX("instance_");
std::string peer_key(const std::string &uuid) {
return PEER_KEY_PREFIX + uuid;
return STATUS_GLOBAL_KEY_PREFIX + global_id;
}
+std::string instance_key(const string &instance_id) {
+ return INSTANCE_KEY_PREFIX + instance_id;
+}
+
int uuid_get(cls_method_context_t hctx, std::string *mirror_uuid) {
bufferlist mirror_uuid_bl;
int r = cls_cxx_map_get_val(hctx, mirror::UUID, &mirror_uuid_bl);
return 0;
}
+int instances_list(cls_method_context_t hctx,
+ std::vector<std::string> *instance_ids) {
+ std::string last_read = INSTANCE_KEY_PREFIX;
+ int max_read = RBD_MAX_KEYS_READ;
+ int r = max_read;
+ while (r == max_read) {
+ std::map<std::string, bufferlist> vals;
+ r = cls_cxx_map_get_vals(hctx, last_read, INSTANCE_KEY_PREFIX.c_str(),
+ max_read, &vals);
+ if (r < 0) {
+ if (r != -ENOENT) {
+ CLS_ERR("error reading mirror instances: %s", cpp_strerror(r).c_str());
+ }
+ return r;
+ }
+
+ for (auto &it : vals) {
+ instance_ids->push_back(it.first.substr(INSTANCE_KEY_PREFIX.size()));
+ }
+
+ if (!vals.empty()) {
+ last_read = vals.rbegin()->first;
+ }
+ }
+ return 0;
+}
+
+int instances_add(cls_method_context_t hctx, const string &instance_id) {
+ bufferlist bl;
+
+ int r = cls_cxx_map_set_val(hctx, instance_key(instance_id), &bl);
+ if (r < 0) {
+ CLS_ERR("error setting mirror instance %s: %s", instance_id.c_str(),
+ cpp_strerror(r).c_str());
+ return r;
+ }
+ return 0;
+}
+
+int instances_remove(cls_method_context_t hctx, const string &instance_id) {
+
+ int r = cls_cxx_map_remove_key(hctx, instance_key(instance_id));
+ if (r < 0) {
+ CLS_ERR("error removing mirror instance %s: %s", instance_id.c_str(),
+ cpp_strerror(r).c_str());
+ return r;
+ }
+ return 0;
+}
+
} // namespace mirror
/**
return 0;
}
+/**
+ * Input:
+ * none
+ *
+ * Output:
+ * @param std::vector<std::string>: instance ids
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_instances_list(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::vector<std::string> instance_ids;
+
+ int r = mirror::instances_list(hctx, &instance_ids);
+ if (r < 0) {
+ return r;
+ }
+
+ ::encode(instance_ids, *out);
+ return 0;
+}
+
+/**
+ * Input:
+ * @param instance_id (std::string)
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_instances_add(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::string instance_id;
+ try {
+ bufferlist::iterator iter = in->begin();
+ ::decode(instance_id, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ int r = mirror::instances_add(hctx, instance_id);
+ if (r < 0) {
+ return r;
+ }
+ return 0;
+}
+
+/**
+ * Input:
+ * @param instance_id (std::string)
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_instances_remove(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::string instance_id;
+ try {
+ bufferlist::iterator iter = in->begin();
+ ::decode(instance_id, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ int r = mirror::instances_remove(hctx, instance_id);
+ if (r < 0) {
+ return r;
+ }
+ return 0;
+}
+
/**
* Initialize the header with basic metadata.
* Everything is stored as key/value pairs as omaps in the header object.
cls_method_handle_t h_mirror_image_status_list;
cls_method_handle_t h_mirror_image_status_get_summary;
cls_method_handle_t h_mirror_image_status_remove_down;
+ cls_method_handle_t h_mirror_instances_list;
+ cls_method_handle_t h_mirror_instances_add;
+ cls_method_handle_t h_mirror_instances_remove;
cls_method_handle_t h_group_create;
cls_method_handle_t h_group_dir_list;
cls_method_handle_t h_group_dir_add;
CLS_METHOD_RD | CLS_METHOD_WR,
mirror_image_status_remove_down,
&h_mirror_image_status_remove_down);
+ cls_register_cxx_method(h_class, "mirror_instances_list", CLS_METHOD_RD,
+ mirror_instances_list, &h_mirror_instances_list);
+ cls_register_cxx_method(h_class, "mirror_instances_add",
+ CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE,
+ mirror_instances_add, &h_mirror_instances_add);
+ cls_register_cxx_method(h_class, "mirror_instances_remove",
+ CLS_METHOD_RD | CLS_METHOD_WR,
+ mirror_instances_remove,
+ &h_mirror_instances_remove);
/* methods for the consistency groups feature */
cls_register_cxx_method(h_class, "group_create",
CLS_METHOD_RD | CLS_METHOD_WR,
op->exec("rbd", "mirror_image_status_remove_down", bl);
}
+ void mirror_instances_list_start(librados::ObjectReadOperation *op) {
+ bufferlist bl;
+ op->exec("rbd", "mirror_instances_list", bl);
+ }
+
+ int mirror_instances_list_finish(bufferlist::iterator *iter,
+ std::vector<std::string> *instance_ids) {
+ instance_ids->clear();
+ try {
+ ::decode(*instance_ids, *iter);
+ } catch (const buffer::error &err) {
+ return -EBADMSG;
+ }
+ return 0;
+ }
+
+ int mirror_instances_list(librados::IoCtx *ioctx,
+ std::vector<std::string> *instance_ids) {
+ librados::ObjectReadOperation op;
+ mirror_instances_list_start(&op);
+
+ bufferlist out_bl;
+ int r = ioctx->operate(RBD_MIRROR_LEADER, &op, &out_bl);
+ if (r < 0) {
+ return r;
+ }
+
+ bufferlist::iterator iter = out_bl.begin();
+ r = mirror_instances_list_finish(&iter, instance_ids);
+ if (r < 0) {
+ return r;
+ }
+ return 0;
+ }
+
+ void mirror_instances_add(librados::ObjectWriteOperation *op,
+ const std::string &instance_id) {
+ bufferlist bl;
+ ::encode(instance_id, bl);
+ op->exec("rbd", "mirror_instances_add", bl);
+ }
+
+ int mirror_instances_add(librados::IoCtx *ioctx,
+ const std::string &instance_id) {
+ librados::ObjectWriteOperation op;
+ mirror_instances_add(&op, instance_id);
+ return ioctx->operate(RBD_MIRROR_LEADER, &op);
+ }
+
+ void mirror_instances_remove(librados::ObjectWriteOperation *op,
+ const std::string &instance_id) {
+ bufferlist bl;
+ ::encode(instance_id, bl);
+ op->exec("rbd", "mirror_instances_remove", bl);
+ }
+
+ int mirror_instances_remove(librados::IoCtx *ioctx,
+ const std::string &instance_id) {
+ librados::ObjectWriteOperation op;
+ mirror_instances_remove(&op, instance_id);
+ return ioctx->operate(RBD_MIRROR_LEADER, &op);
+ }
+
// Consistency groups functions
int group_create(librados::IoCtx *ioctx, const std::string &oid)
{
int mirror_image_status_remove_down(librados::IoCtx *ioctx);
void mirror_image_status_remove_down(librados::ObjectWriteOperation *op);
+ void mirror_instances_list_start(librados::ObjectReadOperation *op);
+ int mirror_instances_list_finish(bufferlist::iterator *iter,
+ std::vector<std::string> *instance_ids);
+ int mirror_instances_list(librados::IoCtx *ioctx,
+ std::vector<std::string> *instance_ids);
+ void mirror_instances_add(librados::ObjectWriteOperation *op,
+ const std::string &instance_id);
+ int mirror_instances_add(librados::IoCtx *ioctx,
+ const std::string &instance_id);
+ void mirror_instances_remove(librados::ObjectWriteOperation *op,
+ const std::string &instance_id);
+ int mirror_instances_remove(librados::IoCtx *ioctx,
+ const std::string &instance_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,
ASSERT_EQ(0U, statuses.size());
}
+TEST_F(TestClsRbd, mirror_instances) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+ ioctx.remove(RBD_MIRROR_LEADER);
+
+ std::vector<std::string> instance_ids;
+ ASSERT_EQ(-ENOENT, mirror_instances_list(&ioctx, &instance_ids));
+
+ ASSERT_EQ(0, ioctx.create(RBD_MIRROR_LEADER, true));
+ ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
+ ASSERT_EQ(0U, instance_ids.size());
+
+ ASSERT_EQ(0, mirror_instances_add(&ioctx, "instance_id1"));
+ ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
+ ASSERT_EQ(1U, instance_ids.size());
+ ASSERT_EQ(instance_ids[0], "instance_id1");
+
+ ASSERT_EQ(0, mirror_instances_add(&ioctx, "instance_id1"));
+ ASSERT_EQ(0, mirror_instances_add(&ioctx, "instance_id2"));
+ ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
+ ASSERT_EQ(2U, instance_ids.size());
+
+ ASSERT_EQ(0, mirror_instances_remove(&ioctx, "instance_id1"));
+ ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
+ ASSERT_EQ(1U, instance_ids.size());
+ ASSERT_EQ(instance_ids[0], "instance_id2");
+
+ ASSERT_EQ(0, mirror_instances_remove(&ioctx, "instance_id2"));
+ ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
+ 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));