]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_SimpleSchedulerObjectDispatch.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / test / librbd / io / test_mock_SimpleSchedulerObjectDispatch.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librbd/mock/MockImageCtx.h"
7 #include "test/librbd/mock/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"
13
14 namespace librbd {
15 namespace {
16
17 struct MockTestImageCtx : public MockImageCtx {
18 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
19 }
20 };
21
22 } // anonymous namespace
23
24 namespace io {
25
26 template <>
27 struct TypeTraits<MockTestImageCtx> {
28 typedef ::MockSafeTimer SafeTimer;
29 };
30
31 } // namespace io
32 } // namespace librbd
33
34 #include "librbd/io/SimpleSchedulerObjectDispatch.cc"
35
36 namespace librbd {
37 namespace io {
38
39 using ::testing::_;
40 using ::testing::InSequence;
41 using ::testing::Invoke;
42 using ::testing::Return;
43
44 struct TestMockIoSimpleSchedulerObjectDispatch : public TestMockFixture {
45 typedef SimpleSchedulerObjectDispatch<librbd::MockTestImageCtx> MockSimpleSchedulerObjectDispatch;
46
47 MockSafeTimer m_mock_timer;
48 ceph::mutex m_mock_timer_lock =
49 ceph::make_mutex("TestMockIoSimpleSchedulerObjectDispatch::Mutex");
50
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"));
54 }
55
56 void expect_get_object_name(MockTestImageCtx &mock_image_ctx,
57 uint64_t object_no) {
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)));
61 }
62
63 void expect_dispatch_delayed_requests(MockTestImageCtx &mock_image_ctx,
64 int r) {
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);
70 }));
71 }
72
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) {
76 delete timer_task;
77 return true;
78 }));
79 }
80
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) {
84 *timer_task = task;
85 return task;
86 }));
87 }
88
89 void expect_schedule_dispatch_delayed_requests(Context *current_task,
90 Context **new_task) {
91 if (current_task != nullptr) {
92 expect_cancel_timer_task(current_task);
93 }
94 if (new_task != nullptr) {
95 expect_add_timer_task(new_task);
96 }
97 }
98
99 void run_timer_task(Context *timer_task) {
100 std::lock_guard timer_locker{m_mock_timer_lock};
101 timer_task->complete(0);
102 }
103 };
104
105 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, Read) {
106 librbd::ImageCtx *ictx;
107 ASSERT_EQ(0, open_image(m_image_name, &ictx));
108
109 MockTestImageCtx mock_image_ctx(*ictx);
110 MockSimpleSchedulerObjectDispatch
111 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
112
113 C_SaferCond cond;
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());
121 }
122
123 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, Discard) {
124 librbd::ImageCtx *ictx;
125 ASSERT_EQ(0, open_image(m_image_name, &ictx));
126
127 MockTestImageCtx mock_image_ctx(*ictx);
128 MockSimpleSchedulerObjectDispatch
129 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
130
131 C_SaferCond cond;
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());
139 }
140
141 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, Write) {
142 librbd::ImageCtx *ictx;
143 ASSERT_EQ(0, open_image(m_image_name, &ictx));
144
145 MockTestImageCtx mock_image_ctx(*ictx);
146 MockSimpleSchedulerObjectDispatch
147 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
148
149 ceph::bufferlist data;
150 data.append("X");
151 int object_dispatch_flags = 0;
152 C_SaferCond cond;
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());
160 }
161
162 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, WriteSame) {
163 librbd::ImageCtx *ictx;
164 ASSERT_EQ(0, open_image(m_image_name, &ictx));
165
166 MockTestImageCtx mock_image_ctx(*ictx);
167 MockSimpleSchedulerObjectDispatch
168 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
169
170 io::LightweightBufferExtents buffer_extents;
171 ceph::bufferlist data;
172 C_SaferCond cond;
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,
177 nullptr));
178 ASSERT_NE(on_finish, &cond);
179 on_finish->complete(0);
180 ASSERT_EQ(0, cond.wait());
181 }
182
183 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, CompareAndWrite) {
184 librbd::ImageCtx *ictx;
185 ASSERT_EQ(0, open_image(m_image_name, &ictx));
186
187 MockTestImageCtx mock_image_ctx(*ictx);
188 MockSimpleSchedulerObjectDispatch
189 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
190
191 ceph::bufferlist cmp_data;
192 ceph::bufferlist write_data;
193 C_SaferCond cond;
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());
201 }
202
203 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, Flush) {
204 librbd::ImageCtx *ictx;
205 ASSERT_EQ(0, open_image(m_image_name, &ictx));
206
207 MockTestImageCtx mock_image_ctx(*ictx);
208 MockSimpleSchedulerObjectDispatch
209 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
210
211 C_SaferCond cond;
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());
218 }
219
220 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, WriteDelayed) {
221 librbd::ImageCtx *ictx;
222 ASSERT_EQ(0, open_image(m_image_name, &ictx));
223
224 MockTestImageCtx mock_image_ctx(*ictx);
225 MockSimpleSchedulerObjectDispatch
226 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
227
228 expect_get_object_name(mock_image_ctx, 0);
229
230 InSequence seq;
231
232 ceph::bufferlist data;
233 data.append("X");
234 int object_dispatch_flags = 0;
235 C_SaferCond cond1;
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);
241
242 Context *timer_task = nullptr;
243 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task);
244
245 io::DispatchResult dispatch_result;
246 C_SaferCond cond2;
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,
252 &on_dispatched));
253 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
254 ASSERT_EQ(on_finish2, &cond2);
255 ASSERT_NE(timer_task, nullptr);
256
257 expect_dispatch_delayed_requests(mock_image_ctx, 0);
258 expect_schedule_dispatch_delayed_requests(timer_task, nullptr);
259
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());
265 }
266
267 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, WriteDelayedFlush) {
268 librbd::ImageCtx *ictx;
269 ASSERT_EQ(0, open_image(m_image_name, &ictx));
270
271 MockTestImageCtx mock_image_ctx(*ictx);
272 MockSimpleSchedulerObjectDispatch
273 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
274
275 expect_get_object_name(mock_image_ctx, 0);
276
277 InSequence seq;
278
279 ceph::bufferlist data;
280 data.append("X");
281 int object_dispatch_flags = 0;
282 C_SaferCond cond1;
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);
288
289 Context *timer_task = nullptr;
290 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task);
291
292 io::DispatchResult dispatch_result;
293 C_SaferCond cond2;
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,
299 &on_dispatched));
300 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
301 ASSERT_EQ(on_finish2, &cond2);
302 ASSERT_NE(timer_task, nullptr);
303
304 expect_dispatch_delayed_requests(mock_image_ctx, 0);
305 expect_schedule_dispatch_delayed_requests(timer_task, nullptr);
306
307 C_SaferCond cond3;
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);
312
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());
320 }
321
322 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, WriteMerged) {
323 librbd::ImageCtx *ictx;
324 ASSERT_EQ(0, open_image(m_image_name, &ictx));
325
326 MockTestImageCtx mock_image_ctx(*ictx);
327 MockSimpleSchedulerObjectDispatch
328 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
329
330 expect_get_object_name(mock_image_ctx, 0);
331
332 InSequence seq;
333
334 ceph::bufferlist data;
335 data.append("X");
336 int object_dispatch_flags = 0;
337 C_SaferCond cond1;
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);
343
344 Context *timer_task = nullptr;
345 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task);
346
347 uint64_t object_off = 20;
348 data.clear();
349 data.append(std::string(10, 'A'));
350 io::DispatchResult dispatch_result;
351 C_SaferCond cond2;
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,
357 &on_dispatched2));
358 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
359 ASSERT_EQ(on_finish2, &cond2);
360 ASSERT_NE(timer_task, nullptr);
361
362 object_off = 0;
363 data.clear();
364 data.append(std::string(10, 'B'));
365 C_SaferCond cond3;
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,
371 &on_dispatched3));
372 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
373 ASSERT_EQ(on_finish3, &cond3);
374
375 object_off = 10;
376 data.clear();
377 data.append(std::string(10, 'C'));
378 C_SaferCond cond4;
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,
384 &on_dispatched4));
385 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
386 ASSERT_EQ(on_finish4, &cond4);
387
388 object_off = 30;
389 data.clear();
390 data.append(std::string(10, 'D'));
391 C_SaferCond cond5;
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,
397 &on_dispatched5));
398 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
399 ASSERT_EQ(on_finish5, &cond5);
400
401 object_off = 50;
402 data.clear();
403 data.append(std::string(10, 'E'));
404 C_SaferCond cond6;
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,
410 &on_dispatched6));
411 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
412 ASSERT_EQ(on_finish6, &cond6);
413
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);
419
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());
437 }
438
439 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, WriteNonSequential) {
440 librbd::ImageCtx *ictx;
441 ASSERT_EQ(0, open_image(m_image_name, &ictx));
442
443 MockTestImageCtx mock_image_ctx(*ictx);
444 MockSimpleSchedulerObjectDispatch
445 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
446
447 expect_get_object_name(mock_image_ctx, 0);
448
449 InSequence seq;
450
451 ceph::bufferlist data;
452 int object_dispatch_flags = 0;
453 C_SaferCond cond1;
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);
459
460 Context *timer_task = nullptr;
461 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task);
462
463 uint64_t object_off = 0;
464 data.clear();
465 data.append(std::string(10, 'X'));
466 io::DispatchResult dispatch_result;
467 C_SaferCond cond2;
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,
473 &on_dispatched2));
474 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
475 ASSERT_EQ(on_finish2, &cond2);
476 ASSERT_NE(timer_task, nullptr);
477
478 expect_dispatch_delayed_requests(mock_image_ctx, 0);
479 expect_schedule_dispatch_delayed_requests(timer_task, nullptr);
480
481 object_off = 5;
482 data.clear();
483 data.append(std::string(10, 'Y'));
484 C_SaferCond cond3;
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);
490
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());
498 }
499
500 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, Mixed) {
501 librbd::ImageCtx *ictx;
502 ASSERT_EQ(0, open_image(m_image_name, &ictx));
503
504 MockTestImageCtx mock_image_ctx(*ictx);
505 MockSimpleSchedulerObjectDispatch
506 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
507
508 expect_get_object_name(mock_image_ctx, 0);
509
510 InSequence seq;
511
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;
516 C_SaferCond cond1;
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);
522
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;
528 data.clear();
529 data.append(std::string(10, 'A'));
530 io::DispatchResult dispatch_result;
531 C_SaferCond cond2;
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,
537 &on_dispatched2));
538 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
539 ASSERT_EQ(on_finish2, &cond2);
540 ASSERT_NE(timer_task, nullptr);
541
542 // write (3) 10~10 (delayed)
543 // will be merged with write (2)
544 object_off = 10;
545 data.clear();
546 data.append(std::string(10, 'B'));
547 C_SaferCond cond3;
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,
553 &on_dispatched3));
554 ASSERT_EQ(on_finish3, &cond3);
555
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);
561 C_SaferCond cond4;
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());
569
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);
574 object_off = 20;
575 data.clear();
576 data.append(std::string(10, 'C'));
577 C_SaferCond cond5;
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,
583 &on_dispatched5));
584 ASSERT_EQ(on_finish5, &cond5);
585 ASSERT_NE(timer_task, nullptr);
586
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);
592 C_SaferCond cond6;
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());
599
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);
604 object_off = 30;
605 data.clear();
606 data.append(std::string(10, 'D'));
607 C_SaferCond cond7;
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,
613 &on_dispatched7));
614 ASSERT_EQ(on_finish7, &cond7);
615 ASSERT_NE(timer_task, nullptr);
616
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());
622
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());
628
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());
634
635 // writes (4) finishes ("dispatch delayed" is not called)
636 on_finish5->complete(0);
637 ASSERT_EQ(0, cond5.wait());
638
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());
647
648 // write (5) finishes ("dispatch delayed" is not called)
649 on_finish7->complete(0);
650 ASSERT_EQ(0, cond7.wait());
651 }
652
653 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, DispatchQueue) {
654 librbd::ImageCtx *ictx;
655 ASSERT_EQ(0, open_image(m_image_name, &ictx));
656
657 MockTestImageCtx mock_image_ctx(*ictx);
658 MockSimpleSchedulerObjectDispatch
659 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
660
661 expect_get_object_name(mock_image_ctx, 0);
662 expect_get_object_name(mock_image_ctx, 1);
663
664 InSequence seq;
665
666 // send 2 writes to object 0
667
668 uint64_t object_no = 0;
669 ceph::bufferlist data;
670 int object_dispatch_flags = 0;
671 C_SaferCond cond1;
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);
677
678 Context *timer_task = nullptr;
679 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task);
680
681 data.clear();
682 io::DispatchResult dispatch_result;
683 C_SaferCond cond2;
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,
689 &on_dispatched2));
690 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
691 ASSERT_EQ(on_finish2, &cond2);
692 ASSERT_NE(timer_task, nullptr);
693
694 // send 2 writes to object 1
695
696 object_no = 1;
697 data.clear();
698 C_SaferCond cond3;
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);
704
705 data.clear();
706 C_SaferCond cond4;
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,
712 &on_dispatched4));
713 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
714 ASSERT_EQ(on_finish4, &cond4);
715
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());
722
723 // finish write (2) to object 0
724 on_finish2->complete(0);
725 ASSERT_EQ(0, cond2.wait());
726
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());
733
734 // finish write (2) to object 1
735 on_finish4->complete(0);
736 ASSERT_EQ(0, cond4.wait());
737 }
738
739 TEST_F(TestMockIoSimpleSchedulerObjectDispatch, Timer) {
740 librbd::ImageCtx *ictx;
741 ASSERT_EQ(0, open_image(m_image_name, &ictx));
742
743 MockTestImageCtx mock_image_ctx(*ictx);
744 MockSimpleSchedulerObjectDispatch
745 mock_simple_scheduler_object_dispatch(&mock_image_ctx);
746
747 expect_get_object_name(mock_image_ctx, 0);
748 expect_op_work_queue(mock_image_ctx);
749
750 InSequence seq;
751
752 ceph::bufferlist data;
753 int object_dispatch_flags = 0;
754 C_SaferCond cond1;
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);
760
761 Context *timer_task = nullptr;
762 expect_schedule_dispatch_delayed_requests(nullptr, &timer_task);
763
764 data.clear();
765 io::DispatchResult dispatch_result;
766 C_SaferCond cond2;
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,
772 &on_dispatched));
773 ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
774 ASSERT_EQ(on_finish2, &cond2);
775 ASSERT_NE(timer_task, nullptr);
776
777 expect_dispatch_delayed_requests(mock_image_ctx, 0);
778
779 run_timer_task(timer_task);
780 ASSERT_EQ(0, on_dispatched.wait());
781
782 on_finish1->complete(0);
783 ASSERT_EQ(0, cond1.wait());
784 on_finish2->complete(0);
785 ASSERT_EQ(0, cond2.wait());
786 }
787
788 } // namespace io
789 } // namespace librbd