]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rbd_mirror/test_ImageSync.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / test / rbd_mirror / test_ImageSync.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
22
23 void register_test_image_sync() {
24 }
25
26 namespace rbd {
27 namespace mirror {
28
29 namespace {
30
31 int flush(librbd::ImageCtx *image_ctx) {
32 C_SaferCond 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, {});
37 req->send();
38 delete req;
39 return ctx.wait();
40 }
41
42 void scribble(librbd::ImageCtx *image_ctx, int num_ops, uint64_t max_size)
43 {
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;
48
49 if (rand() % 4 == 0) {
50 ASSERT_EQ((int)len,
51 image_ctx->io_work_queue->discard(
52 off, len, image_ctx->discard_granularity_bytes));
53 } else {
54 bufferlist bl;
55 bl.append(std::string(len, '1'));
56 ASSERT_EQ((int)len, image_ctx->io_work_queue->write(off, len,
57 std::move(bl), 0));
58 }
59 }
60
61 RWLock::RLocker owner_locker(image_ctx->owner_lock);
62 ASSERT_EQ(0, flush(image_ctx));
63 }
64
65 } // anonymous namespace
66 class TestImageSync : public TestFixture {
67 public:
68
69 void SetUp() override {
70 TestFixture::SetUp();
71 create_and_open(m_local_io_ctx, &m_local_image_ctx);
72 create_and_open(m_remote_io_ctx, &m_remote_image_ctx);
73
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();
77
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", {});
81
82 m_client_meta = {"image-id"};
83
84 librbd::journal::ClientData client_data(m_client_meta);
85 bufferlist client_data_bl;
86 encode(client_data, client_data_bl);
87
88 ASSERT_EQ(0, m_remote_journaler->register_client(client_data_bl));
89 }
90
91 void TearDown() override {
92 TestFixture::TearDown();
93
94 m_instance_watcher->handle_release_leader();
95
96 delete m_remote_journaler;
97 delete m_instance_watcher;
98 }
99
100 void create_and_open(librados::IoCtx &io_ctx, librbd::ImageCtx **image_ctx) {
101 librbd::RBD rbd;
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));
104
105 C_SaferCond ctx;
106 {
107 RWLock::RLocker owner_locker((*image_ctx)->owner_lock);
108 (*image_ctx)->exclusive_lock->try_acquire_lock(&ctx);
109 }
110 ASSERT_EQ(0, ctx.wait());
111 ASSERT_TRUE((*image_ctx)->exclusive_lock->is_lock_owner());
112 }
113
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);
119 }
120
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;
126 };
127
128 TEST_F(TestImageSync, Empty) {
129 C_SaferCond ctx;
130 ImageSync<> *request = create_request(&ctx);
131 request->send();
132 ASSERT_EQ(0, ctx.wait());
133
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
139 }
140
141 TEST_F(TestImageSync, Simple) {
142 scribble(m_remote_image_ctx, 10, 102400);
143
144 C_SaferCond ctx;
145 ImageSync<> *request = create_request(&ctx);
146 request->send();
147 ASSERT_EQ(0, ctx.wait());
148
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'));
155
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(
159 offset, object_size,
160 librbd::io::ReadResult{&read_remote_bl}, 0));
161 ASSERT_LE(0, m_local_image_ctx->io_work_queue->read(
162 offset, object_size,
163 librbd::io::ReadResult{&read_local_bl}, 0));
164 ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
165 }
166 }
167
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);
171
172 uint64_t off = 0;
173 uint64_t len = object_size / 10;
174
175 bufferlist bl;
176 bl.append(std::string(len, '1'));
177 ASSERT_EQ((int)len, m_remote_image_ctx->io_work_queue->write(off, len,
178 std::move(bl),
179 0));
180 {
181 RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock);
182 ASSERT_EQ(0, flush(m_remote_image_ctx));
183 }
184
185 ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap", nullptr));
186
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));
191
192 C_SaferCond ctx;
193 ImageSync<> *request = create_request(&ctx);
194 request->send();
195 ASSERT_EQ(0, ctx.wait());
196
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'));
201
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));
206
207 ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
208 }
209
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);
213
214 uint64_t off = 0;
215 uint64_t len = object_size / 10;
216
217 bufferlist bl;
218 bl.append(std::string(len, '1'));
219 ASSERT_EQ((int)len, m_remote_image_ctx->io_work_queue->write(off, len,
220 std::move(bl),
221 0));
222 {
223 RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock);
224 ASSERT_EQ(0, flush(m_remote_image_ctx));
225 }
226
227 ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap", nullptr));
228
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));
232 {
233 RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock);
234 ASSERT_EQ(0, flush(m_remote_image_ctx));
235 }
236
237 C_SaferCond ctx;
238 ImageSync<> *request = create_request(&ctx);
239 request->send();
240 ASSERT_EQ(0, ctx.wait());
241
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'));
246
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));
251
252 ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
253 }
254
255 TEST_F(TestImageSync, SnapshotStress) {
256 std::list<std::string> snap_names;
257
258 const int num_snaps = 4;
259 for (int idx = 0; idx <= num_snaps; ++idx) {
260 scribble(m_remote_image_ctx, 10, 102400);
261
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());
267
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(),
271 nullptr));
272 } else {
273 snap_names.push_back("");
274 }
275 }
276
277 C_SaferCond ctx;
278 ImageSync<> *request = create_request(&ctx);
279 request->send();
280 ASSERT_EQ(0, ctx.wait());
281
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'));
288
289 for (auto &snap_name : snap_names) {
290 uint64_t remote_snap_id;
291 {
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);
295 }
296
297 uint64_t remote_size;
298 {
299 C_SaferCond ctx;
300 m_remote_image_ctx->state->snap_set(remote_snap_id, &ctx);
301 ASSERT_EQ(0, ctx.wait());
302
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);
306 }
307
308 uint64_t local_snap_id;
309 {
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);
313 }
314
315 uint64_t local_size;
316 {
317 C_SaferCond ctx;
318 m_local_image_ctx->state->snap_set(local_snap_id, &ctx);
319 ASSERT_EQ(0, ctx.wait());
320
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);
324 bool flags_set;
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,
328 &flags_set));
329 ASSERT_FALSE(flags_set);
330 }
331
332 ASSERT_EQ(remote_size, local_size);
333
334 for (uint64_t offset = 0; offset < remote_size; offset += object_size) {
335 ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read(
336 offset, object_size,
337 librbd::io::ReadResult{&read_remote_bl}, 0));
338 ASSERT_LE(0, m_local_image_ctx->io_work_queue->read(
339 offset, object_size,
340 librbd::io::ReadResult{&read_local_bl}, 0));
341 ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
342 }
343 }
344 }
345
346 } // namespace mirror
347 } // namespace rbd