1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/librbd/test_mock_fixture.h"
5 #include "include/interval_set.h"
6 #include "include/rbd/librbd.hpp"
7 #include "include/rbd/object_map_types.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/internal.h"
11 #include "librbd/Operations.h"
12 #include "librbd/api/Image.h"
13 #include "librbd/deep_copy/ObjectCopyRequest.h"
14 #include "librbd/io/ImageRequest.h"
15 #include "librbd/io/ImageRequestWQ.h"
16 #include "librbd/io/ReadResult.h"
17 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
18 #include "test/librbd/mock/MockImageCtx.h"
19 #include "test/librbd/test_support.h"
24 struct MockTestImageCtx
: public librbd::MockImageCtx
{
25 explicit MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
26 : librbd::MockImageCtx(image_ctx
) {
29 MockTestImageCtx
*parent
= nullptr;
32 } // anonymous namespace
36 inline ImageCtx
* get_image_ctx(MockTestImageCtx
* image_ctx
) {
37 return image_ctx
->image_ctx
;
45 struct ImageRequest
<MockTestImageCtx
> {
46 static ImageRequest
*s_instance
;
48 static void aio_read(MockTestImageCtx
*ictx
, AioCompletion
*c
,
49 Extents
&&image_extents
, ReadResult
&&read_result
,
50 int op_flags
, const ZTracer::Trace
&parent_trace
) {
51 ceph_assert(s_instance
!= nullptr);
52 s_instance
->aio_read(c
, image_extents
);
54 MOCK_METHOD2(aio_read
, void(AioCompletion
*, const Extents
&));
57 ImageRequest
<MockTestImageCtx
> *ImageRequest
<MockTestImageCtx
>::s_instance
= nullptr;
63 // template definitions
64 #include "librbd/deep_copy/ObjectCopyRequest.cc"
65 template class librbd::deep_copy::ObjectCopyRequest
<librbd::MockTestImageCtx
>;
67 bool operator==(const SnapContext
& rhs
, const SnapContext
& lhs
) {
68 return (rhs
.seq
== lhs
.seq
&& rhs
.snaps
== lhs
.snaps
);
75 using ::testing::DoAll
;
76 using ::testing::DoDefault
;
77 using ::testing::InSequence
;
78 using ::testing::Invoke
;
79 using ::testing::Return
;
80 using ::testing::ReturnNew
;
81 using ::testing::WithArg
;
85 void scribble(librbd::ImageCtx
*image_ctx
, int num_ops
, size_t max_size
,
86 interval_set
<uint64_t> *what
)
88 uint64_t object_size
= 1 << image_ctx
->order
;
89 for (int i
= 0; i
< num_ops
; i
++) {
90 uint64_t off
= rand() % (object_size
- max_size
+ 1);
91 uint64_t len
= 1 + rand() % max_size
;
92 std::cout
<< __func__
<< ": off=" << off
<< ", len=" << len
<< std::endl
;
95 bl
.append(std::string(len
, '1'));
97 int r
= image_ctx
->io_work_queue
->write(off
, len
, std::move(bl
), 0);
98 ASSERT_EQ(static_cast<int>(len
), r
);
100 interval_set
<uint64_t> w
;
104 std::cout
<< " wrote " << *what
<< std::endl
;
107 } // anonymous namespace
109 class TestMockDeepCopyObjectCopyRequest
: public TestMockFixture
{
111 typedef ObjectCopyRequest
<librbd::MockTestImageCtx
> MockObjectCopyRequest
;
113 librbd::ImageCtx
*m_src_image_ctx
;
114 librbd::ImageCtx
*m_dst_image_ctx
;
115 ThreadPool
*m_thread_pool
;
116 ContextWQ
*m_work_queue
;
119 std::vector
<librados::snap_t
> m_src_snap_ids
;
120 std::vector
<librados::snap_t
> m_dst_snap_ids
;
122 void SetUp() override
{
123 TestMockFixture::SetUp();
125 ASSERT_EQ(0, open_image(m_image_name
, &m_src_image_ctx
));
127 librbd::NoOpProgressContext no_op
;
128 m_image_size
= 1 << m_src_image_ctx
->order
;
129 ASSERT_EQ(0, m_src_image_ctx
->operations
->resize(m_image_size
, true, no_op
));
132 std::string dst_image_name
= get_temp_image_name();
133 ASSERT_EQ(0, create_image_pp(rbd
, m_ioctx
, dst_image_name
, m_image_size
));
134 ASSERT_EQ(0, open_image(dst_image_name
, &m_dst_image_ctx
));
136 librbd::ImageCtx::get_thread_pool_instance(m_src_image_ctx
->cct
,
137 &m_thread_pool
, &m_work_queue
);
140 bool is_fast_diff(librbd::MockImageCtx
&mock_image_ctx
) {
141 return (mock_image_ctx
.features
& RBD_FEATURE_FAST_DIFF
) != 0;
144 void prepare_exclusive_lock(librbd::MockImageCtx
&mock_image_ctx
,
145 librbd::MockExclusiveLock
&mock_exclusive_lock
) {
146 if ((mock_image_ctx
.features
& RBD_FEATURE_EXCLUSIVE_LOCK
) == 0) {
149 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
152 void expect_get_object_count(librbd::MockImageCtx
& mock_image_ctx
) {
153 EXPECT_CALL(mock_image_ctx
, get_object_count(_
))
154 .WillRepeatedly(Invoke([&mock_image_ctx
](librados::snap_t snap_id
) {
155 return mock_image_ctx
.image_ctx
->get_object_count(snap_id
);
159 void expect_test_features(librbd::MockImageCtx
&mock_image_ctx
) {
160 EXPECT_CALL(mock_image_ctx
, test_features(_
))
161 .WillRepeatedly(WithArg
<0>(Invoke([&mock_image_ctx
](uint64_t features
) {
162 return (mock_image_ctx
.features
& features
) != 0;
166 void expect_start_op(librbd::MockExclusiveLock
&mock_exclusive_lock
) {
167 if ((m_src_image_ctx
->features
& RBD_FEATURE_EXCLUSIVE_LOCK
) == 0) {
170 EXPECT_CALL(mock_exclusive_lock
, start_op(_
)).WillOnce(
171 ReturnNew
<FunctionContext
>([](int) {}));
174 void expect_list_snaps(librbd::MockTestImageCtx
&mock_image_ctx
,
175 librados::MockTestMemIoCtxImpl
&mock_io_ctx
,
176 const librados::snap_set_t
&snap_set
) {
177 expect_get_object_name(mock_image_ctx
);
178 expect_set_snap_read(mock_io_ctx
, CEPH_SNAPDIR
);
179 EXPECT_CALL(mock_io_ctx
,
180 list_snaps(mock_image_ctx
.image_ctx
->get_object_name(0), _
))
181 .WillOnce(DoAll(WithArg
<1>(Invoke([&snap_set
](librados::snap_set_t
*out_snap_set
) {
182 *out_snap_set
= snap_set
;
187 void expect_list_snaps(librbd::MockTestImageCtx
&mock_image_ctx
,
188 librados::MockTestMemIoCtxImpl
&mock_io_ctx
, int r
) {
189 expect_get_object_name(mock_image_ctx
);
190 expect_set_snap_read(mock_io_ctx
, CEPH_SNAPDIR
);
191 auto &expect
= EXPECT_CALL(mock_io_ctx
,
192 list_snaps(mock_image_ctx
.image_ctx
->get_object_name(0),
195 expect
.WillOnce(Return(r
));
197 expect
.WillOnce(DoDefault());
201 void expect_get_object_name(librbd::MockTestImageCtx
&mock_image_ctx
) {
202 EXPECT_CALL(mock_image_ctx
, get_object_name(0))
203 .WillOnce(Return(mock_image_ctx
.image_ctx
->get_object_name(0)));
206 MockObjectCopyRequest
*create_request(
207 librbd::MockTestImageCtx
&mock_src_image_ctx
,
208 librbd::MockTestImageCtx
&mock_dst_image_ctx
, Context
*on_finish
) {
209 expect_get_object_name(mock_dst_image_ctx
);
210 expect_get_object_count(mock_dst_image_ctx
);
211 return new MockObjectCopyRequest(&mock_src_image_ctx
, &mock_dst_image_ctx
,
212 m_snap_map
, 0, false, on_finish
);
215 void expect_set_snap_read(librados::MockTestMemIoCtxImpl
&mock_io_ctx
,
217 EXPECT_CALL(mock_io_ctx
, set_snap_read(snap_id
));
220 void expect_sparse_read(librados::MockTestMemIoCtxImpl
&mock_io_ctx
, uint64_t offset
,
221 uint64_t length
, int r
) {
223 auto &expect
= EXPECT_CALL(mock_io_ctx
, sparse_read(_
, offset
, length
, _
, _
));
225 expect
.WillOnce(Return(r
));
227 expect
.WillOnce(DoDefault());
231 void expect_sparse_read(librados::MockTestMemIoCtxImpl
&mock_io_ctx
,
232 const interval_set
<uint64_t> &extents
, int r
) {
233 for (auto extent
: extents
) {
234 expect_sparse_read(mock_io_ctx
, extent
.first
, extent
.second
, r
);
241 void expect_write(librados::MockTestMemIoCtxImpl
&mock_io_ctx
,
242 uint64_t offset
, uint64_t length
,
243 const SnapContext
&snapc
, int r
) {
244 auto &expect
= EXPECT_CALL(mock_io_ctx
, write(_
, _
, length
, offset
, snapc
));
246 expect
.WillOnce(Return(r
));
248 expect
.WillOnce(DoDefault());
252 void expect_write(librados::MockTestMemIoCtxImpl
&mock_io_ctx
,
253 const interval_set
<uint64_t> &extents
,
254 const SnapContext
&snapc
, int r
) {
255 for (auto extent
: extents
) {
256 expect_write(mock_io_ctx
, extent
.first
, extent
.second
, snapc
, r
);
263 void expect_truncate(librados::MockTestMemIoCtxImpl
&mock_io_ctx
,
264 uint64_t offset
, int r
) {
265 auto &expect
= EXPECT_CALL(mock_io_ctx
, truncate(_
, offset
, _
));
267 expect
.WillOnce(Return(r
));
269 expect
.WillOnce(DoDefault());
273 void expect_remove(librados::MockTestMemIoCtxImpl
&mock_io_ctx
, int r
) {
274 auto &expect
= EXPECT_CALL(mock_io_ctx
, remove(_
, _
));
276 expect
.WillOnce(Return(r
));
278 expect
.WillOnce(DoDefault());
282 void expect_update_object_map(librbd::MockTestImageCtx
&mock_image_ctx
,
283 librbd::MockObjectMap
&mock_object_map
,
284 librados::snap_t snap_id
, uint8_t state
,
286 if (mock_image_ctx
.image_ctx
->object_map
!= nullptr) {
287 auto &expect
= EXPECT_CALL(mock_object_map
, aio_update(snap_id
, 0, 1, state
, _
, _
, false, _
));
289 expect
.WillOnce(DoAll(WithArg
<7>(Invoke([this, r
](Context
*ctx
) {
290 m_work_queue
->queue(ctx
, r
);
294 expect
.WillOnce(DoAll(WithArg
<7>(Invoke([&mock_image_ctx
, snap_id
, state
](Context
*ctx
) {
295 ceph_assert(mock_image_ctx
.image_ctx
->snap_lock
.is_locked());
296 ceph_assert(mock_image_ctx
.image_ctx
->object_map_lock
.is_wlocked());
297 mock_image_ctx
.image_ctx
->object_map
->aio_update
<Context
>(
298 snap_id
, 0, 1, state
, boost::none
, {}, false, ctx
);
305 int create_snap(librbd::ImageCtx
*image_ctx
, const char* snap_name
,
306 librados::snap_t
*snap_id
) {
307 int r
= image_ctx
->operations
->snap_create(
308 cls::rbd::UserSnapshotNamespace(), snap_name
);
313 r
= image_ctx
->state
->refresh();
318 if (image_ctx
->snap_ids
.count({cls::rbd::UserSnapshotNamespace(),
323 if (snap_id
!= nullptr) {
324 *snap_id
= image_ctx
->snap_ids
[{cls::rbd::UserSnapshotNamespace(),
330 int create_snap(const char* snap_name
) {
331 librados::snap_t src_snap_id
;
332 int r
= create_snap(m_src_image_ctx
, snap_name
, &src_snap_id
);
337 librados::snap_t dst_snap_id
;
338 r
= create_snap(m_dst_image_ctx
, snap_name
, &dst_snap_id
);
343 // collection of all existing snaps in dst image
344 SnapIds
dst_snap_ids({dst_snap_id
});
345 if (!m_snap_map
.empty()) {
346 dst_snap_ids
.insert(dst_snap_ids
.end(),
347 m_snap_map
.rbegin()->second
.begin(),
348 m_snap_map
.rbegin()->second
.end());
350 m_snap_map
[src_snap_id
] = dst_snap_ids
;
351 m_src_snap_ids
.push_back(src_snap_id
);
352 m_dst_snap_ids
.push_back(dst_snap_id
);
357 std::string
get_snap_name(librbd::ImageCtx
*image_ctx
,
358 librados::snap_t snap_id
) {
359 auto it
= std::find_if(image_ctx
->snap_ids
.begin(),
360 image_ctx
->snap_ids
.end(),
361 [snap_id
](const std::pair
<std::pair
<cls::rbd::SnapshotNamespace
,
363 librados::snap_t
> &pair
) {
364 return (pair
.second
== snap_id
);
366 if (it
== image_ctx
->snap_ids
.end()) {
369 return it
->first
.second
;
372 int compare_objects() {
373 SnapMap
snap_map(m_snap_map
);
374 if (snap_map
.empty()) {
379 uint64_t object_size
= 1 << m_src_image_ctx
->order
;
380 while (!snap_map
.empty()) {
381 librados::snap_t src_snap_id
= snap_map
.begin()->first
;
382 librados::snap_t dst_snap_id
= *snap_map
.begin()->second
.begin();
383 snap_map
.erase(snap_map
.begin());
385 std::string snap_name
= get_snap_name(m_src_image_ctx
, src_snap_id
);
386 if (snap_name
.empty()) {
390 std::cout
<< "comparing '" << snap_name
<< " (" << src_snap_id
391 << " to " << dst_snap_id
<< ")" << std::endl
;
393 r
= librbd::api::Image
<>::snap_set(m_src_image_ctx
,
394 cls::rbd::UserSnapshotNamespace(),
400 r
= librbd::api::Image
<>::snap_set(m_dst_image_ctx
,
401 cls::rbd::UserSnapshotNamespace(),
408 src_bl
.append(std::string(object_size
, '1'));
409 r
= m_src_image_ctx
->io_work_queue
->read(
410 0, object_size
, librbd::io::ReadResult
{&src_bl
}, 0);
416 dst_bl
.append(std::string(object_size
, '1'));
417 r
= m_dst_image_ctx
->io_work_queue
->read(
418 0, object_size
, librbd::io::ReadResult
{&dst_bl
}, 0);
423 if (!src_bl
.contents_equal(dst_bl
)) {
428 r
= librbd::api::Image
<>::snap_set(m_src_image_ctx
,
429 cls::rbd::UserSnapshotNamespace(),
434 r
= librbd::api::Image
<>::snap_set(m_dst_image_ctx
,
435 cls::rbd::UserSnapshotNamespace(),
445 TEST_F(TestMockDeepCopyObjectCopyRequest
, DNE
) {
446 ASSERT_EQ(0, create_snap("copy"));
447 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
448 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
450 librbd::MockExclusiveLock mock_exclusive_lock
;
451 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
453 librbd::MockObjectMap mock_object_map
;
454 mock_dst_image_ctx
.object_map
= &mock_object_map
;
455 expect_test_features(mock_dst_image_ctx
);
458 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
459 mock_dst_image_ctx
, &ctx
);
461 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
462 request
->get_src_io_ctx()));
465 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, -ENOENT
);
468 ASSERT_EQ(-ENOENT
, ctx
.wait());
471 TEST_F(TestMockDeepCopyObjectCopyRequest
, Write
) {
472 // scribble some data
473 interval_set
<uint64_t> one
;
474 scribble(m_src_image_ctx
, 10, 102400, &one
);
476 ASSERT_EQ(0, create_snap("copy"));
477 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
478 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
480 librbd::MockExclusiveLock mock_exclusive_lock
;
481 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
483 librbd::MockObjectMap mock_object_map
;
484 mock_dst_image_ctx
.object_map
= &mock_object_map
;
486 expect_test_features(mock_dst_image_ctx
);
489 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
490 mock_dst_image_ctx
, &ctx
);
492 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
493 request
->get_src_io_ctx()));
494 librados::MockTestMemIoCtxImpl
&mock_dst_io_ctx(get_mock_io_ctx(
495 request
->get_dst_io_ctx()));
498 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
499 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[0]);
500 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), 0);
501 expect_start_op(mock_exclusive_lock
);
502 expect_write(mock_dst_io_ctx
, 0, one
.range_end(), {0, {}}, 0);
503 expect_start_op(mock_exclusive_lock
);
504 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
505 m_dst_snap_ids
[0], OBJECT_EXISTS
, 0);
508 ASSERT_EQ(0, ctx
.wait());
509 ASSERT_EQ(0, compare_objects());
512 TEST_F(TestMockDeepCopyObjectCopyRequest
, ReadMissingStaleSnapSet
) {
513 ASSERT_EQ(0, create_snap("one"));
514 ASSERT_EQ(0, create_snap("two"));
516 // scribble some data
517 interval_set
<uint64_t> one
;
518 scribble(m_src_image_ctx
, 10, 102400, &one
);
519 ASSERT_EQ(0, create_snap("three"));
521 ASSERT_EQ(0, create_snap("copy"));
522 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
523 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
525 librbd::MockExclusiveLock mock_exclusive_lock
;
526 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
528 librbd::MockObjectMap mock_object_map
;
529 mock_dst_image_ctx
.object_map
= &mock_object_map
;
531 expect_test_features(mock_dst_image_ctx
);
534 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
535 mock_dst_image_ctx
, &ctx
);
537 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
538 request
->get_src_io_ctx()));
539 librados::MockTestMemIoCtxImpl
&mock_dst_io_ctx(get_mock_io_ctx(
540 request
->get_dst_io_ctx()));
542 librados::clone_info_t dummy_clone_info
;
543 dummy_clone_info
.cloneid
= librados::SNAP_HEAD
;
544 dummy_clone_info
.size
= 123;
546 librados::snap_set_t dummy_snap_set1
;
547 dummy_snap_set1
.clones
.push_back(dummy_clone_info
);
549 dummy_clone_info
.size
= 234;
550 librados::snap_set_t dummy_snap_set2
;
551 dummy_snap_set2
.clones
.push_back(dummy_clone_info
);
554 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, dummy_snap_set1
);
555 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[3]);
556 expect_sparse_read(mock_src_io_ctx
, 0, 123, -ENOENT
);
557 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, dummy_snap_set2
);
558 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[3]);
559 expect_sparse_read(mock_src_io_ctx
, 0, 234, -ENOENT
);
560 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
561 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[3]);
562 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), 0);
563 expect_start_op(mock_exclusive_lock
);
564 expect_write(mock_dst_io_ctx
, 0, one
.range_end(),
565 {m_dst_snap_ids
[1], {m_dst_snap_ids
[1],
568 expect_start_op(mock_exclusive_lock
);
569 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
570 m_dst_snap_ids
[2], OBJECT_EXISTS
, 0);
571 expect_start_op(mock_exclusive_lock
);
572 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
573 m_dst_snap_ids
[3], is_fast_diff(mock_dst_image_ctx
) ?
574 OBJECT_EXISTS_CLEAN
: OBJECT_EXISTS
, 0);
577 ASSERT_EQ(0, ctx
.wait());
578 ASSERT_EQ(0, compare_objects());
581 TEST_F(TestMockDeepCopyObjectCopyRequest
, ReadMissingUpToDateSnapMap
) {
582 // scribble some data
583 interval_set
<uint64_t> one
;
584 scribble(m_src_image_ctx
, 10, 102400, &one
);
586 ASSERT_EQ(0, create_snap("copy"));
587 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
588 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
590 librbd::MockExclusiveLock mock_exclusive_lock
;
591 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
593 librbd::MockObjectMap mock_object_map
;
594 mock_dst_image_ctx
.object_map
= &mock_object_map
;
596 expect_test_features(mock_dst_image_ctx
);
599 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
600 mock_dst_image_ctx
, &ctx
);
602 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
603 request
->get_src_io_ctx()));
606 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
607 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[0]);
608 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), -ENOENT
);
609 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
612 ASSERT_EQ(-ENOENT
, ctx
.wait());
615 TEST_F(TestMockDeepCopyObjectCopyRequest
, ReadError
) {
616 // scribble some data
617 interval_set
<uint64_t> one
;
618 scribble(m_src_image_ctx
, 10, 102400, &one
);
620 ASSERT_EQ(0, create_snap("copy"));
621 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
622 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
624 librbd::MockExclusiveLock mock_exclusive_lock
;
625 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
627 librbd::MockObjectMap mock_object_map
;
628 mock_dst_image_ctx
.object_map
= &mock_object_map
;
630 expect_test_features(mock_dst_image_ctx
);
633 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
634 mock_dst_image_ctx
, &ctx
);
636 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
637 request
->get_src_io_ctx()));
640 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
641 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[0]);
642 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), -EINVAL
);
645 ASSERT_EQ(-EINVAL
, ctx
.wait());
648 TEST_F(TestMockDeepCopyObjectCopyRequest
, WriteError
) {
649 // scribble some data
650 interval_set
<uint64_t> one
;
651 scribble(m_src_image_ctx
, 10, 102400, &one
);
653 ASSERT_EQ(0, create_snap("copy"));
654 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
655 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
657 librbd::MockExclusiveLock mock_exclusive_lock
;
658 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
660 librbd::MockObjectMap mock_object_map
;
661 mock_dst_image_ctx
.object_map
= &mock_object_map
;
663 expect_test_features(mock_dst_image_ctx
);
666 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
667 mock_dst_image_ctx
, &ctx
);
669 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
670 request
->get_src_io_ctx()));
671 librados::MockTestMemIoCtxImpl
&mock_dst_io_ctx(get_mock_io_ctx(
672 request
->get_dst_io_ctx()));
675 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
676 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[0]);
677 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), 0);
678 expect_start_op(mock_exclusive_lock
);
679 expect_write(mock_dst_io_ctx
, 0, one
.range_end(), {0, {}}, -EINVAL
);
682 ASSERT_EQ(-EINVAL
, ctx
.wait());
685 TEST_F(TestMockDeepCopyObjectCopyRequest
, WriteSnaps
) {
686 // scribble some data
687 interval_set
<uint64_t> one
;
688 scribble(m_src_image_ctx
, 10, 102400, &one
);
689 ASSERT_EQ(0, create_snap("one"));
691 interval_set
<uint64_t> two
;
692 scribble(m_src_image_ctx
, 10, 102400, &two
);
693 ASSERT_EQ(0, create_snap("two"));
695 if (one
.range_end() < two
.range_end()) {
696 interval_set
<uint64_t> resize_diff
;
697 resize_diff
.insert(one
.range_end(), two
.range_end() - one
.range_end());
698 two
.union_of(resize_diff
);
701 ASSERT_EQ(0, create_snap("copy"));
702 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
703 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
705 librbd::MockExclusiveLock mock_exclusive_lock
;
706 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
708 librbd::MockObjectMap mock_object_map
;
709 mock_dst_image_ctx
.object_map
= &mock_object_map
;
711 expect_test_features(mock_dst_image_ctx
);
714 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
715 mock_dst_image_ctx
, &ctx
);
717 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
718 request
->get_src_io_ctx()));
719 librados::MockTestMemIoCtxImpl
&mock_dst_io_ctx(get_mock_io_ctx(
720 request
->get_dst_io_ctx()));
723 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
724 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[0]);
725 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), 0);
726 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[2]);
727 expect_sparse_read(mock_src_io_ctx
, two
, 0);
728 expect_start_op(mock_exclusive_lock
);
729 expect_write(mock_dst_io_ctx
, 0, one
.range_end(), {0, {}}, 0);
730 expect_start_op(mock_exclusive_lock
);
731 expect_write(mock_dst_io_ctx
, two
,
732 {m_dst_snap_ids
[0], {m_dst_snap_ids
[0]}}, 0);
733 expect_start_op(mock_exclusive_lock
);
734 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
735 m_dst_snap_ids
[0], OBJECT_EXISTS
, 0);
736 expect_start_op(mock_exclusive_lock
);
737 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
738 m_dst_snap_ids
[1], OBJECT_EXISTS
, 0);
739 expect_start_op(mock_exclusive_lock
);
740 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
741 m_dst_snap_ids
[2], is_fast_diff(mock_dst_image_ctx
) ?
742 OBJECT_EXISTS_CLEAN
: OBJECT_EXISTS
, 0);
745 ASSERT_EQ(0, ctx
.wait());
746 ASSERT_EQ(0, compare_objects());
749 TEST_F(TestMockDeepCopyObjectCopyRequest
, Trim
) {
750 ASSERT_EQ(0, m_src_image_ctx
->operations
->metadata_set(
751 "conf_rbd_skip_partial_discard", "false"));
752 m_src_image_ctx
->discard_granularity_bytes
= 0;
754 // scribble some data
755 interval_set
<uint64_t> one
;
756 scribble(m_src_image_ctx
, 10, 102400, &one
);
757 ASSERT_EQ(0, create_snap("one"));
760 uint64_t trim_offset
= rand() % one
.range_end();
761 ASSERT_LE(0, m_src_image_ctx
->io_work_queue
->discard(
762 trim_offset
, one
.range_end() - trim_offset
,
763 m_src_image_ctx
->discard_granularity_bytes
));
764 ASSERT_EQ(0, create_snap("copy"));
766 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
767 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
769 librbd::MockExclusiveLock mock_exclusive_lock
;
770 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
772 librbd::MockObjectMap mock_object_map
;
773 mock_dst_image_ctx
.object_map
= &mock_object_map
;
775 expect_test_features(mock_dst_image_ctx
);
778 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
779 mock_dst_image_ctx
, &ctx
);
781 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
782 request
->get_src_io_ctx()));
783 librados::MockTestMemIoCtxImpl
&mock_dst_io_ctx(get_mock_io_ctx(
784 request
->get_dst_io_ctx()));
787 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
788 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[0]);
789 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), 0);
790 expect_start_op(mock_exclusive_lock
);
791 expect_write(mock_dst_io_ctx
, 0, one
.range_end(), {0, {}}, 0);
792 expect_start_op(mock_exclusive_lock
);
793 expect_truncate(mock_dst_io_ctx
, trim_offset
, 0);
794 expect_start_op(mock_exclusive_lock
);
795 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
796 m_dst_snap_ids
[0], OBJECT_EXISTS
, 0);
797 expect_start_op(mock_exclusive_lock
);
798 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
799 m_dst_snap_ids
[1], OBJECT_EXISTS
, 0);
802 ASSERT_EQ(0, ctx
.wait());
803 ASSERT_EQ(0, compare_objects());
806 TEST_F(TestMockDeepCopyObjectCopyRequest
, Remove
) {
807 // scribble some data
808 interval_set
<uint64_t> one
;
809 scribble(m_src_image_ctx
, 10, 102400, &one
);
810 ASSERT_EQ(0, create_snap("one"));
811 ASSERT_EQ(0, create_snap("two"));
814 uint64_t object_size
= 1 << m_src_image_ctx
->order
;
815 ASSERT_LE(0, m_src_image_ctx
->io_work_queue
->discard(
816 0, object_size
, m_src_image_ctx
->discard_granularity_bytes
));
817 ASSERT_EQ(0, create_snap("copy"));
818 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
819 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
821 librbd::MockExclusiveLock mock_exclusive_lock
;
822 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
824 librbd::MockObjectMap mock_object_map
;
825 mock_dst_image_ctx
.object_map
= &mock_object_map
;
827 expect_test_features(mock_dst_image_ctx
);
830 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
831 mock_dst_image_ctx
, &ctx
);
833 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
834 request
->get_src_io_ctx()));
835 librados::MockTestMemIoCtxImpl
&mock_dst_io_ctx(get_mock_io_ctx(
836 request
->get_dst_io_ctx()));
839 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
840 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[1]);
841 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), 0);
842 expect_start_op(mock_exclusive_lock
);
843 expect_write(mock_dst_io_ctx
, 0, one
.range_end(), {0, {}}, 0);
844 expect_start_op(mock_exclusive_lock
);
845 expect_remove(mock_dst_io_ctx
, 0);
846 expect_start_op(mock_exclusive_lock
);
847 uint8_t state
= OBJECT_EXISTS
;
848 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
849 m_dst_snap_ids
[0], state
, 0);
850 expect_start_op(mock_exclusive_lock
);
851 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
852 m_dst_snap_ids
[1], is_fast_diff(mock_dst_image_ctx
) ?
853 OBJECT_EXISTS_CLEAN
: OBJECT_EXISTS
, 0);
856 ASSERT_EQ(0, ctx
.wait());
857 ASSERT_EQ(0, compare_objects());
860 TEST_F(TestMockDeepCopyObjectCopyRequest
, ObjectMapUpdateError
) {
861 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
863 // scribble some data
864 interval_set
<uint64_t> one
;
865 scribble(m_src_image_ctx
, 10, 102400, &one
);
867 ASSERT_EQ(0, create_snap("copy"));
868 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
869 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
871 librbd::MockExclusiveLock mock_exclusive_lock
;
872 prepare_exclusive_lock(mock_dst_image_ctx
, mock_exclusive_lock
);
874 librbd::MockObjectMap mock_object_map
;
875 mock_dst_image_ctx
.object_map
= &mock_object_map
;
877 expect_test_features(mock_dst_image_ctx
);
880 MockObjectCopyRequest
*request
= create_request(mock_src_image_ctx
,
881 mock_dst_image_ctx
, &ctx
);
883 librados::MockTestMemIoCtxImpl
&mock_src_io_ctx(get_mock_io_ctx(
884 request
->get_src_io_ctx()));
885 librados::MockTestMemIoCtxImpl
&mock_dst_io_ctx(get_mock_io_ctx(
886 request
->get_dst_io_ctx()));
889 expect_list_snaps(mock_src_image_ctx
, mock_src_io_ctx
, 0);
890 expect_set_snap_read(mock_src_io_ctx
, m_src_snap_ids
[0]);
891 expect_sparse_read(mock_src_io_ctx
, 0, one
.range_end(), 0);
892 expect_start_op(mock_exclusive_lock
);
893 expect_write(mock_dst_io_ctx
, 0, one
.range_end(), {0, {}}, 0);
894 expect_start_op(mock_exclusive_lock
);
895 expect_update_object_map(mock_dst_image_ctx
, mock_object_map
,
896 m_dst_snap_ids
[0], OBJECT_EXISTS
, -EBLACKLISTED
);
899 ASSERT_EQ(-EBLACKLISTED
, ctx
.wait());
902 } // namespace deep_copy
903 } // namespace librbd