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_");
+static const std::string MIRROR_IMAGE_MAP_KEY_PREFIX("image_map_");
std::string peer_key(const std::string &uuid) {
return PEER_KEY_PREFIX + uuid;
return INSTANCE_KEY_PREFIX + instance_id;
}
+std::string mirror_image_map_key(const string& global_image_id) {
+ return MIRROR_IMAGE_MAP_KEY_PREFIX + global_image_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 mirror_image_map_list(cls_method_context_t hctx,
+ const std::string &start_after,
+ uint64_t max_return,
+ std::map<std::string, cls::rbd::MirrorImageMap> *image_mapping) {
+ bool more = true;
+ std::string last_read = mirror_image_map_key(start_after);
+
+ while (more && image_mapping->size() < max_return) {
+ std::map<std::string, bufferlist> vals;
+ CLS_LOG(20, "last read: '%s'", last_read.c_str());
+
+ int max_read = MIN(RBD_MAX_KEYS_READ, max_return - image_mapping->size());
+ int r = cls_cxx_map_get_vals(hctx, last_read, MIRROR_IMAGE_MAP_KEY_PREFIX,
+ max_read, &vals, &more);
+ if (r < 0) {
+ CLS_ERR("error reading image map: %s", cpp_strerror(r).c_str());
+ return r;
+ }
+
+ if (vals.empty()) {
+ return 0;
+ }
+
+ for (auto it = vals.begin(); it != vals.end(); ++it) {
+ const std::string &global_image_id =
+ it->first.substr(MIRROR_IMAGE_MAP_KEY_PREFIX.size());
+
+ cls::rbd::MirrorImageMap mirror_image_map;
+ bufferlist::iterator iter = it->second.begin();
+ try {
+ ::decode(mirror_image_map, iter);
+ } catch (const buffer::error &err) {
+ CLS_ERR("could not decode image map payload: %s", cpp_strerror(r).c_str());
+ return -EINVAL;
+ }
+
+ image_mapping->insert(std::make_pair(global_image_id, mirror_image_map));
+ }
+
+ if (!vals.empty()) {
+ last_read = mirror_image_map_key(vals.rbegin()->first);
+ }
+ }
+
+ return 0;
+}
+
} // namespace mirror
/**
return 0;
}
+/**
+ * Input:
+ * @param start_after: key to start after
+ * @param max_return: max return items
+ *
+ * Output:
+ * @param std::map<std::string, cls::rbd::MirrorImageMap>: image mapping
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_map_list(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::string start_after;
+ uint64_t max_return;
+ try {
+ bufferlist::iterator it = in->begin();
+ ::decode(start_after, it);
+ ::decode(max_return, it);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ std::map<std::string, cls::rbd::MirrorImageMap> image_mapping;
+ int r = mirror::mirror_image_map_list(hctx, start_after, max_return, &image_mapping);
+ if (r < 0) {
+ return r;
+ }
+
+ ::encode(image_mapping, *out);
+ return 0;
+}
+
+/**
+ * Input:
+ * @param global_image_id: global image id
+ * @param image_map: image map
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_map_update(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::string global_image_id;
+ cls::rbd::MirrorImageMap image_map;
+
+ try {
+ bufferlist::iterator it = in->begin();
+ ::decode(global_image_id, it);
+ ::decode(image_map, it);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ bufferlist bl;
+ ::encode(image_map, bl);
+
+ const std::string key = mirror::mirror_image_map_key(global_image_id);
+ int r = cls_cxx_map_set_val(hctx, key, &bl);
+ if (r < 0) {
+ CLS_ERR("error updating image map %s: %s", key.c_str(),
+ cpp_strerror(r).c_str());
+ return r;
+ }
+
+ return 0;
+}
+
+/**
+ * Input:
+ * @param global_image_id: global image id
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_map_remove(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::string global_image_id;
+
+ try {
+ bufferlist::iterator it = in->begin();
+ ::decode(global_image_id, it);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ const std::string key = mirror::mirror_image_map_key(global_image_id);
+ int r = cls_cxx_map_remove_key(hctx, key);
+ if (r < 0 && r != -ENOENT) {
+ CLS_ERR("error removing image map %s: %s", key.c_str(),
+ cpp_strerror(r).c_str());
+ 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_instances_list;
cls_method_handle_t h_mirror_instances_add;
cls_method_handle_t h_mirror_instances_remove;
+ cls_method_handle_t h_mirror_image_map_list;
+ cls_method_handle_t h_mirror_image_map_update;
+ cls_method_handle_t h_mirror_image_map_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_instances_remove,
&h_mirror_instances_remove);
+ cls_register_cxx_method(h_class, "mirror_image_map_list",
+ CLS_METHOD_RD, mirror_image_map_list,
+ &h_mirror_image_map_list);
+ cls_register_cxx_method(h_class, "mirror_image_map_update",
+ CLS_METHOD_WR, mirror_image_map_update,
+ &h_mirror_image_map_update);
+ cls_register_cxx_method(h_class, "mirror_image_map_remove",
+ 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,
return ioctx->operate(RBD_MIRROR_LEADER, &op);
}
+ void mirror_image_map_list_start(librados::ObjectReadOperation *op,
+ const std::string &start_after,
+ uint64_t max_read) {
+ bufferlist bl;
+ ::encode(start_after, bl);
+ ::encode(max_read, bl);
+
+ op->exec("rbd", "mirror_image_map_list", bl);
+ }
+
+ int mirror_image_map_list_finish(bufferlist::iterator *iter,
+ std::map<std::string, cls::rbd::MirrorImageMap> *image_mapping) {
+ try {
+ ::decode(*image_mapping, *iter);
+ } catch (const buffer::error &err) {
+ return -EBADMSG;
+ }
+ return 0;
+ }
+
+ void mirror_image_map_update(librados::ObjectWriteOperation *op,
+ const std::string &global_image_id,
+ const cls::rbd::MirrorImageMap &image_map) {
+ bufferlist bl;
+ ::encode(global_image_id, bl);
+ ::encode(image_map, bl);
+
+ op->exec("rbd", "mirror_image_map_update", bl);
+ }
+
+ void mirror_image_map_remove(librados::ObjectWriteOperation *op,
+ const std::string &global_image_id) {
+ bufferlist bl;
+ ::encode(global_image_id, bl);
+
+ op->exec("rbd", "mirror_image_map_remove", bl);
+ }
+
// Consistency groups functions
int group_create(librados::IoCtx *ioctx, const std::string &oid)
{
f->dump_unsigned("deferment_end_time", deferment_end_time);
}
+void MirrorImageMap::encode(bufferlist &bl) const {
+ ENCODE_START(1, 1, bl);
+ ::encode(instance_id, bl);
+ ::encode(data, bl);
+ ENCODE_FINISH(bl);
+}
+
+void MirrorImageMap::decode(bufferlist::iterator &it) {
+ DECODE_START(1, it);
+ ::decode(instance_id, it);
+ ::decode(data, it);
+ DECODE_FINISH(it);
+}
+
+void MirrorImageMap::dump(Formatter *f) const {
+ f->dump_string("instance_id", instance_id);
+
+ std::stringstream data_ss;
+ data.hexdump(data_ss);
+ f->dump_string("data", data_ss.str());
+}
+
+void MirrorImageMap::generate_test_instances(
+ std::list<MirrorImageMap*> &o) {
+ bufferlist data;
+ data.append(std::string(128, '1'));
+
+ o.push_back(new MirrorImageMap("uuid-123", data));
+ o.push_back(new MirrorImageMap("uuid-abc", data));
+}
+
+bool MirrorImageMap::operator==(const MirrorImageMap &rhs) const {
+ return instance_id == rhs.instance_id && data.contents_equal(data);
+}
+
+bool MirrorImageMap::operator<(const MirrorImageMap &rhs) const {
+ return instance_id < rhs.instance_id;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const MirrorImageMap &image_map) {
+ return os << "["
+ << "instance_id=" << image_map.instance_id << "]";
+}
+
} // namespace rbd
} // namespace cls