DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_image>(this);
m_image_copy_request = ImageCopyRequest<I>::create(
m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_start, m_src_snap_id_end,
- m_flatten, m_object_number, *m_snap_seqs, m_prog_ctx, ctx);
+ m_dst_snap_id_start, m_flatten, m_object_number, *m_snap_seqs, m_prog_ctx,
+ ctx);
m_image_copy_request->get();
m_lock.Unlock();
ImageCopyRequest<I>::ImageCopyRequest(I *src_image_ctx, I *dst_image_ctx,
librados::snap_t src_snap_id_start,
librados::snap_t src_snap_id_end,
+ librados::snap_t dst_snap_id_start,
bool flatten,
const ObjectNumber &object_number,
const SnapSeqs &snap_seqs,
Context *on_finish)
: RefCountedObject(dst_image_ctx->cct, 1), m_src_image_ctx(src_image_ctx),
m_dst_image_ctx(dst_image_ctx), m_src_snap_id_start(src_snap_id_start),
- m_src_snap_id_end(src_snap_id_end), m_flatten(flatten),
- m_object_number(object_number), m_snap_seqs(snap_seqs),
+ m_src_snap_id_end(src_snap_id_end), m_dst_snap_id_start(dst_snap_id_start),
+ m_flatten(flatten), m_object_number(object_number), m_snap_seqs(snap_seqs),
m_prog_ctx(prog_ctx), m_on_finish(on_finish), m_cct(dst_image_ctx->cct),
m_lock(unique_lock_name("ImageCopyRequest::m_lock", this)) {
}
handle_object_copy(ono, r);
});
ObjectCopyRequest<I> *req = ObjectCopyRequest<I>::create(
- m_src_image_ctx, m_dst_image_ctx, m_snap_map, ono, m_flatten, ctx);
+ m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_start, m_dst_snap_id_start,
+ m_snap_map, ono, m_flatten, ctx);
req->send();
}
ImageCtxT *dst_image_ctx,
librados::snap_t src_snap_id_start,
librados::snap_t src_snap_id_end,
+ librados::snap_t dst_snap_id_start,
bool flatten,
const ObjectNumber &object_number,
const SnapSeqs &snap_seqs,
ProgressContext *prog_ctx,
Context *on_finish) {
return new ImageCopyRequest(src_image_ctx, dst_image_ctx, src_snap_id_start,
- src_snap_id_end, flatten, object_number,
- snap_seqs, prog_ctx, on_finish);
+ src_snap_id_end, dst_snap_id_start, flatten,
+ object_number, snap_seqs, prog_ctx, on_finish);
}
ImageCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx,
librados::snap_t src_snap_id_start,
librados::snap_t src_snap_id_end,
+ librados::snap_t dst_snap_id_start,
bool flatten, const ObjectNumber &object_number,
const SnapSeqs &snap_seqs, ProgressContext *prog_ctx,
Context *on_finish);
ImageCtxT *m_dst_image_ctx;
librados::snap_t m_src_snap_id_start;
librados::snap_t m_src_snap_id_end;
+ librados::snap_t m_dst_snap_id_start;
bool m_flatten;
ObjectNumber m_object_number;
SnapSeqs m_snap_seqs;
template <typename I>
ObjectCopyRequest<I>::ObjectCopyRequest(I *src_image_ctx,
I *dst_image_ctx,
+ librados::snap_t src_snap_id_start,
+ librados::snap_t dst_snap_id_start,
const SnapMap &snap_map,
uint64_t dst_object_number,
bool flatten, Context *on_finish)
: m_src_image_ctx(src_image_ctx),
m_dst_image_ctx(dst_image_ctx), m_cct(dst_image_ctx->cct),
- m_snap_map(snap_map), m_dst_object_number(dst_object_number),
- m_flatten(flatten), m_on_finish(on_finish) {
+ m_src_snap_id_start(src_snap_id_start),
+ m_dst_snap_id_start(dst_snap_id_start), m_snap_map(snap_map),
+ m_dst_object_number(dst_object_number), m_flatten(flatten),
+ m_on_finish(on_finish) {
ceph_assert(src_image_ctx->data_ctx.is_valid());
ceph_assert(dst_image_ctx->data_ctx.is_valid());
ceph_assert(!m_snap_map.empty());
}
// write snapshot context should be before actual snapshot
- if (snap_map_it != m_snap_map.begin()) {
- --snap_map_it;
- ceph_assert(!snap_map_it->second.empty());
- dst_snap_seq = snap_map_it->second.front();
- dst_snap_ids = snap_map_it->second;
+ ceph_assert(!snap_map_it->second.empty());
+ auto dst_snap_ids_it = snap_map_it->second.begin();
+ ++dst_snap_ids_it;
+
+ dst_snap_ids = SnapIds{dst_snap_ids_it, snap_map_it->second.end()};
+ if (!dst_snap_ids.empty()) {
+ dst_snap_seq = dst_snap_ids.front();
}
+ ceph_assert(dst_snap_seq != CEPH_NOSNAP);
}
ldout(m_cct, 20) << "dst_snap_seq=" << dst_snap_seq << ", "
m_src_image_ctx->parent_lock.put_read();
librados::snap_t src_copy_point_snap_id = m_snap_map.rbegin()->first;
- bool prev_exists = hide_parent;
+ bool prev_exists = (hide_parent || m_src_snap_id_start > 0);
uint64_t prev_end_size = prev_exists ?
m_src_image_ctx->layout.object_size : 0;
- librados::snap_t start_src_snap_id = 0;
+ librados::snap_t start_src_snap_id = m_src_snap_id_start;
for (auto &pair : m_snap_map) {
ceph_assert(!pair.second.empty());
public:
static ObjectCopyRequest* create(ImageCtxT *src_image_ctx,
ImageCtxT *dst_image_ctx,
+ librados::snap_t src_snap_id_start,
+ librados::snap_t dst_snap_id_start,
const SnapMap &snap_map,
uint64_t object_number, bool flatten,
Context *on_finish) {
- return new ObjectCopyRequest(src_image_ctx, dst_image_ctx, snap_map,
+ return new ObjectCopyRequest(src_image_ctx, dst_image_ctx,
+ src_snap_id_start, dst_snap_id_start, snap_map,
object_number, flatten, on_finish);
}
ObjectCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx,
- const SnapMap &snap_map, uint64_t object_number,
- bool flatten, Context *on_finish);
+ librados::snap_t src_snap_id_start,
+ librados::snap_t dst_snap_id_start, const SnapMap &snap_map,
+ uint64_t object_number, bool flatten, Context *on_finish);
void send();
ImageCtxT *m_src_image_ctx;
ImageCtxT *m_dst_image_ctx;
CephContext *m_cct;
+ librados::snap_t m_src_snap_id_start;
+ librados::snap_t m_dst_snap_id_start;
SnapMap m_snap_map;
uint64_t m_dst_object_number;
bool m_flatten;
auto ctx = util::create_context_callback<
CopyupRequest<I>, &CopyupRequest<I>::handle_deep_copy>(this);
auto req = deep_copy::ObjectCopyRequest<I>::create(
- m_image_ctx->parent, m_image_ctx, m_image_ctx->migration_info.snap_map,
- m_object_no, m_flatten, ctx);
+ m_image_ctx->parent, m_image_ctx, 0, 0,
+ m_image_ctx->migration_info.snap_map, m_object_no, m_flatten, ctx);
req->send();
}
ceph_assert(image_ctx.parent != nullptr);
auto req = deep_copy::ObjectCopyRequest<I>::create(
- image_ctx.parent, &image_ctx, image_ctx.migration_info.snap_map,
+ image_ctx.parent, &image_ctx, 0, 0, image_ctx.migration_info.snap_map,
m_object_no, image_ctx.migration_info.flatten, ctx);
ldout(cct, 20) << "deep copy object req " << req << ", object_no "
static ObjectCopyRequest* s_instance;
static ObjectCopyRequest* create(
librbd::MockTestImageCtx *src_image_ctx,
- librbd::MockTestImageCtx *dst_image_ctx, const SnapMap &snap_map,
+ librbd::MockTestImageCtx *dst_image_ctx,
+ librados::snap_t src_snap_id_start,
+ librados::snap_t dst_snap_id_start,
+ const SnapMap &snap_map,
uint64_t object_number, bool flatten, Context *on_finish) {
ceph_assert(s_instance != nullptr);
Mutex::Locker locker(s_instance->lock);
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- 0, snap_id_end, false, boost::none,
+ 0, snap_id_end, 0, false, boost::none,
m_snap_seqs, &no_op, &ctx);
request->send();
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- 0, snap_id_end, false, boost::none,
+ 0, snap_id_end, 0, false, boost::none,
m_snap_seqs, &prog_ctx, &ctx);
request->send();
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- snap_id_start, snap_id_end, false,
+ snap_id_start, snap_id_end, 0, false,
boost::none, m_snap_seqs, &no_op,
&ctx);
request->send();
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- 0, snap_id_end, false,
+ 0, snap_id_end, 0, false,
librbd::deep_copy::ObjectNumber{0U},
m_snap_seqs, &no_op, &ctx);
request->send();
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- 0, snap_id_end, false, boost::none,
+ 0, snap_id_end, 0, false, boost::none,
m_snap_seqs, &no_op, &ctx);
request->send();
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- 0, snap_id_end, false, boost::none,
+ 0, snap_id_end, 0, false, boost::none,
m_snap_seqs, &prog_ctx, &ctx);
request->send();
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- 0, 123, false, boost::none,
+ 0, 123, 0, false, boost::none,
m_snap_seqs, &no_op, &ctx);
request->send();
ASSERT_EQ(-EINVAL, ctx.wait());
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- 123, snap_id_end, false, boost::none,
- m_snap_seqs, &no_op, &ctx);
+ 123, snap_id_end, 0, false,
+ boost::none, m_snap_seqs, &no_op,
+ &ctx);
request->send();
ASSERT_EQ(-EINVAL, ctx.wait());
}
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- snap_id_start, snap_id_end, false,
+ snap_id_start, snap_id_end, 0, false,
boost::none, {{0, 0}}, &no_op, &ctx);
request->send();
ASSERT_EQ(-EINVAL, ctx.wait());
C_SaferCond ctx;
auto request = new MockImageCopyRequest(&mock_src_image_ctx,
&mock_dst_image_ctx,
- snap_id_start, snap_id_end, false,
+ snap_id_start, snap_id_end, 0, false,
boost::none, {}, &no_op, &ctx);
request->send();
ASSERT_EQ(-EINVAL, ctx.wait());
MockObjectCopyRequest *create_request(
librbd::MockTestImageCtx &mock_src_image_ctx,
- librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish) {
+ librbd::MockTestImageCtx &mock_dst_image_ctx,
+ librados::snap_t src_snap_id_start,
+ librados::snap_t dst_snap_id_start,
+ Context *on_finish) {
expect_get_object_name(mock_dst_image_ctx);
return new MockObjectCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx,
+ src_snap_id_start, dst_snap_id_start,
m_snap_map, 0, false, on_finish);
}
return it->first.second;
}
+ int copy_objects() {
+ int r;
+ uint64_t object_size = 1 << m_src_image_ctx->order;
+
+ bufferlist bl;
+ bl.append(std::string(object_size, '1'));
+ r = m_src_image_ctx->io_work_queue->read(
+ 0, object_size, librbd::io::ReadResult{&bl}, 0);
+ if (r < 0) {
+ return r;
+ }
+
+ r = m_dst_image_ctx->io_work_queue->write(0, object_size, std::move(bl), 0);
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
+ }
+
int compare_objects() {
SnapMap snap_map(m_snap_map);
if (snap_map.empty()) {
}
if (!src_bl.contents_equal(dst_bl)) {
+ std::cout << "src block: " << std::endl; src_bl.hexdump(std::cout);
+ std::cout << "dst block: " << std::endl; dst_bl.hexdump(std::cout);
return -EBADMSG;
}
}
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
C_SaferCond ctx;
MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
- mock_dst_image_ctx, &ctx);
+ mock_dst_image_ctx, 0, 0,
+ &ctx);
librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
request->get_src_io_ctx()));
ASSERT_EQ(-EBLACKLISTED, ctx.wait());
}
+TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnapsStart) {
+ // scribble some data
+ interval_set<uint64_t> one;
+ scribble(m_src_image_ctx, 10, 102400, &one);
+ ASSERT_EQ(0, copy_objects());
+ ASSERT_EQ(0, create_snap("one"));
+
+ auto src_snap_id_start = m_src_image_ctx->snaps[0];
+ auto dst_snap_id_start = m_dst_image_ctx->snaps[0];
+
+ interval_set<uint64_t> two;
+ scribble(m_src_image_ctx, 10, 102400, &two);
+ ASSERT_EQ(0, create_snap("two"));
+
+ interval_set<uint64_t> three;
+ scribble(m_src_image_ctx, 10, 102400, &three);
+ ASSERT_EQ(0, create_snap("three"));
+
+ auto max_extent = one.range_end();
+ if (max_extent < two.range_end()) {
+ interval_set<uint64_t> resize_diff;
+ resize_diff.insert(max_extent, two.range_end() - max_extent);
+ two.union_of(resize_diff);
+ }
+
+ max_extent = std::max(max_extent, two.range_end());
+ if (max_extent < three.range_end()) {
+ interval_set<uint64_t> resize_diff;
+ resize_diff.insert(max_extent, three.range_end() - max_extent);
+ three.union_of(resize_diff);
+ }
+
+ interval_set<uint64_t> four;
+ scribble(m_src_image_ctx, 10, 102400, &four);
+
+ // map should begin after src start and src end's dst snap seqs should
+ // point to HEAD revision
+ m_snap_map.erase(src_snap_id_start);
+ m_snap_map[m_src_image_ctx->snaps[0]][0] = CEPH_NOSNAP;
+
+ librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
+ librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
+
+ librbd::MockObjectMap mock_object_map;
+ mock_dst_image_ctx.object_map = &mock_object_map;
+
+ expect_test_features(mock_dst_image_ctx);
+ expect_get_object_count(mock_dst_image_ctx);
+
+ C_SaferCond ctx;
+ MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
+ mock_dst_image_ctx,
+ src_snap_id_start,
+ dst_snap_id_start,
+ &ctx);
+
+ librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
+ request->get_src_io_ctx()));
+ librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx(
+ request->get_dst_io_ctx()));
+
+ InSequence seq;
+ expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
+
+ expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[1]);
+ expect_sparse_read(mock_src_io_ctx, two, 0);
+
+ expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[2]);
+ expect_sparse_read(mock_src_io_ctx, three, 0);
+
+ expect_start_op(mock_exclusive_lock);
+ expect_write(mock_dst_io_ctx, two,
+ {m_dst_snap_ids[0], {m_dst_snap_ids[0]}}, 0);
+
+ expect_start_op(mock_exclusive_lock);
+ expect_write(mock_dst_io_ctx, three,
+ {m_dst_snap_ids[1], {m_dst_snap_ids[1], m_dst_snap_ids[0]}}, 0);
+
+ expect_start_op(mock_exclusive_lock);
+ expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+ m_dst_snap_ids[1], OBJECT_EXISTS, 0);
+
+ expect_start_op(mock_exclusive_lock);
+ expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+ CEPH_NOSNAP, OBJECT_EXISTS, 0);
+
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(0, compare_objects());
+}
+
} // namespace deep_copy
} // namespace librbd
static ObjectCopyRequest* s_instance;
static ObjectCopyRequest* create(librbd::MockImageCtx* parent_image_ctx,
librbd::MockTestImageCtx* image_ctx,
+ librados::snap_t src_snap_id_start,
+ librados::snap_t dst_snap_id_start,
const SnapMap &snap_map,
uint64_t object_number, bool flatten,
Context *on_finish) {
static ImageCopyRequest* create(
librbd::MockTestImageCtx *src_image_ctx,
- librbd::MockTestImageCtx *dst_image_ctx, librados::snap_t snap_id_start,
- librados::snap_t snap_id_end, bool flatten,
- const ObjectNumber &object_number, const SnapSeqs &snap_seqs,
- ProgressContext *prog_ctx,
+ librbd::MockTestImageCtx *dst_image_ctx,
+ librados::snap_t src_snap_id_start,
+ librados::snap_t src_snap_id_end,
+ librados::snap_t dst_snap_id_start,
+ bool flatten, const ObjectNumber &object_number,
+ const SnapSeqs &snap_seqs, ProgressContext *prog_ctx,
Context *on_finish) {
ceph_assert(s_instance != nullptr);
s_instance->on_finish = on_finish;