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/journal/mock/MockJournaler.h"
6 #include "test/librbd/test_support.h"
7 #include "test/librbd/mock/MockImageCtx.h"
8 #include "test/librbd/mock/MockJournalPolicy.h"
9 #include "test/librbd/mock/io/MockObjectDispatch.h"
10 #include "common/Cond.h"
11 #include "common/ceph_mutex.h"
12 #include "common/WorkQueue.h"
13 #include "cls/journal/cls_journal_types.h"
14 #include "journal/Journaler.h"
15 #include "librbd/Journal.h"
16 #include "librbd/Utils.h"
17 #include "librbd/io/AioCompletion.h"
18 #include "librbd/io/ObjectDispatchSpec.h"
19 #include "librbd/journal/Replay.h"
20 #include "librbd/journal/RemoveRequest.h"
21 #include "librbd/journal/CreateRequest.h"
22 #include "librbd/journal/ObjectDispatch.h"
23 #include "librbd/journal/OpenRequest.h"
24 #include "librbd/journal/Types.h"
25 #include "librbd/journal/TypeTraits.h"
26 #include "librbd/journal/PromoteRequest.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
31 #include <boost/scope_exit.hpp>
33 #define dout_context g_ceph_context
34 #define dout_subsys ceph_subsys_rbd
40 struct MockJournalImageCtx
: public MockImageCtx
{
41 MockJournalImageCtx(librbd::ImageCtx
& image_ctx
) : MockImageCtx(image_ctx
) {
45 } // anonymous namespace
50 struct TypeTraits
<MockJournalImageCtx
> {
51 typedef ::journal::MockJournalerProxy Journaler
;
52 typedef ::journal::MockFutureProxy Future
;
53 typedef ::journal::MockReplayEntryProxy ReplayEntry
;
57 static MockReplay
*s_instance
;
58 static MockReplay
&get_instance() {
59 ceph_assert(s_instance
!= nullptr);
67 MOCK_METHOD2(shut_down
, void(bool cancel_ops
, Context
*));
68 MOCK_METHOD2(decode
, int(bufferlist::const_iterator
*, EventEntry
*));
69 MOCK_METHOD3(process
, void(const EventEntry
&, Context
*, Context
*));
70 MOCK_METHOD2(replay_op_ready
, void(uint64_t, Context
*));
74 class Replay
<MockJournalImageCtx
> {
76 static Replay
*create(MockJournalImageCtx
&image_ctx
) {
80 void shut_down(bool cancel_ops
, Context
*on_finish
) {
81 MockReplay::get_instance().shut_down(cancel_ops
, on_finish
);
84 int decode(bufferlist::const_iterator
*it
, EventEntry
*event_entry
) {
85 return MockReplay::get_instance().decode(it
, event_entry
);
88 void process(const EventEntry
& event_entry
, Context
*on_ready
,
90 MockReplay::get_instance().process(event_entry
, on_ready
, on_commit
);
93 void replay_op_ready(uint64_t op_tid
, Context
*on_resume
) {
94 MockReplay::get_instance().replay_op_ready(op_tid
, on_resume
);
98 MockReplay
*MockReplay::s_instance
= nullptr;
101 static MockRemove
*s_instance
;
102 static MockRemove
&get_instance() {
103 ceph_assert(s_instance
!= nullptr);
111 MOCK_METHOD0(send
, void());
115 class RemoveRequest
<MockJournalImageCtx
> {
117 static RemoveRequest
*create(IoCtx
&ioctx
, const std::string
&imageid
,
118 const std::string
&client_id
,
119 ContextWQ
*op_work_queue
, Context
*on_finish
) {
120 return new RemoveRequest();
124 MockRemove::get_instance().send();
128 MockRemove
*MockRemove::s_instance
= nullptr;
131 static MockCreate
*s_instance
;
132 static MockCreate
&get_instance() {
133 ceph_assert(s_instance
!= nullptr);
141 MOCK_METHOD0(send
, void());
145 class CreateRequest
<MockJournalImageCtx
> {
147 static CreateRequest
*create(IoCtx
&ioctx
, const std::string
&imageid
,
148 uint8_t order
, uint8_t splay_width
,
149 const std::string
&object_pool
,
150 uint64_t tag_class
, TagData
&tag_data
,
151 const std::string
&client_id
,
152 ContextWQ
*op_work_queue
, Context
*on_finish
) {
153 return new CreateRequest();
157 MockCreate::get_instance().send();
161 MockCreate
*MockCreate::s_instance
= nullptr;
164 class OpenRequest
<MockJournalImageCtx
> {
168 static OpenRequest
*s_instance
;
169 static OpenRequest
*create(MockJournalImageCtx
*image_ctx
,
170 ::journal::MockJournalerProxy
*journaler
,
171 ceph::mutex
*lock
, journal::ImageClientMeta
*client_meta
,
172 uint64_t *tag_tid
, journal::TagData
*tag_data
,
173 Context
*on_finish
) {
174 ceph_assert(s_instance
!= nullptr);
175 s_instance
->tag_data
= tag_data
;
176 s_instance
->on_finish
= on_finish
;
184 MOCK_METHOD0(send
, void());
187 OpenRequest
<MockJournalImageCtx
> *OpenRequest
<MockJournalImageCtx
>::s_instance
= nullptr;
191 class PromoteRequest
<MockJournalImageCtx
> {
193 static PromoteRequest s_instance
;
194 static PromoteRequest
*create(MockJournalImageCtx
*image_ctx
, bool force
,
195 Context
*on_finish
) {
199 MOCK_METHOD0(send
, void());
202 PromoteRequest
<MockJournalImageCtx
> PromoteRequest
<MockJournalImageCtx
>::s_instance
;
205 struct ObjectDispatch
<MockJournalImageCtx
> : public io::MockObjectDispatch
{
206 static ObjectDispatch
* s_instance
;
208 static ObjectDispatch
* create(MockJournalImageCtx
* image_ctx
,
209 Journal
<MockJournalImageCtx
>* journal
) {
210 ceph_assert(s_instance
!= nullptr);
219 ObjectDispatch
<MockJournalImageCtx
>* ObjectDispatch
<MockJournalImageCtx
>::s_instance
= nullptr;
221 } // namespace journal
222 } // namespace librbd
224 // template definitions
225 #include "librbd/Journal.cc"
228 using ::testing::DoAll
;
229 using ::testing::InSequence
;
230 using ::testing::Invoke
;
231 using ::testing::InvokeWithoutArgs
;
232 using ::testing::MatcherCast
;
233 using ::testing::Return
;
234 using ::testing::SaveArg
;
235 using ::testing::SetArgPointee
;
236 using ::testing::WithArg
;
237 using namespace std::placeholders
;
239 ACTION_P2(StartReplay
, wq
, ctx
) {
245 class TestMockJournal
: public TestMockFixture
{
247 typedef journal::MockReplay MockJournalReplay
;
248 typedef Journal
<MockJournalImageCtx
> MockJournal
;
249 typedef journal::OpenRequest
<MockJournalImageCtx
> MockJournalOpenRequest
;
250 typedef journal::ObjectDispatch
<MockJournalImageCtx
> MockObjectDispatch
;
251 typedef std::function
<void(::journal::ReplayHandler
*)> ReplayAction
;
252 typedef std::list
<Context
*> Contexts
;
254 TestMockJournal() = default;
255 ~TestMockJournal() override
{
256 ceph_assert(m_commit_contexts
.empty());
259 ceph::mutex m_lock
= ceph::make_mutex("lock");
260 ceph::condition_variable m_cond
;
261 Contexts m_commit_contexts
;
263 struct C_ReplayAction
: public Context
{
264 ::journal::ReplayHandler
**replay_handler
;
265 ReplayAction replay_action
;
267 C_ReplayAction(::journal::ReplayHandler
**replay_handler
,
268 const ReplayAction
&replay_action
)
269 : replay_handler(replay_handler
), replay_action(replay_action
) {
271 void finish(int r
) override
{
273 replay_action(*replay_handler
);
278 void expect_construct_journaler(::journal::MockJournaler
&mock_journaler
) {
279 EXPECT_CALL(mock_journaler
, construct());
282 void expect_open_journaler(MockImageCtx
&mock_image_ctx
,
283 ::journal::MockJournaler
&mock_journaler
,
284 MockJournalOpenRequest
&mock_open_request
,
285 bool primary
, int r
) {
286 EXPECT_CALL(mock_journaler
, add_listener(_
))
287 .WillOnce(SaveArg
<0>(&m_listener
));
288 EXPECT_CALL(mock_open_request
, send())
289 .WillOnce(DoAll(Invoke([&mock_open_request
, primary
]() {
291 mock_open_request
.tag_data
->mirror_uuid
= "remote mirror uuid";
294 FinishRequest(&mock_open_request
, r
,
298 void expect_shut_down_journaler(::journal::MockJournaler
&mock_journaler
) {
299 EXPECT_CALL(mock_journaler
, remove_listener(_
));
300 EXPECT_CALL(mock_journaler
, shut_down(_
))
301 .WillOnce(CompleteContext(0, static_cast<asio::ContextWQ
*>(NULL
)));
304 void expect_register_dispatch(MockImageCtx
& mock_image_ctx
,
305 MockObjectDispatch
& mock_object_dispatch
) {
306 EXPECT_CALL(*mock_image_ctx
.io_object_dispatcher
,
307 register_dispatch(&mock_object_dispatch
));
310 void expect_shut_down_dispatch(MockImageCtx
& mock_image_ctx
) {
311 EXPECT_CALL(*mock_image_ctx
.io_object_dispatcher
,
312 shut_down_dispatch(io::OBJECT_DISPATCH_LAYER_JOURNAL
, _
))
313 .WillOnce(WithArg
<1>(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
)));
316 void expect_get_max_append_size(::journal::MockJournaler
&mock_journaler
,
318 EXPECT_CALL(mock_journaler
, get_max_append_size())
319 .WillOnce(Return(max_size
));
322 void expect_get_journaler_cached_client(::journal::MockJournaler
&mock_journaler
,
323 const journal::ImageClientMeta
&client_meta
,
325 journal::ClientData client_data
;
326 client_data
.client_meta
= client_meta
;
328 cls::journal::Client client
;
329 encode(client_data
, client
.data
);
331 EXPECT_CALL(mock_journaler
, get_cached_client("", _
))
332 .WillOnce(DoAll(SetArgPointee
<1>(client
),
336 void expect_get_journaler_tags(MockImageCtx
&mock_image_ctx
,
337 ::journal::MockJournaler
&mock_journaler
,
338 uint64_t start_after_tag_tid
,
339 ::journal::Journaler::Tags
&&tags
, int r
) {
340 EXPECT_CALL(mock_journaler
, get_tags(start_after_tag_tid
, 0, _
, _
))
341 .WillOnce(DoAll(SetArgPointee
<2>(tags
),
342 WithArg
<3>(CompleteContext(r
, mock_image_ctx
.image_ctx
->op_work_queue
))));
345 void expect_start_replay(MockJournalImageCtx
&mock_image_ctx
,
346 ::journal::MockJournaler
&mock_journaler
,
347 const ReplayAction
&action
) {
348 EXPECT_CALL(mock_journaler
, start_replay(_
))
349 .WillOnce(DoAll(SaveArg
<0>(&m_replay_handler
),
350 StartReplay(mock_image_ctx
.image_ctx
->op_work_queue
,
351 new C_ReplayAction(&m_replay_handler
,
355 void expect_stop_replay(::journal::MockJournaler
&mock_journaler
) {
356 EXPECT_CALL(mock_journaler
, stop_replay(_
))
357 .WillOnce(CompleteContext(0, static_cast<asio::ContextWQ
*>(NULL
)));
360 void expect_shut_down_replay(MockJournalImageCtx
&mock_image_ctx
,
361 MockJournalReplay
&mock_journal_replay
, int r
,
362 bool cancel_ops
= false) {
363 EXPECT_CALL(mock_journal_replay
, shut_down(cancel_ops
, _
))
364 .WillOnce(WithArg
<1>(Invoke([this, &mock_image_ctx
, r
](Context
*on_flush
) {
365 this->commit_replay(mock_image_ctx
, on_flush
, r
);})));
368 void expect_get_data(::journal::MockReplayEntry
&mock_replay_entry
) {
369 EXPECT_CALL(mock_replay_entry
, get_data())
370 .WillOnce(Return(bufferlist()));
373 void expect_try_pop_front(MockJournalImageCtx
&mock_image_ctx
,
374 ::journal::MockJournaler
&mock_journaler
,
375 bool entries_available
,
376 ::journal::MockReplayEntry
&mock_replay_entry
,
377 const ReplayAction
&action
= {}) {
378 EXPECT_CALL(mock_journaler
, try_pop_front(_
))
379 .WillOnce(DoAll(SetArgPointee
<0>(::journal::MockReplayEntryProxy()),
380 StartReplay(mock_image_ctx
.image_ctx
->op_work_queue
,
381 new C_ReplayAction(&m_replay_handler
,
383 Return(entries_available
)));
384 if (entries_available
) {
385 expect_get_data(mock_replay_entry
);
389 void expect_replay_process(MockJournalReplay
&mock_journal_replay
) {
390 EXPECT_CALL(mock_journal_replay
, decode(_
, _
))
391 .WillOnce(Return(0));
392 EXPECT_CALL(mock_journal_replay
, process(_
, _
, _
))
393 .WillOnce(DoAll(WithArg
<1>(CompleteContext(0, static_cast<asio::ContextWQ
*>(NULL
))),
394 WithArg
<2>(Invoke(this, &TestMockJournal::save_commit_context
))));
397 void expect_start_append(::journal::MockJournaler
&mock_journaler
) {
398 EXPECT_CALL(mock_journaler
, start_append(_
));
401 void expect_set_append_batch_options(MockJournalImageCtx
&mock_image_ctx
,
402 ::journal::MockJournaler
&mock_journaler
,
404 if (mock_image_ctx
.image_ctx
->config
.get_val
<bool>("rbd_journal_object_writethrough_until_flush") ==
406 EXPECT_CALL(mock_journaler
, set_append_batch_options(_
, _
, _
));
410 void expect_stop_append(::journal::MockJournaler
&mock_journaler
, int r
) {
411 EXPECT_CALL(mock_journaler
, stop_append(_
))
412 .WillOnce(CompleteContext(r
, static_cast<asio::ContextWQ
*>(NULL
)));
415 void expect_committed(::journal::MockJournaler
&mock_journaler
,
417 EXPECT_CALL(mock_journaler
, committed(MatcherCast
<const ::journal::MockReplayEntryProxy
&>(_
)))
421 void expect_append_journaler(::journal::MockJournaler
&mock_journaler
) {
422 EXPECT_CALL(mock_journaler
, append(_
, _
))
423 .WillOnce(Return(::journal::MockFutureProxy()));
426 void expect_wait_future(::journal::MockFuture
&mock_future
,
428 EXPECT_CALL(mock_future
, wait(_
))
429 .WillOnce(SaveArg
<0>(on_safe
));
432 void expect_future_committed(::journal::MockJournaler
&mock_journaler
) {
433 EXPECT_CALL(mock_journaler
, committed(MatcherCast
<const ::journal::MockFutureProxy
&>(_
)));
436 void expect_future_is_valid(::journal::MockFuture
&mock_future
) {
437 EXPECT_CALL(mock_future
, is_valid()).WillOnce(Return(false));
440 void expect_flush_commit_position(::journal::MockJournaler
&mock_journaler
) {
441 EXPECT_CALL(mock_journaler
, flush_commit_position(_
))
442 .WillOnce(CompleteContext(0, static_cast<asio::ContextWQ
*>(NULL
)));
445 int when_open(MockJournal
*mock_journal
) {
447 mock_journal
->open(&ctx
);
451 int when_close(MockJournal
*mock_journal
) {
453 mock_journal
->close(&ctx
);
457 uint64_t when_append_write_event(MockJournalImageCtx
&mock_image_ctx
,
458 MockJournal
*mock_journal
, uint64_t length
) {
460 bl
.append_zero(length
);
462 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
463 return mock_journal
->append_write_event(0, length
, bl
, false);
466 uint64_t when_append_io_event(MockJournalImageCtx
&mock_image_ctx
,
467 MockJournal
*mock_journal
,
468 int filter_ret_val
) {
469 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
470 return mock_journal
->append_io_event(
471 journal::EventEntry
{journal::AioFlushEvent
{}}, 0, 0, false,
475 void save_commit_context(Context
*ctx
) {
476 std::lock_guard locker
{m_lock
};
477 m_commit_contexts
.push_back(ctx
);
482 std::lock_guard locker
{m_lock
};
486 void commit_replay(MockJournalImageCtx
&mock_image_ctx
, Context
*on_flush
,
488 Contexts commit_contexts
;
489 std::swap(commit_contexts
, m_commit_contexts
);
491 derr
<< "SHUT DOWN REPLAY START" << dendl
;
492 for (auto ctx
: commit_contexts
) {
493 mock_image_ctx
.image_ctx
->op_work_queue
->queue(ctx
, r
);
496 on_flush
= new LambdaContext([on_flush
](int r
) {
497 derr
<< "FLUSH START" << dendl
;
498 on_flush
->complete(r
);
499 derr
<< "FLUSH FINISH" << dendl
;
501 mock_image_ctx
.image_ctx
->op_work_queue
->queue(on_flush
, 0);
502 derr
<< "SHUT DOWN REPLAY FINISH" << dendl
;
505 void open_journal(MockJournalImageCtx
&mock_image_ctx
,
506 MockJournal
*mock_journal
,
507 MockObjectDispatch
& mock_object_dispatch
,
508 ::journal::MockJournaler
&mock_journaler
,
509 MockJournalOpenRequest
&mock_open_request
,
510 bool primary
= true) {
511 expect_op_work_queue(mock_image_ctx
);
514 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
515 expect_construct_journaler(mock_journaler
);
516 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
518 expect_get_max_append_size(mock_journaler
, 1 << 16);
520 mock_image_ctx
, mock_journaler
,
521 std::bind(&invoke_replay_complete
, _1
, 0));
523 MockJournalReplay mock_journal_replay
;
524 expect_stop_replay(mock_journaler
);
525 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
526 expect_committed(mock_journaler
, 0);
527 expect_flush_commit_position(mock_journaler
);
528 expect_start_append(mock_journaler
);
529 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
530 ASSERT_EQ(0, when_open(mock_journal
));
533 void close_journal(MockJournalImageCtx
& mock_image_ctx
,
534 MockJournal
*mock_journal
,
535 ::journal::MockJournaler
&mock_journaler
) {
536 expect_stop_append(mock_journaler
, 0);
537 expect_shut_down_dispatch(mock_image_ctx
);
538 ASSERT_EQ(0, when_close(mock_journal
));
541 static void invoke_replay_ready(::journal::ReplayHandler
*handler
) {
542 handler
->handle_entries_available();
545 static void invoke_replay_complete(::journal::ReplayHandler
*handler
, int r
) {
546 handler
->handle_complete(r
);
549 ::journal::ReplayHandler
*m_replay_handler
= nullptr;
550 ::journal::JournalMetadataListener
*m_listener
= nullptr;
553 TEST_F(TestMockJournal
, StateTransitions
) {
554 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
556 librbd::ImageCtx
*ictx
;
557 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
559 MockJournalImageCtx
mock_image_ctx(*ictx
);
560 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
561 expect_op_work_queue(mock_image_ctx
);
563 BOOST_SCOPE_EXIT(&mock_journal
) {
565 } BOOST_SCOPE_EXIT_END
569 MockObjectDispatch mock_object_dispatch
;
570 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
572 ::journal::MockJournaler mock_journaler
;
573 MockJournalOpenRequest mock_open_request
;
574 expect_construct_journaler(mock_journaler
);
575 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
577 expect_get_max_append_size(mock_journaler
, 1 << 16);
579 mock_image_ctx
, mock_journaler
,
580 std::bind(&invoke_replay_ready
, _1
));
582 ::journal::MockReplayEntry mock_replay_entry
;
583 MockJournalReplay mock_journal_replay
;
584 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
585 expect_replay_process(mock_journal_replay
);
586 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
587 expect_replay_process(mock_journal_replay
);
588 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false, mock_replay_entry
,
589 std::bind(&invoke_replay_ready
, _1
));
590 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
591 expect_replay_process(mock_journal_replay
);
592 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false, mock_replay_entry
,
593 std::bind(&invoke_replay_complete
, _1
, 0));
595 expect_stop_replay(mock_journaler
);
596 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
597 expect_committed(mock_journaler
, 3);
598 expect_flush_commit_position(mock_journaler
);
600 expect_start_append(mock_journaler
);
601 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
603 ASSERT_EQ(0, when_open(mock_journal
));
605 expect_stop_append(mock_journaler
, 0);
606 expect_shut_down_journaler(mock_journaler
);
607 expect_shut_down_dispatch(mock_image_ctx
);
608 ASSERT_EQ(0, when_close(mock_journal
));
611 TEST_F(TestMockJournal
, InitError
) {
612 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
614 librbd::ImageCtx
*ictx
;
615 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
617 MockJournalImageCtx
mock_image_ctx(*ictx
);
618 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
619 expect_op_work_queue(mock_image_ctx
);
621 BOOST_SCOPE_EXIT(&mock_journal
) {
623 } BOOST_SCOPE_EXIT_END
627 MockObjectDispatch mock_object_dispatch
;
628 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
630 ::journal::MockJournaler mock_journaler
;
631 MockJournalOpenRequest mock_open_request
;
632 expect_construct_journaler(mock_journaler
);
633 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
635 expect_shut_down_journaler(mock_journaler
);
636 ASSERT_EQ(-EINVAL
, when_open(mock_journal
));
639 TEST_F(TestMockJournal
, ReplayCompleteError
) {
640 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
642 librbd::ImageCtx
*ictx
;
643 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
645 MockJournalImageCtx
mock_image_ctx(*ictx
);
646 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
647 expect_op_work_queue(mock_image_ctx
);
649 BOOST_SCOPE_EXIT(&mock_journal
) {
651 } BOOST_SCOPE_EXIT_END
655 MockObjectDispatch mock_object_dispatch
;
656 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
658 ::journal::MockJournaler mock_journaler
;
659 MockJournalOpenRequest mock_open_request
;
660 expect_construct_journaler(mock_journaler
);
661 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
663 expect_get_max_append_size(mock_journaler
, 1 << 16);
665 mock_image_ctx
, mock_journaler
,
666 std::bind(&invoke_replay_complete
, _1
, -EINVAL
));
668 MockJournalReplay mock_journal_replay
;
669 expect_stop_replay(mock_journaler
);
670 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0, true);
671 expect_flush_commit_position(mock_journaler
);
672 expect_shut_down_journaler(mock_journaler
);
674 // replay failure should result in replay-restart
675 expect_construct_journaler(mock_journaler
);
676 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
678 expect_get_max_append_size(mock_journaler
, 1 << 16);
680 mock_image_ctx
, mock_journaler
,
681 std::bind(&invoke_replay_complete
, _1
, 0));
683 expect_stop_replay(mock_journaler
);
684 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
685 expect_flush_commit_position(mock_journaler
);
686 expect_start_append(mock_journaler
);
687 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
688 ASSERT_EQ(0, when_open(mock_journal
));
690 expect_stop_append(mock_journaler
, 0);
691 expect_shut_down_journaler(mock_journaler
);
692 expect_shut_down_dispatch(mock_image_ctx
);
693 ASSERT_EQ(0, when_close(mock_journal
));
696 TEST_F(TestMockJournal
, FlushReplayError
) {
697 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
699 librbd::ImageCtx
*ictx
;
700 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
702 MockJournalImageCtx
mock_image_ctx(*ictx
);
703 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
704 expect_op_work_queue(mock_image_ctx
);
706 BOOST_SCOPE_EXIT(&mock_journal
) {
708 } BOOST_SCOPE_EXIT_END
712 MockObjectDispatch mock_object_dispatch
;
713 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
715 ::journal::MockJournaler mock_journaler
;
716 MockJournalOpenRequest mock_open_request
;
717 expect_construct_journaler(mock_journaler
);
718 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
720 expect_get_max_append_size(mock_journaler
, 1 << 16);
722 mock_image_ctx
, mock_journaler
,
723 std::bind(&invoke_replay_ready
, _1
));
725 ::journal::MockReplayEntry mock_replay_entry
;
726 MockJournalReplay mock_journal_replay
;
727 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
728 expect_replay_process(mock_journal_replay
);
729 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false, mock_replay_entry
,
730 std::bind(&invoke_replay_complete
, _1
, 0));
731 expect_stop_replay(mock_journaler
);
732 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, -EINVAL
);
733 expect_flush_commit_position(mock_journaler
);
734 expect_shut_down_journaler(mock_journaler
);
736 // replay flush failure should result in replay-restart
737 expect_construct_journaler(mock_journaler
);
738 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
740 expect_get_max_append_size(mock_journaler
, 1 << 16);
742 mock_image_ctx
, mock_journaler
,
743 std::bind(&invoke_replay_complete
, _1
, 0));
745 expect_stop_replay(mock_journaler
);
746 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
747 expect_flush_commit_position(mock_journaler
);
748 expect_start_append(mock_journaler
);
749 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
750 ASSERT_EQ(0, when_open(mock_journal
));
752 expect_stop_append(mock_journaler
, 0);
753 expect_shut_down_journaler(mock_journaler
);
754 expect_shut_down_dispatch(mock_image_ctx
);
755 ASSERT_EQ(0, when_close(mock_journal
));
758 TEST_F(TestMockJournal
, CorruptEntry
) {
759 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
761 librbd::ImageCtx
*ictx
;
762 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
764 MockJournalImageCtx
mock_image_ctx(*ictx
);
765 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
766 expect_op_work_queue(mock_image_ctx
);
768 BOOST_SCOPE_EXIT(&mock_journal
) {
770 } BOOST_SCOPE_EXIT_END
774 MockObjectDispatch mock_object_dispatch
;
775 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
777 ::journal::MockJournaler mock_journaler
;
778 MockJournalOpenRequest mock_open_request
;
779 expect_construct_journaler(mock_journaler
);
780 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
782 expect_get_max_append_size(mock_journaler
, 1 << 16);
784 mock_image_ctx
, mock_journaler
,
785 std::bind(&invoke_replay_ready
, _1
));
787 ::journal::MockReplayEntry mock_replay_entry
;
788 MockJournalReplay mock_journal_replay
;
789 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
790 EXPECT_CALL(mock_journal_replay
, decode(_
, _
)).WillOnce(Return(-EBADMSG
));
791 expect_stop_replay(mock_journaler
);
792 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0, true);
793 expect_flush_commit_position(mock_journaler
);
794 expect_shut_down_journaler(mock_journaler
);
796 // replay failure should result in replay-restart
797 expect_construct_journaler(mock_journaler
);
798 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
800 expect_get_max_append_size(mock_journaler
, 1 << 16);
802 mock_image_ctx
, mock_journaler
,
803 std::bind(&invoke_replay_complete
, _1
, 0));
804 expect_stop_replay(mock_journaler
);
805 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
806 expect_flush_commit_position(mock_journaler
);
807 expect_start_append(mock_journaler
);
808 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
809 ASSERT_EQ(0, when_open(mock_journal
));
811 expect_stop_append(mock_journaler
, -EINVAL
);
812 expect_shut_down_journaler(mock_journaler
);
813 expect_shut_down_dispatch(mock_image_ctx
);
814 ASSERT_EQ(-EINVAL
, when_close(mock_journal
));
817 TEST_F(TestMockJournal
, StopError
) {
818 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
820 librbd::ImageCtx
*ictx
;
821 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
823 MockJournalImageCtx
mock_image_ctx(*ictx
);
824 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
825 expect_op_work_queue(mock_image_ctx
);
827 BOOST_SCOPE_EXIT(&mock_journal
) {
829 } BOOST_SCOPE_EXIT_END
833 MockObjectDispatch mock_object_dispatch
;
834 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
836 ::journal::MockJournaler mock_journaler
;
837 MockJournalOpenRequest mock_open_request
;
838 expect_construct_journaler(mock_journaler
);
839 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
841 expect_get_max_append_size(mock_journaler
, 1 << 16);
843 mock_image_ctx
, mock_journaler
,
844 std::bind(&invoke_replay_complete
, _1
, 0));
846 MockJournalReplay mock_journal_replay
;
847 expect_stop_replay(mock_journaler
);
848 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
849 expect_flush_commit_position(mock_journaler
);
850 expect_start_append(mock_journaler
);
851 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
852 ASSERT_EQ(0, when_open(mock_journal
));
854 expect_stop_append(mock_journaler
, -EINVAL
);
855 expect_shut_down_journaler(mock_journaler
);
856 expect_shut_down_dispatch(mock_image_ctx
);
857 ASSERT_EQ(-EINVAL
, when_close(mock_journal
));
860 TEST_F(TestMockJournal
, ReplayOnDiskPreFlushError
) {
861 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
863 librbd::ImageCtx
*ictx
;
864 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
866 MockJournalImageCtx
mock_image_ctx(*ictx
);
867 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
868 expect_op_work_queue(mock_image_ctx
);
870 BOOST_SCOPE_EXIT(&mock_journal
) {
872 } BOOST_SCOPE_EXIT_END
875 MockObjectDispatch mock_object_dispatch
;
876 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
878 ::journal::MockJournaler mock_journaler
;
879 MockJournalOpenRequest mock_open_request
;
880 expect_construct_journaler(mock_journaler
);
881 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
883 expect_get_max_append_size(mock_journaler
, 1 << 16);
886 mock_image_ctx
, mock_journaler
,
887 std::bind(&invoke_replay_ready
, _1
));
889 ::journal::MockReplayEntry mock_replay_entry
;
890 MockJournalReplay mock_journal_replay
;
891 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
893 EXPECT_CALL(mock_journal_replay
, decode(_
, _
))
894 .WillOnce(Return(0));
896 EXPECT_CALL(mock_journal_replay
, process(_
, _
, _
))
897 .WillOnce(DoAll(SaveArg
<1>(&on_ready
),
898 WithArg
<2>(Invoke(this, &TestMockJournal::save_commit_context
))));
900 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false,
902 expect_stop_replay(mock_journaler
);
903 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0, true);
904 expect_flush_commit_position(mock_journaler
);
905 expect_shut_down_journaler(mock_journaler
);
907 // replay write-to-disk failure should result in replay-restart
908 expect_construct_journaler(mock_journaler
);
909 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
911 expect_get_max_append_size(mock_journaler
, 1 << 16);
913 mock_image_ctx
, mock_journaler
, {
914 std::bind(&invoke_replay_complete
, _1
, 0)
917 expect_stop_replay(mock_journaler
);
918 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
919 expect_flush_commit_position(mock_journaler
);
920 expect_start_append(mock_journaler
);
921 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
924 mock_journal
->open(&ctx
);
926 // wait for the process callback
928 std::unique_lock locker
{m_lock
};
929 m_cond
.wait(locker
, [this] { return !m_commit_contexts
.empty(); });
931 on_ready
->complete(0);
933 // inject RADOS error in the middle of replay
934 Context
*on_safe
= m_commit_contexts
.front();
935 m_commit_contexts
.clear();
936 on_safe
->complete(-EINVAL
);
938 // flag the replay as complete
939 m_replay_handler
->handle_complete(0);
941 ASSERT_EQ(0, ctx
.wait());
943 expect_stop_append(mock_journaler
, 0);
944 expect_shut_down_journaler(mock_journaler
);
945 expect_shut_down_dispatch(mock_image_ctx
);
946 ASSERT_EQ(0, when_close(mock_journal
));
949 TEST_F(TestMockJournal
, ReplayOnDiskPostFlushError
) {
950 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
952 librbd::ImageCtx
*ictx
;
953 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
955 MockJournalImageCtx
mock_image_ctx(*ictx
);
956 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
957 expect_op_work_queue(mock_image_ctx
);
959 BOOST_SCOPE_EXIT(&mock_journal
) {
961 } BOOST_SCOPE_EXIT_END
965 MockObjectDispatch mock_object_dispatch
;
966 expect_register_dispatch(mock_image_ctx
, mock_object_dispatch
);
968 ::journal::MockJournaler mock_journaler
;
969 MockJournalOpenRequest mock_open_request
;
970 expect_construct_journaler(mock_journaler
);
971 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
973 expect_get_max_append_size(mock_journaler
, 1 << 16);
975 mock_image_ctx
, mock_journaler
,
976 std::bind(&invoke_replay_ready
, _1
));
978 ::journal::MockReplayEntry mock_replay_entry
;
979 MockJournalReplay mock_journal_replay
;
980 expect_try_pop_front(mock_image_ctx
, mock_journaler
, true, mock_replay_entry
);
981 expect_replay_process(mock_journal_replay
);
982 expect_try_pop_front(mock_image_ctx
, mock_journaler
, false, mock_replay_entry
,
983 std::bind(&invoke_replay_complete
, _1
, 0));
984 expect_stop_replay(mock_journaler
);
986 Context
*on_flush
= nullptr;
987 EXPECT_CALL(mock_journal_replay
, shut_down(false, _
))
988 .WillOnce(DoAll(SaveArg
<1>(&on_flush
),
989 InvokeWithoutArgs(this, &TestMockJournal::wake_up
)));
990 expect_flush_commit_position(mock_journaler
);
992 // replay write-to-disk failure should result in replay-restart
993 expect_shut_down_journaler(mock_journaler
);
994 expect_construct_journaler(mock_journaler
);
995 expect_open_journaler(mock_image_ctx
, mock_journaler
, mock_open_request
,
997 expect_get_max_append_size(mock_journaler
, 1 << 16);
999 mock_image_ctx
, mock_journaler
,
1000 std::bind(&invoke_replay_complete
, _1
, 0));
1002 expect_stop_replay(mock_journaler
);
1003 expect_shut_down_replay(mock_image_ctx
, mock_journal_replay
, 0);
1004 expect_flush_commit_position(mock_journaler
);
1005 expect_start_append(mock_journaler
);
1006 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
1009 mock_journal
->open(&ctx
);
1011 // proceed with the flush
1013 // wait for on_flush callback
1014 std::unique_lock locker
{m_lock
};
1015 m_cond
.wait(locker
, [&] {return on_flush
!= nullptr;});
1019 // wait for the on_safe process callback
1020 std::unique_lock locker
{m_lock
};
1021 m_cond
.wait(locker
, [this] {return !m_commit_contexts
.empty();});
1023 m_commit_contexts
.front()->complete(-EINVAL
);
1024 m_commit_contexts
.clear();
1025 on_flush
->complete(0);
1027 ASSERT_EQ(0, ctx
.wait());
1029 expect_stop_append(mock_journaler
, 0);
1030 expect_shut_down_journaler(mock_journaler
);
1031 expect_shut_down_dispatch(mock_image_ctx
);
1032 ASSERT_EQ(0, when_close(mock_journal
));
1035 TEST_F(TestMockJournal
, EventAndIOCommitOrder
) {
1036 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1038 librbd::ImageCtx
*ictx
;
1039 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1041 MockJournalImageCtx
mock_image_ctx(*ictx
);
1042 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1043 MockObjectDispatch mock_object_dispatch
;
1044 ::journal::MockJournaler mock_journaler
;
1045 MockJournalOpenRequest mock_open_request
;
1046 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1047 mock_journaler
, mock_open_request
);
1048 BOOST_SCOPE_EXIT_ALL(&) {
1049 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1050 mock_journal
->put();
1053 ::journal::MockFuture mock_future
;
1054 Context
*on_journal_safe1
;
1055 expect_append_journaler(mock_journaler
);
1056 expect_wait_future(mock_future
, &on_journal_safe1
);
1057 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
, 0));
1058 mock_journal
->get_work_queue()->drain();
1060 Context
*on_journal_safe2
;
1061 expect_append_journaler(mock_journaler
);
1062 expect_wait_future(mock_future
, &on_journal_safe2
);
1063 ASSERT_EQ(2U, when_append_io_event(mock_image_ctx
, mock_journal
, 0));
1064 mock_journal
->get_work_queue()->drain();
1066 // commit journal event followed by IO event (standard)
1067 on_journal_safe1
->complete(0);
1068 ictx
->op_work_queue
->drain();
1069 expect_future_committed(mock_journaler
);
1070 mock_journal
->commit_io_event(1U, 0);
1072 // commit IO event followed by journal event (cache overwrite)
1073 mock_journal
->commit_io_event(2U, 0);
1074 expect_future_committed(mock_journaler
);
1076 C_SaferCond event_ctx
;
1077 mock_journal
->wait_event(2U, &event_ctx
);
1078 on_journal_safe2
->complete(0);
1079 ictx
->op_work_queue
->drain();
1080 ASSERT_EQ(0, event_ctx
.wait());
1082 expect_shut_down_journaler(mock_journaler
);
1085 TEST_F(TestMockJournal
, AppendWriteEvent
) {
1086 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1088 librbd::ImageCtx
*ictx
;
1089 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1091 MockJournalImageCtx
mock_image_ctx(*ictx
);
1092 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1093 MockObjectDispatch mock_object_dispatch
;
1094 ::journal::MockJournaler mock_journaler
;
1095 MockJournalOpenRequest mock_open_request
;
1096 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1097 mock_journaler
, mock_open_request
);
1098 BOOST_SCOPE_EXIT_ALL(&) {
1099 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1100 mock_journal
->put();
1105 ::journal::MockFuture mock_future
;
1106 Context
*on_journal_safe
= nullptr;
1107 expect_append_journaler(mock_journaler
);
1108 expect_append_journaler(mock_journaler
);
1109 expect_append_journaler(mock_journaler
);
1110 expect_wait_future(mock_future
, &on_journal_safe
);
1111 ASSERT_EQ(1U, when_append_write_event(mock_image_ctx
, mock_journal
, 1 << 17));
1112 mock_journal
->get_work_queue()->drain();
1114 on_journal_safe
->complete(0);
1115 C_SaferCond event_ctx
;
1116 mock_journal
->wait_event(1U, &event_ctx
);
1117 ASSERT_EQ(0, event_ctx
.wait());
1119 expect_future_committed(mock_journaler
);
1120 expect_future_committed(mock_journaler
);
1121 expect_future_committed(mock_journaler
);
1122 mock_journal
->commit_io_event(1U, 0);
1123 ictx
->op_work_queue
->drain();
1125 expect_shut_down_journaler(mock_journaler
);
1128 TEST_F(TestMockJournal
, EventCommitError
) {
1129 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1131 librbd::ImageCtx
*ictx
;
1132 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1134 MockJournalImageCtx
mock_image_ctx(*ictx
);
1135 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1136 MockObjectDispatch mock_object_dispatch
;
1137 ::journal::MockJournaler mock_journaler
;
1138 MockJournalOpenRequest mock_open_request
;
1139 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1140 mock_journaler
, mock_open_request
);
1141 BOOST_SCOPE_EXIT_ALL(&) {
1142 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1143 mock_journal
->put();
1146 ::journal::MockFuture mock_future
;
1147 Context
*on_journal_safe
;
1148 expect_append_journaler(mock_journaler
);
1149 expect_wait_future(mock_future
, &on_journal_safe
);
1150 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
, 0));
1151 mock_journal
->get_work_queue()->drain();
1153 // commit the event in the journal w/o waiting writeback
1154 expect_future_committed(mock_journaler
);
1155 C_SaferCond object_request_ctx
;
1156 mock_journal
->wait_event(1U, &object_request_ctx
);
1157 on_journal_safe
->complete(-EINVAL
);
1158 ASSERT_EQ(-EINVAL
, object_request_ctx
.wait());
1160 // cache should receive the error after attempting writeback
1161 expect_future_is_valid(mock_future
);
1162 C_SaferCond flush_ctx
;
1163 mock_journal
->flush_event(1U, &flush_ctx
);
1164 ASSERT_EQ(-EINVAL
, flush_ctx
.wait());
1166 expect_shut_down_journaler(mock_journaler
);
1169 TEST_F(TestMockJournal
, EventCommitErrorWithPendingWriteback
) {
1170 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1172 librbd::ImageCtx
*ictx
;
1173 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1175 MockJournalImageCtx
mock_image_ctx(*ictx
);
1176 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1177 MockObjectDispatch mock_object_dispatch
;
1178 ::journal::MockJournaler mock_journaler
;
1179 MockJournalOpenRequest mock_open_request
;
1180 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1181 mock_journaler
, mock_open_request
);
1182 BOOST_SCOPE_EXIT_ALL(&) {
1183 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1184 mock_journal
->put();
1187 ::journal::MockFuture mock_future
;
1188 Context
*on_journal_safe
;
1189 expect_append_journaler(mock_journaler
);
1190 expect_wait_future(mock_future
, &on_journal_safe
);
1191 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
, 0));
1192 mock_journal
->get_work_queue()->drain();
1194 expect_future_is_valid(mock_future
);
1195 C_SaferCond flush_ctx
;
1196 mock_journal
->flush_event(1U, &flush_ctx
);
1198 // commit the event in the journal w/ waiting cache writeback
1199 expect_future_committed(mock_journaler
);
1200 C_SaferCond object_request_ctx
;
1201 mock_journal
->wait_event(1U, &object_request_ctx
);
1202 on_journal_safe
->complete(-EINVAL
);
1203 ASSERT_EQ(-EINVAL
, object_request_ctx
.wait());
1205 // cache should receive the error if waiting
1206 ASSERT_EQ(-EINVAL
, flush_ctx
.wait());
1208 expect_shut_down_journaler(mock_journaler
);
1211 TEST_F(TestMockJournal
, IOCommitError
) {
1212 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1214 librbd::ImageCtx
*ictx
;
1215 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1217 MockJournalImageCtx
mock_image_ctx(*ictx
);
1218 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1219 MockObjectDispatch mock_object_dispatch
;
1220 ::journal::MockJournaler mock_journaler
;
1221 MockJournalOpenRequest mock_open_request
;
1222 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1223 mock_journaler
, mock_open_request
);
1224 BOOST_SCOPE_EXIT_ALL(&) {
1225 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1226 mock_journal
->put();
1229 ::journal::MockFuture mock_future
;
1230 Context
*on_journal_safe
;
1231 expect_append_journaler(mock_journaler
);
1232 expect_wait_future(mock_future
, &on_journal_safe
);
1233 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
, 0));
1234 mock_journal
->get_work_queue()->drain();
1236 // failed IO remains uncommitted in journal
1237 on_journal_safe
->complete(0);
1238 ictx
->op_work_queue
->drain();
1239 mock_journal
->commit_io_event(1U, -EINVAL
);
1241 expect_shut_down_journaler(mock_journaler
);
1244 TEST_F(TestMockJournal
, IOCommitErrorFiltered
) {
1245 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1247 librbd::ImageCtx
*ictx
;
1248 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1250 MockJournalImageCtx
mock_image_ctx(*ictx
);
1251 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1252 MockObjectDispatch mock_object_dispatch
;
1253 ::journal::MockJournaler mock_journaler
;
1254 MockJournalOpenRequest mock_open_request
;
1255 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1256 mock_journaler
, mock_open_request
);
1257 BOOST_SCOPE_EXIT_ALL(&) {
1258 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1259 mock_journal
->put();
1262 ::journal::MockFuture mock_future
;
1263 Context
*on_journal_safe
;
1264 expect_append_journaler(mock_journaler
);
1265 expect_wait_future(mock_future
, &on_journal_safe
);
1266 ASSERT_EQ(1U, when_append_io_event(mock_image_ctx
, mock_journal
, -EILSEQ
));
1267 mock_journal
->get_work_queue()->drain();
1269 // filter failed IO committed in journal
1270 on_journal_safe
->complete(0);
1271 ictx
->op_work_queue
->drain();
1272 expect_future_committed(mock_journaler
);
1273 mock_journal
->commit_io_event(1U, -EILSEQ
);
1275 expect_shut_down_journaler(mock_journaler
);
1278 TEST_F(TestMockJournal
, FlushCommitPosition
) {
1279 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1281 librbd::ImageCtx
*ictx
;
1282 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1284 MockJournalImageCtx
mock_image_ctx(*ictx
);
1285 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1286 MockObjectDispatch mock_object_dispatch
;
1287 ::journal::MockJournaler mock_journaler
;
1288 MockJournalOpenRequest mock_open_request
;
1289 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1290 mock_journaler
, mock_open_request
);
1291 BOOST_SCOPE_EXIT_ALL(&) {
1292 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1293 mock_journal
->put();
1296 expect_flush_commit_position(mock_journaler
);
1298 mock_journal
->flush_commit_position(&ctx
);
1299 ASSERT_EQ(0, ctx
.wait());
1301 expect_shut_down_journaler(mock_journaler
);
1304 TEST_F(TestMockJournal
, ExternalReplay
) {
1305 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1307 librbd::ImageCtx
*ictx
;
1308 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1310 MockJournalImageCtx
mock_image_ctx(*ictx
);
1311 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1312 MockObjectDispatch mock_object_dispatch
;
1313 ::journal::MockJournaler mock_journaler
;
1314 MockJournalOpenRequest mock_open_request
;
1315 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1316 mock_journaler
, mock_open_request
);
1317 BOOST_SCOPE_EXIT_ALL(&) {
1318 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1319 mock_journal
->put();
1323 expect_stop_append(mock_journaler
, 0);
1324 expect_start_append(mock_journaler
);
1325 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
1326 expect_shut_down_journaler(mock_journaler
);
1328 C_SaferCond start_ctx
;
1330 journal::Replay
<MockJournalImageCtx
> *journal_replay
= nullptr;
1331 mock_journal
->start_external_replay(&journal_replay
, &start_ctx
);
1332 ASSERT_EQ(0, start_ctx
.wait());
1334 mock_journal
->stop_external_replay();
1337 TEST_F(TestMockJournal
, ExternalReplayFailure
) {
1338 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1340 librbd::ImageCtx
*ictx
;
1341 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1343 MockJournalImageCtx
mock_image_ctx(*ictx
);
1344 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1345 MockObjectDispatch mock_object_dispatch
;
1346 ::journal::MockJournaler mock_journaler
;
1347 MockJournalOpenRequest mock_open_request
;
1348 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1349 mock_journaler
, mock_open_request
);
1350 BOOST_SCOPE_EXIT_ALL(&) {
1351 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1352 mock_journal
->put();
1356 expect_stop_append(mock_journaler
, -EINVAL
);
1357 expect_start_append(mock_journaler
);
1358 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, false);
1359 expect_shut_down_journaler(mock_journaler
);
1361 C_SaferCond start_ctx
;
1363 journal::Replay
<MockJournalImageCtx
> *journal_replay
= nullptr;
1364 mock_journal
->start_external_replay(&journal_replay
, &start_ctx
);
1365 ASSERT_EQ(-EINVAL
, start_ctx
.wait());
1368 TEST_F(TestMockJournal
, AppendDisabled
) {
1369 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1371 librbd::ImageCtx
*ictx
;
1372 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1374 MockJournalImageCtx
mock_image_ctx(*ictx
);
1375 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1376 MockObjectDispatch mock_object_dispatch
;
1377 MockJournalPolicy mock_journal_policy
;
1379 ::journal::MockJournaler mock_journaler
;
1380 MockJournalOpenRequest mock_open_request
;
1381 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1382 mock_journaler
, mock_open_request
);
1383 BOOST_SCOPE_EXIT_ALL(&) {
1384 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1385 mock_journal
->put();
1389 std::shared_lock image_locker
{mock_image_ctx
.image_lock
};
1390 EXPECT_CALL(mock_image_ctx
, get_journal_policy()).WillOnce(
1391 Return(ictx
->get_journal_policy()));
1392 ASSERT_TRUE(mock_journal
->is_journal_appending());
1394 EXPECT_CALL(mock_image_ctx
, get_journal_policy()).WillOnce(
1395 Return(&mock_journal_policy
));
1396 EXPECT_CALL(mock_journal_policy
, append_disabled()).WillOnce(Return(true));
1397 ASSERT_FALSE(mock_journal
->is_journal_appending());
1399 expect_shut_down_journaler(mock_journaler
);
1402 TEST_F(TestMockJournal
, CloseListenerEvent
) {
1403 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1405 librbd::ImageCtx
*ictx
;
1406 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1408 MockJournalImageCtx
mock_image_ctx(*ictx
);
1409 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1411 BOOST_SCOPE_EXIT(&mock_journal
) {
1412 mock_journal
->put();
1413 } BOOST_SCOPE_EXIT_END
1415 MockObjectDispatch mock_object_dispatch
;
1416 ::journal::MockJournaler mock_journaler
;
1417 MockJournalOpenRequest mock_open_request
;
1418 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1419 mock_journaler
, mock_open_request
);
1421 struct Listener
: public journal::Listener
{
1423 void handle_close() override
{
1426 void handle_resync() override
{
1427 ADD_FAILURE() << "unexpected resync request";
1429 void handle_promoted() override
{
1430 ADD_FAILURE() << "unexpected promotion event";
1433 mock_journal
->add_listener(&listener
);
1435 expect_shut_down_journaler(mock_journaler
);
1436 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1438 ASSERT_EQ(0, listener
.ctx
.wait());
1439 mock_journal
->remove_listener(&listener
);
1442 TEST_F(TestMockJournal
, ResyncRequested
) {
1443 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1445 librbd::ImageCtx
*ictx
;
1446 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1448 MockJournalImageCtx
mock_image_ctx(*ictx
);
1449 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1450 MockObjectDispatch mock_object_dispatch
;
1451 ::journal::MockJournaler mock_journaler
;
1452 MockJournalOpenRequest mock_open_request
;
1453 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1454 mock_journaler
, mock_open_request
,
1457 struct Listener
: public journal::Listener
{
1459 void handle_close() override
{
1460 ADD_FAILURE() << "unexpected close action";
1462 void handle_resync() override
{
1465 void handle_promoted() override
{
1466 ADD_FAILURE() << "unexpected promotion event";
1469 mock_journal
->add_listener(&listener
);
1471 BOOST_SCOPE_EXIT_ALL(&) {
1472 mock_journal
->remove_listener(&listener
);
1473 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1474 mock_journal
->put();
1479 journal::TagData tag_data
;
1480 tag_data
.mirror_uuid
= Journal
<>::LOCAL_MIRROR_UUID
;
1482 bufferlist tag_data_bl
;
1483 encode(tag_data
, tag_data_bl
);
1484 expect_get_journaler_tags(mock_image_ctx
, mock_journaler
, 0,
1485 {{0, 0, tag_data_bl
}}, 0);
1487 journal::ImageClientMeta image_client_meta
;
1488 image_client_meta
.tag_class
= 0;
1489 image_client_meta
.resync_requested
= true;
1490 expect_get_journaler_cached_client(mock_journaler
, image_client_meta
, 0);
1491 expect_shut_down_journaler(mock_journaler
);
1493 m_listener
->handle_update(nullptr);
1494 ASSERT_EQ(0, listener
.ctx
.wait());
1497 TEST_F(TestMockJournal
, ForcePromoted
) {
1498 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1500 librbd::ImageCtx
*ictx
;
1501 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1503 MockJournalImageCtx
mock_image_ctx(*ictx
);
1504 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1505 MockObjectDispatch mock_object_dispatch
;
1506 ::journal::MockJournaler mock_journaler
;
1507 MockJournalOpenRequest mock_open_request
;
1508 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1509 mock_journaler
, mock_open_request
, false);
1511 struct Listener
: public journal::Listener
{
1513 void handle_close() override
{
1514 ADD_FAILURE() << "unexpected close action";
1516 void handle_resync() override
{
1517 ADD_FAILURE() << "unexpected resync event";
1519 void handle_promoted() override
{
1523 mock_journal
->add_listener(&listener
);
1525 BOOST_SCOPE_EXIT_ALL(&) {
1526 mock_journal
->remove_listener(&listener
);
1527 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1528 mock_journal
->put();
1533 journal::TagData tag_data
;
1534 tag_data
.mirror_uuid
= Journal
<>::LOCAL_MIRROR_UUID
;
1536 bufferlist tag_data_bl
;
1537 encode(tag_data
, tag_data_bl
);
1538 expect_get_journaler_tags(mock_image_ctx
, mock_journaler
, 0,
1539 {{100, 0, tag_data_bl
}}, 0);
1541 journal::ImageClientMeta image_client_meta
;
1542 image_client_meta
.tag_class
= 0;
1543 expect_get_journaler_cached_client(mock_journaler
, image_client_meta
, 0);
1544 expect_shut_down_journaler(mock_journaler
);
1546 m_listener
->handle_update(nullptr);
1547 ASSERT_EQ(0, listener
.ctx
.wait());
1550 TEST_F(TestMockJournal
, UserFlushed
) {
1551 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
1553 librbd::ImageCtx
*ictx
;
1554 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
1556 MockJournalImageCtx
mock_image_ctx(*ictx
);
1557 MockJournal
*mock_journal
= new MockJournal(mock_image_ctx
);
1558 MockObjectDispatch mock_object_dispatch
;
1559 ::journal::MockJournaler mock_journaler
;
1560 MockJournalOpenRequest mock_open_request
;
1561 open_journal(mock_image_ctx
, mock_journal
, mock_object_dispatch
,
1562 mock_journaler
, mock_open_request
);
1563 BOOST_SCOPE_EXIT_ALL(&) {
1564 close_journal(mock_image_ctx
, mock_journal
, mock_journaler
);
1565 mock_journal
->put();
1568 expect_set_append_batch_options(mock_image_ctx
, mock_journaler
, true);
1569 mock_journal
->user_flushed();
1571 expect_shut_down_journaler(mock_journaler
);
1574 } // namespace librbd