1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph distributed storage system
6 * Copyright (C) 2016 Mirantis Inc
8 * Author: Mykola Golub <mgolub@mirantis.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
17 #include "include/rados/librados.hpp"
18 #include "include/rbd/librbd.hpp"
19 #include "include/stringify.h"
20 #include "test/librbd/test_support.h"
21 #include "test/rbd_mirror/test_fixture.h"
22 #include "cls/journal/cls_journal_types.h"
23 #include "cls/journal/cls_journal_client.h"
24 #include "cls/rbd/cls_rbd_types.h"
25 #include "cls/rbd/cls_rbd_client.h"
26 #include "journal/Journaler.h"
27 #include "librbd/ExclusiveLock.h"
28 #include "librbd/ImageCtx.h"
29 #include "librbd/ImageState.h"
30 #include "librbd/Journal.h"
31 #include "librbd/Operations.h"
32 #include "librbd/Utils.h"
33 #include "librbd/internal.h"
34 #include "librbd/api/Mirror.h"
35 #include "librbd/api/Snapshot.h"
36 #include "librbd/io/AioCompletion.h"
37 #include "librbd/io/ImageRequestWQ.h"
38 #include "librbd/io/ReadResult.h"
39 #include "tools/rbd_mirror/ImageReplayer.h"
40 #include "tools/rbd_mirror/InstanceWatcher.h"
41 #include "tools/rbd_mirror/MirrorStatusUpdater.h"
42 #include "tools/rbd_mirror/PoolMetaCache.h"
43 #include "tools/rbd_mirror/Threads.h"
44 #include "tools/rbd_mirror/Throttler.h"
45 #include "tools/rbd_mirror/Types.h"
47 #include "test/librados/test_cxx.h"
48 #include "gtest/gtest.h"
50 void register_test_rbd_mirror() {
53 #define TEST_IO_SIZE 512
54 #define TEST_IO_COUNT 11
60 class TestImageReplayer
: public TestFixture
{
62 static const cls::rbd::MirrorImageMode MIRROR_IMAGE_MODE
=
64 static const uint64_t FEATURES
= T::FEATURES
;
66 struct C_WatchCtx
: public librados::WatchCtx2
{
67 TestImageReplayer
*test
;
69 ceph::mutex lock
= ceph::make_mutex("C_WatchCtx::lock");
70 ceph::condition_variable cond
;
73 C_WatchCtx(TestImageReplayer
*test
, const std::string
&oid
)
74 : test(test
), oid(oid
), notified(false) {
77 void handle_notify(uint64_t notify_id
, uint64_t cookie
,
78 uint64_t notifier_id
, bufferlist
& bl_
) override
{
80 test
->m_remote_ioctx
.notify_ack(oid
, notify_id
, cookie
, bl
);
82 std::lock_guard locker
{lock
};
87 void handle_error(uint64_t cookie
, int err
) override
{
93 : m_local_cluster(new librados::Rados()), m_watch_handle(0)
95 EXPECT_EQ("", connect_cluster_pp(*m_local_cluster
.get()));
96 EXPECT_EQ(0, m_local_cluster
->conf_set("rbd_cache", "false"));
97 EXPECT_EQ(0, m_local_cluster
->conf_set("rbd_mirror_journal_poll_age", "1"));
98 EXPECT_EQ(0, m_local_cluster
->conf_set("rbd_mirror_journal_commit_age",
100 m_local_pool_name
= get_temp_pool_name();
101 EXPECT_EQ(0, m_local_cluster
->pool_create(m_local_pool_name
.c_str()));
102 EXPECT_EQ(0, m_local_cluster
->ioctx_create(m_local_pool_name
.c_str(),
104 m_local_ioctx
.application_enable("rbd", true);
106 EXPECT_EQ("", connect_cluster_pp(m_remote_cluster
));
107 EXPECT_EQ(0, m_remote_cluster
.conf_set("rbd_cache", "false"));
109 m_remote_pool_name
= get_temp_pool_name();
110 EXPECT_EQ(0, m_remote_cluster
.pool_create(m_remote_pool_name
.c_str()));
111 m_remote_pool_id
= m_remote_cluster
.pool_lookup(m_remote_pool_name
.c_str());
112 EXPECT_GE(m_remote_pool_id
, 0);
114 EXPECT_EQ(0, m_remote_cluster
.ioctx_create(m_remote_pool_name
.c_str(),
116 m_remote_ioctx
.application_enable("rbd", true);
118 // make snap id debugging easier when local/remote have different mappings
120 EXPECT_EQ(0, m_remote_ioctx
.selfmanaged_snap_create(&snap_id
));
122 uint64_t features
= FEATURES
;
123 if (MIRROR_IMAGE_MODE
== cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
) {
124 EXPECT_EQ(0, librbd::api::Mirror
<>::mode_set(m_remote_ioctx
,
125 RBD_MIRROR_MODE_POOL
));
126 EXPECT_EQ(0, librbd::api::Mirror
<>::mode_set(m_local_ioctx
,
127 RBD_MIRROR_MODE_POOL
));
129 EXPECT_EQ(0, librbd::api::Mirror
<>::mode_set(m_remote_ioctx
,
130 RBD_MIRROR_MODE_IMAGE
));
131 EXPECT_EQ(0, librbd::api::Mirror
<>::mode_set(m_local_ioctx
,
132 RBD_MIRROR_MODE_IMAGE
));
136 uuid_gen
.generate_random();
137 std::string remote_peer_uuid
= uuid_gen
.to_string();
139 EXPECT_EQ(0, librbd::cls_client::mirror_peer_add(
140 &m_remote_ioctx
, {remote_peer_uuid
,
141 cls::rbd::MIRROR_PEER_DIRECTION_RX_TX
,
142 "siteA", "client", m_local_mirror_uuid
}));
144 m_pool_meta_cache
.set_remote_pool_meta(
145 m_remote_ioctx
.get_id(), {m_remote_mirror_uuid
, remote_peer_uuid
});
148 EXPECT_EQ(0, librbd::api::Mirror
<>::uuid_get(m_remote_ioctx
,
149 &m_remote_mirror_uuid
));
150 EXPECT_EQ(0, librbd::api::Mirror
<>::uuid_get(m_local_ioctx
,
151 &m_local_mirror_uuid
));
153 m_image_name
= get_temp_image_name();
155 EXPECT_EQ(0, librbd::create(m_remote_ioctx
, m_image_name
.c_str(), 1 << 22,
156 false, features
, &order
, 0, 0));
158 if (MIRROR_IMAGE_MODE
!= cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
) {
159 librbd::ImageCtx
* remote_image_ctx
;
160 open_remote_image(&remote_image_ctx
);
162 librbd::api::Mirror
<>::image_enable(
164 static_cast<rbd_mirror_image_mode_t
>(MIRROR_IMAGE_MODE
),
166 close_image(remote_image_ctx
);
169 m_remote_image_id
= get_image_id(m_remote_ioctx
, m_image_name
);
170 m_global_image_id
= get_global_image_id(m_remote_ioctx
, m_remote_image_id
);
172 auto cct
= reinterpret_cast<CephContext
*>(m_local_ioctx
.cct());
173 m_threads
.reset(new Threads
<>(cct
));
175 m_image_sync_throttler
.reset(new Throttler
<>(
176 cct
, "rbd_mirror_concurrent_image_syncs"));
178 m_instance_watcher
= InstanceWatcher
<>::create(
179 m_local_ioctx
, m_threads
->work_queue
, nullptr,
180 m_image_sync_throttler
.get());
181 m_instance_watcher
->handle_acquire_leader();
183 EXPECT_EQ(0, m_local_ioctx
.create(RBD_MIRRORING
, false));
185 m_local_status_updater
= MirrorStatusUpdater
<>::create(
186 m_local_ioctx
, m_threads
.get(), "");
187 C_SaferCond status_updater_ctx
;
188 m_local_status_updater
->init(&status_updater_ctx
);
189 EXPECT_EQ(0, status_updater_ctx
.wait());
192 ~TestImageReplayer() override
196 m_instance_watcher
->handle_release_leader();
199 delete m_instance_watcher
;
201 C_SaferCond status_updater_ctx
;
202 m_local_status_updater
->shut_down(&status_updater_ctx
);
203 EXPECT_EQ(0, status_updater_ctx
.wait());
204 delete m_local_status_updater
;
206 EXPECT_EQ(0, m_remote_cluster
.pool_delete(m_remote_pool_name
.c_str()));
207 EXPECT_EQ(0, m_local_cluster
->pool_delete(m_local_pool_name
.c_str()));
210 void create_replayer() {
211 m_replayer
= new ImageReplayer
<>(m_local_ioctx
, m_local_mirror_uuid
,
212 m_global_image_id
, m_threads
.get(),
213 m_instance_watcher
, m_local_status_updater
,
214 nullptr, &m_pool_meta_cache
);
215 m_replayer
->add_peer({"peer uuid", m_remote_ioctx
,
216 {m_remote_mirror_uuid
, "remote mirror peer uuid"},
223 m_replayer
->start(&cond
);
224 ASSERT_EQ(0, cond
.wait());
229 void create_watch_ctx() {
231 if (MIRROR_IMAGE_MODE
== cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
) {
232 oid
= ::journal::Journaler::header_oid(m_remote_image_id
);
234 oid
= librbd::util::header_name(m_remote_image_id
);
237 ASSERT_EQ(0U, m_watch_handle
);
238 ASSERT_TRUE(m_watch_ctx
== nullptr);
239 m_watch_ctx
= new C_WatchCtx(this, oid
);
240 ASSERT_EQ(0, m_remote_ioctx
.watch2(oid
, &m_watch_handle
, m_watch_ctx
));
244 if (m_watch_handle
!= 0) {
245 m_remote_ioctx
.unwatch2(m_watch_handle
);
247 m_watch_ctx
= nullptr;
257 m_replayer
->stop(&cond
);
258 ASSERT_EQ(0, cond
.wait());
266 wait_for_replay_complete();
270 std::string
get_temp_image_name()
272 return "image" + stringify(++_image_number
);
275 std::string
get_image_id(librados::IoCtx
&ioctx
, const string
&image_name
)
277 std::string obj
= librbd::util::id_obj_name(image_name
);
279 EXPECT_EQ(0, librbd::cls_client::get_id(&ioctx
, obj
, &id
));
283 std::string
get_global_image_id(librados::IoCtx
& io_ctx
,
284 const std::string
& image_id
) {
285 cls::rbd::MirrorImage mirror_image
;
286 EXPECT_EQ(0, librbd::cls_client::mirror_image_get(&io_ctx
, image_id
,
288 return mirror_image
.global_image_id
;
291 void open_image(librados::IoCtx
&ioctx
, const std::string
&image_name
,
292 bool readonly
, librbd::ImageCtx
**ictxp
)
294 librbd::ImageCtx
*ictx
= new librbd::ImageCtx(image_name
.c_str(),
295 "", "", ioctx
, readonly
);
296 EXPECT_EQ(0, ictx
->state
->open(0));
300 void open_local_image(librbd::ImageCtx
**ictxp
)
302 open_image(m_local_ioctx
, m_image_name
, true, ictxp
);
305 void open_remote_image(librbd::ImageCtx
**ictxp
)
307 open_image(m_remote_ioctx
, m_image_name
, false, ictxp
);
310 void close_image(librbd::ImageCtx
*ictx
)
312 ictx
->state
->close();
315 void get_commit_positions(cls::journal::ObjectPosition
*master_position
,
316 cls::journal::ObjectPosition
*mirror_position
)
318 std::string master_client_id
= "";
319 std::string mirror_client_id
= m_local_mirror_uuid
;
324 uint64_t minimum_set
;
326 std::set
<cls::journal::Client
> registered_clients
;
327 std::string oid
= ::journal::Journaler::header_oid(m_remote_image_id
);
328 cls::journal::client::get_mutable_metadata(m_remote_ioctx
, oid
,
329 &minimum_set
, &active_set
,
330 ®istered_clients
, &cond
);
331 ASSERT_EQ(0, cond
.wait());
333 *master_position
= cls::journal::ObjectPosition();
334 *mirror_position
= cls::journal::ObjectPosition();
336 std::set
<cls::journal::Client
>::const_iterator c
;
337 for (c
= registered_clients
.begin(); c
!= registered_clients
.end(); ++c
) {
338 std::cout
<< __func__
<< ": client: " << *c
<< std::endl
;
339 if (c
->state
!= cls::journal::CLIENT_STATE_CONNECTED
) {
342 cls::journal::ObjectPositions object_positions
=
343 c
->commit_position
.object_positions
;
344 cls::journal::ObjectPositions::const_iterator p
=
345 object_positions
.begin();
346 if (p
!= object_positions
.end()) {
347 if (c
->id
== master_client_id
) {
348 ASSERT_EQ(cls::journal::ObjectPosition(), *master_position
);
349 *master_position
= *p
;
350 } else if (c
->id
== mirror_client_id
) {
351 ASSERT_EQ(cls::journal::ObjectPosition(), *mirror_position
);
352 *mirror_position
= *p
;
358 bool wait_for_watcher_notify(int seconds
)
360 if (m_watch_handle
== 0) {
364 std::unique_lock locker
{m_watch_ctx
->lock
};
365 while (!m_watch_ctx
->notified
) {
366 if (m_watch_ctx
->cond
.wait_for(locker
,
367 std::chrono::seconds(seconds
)) ==
368 std::cv_status::timeout
) {
372 m_watch_ctx
->notified
= false;
376 int get_last_mirror_snapshot(librados::IoCtx
& io_ctx
,
377 const std::string
& image_id
,
378 uint64_t* mirror_snap_id
,
379 cls::rbd::MirrorSnapshotNamespace
* mirror_ns
) {
380 auto header_oid
= librbd::util::header_name(image_id
);
382 int r
= librbd::cls_client::get_snapcontext(&io_ctx
, header_oid
, &snapc
);
387 // stored in reverse order
388 for (auto snap_id
: snapc
.snaps
) {
389 cls::rbd::SnapshotInfo snap_info
;
390 r
= librbd::cls_client::snapshot_get(&io_ctx
, header_oid
, snap_id
,
396 auto ns
= boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
397 &snap_info
.snapshot_namespace
);
399 *mirror_snap_id
= snap_id
;
408 void wait_for_journal_synced() {
409 cls::journal::ObjectPosition master_position
;
410 cls::journal::ObjectPosition mirror_position
;
411 for (int i
= 0; i
< 100; i
++) {
412 get_commit_positions(&master_position
, &mirror_position
);
413 if (master_position
== mirror_position
) {
416 wait_for_watcher_notify(1);
419 ASSERT_EQ(master_position
, mirror_position
);
422 void wait_for_snapshot_synced() {
423 uint64_t remote_snap_id
= CEPH_NOSNAP
;
424 cls::rbd::MirrorSnapshotNamespace remote_mirror_ns
;
425 ASSERT_EQ(0, get_last_mirror_snapshot(m_remote_ioctx
, m_remote_image_id
,
426 &remote_snap_id
, &remote_mirror_ns
));
428 std::cout
<< "remote_snap_id=" << remote_snap_id
<< std::endl
;
430 std::string local_image_id
;
431 ASSERT_EQ(0, librbd::cls_client::mirror_image_get_image_id(
432 &m_local_ioctx
, m_global_image_id
, &local_image_id
));
434 uint64_t local_snap_id
= CEPH_NOSNAP
;
435 cls::rbd::MirrorSnapshotNamespace local_mirror_ns
;
436 for (int i
= 0; i
< 100; i
++) {
437 int r
= get_last_mirror_snapshot(m_local_ioctx
, local_image_id
,
438 &local_snap_id
, &local_mirror_ns
);
440 ((remote_mirror_ns
.state
==
441 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY
&&
442 local_mirror_ns
.state
==
443 cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY
) ||
444 (remote_mirror_ns
.state
==
445 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED
&&
446 local_mirror_ns
.state
==
447 cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED
)) &&
448 local_mirror_ns
.primary_mirror_uuid
== m_remote_mirror_uuid
&&
449 local_mirror_ns
.primary_snap_id
== remote_snap_id
&&
450 local_mirror_ns
.complete
) {
452 std::cout
<< "local_snap_id=" << local_snap_id
<< ", "
453 << "local_snap_ns=" << local_mirror_ns
<< std::endl
;
457 wait_for_watcher_notify(1);
460 ADD_FAILURE() << "failed to locate matching snapshot: "
461 << "remote_snap_id=" << remote_snap_id
<< ", "
462 << "remote_snap_ns=" << remote_mirror_ns
<< ", "
463 << "local_snap_id=" << local_snap_id
<< ", "
464 << "local_snap_ns=" << local_mirror_ns
;
467 void wait_for_replay_complete()
469 if (MIRROR_IMAGE_MODE
== cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
) {
470 wait_for_journal_synced();
472 wait_for_snapshot_synced();
476 void wait_for_stopped() {
477 for (int i
= 0; i
< 100; i
++) {
478 if (m_replayer
->is_stopped()) {
481 wait_for_watcher_notify(1);
483 ASSERT_TRUE(m_replayer
->is_stopped());
486 void write_test_data(librbd::ImageCtx
*ictx
, const char *test_data
, off_t off
,
491 bl
.append(std::string(test_data
, len
));
492 written
= ictx
->io_work_queue
->write(off
, len
, std::move(bl
), 0);
493 printf("wrote: %d\n", (int)written
);
494 ASSERT_EQ(len
, written
);
497 void read_test_data(librbd::ImageCtx
*ictx
, const char *expected
, off_t off
,
501 char *result
= (char *)malloc(len
+ 1);
503 ASSERT_NE(static_cast<char *>(NULL
), result
);
504 read
= ictx
->io_work_queue
->read(
505 off
, len
, librbd::io::ReadResult
{result
, len
}, 0);
506 printf("read: %d\n", (int)read
);
507 ASSERT_EQ(len
, static_cast<size_t>(read
));
509 if (memcmp(result
, expected
, len
)) {
510 printf("read: %s\nexpected: %s\n", result
, expected
);
511 ASSERT_EQ(0, memcmp(result
, expected
, len
));
516 void generate_test_data() {
517 for (int i
= 0; i
< TEST_IO_SIZE
; ++i
) {
518 m_test_data
[i
] = (char) (rand() % (126 - 33) + 33);
520 m_test_data
[TEST_IO_SIZE
] = '\0';
523 void flush(librbd::ImageCtx
*ictx
)
525 C_SaferCond aio_flush_ctx
;
526 auto c
= librbd::io::AioCompletion::create(&aio_flush_ctx
);
528 ictx
->io_work_queue
->aio_flush(c
);
529 ASSERT_EQ(0, c
->wait_for_complete());
532 if (MIRROR_IMAGE_MODE
== cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
) {
533 C_SaferCond journal_flush_ctx
;
534 ictx
->journal
->flush_commit_position(&journal_flush_ctx
);
535 ASSERT_EQ(0, journal_flush_ctx
.wait());
537 uint64_t snap_id
= CEPH_NOSNAP
;
538 ASSERT_EQ(0, librbd::api::Mirror
<>::image_snapshot_create(
545 static int _image_number
;
547 PoolMetaCache m_pool_meta_cache
{g_ceph_context
};
549 std::shared_ptr
<librados::Rados
> m_local_cluster
;
550 std::unique_ptr
<Threads
<>> m_threads
;
551 std::unique_ptr
<Throttler
<>> m_image_sync_throttler
;
552 librados::Rados m_remote_cluster
;
553 InstanceWatcher
<> *m_instance_watcher
;
554 MirrorStatusUpdater
<> *m_local_status_updater
;
555 std::string m_local_mirror_uuid
= "local mirror uuid";
556 std::string m_remote_mirror_uuid
= "remote mirror uuid";
557 std::string m_local_pool_name
, m_remote_pool_name
;
558 librados::IoCtx m_local_ioctx
, m_remote_ioctx
;
559 std::string m_image_name
;
560 int64_t m_remote_pool_id
;
561 std::string m_remote_image_id
;
562 std::string m_global_image_id
;
563 ImageReplayer
<> *m_replayer
= nullptr;
564 C_WatchCtx
*m_watch_ctx
= nullptr;
565 uint64_t m_watch_handle
= 0;
566 char m_test_data
[TEST_IO_SIZE
+ 1];
567 std::string m_journal_commit_age
;
570 template <typename T
>
571 int TestImageReplayer
<T
>::_image_number
;
573 template <cls::rbd::MirrorImageMode _mirror_image_mode
, uint64_t _features
>
574 class TestImageReplayerParams
{
576 static const cls::rbd::MirrorImageMode MIRROR_IMAGE_MODE
= _mirror_image_mode
;
577 static const uint64_t FEATURES
= _features
;
580 typedef ::testing::Types
<TestImageReplayerParams
<
581 cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, 125>,
582 TestImageReplayerParams
<
583 cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
, 1>,
584 TestImageReplayerParams
<
585 cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
, 5>,
586 TestImageReplayerParams
<
587 cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
, 61>,
588 TestImageReplayerParams
<
589 cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
, 125>>
590 TestImageReplayerTypes
;
592 TYPED_TEST_SUITE(TestImageReplayer
, TestImageReplayerTypes
);
594 TYPED_TEST(TestImageReplayer
, Bootstrap
)
599 typedef TestImageReplayer
<TestImageReplayerParams
<
600 cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, 125>> TestImageReplayerJournal
;
602 TYPED_TEST(TestImageReplayer
, BootstrapErrorLocalImageExists
)
605 EXPECT_EQ(0, librbd::create(this->m_local_ioctx
, this->m_image_name
.c_str(),
606 1 << 22, false, 0, &order
, 0, 0));
608 this->create_replayer();
610 this->m_replayer
->start(&cond
);
611 ASSERT_EQ(-EEXIST
, cond
.wait());
614 TEST_F(TestImageReplayerJournal
, BootstrapErrorNoJournal
)
616 ASSERT_EQ(0, librbd::Journal
<>::remove(this->m_remote_ioctx
,
617 this->m_remote_image_id
));
619 this->create_replayer();
621 this->m_replayer
->start(&cond
);
622 ASSERT_EQ(-ENOENT
, cond
.wait());
625 TYPED_TEST(TestImageReplayer
, BootstrapErrorMirrorDisabled
)
627 // disable remote image mirroring
628 ASSERT_EQ(0, librbd::api::Mirror
<>::mode_set(this->m_remote_ioctx
,
629 RBD_MIRROR_MODE_IMAGE
));
630 librbd::ImageCtx
*ictx
;
631 this->open_remote_image(&ictx
);
632 ASSERT_EQ(0, librbd::api::Mirror
<>::image_disable(ictx
, true));
633 this->close_image(ictx
);
635 this->create_replayer();
637 this->m_replayer
->start(&cond
);
638 ASSERT_EQ(-ENOENT
, cond
.wait());
641 TYPED_TEST(TestImageReplayer
, BootstrapMirrorDisabling
)
643 // set remote image mirroring state to DISABLING
644 if (gtest_TypeParam_::MIRROR_IMAGE_MODE
==
645 cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
) {
646 ASSERT_EQ(0, librbd::api::Mirror
<>::mode_set(this->m_remote_ioctx
,
647 RBD_MIRROR_MODE_IMAGE
));
648 librbd::ImageCtx
*ictx
;
649 this->open_remote_image(&ictx
);
650 ASSERT_EQ(0, librbd::api::Mirror
<>::image_enable(
651 ictx
, RBD_MIRROR_IMAGE_MODE_JOURNAL
, false));
652 this->close_image(ictx
);
655 cls::rbd::MirrorImage mirror_image
;
656 ASSERT_EQ(0, librbd::cls_client::mirror_image_get(&this->m_remote_ioctx
,
657 this->m_remote_image_id
,
659 mirror_image
.state
= cls::rbd::MirrorImageState::MIRROR_IMAGE_STATE_DISABLING
;
660 ASSERT_EQ(0, librbd::cls_client::mirror_image_set(&this->m_remote_ioctx
,
661 this->m_remote_image_id
,
664 this->create_replayer();
666 this->m_replayer
->start(&cond
);
667 ASSERT_EQ(-EREMOTEIO
, cond
.wait());
668 ASSERT_TRUE(this->m_replayer
->is_stopped());
671 TYPED_TEST(TestImageReplayer
, BootstrapDemoted
)
673 // demote remote image
674 librbd::ImageCtx
*ictx
;
675 this->open_remote_image(&ictx
);
676 ASSERT_EQ(0, librbd::api::Mirror
<>::image_demote(ictx
));
677 this->close_image(ictx
);
679 this->create_replayer();
681 this->m_replayer
->start(&cond
);
682 ASSERT_EQ(-EREMOTEIO
, cond
.wait());
683 ASSERT_TRUE(this->m_replayer
->is_stopped());
686 TYPED_TEST(TestImageReplayer
, StartInterrupted
)
688 this->create_replayer();
689 C_SaferCond start_cond
, stop_cond
;
690 this->m_replayer
->start(&start_cond
);
691 this->m_replayer
->stop(&stop_cond
);
692 int r
= start_cond
.wait();
693 printf("start returned %d\n", r
);
694 // TODO: improve the test to avoid this race
695 ASSERT_TRUE(r
== -ECANCELED
|| r
== 0);
696 ASSERT_EQ(0, stop_cond
.wait());
699 TEST_F(TestImageReplayerJournal
, JournalReset
)
702 delete this->m_replayer
;
704 ASSERT_EQ(0, librbd::Journal
<>::reset(this->m_remote_ioctx
,
705 this->m_remote_image_id
));
711 TEST_F(TestImageReplayerJournal
, ErrorNoJournal
)
715 // disable remote journal journaling
716 // (reset before disabling, so it does not fail with EBUSY)
717 ASSERT_EQ(0, librbd::Journal
<>::reset(this->m_remote_ioctx
,
718 this->m_remote_image_id
));
719 librbd::ImageCtx
*ictx
;
720 this->open_remote_image(&ictx
);
722 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
723 ASSERT_EQ(0, ictx
->operations
->update_features(RBD_FEATURE_JOURNALING
,
725 this->close_image(ictx
);
728 this->m_replayer
->start(&cond
);
729 ASSERT_EQ(0, cond
.wait());
732 TYPED_TEST(TestImageReplayer
, StartStop
)
737 this->wait_for_replay_complete();
741 TYPED_TEST(TestImageReplayer
, WriteAndStartReplay
)
745 // Write to remote image and start replay
747 librbd::ImageCtx
*ictx
;
749 this->generate_test_data();
750 this->open_remote_image(&ictx
);
751 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
752 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
756 this->close_image(ictx
);
759 this->wait_for_replay_complete();
762 this->open_local_image(&ictx
);
763 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
764 this->read_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
767 this->close_image(ictx
);
770 TYPED_TEST(TestImageReplayer
, StartReplayAndWrite
)
774 // Start replay and write to remote image
776 librbd::ImageCtx
*ictx
;
780 this->generate_test_data();
781 this->open_remote_image(&ictx
);
782 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
783 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
788 this->wait_for_replay_complete();
790 for (int i
= TEST_IO_COUNT
; i
< 2 * TEST_IO_COUNT
; ++i
) {
791 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
795 this->close_image(ictx
);
797 this->wait_for_replay_complete();
799 this->open_local_image(&ictx
);
800 for (int i
= 0; i
< 2 * TEST_IO_COUNT
; ++i
) {
801 this->read_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
804 this->close_image(ictx
);
809 TEST_F(TestImageReplayerJournal
, NextTag
)
813 // write, reopen, and write again to test switch to the next tag
815 librbd::ImageCtx
*ictx
;
819 this->generate_test_data();
823 for (int j
= 0; j
< N
; j
++) {
824 this->open_remote_image(&ictx
);
825 for (int i
= j
* TEST_IO_COUNT
; i
< (j
+ 1) * TEST_IO_COUNT
; ++i
) {
826 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
829 this->close_image(ictx
);
832 this->wait_for_replay_complete();
834 this->open_local_image(&ictx
);
835 for (int i
= 0; i
< N
* TEST_IO_COUNT
; ++i
) {
836 this->read_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
839 this->close_image(ictx
);
844 TYPED_TEST(TestImageReplayer
, Resync
)
848 librbd::ImageCtx
*ictx
;
852 this->generate_test_data();
854 this->open_remote_image(&ictx
);
855 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
856 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
861 this->wait_for_replay_complete();
863 for (int i
= TEST_IO_COUNT
; i
< 2 * TEST_IO_COUNT
; ++i
) {
864 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
868 this->close_image(ictx
);
870 this->open_local_image(&ictx
);
871 EXPECT_EQ(0, librbd::api::Mirror
<>::image_resync(ictx
));
872 this->close_image(ictx
);
874 this->wait_for_stopped();
877 this->m_replayer
->start(&cond
);
878 ASSERT_EQ(0, cond
.wait());
880 ASSERT_TRUE(this->m_replayer
->is_replaying());
881 this->wait_for_replay_complete();
883 this->open_local_image(&ictx
);
884 for (int i
= 0; i
< 2 * TEST_IO_COUNT
; ++i
) {
885 this->read_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
888 this->close_image(ictx
);
893 TYPED_TEST(TestImageReplayer
, Resync_While_Stop
)
899 this->generate_test_data();
901 librbd::ImageCtx
*ictx
;
902 this->open_remote_image(&ictx
);
903 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
904 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
909 this->wait_for_replay_complete();
911 for (int i
= TEST_IO_COUNT
; i
< 2 * TEST_IO_COUNT
; ++i
) {
912 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
916 this->close_image(ictx
);
918 this->wait_for_replay_complete();
921 this->m_replayer
->stop(&cond
);
922 ASSERT_EQ(0, cond
.wait());
924 this->open_local_image(&ictx
);
925 EXPECT_EQ(0, librbd::api::Mirror
<>::image_resync(ictx
));
926 this->close_image(ictx
);
929 this->m_replayer
->start(&cond2
);
930 ASSERT_EQ(0, cond2
.wait());
932 ASSERT_TRUE(this->m_replayer
->is_stopped());
935 this->m_replayer
->start(&cond3
);
936 ASSERT_EQ(0, cond3
.wait());
938 ASSERT_TRUE(this->m_replayer
->is_replaying());
940 this->wait_for_replay_complete();
942 this->open_local_image(&ictx
);
943 for (int i
= 0; i
< 2 * TEST_IO_COUNT
; ++i
) {
944 this->read_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
947 this->close_image(ictx
);
952 TYPED_TEST(TestImageReplayer
, Resync_StartInterrupted
)
956 librbd::ImageCtx
*ictx
;
957 this->open_local_image(&ictx
);
958 EXPECT_EQ(0, librbd::api::Mirror
<>::image_resync(ictx
));
959 this->close_image(ictx
);
962 this->m_replayer
->start(&cond
);
963 ASSERT_EQ(0, cond
.wait());
965 ASSERT_TRUE(this->m_replayer
->is_stopped());
968 this->m_replayer
->start(&cond2
);
969 ASSERT_EQ(0, cond2
.wait());
971 this->create_watch_ctx();
973 ASSERT_TRUE(this->m_replayer
->is_replaying());
975 this->generate_test_data();
976 this->open_remote_image(&ictx
);
977 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
978 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
983 this->wait_for_replay_complete();
985 for (int i
= TEST_IO_COUNT
; i
< 2 * TEST_IO_COUNT
; ++i
) {
986 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
990 this->close_image(ictx
);
992 this->wait_for_replay_complete();
994 this->open_local_image(&ictx
);
995 for (int i
= 0; i
< 2 * TEST_IO_COUNT
; ++i
) {
996 this->read_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
999 this->close_image(ictx
);
1004 TEST_F(TestImageReplayerJournal
, MultipleReplayFailures_SingleEpoch
) {
1007 // inject a snapshot that cannot be unprotected
1008 librbd::ImageCtx
*ictx
;
1009 this->open_image(this->m_local_ioctx
, this->m_image_name
, false, &ictx
);
1010 ictx
->features
&= ~RBD_FEATURE_JOURNALING
;
1011 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
1013 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
1015 ASSERT_EQ(0, librbd::cls_client::add_child(&ictx
->md_ctx
, RBD_CHILDREN
,
1016 {ictx
->md_ctx
.get_id(), "",
1018 ictx
->snap_ids
[{cls::rbd::UserSnapshotNamespace(), "foo"}]},
1020 this->close_image(ictx
);
1022 // race failed op shut down with new ops
1023 this->open_remote_image(&ictx
);
1024 for (uint64_t i
= 0; i
< 10; ++i
) {
1025 std::shared_lock owner_locker
{ictx
->owner_lock
};
1026 C_SaferCond request_lock
;
1027 ictx
->exclusive_lock
->acquire_lock(&request_lock
);
1028 ASSERT_EQ(0, request_lock
.wait());
1030 C_SaferCond append_ctx
;
1031 ictx
->journal
->append_op_event(
1033 librbd::journal::EventEntry
{
1034 librbd::journal::SnapUnprotectEvent
{i
,
1035 cls::rbd::UserSnapshotNamespace(),
1038 ASSERT_EQ(0, append_ctx
.wait());
1040 C_SaferCond commit_ctx
;
1041 ictx
->journal
->commit_op_event(i
, 0, &commit_ctx
);
1042 ASSERT_EQ(0, commit_ctx
.wait());
1044 C_SaferCond release_ctx
;
1045 ictx
->exclusive_lock
->release_lock(&release_ctx
);
1046 ASSERT_EQ(0, release_ctx
.wait());
1049 for (uint64_t i
= 0; i
< 5; ++i
) {
1051 this->wait_for_stopped();
1054 this->close_image(ictx
);
1057 TEST_F(TestImageReplayerJournal
, MultipleReplayFailures_MultiEpoch
) {
1060 // inject a snapshot that cannot be unprotected
1061 librbd::ImageCtx
*ictx
;
1062 this->open_image(this->m_local_ioctx
, this->m_image_name
, false, &ictx
);
1063 ictx
->features
&= ~RBD_FEATURE_JOURNALING
;
1064 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
1066 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
1068 ASSERT_EQ(0, librbd::cls_client::add_child(&ictx
->md_ctx
, RBD_CHILDREN
,
1069 {ictx
->md_ctx
.get_id(), "",
1071 ictx
->snap_ids
[{cls::rbd::UserSnapshotNamespace(),
1074 this->close_image(ictx
);
1076 // race failed op shut down with new tag flush
1077 this->open_remote_image(&ictx
);
1079 std::shared_lock owner_locker
{ictx
->owner_lock
};
1080 C_SaferCond request_lock
;
1081 ictx
->exclusive_lock
->acquire_lock(&request_lock
);
1082 ASSERT_EQ(0, request_lock
.wait());
1084 C_SaferCond append_ctx
;
1085 ictx
->journal
->append_op_event(
1087 librbd::journal::EventEntry
{
1088 librbd::journal::SnapUnprotectEvent
{1U,
1089 cls::rbd::UserSnapshotNamespace(),
1092 ASSERT_EQ(0, append_ctx
.wait());
1094 C_SaferCond commit_ctx
;
1095 ictx
->journal
->commit_op_event(1U, 0, &commit_ctx
);
1096 ASSERT_EQ(0, commit_ctx
.wait());
1098 C_SaferCond release_ctx
;
1099 ictx
->exclusive_lock
->release_lock(&release_ctx
);
1100 ASSERT_EQ(0, release_ctx
.wait());
1103 this->generate_test_data();
1104 this->write_test_data(ictx
, this->m_test_data
, 0, TEST_IO_SIZE
);
1106 for (uint64_t i
= 0; i
< 5; ++i
) {
1108 this->wait_for_stopped();
1111 this->close_image(ictx
);
1114 TEST_F(TestImageReplayerJournal
, Disconnect
)
1118 // Make sure rbd_mirroring_resync_after_disconnect is not set
1119 EXPECT_EQ(0, this->m_local_cluster
->conf_set("rbd_mirroring_resync_after_disconnect", "false"));
1121 // Test start fails if disconnected
1123 librbd::ImageCtx
*ictx
;
1125 this->generate_test_data();
1126 this->open_remote_image(&ictx
);
1127 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
1128 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
1132 this->close_image(ictx
);
1134 std::string oid
= ::journal::Journaler::header_oid(this->m_remote_image_id
);
1136 cls::journal::client::client_update_state(this->m_remote_ioctx
,
1137 oid
, this->m_local_mirror_uuid
,
1138 cls::journal::CLIENT_STATE_DISCONNECTED
));
1141 this->m_replayer
->start(&cond1
);
1142 ASSERT_EQ(-ENOTCONN
, cond1
.wait());
1144 // Test start succeeds after resync
1146 this->open_local_image(&ictx
);
1147 librbd::Journal
<>::request_resync(ictx
);
1148 this->close_image(ictx
);
1150 this->m_replayer
->start(&cond2
);
1151 ASSERT_EQ(0, cond2
.wait());
1154 this->wait_for_replay_complete();
1156 // Test replay stopped after disconnect
1158 this->open_remote_image(&ictx
);
1159 for (int i
= TEST_IO_COUNT
; i
< 2 * TEST_IO_COUNT
; ++i
) {
1160 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
1164 this->close_image(ictx
);
1167 cls::journal::client::client_update_state(this->m_remote_ioctx
, oid
,
1168 this->m_local_mirror_uuid
,
1169 cls::journal::CLIENT_STATE_DISCONNECTED
));
1171 ASSERT_EQ(0, this->m_remote_ioctx
.notify2(oid
, bl
, 5000, NULL
));
1173 this->wait_for_stopped();
1175 // Test start fails after disconnect
1178 this->m_replayer
->start(&cond3
);
1179 ASSERT_EQ(-ENOTCONN
, cond3
.wait());
1181 this->m_replayer
->start(&cond4
);
1182 ASSERT_EQ(-ENOTCONN
, cond4
.wait());
1184 // Test automatic resync if rbd_mirroring_resync_after_disconnect is set
1186 EXPECT_EQ(0, this->m_local_cluster
->conf_set("rbd_mirroring_resync_after_disconnect", "true"));
1188 // Resync is flagged on first start attempt
1190 this->m_replayer
->start(&cond5
);
1191 ASSERT_EQ(-ENOTCONN
, cond5
.wait());
1194 this->m_replayer
->start(&cond6
);
1195 ASSERT_EQ(0, cond6
.wait());
1196 this->wait_for_replay_complete();
1201 TEST_F(TestImageReplayerJournal
, UpdateFeatures
)
1203 // TODO add support to snapshot-based mirroring
1204 const uint64_t FEATURES_TO_UPDATE
=
1205 RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
;
1208 librbd::ImageCtx
*ictx
;
1210 // Make sure the features we will update are disabled initially
1212 this->open_remote_image(&ictx
);
1213 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1214 features
&= FEATURES_TO_UPDATE
;
1216 ASSERT_EQ(0, ictx
->operations
->update_features(FEATURES_TO_UPDATE
,
1219 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1220 ASSERT_EQ(0U, features
& FEATURES_TO_UPDATE
);
1221 this->close_image(ictx
);
1225 this->open_remote_image(&ictx
);
1226 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1227 ASSERT_EQ(0U, features
& FEATURES_TO_UPDATE
);
1228 this->close_image(ictx
);
1230 this->open_local_image(&ictx
);
1231 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1232 ASSERT_EQ(0U, features
& FEATURES_TO_UPDATE
);
1233 this->close_image(ictx
);
1235 // Start replay and update features
1239 this->open_remote_image(&ictx
);
1240 ASSERT_EQ(0, ictx
->operations
->update_features(FEATURES_TO_UPDATE
,
1242 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1243 ASSERT_EQ(FEATURES_TO_UPDATE
, features
& FEATURES_TO_UPDATE
);
1244 this->close_image(ictx
);
1246 this->wait_for_replay_complete();
1248 this->open_local_image(&ictx
);
1249 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1250 ASSERT_EQ(FEATURES_TO_UPDATE
, features
& FEATURES_TO_UPDATE
);
1251 this->close_image(ictx
);
1253 this->open_remote_image(&ictx
);
1254 ASSERT_EQ(0, ictx
->operations
->update_features(FEATURES_TO_UPDATE
,
1256 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1257 ASSERT_EQ(0U, features
& FEATURES_TO_UPDATE
);
1258 this->close_image(ictx
);
1260 this->wait_for_replay_complete();
1262 this->open_local_image(&ictx
);
1263 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1264 ASSERT_EQ(0U, features
& FEATURES_TO_UPDATE
);
1265 this->close_image(ictx
);
1267 // Test update_features error does not stop replication
1269 this->open_remote_image(&ictx
);
1270 ASSERT_EQ(0, librbd::get_features(ictx
, &features
));
1271 ASSERT_NE(0U, features
& RBD_FEATURE_EXCLUSIVE_LOCK
);
1272 ASSERT_EQ(-EINVAL
, ictx
->operations
->update_features(RBD_FEATURE_EXCLUSIVE_LOCK
,
1274 this->generate_test_data();
1275 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
1276 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
1280 this->close_image(ictx
);
1282 this->wait_for_replay_complete();
1284 this->open_local_image(&ictx
);
1285 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
1286 this->read_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
1289 this->close_image(ictx
);
1294 TEST_F(TestImageReplayerJournal
, MetadataSetRemove
)
1296 // TODO add support to snapshot-based mirroring
1297 const std::string KEY
= "test_key";
1298 const std::string VALUE
= "test_value";
1300 librbd::ImageCtx
*ictx
;
1307 // Test metadata_set replication
1309 this->open_remote_image(&ictx
);
1310 ASSERT_EQ(0, ictx
->operations
->metadata_set(KEY
, VALUE
));
1312 ASSERT_EQ(0, librbd::metadata_get(ictx
, KEY
, &value
));
1313 ASSERT_EQ(VALUE
, value
);
1314 this->close_image(ictx
);
1316 this->wait_for_replay_complete();
1318 this->open_local_image(&ictx
);
1320 ASSERT_EQ(0, librbd::metadata_get(ictx
, KEY
, &value
));
1321 ASSERT_EQ(VALUE
, value
);
1322 this->close_image(ictx
);
1324 // Test metadata_remove replication
1326 this->open_remote_image(&ictx
);
1327 ASSERT_EQ(0, ictx
->operations
->metadata_remove(KEY
));
1328 ASSERT_EQ(-ENOENT
, librbd::metadata_get(ictx
, KEY
, &value
));
1329 this->close_image(ictx
);
1331 this->wait_for_replay_complete();
1333 this->open_local_image(&ictx
);
1334 ASSERT_EQ(-ENOENT
, librbd::metadata_get(ictx
, KEY
, &value
));
1335 this->close_image(ictx
);
1340 TEST_F(TestImageReplayerJournal
, MirroringDelay
)
1342 // TODO add support to snapshot-based mirroring
1343 const double DELAY
= 10; // set less than wait_for_replay_complete timeout
1345 librbd::ImageCtx
*ictx
;
1351 ASSERT_EQ(0, this->m_local_cluster
->conf_set("rbd_mirroring_replay_delay",
1352 stringify(DELAY
).c_str()));
1353 this->open_local_image(&ictx
);
1354 ASSERT_EQ(DELAY
, ictx
->mirroring_replay_delay
);
1355 this->close_image(ictx
);
1361 this->generate_test_data();
1362 this->open_remote_image(&ictx
);
1363 start_time
= ceph_clock_now();
1364 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
1365 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
1369 this->close_image(ictx
);
1371 this->wait_for_replay_complete();
1372 delay
= ceph_clock_now() - start_time
;
1373 ASSERT_GE(delay
, DELAY
);
1375 // Test stop when delaying replay
1377 this->open_remote_image(&ictx
);
1378 start_time
= ceph_clock_now();
1379 for (int i
= 0; i
< TEST_IO_COUNT
; ++i
) {
1380 this->write_test_data(ictx
, this->m_test_data
, TEST_IO_SIZE
* i
,
1383 this->close_image(ictx
);
1389 this->wait_for_replay_complete();
1390 delay
= ceph_clock_now() - start_time
;
1391 ASSERT_GE(delay
, DELAY
);
1396 TYPED_TEST(TestImageReplayer
, ImageRename
) {
1397 this->create_replayer();
1400 librbd::ImageCtx
* remote_image_ctx
= nullptr;
1401 this->open_remote_image(&remote_image_ctx
);
1402 auto image_name
= this->get_temp_image_name();
1403 ASSERT_EQ(0, remote_image_ctx
->operations
->rename(image_name
.c_str()));
1404 this->flush(remote_image_ctx
);
1406 this->wait_for_replay_complete();
1408 librbd::ImageCtx
* local_image_ctx
= nullptr;
1409 this->open_image(this->m_local_ioctx
, image_name
, true, &local_image_ctx
);
1410 ASSERT_EQ(image_name
, local_image_ctx
->name
);
1412 this->close_image(local_image_ctx
);
1413 this->close_image(remote_image_ctx
);
1417 TYPED_TEST(TestImageReplayer
, UpdateFeatures
) {
1418 const uint64_t FEATURES_TO_UPDATE
=
1419 RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
| RBD_FEATURE_DEEP_FLATTEN
;
1420 REQUIRE((this->FEATURES
& FEATURES_TO_UPDATE
) == FEATURES_TO_UPDATE
);
1422 librbd::ImageCtx
* remote_image_ctx
= nullptr;
1423 this->open_remote_image(&remote_image_ctx
);
1425 ASSERT_EQ(0, remote_image_ctx
->operations
->update_features(
1426 (RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
), false));
1427 this->flush(remote_image_ctx
);
1429 this->create_replayer();
1431 this->wait_for_replay_complete();
1433 librbd::ImageCtx
* local_image_ctx
= nullptr;
1434 this->open_local_image(&local_image_ctx
);
1435 ASSERT_EQ(0U, local_image_ctx
->features
& (
1436 RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
));
1438 // enable object-map/fast-diff
1439 ASSERT_EQ(0, remote_image_ctx
->operations
->update_features(
1440 (RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
), true));
1441 this->flush(remote_image_ctx
);
1442 this->wait_for_replay_complete();
1444 ASSERT_EQ(0, local_image_ctx
->state
->refresh());
1445 ASSERT_EQ(RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
,
1446 local_image_ctx
->features
& (
1447 RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
));
1449 // disable deep-flatten
1450 ASSERT_EQ(0, remote_image_ctx
->operations
->update_features(
1451 RBD_FEATURE_DEEP_FLATTEN
, false));
1452 this->flush(remote_image_ctx
);
1453 this->wait_for_replay_complete();
1455 ASSERT_EQ(0, local_image_ctx
->state
->refresh());
1456 ASSERT_EQ(0, local_image_ctx
->features
& RBD_FEATURE_DEEP_FLATTEN
);
1458 this->close_image(local_image_ctx
);
1459 this->close_image(remote_image_ctx
);
1463 TYPED_TEST(TestImageReplayer
, SnapshotUnprotect
) {
1464 librbd::ImageCtx
* remote_image_ctx
= nullptr;
1465 this->open_remote_image(&remote_image_ctx
);
1467 // create a protected snapshot
1468 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_create(
1469 cls::rbd::UserSnapshotNamespace
{}, "snap1"));
1470 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_protect(
1471 cls::rbd::UserSnapshotNamespace
{}, "snap1"));
1472 this->flush(remote_image_ctx
);
1474 this->create_replayer();
1476 this->wait_for_replay_complete();
1478 librbd::ImageCtx
* local_image_ctx
= nullptr;
1479 this->open_local_image(&local_image_ctx
);
1480 auto local_snap_id_it
= local_image_ctx
->snap_ids
.find({
1481 {cls::rbd::UserSnapshotNamespace
{}}, "snap1"});
1482 ASSERT_NE(local_image_ctx
->snap_ids
.end(), local_snap_id_it
);
1483 auto local_snap_id
= local_snap_id_it
->second
;
1484 auto local_snap_info_it
= local_image_ctx
->snap_info
.find(local_snap_id
);
1485 ASSERT_NE(local_image_ctx
->snap_info
.end(), local_snap_info_it
);
1486 ASSERT_EQ(RBD_PROTECTION_STATUS_PROTECTED
,
1487 local_snap_info_it
->second
.protection_status
);
1489 // unprotect the snapshot
1490 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_unprotect(
1491 cls::rbd::UserSnapshotNamespace
{}, "snap1"));
1492 this->flush(remote_image_ctx
);
1493 this->wait_for_replay_complete();
1495 ASSERT_EQ(0, local_image_ctx
->state
->refresh());
1496 local_snap_info_it
= local_image_ctx
->snap_info
.find(local_snap_id
);
1497 ASSERT_NE(local_image_ctx
->snap_info
.end(), local_snap_info_it
);
1498 ASSERT_EQ(RBD_PROTECTION_STATUS_UNPROTECTED
,
1499 local_snap_info_it
->second
.protection_status
);
1501 this->close_image(local_image_ctx
);
1502 this->close_image(remote_image_ctx
);
1506 TYPED_TEST(TestImageReplayer
, SnapshotProtect
) {
1507 librbd::ImageCtx
* remote_image_ctx
= nullptr;
1508 this->open_remote_image(&remote_image_ctx
);
1510 // create an unprotected snapshot
1511 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_create(
1512 cls::rbd::UserSnapshotNamespace
{}, "snap1"));
1513 this->flush(remote_image_ctx
);
1515 this->create_replayer();
1517 this->wait_for_replay_complete();
1519 librbd::ImageCtx
* local_image_ctx
= nullptr;
1520 this->open_local_image(&local_image_ctx
);
1521 auto local_snap_id_it
= local_image_ctx
->snap_ids
.find({
1522 {cls::rbd::UserSnapshotNamespace
{}}, "snap1"});
1523 ASSERT_NE(local_image_ctx
->snap_ids
.end(), local_snap_id_it
);
1524 auto local_snap_id
= local_snap_id_it
->second
;
1525 auto local_snap_info_it
= local_image_ctx
->snap_info
.find(local_snap_id
);
1526 ASSERT_NE(local_image_ctx
->snap_info
.end(), local_snap_info_it
);
1527 ASSERT_EQ(RBD_PROTECTION_STATUS_UNPROTECTED
,
1528 local_snap_info_it
->second
.protection_status
);
1530 // protect the snapshot
1531 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_protect(
1532 cls::rbd::UserSnapshotNamespace
{}, "snap1"));
1533 this->flush(remote_image_ctx
);
1534 this->wait_for_replay_complete();
1536 ASSERT_EQ(0, local_image_ctx
->state
->refresh());
1537 local_snap_info_it
= local_image_ctx
->snap_info
.find(local_snap_id
);
1538 ASSERT_NE(local_image_ctx
->snap_info
.end(), local_snap_info_it
);
1539 ASSERT_EQ(RBD_PROTECTION_STATUS_PROTECTED
,
1540 local_snap_info_it
->second
.protection_status
);
1542 this->close_image(local_image_ctx
);
1543 this->close_image(remote_image_ctx
);
1547 TYPED_TEST(TestImageReplayer
, SnapshotRemove
) {
1548 librbd::ImageCtx
* remote_image_ctx
= nullptr;
1549 this->open_remote_image(&remote_image_ctx
);
1551 // create a user snapshot
1552 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_create(
1553 cls::rbd::UserSnapshotNamespace
{}, "snap1"));
1554 this->flush(remote_image_ctx
);
1556 this->create_replayer();
1558 this->wait_for_replay_complete();
1560 librbd::ImageCtx
* local_image_ctx
= nullptr;
1561 this->open_local_image(&local_image_ctx
);
1562 auto local_snap_id_it
= local_image_ctx
->snap_ids
.find({
1563 {cls::rbd::UserSnapshotNamespace
{}}, "snap1"});
1564 ASSERT_NE(local_image_ctx
->snap_ids
.end(), local_snap_id_it
);
1566 // remove the snapshot
1567 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_remove(
1568 cls::rbd::UserSnapshotNamespace
{}, "snap1"));
1569 this->flush(remote_image_ctx
);
1570 this->wait_for_replay_complete();
1572 ASSERT_EQ(0, local_image_ctx
->state
->refresh());
1573 local_snap_id_it
= local_image_ctx
->snap_ids
.find({
1574 {cls::rbd::UserSnapshotNamespace
{}}, "snap1"});
1575 ASSERT_EQ(local_image_ctx
->snap_ids
.end(), local_snap_id_it
);
1577 this->close_image(local_image_ctx
);
1578 this->close_image(remote_image_ctx
);
1582 TYPED_TEST(TestImageReplayer
, SnapshotRename
) {
1583 librbd::ImageCtx
* remote_image_ctx
= nullptr;
1584 this->open_remote_image(&remote_image_ctx
);
1586 // create a user snapshot
1587 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_create(
1588 cls::rbd::UserSnapshotNamespace
{}, "snap1"));
1589 this->flush(remote_image_ctx
);
1591 this->create_replayer();
1593 this->wait_for_replay_complete();
1595 librbd::ImageCtx
* local_image_ctx
= nullptr;
1596 this->open_local_image(&local_image_ctx
);
1597 auto local_snap_id_it
= local_image_ctx
->snap_ids
.find({
1598 {cls::rbd::UserSnapshotNamespace
{}}, "snap1"});
1599 ASSERT_NE(local_image_ctx
->snap_ids
.end(), local_snap_id_it
);
1600 auto local_snap_id
= local_snap_id_it
->second
;
1601 auto local_snap_info_it
= local_image_ctx
->snap_info
.find(local_snap_id
);
1602 ASSERT_NE(local_image_ctx
->snap_info
.end(), local_snap_info_it
);
1603 ASSERT_EQ(RBD_PROTECTION_STATUS_UNPROTECTED
,
1604 local_snap_info_it
->second
.protection_status
);
1606 // rename the snapshot
1607 ASSERT_EQ(0, remote_image_ctx
->operations
->snap_rename(
1608 "snap1", "snap1-renamed"));
1609 this->flush(remote_image_ctx
);
1610 this->wait_for_replay_complete();
1612 ASSERT_EQ(0, local_image_ctx
->state
->refresh());
1613 local_snap_info_it
= local_image_ctx
->snap_info
.find(local_snap_id
);
1614 ASSERT_NE(local_image_ctx
->snap_info
.end(), local_snap_info_it
);
1615 ASSERT_EQ("snap1-renamed", local_snap_info_it
->second
.name
);
1617 this->close_image(local_image_ctx
);
1618 this->close_image(remote_image_ctx
);
1622 TYPED_TEST(TestImageReplayer
, SnapshotLimit
) {
1623 librbd::ImageCtx
* remote_image_ctx
= nullptr;
1624 this->open_remote_image(&remote_image_ctx
);
1626 this->create_replayer();
1628 this->wait_for_replay_complete();
1630 // update the snap limit
1631 ASSERT_EQ(0, librbd::api::Snapshot
<>::set_limit(remote_image_ctx
, 123U));
1632 this->flush(remote_image_ctx
);
1633 this->wait_for_replay_complete();
1635 librbd::ImageCtx
* local_image_ctx
= nullptr;
1636 this->open_local_image(&local_image_ctx
);
1637 uint64_t local_snap_limit
;
1638 ASSERT_EQ(0, librbd::api::Snapshot
<>::get_limit(local_image_ctx
,
1639 &local_snap_limit
));
1640 ASSERT_EQ(123U, local_snap_limit
);
1642 // update the limit again
1643 ASSERT_EQ(0, librbd::api::Snapshot
<>::set_limit(
1644 remote_image_ctx
, std::numeric_limits
<uint64_t>::max()));
1645 this->flush(remote_image_ctx
);
1646 this->wait_for_replay_complete();
1648 ASSERT_EQ(0, librbd::api::Snapshot
<>::get_limit(local_image_ctx
,
1649 &local_snap_limit
));
1650 ASSERT_EQ(std::numeric_limits
<uint64_t>::max(), local_snap_limit
);
1652 this->close_image(local_image_ctx
);
1653 this->close_image(remote_image_ctx
);
1657 } // namespace mirror