]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/cache/test_mock_WriteAroundObjectDispatch.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / test / librbd / cache / test_mock_WriteAroundObjectDispatch.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 "include/rbd/librbd.hpp"
8 #include "librbd/cache/WriteAroundObjectDispatch.h"
9 #include "librbd/io/ObjectDispatchSpec.h"
10
11 namespace librbd {
12 namespace {
13
14 struct MockTestImageCtx : public MockImageCtx {
15 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
16 }
17 };
18
19 struct MockContext : public C_SaferCond {
20 MOCK_METHOD1(complete, void(int));
21 MOCK_METHOD1(finish, void(int));
22
23 void do_complete(int r) {
24 C_SaferCond::complete(r);
25 }
26 };
27
28 } // anonymous namespace
29 } // namespace librbd
30
31 #include "librbd/cache/WriteAroundObjectDispatch.cc"
32
33 namespace librbd {
34 namespace cache {
35
36 using ::testing::_;
37 using ::testing::DoDefault;
38 using ::testing::InSequence;
39 using ::testing::Invoke;
40
41 struct TestMockCacheWriteAroundObjectDispatch : public TestMockFixture {
42 typedef WriteAroundObjectDispatch<librbd::MockTestImageCtx> MockWriteAroundObjectDispatch;
43
44 void expect_op_work_queue(MockTestImageCtx& mock_image_ctx) {
45 EXPECT_CALL(*mock_image_ctx.op_work_queue, queue(_, _))
46 .WillRepeatedly(Invoke([](Context* ctx, int r) {
47 ctx->complete(r);
48 }));
49 }
50
51 void expect_context_complete(MockContext& mock_context, int r) {
52 EXPECT_CALL(mock_context, complete(r))
53 .WillOnce(Invoke([&mock_context](int r) {
54 mock_context.do_complete(r);
55 }));
56 }
57 };
58
59 TEST_F(TestMockCacheWriteAroundObjectDispatch, WriteThrough) {
60 librbd::ImageCtx *ictx;
61 ASSERT_EQ(0, open_image(m_image_name, &ictx));
62
63 MockTestImageCtx mock_image_ctx(*ictx);
64 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 0, false);
65
66 InSequence seq;
67
68 bufferlist data;
69 data.append(std::string(4096, '1'));
70
71 io::DispatchResult dispatch_result;
72 MockContext finish_ctx;
73 MockContext dispatch_ctx;
74 Context* finish_ctx_ptr = &finish_ctx;
75 ASSERT_FALSE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
76 nullptr, nullptr, &dispatch_result,
77 &finish_ctx_ptr, &dispatch_ctx));
78 ASSERT_EQ(finish_ctx_ptr, &finish_ctx);
79 }
80
81 TEST_F(TestMockCacheWriteAroundObjectDispatch, WriteThroughUntilFlushed) {
82 librbd::ImageCtx *ictx;
83 ASSERT_EQ(0, open_image(m_image_name, &ictx));
84
85 MockTestImageCtx mock_image_ctx(*ictx);
86 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 4096, true);
87 expect_op_work_queue(mock_image_ctx);
88
89 InSequence seq;
90
91 bufferlist data;
92 data.append(std::string(4096, '1'));
93
94 io::DispatchResult dispatch_result;
95 MockContext finish_ctx;
96 MockContext dispatch_ctx;
97 Context* finish_ctx_ptr = &finish_ctx;
98 ASSERT_FALSE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
99 nullptr, nullptr, &dispatch_result,
100 &finish_ctx_ptr, &dispatch_ctx));
101 ASSERT_EQ(finish_ctx_ptr, &finish_ctx);
102
103 ASSERT_FALSE(object_dispatch.flush(io::FLUSH_SOURCE_USER, {}, nullptr,
104 &dispatch_result, &finish_ctx_ptr,
105 &dispatch_ctx));
106
107 expect_context_complete(dispatch_ctx, 0);
108 expect_context_complete(finish_ctx, 0);
109
110 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
111 nullptr, nullptr, &dispatch_result,
112 &finish_ctx_ptr, &dispatch_ctx));
113 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
114 ASSERT_NE(finish_ctx_ptr, &finish_ctx);
115 ASSERT_EQ(0, dispatch_ctx.wait());
116 ASSERT_EQ(0, finish_ctx.wait());
117 finish_ctx_ptr->complete(0);
118 }
119
120 TEST_F(TestMockCacheWriteAroundObjectDispatch, DispatchIO) {
121 librbd::ImageCtx *ictx;
122 ASSERT_EQ(0, open_image(m_image_name, &ictx));
123
124 MockTestImageCtx mock_image_ctx(*ictx);
125 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 4096, false);
126 expect_op_work_queue(mock_image_ctx);
127
128 InSequence seq;
129
130 bufferlist data;
131 data.append(std::string(4096, '1'));
132
133 io::DispatchResult dispatch_result;
134 MockContext finish_ctx;
135 MockContext dispatch_ctx;
136 Context* finish_ctx_ptr = &finish_ctx;
137
138 expect_context_complete(dispatch_ctx, 0);
139 expect_context_complete(finish_ctx, 0);
140
141 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
142 nullptr, nullptr, &dispatch_result,
143 &finish_ctx_ptr, &dispatch_ctx));
144 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
145 ASSERT_NE(finish_ctx_ptr, &finish_ctx);
146
147 ASSERT_EQ(0, dispatch_ctx.wait());
148 ASSERT_EQ(0, finish_ctx.wait());
149 finish_ctx_ptr->complete(0);
150 }
151
152 TEST_F(TestMockCacheWriteAroundObjectDispatch, BlockedIO) {
153 librbd::ImageCtx *ictx;
154 ASSERT_EQ(0, open_image(m_image_name, &ictx));
155
156 MockTestImageCtx mock_image_ctx(*ictx);
157 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 16384, false);
158 expect_op_work_queue(mock_image_ctx);
159
160 InSequence seq;
161
162 bufferlist data;
163 data.append(std::string(4096, '1'));
164
165 io::DispatchResult dispatch_result;
166 MockContext finish_ctx1;
167 MockContext dispatch_ctx1;
168 Context* finish_ctx_ptr1 = &finish_ctx1;
169
170 expect_context_complete(dispatch_ctx1, 0);
171 expect_context_complete(finish_ctx1, 0);
172
173 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
174 nullptr, nullptr, &dispatch_result,
175 &finish_ctx_ptr1, &dispatch_ctx1));
176 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
177 ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
178
179 MockContext finish_ctx2;
180 MockContext dispatch_ctx2;
181 Context* finish_ctx_ptr2 = &finish_ctx2;
182
183 expect_context_complete(dispatch_ctx2, 0);
184 expect_context_complete(finish_ctx2, 0);
185
186 ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, {},
187 nullptr, nullptr, &dispatch_result,
188 &finish_ctx_ptr2, &dispatch_ctx2));
189 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
190 ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
191
192 MockContext finish_ctx3;
193 MockContext dispatch_ctx3;
194 Context* finish_ctx_ptr3 = &finish_ctx3;
195
196 ASSERT_TRUE(object_dispatch.write(0, 1024, std::move(data), {}, 0,
197 {}, nullptr, nullptr, &dispatch_result,
198 &finish_ctx_ptr3, &dispatch_ctx3));
199 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
200 ASSERT_NE(finish_ctx_ptr3, &finish_ctx3);
201
202 ASSERT_EQ(0, dispatch_ctx1.wait());
203 ASSERT_EQ(0, dispatch_ctx2.wait());
204 ASSERT_EQ(0, finish_ctx1.wait());
205 ASSERT_EQ(0, finish_ctx2.wait());
206 finish_ctx_ptr2->complete(0);
207
208 expect_context_complete(dispatch_ctx3, 0);
209 expect_context_complete(finish_ctx3, 0);
210 finish_ctx_ptr1->complete(0);
211
212 ASSERT_EQ(0, dispatch_ctx3.wait());
213 finish_ctx_ptr3->complete(0);
214 ASSERT_EQ(0, finish_ctx3.wait());
215 }
216
217 TEST_F(TestMockCacheWriteAroundObjectDispatch, QueuedIO) {
218 librbd::ImageCtx *ictx;
219 ASSERT_EQ(0, open_image(m_image_name, &ictx));
220
221 MockTestImageCtx mock_image_ctx(*ictx);
222 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 4095, false);
223 expect_op_work_queue(mock_image_ctx);
224
225 InSequence seq;
226
227 bufferlist data;
228 data.append(std::string(4096, '1'));
229
230 io::DispatchResult dispatch_result;
231 MockContext finish_ctx1;
232 MockContext dispatch_ctx1;
233 Context* finish_ctx_ptr1 = &finish_ctx1;
234
235 expect_context_complete(dispatch_ctx1, 0);
236 expect_context_complete(finish_ctx1, 0);
237
238 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
239 nullptr, nullptr, &dispatch_result,
240 &finish_ctx_ptr1, &dispatch_ctx1));
241 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
242 ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
243
244 MockContext finish_ctx2;
245 MockContext dispatch_ctx2;
246 Context* finish_ctx_ptr2 = &finish_ctx2;
247
248 ASSERT_TRUE(object_dispatch.write(0, 8192, std::move(data), {}, 0, {},
249 nullptr, nullptr, &dispatch_result,
250 &finish_ctx_ptr2, &dispatch_ctx2));
251 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
252 ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
253 ASSERT_EQ(0, dispatch_ctx1.wait());
254
255 expect_context_complete(dispatch_ctx2, 0);
256 expect_context_complete(finish_ctx2, 0);
257 finish_ctx_ptr1->complete(0);
258
259 ASSERT_EQ(0, finish_ctx1.wait());
260 ASSERT_EQ(0, dispatch_ctx2.wait());
261 ASSERT_EQ(0, finish_ctx2.wait());
262 finish_ctx_ptr2->complete(0);
263 }
264
265 TEST_F(TestMockCacheWriteAroundObjectDispatch, BlockedAndQueuedIO) {
266 librbd::ImageCtx *ictx;
267 ASSERT_EQ(0, open_image(m_image_name, &ictx));
268
269 MockTestImageCtx mock_image_ctx(*ictx);
270 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 8196, false);
271 expect_op_work_queue(mock_image_ctx);
272
273 InSequence seq;
274
275 bufferlist data;
276 data.append(std::string(4096, '1'));
277
278 io::DispatchResult dispatch_result;
279 MockContext finish_ctx1;
280 MockContext dispatch_ctx1;
281 Context* finish_ctx_ptr1 = &finish_ctx1;
282
283 expect_context_complete(dispatch_ctx1, 0);
284 expect_context_complete(finish_ctx1, 0);
285
286 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
287 nullptr, nullptr, &dispatch_result,
288 &finish_ctx_ptr1, &dispatch_ctx1));
289 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
290 ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
291
292 MockContext finish_ctx2;
293 MockContext dispatch_ctx2;
294 Context* finish_ctx_ptr2 = &finish_ctx2;
295
296 expect_context_complete(dispatch_ctx2, 0);
297 expect_context_complete(finish_ctx2, 0);
298
299 ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, {},
300 nullptr, nullptr, &dispatch_result,
301 &finish_ctx_ptr2, &dispatch_ctx2));
302 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
303 ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
304
305 MockContext finish_ctx3;
306 MockContext dispatch_ctx3;
307 Context* finish_ctx_ptr3 = &finish_ctx3;
308
309 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0,
310 {}, nullptr, nullptr, &dispatch_result,
311 &finish_ctx_ptr3, &dispatch_ctx3));
312 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
313 ASSERT_NE(finish_ctx_ptr3, &finish_ctx3);
314
315 ASSERT_EQ(0, dispatch_ctx1.wait());
316 ASSERT_EQ(0, dispatch_ctx2.wait());
317 ASSERT_EQ(0, finish_ctx1.wait());
318 ASSERT_EQ(0, finish_ctx2.wait());
319 finish_ctx_ptr2->complete(0);
320
321 expect_context_complete(dispatch_ctx3, 0);
322 expect_context_complete(finish_ctx3, 0);
323 finish_ctx_ptr1->complete(0);
324
325 ASSERT_EQ(0, dispatch_ctx3.wait());
326 ASSERT_EQ(0, finish_ctx3.wait());
327 finish_ctx_ptr3->complete(0);
328 }
329
330 TEST_F(TestMockCacheWriteAroundObjectDispatch, Flush) {
331 librbd::ImageCtx *ictx;
332 ASSERT_EQ(0, open_image(m_image_name, &ictx));
333
334 MockTestImageCtx mock_image_ctx(*ictx);
335 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 4096, true);
336 expect_op_work_queue(mock_image_ctx);
337
338 InSequence seq;
339
340 io::DispatchResult dispatch_result;
341 MockContext finish_ctx;
342 MockContext dispatch_ctx;
343 Context* finish_ctx_ptr = &finish_ctx;
344 ASSERT_FALSE(object_dispatch.flush(io::FLUSH_SOURCE_USER, {}, nullptr,
345 &dispatch_result, &finish_ctx_ptr,
346 &dispatch_ctx));
347 ASSERT_EQ(finish_ctx_ptr, &finish_ctx);
348 }
349
350 TEST_F(TestMockCacheWriteAroundObjectDispatch, FlushQueuedOnInFlightIO) {
351 librbd::ImageCtx *ictx;
352 ASSERT_EQ(0, open_image(m_image_name, &ictx));
353
354 MockTestImageCtx mock_image_ctx(*ictx);
355 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 4096, false);
356 expect_op_work_queue(mock_image_ctx);
357
358 InSequence seq;
359
360 bufferlist data;
361 data.append(std::string(4096, '1'));
362
363 io::DispatchResult dispatch_result;
364 MockContext finish_ctx1;
365 MockContext dispatch_ctx1;
366 Context* finish_ctx_ptr1 = &finish_ctx1;
367
368 expect_context_complete(dispatch_ctx1, 0);
369 expect_context_complete(finish_ctx1, 0);
370
371 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
372 nullptr, nullptr, &dispatch_result,
373 &finish_ctx_ptr1, &dispatch_ctx1));
374 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
375 ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
376 ASSERT_EQ(0, dispatch_ctx1.wait());
377
378 MockContext finish_ctx2;
379 MockContext dispatch_ctx2;
380 Context* finish_ctx_ptr2 = &finish_ctx2;
381 ASSERT_FALSE(object_dispatch.flush(io::FLUSH_SOURCE_USER, {}, nullptr,
382 &dispatch_result, &finish_ctx_ptr2,
383 &dispatch_ctx2));
384 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
385 ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
386
387 expect_context_complete(finish_ctx2, 0);
388 finish_ctx_ptr1->complete(0);
389 ASSERT_EQ(0, finish_ctx1.wait());
390
391 finish_ctx_ptr2->complete(0);
392 ASSERT_EQ(0, finish_ctx2.wait());
393 }
394
395 TEST_F(TestMockCacheWriteAroundObjectDispatch, FlushQueuedOnQueuedIO) {
396 librbd::ImageCtx *ictx;
397 ASSERT_EQ(0, open_image(m_image_name, &ictx));
398
399 MockTestImageCtx mock_image_ctx(*ictx);
400 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 4096, false);
401 expect_op_work_queue(mock_image_ctx);
402
403 InSequence seq;
404
405 bufferlist data;
406 data.append(std::string(4096, '1'));
407
408 io::DispatchResult dispatch_result;
409 MockContext finish_ctx1;
410 MockContext dispatch_ctx1;
411 Context* finish_ctx_ptr1 = &finish_ctx1;
412
413 expect_context_complete(dispatch_ctx1, 0);
414 expect_context_complete(finish_ctx1, 0);
415
416 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
417 nullptr, nullptr, &dispatch_result,
418 &finish_ctx_ptr1, &dispatch_ctx1));
419 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
420 ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
421 ASSERT_EQ(0, dispatch_ctx1.wait());
422
423 MockContext finish_ctx2;
424 MockContext dispatch_ctx2;
425 Context* finish_ctx_ptr2 = &finish_ctx2;
426
427 ASSERT_TRUE(object_dispatch.write(0, 8192, std::move(data), {}, 0, {},
428 nullptr, nullptr, &dispatch_result,
429 &finish_ctx_ptr2, &dispatch_ctx2));
430 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
431 ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
432 ASSERT_EQ(0, dispatch_ctx1.wait());
433
434 MockContext finish_ctx3;
435 MockContext dispatch_ctx3;
436 Context* finish_ctx_ptr3 = &finish_ctx3;
437 ASSERT_TRUE(object_dispatch.flush(io::FLUSH_SOURCE_USER, {}, nullptr,
438 &dispatch_result, &finish_ctx_ptr3,
439 &dispatch_ctx3));
440 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
441 ASSERT_NE(finish_ctx_ptr3, &finish_ctx3);
442
443 expect_context_complete(dispatch_ctx2, 0);
444 expect_context_complete(finish_ctx2, 0);
445 expect_context_complete(dispatch_ctx3, 0);
446 finish_ctx_ptr1->complete(0);
447
448 ASSERT_EQ(0, finish_ctx1.wait());
449 ASSERT_EQ(0, dispatch_ctx2.wait());
450 ASSERT_EQ(0, finish_ctx2.wait());
451
452 expect_context_complete(finish_ctx3, 0);
453 finish_ctx_ptr2->complete(0);
454
455 finish_ctx_ptr3->complete(0);
456 ASSERT_EQ(0, finish_ctx3.wait());
457 }
458
459 TEST_F(TestMockCacheWriteAroundObjectDispatch, FlushError) {
460 librbd::ImageCtx *ictx;
461 ASSERT_EQ(0, open_image(m_image_name, &ictx));
462
463 MockTestImageCtx mock_image_ctx(*ictx);
464 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 4096, false);
465 expect_op_work_queue(mock_image_ctx);
466
467 InSequence seq;
468
469 bufferlist data;
470 data.append(std::string(4096, '1'));
471
472 io::DispatchResult dispatch_result;
473 MockContext finish_ctx1;
474 MockContext dispatch_ctx1;
475 Context* finish_ctx_ptr1 = &finish_ctx1;
476
477 expect_context_complete(dispatch_ctx1, 0);
478 expect_context_complete(finish_ctx1, 0);
479
480 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
481 nullptr, nullptr, &dispatch_result,
482 &finish_ctx_ptr1, &dispatch_ctx1));
483 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
484 ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
485 ASSERT_EQ(0, dispatch_ctx1.wait());
486 ASSERT_EQ(0, finish_ctx1.wait());
487
488 MockContext finish_ctx2;
489 MockContext dispatch_ctx2;
490 Context* finish_ctx_ptr2 = &finish_ctx2;
491 ASSERT_FALSE(object_dispatch.flush(io::FLUSH_SOURCE_USER, {}, nullptr,
492 &dispatch_result, &finish_ctx_ptr2,
493 &dispatch_ctx2));
494 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
495 ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
496
497 expect_context_complete(finish_ctx2, -EPERM);
498 finish_ctx_ptr1->complete(-EPERM);
499 finish_ctx_ptr2->complete(0);
500 ASSERT_EQ(-EPERM, finish_ctx2.wait());
501 }
502
503 TEST_F(TestMockCacheWriteAroundObjectDispatch, UnoptimizedIO) {
504 librbd::ImageCtx *ictx;
505 ASSERT_EQ(0, open_image(m_image_name, &ictx));
506
507 MockTestImageCtx mock_image_ctx(*ictx);
508 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 16384, false);
509
510 InSequence seq;
511
512 bufferlist data;
513 data.append(std::string(4096, '1'));
514
515 io::DispatchResult dispatch_result;
516 MockContext finish_ctx;
517 MockContext dispatch_ctx;
518 Context* finish_ctx_ptr = &finish_ctx;
519
520 ASSERT_FALSE(object_dispatch.compare_and_write(0, 0, std::move(data),
521 std::move(data), {}, 0, {},
522 nullptr, nullptr, nullptr,
523 &dispatch_result,
524 &finish_ctx_ptr,
525 &dispatch_ctx));
526 ASSERT_EQ(finish_ctx_ptr, &finish_ctx);
527 }
528
529 TEST_F(TestMockCacheWriteAroundObjectDispatch, UnoptimizedIOInFlightIO) {
530 librbd::ImageCtx *ictx;
531 ASSERT_EQ(0, open_image(m_image_name, &ictx));
532
533 MockTestImageCtx mock_image_ctx(*ictx);
534 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 16384, false);
535 expect_op_work_queue(mock_image_ctx);
536
537 InSequence seq;
538
539 bufferlist data;
540 data.append(std::string(4096, '1'));
541
542 io::DispatchResult dispatch_result;
543 MockContext finish_ctx1;
544 MockContext dispatch_ctx1;
545 Context* finish_ctx_ptr1 = &finish_ctx1;
546
547 expect_context_complete(dispatch_ctx1, 0);
548 expect_context_complete(finish_ctx1, 0);
549
550 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
551 nullptr, nullptr, &dispatch_result,
552 &finish_ctx_ptr1, &dispatch_ctx1));
553 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
554 ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
555 ASSERT_EQ(0, dispatch_ctx1.wait());
556 ASSERT_EQ(0, finish_ctx1.wait());
557
558 MockContext finish_ctx2;
559 MockContext dispatch_ctx2;
560 Context* finish_ctx_ptr2 = &finish_ctx2;
561 ASSERT_TRUE(object_dispatch.compare_and_write(0, 0, std::move(data),
562 std::move(data), {}, 0, {},
563 nullptr, nullptr, nullptr,
564 &dispatch_result,
565 &finish_ctx_ptr2,
566 &dispatch_ctx2));
567 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
568 ASSERT_EQ(finish_ctx_ptr2, &finish_ctx2);
569
570 expect_context_complete(dispatch_ctx2, 0);
571 finish_ctx_ptr1->complete(0);
572 ASSERT_EQ(0, dispatch_ctx2.wait());
573 }
574
575 TEST_F(TestMockCacheWriteAroundObjectDispatch, UnoptimizedIOBlockedIO) {
576 librbd::ImageCtx *ictx;
577 ASSERT_EQ(0, open_image(m_image_name, &ictx));
578
579 MockTestImageCtx mock_image_ctx(*ictx);
580 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 4096, false);
581 expect_op_work_queue(mock_image_ctx);
582
583 InSequence seq;
584
585 bufferlist data;
586 data.append(std::string(4096, '1'));
587
588 io::DispatchResult dispatch_result;
589 MockContext finish_ctx1;
590 MockContext dispatch_ctx1;
591 Context* finish_ctx_ptr1 = &finish_ctx1;
592
593 expect_context_complete(dispatch_ctx1, 0);
594 expect_context_complete(finish_ctx1, 0);
595
596 ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
597 nullptr, nullptr, &dispatch_result,
598 &finish_ctx_ptr1, &dispatch_ctx1));
599 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
600 ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
601 ASSERT_EQ(0, dispatch_ctx1.wait());
602 ASSERT_EQ(0, finish_ctx1.wait());
603
604 MockContext finish_ctx2;
605 MockContext dispatch_ctx2;
606 Context* finish_ctx_ptr2 = &finish_ctx2;
607 ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, {},
608 nullptr, nullptr, &dispatch_result,
609 &finish_ctx_ptr2, &dispatch_ctx2));
610 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
611 ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
612
613 MockContext finish_ctx3;
614 MockContext dispatch_ctx3;
615 Context* finish_ctx_ptr3 = &finish_ctx3;
616 ASSERT_TRUE(object_dispatch.compare_and_write(0, 0, std::move(data),
617 std::move(data), {}, 0, {},
618 nullptr, nullptr, nullptr,
619 &dispatch_result,
620 &finish_ctx_ptr3,
621 &dispatch_ctx3));
622 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
623 ASSERT_EQ(finish_ctx_ptr3, &finish_ctx3);
624
625 expect_context_complete(dispatch_ctx3, 0);
626 expect_context_complete(dispatch_ctx2, 0);
627 expect_context_complete(finish_ctx2, 0);
628 finish_ctx_ptr1->complete(0);
629 ASSERT_EQ(0, dispatch_ctx3.wait());
630 ASSERT_EQ(0, dispatch_ctx2.wait());
631 ASSERT_EQ(0, finish_ctx2.wait());
632 finish_ctx_ptr2->complete(0);
633 }
634
635 TEST_F(TestMockCacheWriteAroundObjectDispatch, FUA) {
636 librbd::ImageCtx *ictx;
637 ASSERT_EQ(0, open_image(m_image_name, &ictx));
638
639 MockTestImageCtx mock_image_ctx(*ictx);
640 MockWriteAroundObjectDispatch object_dispatch(&mock_image_ctx, 16384, false);
641
642 InSequence seq;
643
644 bufferlist data;
645 data.append(std::string(4096, '1'));
646
647 io::DispatchResult dispatch_result;
648 MockContext finish_ctx;
649 MockContext dispatch_ctx;
650 Context* finish_ctx_ptr = &finish_ctx;
651 ASSERT_FALSE(object_dispatch.write(0, 0, std::move(data), {},
652 LIBRADOS_OP_FLAG_FADVISE_FUA, {},
653 nullptr, nullptr, &dispatch_result,
654 &finish_ctx_ptr, &dispatch_ctx));
655 ASSERT_EQ(finish_ctx_ptr, &finish_ctx);
656 }
657
658 } // namespace cache
659 } // namespace librbd