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 "test/librbd/test_support.h"
6 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
7 #include "common/bit_vector.hpp"
8 #include "librbd/ImageState.h"
9 #include "librbd/internal.h"
10 #include "librbd/ObjectMap.h"
11 #include "librbd/object_map/SnapshotRemoveRequest.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
16 namespace object_map
{
19 using ::testing::DoDefault
;
20 using ::testing::Return
;
21 using ::testing::StrEq
;
23 class TestMockObjectMapSnapshotRemoveRequest
: public TestMockFixture
{
25 void expect_load_map(librbd::ImageCtx
*ictx
, uint64_t snap_id
, int r
) {
26 std::string
snap_oid(ObjectMap
<>::object_map_name(ictx
->id
, snap_id
));
28 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
29 exec(snap_oid
, _
, StrEq("rbd"), StrEq("object_map_load"), _
, _
, _
))
32 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
33 exec(snap_oid
, _
, StrEq("rbd"), StrEq("object_map_load"), _
, _
, _
))
34 .WillOnce(DoDefault());
38 void expect_remove_snapshot(librbd::ImageCtx
*ictx
, int r
) {
39 std::string
oid(ObjectMap
<>::object_map_name(ictx
->id
, CEPH_NOSNAP
));
41 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
42 exec(oid
, _
, StrEq("lock"), StrEq("assert_locked"), _
, _
, _
))
45 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
46 exec(oid
, _
, StrEq("lock"), StrEq("assert_locked"), _
, _
, _
))
47 .WillOnce(DoDefault());
48 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
49 exec(oid
, _
, StrEq("rbd"), StrEq("object_map_snap_remove"), _
, _
, _
))
50 .WillOnce(DoDefault());
54 void expect_remove_map(librbd::ImageCtx
*ictx
, uint64_t snap_id
, int r
) {
55 std::string
snap_oid(ObjectMap
<>::object_map_name(ictx
->id
, snap_id
));
57 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
), remove(snap_oid
, _
))
60 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
), remove(snap_oid
, _
))
61 .WillOnce(DoDefault());
65 void expect_invalidate(librbd::ImageCtx
*ictx
) {
66 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
67 exec(ictx
->header_oid
, _
, StrEq("rbd"), StrEq("set_flags"), _
, _
, _
))
68 .WillOnce(DoDefault());
72 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, Success
) {
73 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
75 librbd::ImageCtx
*ictx
;
76 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
77 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
78 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
80 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
81 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
82 expect_load_map(ictx
, snap_id
, 0);
83 expect_remove_snapshot(ictx
, 0);
85 expect_remove_map(ictx
, snap_id
, 0);
87 ceph::BitVector
<2> object_map
;
89 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
90 *ictx
, &object_map
, snap_id
, &cond_ctx
);
92 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
93 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
96 ASSERT_EQ(0, cond_ctx
.wait());
98 expect_unlock_exclusive_lock(*ictx
);
101 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, LoadMapMissing
) {
102 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
104 librbd::ImageCtx
*ictx
;
105 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
106 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
107 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
109 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
110 expect_load_map(ictx
, snap_id
, -ENOENT
);
112 ceph::BitVector
<2> object_map
;
113 C_SaferCond cond_ctx
;
114 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
115 *ictx
, &object_map
, snap_id
, &cond_ctx
);
117 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
118 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
121 ASSERT_EQ(0, cond_ctx
.wait());
123 expect_unlock_exclusive_lock(*ictx
);
126 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, LoadMapError
) {
127 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
129 librbd::ImageCtx
*ictx
;
130 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
131 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
132 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
134 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
135 expect_load_map(ictx
, snap_id
, -EINVAL
);
136 expect_invalidate(ictx
);
137 expect_remove_map(ictx
, snap_id
, 0);
139 ceph::BitVector
<2> object_map
;
140 C_SaferCond cond_ctx
;
141 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
142 *ictx
, &object_map
, snap_id
, &cond_ctx
);
144 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
145 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
148 ASSERT_EQ(0, cond_ctx
.wait());
150 expect_unlock_exclusive_lock(*ictx
);
153 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, RemoveSnapshotMissing
) {
154 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
156 librbd::ImageCtx
*ictx
;
157 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
158 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
159 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
161 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
162 expect_load_map(ictx
, snap_id
, 0);
163 expect_remove_snapshot(ictx
, -ENOENT
);
164 expect_remove_map(ictx
, snap_id
, 0);
166 ceph::BitVector
<2> object_map
;
167 C_SaferCond cond_ctx
;
168 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
169 *ictx
, &object_map
, snap_id
, &cond_ctx
);
171 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
172 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
175 ASSERT_EQ(0, cond_ctx
.wait());
177 expect_unlock_exclusive_lock(*ictx
);
180 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, RemoveSnapshotError
) {
181 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
183 librbd::ImageCtx
*ictx
;
184 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
185 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
186 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
188 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
189 expect_load_map(ictx
, snap_id
, 0);
190 expect_remove_snapshot(ictx
, -EINVAL
);
191 expect_invalidate(ictx
);
192 expect_remove_map(ictx
, snap_id
, 0);
194 ceph::BitVector
<2> object_map
;
195 C_SaferCond cond_ctx
;
196 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
197 *ictx
, &object_map
, snap_id
, &cond_ctx
);
199 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
200 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
203 ASSERT_EQ(0, cond_ctx
.wait());
205 expect_unlock_exclusive_lock(*ictx
);
208 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, RemoveMapMissing
) {
209 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
211 librbd::ImageCtx
*ictx
;
212 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
213 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
214 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
216 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
217 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
218 expect_load_map(ictx
, snap_id
, 0);
219 expect_remove_snapshot(ictx
, 0);
221 expect_remove_map(ictx
, snap_id
, -ENOENT
);
223 ceph::BitVector
<2> object_map
;
224 C_SaferCond cond_ctx
;
225 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
226 *ictx
, &object_map
, snap_id
, &cond_ctx
);
228 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
229 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
232 ASSERT_EQ(0, cond_ctx
.wait());
234 expect_unlock_exclusive_lock(*ictx
);
237 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, RemoveMapError
) {
238 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
240 librbd::ImageCtx
*ictx
;
241 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
242 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
243 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
245 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
246 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
247 expect_load_map(ictx
, snap_id
, 0);
248 expect_remove_snapshot(ictx
, 0);
250 expect_remove_map(ictx
, snap_id
, -EINVAL
);
252 ceph::BitVector
<2> object_map
;
253 C_SaferCond cond_ctx
;
254 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
255 *ictx
, &object_map
, snap_id
, &cond_ctx
);
257 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
258 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
261 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
263 expect_unlock_exclusive_lock(*ictx
);
266 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, ScrubCleanObjects
) {
267 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
269 librbd::ImageCtx
*ictx
;
270 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
271 librbd::NoOpProgressContext prog_ctx
;
272 uint64_t size
= 4294967296; // 4GB = 1024 * 4MB
273 ASSERT_EQ(0, resize(ictx
, size
));
275 // update image objectmap for snap inherit
276 ceph::BitVector
<2> object_map
;
277 object_map
.resize(1024);
278 for (uint64_t i
= 512; i
< object_map
.size(); ++i
) {
279 object_map
[i
] = i
% 2 == 0 ? OBJECT_EXISTS
: OBJECT_NONEXISTENT
;
282 C_SaferCond cond_ctx1
;
284 librbd::ObjectMap
<ImageCtx
> om(*ictx
, ictx
->snap_id
);
285 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
286 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
287 om
.set_object_map(object_map
);
288 om
.aio_save(&cond_ctx1
);
290 ASSERT_EQ(0, cond_ctx1
.wait());
291 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
292 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
294 // simutate the image objectmap state after creating snap
295 for (uint64_t i
= 512; i
< object_map
.size(); ++i
) {
296 object_map
[i
] = i
% 2 == 0 ? OBJECT_EXISTS_CLEAN
: OBJECT_NONEXISTENT
;
299 C_SaferCond cond_ctx2
;
300 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
301 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
302 *ictx
, &object_map
, snap_id
, &cond_ctx2
);
304 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
305 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
308 ASSERT_EQ(0, cond_ctx2
.wait());
310 for (uint64_t i
= 512; i
< object_map
.size(); ++i
) {
311 ASSERT_EQ(i
% 2 == 0 ? OBJECT_EXISTS
: OBJECT_NONEXISTENT
,
316 } // namespace object_map
317 } // namespace librbd