]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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/librbd/test_mock_fixture.h" | |
5 | #include "test/librbd/test_support.h" | |
6 | #include "test/librbd/mock/MockImageCtx.h" | |
7 | #include "test/librbd/mock/MockJournal.h" | |
8 | #include "test/librbd/mock/cache/MockImageCache.h" | |
9 | #include "librbd/io/ImageRequest.h" | |
11fdf7f2 | 10 | #include "librbd/io/ObjectDispatchSpec.h" |
f67539c2 | 11 | #include "librbd/io/Utils.h" |
7c673cae FG |
12 | |
13 | namespace librbd { | |
14 | namespace { | |
15 | ||
11fdf7f2 TL |
16 | struct MockTestImageCtx; |
17 | ||
18 | struct MockTestJournal : public MockJournal { | |
19 | MOCK_METHOD4(append_write_event, uint64_t(uint64_t, size_t, | |
20 | const bufferlist &, bool)); | |
21 | MOCK_METHOD5(append_io_event_mock, uint64_t(const journal::EventEntry&, | |
22 | uint64_t, size_t, bool, int)); | |
23 | uint64_t append_io_event(journal::EventEntry &&event_entry, | |
24 | uint64_t offset, size_t length, | |
25 | bool flush_entry, int filter_ret_val) { | |
26 | // googlemock doesn't support move semantics | |
27 | return append_io_event_mock(event_entry, offset, length, flush_entry, | |
28 | filter_ret_val); | |
29 | } | |
30 | ||
31 | MOCK_METHOD2(commit_io_event, void(uint64_t, int)); | |
32 | }; | |
33 | ||
7c673cae FG |
34 | struct MockTestImageCtx : public MockImageCtx { |
35 | MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) { | |
36 | } | |
11fdf7f2 TL |
37 | |
38 | MockTestJournal* journal; | |
7c673cae FG |
39 | }; |
40 | ||
41 | } // anonymous namespace | |
42 | ||
43 | namespace util { | |
44 | ||
45 | inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) { | |
46 | return image_ctx->image_ctx; | |
47 | } | |
48 | ||
49 | } // namespace util | |
7c673cae FG |
50 | } // namespace librbd |
51 | ||
52 | #include "librbd/io/ImageRequest.cc" | |
53 | ||
54 | namespace librbd { | |
55 | namespace io { | |
56 | ||
f67539c2 TL |
57 | namespace util { |
58 | ||
59 | template<> | |
60 | void file_to_extents( | |
61 | MockTestImageCtx *image_ctx, uint64_t offset, uint64_t length, | |
62 | uint64_t buffer_offset, | |
63 | striper::LightweightObjectExtents *object_extents) { | |
64 | Striper::file_to_extents(image_ctx->cct, &image_ctx->layout, offset, length, | |
65 | 0, buffer_offset, object_extents); | |
66 | } | |
67 | ||
68 | template <> void extent_to_file( | |
69 | MockTestImageCtx* image_ctx, uint64_t object_no, uint64_t offset, | |
70 | uint64_t length, | |
71 | std::vector<std::pair<uint64_t, uint64_t> >& extents) { | |
72 | Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, object_no, | |
73 | offset, length, extents); | |
74 | } | |
75 | ||
76 | } // namespace util | |
77 | ||
7c673cae FG |
78 | using ::testing::_; |
79 | using ::testing::InSequence; | |
80 | using ::testing::Invoke; | |
81 | using ::testing::Return; | |
82 | using ::testing::WithArg; | |
11fdf7f2 TL |
83 | using ::testing::WithoutArgs; |
84 | using ::testing::Exactly; | |
7c673cae FG |
85 | |
86 | struct TestMockIoImageRequest : public TestMockFixture { | |
87 | typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest; | |
11fdf7f2 | 88 | typedef ImageReadRequest<librbd::MockTestImageCtx> MockImageReadRequest; |
7c673cae FG |
89 | typedef ImageWriteRequest<librbd::MockTestImageCtx> MockImageWriteRequest; |
90 | typedef ImageDiscardRequest<librbd::MockTestImageCtx> MockImageDiscardRequest; | |
91 | typedef ImageFlushRequest<librbd::MockTestImageCtx> MockImageFlushRequest; | |
92 | typedef ImageWriteSameRequest<librbd::MockTestImageCtx> MockImageWriteSameRequest; | |
c07f9fc5 | 93 | typedef ImageCompareAndWriteRequest<librbd::MockTestImageCtx> MockImageCompareAndWriteRequest; |
f67539c2 | 94 | typedef ImageListSnapsRequest<librbd::MockTestImageCtx> MockImageListSnapsRequest; |
7c673cae | 95 | |
11fdf7f2 | 96 | void expect_is_journal_appending(MockTestJournal &mock_journal, bool appending) { |
7c673cae FG |
97 | EXPECT_CALL(mock_journal, is_journal_appending()) |
98 | .WillOnce(Return(appending)); | |
99 | } | |
100 | ||
11fdf7f2 TL |
101 | void expect_get_modify_timestamp(MockTestImageCtx &mock_image_ctx, |
102 | bool needs_update) { | |
103 | if (needs_update) { | |
104 | mock_image_ctx.mtime_update_interval = 5; | |
105 | EXPECT_CALL(mock_image_ctx, get_modify_timestamp()) | |
106 | .WillOnce(Return(ceph_clock_now() - utime_t(10,0))); | |
107 | } else { | |
108 | mock_image_ctx.mtime_update_interval = 600; | |
109 | EXPECT_CALL(mock_image_ctx, get_modify_timestamp()) | |
110 | .WillOnce(Return(ceph_clock_now())); | |
111 | } | |
7c673cae FG |
112 | } |
113 | ||
11fdf7f2 TL |
114 | void expect_object_discard_request(MockTestImageCtx &mock_image_ctx, |
115 | uint64_t object_no, uint64_t offset, | |
116 | uint32_t length, int r) { | |
117 | EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_)) | |
118 | .WillOnce(Invoke([&mock_image_ctx, object_no, offset, length, r] | |
119 | (ObjectDispatchSpec* spec) { | |
120 | auto* discard_spec = boost::get<ObjectDispatchSpec::DiscardRequest>(&spec->request); | |
121 | ASSERT_TRUE(discard_spec != nullptr); | |
122 | ASSERT_EQ(object_no, discard_spec->object_no); | |
123 | ASSERT_EQ(offset, discard_spec->object_off); | |
124 | ASSERT_EQ(length, discard_spec->object_len); | |
125 | ||
126 | spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE; | |
127 | mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r); | |
7c673cae FG |
128 | })); |
129 | } | |
130 | ||
11fdf7f2 TL |
131 | void expect_object_request_send(MockTestImageCtx &mock_image_ctx, |
132 | int r) { | |
133 | EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_)) | |
134 | .WillOnce(Invoke([&mock_image_ctx, r](ObjectDispatchSpec* spec) { | |
135 | spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE; | |
136 | mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r); | |
137 | })); | |
7c673cae | 138 | } |
f67539c2 TL |
139 | |
140 | void expect_object_list_snaps_request(MockTestImageCtx &mock_image_ctx, | |
141 | uint64_t object_no, | |
142 | const SnapshotDelta& snap_delta, | |
143 | int r) { | |
144 | EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_)) | |
145 | .WillOnce( | |
146 | Invoke([&mock_image_ctx, object_no, snap_delta, r] | |
147 | (ObjectDispatchSpec* spec) { | |
148 | auto request = boost::get< | |
149 | librbd::io::ObjectDispatchSpec::ListSnapsRequest>( | |
150 | &spec->request); | |
151 | ASSERT_TRUE(request != nullptr); | |
152 | ASSERT_EQ(object_no, request->object_no); | |
153 | ||
154 | *request->snapshot_delta = snap_delta; | |
155 | spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE; | |
156 | mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r); | |
157 | })); | |
158 | } | |
7c673cae FG |
159 | }; |
160 | ||
11fdf7f2 TL |
161 | TEST_F(TestMockIoImageRequest, AioWriteModifyTimestamp) { |
162 | REQUIRE_FORMAT_V2(); | |
163 | ||
164 | librbd::ImageCtx *ictx; | |
165 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
166 | ||
167 | MockTestImageCtx mock_image_ctx(*ictx); | |
168 | MockTestJournal mock_journal; | |
169 | mock_image_ctx.journal = &mock_journal; | |
170 | ||
171 | mock_image_ctx.mtime_update_interval = 5; | |
172 | ||
173 | utime_t dummy = ceph_clock_now(); | |
174 | dummy -= utime_t(10,0); | |
175 | ||
176 | EXPECT_CALL(mock_image_ctx, get_modify_timestamp()) | |
177 | .Times(Exactly(3)) | |
178 | .WillOnce(Return(dummy)) | |
179 | .WillOnce(Return(dummy)) | |
180 | .WillOnce(Return(dummy + utime_t(10,0))); | |
181 | ||
182 | EXPECT_CALL(mock_image_ctx, set_modify_timestamp(_)) | |
183 | .Times(Exactly(1)); | |
184 | ||
185 | InSequence seq; | |
186 | expect_is_journal_appending(mock_journal, false); | |
187 | expect_object_request_send(mock_image_ctx, 0); | |
188 | ||
189 | C_SaferCond aio_comp_ctx_1, aio_comp_ctx_2; | |
190 | AioCompletion *aio_comp_1 = AioCompletion::create_and_start( | |
191 | &aio_comp_ctx_1, ictx, AIO_TYPE_WRITE); | |
192 | ||
193 | AioCompletion *aio_comp_2 = AioCompletion::create_and_start( | |
194 | &aio_comp_ctx_2, ictx, AIO_TYPE_WRITE); | |
195 | ||
196 | bufferlist bl; | |
197 | bl.append("1"); | |
f67539c2 TL |
198 | MockImageWriteRequest mock_aio_image_write_1( |
199 | mock_image_ctx, aio_comp_1, {{0, 1}}, std::move(bl), | |
200 | mock_image_ctx.get_data_io_context(), 0, {}); | |
11fdf7f2 | 201 | { |
9f95a23c | 202 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
11fdf7f2 TL |
203 | mock_aio_image_write_1.send(); |
204 | } | |
205 | ASSERT_EQ(0, aio_comp_ctx_1.wait()); | |
206 | ||
207 | expect_is_journal_appending(mock_journal, false); | |
208 | expect_object_request_send(mock_image_ctx, 0); | |
209 | ||
210 | bl.append("1"); | |
f67539c2 TL |
211 | MockImageWriteRequest mock_aio_image_write_2( |
212 | mock_image_ctx, aio_comp_2, {{0, 1}}, std::move(bl), | |
213 | mock_image_ctx.get_data_io_context(), 0, {}); | |
11fdf7f2 | 214 | { |
9f95a23c | 215 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
11fdf7f2 TL |
216 | mock_aio_image_write_2.send(); |
217 | } | |
218 | ASSERT_EQ(0, aio_comp_ctx_2.wait()); | |
219 | } | |
220 | ||
221 | TEST_F(TestMockIoImageRequest, AioReadAccessTimestamp) { | |
222 | REQUIRE_FORMAT_V2(); | |
223 | ||
224 | librbd::ImageCtx *ictx; | |
225 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
226 | ||
227 | MockTestImageCtx mock_image_ctx(*ictx); | |
228 | MockTestJournal mock_journal; | |
229 | mock_image_ctx.journal = &mock_journal; | |
230 | ||
231 | mock_image_ctx.atime_update_interval = 5; | |
232 | ||
233 | utime_t dummy = ceph_clock_now(); | |
234 | dummy -= utime_t(10,0); | |
235 | ||
236 | EXPECT_CALL(mock_image_ctx, get_access_timestamp()) | |
237 | .Times(Exactly(3)) | |
238 | .WillOnce(Return(dummy)) | |
239 | .WillOnce(Return(dummy)) | |
240 | .WillOnce(Return(dummy + utime_t(10,0))); | |
241 | ||
242 | EXPECT_CALL(mock_image_ctx, set_access_timestamp(_)) | |
243 | .Times(Exactly(1)); | |
244 | ||
245 | InSequence seq; | |
246 | expect_object_request_send(mock_image_ctx, 0); | |
247 | ||
248 | C_SaferCond aio_comp_ctx_1, aio_comp_ctx_2; | |
249 | AioCompletion *aio_comp_1 = AioCompletion::create_and_start( | |
250 | &aio_comp_ctx_1, ictx, AIO_TYPE_READ); | |
251 | ||
252 | ||
253 | ReadResult rr; | |
f67539c2 TL |
254 | MockImageReadRequest mock_aio_image_read_1( |
255 | mock_image_ctx, aio_comp_1, {{0, 1}}, std::move(rr), | |
256 | mock_image_ctx.get_data_io_context(), 0, 0, {}); | |
11fdf7f2 | 257 | { |
9f95a23c | 258 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
11fdf7f2 TL |
259 | mock_aio_image_read_1.send(); |
260 | } | |
261 | ASSERT_EQ(1, aio_comp_ctx_1.wait()); | |
262 | ||
263 | AioCompletion *aio_comp_2 = AioCompletion::create_and_start( | |
264 | &aio_comp_ctx_2, ictx, AIO_TYPE_READ); | |
265 | expect_object_request_send(mock_image_ctx, 0); | |
266 | ||
f67539c2 TL |
267 | MockImageReadRequest mock_aio_image_read_2( |
268 | mock_image_ctx, aio_comp_2, {{0, 1}}, std::move(rr), | |
269 | mock_image_ctx.get_data_io_context(), 0, 0, {}); | |
11fdf7f2 | 270 | { |
9f95a23c | 271 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
11fdf7f2 TL |
272 | mock_aio_image_read_2.send(); |
273 | } | |
274 | ASSERT_EQ(1, aio_comp_ctx_2.wait()); | |
275 | } | |
276 | ||
277 | TEST_F(TestMockIoImageRequest, PartialDiscard) { | |
278 | librbd::ImageCtx *ictx; | |
279 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
280 | ictx->discard_granularity_bytes = 0; | |
281 | ||
282 | MockTestImageCtx mock_image_ctx(*ictx); | |
283 | mock_image_ctx.journal = nullptr; | |
284 | ||
285 | InSequence seq; | |
286 | expect_get_modify_timestamp(mock_image_ctx, false); | |
287 | expect_object_discard_request(mock_image_ctx, 0, 16, 63, 0); | |
288 | expect_object_discard_request(mock_image_ctx, 0, 84, 100, 0); | |
289 | ||
290 | C_SaferCond aio_comp_ctx; | |
291 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
292 | &aio_comp_ctx, ictx, AIO_TYPE_DISCARD); | |
293 | MockImageDiscardRequest mock_aio_image_discard( | |
294 | mock_image_ctx, aio_comp, {{16, 63}, {84, 100}}, | |
f67539c2 | 295 | ictx->discard_granularity_bytes, mock_image_ctx.get_data_io_context(), {}); |
11fdf7f2 | 296 | { |
9f95a23c | 297 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
11fdf7f2 TL |
298 | mock_aio_image_discard.send(); |
299 | } | |
300 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
301 | } | |
302 | ||
303 | TEST_F(TestMockIoImageRequest, TailDiscard) { | |
304 | librbd::ImageCtx *ictx; | |
305 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
306 | ASSERT_EQ(0, resize(ictx, ictx->layout.object_size)); | |
307 | ictx->discard_granularity_bytes = 2 * ictx->layout.object_size; | |
308 | ||
309 | MockTestImageCtx mock_image_ctx(*ictx); | |
310 | mock_image_ctx.journal = nullptr; | |
311 | ||
312 | InSequence seq; | |
313 | expect_get_modify_timestamp(mock_image_ctx, false); | |
314 | expect_object_discard_request( | |
315 | mock_image_ctx, 0, ictx->layout.object_size - 1024, 1024, 0); | |
316 | ||
317 | C_SaferCond aio_comp_ctx; | |
318 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
319 | &aio_comp_ctx, ictx, AIO_TYPE_DISCARD); | |
320 | MockImageDiscardRequest mock_aio_image_discard( | |
321 | mock_image_ctx, aio_comp, | |
322 | {{ictx->layout.object_size - 1024, 1024}}, | |
f67539c2 | 323 | ictx->discard_granularity_bytes, mock_image_ctx.get_data_io_context(), {}); |
11fdf7f2 | 324 | { |
9f95a23c | 325 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
11fdf7f2 TL |
326 | mock_aio_image_discard.send(); |
327 | } | |
328 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
329 | } | |
330 | ||
331 | TEST_F(TestMockIoImageRequest, DiscardGranularity) { | |
332 | librbd::ImageCtx *ictx; | |
333 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
334 | ASSERT_EQ(0, resize(ictx, ictx->layout.object_size)); | |
335 | ictx->discard_granularity_bytes = 32; | |
336 | ||
337 | MockTestImageCtx mock_image_ctx(*ictx); | |
338 | mock_image_ctx.journal = nullptr; | |
339 | ||
340 | InSequence seq; | |
341 | expect_get_modify_timestamp(mock_image_ctx, false); | |
342 | expect_object_discard_request(mock_image_ctx, 0, 32, 32, 0); | |
343 | expect_object_discard_request(mock_image_ctx, 0, 96, 64, 0); | |
344 | expect_object_discard_request( | |
345 | mock_image_ctx, 0, ictx->layout.object_size - 32, 32, 0); | |
346 | ||
347 | C_SaferCond aio_comp_ctx; | |
348 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
349 | &aio_comp_ctx, ictx, AIO_TYPE_DISCARD); | |
350 | MockImageDiscardRequest mock_aio_image_discard( | |
351 | mock_image_ctx, aio_comp, | |
352 | {{16, 63}, {96, 31}, {84, 100}, {ictx->layout.object_size - 33, 33}}, | |
f67539c2 | 353 | ictx->discard_granularity_bytes, mock_image_ctx.get_data_io_context(), {}); |
11fdf7f2 | 354 | { |
9f95a23c | 355 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
11fdf7f2 TL |
356 | mock_aio_image_discard.send(); |
357 | } | |
358 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
359 | } | |
360 | ||
7c673cae FG |
361 | TEST_F(TestMockIoImageRequest, AioWriteJournalAppendDisabled) { |
362 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
363 | ||
364 | librbd::ImageCtx *ictx; | |
365 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
366 | ||
7c673cae | 367 | MockTestImageCtx mock_image_ctx(*ictx); |
11fdf7f2 | 368 | MockTestJournal mock_journal; |
7c673cae FG |
369 | mock_image_ctx.journal = &mock_journal; |
370 | ||
371 | InSequence seq; | |
11fdf7f2 | 372 | expect_get_modify_timestamp(mock_image_ctx, false); |
7c673cae | 373 | expect_is_journal_appending(mock_journal, false); |
11fdf7f2 | 374 | expect_object_request_send(mock_image_ctx, 0); |
7c673cae FG |
375 | |
376 | C_SaferCond aio_comp_ctx; | |
377 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
378 | &aio_comp_ctx, ictx, AIO_TYPE_WRITE); | |
379 | ||
380 | bufferlist bl; | |
381 | bl.append("1"); | |
f67539c2 TL |
382 | MockImageWriteRequest mock_aio_image_write( |
383 | mock_image_ctx, aio_comp, {{0, 1}}, std::move(bl), | |
384 | mock_image_ctx.get_data_io_context(), 0, {}); | |
7c673cae | 385 | { |
9f95a23c | 386 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
7c673cae FG |
387 | mock_aio_image_write.send(); |
388 | } | |
389 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
390 | } | |
391 | ||
392 | TEST_F(TestMockIoImageRequest, AioDiscardJournalAppendDisabled) { | |
393 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
394 | ||
395 | librbd::ImageCtx *ictx; | |
396 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
11fdf7f2 | 397 | ictx->discard_granularity_bytes = 0; |
7c673cae | 398 | |
7c673cae | 399 | MockTestImageCtx mock_image_ctx(*ictx); |
11fdf7f2 | 400 | MockTestJournal mock_journal; |
7c673cae FG |
401 | mock_image_ctx.journal = &mock_journal; |
402 | ||
403 | InSequence seq; | |
11fdf7f2 | 404 | expect_get_modify_timestamp(mock_image_ctx, false); |
7c673cae | 405 | expect_is_journal_appending(mock_journal, false); |
11fdf7f2 | 406 | expect_object_request_send(mock_image_ctx, 0); |
7c673cae FG |
407 | |
408 | C_SaferCond aio_comp_ctx; | |
409 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
410 | &aio_comp_ctx, ictx, AIO_TYPE_DISCARD); | |
11fdf7f2 | 411 | MockImageDiscardRequest mock_aio_image_discard( |
f67539c2 TL |
412 | mock_image_ctx, aio_comp, {{0, 1}}, ictx->discard_granularity_bytes, |
413 | mock_image_ctx.get_data_io_context(), {}); | |
7c673cae | 414 | { |
9f95a23c | 415 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
7c673cae FG |
416 | mock_aio_image_discard.send(); |
417 | } | |
418 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
419 | } | |
420 | ||
421 | TEST_F(TestMockIoImageRequest, AioFlushJournalAppendDisabled) { | |
422 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
423 | ||
424 | librbd::ImageCtx *ictx; | |
425 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
426 | ||
427 | MockTestImageCtx mock_image_ctx(*ictx); | |
11fdf7f2 | 428 | MockTestJournal mock_journal; |
7c673cae FG |
429 | mock_image_ctx.journal = &mock_journal; |
430 | ||
11fdf7f2 TL |
431 | expect_op_work_queue(mock_image_ctx); |
432 | ||
7c673cae | 433 | InSequence seq; |
7c673cae | 434 | expect_is_journal_appending(mock_journal, false); |
11fdf7f2 | 435 | expect_object_request_send(mock_image_ctx, 0); |
7c673cae FG |
436 | |
437 | C_SaferCond aio_comp_ctx; | |
438 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
439 | &aio_comp_ctx, ictx, AIO_TYPE_FLUSH); | |
11fdf7f2 TL |
440 | MockImageFlushRequest mock_aio_image_flush(mock_image_ctx, aio_comp, |
441 | FLUSH_SOURCE_USER, {}); | |
7c673cae | 442 | { |
9f95a23c | 443 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
7c673cae FG |
444 | mock_aio_image_flush.send(); |
445 | } | |
446 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
447 | } | |
448 | ||
449 | TEST_F(TestMockIoImageRequest, AioWriteSameJournalAppendDisabled) { | |
450 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
451 | ||
452 | librbd::ImageCtx *ictx; | |
453 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
454 | ||
7c673cae | 455 | MockTestImageCtx mock_image_ctx(*ictx); |
11fdf7f2 | 456 | MockTestJournal mock_journal; |
7c673cae FG |
457 | mock_image_ctx.journal = &mock_journal; |
458 | ||
459 | InSequence seq; | |
11fdf7f2 | 460 | expect_get_modify_timestamp(mock_image_ctx, false); |
7c673cae | 461 | expect_is_journal_appending(mock_journal, false); |
11fdf7f2 | 462 | expect_object_request_send(mock_image_ctx, 0); |
7c673cae FG |
463 | |
464 | C_SaferCond aio_comp_ctx; | |
465 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
466 | &aio_comp_ctx, ictx, AIO_TYPE_WRITESAME); | |
467 | ||
468 | bufferlist bl; | |
469 | bl.append("1"); | |
f67539c2 TL |
470 | MockImageWriteSameRequest mock_aio_image_writesame( |
471 | mock_image_ctx, aio_comp, {{0, 1}}, std::move(bl), | |
472 | mock_image_ctx.get_data_io_context(), 0, {}); | |
7c673cae | 473 | { |
9f95a23c | 474 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
7c673cae FG |
475 | mock_aio_image_writesame.send(); |
476 | } | |
477 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
478 | } | |
479 | ||
c07f9fc5 FG |
480 | TEST_F(TestMockIoImageRequest, AioCompareAndWriteJournalAppendDisabled) { |
481 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
482 | ||
483 | librbd::ImageCtx *ictx; | |
484 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
485 | ||
c07f9fc5 | 486 | MockTestImageCtx mock_image_ctx(*ictx); |
11fdf7f2 | 487 | MockTestJournal mock_journal; |
c07f9fc5 FG |
488 | mock_image_ctx.journal = &mock_journal; |
489 | ||
490 | InSequence seq; | |
11fdf7f2 | 491 | expect_get_modify_timestamp(mock_image_ctx, false); |
c07f9fc5 | 492 | expect_is_journal_appending(mock_journal, false); |
11fdf7f2 | 493 | expect_object_request_send(mock_image_ctx, 0); |
c07f9fc5 FG |
494 | |
495 | C_SaferCond aio_comp_ctx; | |
496 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
497 | &aio_comp_ctx, ictx, AIO_TYPE_COMPARE_AND_WRITE); | |
498 | ||
499 | bufferlist cmp_bl; | |
500 | cmp_bl.append("1"); | |
501 | bufferlist write_bl; | |
502 | write_bl.append("1"); | |
503 | uint64_t mismatch_offset; | |
f67539c2 TL |
504 | MockImageCompareAndWriteRequest mock_aio_image_write( |
505 | mock_image_ctx, aio_comp, {{0, 1}}, std::move(cmp_bl), std::move(write_bl), | |
506 | &mismatch_offset, mock_image_ctx.get_data_io_context(), 0, {}); | |
c07f9fc5 | 507 | { |
9f95a23c | 508 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; |
c07f9fc5 FG |
509 | mock_aio_image_write.send(); |
510 | } | |
511 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
512 | } | |
513 | ||
f67539c2 TL |
514 | TEST_F(TestMockIoImageRequest, ListSnaps) { |
515 | librbd::ImageCtx *ictx; | |
516 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
517 | ||
518 | MockTestImageCtx mock_image_ctx(*ictx); | |
519 | mock_image_ctx.layout.object_size = 16384; | |
520 | mock_image_ctx.layout.stripe_unit = 4096; | |
521 | mock_image_ctx.layout.stripe_count = 2; | |
522 | ||
523 | InSequence seq; | |
524 | ||
525 | SnapshotDelta object_snapshot_delta; | |
526 | object_snapshot_delta[{5,6}].insert( | |
527 | 0, 1024, {SPARSE_EXTENT_STATE_DATA, 1024}); | |
528 | object_snapshot_delta[{5,5}].insert( | |
529 | 4096, 4096, {SPARSE_EXTENT_STATE_ZEROED, 4096}); | |
530 | expect_object_list_snaps_request(mock_image_ctx, 0, object_snapshot_delta, 0); | |
531 | object_snapshot_delta = {}; | |
532 | object_snapshot_delta[{5,6}].insert( | |
533 | 1024, 3072, {SPARSE_EXTENT_STATE_DATA, 3072}); | |
534 | object_snapshot_delta[{5,5}].insert( | |
535 | 2048, 2048, {SPARSE_EXTENT_STATE_ZEROED, 2048}); | |
536 | expect_object_list_snaps_request(mock_image_ctx, 1, object_snapshot_delta, 0); | |
537 | ||
538 | SnapshotDelta snapshot_delta; | |
539 | C_SaferCond aio_comp_ctx; | |
540 | AioCompletion *aio_comp = AioCompletion::create_and_start( | |
541 | &aio_comp_ctx, ictx, AIO_TYPE_GENERIC); | |
542 | MockImageListSnapsRequest mock_image_list_snaps_request( | |
543 | mock_image_ctx, aio_comp, {{0, 16384}, {16384, 16384}}, {0, CEPH_NOSNAP}, | |
544 | 0, &snapshot_delta, {}); | |
545 | { | |
546 | std::shared_lock owner_locker{mock_image_ctx.owner_lock}; | |
547 | mock_image_list_snaps_request.send(); | |
548 | } | |
549 | ASSERT_EQ(0, aio_comp_ctx.wait()); | |
550 | ||
551 | SnapshotDelta expected_snapshot_delta; | |
552 | expected_snapshot_delta[{5,6}].insert( | |
553 | 0, 1024, {SPARSE_EXTENT_STATE_DATA, 1024}); | |
554 | expected_snapshot_delta[{5,6}].insert( | |
555 | 5120, 3072, {SPARSE_EXTENT_STATE_DATA, 3072}); | |
556 | expected_snapshot_delta[{5,5}].insert( | |
557 | 6144, 6144, {SPARSE_EXTENT_STATE_ZEROED, 6144}); | |
558 | ASSERT_EQ(expected_snapshot_delta, snapshot_delta); | |
559 | } | |
560 | ||
7c673cae FG |
561 | } // namespace io |
562 | } // namespace librbd |