]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_ImageRequest.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / test / librbd / io / test_mock_ImageRequest.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/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"
10 #include "librbd/io/ObjectDispatchSpec.h"
11 #include "librbd/io/Utils.h"
12
13 namespace librbd {
14 namespace {
15
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_compare_and_write_event, uint64_t(uint64_t, size_t,
22 const bufferlist &,
23 const bufferlist &,
24 bool));
25 MOCK_METHOD5(append_io_event_mock, uint64_t(const journal::EventEntry&,
26 uint64_t, size_t, bool, int));
27 uint64_t append_io_event(journal::EventEntry &&event_entry,
28 uint64_t offset, size_t length,
29 bool flush_entry, int filter_ret_val) {
30 // googlemock doesn't support move semantics
31 return append_io_event_mock(event_entry, offset, length, flush_entry,
32 filter_ret_val);
33 }
34
35 MOCK_METHOD2(commit_io_event, void(uint64_t, int));
36 };
37
38 struct MockTestImageCtx : public MockImageCtx {
39 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
40 }
41
42 MockTestJournal* journal;
43 };
44
45 } // anonymous namespace
46
47 namespace util {
48
49 inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) {
50 return image_ctx->image_ctx;
51 }
52
53 } // namespace util
54 } // namespace librbd
55
56 #include "librbd/io/ImageRequest.cc"
57
58 namespace librbd {
59 namespace io {
60
61 namespace util {
62
63 template <>
64 void area_to_object_extents(MockTestImageCtx* image_ctx, uint64_t offset,
65 uint64_t length, ImageArea area,
66 uint64_t buffer_offset,
67 striper::LightweightObjectExtents* object_extents) {
68 Striper::file_to_extents(image_ctx->cct, &image_ctx->layout, offset, length,
69 0, buffer_offset, object_extents);
70 }
71
72 template <>
73 std::pair<Extents, ImageArea> object_to_area_extents(
74 MockTestImageCtx* image_ctx, uint64_t object_no,
75 const Extents& object_extents) {
76 Extents extents;
77 for (auto [off, len] : object_extents) {
78 Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, object_no, off,
79 len, extents);
80 }
81 return {std::move(extents), ImageArea::DATA};
82 }
83
84 } // namespace util
85
86 using ::testing::_;
87 using ::testing::InSequence;
88 using ::testing::Invoke;
89 using ::testing::Return;
90 using ::testing::WithArg;
91 using ::testing::WithoutArgs;
92 using ::testing::Exactly;
93
94 struct TestMockIoImageRequest : public TestMockFixture {
95 typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
96 typedef ImageReadRequest<librbd::MockTestImageCtx> MockImageReadRequest;
97 typedef ImageWriteRequest<librbd::MockTestImageCtx> MockImageWriteRequest;
98 typedef ImageDiscardRequest<librbd::MockTestImageCtx> MockImageDiscardRequest;
99 typedef ImageFlushRequest<librbd::MockTestImageCtx> MockImageFlushRequest;
100 typedef ImageWriteSameRequest<librbd::MockTestImageCtx> MockImageWriteSameRequest;
101 typedef ImageCompareAndWriteRequest<librbd::MockTestImageCtx> MockImageCompareAndWriteRequest;
102 typedef ImageListSnapsRequest<librbd::MockTestImageCtx> MockImageListSnapsRequest;
103
104 void expect_is_journal_appending(MockTestJournal &mock_journal, bool appending) {
105 EXPECT_CALL(mock_journal, is_journal_appending())
106 .WillOnce(Return(appending));
107 }
108
109 void expect_get_modify_timestamp(MockTestImageCtx &mock_image_ctx,
110 bool needs_update) {
111 if (needs_update) {
112 mock_image_ctx.mtime_update_interval = 5;
113 EXPECT_CALL(mock_image_ctx, get_modify_timestamp())
114 .WillOnce(Return(ceph_clock_now() - utime_t(10,0)));
115 } else {
116 mock_image_ctx.mtime_update_interval = 600;
117 EXPECT_CALL(mock_image_ctx, get_modify_timestamp())
118 .WillOnce(Return(ceph_clock_now()));
119 }
120 }
121
122 void expect_journal_append_io_event(MockTestJournal &mock_journal, uint64_t journal_tid,
123 uint64_t offset, size_t length) {
124 EXPECT_CALL(mock_journal, append_io_event_mock(_, offset, length, _, _))
125 .WillOnce(Return(journal_tid));
126 }
127
128 void expect_object_discard_request(MockTestImageCtx &mock_image_ctx,
129 uint64_t object_no, uint64_t offset,
130 uint32_t length, int r) {
131 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_))
132 .WillOnce(Invoke([&mock_image_ctx, object_no, offset, length, r]
133 (ObjectDispatchSpec* spec) {
134 auto* discard_spec = boost::get<ObjectDispatchSpec::DiscardRequest>(&spec->request);
135 ASSERT_TRUE(discard_spec != nullptr);
136 ASSERT_EQ(object_no, discard_spec->object_no);
137 ASSERT_EQ(offset, discard_spec->object_off);
138 ASSERT_EQ(length, discard_spec->object_len);
139
140 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
141 mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r);
142 }));
143 }
144
145 void expect_object_request_send(MockTestImageCtx &mock_image_ctx,
146 int r) {
147 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_))
148 .WillOnce(Invoke([&mock_image_ctx, r](ObjectDispatchSpec* spec) {
149 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
150 mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r);
151 }));
152 }
153
154 void expect_object_list_snaps_request(MockTestImageCtx &mock_image_ctx,
155 uint64_t object_no,
156 const SnapshotDelta& snap_delta,
157 int r) {
158 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_))
159 .WillOnce(
160 Invoke([&mock_image_ctx, object_no, snap_delta, r]
161 (ObjectDispatchSpec* spec) {
162 auto request = boost::get<
163 librbd::io::ObjectDispatchSpec::ListSnapsRequest>(
164 &spec->request);
165 ASSERT_TRUE(request != nullptr);
166 ASSERT_EQ(object_no, request->object_no);
167
168 *request->snapshot_delta = snap_delta;
169 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
170 mock_image_ctx.image_ctx->op_work_queue->queue(&spec->dispatcher_ctx, r);
171 }));
172 }
173 };
174
175 TEST_F(TestMockIoImageRequest, AioWriteModifyTimestamp) {
176 REQUIRE_FORMAT_V2();
177
178 librbd::ImageCtx *ictx;
179 ASSERT_EQ(0, open_image(m_image_name, &ictx));
180
181 MockTestImageCtx mock_image_ctx(*ictx);
182 MockTestJournal mock_journal;
183 mock_image_ctx.journal = &mock_journal;
184
185 mock_image_ctx.mtime_update_interval = 5;
186
187 utime_t dummy = ceph_clock_now();
188 dummy -= utime_t(10,0);
189
190 EXPECT_CALL(mock_image_ctx, get_modify_timestamp())
191 .Times(Exactly(3))
192 .WillOnce(Return(dummy))
193 .WillOnce(Return(dummy))
194 .WillOnce(Return(dummy + utime_t(10,0)));
195
196 EXPECT_CALL(mock_image_ctx, set_modify_timestamp(_))
197 .Times(Exactly(1));
198
199 InSequence seq;
200 expect_is_journal_appending(mock_journal, false);
201 expect_object_request_send(mock_image_ctx, 0);
202
203 C_SaferCond aio_comp_ctx_1, aio_comp_ctx_2;
204 AioCompletion *aio_comp_1 = AioCompletion::create_and_start(
205 &aio_comp_ctx_1, ictx, AIO_TYPE_WRITE);
206
207 AioCompletion *aio_comp_2 = AioCompletion::create_and_start(
208 &aio_comp_ctx_2, ictx, AIO_TYPE_WRITE);
209
210 bufferlist bl;
211 bl.append("1");
212 MockImageWriteRequest mock_aio_image_write_1(
213 mock_image_ctx, aio_comp_1, {{0, 1}}, ImageArea::DATA, std::move(bl),
214 0, {});
215 {
216 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
217 mock_aio_image_write_1.send();
218 }
219 ASSERT_EQ(0, aio_comp_ctx_1.wait());
220
221 expect_is_journal_appending(mock_journal, false);
222 expect_object_request_send(mock_image_ctx, 0);
223
224 bl.append("1");
225 MockImageWriteRequest mock_aio_image_write_2(
226 mock_image_ctx, aio_comp_2, {{0, 1}}, ImageArea::DATA, std::move(bl),
227 0, {});
228 {
229 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
230 mock_aio_image_write_2.send();
231 }
232 ASSERT_EQ(0, aio_comp_ctx_2.wait());
233 }
234
235 TEST_F(TestMockIoImageRequest, AioReadAccessTimestamp) {
236 REQUIRE_FORMAT_V2();
237
238 librbd::ImageCtx *ictx;
239 ASSERT_EQ(0, open_image(m_image_name, &ictx));
240
241 MockTestImageCtx mock_image_ctx(*ictx);
242 MockTestJournal mock_journal;
243 mock_image_ctx.journal = &mock_journal;
244
245 mock_image_ctx.atime_update_interval = 5;
246
247 utime_t dummy = ceph_clock_now();
248 dummy -= utime_t(10,0);
249
250 EXPECT_CALL(mock_image_ctx, get_access_timestamp())
251 .Times(Exactly(3))
252 .WillOnce(Return(dummy))
253 .WillOnce(Return(dummy))
254 .WillOnce(Return(dummy + utime_t(10,0)));
255
256 EXPECT_CALL(mock_image_ctx, set_access_timestamp(_))
257 .Times(Exactly(1));
258
259 InSequence seq;
260 expect_object_request_send(mock_image_ctx, 0);
261
262 C_SaferCond aio_comp_ctx_1, aio_comp_ctx_2;
263 AioCompletion *aio_comp_1 = AioCompletion::create_and_start(
264 &aio_comp_ctx_1, ictx, AIO_TYPE_READ);
265
266
267 ReadResult rr;
268 MockImageReadRequest mock_aio_image_read_1(
269 mock_image_ctx, aio_comp_1, {{0, 1}}, ImageArea::DATA, std::move(rr),
270 mock_image_ctx.get_data_io_context(), 0, 0, {});
271 {
272 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
273 mock_aio_image_read_1.send();
274 }
275 ASSERT_EQ(1, aio_comp_ctx_1.wait());
276
277 AioCompletion *aio_comp_2 = AioCompletion::create_and_start(
278 &aio_comp_ctx_2, ictx, AIO_TYPE_READ);
279 expect_object_request_send(mock_image_ctx, 0);
280
281 MockImageReadRequest mock_aio_image_read_2(
282 mock_image_ctx, aio_comp_2, {{0, 1}}, ImageArea::DATA, std::move(rr),
283 mock_image_ctx.get_data_io_context(), 0, 0, {});
284 {
285 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
286 mock_aio_image_read_2.send();
287 }
288 ASSERT_EQ(1, aio_comp_ctx_2.wait());
289 }
290
291 TEST_F(TestMockIoImageRequest, PartialDiscard) {
292 librbd::ImageCtx *ictx;
293 ASSERT_EQ(0, open_image(m_image_name, &ictx));
294 ictx->discard_granularity_bytes = 0;
295
296 MockTestImageCtx mock_image_ctx(*ictx);
297 mock_image_ctx.journal = nullptr;
298
299 InSequence seq;
300 expect_get_modify_timestamp(mock_image_ctx, false);
301 expect_object_discard_request(mock_image_ctx, 0, 16, 63, 0);
302 expect_object_discard_request(mock_image_ctx, 0, 84, 100, 0);
303
304 C_SaferCond aio_comp_ctx;
305 AioCompletion *aio_comp = AioCompletion::create_and_start(
306 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
307 MockImageDiscardRequest mock_aio_image_discard(
308 mock_image_ctx, aio_comp, {{16, 63}, {84, 100}}, ImageArea::DATA,
309 ictx->discard_granularity_bytes, {});
310 {
311 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
312 mock_aio_image_discard.send();
313 }
314 ASSERT_EQ(0, aio_comp_ctx.wait());
315 }
316
317 TEST_F(TestMockIoImageRequest, TailDiscard) {
318 librbd::ImageCtx *ictx;
319 ASSERT_EQ(0, open_image(m_image_name, &ictx));
320 ASSERT_EQ(0, resize(ictx, ictx->layout.object_size));
321 ictx->discard_granularity_bytes = 2 * ictx->layout.object_size;
322
323 MockTestImageCtx mock_image_ctx(*ictx);
324 mock_image_ctx.journal = nullptr;
325
326 InSequence seq;
327 expect_get_modify_timestamp(mock_image_ctx, false);
328 expect_object_discard_request(
329 mock_image_ctx, 0, ictx->layout.object_size - 1024, 1024, 0);
330
331 C_SaferCond aio_comp_ctx;
332 AioCompletion *aio_comp = AioCompletion::create_and_start(
333 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
334 MockImageDiscardRequest mock_aio_image_discard(
335 mock_image_ctx, aio_comp,
336 {{ictx->layout.object_size - 1024, 1024}}, ImageArea::DATA,
337 ictx->discard_granularity_bytes, {});
338 {
339 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
340 mock_aio_image_discard.send();
341 }
342 ASSERT_EQ(0, aio_comp_ctx.wait());
343 }
344
345 TEST_F(TestMockIoImageRequest, DiscardGranularity) {
346 librbd::ImageCtx *ictx;
347 ASSERT_EQ(0, open_image(m_image_name, &ictx));
348 ASSERT_EQ(0, resize(ictx, ictx->layout.object_size));
349 ictx->discard_granularity_bytes = 32;
350
351 MockTestImageCtx mock_image_ctx(*ictx);
352 mock_image_ctx.journal = nullptr;
353
354 InSequence seq;
355 expect_get_modify_timestamp(mock_image_ctx, false);
356 expect_object_discard_request(mock_image_ctx, 0, 32, 32, 0);
357 expect_object_discard_request(mock_image_ctx, 0, 96, 64, 0);
358 expect_object_discard_request(
359 mock_image_ctx, 0, ictx->layout.object_size - 32, 32, 0);
360
361 C_SaferCond aio_comp_ctx;
362 AioCompletion *aio_comp = AioCompletion::create_and_start(
363 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
364 MockImageDiscardRequest mock_aio_image_discard(
365 mock_image_ctx, aio_comp,
366 {{16, 63}, {96, 31}, {84, 100}, {ictx->layout.object_size - 33, 33}},
367 ImageArea::DATA, ictx->discard_granularity_bytes, {});
368 {
369 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
370 mock_aio_image_discard.send();
371 }
372 ASSERT_EQ(0, aio_comp_ctx.wait());
373 }
374
375 TEST_F(TestMockIoImageRequest, PartialDiscardJournalAppendEnabled) {
376 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
377
378 librbd::ImageCtx *ictx;
379 ASSERT_EQ(0, open_image(m_image_name, &ictx));
380 ictx->discard_granularity_bytes = 0;
381
382 MockTestImageCtx mock_image_ctx(*ictx);
383 MockTestJournal mock_journal;
384 mock_image_ctx.journal = &mock_journal;
385
386 InSequence seq;
387 expect_get_modify_timestamp(mock_image_ctx, false);
388 expect_is_journal_appending(mock_journal, true);
389 expect_journal_append_io_event(mock_journal, 0, 16, 63);
390 expect_journal_append_io_event(mock_journal, 1, 84, 100);
391 expect_object_discard_request(mock_image_ctx, 0, 16, 63, 0);
392 expect_object_discard_request(mock_image_ctx, 0, 84, 100, 0);
393
394 C_SaferCond aio_comp_ctx;
395 AioCompletion *aio_comp = AioCompletion::create_and_start(
396 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
397 MockImageDiscardRequest mock_aio_image_discard(
398 mock_image_ctx, aio_comp, {{16, 63}, {84, 100}}, ImageArea::DATA,
399 ictx->discard_granularity_bytes, {});
400 {
401 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
402 mock_aio_image_discard.send();
403 }
404 ASSERT_EQ(0, aio_comp_ctx.wait());
405 }
406
407 TEST_F(TestMockIoImageRequest, TailDiscardJournalAppendEnabled) {
408 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
409
410 librbd::ImageCtx *ictx;
411 ASSERT_EQ(0, open_image(m_image_name, &ictx));
412 ASSERT_EQ(0, resize(ictx, ictx->layout.object_size));
413 ictx->discard_granularity_bytes = 2 * ictx->layout.object_size;
414
415 MockTestImageCtx mock_image_ctx(*ictx);
416 MockTestJournal mock_journal;
417 mock_image_ctx.journal = &mock_journal;
418
419 InSequence seq;
420 expect_get_modify_timestamp(mock_image_ctx, false);
421 expect_is_journal_appending(mock_journal, true);
422 expect_journal_append_io_event(
423 mock_journal, 0, ictx->layout.object_size - 1024, 1024);
424 expect_object_discard_request(
425 mock_image_ctx, 0, ictx->layout.object_size - 1024, 1024, 0);
426
427 C_SaferCond aio_comp_ctx;
428 AioCompletion *aio_comp = AioCompletion::create_and_start(
429 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
430 MockImageDiscardRequest mock_aio_image_discard(
431 mock_image_ctx, aio_comp,
432 {{ictx->layout.object_size - 1024, 1024}}, ImageArea::DATA,
433 ictx->discard_granularity_bytes, {});
434 {
435 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
436 mock_aio_image_discard.send();
437 }
438 ASSERT_EQ(0, aio_comp_ctx.wait());
439 }
440
441 TEST_F(TestMockIoImageRequest, PruneRequiredDiscardJournalAppendEnabled) {
442 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
443
444 librbd::ImageCtx *ictx;
445 ASSERT_EQ(0, open_image(m_image_name, &ictx));
446 ictx->discard_granularity_bytes = 32;
447
448 MockTestImageCtx mock_image_ctx(*ictx);
449 MockTestJournal mock_journal;
450 mock_image_ctx.journal = &mock_journal;
451
452 InSequence seq;
453 expect_get_modify_timestamp(mock_image_ctx, false);
454 expect_is_journal_appending(mock_journal, true);
455 EXPECT_CALL(mock_journal, append_io_event_mock(_, _, _, _, _)).Times(0);
456 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_)).Times(0);
457
458 C_SaferCond aio_comp_ctx;
459 AioCompletion *aio_comp = AioCompletion::create_and_start(
460 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
461 MockImageDiscardRequest mock_aio_image_discard(
462 mock_image_ctx, aio_comp, {{96, 31}}, ImageArea::DATA,
463 ictx->discard_granularity_bytes, {});
464 {
465 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
466 mock_aio_image_discard.send();
467 }
468 ASSERT_EQ(0, aio_comp_ctx.wait());
469 }
470
471 TEST_F(TestMockIoImageRequest, LengthModifiedDiscardJournalAppendEnabled) {
472 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
473
474 librbd::ImageCtx *ictx;
475 ASSERT_EQ(0, open_image(m_image_name, &ictx));
476 ictx->discard_granularity_bytes = 32;
477
478 MockTestImageCtx mock_image_ctx(*ictx);
479 MockTestJournal mock_journal;
480 mock_image_ctx.journal = &mock_journal;
481
482 InSequence seq;
483 expect_get_modify_timestamp(mock_image_ctx, false);
484 expect_is_journal_appending(mock_journal, true);
485 expect_journal_append_io_event(mock_journal, 0, 32, 32);
486 expect_object_discard_request(mock_image_ctx, 0, 32, 32, 0);
487
488 C_SaferCond aio_comp_ctx;
489 AioCompletion *aio_comp = AioCompletion::create_and_start(
490 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
491 MockImageDiscardRequest mock_aio_image_discard(
492 mock_image_ctx, aio_comp, {{16, 63}}, ImageArea::DATA,
493 ictx->discard_granularity_bytes, {});
494 {
495 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
496 mock_aio_image_discard.send();
497 }
498 ASSERT_EQ(0, aio_comp_ctx.wait());
499 }
500
501 TEST_F(TestMockIoImageRequest, DiscardGranularityJournalAppendEnabled) {
502 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
503
504 librbd::ImageCtx *ictx;
505 ASSERT_EQ(0, open_image(m_image_name, &ictx));
506 ASSERT_EQ(0, resize(ictx, ictx->layout.object_size));
507 ictx->discard_granularity_bytes = 32;
508
509 MockTestImageCtx mock_image_ctx(*ictx);
510 MockTestJournal mock_journal;
511 mock_image_ctx.journal = &mock_journal;
512
513 InSequence seq;
514 expect_get_modify_timestamp(mock_image_ctx, false);
515 expect_is_journal_appending(mock_journal, true);
516 expect_journal_append_io_event(mock_journal, 0, 32, 32);
517 expect_journal_append_io_event(mock_journal, 1, 96, 64);
518 expect_journal_append_io_event(
519 mock_journal, 2, ictx->layout.object_size - 32, 32);
520 expect_object_discard_request(mock_image_ctx, 0, 32, 32, 0);
521 expect_object_discard_request(mock_image_ctx, 0, 96, 64, 0);
522 expect_object_discard_request(
523 mock_image_ctx, 0, ictx->layout.object_size - 32, 32, 0);
524
525 C_SaferCond aio_comp_ctx;
526 AioCompletion *aio_comp = AioCompletion::create_and_start(
527 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
528 MockImageDiscardRequest mock_aio_image_discard(
529 mock_image_ctx, aio_comp,
530 {{16, 63}, {96, 31}, {84, 100}, {ictx->layout.object_size - 33, 33}},
531 ImageArea::DATA, ictx->discard_granularity_bytes, {});
532 {
533 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
534 mock_aio_image_discard.send();
535 }
536 ASSERT_EQ(0, aio_comp_ctx.wait());
537 }
538
539 TEST_F(TestMockIoImageRequest, AioWriteJournalAppendDisabled) {
540 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
541
542 librbd::ImageCtx *ictx;
543 ASSERT_EQ(0, open_image(m_image_name, &ictx));
544
545 MockTestImageCtx mock_image_ctx(*ictx);
546 MockTestJournal mock_journal;
547 mock_image_ctx.journal = &mock_journal;
548
549 InSequence seq;
550 expect_get_modify_timestamp(mock_image_ctx, false);
551 expect_is_journal_appending(mock_journal, false);
552 expect_object_request_send(mock_image_ctx, 0);
553
554 C_SaferCond aio_comp_ctx;
555 AioCompletion *aio_comp = AioCompletion::create_and_start(
556 &aio_comp_ctx, ictx, AIO_TYPE_WRITE);
557
558 bufferlist bl;
559 bl.append("1");
560 MockImageWriteRequest mock_aio_image_write(
561 mock_image_ctx, aio_comp, {{0, 1}}, ImageArea::DATA, std::move(bl), 0, {});
562 {
563 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
564 mock_aio_image_write.send();
565 }
566 ASSERT_EQ(0, aio_comp_ctx.wait());
567 }
568
569 TEST_F(TestMockIoImageRequest, AioDiscardJournalAppendDisabled) {
570 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
571
572 librbd::ImageCtx *ictx;
573 ASSERT_EQ(0, open_image(m_image_name, &ictx));
574 ictx->discard_granularity_bytes = 0;
575
576 MockTestImageCtx mock_image_ctx(*ictx);
577 MockTestJournal mock_journal;
578 mock_image_ctx.journal = &mock_journal;
579
580 InSequence seq;
581 expect_get_modify_timestamp(mock_image_ctx, false);
582 expect_is_journal_appending(mock_journal, false);
583 expect_object_request_send(mock_image_ctx, 0);
584
585 C_SaferCond aio_comp_ctx;
586 AioCompletion *aio_comp = AioCompletion::create_and_start(
587 &aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
588 MockImageDiscardRequest mock_aio_image_discard(
589 mock_image_ctx, aio_comp, {{0, 1}}, ImageArea::DATA,
590 ictx->discard_granularity_bytes, {});
591 {
592 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
593 mock_aio_image_discard.send();
594 }
595 ASSERT_EQ(0, aio_comp_ctx.wait());
596 }
597
598 TEST_F(TestMockIoImageRequest, AioFlushJournalAppendDisabled) {
599 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
600
601 librbd::ImageCtx *ictx;
602 ASSERT_EQ(0, open_image(m_image_name, &ictx));
603
604 MockTestImageCtx mock_image_ctx(*ictx);
605 MockTestJournal mock_journal;
606 mock_image_ctx.journal = &mock_journal;
607
608 expect_op_work_queue(mock_image_ctx);
609
610 InSequence seq;
611 expect_is_journal_appending(mock_journal, false);
612 expect_object_request_send(mock_image_ctx, 0);
613
614 C_SaferCond aio_comp_ctx;
615 AioCompletion *aio_comp = AioCompletion::create_and_start(
616 &aio_comp_ctx, ictx, AIO_TYPE_FLUSH);
617 MockImageFlushRequest mock_aio_image_flush(mock_image_ctx, aio_comp,
618 FLUSH_SOURCE_USER, {});
619 {
620 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
621 mock_aio_image_flush.send();
622 }
623 ASSERT_EQ(0, aio_comp_ctx.wait());
624 }
625
626 TEST_F(TestMockIoImageRequest, AioWriteSameJournalAppendDisabled) {
627 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
628
629 librbd::ImageCtx *ictx;
630 ASSERT_EQ(0, open_image(m_image_name, &ictx));
631
632 MockTestImageCtx mock_image_ctx(*ictx);
633 MockTestJournal mock_journal;
634 mock_image_ctx.journal = &mock_journal;
635
636 InSequence seq;
637 expect_get_modify_timestamp(mock_image_ctx, false);
638 expect_is_journal_appending(mock_journal, false);
639 expect_object_request_send(mock_image_ctx, 0);
640
641 C_SaferCond aio_comp_ctx;
642 AioCompletion *aio_comp = AioCompletion::create_and_start(
643 &aio_comp_ctx, ictx, AIO_TYPE_WRITESAME);
644
645 bufferlist bl;
646 bl.append("1");
647 MockImageWriteSameRequest mock_aio_image_writesame(
648 mock_image_ctx, aio_comp, {{0, 1}}, ImageArea::DATA, std::move(bl), 0, {});
649 {
650 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
651 mock_aio_image_writesame.send();
652 }
653 ASSERT_EQ(0, aio_comp_ctx.wait());
654 }
655
656 TEST_F(TestMockIoImageRequest, AioCompareAndWriteJournalAppendDisabled) {
657 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
658
659 librbd::ImageCtx *ictx;
660 ASSERT_EQ(0, open_image(m_image_name, &ictx));
661
662 MockTestImageCtx mock_image_ctx(*ictx);
663 MockTestJournal mock_journal;
664 mock_image_ctx.journal = &mock_journal;
665
666 InSequence seq;
667 expect_get_modify_timestamp(mock_image_ctx, false);
668 expect_is_journal_appending(mock_journal, false);
669 expect_object_request_send(mock_image_ctx, 0);
670
671 C_SaferCond aio_comp_ctx;
672 AioCompletion *aio_comp = AioCompletion::create_and_start(
673 &aio_comp_ctx, ictx, AIO_TYPE_COMPARE_AND_WRITE);
674
675 bufferlist cmp_bl;
676 cmp_bl.append("1");
677 bufferlist write_bl;
678 write_bl.append("1");
679 uint64_t mismatch_offset;
680 MockImageCompareAndWriteRequest mock_aio_image_write(
681 mock_image_ctx, aio_comp, {{0, 1}}, ImageArea::DATA,
682 std::move(cmp_bl), std::move(write_bl), &mismatch_offset, 0, {});
683 {
684 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
685 mock_aio_image_write.send();
686 }
687 ASSERT_EQ(0, aio_comp_ctx.wait());
688 }
689
690 TEST_F(TestMockIoImageRequest, ListSnaps) {
691 librbd::ImageCtx *ictx;
692 ASSERT_EQ(0, open_image(m_image_name, &ictx));
693
694 MockTestImageCtx mock_image_ctx(*ictx);
695 mock_image_ctx.layout.object_size = 16384;
696 mock_image_ctx.layout.stripe_unit = 4096;
697 mock_image_ctx.layout.stripe_count = 2;
698
699 InSequence seq;
700
701 SnapshotDelta object_snapshot_delta;
702 object_snapshot_delta[{5,6}].insert(
703 0, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
704 object_snapshot_delta[{5,5}].insert(
705 4096, 4096, {SPARSE_EXTENT_STATE_ZEROED, 4096});
706 expect_object_list_snaps_request(mock_image_ctx, 0, object_snapshot_delta, 0);
707 object_snapshot_delta = {};
708 object_snapshot_delta[{5,6}].insert(
709 1024, 3072, {SPARSE_EXTENT_STATE_DATA, 3072});
710 object_snapshot_delta[{5,5}].insert(
711 2048, 2048, {SPARSE_EXTENT_STATE_ZEROED, 2048});
712 expect_object_list_snaps_request(mock_image_ctx, 1, object_snapshot_delta, 0);
713
714 SnapshotDelta snapshot_delta;
715 C_SaferCond aio_comp_ctx;
716 AioCompletion *aio_comp = AioCompletion::create_and_start(
717 &aio_comp_ctx, ictx, AIO_TYPE_GENERIC);
718 MockImageListSnapsRequest mock_image_list_snaps_request(
719 mock_image_ctx, aio_comp, {{0, 16384}, {16384, 16384}}, ImageArea::DATA,
720 {0, CEPH_NOSNAP}, 0, &snapshot_delta, {});
721 {
722 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
723 mock_image_list_snaps_request.send();
724 }
725 ASSERT_EQ(0, aio_comp_ctx.wait());
726
727 SnapshotDelta expected_snapshot_delta;
728 expected_snapshot_delta[{5,6}].insert(
729 0, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
730 expected_snapshot_delta[{5,6}].insert(
731 5120, 3072, {SPARSE_EXTENT_STATE_DATA, 3072});
732 expected_snapshot_delta[{5,5}].insert(
733 6144, 6144, {SPARSE_EXTENT_STATE_ZEROED, 6144});
734 ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
735 }
736
737 } // namespace io
738 } // namespace librbd