return 0;
}
+int image_instance_get(cls_method_context_t hctx,
+ const string &global_image_id,
+ const std::set<entity_inst_t> &watchers,
+ entity_inst_t *instance) {
+ bufferlist bl;
+ int r = cls_cxx_map_get_val(hctx, status_global_key(global_image_id), &bl);
+ if (r < 0) {
+ if (r != -ENOENT) {
+ CLS_ERR("error reading status for mirrored image, global id '%s': '%s'",
+ global_image_id.c_str(), cpp_strerror(r).c_str());
+ }
+ return r;
+ }
+
+ MirrorImageStatusOnDisk ondisk_status;
+ try {
+ auto it = bl.cbegin();
+ decode(ondisk_status, it);
+ } catch (const buffer::error &err) {
+ CLS_ERR("could not decode status for mirrored image, global id '%s'",
+ global_image_id.c_str());
+ return -EIO;
+ }
+
+ if (watchers.find(ondisk_status.origin) == watchers.end()) {
+ return -ESTALE;
+ }
+
+ *instance = ondisk_status.origin;
+ return 0;
+}
+
+int image_instance_list(cls_method_context_t hctx,
+ const std::string &start_after,
+ uint64_t max_return,
+ map<std::string, entity_inst_t> *instances) {
+ std::string last_read = image_key(start_after);
+ int max_read = RBD_MAX_KEYS_READ;
+ bool more = true;
+
+ std::set<entity_inst_t> watchers;
+ int r = list_watchers(hctx, &watchers);
+ if (r < 0) {
+ return r;
+ }
+
+ while (more && instances->size() < max_return) {
+ std::map<std::string, bufferlist> vals;
+ CLS_LOG(20, "last_read = '%s'", last_read.c_str());
+ r = cls_cxx_map_get_vals(hctx, last_read, IMAGE_KEY_PREFIX, max_read, &vals,
+ &more);
+ if (r < 0) {
+ CLS_ERR("error reading mirror image directory by name: %s",
+ cpp_strerror(r).c_str());
+ return r;
+ }
+
+ for (auto it = vals.begin(); it != vals.end() &&
+ instances->size() < max_return; ++it) {
+ const std::string &image_id = it->first.substr(IMAGE_KEY_PREFIX.size());
+ cls::rbd::MirrorImage mirror_image;
+ auto iter = it->second.cbegin();
+ try {
+ decode(mirror_image, iter);
+ } catch (const buffer::error &err) {
+ CLS_ERR("could not decode mirror image payload of image '%s'",
+ image_id.c_str());
+ return -EIO;
+ }
+
+ entity_inst_t instance;
+ r = image_instance_get(hctx, mirror_image.global_image_id, watchers,
+ &instance);
+ if (r < 0) {
+ continue;
+ }
+
+ (*instances)[image_id] = instance;
+ }
+ if (!vals.empty()) {
+ last_read = vals.rbegin()->first;
+ }
+ }
+
+ return 0;
+}
+
int instances_list(cls_method_context_t hctx,
std::vector<std::string> *instance_ids) {
std::string last_read = INSTANCE_KEY_PREFIX;
return 0;
}
+/**
+ * Input:
+ * @param global_image_id (std::string)
+ *
+ * Output:
+ * @param entity_inst_t - instance
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_instance_get(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ string global_image_id;
+ try {
+ auto it = in->cbegin();
+ decode(global_image_id, it);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ std::set<entity_inst_t> watchers;
+ int r = mirror::list_watchers(hctx, &watchers);
+ if (r < 0) {
+ return r;
+ }
+
+ entity_inst_t instance;
+ r = mirror::image_instance_get(hctx, global_image_id, watchers, &instance);
+ if (r < 0) {
+ return r;
+ }
+
+ encode(instance, *out, cls_get_features(hctx));
+ return 0;
+}
+
+/**
+ * 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 names to list
+ *
+ * Output:
+ * @param std::map<std::string, entity_inst_t>: image id to instance map
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_instance_list(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::string start_after;
+ uint64_t max_return;
+ try {
+ auto iter = in->cbegin();
+ decode(start_after, iter);
+ decode(max_return, iter);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ map<std::string, entity_inst_t> instances;
+ int r = mirror::image_instance_list(hctx, start_after, max_return,
+ &instances);
+ if (r < 0) {
+ return r;
+ }
+
+ encode(instances, *out, cls_get_features(hctx));
+ return 0;
+}
+
/**
* Input:
* none
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_image_instance_get;
+ cls_method_handle_t h_mirror_image_instance_list;
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_RD | CLS_METHOD_WR,
mirror_image_status_remove_down,
&h_mirror_image_status_remove_down);
+ cls_register_cxx_method(h_class, "mirror_image_instance_get", CLS_METHOD_RD,
+ mirror_image_instance_get,
+ &h_mirror_image_instance_get);
+ cls_register_cxx_method(h_class, "mirror_image_instance_list", CLS_METHOD_RD,
+ mirror_image_instance_list,
+ &h_mirror_image_instance_list);
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",
op->exec("rbd", "mirror_image_status_remove_down", bl);
}
+int mirror_image_instance_get(librados::IoCtx *ioctx,
+ const std::string &global_image_id,
+ entity_inst_t *instance) {
+ librados::ObjectReadOperation op;
+ mirror_image_instance_get_start(&op, global_image_id);
+
+ bufferlist out_bl;
+ int r = ioctx->operate(RBD_MIRRORING, &op, &out_bl);
+ if (r < 0) {
+ return r;
+ }
+
+ auto iter = out_bl.cbegin();
+ r = mirror_image_instance_get_finish(&iter, instance);
+ if (r < 0) {
+ return r;
+ }
+ return 0;
+}
+
+void mirror_image_instance_get_start(librados::ObjectReadOperation *op,
+ const std::string &global_image_id) {
+ bufferlist bl;
+ encode(global_image_id, bl);
+ op->exec("rbd", "mirror_image_instance_get", bl);
+}
+
+int mirror_image_instance_get_finish(bufferlist::const_iterator *iter,
+ entity_inst_t *instance) {
+ try {
+ decode(*instance, *iter);
+ } catch (const buffer::error &err) {
+ return -EBADMSG;
+ }
+ return 0;
+}
+
+int mirror_image_instance_list(
+ librados::IoCtx *ioctx, const std::string &start, uint64_t max_return,
+ std::map<std::string, entity_inst_t> *instances) {
+ librados::ObjectReadOperation op;
+ mirror_image_instance_list_start(&op, start, max_return);
+
+ bufferlist out_bl;
+ int r = ioctx->operate(RBD_MIRRORING, &op, &out_bl);
+ if (r < 0) {
+ return r;
+ }
+
+ auto iter = out_bl.cbegin();
+ r = mirror_image_instance_list_finish(&iter, instances);
+ if (r < 0) {
+ return r;
+ }
+ return 0;
+}
+
+void mirror_image_instance_list_start(librados::ObjectReadOperation *op,
+ const std::string &start,
+ uint64_t max_return) {
+ bufferlist bl;
+ encode(start, bl);
+ encode(max_return, bl);
+ op->exec("rbd", "mirror_image_instance_list", bl);
+}
+
+int mirror_image_instance_list_finish(
+ bufferlist::const_iterator *iter,
+ std::map<std::string, entity_inst_t> *instances) {
+ instances->clear();
+ try {
+ decode(*instances, *iter);
+ } catch (const buffer::error &err) {
+ return -EBADMSG;
+ }
+ return 0;
+}
+
void mirror_instances_list_start(librados::ObjectReadOperation *op) {
bufferlist bl;
op->exec("rbd", "mirror_instances_list", bl);
int mirror_image_status_remove_down(librados::IoCtx *ioctx);
void mirror_image_status_remove_down(librados::ObjectWriteOperation *op);
+int mirror_image_instance_get(librados::IoCtx *ioctx,
+ const std::string &global_image_id,
+ entity_inst_t *instance);
+void mirror_image_instance_get_start(librados::ObjectReadOperation *op,
+ const std::string &global_image_id);
+int mirror_image_instance_get_finish(bufferlist::const_iterator *iter,
+ entity_inst_t *instance);
+int mirror_image_instance_list(librados::IoCtx *ioctx,
+ const std::string &start, uint64_t max_return,
+ std::map<std::string, entity_inst_t> *instances);
+void mirror_image_instance_list_start(librados::ObjectReadOperation *op,
+ const std::string &start,
+ uint64_t max_return);
+int mirror_image_instance_list_finish(bufferlist::const_iterator *iter,
+ std::map<std::string, entity_inst_t> *instances);
+
void mirror_instances_list_start(librados::ObjectReadOperation *op);
int mirror_instances_list_finish(bufferlist::const_iterator *iter,
std::vector<std::string> *instance_ids);
explicit WatchCtx(librados::IoCtx *ioctx) : m_ioctx(ioctx) {}
void handle_notify(uint64_t notify_id, uint64_t cookie,
- uint64_t notifier_id, bufferlist& bl_) override {
+ uint64_t notifier_id, bufferlist& bl_) override {
bufferlist bl;
m_ioctx->notify_ack(RBD_MIRRORING, notify_id, cookie, bl);
}
map<std::string, cls::rbd::MirrorImage> images;
map<std::string, cls::rbd::MirrorImageStatus> statuses;
std::map<cls::rbd::MirrorImageStatusState, int> states;
+ std::map<std::string, entity_inst_t> instances;
cls::rbd::MirrorImageStatus read_status;
+ entity_inst_t read_instance;
uint64_t watch_handle;
librados::IoCtx ioctx;
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
ioctx.remove(RBD_MIRRORING);
+ int64_t instance_id = librados::Rados(ioctx).get_instance_id();
+
// Test list fails on nonexistent RBD_MIRRORING object
ASSERT_EQ(-ENOENT, mirror_image_status_list(&ioctx, "", 1024, &images,
ASSERT_EQ(1U, states.size());
ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
+ // Test get instance return -ESTALE due to down.
+
+ ASSERT_EQ(-ESTALE, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
+ instances.clear();
+ ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances));
+ ASSERT_TRUE(instances.empty());
+
// Test remove_down removes stale statuses
ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx));
ASSERT_EQ(-ENOENT, mirror_image_status_get(&ioctx, "uuid1", &read_status));
+ ASSERT_EQ(-ENOENT, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses));
ASSERT_EQ(3U, images.size());
ASSERT_TRUE(statuses.empty());
ASSERT_EQ(statuses["image_id2"], status2);
ASSERT_EQ(statuses["image_id3"], status3);
+ read_instance = {};
+ ASSERT_EQ(0, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
+ ASSERT_EQ(read_instance.name.num(), instance_id);
+ instances.clear();
+ ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances));
+ ASSERT_EQ(3U, instances.size());
+ ASSERT_EQ(instances["image_id1"].name.num(), instance_id);
+ ASSERT_EQ(instances["image_id2"].name.num(), instance_id);
+ ASSERT_EQ(instances["image_id3"].name.num(), instance_id);
+
ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx));
ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid1", &read_status));
ASSERT_EQ(read_status, status1);
ASSERT_EQ(1U, states.size());
ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
+ ASSERT_EQ(-ESTALE, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
+ instances.clear();
+ ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances));
+ ASSERT_TRUE(instances.empty());
+
ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx));
ASSERT_EQ(-ENOENT, mirror_image_status_get(&ioctx, "uuid1", &read_status));