Mutex lock;
Cond cond;
- const ImageCopyRequest<librbd::MockImageCtx>::SnapMap *snap_map;
+ const ImageCopyRequest<librbd::MockImageCtx>::SnapMap *snap_map = nullptr;
std::map<uint64_t, Context *> object_contexts;
ObjectCopyRequest() : lock("lock") {
}
bool complete_object_copy(MockObjectCopyRequest &mock_object_copy_request,
- uint64_t object_num, int r) {
+ uint64_t object_num, int r,
+ std::function<void()> fn = []() {}) {
Mutex::Locker locker(mock_object_copy_request.lock);
while (mock_object_copy_request.object_contexts.count(object_num) == 0) {
if (mock_object_copy_request.cond.WaitInterval(m_local_image_ctx->cct,
}
}
- m_threads->work_queue->queue(mock_object_copy_request.object_contexts[object_num], r);
+ FunctionContext *wrapper_ctx = new FunctionContext(
+ [&mock_object_copy_request, object_num, fn] (int r) {
+ fn();
+ mock_object_copy_request.object_contexts[object_num]->complete(r);
+ });
+ m_threads->work_queue->queue(wrapper_ctx, r);
return true;
}
ASSERT_EQ(0, create_snap("snap1"));
m_client_meta.sync_points = {{"snap1", boost::none}};
+ std::string update_sync_age;;
+ ASSERT_EQ(0, _rados->conf_get("rbd_mirror_sync_point_update_age", update_sync_age));
+ ASSERT_EQ(0, _rados->conf_set("rbd_mirror_sync_point_update_age", "1"));
+ BOOST_SCOPE_EXIT( (update_sync_age) ) {
+ ASSERT_EQ(0, _rados->conf_set("rbd_mirror_sync_point_update_age", update_sync_age.c_str()));
+ } BOOST_SCOPE_EXIT_END;
+
+
+ std::string max_ops_str;
+ ASSERT_EQ(0, _rados->conf_get("rbd_concurrent_management_ops", max_ops_str));
+ int max_ops = std::stoi(max_ops_str);
+
+ uint64_t object_count = 55;
+
librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
journal::MockJournaler mock_journaler;
expect_get_snap_id(mock_remote_image_ctx);
- InSequence seq;
- expect_get_object_count(mock_remote_image_ctx, 50);
+ expect_get_object_count(mock_remote_image_ctx, object_count);
expect_get_object_count(mock_remote_image_ctx, 0);
- expect_update_client(mock_journaler, 0);
- for (int i = 0; i < 50; ++i) {
- expect_object_copy_send(mock_object_copy_request);
- }
- expect_update_client(mock_journaler, 0);
+
+ EXPECT_CALL(mock_object_copy_request, send()).Times(object_count);
+
+ boost::optional<uint64_t> expected_object_number(boost::none);
+ EXPECT_CALL(mock_journaler, update_client(_, _))
+ .WillRepeatedly(
+ Invoke([&expected_object_number, max_ops, object_count, this]
+ (bufferlist data, Context *ctx) {
+ ASSERT_EQ(expected_object_number,
+ m_client_meta.sync_points.front().object_number);
+ if (!expected_object_number) {
+ expected_object_number = (max_ops - 1);
+ } else {
+ expected_object_number = expected_object_number.get() + max_ops;
+ }
+
+ if (expected_object_number.get() > (object_count - 1)) {
+ expected_object_number = (object_count - 1);
+ }
+
+ m_threads->work_queue->queue(ctx, 0);
+ }));
+
C_SaferCond ctx;
MockImageCopyRequest *request = create_request(mock_remote_image_ctx,
&ctx);
request->send();
+ std::function<void()> sleep_fn = [request]() {
+ sleep(2);
+ };
+
ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
- for (uint64_t i = 0; i < 50; ++i) {
- ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, 0));
+ for (uint64_t i = 0; i < object_count; ++i) {
+ if (i % 10 == 0) {
+ ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, 0, sleep_fn));
+ } else {
+ ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, 0));
+ }
}
ASSERT_EQ(0, ctx.wait());
}
ASSERT_EQ(-ECANCELED, ctx.wait());
}
+TEST_F(TestMockImageSyncImageCopyRequest, Cancel_Inflight_Sync) {
+ std::string update_sync_age;;
+ ASSERT_EQ(0, _rados->conf_get("rbd_mirror_sync_point_update_age", update_sync_age));
+ ASSERT_EQ(0, _rados->conf_set("rbd_mirror_sync_point_update_age", "1"));
+ BOOST_SCOPE_EXIT( (update_sync_age) ) {
+ ASSERT_EQ(0, _rados->conf_set("rbd_mirror_sync_point_update_age", update_sync_age.c_str()));
+ } BOOST_SCOPE_EXIT_END;
+
+ std::string max_ops_str;
+ ASSERT_EQ(0, _rados->conf_get("rbd_concurrent_management_ops", max_ops_str));
+ ASSERT_EQ(0, _rados->conf_set("rbd_concurrent_management_ops", "3"));
+ BOOST_SCOPE_EXIT( (max_ops_str) ) {
+ ASSERT_EQ(0, _rados->conf_set("rbd_concurrent_management_ops", max_ops_str.c_str()));
+ } BOOST_SCOPE_EXIT_END;
+
+ ASSERT_EQ(0, create_snap("snap1"));
+ m_client_meta.sync_points = {{"snap1", boost::none}};
+
+ librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+ librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ journal::MockJournaler mock_journaler;
+ MockObjectCopyRequest mock_object_copy_request;
+
+ expect_get_snap_id(mock_remote_image_ctx);
+
+ expect_get_object_count(mock_remote_image_ctx, 10);
+ expect_get_object_count(mock_remote_image_ctx, 0);
+
+ EXPECT_CALL(mock_object_copy_request, send()).Times(6);
+
+ EXPECT_CALL(mock_journaler, update_client(_, _))
+ .WillRepeatedly(Invoke([this] (bufferlist data, Context *ctx) {
+ m_threads->work_queue->queue(ctx, 0);
+ }));
+
+
+ C_SaferCond ctx;
+ MockImageCopyRequest *request = create_request(mock_remote_image_ctx,
+ mock_local_image_ctx,
+ mock_journaler,
+ m_client_meta.sync_points.front(),
+ &ctx);
+ request->send();
+
+ ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
+
+ std::function<void()> cancel_fn = [request]() {
+ sleep(2);
+ request->cancel();
+ };
+
+ ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, 0));
+ ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, 0));
+ ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 2, 0));
+ ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 3, 0, cancel_fn));
+ ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 4, 0));
+ ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 5, 0));
+
+ ASSERT_EQ(-ECANCELED, ctx.wait());
+ ASSERT_EQ(5u, m_client_meta.sync_points.front().object_number.get());
+}
+
TEST_F(TestMockImageSyncImageCopyRequest, Cancel1) {
ASSERT_EQ(0, create_snap("snap1"));
m_client_meta.sync_points = {{"snap1", boost::none}};