})));
}
- void expect_mirror_uuid_get(librados::IoCtx &io_ctx,
- const std::string &uuid, int r) {
- bufferlist out_bl;
- encode(uuid, out_bl);
-
- EXPECT_CALL(get_mock_io_ctx(io_ctx),
- exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_uuid_get"),
- _, _, _))
- .WillOnce(DoAll(WithArg<5>(Invoke([out_bl](bufferlist *bl) {
- *bl = out_bl;
- })),
- Return(r)));
- }
-
void expect_timer_add_event(MockThreads &mock_threads) {
EXPECT_CALL(*mock_threads.timer, add_event_after(_, _))
.WillOnce(DoAll(WithArg<1>(Invoke([this](Context *ctx) {
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
{"global id 2", "remote id 2"}};
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, image_ids, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", image_ids, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
m_cond.notify_all();
}));
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
image_ids = {
expect_listener_handle_update(mock_listener, "remote uuid", image_ids, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
mock_pool_watcher.init(nullptr);
{
{"global id 2", "remote id 2"}};
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, image_ids, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
EXPECT_CALL(*mock_threads.work_queue, queue(_, _))
.WillOnce(Invoke([this](Context *ctx, int r) {
{{"global id 1", "remote id 1"}, {"global id 2", "remote id 2"}});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
MockListener mock_listener(this);
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(-EBLACKLISTED, ctx.wait());
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(-ENOENT, ctx.wait());
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
MockListener mock_listener(this);
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(-EBLACKLISTED, ctx.wait());
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, {}, -ENOENT);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
- C_SaferCond ctx;
- mock_pool_watcher.init(&ctx);
- ASSERT_EQ(0, ctx.wait());
-
- ASSERT_TRUE(wait_for_update(1));
- expect_mirroring_watcher_unregister(mock_mirroring_watcher, 0);
- ASSERT_EQ(0, when_shut_down(mock_pool_watcher));
-}
-
-TEST_F(TestMockPoolWatcher, GetMirrorUuidBlacklist) {
- MockThreads mock_threads(m_threads);
- expect_work_queue(mock_threads);
-
- InSequence seq;
- MockMirroringWatcher mock_mirroring_watcher;
- expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
- expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
-
- MockRefreshImagesRequest mock_refresh_images_request;
- expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", -EBLACKLISTED);
-
- MockListener mock_listener(this);
- MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
- C_SaferCond ctx;
- mock_pool_watcher.init(&ctx);
- ASSERT_EQ(-EBLACKLISTED, ctx.wait());
- ASSERT_TRUE(mock_pool_watcher.is_blacklisted());
-
- expect_mirroring_watcher_unregister(mock_mirroring_watcher, 0);
- ASSERT_EQ(0, when_shut_down(mock_pool_watcher));
-}
-
-TEST_F(TestMockPoolWatcher, GetMirrorUuidMissing) {
- MockThreads mock_threads(m_threads);
- expect_work_queue(mock_threads);
-
- InSequence seq;
- MockMirroringWatcher mock_mirroring_watcher;
- expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
- expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
-
- MockRefreshImagesRequest mock_refresh_images_request;
- expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "", -ENOENT);
- expect_timer_add_event(mock_threads);
-
- expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
- expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
-
- MockListener mock_listener(this);
- expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
-
- MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
- C_SaferCond ctx;
- mock_pool_watcher.init(&ctx);
- ASSERT_EQ(-ENOENT, ctx.wait());
-
- ASSERT_TRUE(wait_for_update(1));
- expect_mirroring_watcher_unregister(mock_mirroring_watcher, 0);
- ASSERT_EQ(0, when_shut_down(mock_pool_watcher));
-}
-
-TEST_F(TestMockPoolWatcher, GetMirrorUuidError) {
- MockThreads mock_threads(m_threads);
- expect_work_queue(mock_threads);
-
- InSequence seq;
- MockMirroringWatcher mock_mirroring_watcher;
- expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
- expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
-
- MockRefreshImagesRequest mock_refresh_images_request;
- expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", -EINVAL);
- expect_timer_add_event(mock_threads);
-
- expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
- expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
-
- MockListener mock_listener(this);
- expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
-
- MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
expect_timer_add_event(mock_threads);
expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
expect_refresh_images(mock_refresh_images_request, {{"global id", "image id"}}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
expect_listener_handle_update(mock_listener, "remote uuid",
{{"global id", "image id"}}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
MockRefreshImagesRequest mock_refresh_images_request;
expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
expect_timer_add_event(mock_threads);
expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
expect_refresh_images(mock_refresh_images_request, {{"global id", "image id"}}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
expect_listener_handle_update(mock_listener, "remote uuid",
{{"global id", "image id"}}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
MirroringWatcher::get_instance().handle_rewatch_complete(0);
mock_refresh_images_request.on_finish->complete(0);
}));
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
expect_timer_add_event(mock_threads);
expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
expect_refresh_images(mock_refresh_images_request, {}, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
MockListener mock_listener(this);
expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
- C_SaferCond ctx;
- mock_pool_watcher.init(&ctx);
- ASSERT_EQ(0, ctx.wait());
- ASSERT_TRUE(wait_for_update(1));
-
- expect_mirroring_watcher_unregister(mock_mirroring_watcher, 0);
- ASSERT_EQ(0, when_shut_down(mock_pool_watcher));
-}
-
-TEST_F(TestMockPoolWatcher, MirrorUuidUpdated) {
- MockThreads mock_threads(m_threads);
- expect_work_queue(mock_threads);
-
- InSequence seq;
- MockMirroringWatcher mock_mirroring_watcher;
- expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
- expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
-
- ImageIds image_ids{
- {"global id 1", "remote id 1"},
- {"global id 2", "remote id 2"}};
- MockRefreshImagesRequest mock_refresh_images_request;
- expect_refresh_images(mock_refresh_images_request, image_ids, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "remote uuid", 0);
-
- MockListener mock_listener(this);
- expect_listener_handle_update(mock_listener, "remote uuid", image_ids, {});
-
- MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
- mock_listener);
+ "remote uuid", mock_listener);
C_SaferCond ctx;
mock_pool_watcher.init(&ctx);
ASSERT_EQ(0, ctx.wait());
-
ASSERT_TRUE(wait_for_update(1));
- expect_timer_add_event(mock_threads);
- ImageIds new_image_ids{
- {"global id 1", "remote id 1"}};
- expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
- expect_refresh_images(mock_refresh_images_request, new_image_ids, 0);
- expect_mirror_uuid_get(m_remote_io_ctx, "updated uuid", 0);
- expect_listener_handle_update(mock_listener, "remote uuid", {}, image_ids);
- expect_listener_handle_update(mock_listener, "updated uuid", new_image_ids,
- {});
-
- MirroringWatcher::get_instance().handle_rewatch_complete(0);
- ASSERT_TRUE(wait_for_update(2));
-
expect_mirroring_watcher_unregister(mock_mirroring_watcher, 0);
ASSERT_EQ(0, when_shut_down(mock_pool_watcher));
}
}
void handle_image_updated(cls::rbd::MirrorImageState state,
- const std::string &remote_image_id,
+ const std::string &image_id,
const std::string &global_image_id) override {
bool enabled = (state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED);
- m_pool_watcher->handle_image_updated(remote_image_id, global_image_id,
+ m_pool_watcher->handle_image_updated(image_id, global_image_id,
enabled);
}
};
template <typename I>
-PoolWatcher<I>::PoolWatcher(Threads<I> *threads, librados::IoCtx &remote_io_ctx,
+PoolWatcher<I>::PoolWatcher(Threads<I> *threads,
+ librados::IoCtx &io_ctx,
+ const std::string& mirror_uuid,
pool_watcher::Listener &listener)
- : m_threads(threads), m_remote_io_ctx(remote_io_ctx), m_listener(listener),
- m_lock(ceph::make_mutex(librbd::util::unique_lock_name("rbd::mirror::PoolWatcher", this))) {
- m_mirroring_watcher = new MirroringWatcher(m_remote_io_ctx,
+ : m_threads(threads),
+ m_io_ctx(io_ctx),
+ m_mirror_uuid(mirror_uuid),
+ m_listener(listener),
+ m_lock(ceph::make_mutex(librbd::util::unique_lock_name(
+ "rbd::mirror::PoolWatcher", this))) {
+ m_mirroring_watcher = new MirroringWatcher(m_io_ctx,
m_threads->work_queue, this);
}
m_refresh_image_ids.clear();
Context *ctx = create_context_callback<
PoolWatcher, &PoolWatcher<I>::handle_refresh_images>(this);
- auto req = pool_watcher::RefreshImagesRequest<I>::create(m_remote_io_ctx,
+ auto req = pool_watcher::RefreshImagesRequest<I>::create(m_io_ctx,
&m_refresh_image_ids,
ctx);
req->send();
void PoolWatcher<I>::handle_refresh_images(int r) {
dout(5) << "r=" << r << dendl;
- bool retry_refresh = false;
- Context *on_init_finish = nullptr;
- {
- std::lock_guard locker{m_lock};
- ceph_assert(m_image_ids_invalid);
- ceph_assert(m_refresh_in_progress);
-
- if (r >= 0) {
- m_pending_image_ids = std::move(m_refresh_image_ids);
- } else if (r == -EBLACKLISTED) {
- dout(0) << "detected client is blacklisted during image refresh" << dendl;
-
- m_blacklisted = true;
- m_refresh_in_progress = false;
- std::swap(on_init_finish, m_on_init_finish);
- } else if (r == -ENOENT) {
- dout(5) << "mirroring directory not found" << dendl;
- m_pending_image_ids.clear();
- r = 0;
- } else {
- m_refresh_in_progress = false;
- retry_refresh = true;
- }
- }
-
- if (retry_refresh) {
- derr << "failed to retrieve mirroring directory: " << cpp_strerror(r)
- << dendl;
- schedule_refresh_images(10);
- } else if (r >= 0) {
- get_mirror_uuid();
- return;
- }
-
- m_async_op_tracker.finish_op();
- if (on_init_finish != nullptr) {
- ceph_assert(r == -EBLACKLISTED);
- on_init_finish->complete(r);
- }
-}
-
-template <typename I>
-void PoolWatcher<I>::get_mirror_uuid() {
- dout(5) << dendl;
-
- librados::ObjectReadOperation op;
- librbd::cls_client::mirror_uuid_get_start(&op);
-
- m_out_bl.clear();
- librados::AioCompletion *aio_comp = create_rados_callback<
- PoolWatcher, &PoolWatcher<I>::handle_get_mirror_uuid>(this);
- int r = m_remote_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl);
- ceph_assert(r == 0);
- aio_comp->release();
-}
-
-template <typename I>
-void PoolWatcher<I>::handle_get_mirror_uuid(int r) {
- dout(5) << "r=" << r << dendl;
-
bool deferred_refresh = false;
bool retry_refresh = false;
Context *on_init_finish = nullptr;
ceph_assert(m_refresh_in_progress);
m_refresh_in_progress = false;
- m_pending_mirror_uuid = "";
- if (r >= 0) {
- auto it = m_out_bl.cbegin();
- r = librbd::cls_client::mirror_uuid_get_finish(
- &it, &m_pending_mirror_uuid);
- }
- if (r >= 0 && m_pending_mirror_uuid.empty()) {
- r = -ENOENT;
+ if (r == -ENOENT) {
+ dout(5) << "mirroring directory not found" << dendl;
+ r = 0;
+ m_refresh_image_ids.clear();
}
if (m_deferred_refresh) {
// need to refresh -- skip the notification
deferred_refresh = true;
} else if (r >= 0) {
- dout(10) << "mirror_uuid=" << m_pending_mirror_uuid << dendl;
+ m_pending_image_ids = std::move(m_refresh_image_ids);
m_image_ids_invalid = false;
std::swap(on_init_finish, m_on_init_finish);
+
schedule_listener();
} else if (r == -EBLACKLISTED) {
dout(0) << "detected client is blacklisted during image refresh" << dendl;
m_blacklisted = true;
std::swap(on_init_finish, m_on_init_finish);
- } else if (r == -ENOENT) {
- dout(5) << "mirroring uuid not found" << dendl;
- std::swap(on_init_finish, m_on_init_finish);
- retry_refresh = true;
} else {
retry_refresh = true;
}
dout(5) << "scheduling deferred refresh" << dendl;
schedule_refresh_images(0);
} else if (retry_refresh) {
- derr << "failed to retrieve mirror uuid: " << cpp_strerror(r)
+ derr << "failed to retrieve mirroring directory: " << cpp_strerror(r)
<< dendl;
schedule_refresh_images(10);
}
}
template <typename I>
-void PoolWatcher<I>::handle_image_updated(const std::string &remote_image_id,
- const std::string &global_image_id,
- bool enabled) {
- dout(10) << "remote_image_id=" << remote_image_id << ", "
+void PoolWatcher<I>::handle_image_updated(const std::string &id,
+ const std::string &global_image_id,
+ bool enabled) {
+ dout(10) << "image_id=" << id << ", "
<< "global_image_id=" << global_image_id << ", "
<< "enabled=" << enabled << dendl;
std::lock_guard locker{m_lock};
- ImageId image_id(global_image_id, remote_image_id);
+ ImageId image_id(global_image_id, id);
m_pending_added_image_ids.erase(image_id);
m_pending_removed_image_ids.erase(image_id);
{
std::lock_guard locker{m_lock};
ceph_assert(m_notify_listener_in_progress);
-
- // if the mirror uuid is updated, treat it as the removal of all
- // images in the pool
- if (m_mirror_uuid != m_pending_mirror_uuid) {
- if (!m_mirror_uuid.empty()) {
- dout(0) << "mirror uuid updated:"
- << "old=" << m_mirror_uuid << ", "
- << "new=" << m_pending_mirror_uuid << dendl;
- }
-
- mirror_uuid = m_mirror_uuid;
- removed_image_ids = std::move(m_image_ids);
- m_image_ids.clear();
- }
}
if (!removed_image_ids.empty()) {
m_pending_updates = false;
m_image_ids = m_pending_image_ids;
-
- m_mirror_uuid = m_pending_mirror_uuid;
- mirror_uuid = m_mirror_uuid;
}
- m_listener.handle_update(mirror_uuid, std::move(added_image_ids),
+ m_listener.handle_update(m_mirror_uuid, std::move(added_image_ids),
std::move(removed_image_ids));
{