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/InstanceWatcher.h"
19 #include "tools/rbd_mirror/Threads.h"
21 void register_test_image_sync() {
29 void scribble(librbd::ImageCtx
*image_ctx
, int num_ops
, size_t max_size
)
31 max_size
= MIN(image_ctx
->size
, max_size
);
32 for (int i
=0; i
<num_ops
; i
++) {
33 uint64_t off
= rand() % (image_ctx
->size
- max_size
+ 1);
34 uint64_t len
= 1 + rand() % max_size
;
36 if (rand() % 4 == 0) {
37 ASSERT_EQ((int)len
, image_ctx
->io_work_queue
->discard(off
, len
, image_ctx
->skip_partial_discard
));
40 bl
.append(std::string(len
, '1'));
41 ASSERT_EQ((int)len
, image_ctx
->io_work_queue
->write(off
, len
,
46 RWLock::RLocker
owner_locker(image_ctx
->owner_lock
);
47 ASSERT_EQ(0, image_ctx
->flush());
50 } // anonymous namespace
51 class TestImageSync
: public TestFixture
{
54 void SetUp() override
{
56 create_and_open(m_local_io_ctx
, &m_local_image_ctx
);
57 create_and_open(m_remote_io_ctx
, &m_remote_image_ctx
);
59 m_instance_watcher
= rbd::mirror::InstanceWatcher
<>::create(
60 m_local_io_ctx
, m_threads
->work_queue
, nullptr);
61 m_instance_watcher
->handle_acquire_leader();
63 m_remote_journaler
= new ::journal::Journaler(
64 m_threads
->work_queue
, m_threads
->timer
, &m_threads
->timer_lock
,
65 m_remote_io_ctx
, m_remote_image_ctx
->id
, "mirror-uuid", {});
67 m_client_meta
= {"image-id"};
69 librbd::journal::ClientData
client_data(m_client_meta
);
70 bufferlist client_data_bl
;
71 ::encode(client_data
, client_data_bl
);
73 ASSERT_EQ(0, m_remote_journaler
->register_client(client_data_bl
));
76 void TearDown() override
{
77 TestFixture::TearDown();
79 m_instance_watcher
->handle_release_leader();
81 delete m_remote_journaler
;
82 delete m_instance_watcher
;
85 void create_and_open(librados::IoCtx
&io_ctx
, librbd::ImageCtx
**image_ctx
) {
87 ASSERT_EQ(0, create_image(rbd
, io_ctx
, m_image_name
, m_image_size
));
88 ASSERT_EQ(0, open_image(io_ctx
, m_image_name
, image_ctx
));
92 RWLock::RLocker
owner_locker((*image_ctx
)->owner_lock
);
93 (*image_ctx
)->exclusive_lock
->try_acquire_lock(&ctx
);
95 ASSERT_EQ(0, ctx
.wait());
96 ASSERT_TRUE((*image_ctx
)->exclusive_lock
->is_lock_owner());
99 ImageSync
<> *create_request(Context
*ctx
) {
100 return new ImageSync
<>(m_local_image_ctx
, m_remote_image_ctx
,
101 m_threads
->timer
, &m_threads
->timer_lock
,
102 "mirror-uuid", m_remote_journaler
, &m_client_meta
,
103 m_threads
->work_queue
, m_instance_watcher
, ctx
);
106 librbd::ImageCtx
*m_remote_image_ctx
;
107 librbd::ImageCtx
*m_local_image_ctx
;
108 rbd::mirror::InstanceWatcher
<> *m_instance_watcher
;
109 ::journal::Journaler
*m_remote_journaler
;
110 librbd::journal::MirrorPeerClientMeta m_client_meta
;
113 TEST_F(TestImageSync
, Empty
) {
115 ImageSync
<> *request
= create_request(&ctx
);
117 ASSERT_EQ(0, ctx
.wait());
119 ASSERT_EQ(0U, m_client_meta
.sync_points
.size());
120 ASSERT_EQ(0, m_remote_image_ctx
->state
->refresh());
121 ASSERT_EQ(0U, m_remote_image_ctx
->snap_ids
.size());
122 ASSERT_EQ(0, m_local_image_ctx
->state
->refresh());
123 ASSERT_EQ(1U, m_local_image_ctx
->snap_ids
.size()); // deleted on journal replay
126 TEST_F(TestImageSync
, Simple
) {
127 scribble(m_remote_image_ctx
, 10, 102400);
130 ImageSync
<> *request
= create_request(&ctx
);
132 ASSERT_EQ(0, ctx
.wait());
134 int64_t object_size
= std::min
<int64_t>(
135 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
136 bufferlist read_remote_bl
;
137 read_remote_bl
.append(std::string(object_size
, '1'));
138 bufferlist read_local_bl
;
139 read_local_bl
.append(std::string(object_size
, '1'));
141 for (uint64_t offset
= 0; offset
< m_remote_image_ctx
->size
;
142 offset
+= object_size
) {
143 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
145 librbd::io::ReadResult
{&read_remote_bl
}, 0));
146 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
148 librbd::io::ReadResult
{&read_local_bl
}, 0));
149 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
153 TEST_F(TestImageSync
, Resize
) {
154 int64_t object_size
= std::min
<int64_t>(
155 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
158 uint64_t len
= object_size
/ 10;
161 bl
.append(std::string(len
, '1'));
162 ASSERT_EQ((int)len
, m_remote_image_ctx
->io_work_queue
->write(off
, len
,
166 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
167 ASSERT_EQ(0, m_remote_image_ctx
->flush());
170 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, "snap", nullptr));
172 uint64_t size
= object_size
- 1;
173 librbd::NoOpProgressContext no_op_progress_ctx
;
174 ASSERT_EQ(0, m_remote_image_ctx
->operations
->resize(size
, true,
175 no_op_progress_ctx
));
178 ImageSync
<> *request
= create_request(&ctx
);
180 ASSERT_EQ(0, ctx
.wait());
182 bufferlist read_remote_bl
;
183 read_remote_bl
.append(std::string(len
, '\0'));
184 bufferlist read_local_bl
;
185 read_local_bl
.append(std::string(len
, '\0'));
187 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
188 off
, len
, librbd::io::ReadResult
{&read_remote_bl
}, 0));
189 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
190 off
, len
, librbd::io::ReadResult
{&read_local_bl
}, 0));
192 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
195 TEST_F(TestImageSync
, Discard
) {
196 int64_t object_size
= std::min
<int64_t>(
197 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
200 uint64_t len
= object_size
/ 10;
203 bl
.append(std::string(len
, '1'));
204 ASSERT_EQ((int)len
, m_remote_image_ctx
->io_work_queue
->write(off
, len
,
208 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
209 ASSERT_EQ(0, m_remote_image_ctx
->flush());
212 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, "snap", nullptr));
214 ASSERT_EQ((int)len
- 2, m_remote_image_ctx
->io_work_queue
->discard(off
+ 1,
215 len
- 2, m_remote_image_ctx
->skip_partial_discard
));
217 RWLock::RLocker
owner_locker(m_remote_image_ctx
->owner_lock
);
218 ASSERT_EQ(0, m_remote_image_ctx
->flush());
222 ImageSync
<> *request
= create_request(&ctx
);
224 ASSERT_EQ(0, ctx
.wait());
226 bufferlist read_remote_bl
;
227 read_remote_bl
.append(std::string(object_size
, '\0'));
228 bufferlist read_local_bl
;
229 read_local_bl
.append(std::string(object_size
, '\0'));
231 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
232 off
, len
, librbd::io::ReadResult
{&read_remote_bl
}, 0));
233 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
234 off
, len
, librbd::io::ReadResult
{&read_local_bl
}, 0));
236 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
239 TEST_F(TestImageSync
, SnapshotStress
) {
240 std::list
<std::string
> snap_names
;
242 const int num_snaps
= 4;
243 for (int idx
= 0; idx
<= num_snaps
; ++idx
) {
244 scribble(m_remote_image_ctx
, 10, 102400);
246 librbd::NoOpProgressContext no_op_progress_ctx
;
247 uint64_t size
= 1 + rand() % m_image_size
;
248 ASSERT_EQ(0, m_remote_image_ctx
->operations
->resize(size
, true,
249 no_op_progress_ctx
));
250 ASSERT_EQ(0, m_remote_image_ctx
->state
->refresh());
252 if (idx
< num_snaps
) {
253 snap_names
.push_back("snap" + stringify(idx
+ 1));
254 ASSERT_EQ(0, create_snap(m_remote_image_ctx
, snap_names
.back().c_str(),
257 snap_names
.push_back("");
262 ImageSync
<> *request
= create_request(&ctx
);
264 ASSERT_EQ(0, ctx
.wait());
266 int64_t object_size
= std::min
<int64_t>(
267 m_remote_image_ctx
->size
, 1 << m_remote_image_ctx
->order
);
268 bufferlist read_remote_bl
;
269 read_remote_bl
.append(std::string(object_size
, '1'));
270 bufferlist read_local_bl
;
271 read_local_bl
.append(std::string(object_size
, '1'));
273 for (auto &snap_name
: snap_names
) {
274 uint64_t remote_size
;
277 m_remote_image_ctx
->state
->snap_set(cls::rbd::UserSnapshotNamespace(),
280 ASSERT_EQ(0, ctx
.wait());
282 RWLock::RLocker
remote_snap_locker(m_remote_image_ctx
->snap_lock
);
283 remote_size
= m_remote_image_ctx
->get_image_size(
284 m_remote_image_ctx
->snap_id
);
290 m_local_image_ctx
->state
->snap_set(cls::rbd::UserSnapshotNamespace(),
293 ASSERT_EQ(0, ctx
.wait());
295 RWLock::RLocker
snap_locker(m_local_image_ctx
->snap_lock
);
296 local_size
= m_local_image_ctx
->get_image_size(
297 m_local_image_ctx
->snap_id
);
299 ASSERT_EQ(0, m_local_image_ctx
->test_flags(RBD_FLAG_OBJECT_MAP_INVALID
,
300 m_local_image_ctx
->snap_lock
,
302 ASSERT_FALSE(flags_set
);
305 ASSERT_EQ(remote_size
, local_size
);
307 for (uint64_t offset
= 0; offset
< remote_size
; offset
+= object_size
) {
308 ASSERT_LE(0, m_remote_image_ctx
->io_work_queue
->read(
310 librbd::io::ReadResult
{&read_remote_bl
}, 0));
311 ASSERT_LE(0, m_local_image_ctx
->io_work_queue
->read(
313 librbd::io::ReadResult
{&read_local_bl
}, 0));
314 ASSERT_TRUE(read_remote_bl
.contents_equal(read_local_bl
));
319 } // namespace mirror