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/AioCompletion.h"
15 #include "librbd/io/ImageDispatchSpec.h"
16 #include "librbd/io/ImageRequestWQ.h"
17 #include "librbd/io/ReadResult.h"
18 #include "librbd/journal/Types.h"
19 #include "tools/rbd_mirror/ImageSync.h"
20 #include "tools/rbd_mirror/InstanceWatcher.h"
21 #include "tools/rbd_mirror/Threads.h"
23 void register_test_image_sync() {
31 int flush(librbd::ImageCtx
*image_ctx
) {
33 auto aio_comp
= librbd::io::AioCompletion::create_and_start(
34 &ctx
, image_ctx
, librbd::io::AIO_TYPE_FLUSH
);
35 auto req
= librbd::io::ImageDispatchSpec
<>::create_flush_request(
36 *image_ctx
, aio_comp
, librbd::io::FLUSH_SOURCE_INTERNAL
, {});
42 void scribble(librbd::ImageCtx
*image_ctx
, int num_ops
, uint64_t max_size
)
44 max_size
= std::min
<uint64_t>(image_ctx
->size
, max_size
);
45 for (int i
=0; i
<num_ops
; i
++) {
46 uint64_t off
= rand() % (image_ctx
->size
- max_size
+ 1);
47 uint64_t len
= 1 + rand() % max_size
;
49 if (rand() % 4 == 0) {
51 image_ctx
->io_work_queue
->discard(
52 off
, len
, image_ctx
->discard_granularity_bytes
));
55 bl
.append(std::string(len
, '1'));
56 ASSERT_EQ((int)len
, image_ctx
->io_work_queue
->write(off
, len
,
61 RWLock::RLocker
owner_locker(image_ctx
->owner_lock
);
62 ASSERT_EQ(0, flush(image_ctx
));
65 } // anonymous namespace
66 class TestImageSync
: public TestFixture
{
69 void SetUp() override
{
71 create_and_open(m_local_io_ctx
, &m_local_image_ctx
);
72 create_and_open(m_remote_io_ctx
, &m_remote_image_ctx
);
74 m_instance_watcher
= rbd::mirror::InstanceWatcher
<>::create(
75 m_local_io_ctx
, m_threads
->work_queue
, nullptr);
76 m_instance_watcher
->handle_acquire_leader();
78 m_remote_journaler
= new ::journal::Journaler(
79 m_threads
->work_queue
, m_threads
->timer
, &m_threads
->timer_lock
,
80 m_remote_io_ctx
, m_remote_image_ctx
->id
, "mirror-uuid", {});
82 m_client_meta
= {"image-id"};
84 librbd::journal::ClientData
client_data(m_client_meta
);
85 bufferlist client_data_bl
;
86 encode(client_data
, client_data_bl
);
88 ASSERT_EQ(0, m_remote_journaler
->register_client(client_data_bl
));
91 void TearDown() override
{
92 TestFixture::TearDown();
94 m_instance_watcher
->handle_release_leader();
96 delete m_remote_journaler
;
97 delete m_instance_watcher
;
100 void create_and_open(librados::IoCtx
&io_ctx
, librbd::ImageCtx
**image_ctx
) {
102 ASSERT_EQ(0, create_image(rbd
, io_ctx
, m_image_name
, m_image_size
));
103 ASSERT_EQ(0, open_image(io_ctx
, m_image_name
, image_ctx
));
107 RWLock::RLocker
owner_locker((*image_ctx
)->owner_lock
);
108 (*image_ctx
)->exclusive_lock
->try_acquire_lock(&ctx
);
110 ASSERT_EQ(0, ctx
.wait());
111 ASSERT_TRUE((*image_ctx
)->exclusive_lock
->is_lock_owner());
114 ImageSync
<> *create_request(Context
*ctx
) {
115 return new ImageSync
<>(m_local_image_ctx
, m_remote_image_ctx
,
116 m_threads
->timer
, &m_threads
->timer_lock
,
117 "mirror-uuid", m_remote_journaler
, &m_client_meta
,
118 m_threads
->work_queue
, m_instance_watcher
, ctx
);
121 librbd::ImageCtx
*m_remote_image_ctx
;
122 librbd::ImageCtx
*m_local_image_ctx
;
123 rbd::mirror::InstanceWatcher
<> *m_instance_watcher
;
124 ::journal::Journaler
*m_remote_journaler
;
125 librbd::journal::MirrorPeerClientMeta m_client_meta
;
128 TEST_F(TestImageSync
, Empty
) {
130 ImageSync
<> *request
= create_request(&ctx
);
132 ASSERT_EQ(0, ctx
.wait());
134 ASSERT_EQ(0U, m_client_meta
.sync_points
.size());
135 ASSERT_EQ(0, m_remote_image_ctx
->state
->refresh());
136 ASSERT_EQ(0U, m_remote_image_ctx
->snap_ids
.size());
137 ASSERT_EQ(0, m_local_image_ctx
->state
->refresh());
138 ASSERT_EQ(1U, m_local_image_ctx
->snap_ids
.size()); // deleted on journal replay
141 TEST_F(TestImageSync
, Simple
) {
142 scribble(m_remote_image_ctx
, 10, 102400);
145 ImageSync
<> *request
= create_request(&ctx
);
147 ASSERT_EQ(0, ctx
.wait());
149 int64_t object_size
= std::min
<int64_t>(
150 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
151 bufferlist read_remote_bl
;
152 read_remote_bl
.append(std::string(object_size
, '1'));
153 bufferlist read_local_bl
;
154 read_local_bl
.append(std::string(object_size
, '1'));
156 for (uint64_t offset
= 0; offset
< m_remote_image_ctx
->size
;
157 offset
+= object_size
) {
158 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
160 librbd::io::ReadResult
{&read_remote_bl
}, 0));
161 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
163 librbd::io::ReadResult
{&read_local_bl
}, 0));
164 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
168 TEST_F(TestImageSync
, Resize
) {
169 int64_t object_size
= std::min
<int64_t>(
170 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
173 uint64_t len
= object_size
/ 10;
176 bl
.append(std::string(len
, '1'));
177 ASSERT_EQ((int)len
, m_remote_image_ctx
->io_work_queue
->write(off
, len
,
181 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
182 ASSERT_EQ(0, flush(m_remote_image_ctx
));
185 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, "snap", nullptr));
187 uint64_t size
= object_size
- 1;
188 librbd::NoOpProgressContext no_op_progress_ctx
;
189 ASSERT_EQ(0, m_remote_image_ctx
->operations
->resize(size
, true,
190 no_op_progress_ctx
));
193 ImageSync
<> *request
= create_request(&ctx
);
195 ASSERT_EQ(0, ctx
.wait());
197 bufferlist read_remote_bl
;
198 read_remote_bl
.append(std::string(len
, '\0'));
199 bufferlist read_local_bl
;
200 read_local_bl
.append(std::string(len
, '\0'));
202 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
203 off
, len
, librbd::io::ReadResult
{&read_remote_bl
}, 0));
204 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
205 off
, len
, librbd::io::ReadResult
{&read_local_bl
}, 0));
207 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
210 TEST_F(TestImageSync
, Discard
) {
211 int64_t object_size
= std::min
<int64_t>(
212 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
215 uint64_t len
= object_size
/ 10;
218 bl
.append(std::string(len
, '1'));
219 ASSERT_EQ((int)len
, m_remote_image_ctx
->io_work_queue
->write(off
, len
,
223 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
224 ASSERT_EQ(0, flush(m_remote_image_ctx
));
227 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, "snap", nullptr));
229 ASSERT_EQ((int)len
- 2,
230 m_remote_image_ctx
->io_work_queue
->discard(
231 off
+ 1, len
- 2, m_remote_image_ctx
->discard_granularity_bytes
));
233 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
234 ASSERT_EQ(0, flush(m_remote_image_ctx
));
238 ImageSync
<> *request
= create_request(&ctx
);
240 ASSERT_EQ(0, ctx
.wait());
242 bufferlist read_remote_bl
;
243 read_remote_bl
.append(std::string(object_size
, '\0'));
244 bufferlist read_local_bl
;
245 read_local_bl
.append(std::string(object_size
, '\0'));
247 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
248 off
, len
, librbd::io::ReadResult
{&read_remote_bl
}, 0));
249 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
250 off
, len
, librbd::io::ReadResult
{&read_local_bl
}, 0));
252 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
255 TEST_F(TestImageSync
, SnapshotStress
) {
256 std::list
<std::string
> snap_names
;
258 const int num_snaps
= 4;
259 for (int idx
= 0; idx
<= num_snaps
; ++idx
) {
260 scribble(m_remote_image_ctx
, 10, 102400);
262 librbd::NoOpProgressContext no_op_progress_ctx
;
263 uint64_t size
= 1 + rand() % m_image_size
;
264 ASSERT_EQ(0, m_remote_image_ctx
->operations
->resize(size
, true,
265 no_op_progress_ctx
));
266 ASSERT_EQ(0, m_remote_image_ctx
->state
->refresh());
268 if (idx
< num_snaps
) {
269 snap_names
.push_back("snap" + stringify(idx
+ 1));
270 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, snap_names
.back().c_str(),
273 snap_names
.push_back("");
278 ImageSync
<> *request
= create_request(&ctx
);
280 ASSERT_EQ(0, ctx
.wait());
282 int64_t object_size
= std::min
<int64_t>(
283 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
284 bufferlist read_remote_bl
;
285 read_remote_bl
.append(std::string(object_size
, '1'));
286 bufferlist read_local_bl
;
287 read_local_bl
.append(std::string(object_size
, '1'));
289 for (auto &snap_name
: snap_names
) {
290 uint64_t remote_snap_id
;
292 RWLock::RLocker
remote_snap_locker(m_remote_image_ctx
->snap_lock
);
293 remote_snap_id
= m_remote_image_ctx
->get_snap_id(
294 cls::rbd::UserSnapshotNamespace
{}, snap_name
);
297 uint64_t remote_size
;
300 m_remote_image_ctx
->state
->snap_set(remote_snap_id
, &ctx
);
301 ASSERT_EQ(0, ctx
.wait());
303 RWLock::RLocker
remote_snap_locker(m_remote_image_ctx
->snap_lock
);
304 remote_size
= m_remote_image_ctx
->get_image_size(
305 m_remote_image_ctx
->snap_id
);
308 uint64_t local_snap_id
;
310 RWLock::RLocker
snap_locker(m_local_image_ctx
->snap_lock
);
311 local_snap_id
= m_local_image_ctx
->get_snap_id(
312 cls::rbd::UserSnapshotNamespace
{}, snap_name
);
318 m_local_image_ctx
->state
->snap_set(local_snap_id
, &ctx
);
319 ASSERT_EQ(0, ctx
.wait());
321 RWLock::RLocker
snap_locker(m_local_image_ctx
->snap_lock
);
322 local_size
= m_local_image_ctx
->get_image_size(
323 m_local_image_ctx
->snap_id
);
325 ASSERT_EQ(0, m_local_image_ctx
->test_flags(m_local_image_ctx
->snap_id
,
326 RBD_FLAG_OBJECT_MAP_INVALID
,
327 m_local_image_ctx
->snap_lock
,
329 ASSERT_FALSE(flags_set
);
332 ASSERT_EQ(remote_size
, local_size
);
334 for (uint64_t offset
= 0; offset
< remote_size
; offset
+= object_size
) {
335 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
337 librbd::io::ReadResult
{&read_remote_bl
}, 0));
338 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
340 librbd::io::ReadResult
{&read_local_bl
}, 0));
341 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
346 } // namespace mirror