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/librbd/mock/MockImageCtx.h"
7 #include "include/rbd/librbd.hpp"
8 #include "librbd/cache/WriteAroundObjectDispatch.h"
9 #include "librbd/io/ObjectDispatchSpec.h"
14 struct MockTestImageCtx
: public MockImageCtx
{
15 MockTestImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
19 struct MockContext
: public C_SaferCond
{
20 MOCK_METHOD1(complete
, void(int));
21 MOCK_METHOD1(finish
, void(int));
23 void do_complete(int r
) {
24 C_SaferCond::complete(r
);
28 } // anonymous namespace
31 #include "librbd/cache/WriteAroundObjectDispatch.cc"
37 using ::testing::DoDefault
;
38 using ::testing::InSequence
;
39 using ::testing::Invoke
;
41 struct TestMockCacheWriteAroundObjectDispatch
: public TestMockFixture
{
42 typedef WriteAroundObjectDispatch
<librbd::MockTestImageCtx
> MockWriteAroundObjectDispatch
;
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
) {
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
);
59 TEST_F(TestMockCacheWriteAroundObjectDispatch
, WriteThrough
) {
60 librbd::ImageCtx
*ictx
;
61 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
63 MockTestImageCtx
mock_image_ctx(*ictx
);
64 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 0, false);
69 data
.append(std::string(4096, '1'));
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
);
81 TEST_F(TestMockCacheWriteAroundObjectDispatch
, WriteThroughUntilFlushed
) {
82 librbd::ImageCtx
*ictx
;
83 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
85 MockTestImageCtx
mock_image_ctx(*ictx
);
86 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 4096, true);
87 expect_op_work_queue(mock_image_ctx
);
92 data
.append(std::string(4096, '1'));
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
);
103 ASSERT_FALSE(object_dispatch
.flush(io::FLUSH_SOURCE_USER
, {}, nullptr,
104 &dispatch_result
, &finish_ctx_ptr
,
107 expect_context_complete(dispatch_ctx
, 0);
108 expect_context_complete(finish_ctx
, 0);
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);
120 TEST_F(TestMockCacheWriteAroundObjectDispatch
, DispatchIO
) {
121 librbd::ImageCtx
*ictx
;
122 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
124 MockTestImageCtx
mock_image_ctx(*ictx
);
125 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 4096, false);
126 expect_op_work_queue(mock_image_ctx
);
131 data
.append(std::string(4096, '1'));
133 io::DispatchResult dispatch_result
;
134 MockContext finish_ctx
;
135 MockContext dispatch_ctx
;
136 Context
* finish_ctx_ptr
= &finish_ctx
;
138 expect_context_complete(dispatch_ctx
, 0);
139 expect_context_complete(finish_ctx
, 0);
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
);
147 ASSERT_EQ(0, dispatch_ctx
.wait());
148 ASSERT_EQ(0, finish_ctx
.wait());
149 finish_ctx_ptr
->complete(0);
152 TEST_F(TestMockCacheWriteAroundObjectDispatch
, BlockedIO
) {
153 librbd::ImageCtx
*ictx
;
154 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
156 MockTestImageCtx
mock_image_ctx(*ictx
);
157 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 16384, false);
158 expect_op_work_queue(mock_image_ctx
);
163 data
.append(std::string(4096, '1'));
165 io::DispatchResult dispatch_result
;
166 MockContext finish_ctx1
;
167 MockContext dispatch_ctx1
;
168 Context
* finish_ctx_ptr1
= &finish_ctx1
;
170 expect_context_complete(dispatch_ctx1
, 0);
171 expect_context_complete(finish_ctx1
, 0);
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
);
179 MockContext finish_ctx2
;
180 MockContext dispatch_ctx2
;
181 Context
* finish_ctx_ptr2
= &finish_ctx2
;
183 expect_context_complete(dispatch_ctx2
, 0);
184 expect_context_complete(finish_ctx2
, 0);
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
);
192 MockContext finish_ctx3
;
193 MockContext dispatch_ctx3
;
194 Context
* finish_ctx_ptr3
= &finish_ctx3
;
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
);
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);
208 expect_context_complete(dispatch_ctx3
, 0);
209 expect_context_complete(finish_ctx3
, 0);
210 finish_ctx_ptr1
->complete(0);
212 ASSERT_EQ(0, dispatch_ctx3
.wait());
213 finish_ctx_ptr3
->complete(0);
214 ASSERT_EQ(0, finish_ctx3
.wait());
217 TEST_F(TestMockCacheWriteAroundObjectDispatch
, QueuedIO
) {
218 librbd::ImageCtx
*ictx
;
219 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
221 MockTestImageCtx
mock_image_ctx(*ictx
);
222 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 4095, false);
223 expect_op_work_queue(mock_image_ctx
);
228 data
.append(std::string(4096, '1'));
230 io::DispatchResult dispatch_result
;
231 MockContext finish_ctx1
;
232 MockContext dispatch_ctx1
;
233 Context
* finish_ctx_ptr1
= &finish_ctx1
;
235 expect_context_complete(dispatch_ctx1
, 0);
236 expect_context_complete(finish_ctx1
, 0);
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
);
244 MockContext finish_ctx2
;
245 MockContext dispatch_ctx2
;
246 Context
* finish_ctx_ptr2
= &finish_ctx2
;
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());
255 expect_context_complete(dispatch_ctx2
, 0);
256 expect_context_complete(finish_ctx2
, 0);
257 finish_ctx_ptr1
->complete(0);
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);
265 TEST_F(TestMockCacheWriteAroundObjectDispatch
, BlockedAndQueuedIO
) {
266 librbd::ImageCtx
*ictx
;
267 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
269 MockTestImageCtx
mock_image_ctx(*ictx
);
270 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 8196, false);
271 expect_op_work_queue(mock_image_ctx
);
276 data
.append(std::string(4096, '1'));
278 io::DispatchResult dispatch_result
;
279 MockContext finish_ctx1
;
280 MockContext dispatch_ctx1
;
281 Context
* finish_ctx_ptr1
= &finish_ctx1
;
283 expect_context_complete(dispatch_ctx1
, 0);
284 expect_context_complete(finish_ctx1
, 0);
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
);
292 MockContext finish_ctx2
;
293 MockContext dispatch_ctx2
;
294 Context
* finish_ctx_ptr2
= &finish_ctx2
;
296 expect_context_complete(dispatch_ctx2
, 0);
297 expect_context_complete(finish_ctx2
, 0);
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
);
305 MockContext finish_ctx3
;
306 MockContext dispatch_ctx3
;
307 Context
* finish_ctx_ptr3
= &finish_ctx3
;
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
);
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);
321 expect_context_complete(dispatch_ctx3
, 0);
322 expect_context_complete(finish_ctx3
, 0);
323 finish_ctx_ptr1
->complete(0);
325 ASSERT_EQ(0, dispatch_ctx3
.wait());
326 ASSERT_EQ(0, finish_ctx3
.wait());
327 finish_ctx_ptr3
->complete(0);
330 TEST_F(TestMockCacheWriteAroundObjectDispatch
, Flush
) {
331 librbd::ImageCtx
*ictx
;
332 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
334 MockTestImageCtx
mock_image_ctx(*ictx
);
335 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 4096, true);
336 expect_op_work_queue(mock_image_ctx
);
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
,
347 ASSERT_EQ(finish_ctx_ptr
, &finish_ctx
);
350 TEST_F(TestMockCacheWriteAroundObjectDispatch
, FlushQueuedOnInFlightIO
) {
351 librbd::ImageCtx
*ictx
;
352 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
354 MockTestImageCtx
mock_image_ctx(*ictx
);
355 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 4096, false);
356 expect_op_work_queue(mock_image_ctx
);
361 data
.append(std::string(4096, '1'));
363 io::DispatchResult dispatch_result
;
364 MockContext finish_ctx1
;
365 MockContext dispatch_ctx1
;
366 Context
* finish_ctx_ptr1
= &finish_ctx1
;
368 expect_context_complete(dispatch_ctx1
, 0);
369 expect_context_complete(finish_ctx1
, 0);
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());
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
,
384 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE
, dispatch_result
);
385 ASSERT_NE(finish_ctx_ptr2
, &finish_ctx2
);
387 expect_context_complete(finish_ctx2
, 0);
388 finish_ctx_ptr1
->complete(0);
389 ASSERT_EQ(0, finish_ctx1
.wait());
391 finish_ctx_ptr2
->complete(0);
392 ASSERT_EQ(0, finish_ctx2
.wait());
395 TEST_F(TestMockCacheWriteAroundObjectDispatch
, FlushQueuedOnQueuedIO
) {
396 librbd::ImageCtx
*ictx
;
397 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
399 MockTestImageCtx
mock_image_ctx(*ictx
);
400 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 4096, false);
401 expect_op_work_queue(mock_image_ctx
);
406 data
.append(std::string(4096, '1'));
408 io::DispatchResult dispatch_result
;
409 MockContext finish_ctx1
;
410 MockContext dispatch_ctx1
;
411 Context
* finish_ctx_ptr1
= &finish_ctx1
;
413 expect_context_complete(dispatch_ctx1
, 0);
414 expect_context_complete(finish_ctx1
, 0);
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());
423 MockContext finish_ctx2
;
424 MockContext dispatch_ctx2
;
425 Context
* finish_ctx_ptr2
= &finish_ctx2
;
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());
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
,
440 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE
, dispatch_result
);
441 ASSERT_NE(finish_ctx_ptr3
, &finish_ctx3
);
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);
448 ASSERT_EQ(0, finish_ctx1
.wait());
449 ASSERT_EQ(0, dispatch_ctx2
.wait());
450 ASSERT_EQ(0, finish_ctx2
.wait());
452 expect_context_complete(finish_ctx3
, 0);
453 finish_ctx_ptr2
->complete(0);
455 finish_ctx_ptr3
->complete(0);
456 ASSERT_EQ(0, finish_ctx3
.wait());
459 TEST_F(TestMockCacheWriteAroundObjectDispatch
, FlushError
) {
460 librbd::ImageCtx
*ictx
;
461 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
463 MockTestImageCtx
mock_image_ctx(*ictx
);
464 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 4096, false);
465 expect_op_work_queue(mock_image_ctx
);
470 data
.append(std::string(4096, '1'));
472 io::DispatchResult dispatch_result
;
473 MockContext finish_ctx1
;
474 MockContext dispatch_ctx1
;
475 Context
* finish_ctx_ptr1
= &finish_ctx1
;
477 expect_context_complete(dispatch_ctx1
, 0);
478 expect_context_complete(finish_ctx1
, 0);
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());
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
,
494 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE
, dispatch_result
);
495 ASSERT_NE(finish_ctx_ptr2
, &finish_ctx2
);
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());
503 TEST_F(TestMockCacheWriteAroundObjectDispatch
, UnoptimizedIO
) {
504 librbd::ImageCtx
*ictx
;
505 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
507 MockTestImageCtx
mock_image_ctx(*ictx
);
508 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 16384, false);
513 data
.append(std::string(4096, '1'));
515 io::DispatchResult dispatch_result
;
516 MockContext finish_ctx
;
517 MockContext dispatch_ctx
;
518 Context
* finish_ctx_ptr
= &finish_ctx
;
520 ASSERT_FALSE(object_dispatch
.compare_and_write(0, 0, std::move(data
),
521 std::move(data
), {}, 0, {},
522 nullptr, nullptr, nullptr,
526 ASSERT_EQ(finish_ctx_ptr
, &finish_ctx
);
529 TEST_F(TestMockCacheWriteAroundObjectDispatch
, UnoptimizedIOInFlightIO
) {
530 librbd::ImageCtx
*ictx
;
531 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
533 MockTestImageCtx
mock_image_ctx(*ictx
);
534 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 16384, false);
535 expect_op_work_queue(mock_image_ctx
);
540 data
.append(std::string(4096, '1'));
542 io::DispatchResult dispatch_result
;
543 MockContext finish_ctx1
;
544 MockContext dispatch_ctx1
;
545 Context
* finish_ctx_ptr1
= &finish_ctx1
;
547 expect_context_complete(dispatch_ctx1
, 0);
548 expect_context_complete(finish_ctx1
, 0);
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());
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,
567 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE
, dispatch_result
);
568 ASSERT_EQ(finish_ctx_ptr2
, &finish_ctx2
);
570 expect_context_complete(dispatch_ctx2
, 0);
571 finish_ctx_ptr1
->complete(0);
572 ASSERT_EQ(0, dispatch_ctx2
.wait());
575 TEST_F(TestMockCacheWriteAroundObjectDispatch
, UnoptimizedIOBlockedIO
) {
576 librbd::ImageCtx
*ictx
;
577 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
579 MockTestImageCtx
mock_image_ctx(*ictx
);
580 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 4096, false);
581 expect_op_work_queue(mock_image_ctx
);
586 data
.append(std::string(4096, '1'));
588 io::DispatchResult dispatch_result
;
589 MockContext finish_ctx1
;
590 MockContext dispatch_ctx1
;
591 Context
* finish_ctx_ptr1
= &finish_ctx1
;
593 expect_context_complete(dispatch_ctx1
, 0);
594 expect_context_complete(finish_ctx1
, 0);
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());
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
);
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,
622 ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE
, dispatch_result
);
623 ASSERT_EQ(finish_ctx_ptr3
, &finish_ctx3
);
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);
635 TEST_F(TestMockCacheWriteAroundObjectDispatch
, FUA
) {
636 librbd::ImageCtx
*ictx
;
637 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
639 MockTestImageCtx
mock_image_ctx(*ictx
);
640 MockWriteAroundObjectDispatch
object_dispatch(&mock_image_ctx
, 16384, false);
645 data
.append(std::string(4096, '1'));
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
);
659 } // namespace librbd