return 0;
}
-int image_list_ids(cls_method_context_t hctx, vector<string> *image_ids) {
- string last_read = IMAGE_KEY_PREFIX;
- int max_read = RBD_MAX_KEYS_READ;
- int r = max_read;
- while (r == max_read) {
- set<string> keys;
- r = cls_cxx_map_get_keys(hctx, last_read, max_read, &keys);
- if (r < 0) {
- CLS_ERR("error reading mirrored images: %s", cpp_strerror(r).c_str());
- return r;
- }
-
- for (auto &image_key : keys) {
- if (0 != image_key.compare(0, IMAGE_KEY_PREFIX.size(), IMAGE_KEY_PREFIX)) {
- return 0;
- }
- image_ids->push_back(image_key.substr(IMAGE_KEY_PREFIX.size()));
- }
- }
- return 0;
-}
-
int image_get(cls_method_context_t hctx, const string &image_id,
cls::rbd::MirrorImage *mirror_image) {
bufferlist bl;
/**
* Input:
- * none
+ * @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::vector<std::string>: collection of image_ids
+ * @param std::map<std::string, std::string>: local id to global id map
* @returns 0 on success, negative error code on failure
*/
int mirror_image_list(cls_method_context_t hctx, bufferlist *in,
bufferlist *out) {
- vector<string> image_ids;
- int r = mirror::image_list_ids(hctx, &image_ids);
- if (r < 0) {
- return r;
+ std::string 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;
+ }
+
+ int max_read = RBD_MAX_KEYS_READ;
+ int r = max_read;
+ std::map<std::string, std::string> mirror_images;
+ std::string last_read = mirror::image_key(start_after);
+
+ while (r == max_read && mirror_images.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, mirror::IMAGE_KEY_PREFIX,
+ max_read, &vals);
+ 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(); ++it) {
+ const std::string &image_id =
+ it->first.substr(mirror::IMAGE_KEY_PREFIX.size());
+ cls::rbd::MirrorImage mirror_image;
+ bufferlist::iterator iter = it->second.begin();
+ 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;
+ }
+
+ mirror_images[image_id] = mirror_image.global_image_id;
+ if (mirror_images.size() >= max_return) {
+ break;
+ }
+ }
+ if (!vals.empty()) {
+ last_read = mirror::image_key(mirror_images.rbegin()->first);
+ }
}
- ::encode(image_ids, *out);
+ ::encode(mirror_images, *out);
return 0;
}
}
int mirror_image_list(librados::IoCtx *ioctx,
- std::vector<std::string> *image_ids) {
+ const std::string &start, uint64_t max_return,
+ std::map<std::string, std::string> *mirror_image_ids) {
bufferlist in_bl;
+ ::encode(start, in_bl);
+ ::encode(max_return, in_bl);
+
bufferlist out_bl;
int r = ioctx->exec(RBD_MIRRORING, "rbd", "mirror_image_list", in_bl,
out_bl);
return r;
}
- image_ids->clear();
try {
bufferlist::iterator bl_it = out_bl.begin();
- ::decode(*image_ids, bl_it);
+ ::decode(*mirror_image_ids, bl_it);
} catch (const buffer::error &err) {
return -EBADMSG;
}
const std::string &uuid,
const std::string &cluster_name);
int mirror_image_list(librados::IoCtx *ioctx,
- std::vector<std::string> *image_ids);
+ const std::string &start, uint64_t max_return,
+ std::map<std::string, std::string> *mirror_image_ids);
int mirror_image_get(librados::IoCtx *ioctx, const std::string &image_id,
cls::rbd::MirrorImage *mirror_image);
int mirror_image_set(librados::IoCtx *ioctx, const std::string &image_id,
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
ioctx.remove(RBD_MIRRORING);
- vector<string> image_ids;
- ASSERT_EQ(-ENOENT, mirror_image_list(&ioctx, &image_ids));
+ std::map<std::string, std::string> mirror_image_ids;
+ ASSERT_EQ(-ENOENT, mirror_image_list(&ioctx, "", 0, &mirror_image_ids));
cls::rbd::MirrorImage image1("uuid1", cls::rbd::MIRROR_IMAGE_STATE_ENABLED);
cls::rbd::MirrorImage image2("uuid2", cls::rbd::MIRROR_IMAGE_STATE_DISABLING);
ASSERT_EQ(0, mirror_image_get(&ioctx, "image_id3", &read_image));
ASSERT_EQ(read_image, image3);
- ASSERT_EQ(0, mirror_image_list(&ioctx, &image_ids));
- vector<string> expected_image_ids = {
- {"image_id1"}, {"image_id2"}, {"image_id3"}};
- ASSERT_EQ(expected_image_ids, image_ids);
+ ASSERT_EQ(0, mirror_image_list(&ioctx, "", 1, &mirror_image_ids));
+ std::map<std::string, std::string> expected_mirror_image_ids = {
+ {"image_id1", "uuid1"}};
+ ASSERT_EQ(expected_mirror_image_ids, mirror_image_ids);
+
+ ASSERT_EQ(0, mirror_image_list(&ioctx, "image_id1", 2, &mirror_image_ids));
+ expected_mirror_image_ids = {{"image_id2", "uuid2"}, {"image_id3", "uuid3"}};
+ ASSERT_EQ(expected_mirror_image_ids, mirror_image_ids);
ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id2"));
ASSERT_EQ(-EBUSY, mirror_image_remove(&ioctx, "image_id1"));
- ASSERT_EQ(0, mirror_image_list(&ioctx, &image_ids));
- expected_image_ids = {{"image_id1"}, {"image_id3"}};
- ASSERT_EQ(expected_image_ids, image_ids);
+ ASSERT_EQ(0, mirror_image_list(&ioctx, "", 3, &mirror_image_ids));
+ expected_mirror_image_ids = {{"image_id1", "uuid1"}, {"image_id3", "uuid3"}};
+ ASSERT_EQ(expected_mirror_image_ids, mirror_image_ids);
image1.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
image3.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id1"));
ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id3"));
- ASSERT_EQ(0, mirror_image_list(&ioctx, &image_ids));
- expected_image_ids = {};
- ASSERT_EQ(expected_image_ids, image_ids);
+ ASSERT_EQ(0, mirror_image_list(&ioctx, "", 3, &mirror_image_ids));
+ expected_mirror_image_ids = {};
+ ASSERT_EQ(expected_mirror_image_ids, mirror_image_ids);
}
continue;
}
- // only format 2 images can be mirrored, so only check the format
- // 2 rbd_directory structure
- std::vector<std::string> image_ids;
- r = mirror_image_list(&ioctx, &image_ids);
- if (r < 0) {
- derr << "error listing mirrored images in pool " << pool_name << ": "
- << cpp_strerror(r) << dendl;
- continue;
- }
+ std::set<std::string> image_ids;
+ std::string last_read = "";
+ int max_read = 1024;
+ do {
+ std::map<std::string, std::string> mirror_images;
+ r = mirror_image_list(&ioctx, last_read, max_read, &mirror_images);
+ if (r < 0) {
+ derr << "error listing mirrored image directory: "
+ << cpp_strerror(r) << dendl;
+ continue;
+ }
+ for (auto it = mirror_images.begin(); it != mirror_images.end(); ++it) {
+ image_ids.insert(it->first);
+ }
+ if (!mirror_images.empty()) {
+ last_read = mirror_images.rbegin()->first;
+ }
+ r = mirror_images.size();
+ } while (r == max_read);
if (!image_ids.empty()) {
- std::set<std::string> image_set(image_ids.begin(), image_ids.end());
- images[pool_id] = std::move(image_set);
+ images[pool_id] = std::move(image_ids);
}
}