#include "librbd/Operations.h"
#include "librbd/api/DiffIterate.h"
#include "librbd/api/Group.h"
+#include "librbd/api/Image.h"
#include "librbd/api/Mirror.h"
#include "librbd/io/AioCompletion.h"
#include "librbd/io/ImageRequestWQ.h"
return r;
}
+ int Image::deep_copy(IoCtx& dest_io_ctx, const char *destname,
+ ImageOptions& opts)
+ {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ tracepoint(librbd, deep_copy_enter, ictx, ictx->name.c_str(),
+ ictx->snap_name.c_str(), ictx->read_only,
+ dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(),
+ destname, opts.opts);
+ librbd::NoOpProgressContext prog_ctx;
+ int r = librbd::api::Image<>::deep_copy(ictx, dest_io_ctx, destname, opts,
+ prog_ctx);
+ tracepoint(librbd, deep_copy_exit, r);
+ return r;
+ }
+
+ int Image::deep_copy_with_progress(IoCtx& dest_io_ctx, const char *destname,
+ ImageOptions& opts,
+ librbd::ProgressContext &prog_ctx)
+ {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ tracepoint(librbd, deep_copy_enter, ictx, ictx->name.c_str(),
+ ictx->snap_name.c_str(), ictx->read_only,
+ dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(),
+ destname, opts.opts);
+ int r = librbd::api::Image<>::deep_copy(ictx, dest_io_ctx, destname, opts,
+ prog_ctx);
+ tracepoint(librbd, deep_copy_exit, r);
+ return r;
+ }
+
int Image::flatten()
{
ImageCtx *ictx = (ImageCtx *)ctx;
return ret;
}
+extern "C" int rbd_deep_copy(rbd_image_t image, rados_ioctx_t dest_p,
+ const char *destname, rbd_image_options_t c_opts)
+{
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ librados::IoCtx dest_io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
+ tracepoint(librbd, deep_copy_enter, ictx, ictx->name.c_str(),
+ ictx->snap_name.c_str(), ictx->read_only,
+ dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(),
+ destname, c_opts);
+ librbd::ImageOptions opts(c_opts);
+ librbd::NoOpProgressContext prog_ctx;
+ int r = librbd::api::Image<>::deep_copy(ictx, dest_io_ctx, destname, opts,
+ prog_ctx);
+ tracepoint(librbd, deep_copy_exit, r);
+ return r;
+}
+
+extern "C" int rbd_deep_copy_with_progress(rbd_image_t image,
+ rados_ioctx_t dest_p,
+ const char *destname,
+ rbd_image_options_t dest_opts,
+ librbd_progress_fn_t fn, void *data)
+{
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ librados::IoCtx dest_io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
+ tracepoint(librbd, deep_copy_enter, ictx, ictx->name.c_str(),
+ ictx->snap_name.c_str(), ictx->read_only,
+ dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(),
+ destname, dest_opts);
+ librbd::ImageOptions opts(dest_opts);
+ librbd::CProgressContext prog_ctx(fn, data);
+ int ret = librbd::api::Image<>::deep_copy(ictx, dest_io_ctx, destname, opts,
+ prog_ctx);
+ tracepoint(librbd, deep_copy_exit, ret);
+ return ret;
+}
extern "C" int rbd_flatten(rbd_image_t image)
{
ioctx.close();
}
+TEST_F(TestLibRBD, TestDeepCopy)
+{
+ REQUIRE_FORMAT_V2();
+
+ rados_ioctx_t ioctx;
+ rados_ioctx_create(_cluster, create_pool(true).c_str(), &ioctx);
+ BOOST_SCOPE_EXIT_ALL( (&ioctx) ) {
+ rados_ioctx_destroy(ioctx);
+ };
+
+ rbd_image_t image;
+ rbd_image_t image2;
+ rbd_image_t image3;
+ int order = 0;
+ std::string name = get_temp_image_name();
+ std::string name2 = get_temp_image_name();
+ std::string name3 = get_temp_image_name();
+
+ uint64_t size = 2 << 20;
+
+ rbd_image_options_t opts;
+ rbd_image_options_create(&opts);
+ BOOST_SCOPE_EXIT_ALL( (&opts) ) {
+ rbd_image_options_destroy(opts);
+ };
+
+ ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
+ ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
+ BOOST_SCOPE_EXIT_ALL( (&image) ) {
+ ASSERT_EQ(0, rbd_close(image));
+ };
+ ASSERT_EQ(1, test_ls(ioctx, 1, name.c_str()));
+
+ size_t sum_key_len = 0;
+ size_t sum_value_len = 0;
+ std::string key;
+ std::string val;
+ for (int i = 1; i <= 70; i++) {
+ key = "key" + stringify(i);
+ val = "value" + stringify(i);
+ ASSERT_EQ(0, rbd_metadata_set(image, key.c_str(), val.c_str()));
+
+ sum_key_len += (key.size() + 1);
+ sum_value_len += (val.size() + 1);
+ }
+
+ char keys[1024];
+ char vals[1024];
+ size_t keys_len = sizeof(keys);
+ size_t vals_len = sizeof(vals);
+
+ char value[1024];
+ size_t value_len = sizeof(value);
+
+ ASSERT_EQ(0, rbd_deep_copy(image, ioctx, name2.c_str(), opts));
+ ASSERT_EQ(2, test_ls(ioctx, 2, name.c_str(), name2.c_str()));
+ ASSERT_EQ(0, rbd_open(ioctx, name2.c_str(), &image2, NULL));
+ BOOST_SCOPE_EXIT_ALL( (&image2) ) {
+ ASSERT_EQ(0, rbd_close(image2));
+ };
+ ASSERT_EQ(0, rbd_metadata_list(image2, "", 70, keys, &keys_len, vals,
+ &vals_len));
+ ASSERT_EQ(keys_len, sum_key_len);
+ ASSERT_EQ(vals_len, sum_value_len);
+
+ for (int i = 1; i <= 70; i++) {
+ key = "key" + stringify(i);
+ val = "value" + stringify(i);
+ ASSERT_EQ(0, rbd_metadata_get(image2, key.c_str(), value, &value_len));
+ ASSERT_STREQ(val.c_str(), value);
+
+ value_len = sizeof(value);
+ }
+
+ ASSERT_EQ(0, rbd_deep_copy_with_progress(image, ioctx, name3.c_str(), opts,
+ print_progress_percent, NULL));
+ ASSERT_EQ(3, test_ls(ioctx, 3, name.c_str(), name2.c_str(), name3.c_str()));
+
+ keys_len = sizeof(keys);
+ vals_len = sizeof(vals);
+ ASSERT_EQ(0, rbd_open(ioctx, name3.c_str(), &image3, NULL));
+ BOOST_SCOPE_EXIT_ALL( (&image3) ) {
+ ASSERT_EQ(0, rbd_close(image3));
+ };
+ ASSERT_EQ(0, rbd_metadata_list(image3, "", 70, keys, &keys_len, vals,
+ &vals_len));
+ ASSERT_EQ(keys_len, sum_key_len);
+ ASSERT_EQ(vals_len, sum_value_len);
+
+ for (int i = 1; i <= 70; i++) {
+ key = "key" + stringify(i);
+ val = "value" + stringify(i);
+ ASSERT_EQ(0, rbd_metadata_get(image3, key.c_str(), value, &value_len));
+ ASSERT_STREQ(val.c_str(), value);
+
+ value_len = sizeof(value);
+ }
+}
+
+TEST_F(TestLibRBD, TestDeepCopyPP)
+{
+ REQUIRE_FORMAT_V2();
+
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(create_pool(true).c_str(), ioctx));
+
+ {
+ librbd::RBD rbd;
+ librbd::Image image;
+ librbd::Image image2;
+ librbd::Image image3;
+ int order = 0;
+ std::string name = get_temp_image_name();
+ std::string name2 = get_temp_image_name();
+ std::string name3 = get_temp_image_name();
+ uint64_t size = 2 << 20;
+ librbd::ImageOptions opts;
+ PrintProgress pp;
+
+ ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
+ ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
+
+ std::string key;
+ std::string val;
+ for (int i = 1; i <= 70; i++) {
+ key = "key" + stringify(i);
+ val = "value" + stringify(i);
+ ASSERT_EQ(0, image.metadata_set(key, val));
+ }
+
+ ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name.c_str()));
+ ASSERT_EQ(0, image.deep_copy(ioctx, name2.c_str(), opts));
+ ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name.c_str(), name2.c_str()));
+ ASSERT_EQ(0, rbd.open(ioctx, image2, name2.c_str(), NULL));
+
+ map<string, bufferlist> pairs;
+ std::string value;
+ ASSERT_EQ(0, image2.metadata_list("", 70, &pairs));
+ ASSERT_EQ(70U, pairs.size());
+
+ for (int i = 1; i <= 70; i++) {
+ key = "key" + stringify(i);
+ val = "value" + stringify(i);
+ ASSERT_EQ(0, image2.metadata_get(key.c_str(), &value));
+ ASSERT_STREQ(val.c_str(), value.c_str());
+ }
+
+ ASSERT_EQ(0, image.deep_copy_with_progress(ioctx, name3.c_str(), opts, pp));
+ ASSERT_EQ(3, test_ls_pp(rbd, ioctx, 3, name.c_str(), name2.c_str(),
+ name3.c_str()));
+ ASSERT_EQ(0, rbd.open(ioctx, image3, name3.c_str(), NULL));
+
+ pairs.clear();
+ ASSERT_EQ(0, image3.metadata_list("", 70, &pairs));
+ ASSERT_EQ(70U, pairs.size());
+
+ for (int i = 1; i <= 70; i++) {
+ key = "key" + stringify(i);
+ val = "value" + stringify(i);
+ ASSERT_EQ(0, image3.metadata_get(key.c_str(), &value));
+ ASSERT_STREQ(val.c_str(), value.c_str());
+ }
+ }
+
+ ioctx.close();
+}
+
int test_ls_snaps(rbd_image_t image, int num_expected, ...)
{
int num_snaps, i, j, max_size = 10;