#include "tools/rbd_mirror/image_sync/ObjectCopyRequest.cc"
template class rbd::mirror::image_sync::ObjectCopyRequest<librbd::MockTestImageCtx>;
+bool operator==(const SnapContext& rhs, const SnapContext& lhs) {
+ return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps);
+}
+
namespace rbd {
namespace mirror {
namespace image_sync {
using ::testing::_;
+using ::testing::DoAll;
using ::testing::DoDefault;
using ::testing::InSequence;
using ::testing::Invoke;
ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
}
+ void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
+ librados::MockTestMemIoCtxImpl &mock_io_ctx,
+ const librados::snap_set_t &snap_set) {
+ expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR);
+ EXPECT_CALL(mock_io_ctx,
+ list_snaps(mock_image_ctx.image_ctx->get_object_name(0), _))
+ .WillOnce(DoAll(WithArg<1>(Invoke([&snap_set](librados::snap_set_t *out_snap_set) {
+ *out_snap_set = snap_set;
+ })),
+ Return(0)));
+ }
+
void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) {
+ expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR);
auto &expect = EXPECT_CALL(mock_io_ctx,
list_snaps(mock_image_ctx.image_ctx->get_object_name(0),
_));
0, on_finish);
}
+ void expect_set_snap_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
+ uint64_t snap_id) {
+ EXPECT_CALL(mock_io_ctx, set_snap_read(snap_id));
+ }
+
void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, uint64_t offset,
uint64_t length, int r) {
}
void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx,
- uint64_t offset, uint64_t length, int r) {
- auto &expect = EXPECT_CALL(mock_io_ctx, write(_, _, length, offset, _));
+ uint64_t offset, uint64_t length,
+ const SnapContext &snapc, int r) {
+ auto &expect = EXPECT_CALL(mock_io_ctx, write(_, _, length, offset, snapc));
if (r < 0) {
expect.WillOnce(Return(r));
} else {
}
void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx,
- const interval_set<uint64_t> &extents, int r) {
+ const interval_set<uint64_t> &extents,
+ const SnapContext &snapc, int r) {
for (auto extent : extents) {
- expect_write(mock_io_ctx, extent.first, extent.second, r);
+ expect_write(mock_io_ctx, extent.first, extent.second, snapc, r);
if (r < 0) {
break;
}
m_snap_map.rbegin()->second.end());
}
m_snap_map[remote_snap_id] = local_snap_ids;
+ m_remote_snap_ids.push_back(remote_snap_id);
m_local_snap_ids.push_back(local_snap_id);
return 0;
librbd::ImageCtx *m_local_image_ctx;
MockObjectCopyRequest::SnapMap m_snap_map;
+ std::vector<librados::snap_t> m_remote_snap_ids;
std::vector<librados::snap_t> m_local_snap_ids;
};
InSequence seq;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
- expect_write(mock_local_io_ctx, 0, one.range_end(), 0);
+ expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[0], OBJECT_EXISTS, 0);
ASSERT_EQ(0, compare_objects());
}
+TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingStaleSnapSet) {
+ ASSERT_EQ(0, create_snap("one"));
+ ASSERT_EQ(0, create_snap("two"));
+
+ // scribble some data
+ interval_set<uint64_t> one;
+ scribble(m_remote_image_ctx, 10, 102400, &one);
+ ASSERT_EQ(0, create_snap("three"));
+
+ ASSERT_EQ(0, create_snap("sync"));
+ librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+ librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+
+ librbd::MockObjectMap mock_object_map;
+ mock_local_image_ctx.object_map = &mock_object_map;
+
+ expect_test_features(mock_local_image_ctx);
+
+ C_SaferCond ctx;
+ MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
+ mock_local_image_ctx, &ctx);
+
+ librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
+ request->get_remote_io_ctx()));
+ librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
+ request->get_local_io_ctx()));
+
+ librados::clone_info_t dummy_clone_info;
+ dummy_clone_info.cloneid = librados::SNAP_HEAD;
+ dummy_clone_info.size = 123;
+
+ librados::snap_set_t dummy_snap_set1;
+ dummy_snap_set1.clones.push_back(dummy_clone_info);
+
+ dummy_clone_info.size = 234;
+ librados::snap_set_t dummy_snap_set2;
+ dummy_snap_set2.clones.push_back(dummy_clone_info);
+
+ InSequence seq;
+ expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, dummy_snap_set1);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
+ expect_sparse_read(mock_remote_io_ctx, 0, 123, -ENOENT);
+ expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, dummy_snap_set2);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
+ expect_sparse_read(mock_remote_io_ctx, 0, 234, -ENOENT);
+ expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
+ expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
+ expect_write(mock_local_io_ctx, 0, one.range_end(),
+ {m_local_snap_ids[1], {m_local_snap_ids[1],
+ m_local_snap_ids[0]}},
+ 0);
+ expect_update_object_map(mock_local_image_ctx, mock_object_map,
+ m_local_snap_ids[2], OBJECT_EXISTS, 0);
+ expect_update_object_map(mock_local_image_ctx, mock_object_map,
+ m_local_snap_ids[3], OBJECT_EXISTS_CLEAN, 0);
+
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(0, compare_objects());
+}
+
+TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingUpToDateSnapMap) {
+ // scribble some data
+ interval_set<uint64_t> one;
+ scribble(m_remote_image_ctx, 10, 102400, &one);
+
+ ASSERT_EQ(0, create_snap("sync"));
+ librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+ librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+
+ librbd::MockObjectMap mock_object_map;
+ mock_local_image_ctx.object_map = &mock_object_map;
+
+ expect_test_features(mock_local_image_ctx);
+
+ C_SaferCond ctx;
+ MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
+ mock_local_image_ctx, &ctx);
+
+ librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
+ request->get_remote_io_ctx()));
+
+ InSequence seq;
+ expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
+ expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), -ENOENT);
+ expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+
+ request->send();
+ ASSERT_EQ(-ENOENT, ctx.wait());
+}
+
TEST_F(TestMockImageSyncObjectCopyRequest, ReadError) {
// scribble some data
interval_set<uint64_t> one;
InSequence seq;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), -EINVAL);
request->send();
InSequence seq;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
- expect_write(mock_local_io_ctx, 0, one.range_end(), -EINVAL);
+ expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL);
request->send();
ASSERT_EQ(-EINVAL, ctx.wait());
InSequence seq;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
- expect_write(mock_local_io_ctx, 0, one.range_end(), 0);
+ expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[2]);
expect_sparse_read(mock_remote_io_ctx, two, 0);
- expect_write(mock_local_io_ctx, two, 0);
+ expect_write(mock_local_io_ctx, two,
+ {m_local_snap_ids[0], {m_local_snap_ids[0]}}, 0);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[0], OBJECT_EXISTS, 0);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
InSequence seq;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
- expect_write(mock_local_io_ctx, 0, one.range_end(), 0);
+ expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
expect_truncate(mock_local_io_ctx, trim_offset, 0);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[0], OBJECT_EXISTS, 0);
interval_set<uint64_t> one;
scribble(m_remote_image_ctx, 10, 102400, &one);
ASSERT_EQ(0, create_snap("one"));
+ ASSERT_EQ(0, create_snap("two"));
// remove the object
uint64_t object_size = 1 << m_remote_image_ctx->order;
InSequence seq;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
+ expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[1]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
- expect_write(mock_local_io_ctx, 0, one.range_end(), 0);
+ expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
expect_remove(mock_local_io_ctx, 0);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[0], OBJECT_EXISTS, 0);
+ expect_update_object_map(mock_local_image_ctx, mock_object_map,
+ m_local_snap_ids[1], OBJECT_EXISTS_CLEAN, 0);
request->send();
ASSERT_EQ(0, ctx.wait());