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 "test/librbd/mock/MockSafeTimer.h"
8 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9 #include "test/librados_test_stub/MockTestMemRadosClient.h"
10 #include "include/rbd/librbd.hpp"
11 #include "librbd/io/ObjectDispatchSpec.h"
12 #include "librbd/io/SimpleSchedulerObjectDispatch.h"
17 struct MockTestImageCtx
: public MockImageCtx
{
18 MockTestImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
22 } // anonymous namespace
27 struct TypeTraits
<MockTestImageCtx
> {
28 typedef ::MockSafeTimer SafeTimer
;
34 #include "librbd/io/SimpleSchedulerObjectDispatch.cc"
40 using ::testing::InSequence
;
41 using ::testing::Invoke
;
42 using ::testing::Return
;
44 struct TestMockIoSimpleSchedulerObjectDispatch
: public TestMockFixture
{
45 typedef SimpleSchedulerObjectDispatch
<librbd::MockTestImageCtx
> MockSimpleSchedulerObjectDispatch
;
47 MockSafeTimer m_mock_timer
;
48 ceph::mutex m_mock_timer_lock
=
49 ceph::make_mutex("TestMockIoSimpleSchedulerObjectDispatch::Mutex");
51 TestMockIoSimpleSchedulerObjectDispatch() {
52 MockTestImageCtx::set_timer_instance(&m_mock_timer
, &m_mock_timer_lock
);
53 EXPECT_EQ(0, _rados
.conf_set("rbd_io_scheduler_simple_max_delay", "1"));
56 void expect_get_object_name(MockTestImageCtx
&mock_image_ctx
,
58 EXPECT_CALL(mock_image_ctx
, get_object_name(object_no
))
59 .WillRepeatedly(Return(
60 mock_image_ctx
.image_ctx
->get_object_name(object_no
)));
63 void expect_dispatch_delayed_requests(MockTestImageCtx
&mock_image_ctx
,
65 EXPECT_CALL(*mock_image_ctx
.io_object_dispatcher
, send(_
))
66 .WillOnce(Invoke([&mock_image_ctx
, r
](ObjectDispatchSpec
* spec
) {
67 spec
->dispatch_result
= io::DISPATCH_RESULT_COMPLETE
;
68 mock_image_ctx
.image_ctx
->op_work_queue
->queue(
69 &spec
->dispatcher_ctx
, r
);
73 void expect_cancel_timer_task(Context
*timer_task
) {
74 EXPECT_CALL(m_mock_timer
, cancel_event(timer_task
))
75 .WillOnce(Invoke([](Context
*timer_task
) {
81 void expect_add_timer_task(Context
**timer_task
) {
82 EXPECT_CALL(m_mock_timer
, add_event_at(_
, _
))
83 .WillOnce(Invoke([timer_task
](ceph::real_clock::time_point
, Context
*task
) {
89 void expect_schedule_dispatch_delayed_requests(Context
*current_task
,
91 if (current_task
!= nullptr) {
92 expect_cancel_timer_task(current_task
);
94 if (new_task
!= nullptr) {
95 expect_add_timer_task(new_task
);
99 void run_timer_task(Context
*timer_task
) {
100 std::lock_guard timer_locker
{m_mock_timer_lock
};
101 timer_task
->complete(0);
105 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, Read
) {
106 librbd::ImageCtx
*ictx
;
107 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
109 MockTestImageCtx
mock_image_ctx(*ictx
);
110 MockSimpleSchedulerObjectDispatch
111 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
114 Context
*on_finish
= &cond
;
115 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.read(
116 0, 0, 4096, CEPH_NOSNAP
, 0, {}, nullptr, nullptr, nullptr, nullptr,
117 &on_finish
, nullptr));
118 ASSERT_EQ(on_finish
, &cond
); // not modified
119 on_finish
->complete(0);
120 ASSERT_EQ(0, cond
.wait());
123 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, Discard
) {
124 librbd::ImageCtx
*ictx
;
125 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
127 MockTestImageCtx
mock_image_ctx(*ictx
);
128 MockSimpleSchedulerObjectDispatch
129 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
132 Context
*on_finish
= &cond
;
133 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.discard(
134 0, 0, 4096, mock_image_ctx
.snapc
, 0, {}, nullptr, nullptr, nullptr,
135 &on_finish
, nullptr));
136 ASSERT_NE(on_finish
, &cond
);
137 on_finish
->complete(0);
138 ASSERT_EQ(0, cond
.wait());
141 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, Write
) {
142 librbd::ImageCtx
*ictx
;
143 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
145 MockTestImageCtx
mock_image_ctx(*ictx
);
146 MockSimpleSchedulerObjectDispatch
147 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
149 ceph::bufferlist data
;
151 int object_dispatch_flags
= 0;
153 Context
*on_finish
= &cond
;
154 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
155 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
156 &object_dispatch_flags
, nullptr, nullptr, &on_finish
, nullptr));
157 ASSERT_NE(on_finish
, &cond
);
158 on_finish
->complete(0);
159 ASSERT_EQ(0, cond
.wait());
162 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, WriteSame
) {
163 librbd::ImageCtx
*ictx
;
164 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
166 MockTestImageCtx
mock_image_ctx(*ictx
);
167 MockSimpleSchedulerObjectDispatch
168 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
170 io::LightweightBufferExtents buffer_extents
;
171 ceph::bufferlist data
;
173 Context
*on_finish
= &cond
;
174 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write_same(
175 0, 0, 4096, std::move(buffer_extents
), std::move(data
),
176 mock_image_ctx
.snapc
, 0, {}, nullptr, nullptr, nullptr, &on_finish
,
178 ASSERT_NE(on_finish
, &cond
);
179 on_finish
->complete(0);
180 ASSERT_EQ(0, cond
.wait());
183 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, CompareAndWrite
) {
184 librbd::ImageCtx
*ictx
;
185 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
187 MockTestImageCtx
mock_image_ctx(*ictx
);
188 MockSimpleSchedulerObjectDispatch
189 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
191 ceph::bufferlist cmp_data
;
192 ceph::bufferlist write_data
;
194 Context
*on_finish
= &cond
;
195 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.compare_and_write(
196 0, 0, std::move(cmp_data
), std::move(write_data
), mock_image_ctx
.snapc
, 0,
197 {}, nullptr, nullptr, nullptr, nullptr, &on_finish
, nullptr));
198 ASSERT_NE(on_finish
, &cond
);
199 on_finish
->complete(0);
200 ASSERT_EQ(0, cond
.wait());
203 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, Flush
) {
204 librbd::ImageCtx
*ictx
;
205 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
207 MockTestImageCtx
mock_image_ctx(*ictx
);
208 MockSimpleSchedulerObjectDispatch
209 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
212 Context
*on_finish
= &cond
;
213 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.flush(
214 FLUSH_SOURCE_USER
, {}, nullptr, nullptr, &on_finish
, nullptr));
215 ASSERT_EQ(on_finish
, &cond
); // not modified
216 on_finish
->complete(0);
217 ASSERT_EQ(0, cond
.wait());
220 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, WriteDelayed
) {
221 librbd::ImageCtx
*ictx
;
222 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
224 MockTestImageCtx
mock_image_ctx(*ictx
);
225 MockSimpleSchedulerObjectDispatch
226 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
228 expect_get_object_name(mock_image_ctx
, 0);
232 ceph::bufferlist data
;
234 int object_dispatch_flags
= 0;
236 Context
*on_finish1
= &cond1
;
237 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
238 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
239 &object_dispatch_flags
, nullptr, nullptr, &on_finish1
, nullptr));
240 ASSERT_NE(on_finish1
, &cond1
);
242 Context
*timer_task
= nullptr;
243 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
245 io::DispatchResult dispatch_result
;
247 Context
*on_finish2
= &cond2
;
248 C_SaferCond on_dispatched
;
249 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
250 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
251 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish2
,
253 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
254 ASSERT_EQ(on_finish2
, &cond2
);
255 ASSERT_NE(timer_task
, nullptr);
257 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
258 expect_schedule_dispatch_delayed_requests(timer_task
, nullptr);
260 on_finish1
->complete(0);
261 ASSERT_EQ(0, cond1
.wait());
262 ASSERT_EQ(0, on_dispatched
.wait());
263 on_finish2
->complete(0);
264 ASSERT_EQ(0, cond2
.wait());
267 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, WriteDelayedFlush
) {
268 librbd::ImageCtx
*ictx
;
269 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
271 MockTestImageCtx
mock_image_ctx(*ictx
);
272 MockSimpleSchedulerObjectDispatch
273 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
275 expect_get_object_name(mock_image_ctx
, 0);
279 ceph::bufferlist data
;
281 int object_dispatch_flags
= 0;
283 Context
*on_finish1
= &cond1
;
284 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
285 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
286 &object_dispatch_flags
, nullptr, nullptr, &on_finish1
, nullptr));
287 ASSERT_NE(on_finish1
, &cond1
);
289 Context
*timer_task
= nullptr;
290 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
292 io::DispatchResult dispatch_result
;
294 Context
*on_finish2
= &cond2
;
295 C_SaferCond on_dispatched
;
296 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
297 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
298 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish2
,
300 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
301 ASSERT_EQ(on_finish2
, &cond2
);
302 ASSERT_NE(timer_task
, nullptr);
304 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
305 expect_schedule_dispatch_delayed_requests(timer_task
, nullptr);
308 Context
*on_finish3
= &cond3
;
309 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.flush(
310 FLUSH_SOURCE_USER
, {}, nullptr, nullptr, &on_finish3
, nullptr));
311 ASSERT_EQ(on_finish3
, &cond3
);
313 on_finish1
->complete(0);
314 ASSERT_EQ(0, cond1
.wait());
315 ASSERT_EQ(0, on_dispatched
.wait());
316 on_finish2
->complete(0);
317 ASSERT_EQ(0, cond2
.wait());
318 on_finish3
->complete(0);
319 ASSERT_EQ(0, cond3
.wait());
322 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, WriteMerged
) {
323 librbd::ImageCtx
*ictx
;
324 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
326 MockTestImageCtx
mock_image_ctx(*ictx
);
327 MockSimpleSchedulerObjectDispatch
328 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
330 expect_get_object_name(mock_image_ctx
, 0);
334 ceph::bufferlist data
;
336 int object_dispatch_flags
= 0;
338 Context
*on_finish1
= &cond1
;
339 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
340 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
341 &object_dispatch_flags
, nullptr, nullptr, &on_finish1
, nullptr));
342 ASSERT_NE(on_finish1
, &cond1
);
344 Context
*timer_task
= nullptr;
345 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
347 uint64_t object_off
= 20;
349 data
.append(std::string(10, 'A'));
350 io::DispatchResult dispatch_result
;
352 Context
*on_finish2
= &cond2
;
353 C_SaferCond on_dispatched2
;
354 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
355 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
356 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish2
,
358 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
359 ASSERT_EQ(on_finish2
, &cond2
);
360 ASSERT_NE(timer_task
, nullptr);
364 data
.append(std::string(10, 'B'));
366 Context
*on_finish3
= &cond3
;
367 C_SaferCond on_dispatched3
;
368 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
369 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
370 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish3
,
372 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
373 ASSERT_EQ(on_finish3
, &cond3
);
377 data
.append(std::string(10, 'C'));
379 Context
*on_finish4
= &cond4
;
380 C_SaferCond on_dispatched4
;
381 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
382 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
383 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish4
,
385 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
386 ASSERT_EQ(on_finish4
, &cond4
);
390 data
.append(std::string(10, 'D'));
392 Context
*on_finish5
= &cond5
;
393 C_SaferCond on_dispatched5
;
394 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
395 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
396 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish5
,
398 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
399 ASSERT_EQ(on_finish5
, &cond5
);
403 data
.append(std::string(10, 'E'));
405 Context
*on_finish6
= &cond6
;
406 C_SaferCond on_dispatched6
;
407 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
408 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
409 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish6
,
411 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
412 ASSERT_EQ(on_finish6
, &cond6
);
414 // expect two requests dispatched:
415 // 0~40 (merged 0~10, 10~10, 20~10, 30~10) and 50~10
416 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
417 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
418 expect_schedule_dispatch_delayed_requests(timer_task
, nullptr);
420 on_finish1
->complete(0);
421 ASSERT_EQ(0, cond1
.wait());
422 ASSERT_EQ(0, on_dispatched2
.wait());
423 ASSERT_EQ(0, on_dispatched3
.wait());
424 ASSERT_EQ(0, on_dispatched4
.wait());
425 ASSERT_EQ(0, on_dispatched5
.wait());
426 ASSERT_EQ(0, on_dispatched6
.wait());
427 on_finish2
->complete(0);
428 on_finish3
->complete(0);
429 on_finish4
->complete(0);
430 on_finish5
->complete(0);
431 on_finish6
->complete(0);
432 ASSERT_EQ(0, cond2
.wait());
433 ASSERT_EQ(0, cond3
.wait());
434 ASSERT_EQ(0, cond4
.wait());
435 ASSERT_EQ(0, cond5
.wait());
436 ASSERT_EQ(0, cond6
.wait());
439 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, WriteNonSequential
) {
440 librbd::ImageCtx
*ictx
;
441 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
443 MockTestImageCtx
mock_image_ctx(*ictx
);
444 MockSimpleSchedulerObjectDispatch
445 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
447 expect_get_object_name(mock_image_ctx
, 0);
451 ceph::bufferlist data
;
452 int object_dispatch_flags
= 0;
454 Context
*on_finish1
= &cond1
;
455 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
456 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
457 &object_dispatch_flags
, nullptr, nullptr, &on_finish1
, nullptr));
458 ASSERT_NE(on_finish1
, &cond1
);
460 Context
*timer_task
= nullptr;
461 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
463 uint64_t object_off
= 0;
465 data
.append(std::string(10, 'X'));
466 io::DispatchResult dispatch_result
;
468 Context
*on_finish2
= &cond2
;
469 C_SaferCond on_dispatched2
;
470 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
471 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
472 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish2
,
474 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
475 ASSERT_EQ(on_finish2
, &cond2
);
476 ASSERT_NE(timer_task
, nullptr);
478 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
479 expect_schedule_dispatch_delayed_requests(timer_task
, nullptr);
483 data
.append(std::string(10, 'Y'));
485 Context
*on_finish3
= &cond3
;
486 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
487 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
488 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish3
, nullptr));
489 ASSERT_NE(on_finish3
, &cond3
);
491 on_finish1
->complete(0);
492 ASSERT_EQ(0, cond1
.wait());
493 ASSERT_EQ(0, on_dispatched2
.wait());
494 on_finish2
->complete(0);
495 ASSERT_EQ(0, cond2
.wait());
496 on_finish3
->complete(0);
497 ASSERT_EQ(0, cond3
.wait());
500 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, Mixed
) {
501 librbd::ImageCtx
*ictx
;
502 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
504 MockTestImageCtx
mock_image_ctx(*ictx
);
505 MockSimpleSchedulerObjectDispatch
506 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
508 expect_get_object_name(mock_image_ctx
, 0);
512 // write (1) 0~0 (in-flight)
513 // will wrap on_finish with dispatch_seq=1 to dispatch future delayed writes
514 ceph::bufferlist data
;
515 int object_dispatch_flags
= 0;
517 Context
*on_finish1
= &cond1
;
518 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
519 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
520 &object_dispatch_flags
, nullptr, nullptr, &on_finish1
, nullptr));
521 ASSERT_NE(on_finish1
, &cond1
);
523 // write (2) 0~10 (delayed)
524 // will wait for write (1) to finish or a non-seq io comes
525 Context
*timer_task
= nullptr;
526 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
527 uint64_t object_off
= 0;
529 data
.append(std::string(10, 'A'));
530 io::DispatchResult dispatch_result
;
532 Context
*on_finish2
= &cond2
;
533 C_SaferCond on_dispatched2
;
534 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
535 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
536 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish2
,
538 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
539 ASSERT_EQ(on_finish2
, &cond2
);
540 ASSERT_NE(timer_task
, nullptr);
542 // write (3) 10~10 (delayed)
543 // will be merged with write (2)
546 data
.append(std::string(10, 'B'));
548 Context
*on_finish3
= &cond3
;
549 C_SaferCond on_dispatched3
;
550 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
551 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
552 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish3
,
554 ASSERT_EQ(on_finish3
, &cond3
);
556 // discard (1) (non-seq io)
557 // will dispatch the delayed writes (2) and (3) and wrap on_finish
558 // with dispatch_seq=2 to dispatch future delayed writes
559 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
560 expect_schedule_dispatch_delayed_requests(timer_task
, nullptr);
562 Context
*on_finish4
= &cond4
;
563 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.discard(
564 0, 4096, 4096, mock_image_ctx
.snapc
, 0, {}, nullptr, nullptr, nullptr,
565 &on_finish4
, nullptr));
566 ASSERT_NE(on_finish4
, &cond4
);
567 ASSERT_EQ(0, on_dispatched2
.wait());
568 ASSERT_EQ(0, on_dispatched3
.wait());
570 // write (4) 20~10 (delayed)
571 // will wait for discard (1) to finish or a non-seq io comes
572 timer_task
= nullptr;
573 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
576 data
.append(std::string(10, 'C'));
578 Context
*on_finish5
= &cond5
;
579 C_SaferCond on_dispatched5
;
580 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
581 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
582 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish5
,
584 ASSERT_EQ(on_finish5
, &cond5
);
585 ASSERT_NE(timer_task
, nullptr);
587 // discard (2) (non-seq io)
588 // will dispatch the delayed write (4) and wrap on_finish with dispatch_seq=3
589 // to dispatch future delayed writes
590 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
591 expect_schedule_dispatch_delayed_requests(timer_task
, nullptr);
593 Context
*on_finish6
= &cond6
;
594 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.discard(
595 0, 4096, 4096, mock_image_ctx
.snapc
, 0, {}, nullptr, nullptr, nullptr,
596 &on_finish6
, nullptr));
597 ASSERT_NE(on_finish6
, &cond6
);
598 ASSERT_EQ(0, on_dispatched5
.wait());
600 // write (5) 30~10 (delayed)
601 // will wait for discard (2) to finish or a non-seq io comes
602 timer_task
= nullptr;
603 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
606 data
.append(std::string(10, 'D'));
608 Context
*on_finish7
= &cond7
;
609 C_SaferCond on_dispatched7
;
610 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
611 0, object_off
, std::move(data
), mock_image_ctx
.snapc
, 0, {},
612 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish7
,
614 ASSERT_EQ(on_finish7
, &cond7
);
615 ASSERT_NE(timer_task
, nullptr);
617 // write (1) finishes
618 // on_finish wrapper will skip dispatch delayed write (5)
619 // due to dispatch_seq(1) < m_dispatch_seq(3)
620 on_finish1
->complete(0);
621 ASSERT_EQ(0, cond1
.wait());
623 // writes (2) and (3) finish ("dispatch delayed" is not called)
624 on_finish2
->complete(0);
625 on_finish3
->complete(0);
626 ASSERT_EQ(0, cond2
.wait());
627 ASSERT_EQ(0, cond3
.wait());
629 // discard (1) finishes
630 // on_finish wrapper will skip dispatch delayed write (5)
631 // due to dispatch_seq(2) < m_dispatch_seq(3)
632 on_finish4
->complete(0);
633 ASSERT_EQ(0, cond4
.wait());
635 // writes (4) finishes ("dispatch delayed" is not called)
636 on_finish5
->complete(0);
637 ASSERT_EQ(0, cond5
.wait());
639 // discard (2) finishes
640 // on_finish wrapper will dispatch the delayed write (5)
641 // due to dispatch_seq(3) == m_dispatch_seq(3)
642 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
643 expect_schedule_dispatch_delayed_requests(timer_task
, nullptr);
644 on_finish6
->complete(0);
645 ASSERT_EQ(0, cond6
.wait());
646 ASSERT_EQ(0, on_dispatched7
.wait());
648 // write (5) finishes ("dispatch delayed" is not called)
649 on_finish7
->complete(0);
650 ASSERT_EQ(0, cond7
.wait());
653 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, DispatchQueue
) {
654 librbd::ImageCtx
*ictx
;
655 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
657 MockTestImageCtx
mock_image_ctx(*ictx
);
658 MockSimpleSchedulerObjectDispatch
659 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
661 expect_get_object_name(mock_image_ctx
, 0);
662 expect_get_object_name(mock_image_ctx
, 1);
666 // send 2 writes to object 0
668 uint64_t object_no
= 0;
669 ceph::bufferlist data
;
670 int object_dispatch_flags
= 0;
672 Context
*on_finish1
= &cond1
;
673 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
674 object_no
, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
675 &object_dispatch_flags
, nullptr, nullptr, &on_finish1
, nullptr));
676 ASSERT_NE(on_finish1
, &cond1
);
678 Context
*timer_task
= nullptr;
679 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
682 io::DispatchResult dispatch_result
;
684 Context
*on_finish2
= &cond2
;
685 C_SaferCond on_dispatched2
;
686 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
687 object_no
, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
688 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish2
,
690 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
691 ASSERT_EQ(on_finish2
, &cond2
);
692 ASSERT_NE(timer_task
, nullptr);
694 // send 2 writes to object 1
699 Context
*on_finish3
= &cond3
;
700 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
701 object_no
, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
702 &object_dispatch_flags
, nullptr, nullptr, &on_finish3
, nullptr));
703 ASSERT_NE(on_finish3
, &cond3
);
707 Context
*on_finish4
= &cond4
;
708 C_SaferCond on_dispatched4
;
709 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
710 object_no
, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
711 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish4
,
713 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
714 ASSERT_EQ(on_finish4
, &cond4
);
716 // finish write (1) to object 0
717 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
718 expect_schedule_dispatch_delayed_requests(timer_task
, &timer_task
);
719 on_finish1
->complete(0);
720 ASSERT_EQ(0, cond1
.wait());
721 ASSERT_EQ(0, on_dispatched2
.wait());
723 // finish write (2) to object 0
724 on_finish2
->complete(0);
725 ASSERT_EQ(0, cond2
.wait());
727 // finish write (1) to object 1
728 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
729 expect_schedule_dispatch_delayed_requests(timer_task
, nullptr);
730 on_finish3
->complete(0);
731 ASSERT_EQ(0, cond3
.wait());
732 ASSERT_EQ(0, on_dispatched4
.wait());
734 // finish write (2) to object 1
735 on_finish4
->complete(0);
736 ASSERT_EQ(0, cond4
.wait());
739 TEST_F(TestMockIoSimpleSchedulerObjectDispatch
, Timer
) {
740 librbd::ImageCtx
*ictx
;
741 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
743 MockTestImageCtx
mock_image_ctx(*ictx
);
744 MockSimpleSchedulerObjectDispatch
745 mock_simple_scheduler_object_dispatch(&mock_image_ctx
);
747 expect_get_object_name(mock_image_ctx
, 0);
748 expect_op_work_queue(mock_image_ctx
);
752 ceph::bufferlist data
;
753 int object_dispatch_flags
= 0;
755 Context
*on_finish1
= &cond1
;
756 ASSERT_FALSE(mock_simple_scheduler_object_dispatch
.write(
757 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
758 &object_dispatch_flags
, nullptr, nullptr, &on_finish1
, nullptr));
759 ASSERT_NE(on_finish1
, &cond1
);
761 Context
*timer_task
= nullptr;
762 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task
);
765 io::DispatchResult dispatch_result
;
767 Context
*on_finish2
= &cond2
;
768 C_SaferCond on_dispatched
;
769 ASSERT_TRUE(mock_simple_scheduler_object_dispatch
.write(
770 0, 0, std::move(data
), mock_image_ctx
.snapc
, 0, {},
771 &object_dispatch_flags
, nullptr, &dispatch_result
, &on_finish2
,
773 ASSERT_EQ(dispatch_result
, io::DISPATCH_RESULT_COMPLETE
);
774 ASSERT_EQ(on_finish2
, &cond2
);
775 ASSERT_NE(timer_task
, nullptr);
777 expect_dispatch_delayed_requests(mock_image_ctx
, 0);
779 run_timer_task(timer_task
);
780 ASSERT_EQ(0, on_dispatched
.wait());
782 on_finish1
->complete(0);
783 ASSERT_EQ(0, cond1
.wait());
784 on_finish2
->complete(0);
785 ASSERT_EQ(0, cond2
.wait());
789 } // namespace librbd