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