1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/rbd_mirror/test_fixture.h"
5 #include "include/stringify.h"
6 #include "include/rbd/librbd.hpp"
7 #include "journal/Journaler.h"
8 #include "journal/Settings.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/ImageState.h"
12 #include "librbd/internal.h"
13 #include "librbd/Operations.h"
14 #include "librbd/io/ImageRequestWQ.h"
15 #include "librbd/io/ReadResult.h"
16 #include "librbd/journal/Types.h"
17 #include "tools/rbd_mirror/ImageSync.h"
18 #include "tools/rbd_mirror/Threads.h"
20 void register_test_image_sync() {
28 void scribble(librbd::ImageCtx
*image_ctx
, int num_ops
, size_t max_size
)
30 max_size
= MIN(image_ctx
->size
, max_size
);
31 for (int i
=0; i
<num_ops
; i
++) {
32 uint64_t off
= rand() % (image_ctx
->size
- max_size
+ 1);
33 uint64_t len
= 1 + rand() % max_size
;
35 if (rand() % 4 == 0) {
36 ASSERT_EQ((int)len
, image_ctx
->io_work_queue
->discard(off
, len
, image_ctx
->skip_partial_discard
));
39 bl
.append(std::string(len
, '1'));
40 ASSERT_EQ((int)len
, image_ctx
->io_work_queue
->write(off
, len
,
45 RWLock::RLocker
owner_locker(image_ctx
->owner_lock
);
46 ASSERT_EQ(0, image_ctx
->flush());
49 } // anonymous namespace
50 class TestImageSync
: public TestFixture
{
53 void SetUp() override
{
55 create_and_open(m_local_io_ctx
, &m_local_image_ctx
);
56 create_and_open(m_remote_io_ctx
, &m_remote_image_ctx
);
58 m_remote_journaler
= new ::journal::Journaler(
59 m_threads
->work_queue
, m_threads
->timer
, &m_threads
->timer_lock
,
60 m_remote_io_ctx
, m_remote_image_ctx
->id
, "mirror-uuid", {});
62 m_client_meta
= {"image-id"};
64 librbd::journal::ClientData
client_data(m_client_meta
);
65 bufferlist client_data_bl
;
66 ::encode(client_data
, client_data_bl
);
68 ASSERT_EQ(0, m_remote_journaler
->register_client(client_data_bl
));
71 void TearDown() override
{
72 TestFixture::TearDown();
73 delete m_remote_journaler
;
76 void create_and_open(librados::IoCtx
&io_ctx
, librbd::ImageCtx
**image_ctx
) {
78 ASSERT_EQ(0, create_image(rbd
, io_ctx
, m_image_name
, m_image_size
));
79 ASSERT_EQ(0, open_image(io_ctx
, m_image_name
, image_ctx
));
83 RWLock::RLocker
owner_locker((*image_ctx
)->owner_lock
);
84 (*image_ctx
)->exclusive_lock
->try_acquire_lock(&ctx
);
86 ASSERT_EQ(0, ctx
.wait());
87 ASSERT_TRUE((*image_ctx
)->exclusive_lock
->is_lock_owner());
90 ImageSync
<> *create_request(Context
*ctx
) {
91 return new ImageSync
<>(m_local_image_ctx
, m_remote_image_ctx
,
92 m_threads
->timer
, &m_threads
->timer_lock
,
93 "mirror-uuid", m_remote_journaler
, &m_client_meta
,
94 m_threads
->work_queue
, ctx
);
97 librbd::ImageCtx
*m_remote_image_ctx
;
98 librbd::ImageCtx
*m_local_image_ctx
;
99 ::journal::Journaler
*m_remote_journaler
;
100 librbd::journal::MirrorPeerClientMeta m_client_meta
;
103 TEST_F(TestImageSync
, Empty
) {
105 ImageSync
<> *request
= create_request(&ctx
);
107 ASSERT_EQ(0, ctx
.wait());
109 ASSERT_EQ(0U, m_client_meta
.sync_points
.size());
110 ASSERT_EQ(0, m_remote_image_ctx
->state
->refresh());
111 ASSERT_EQ(0U, m_remote_image_ctx
->snap_ids
.size());
112 ASSERT_EQ(0, m_local_image_ctx
->state
->refresh());
113 ASSERT_EQ(1U, m_local_image_ctx
->snap_ids
.size()); // deleted on journal replay
116 TEST_F(TestImageSync
, Simple
) {
117 scribble(m_remote_image_ctx
, 10, 102400);
120 ImageSync
<> *request
= create_request(&ctx
);
122 ASSERT_EQ(0, ctx
.wait());
124 int64_t object_size
= std::min
<int64_t>(
125 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
126 bufferlist read_remote_bl
;
127 read_remote_bl
.append(std::string(object_size
, '1'));
128 bufferlist read_local_bl
;
129 read_local_bl
.append(std::string(object_size
, '1'));
131 for (uint64_t offset
= 0; offset
< m_remote_image_ctx
->size
;
132 offset
+= object_size
) {
133 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
135 librbd::io::ReadResult
{&read_remote_bl
}, 0));
136 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
138 librbd::io::ReadResult
{&read_local_bl
}, 0));
139 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
143 TEST_F(TestImageSync
, Resize
) {
144 int64_t object_size
= std::min
<int64_t>(
145 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
148 uint64_t len
= object_size
/ 10;
151 bl
.append(std::string(len
, '1'));
152 ASSERT_EQ((int)len
, m_remote_image_ctx
->io_work_queue
->write(off
, len
,
156 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
157 ASSERT_EQ(0, m_remote_image_ctx
->flush());
160 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, "snap", nullptr));
162 uint64_t size
= object_size
- 1;
163 librbd::NoOpProgressContext no_op_progress_ctx
;
164 ASSERT_EQ(0, m_remote_image_ctx
->operations
->resize(size
, true,
165 no_op_progress_ctx
));
168 ImageSync
<> *request
= create_request(&ctx
);
170 ASSERT_EQ(0, ctx
.wait());
172 bufferlist read_remote_bl
;
173 read_remote_bl
.append(std::string(len
, '\0'));
174 bufferlist read_local_bl
;
175 read_local_bl
.append(std::string(len
, '\0'));
177 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
178 off
, len
, librbd::io::ReadResult
{&read_remote_bl
}, 0));
179 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
180 off
, len
, librbd::io::ReadResult
{&read_local_bl
}, 0));
182 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
185 TEST_F(TestImageSync
, Discard
) {
186 int64_t object_size
= std::min
<int64_t>(
187 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
190 uint64_t len
= object_size
/ 10;
193 bl
.append(std::string(len
, '1'));
194 ASSERT_EQ((int)len
, m_remote_image_ctx
->io_work_queue
->write(off
, len
,
198 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
199 ASSERT_EQ(0, m_remote_image_ctx
->flush());
202 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, "snap", nullptr));
204 ASSERT_EQ((int)len
- 2, m_remote_image_ctx
->io_work_queue
->discard(off
+ 1,
205 len
- 2, m_remote_image_ctx
->skip_partial_discard
));
207 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
208 ASSERT_EQ(0, m_remote_image_ctx
->flush());
212 ImageSync
<> *request
= create_request(&ctx
);
214 ASSERT_EQ(0, ctx
.wait());
216 bufferlist read_remote_bl
;
217 read_remote_bl
.append(std::string(object_size
, '\0'));
218 bufferlist read_local_bl
;
219 read_local_bl
.append(std::string(object_size
, '\0'));
221 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
222 off
, len
, librbd::io::ReadResult
{&read_remote_bl
}, 0));
223 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
224 off
, len
, librbd::io::ReadResult
{&read_local_bl
}, 0));
226 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
229 TEST_F(TestImageSync
, SnapshotStress
) {
230 std::list
<std::string
> snap_names
;
232 const int num_snaps
= 4;
233 for (int idx
= 0; idx
<= num_snaps
; ++idx
) {
234 scribble(m_remote_image_ctx
, 10, 102400);
236 librbd::NoOpProgressContext no_op_progress_ctx
;
237 uint64_t size
= 1 + rand() % m_image_size
;
238 ASSERT_EQ(0, m_remote_image_ctx
->operations
->resize(size
, true,
239 no_op_progress_ctx
));
240 ASSERT_EQ(0, m_remote_image_ctx
->state
->refresh());
242 if (idx
< num_snaps
) {
243 snap_names
.push_back("snap" + stringify(idx
+ 1));
244 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, snap_names
.back().c_str(),
247 snap_names
.push_back("");
252 ImageSync
<> *request
= create_request(&ctx
);
254 ASSERT_EQ(0, ctx
.wait());
256 int64_t object_size
= std::min
<int64_t>(
257 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
258 bufferlist read_remote_bl
;
259 read_remote_bl
.append(std::string(object_size
, '1'));
260 bufferlist read_local_bl
;
261 read_local_bl
.append(std::string(object_size
, '1'));
263 for (auto &snap_name
: snap_names
) {
264 uint64_t remote_size
;
267 m_remote_image_ctx
->state
->snap_set(cls::rbd::UserSnapshotNamespace(),
270 ASSERT_EQ(0, ctx
.wait());
272 RWLock::RLocker
remote_snap_locker(m_remote_image_ctx
->snap_lock
);
273 remote_size
= m_remote_image_ctx
->get_image_size(
274 m_remote_image_ctx
->snap_id
);
280 m_local_image_ctx
->state
->snap_set(cls::rbd::UserSnapshotNamespace(),
283 ASSERT_EQ(0, ctx
.wait());
285 RWLock::RLocker
snap_locker(m_local_image_ctx
->snap_lock
);
286 local_size
= m_local_image_ctx
->get_image_size(
287 m_local_image_ctx
->snap_id
);
288 ASSERT_FALSE(m_local_image_ctx
->test_flags(RBD_FLAG_OBJECT_MAP_INVALID
,
289 m_local_image_ctx
->snap_lock
));
292 ASSERT_EQ(remote_size
, local_size
);
294 for (uint64_t offset
= 0; offset
< remote_size
; offset
+= object_size
) {
295 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
297 librbd::io::ReadResult
{&read_remote_bl
}, 0));
298 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
300 librbd::io::ReadResult
{&read_local_bl
}, 0));
301 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
306 } // namespace mirror