using ::testing::_;
using ::testing::InSequence;
+using ::testing::Return;
using ::testing::StrEq;
using ::testing::WithArg;
.WillOnce(WithArg<1>(CompleteContext(r)));
}
+ void expect_get_snap_id(librbd::MockImageCtx &mock_remote_image_ctx,
+ const std::string &snap_name, uint64_t snap_id) {
+ EXPECT_CALL(mock_remote_image_ctx, get_snap_id(StrEq(snap_name)))
+ .WillOnce(Return(snap_id));
+ }
+
void expect_image_refresh(librbd::MockImageCtx &mock_remote_image_ctx, int r) {
EXPECT_CALL(*mock_remote_image_ctx.state, refresh(_))
.WillOnce(CompleteContext(r));
journal::MockJournaler mock_journaler;
InSequence seq;
+ expect_get_snap_id(mock_remote_image_ctx, "snap1", 123);
expect_image_refresh(mock_remote_image_ctx, 0);
expect_update_client(mock_journaler, 0);
journal::MockJournaler mock_journaler;
InSequence seq;
+ expect_get_snap_id(mock_remote_image_ctx, "snap1", 123);
expect_snap_remove(mock_remote_image_ctx, "snap2", 0);
expect_image_refresh(mock_remote_image_ctx, 0);
expect_update_client(mock_journaler, 0);
ASSERT_EQ(client_meta, m_client_meta);
}
+TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncInProgressMissingSnapSuccess) {
+ librbd::journal::MirrorPeerClientMeta client_meta;
+ client_meta.sync_points.emplace_front("snap2", "snap1", boost::none);
+ client_meta.sync_points.emplace_front("snap1", boost::none);
+ m_client_meta = client_meta;
+
+ librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+ journal::MockJournaler mock_journaler;
+
+ InSequence seq;
+ expect_get_snap_id(mock_remote_image_ctx, "snap1", CEPH_NOSNAP);
+ expect_snap_remove(mock_remote_image_ctx, "snap2", 0);
+ expect_snap_remove(mock_remote_image_ctx, "snap1", 0);
+ expect_image_refresh(mock_remote_image_ctx, 0);
+ expect_update_client(mock_journaler, 0);
+
+ C_SaferCond ctx;
+ MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+ mock_journaler, false, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+
+ client_meta.sync_points.clear();
+ ASSERT_EQ(client_meta, m_client_meta);
+}
+
+TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncInProgressUnexpectedFromSnapSuccess) {
+ librbd::journal::MirrorPeerClientMeta client_meta;
+ client_meta.sync_points.emplace_front("snap2", "snap1", boost::none);
+ m_client_meta = client_meta;
+
+ librbd::MockImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+ journal::MockJournaler mock_journaler;
+
+ InSequence seq;
+ expect_get_snap_id(mock_remote_image_ctx, "snap2", 124);
+ expect_snap_remove(mock_remote_image_ctx, "snap2", 0);
+ expect_snap_remove(mock_remote_image_ctx, "snap1", 0);
+ expect_image_refresh(mock_remote_image_ctx, 0);
+ expect_update_client(mock_journaler, 0);
+
+ C_SaferCond ctx;
+ MockSyncPointPruneRequest *req = create_request(mock_remote_image_ctx,
+ mock_journaler, false, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+
+ client_meta.sync_points.clear();
+ ASSERT_EQ(client_meta, m_client_meta);
+}
+
TEST_F(TestMockImageSyncSyncPointPruneRequest, SyncCompleteSuccess) {
librbd::journal::MirrorPeerClientMeta client_meta;
client_meta.sync_points.emplace_front("snap1", boost::none);
m_snap_names.push_back(sync_point.from_snap_name);
}
} else {
- // if we have more than one sync point, trim the extras off
+ // if we have more than one sync point or invalid sync points,
+ // trim them off
+ RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock);
std::set<std::string> snap_names;
for (auto it = m_client_meta_copy.sync_points.rbegin();
it != m_client_meta_copy.sync_points.rend(); ++it) {
- MirrorPeerSyncPoint &sync_point =
- m_client_meta_copy.sync_points.back();
+ MirrorPeerSyncPoint &sync_point = *it;
if (&sync_point == &m_client_meta_copy.sync_points.front()) {
- break;
+ if (m_remote_image_ctx->get_snap_id(sync_point.snap_name) ==
+ CEPH_NOSNAP) {
+ derr << ": failed to locate sync point snapshot: "
+ << sync_point.snap_name << dendl;
+ } else if (!sync_point.from_snap_name.empty()) {
+ derr << ": unexpected from_snap_name in primary sync point: "
+ << sync_point.from_snap_name << dendl;
+ } else {
+ // first sync point is OK -- keep it
+ break;
+ }
+ m_invalid_master_sync_point = true;
}
if (snap_names.count(sync_point.snap_name) == 0) {
while (m_client_meta_copy.sync_points.size() > 1) {
m_client_meta_copy.sync_points.pop_back();
}
+ if (m_invalid_master_sync_point) {
+ // all subsequent sync points would have been pruned
+ m_client_meta_copy.sync_points.clear();
+ }
}
bufferlist client_data_bl;