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