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_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "librbd/internal.h"
7 #include "librbd/Journal.h"
8 #include "librbd/io/AioCompletion.h"
9 #include "librbd/io/ImageRequestWQ.h"
10 #include "librbd/journal/Types.h"
11 #include "journal/Journaler.h"
12 #include "journal/ReplayEntry.h"
13 #include "journal/ReplayHandler.h"
14 #include "journal/Settings.h"
16 #include <boost/variant.hpp>
18 void register_test_journal_entries() {
21 class TestJournalEntries
: public TestFixture
{
23 typedef std::list
<journal::Journaler
*> Journalers
;
25 struct ReplayHandler
: public journal::ReplayHandler
{
28 bool entries_available
;
32 : lock("ReplayHandler::lock"), entries_available(false), complete(false) {
40 void handle_entries_available() override
{
41 Mutex::Locker
locker(lock
);
42 entries_available
= true;
46 void handle_complete(int r
) override
{
47 Mutex::Locker
locker(lock
);
53 ReplayHandler m_replay_handler
;
54 Journalers m_journalers
;
56 void TearDown() override
{
57 for (Journalers::iterator it
= m_journalers
.begin();
58 it
!= m_journalers
.end(); ++it
) {
59 journal::Journaler
*journaler
= *it
;
60 journaler
->stop_replay();
61 journaler
->shut_down();
65 TestFixture::TearDown();
68 journal::Journaler
*create_journaler(librbd::ImageCtx
*ictx
) {
69 journal::Journaler
*journaler
= new journal::Journaler(
70 ictx
->md_ctx
, ictx
->id
, "dummy client", {});
72 int r
= journaler
->register_client(bufferlist());
74 ADD_FAILURE() << "failed to register journal client";
80 journaler
->init(&cond
);
83 ADD_FAILURE() << "failed to initialize journal client";
88 journaler
->start_live_replay(&m_replay_handler
, 0.1);
89 m_journalers
.push_back(journaler
);
93 bool wait_for_entries_available(librbd::ImageCtx
*ictx
) {
94 Mutex::Locker
locker(m_replay_handler
.lock
);
95 while (!m_replay_handler
.entries_available
) {
96 if (m_replay_handler
.cond
.WaitInterval(m_replay_handler
.lock
,
97 utime_t(10, 0)) != 0) {
101 m_replay_handler
.entries_available
= false;
105 bool get_event_entry(const journal::ReplayEntry
&replay_entry
,
106 librbd::journal::EventEntry
*event_entry
) {
108 bufferlist data_bl
= replay_entry
.get_data();
109 bufferlist::iterator it
= data_bl
.begin();
110 ::decode(*event_entry
, it
);
111 } catch (const buffer::error
&err
) {
119 TEST_F(TestJournalEntries
, AioWrite
) {
120 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
122 librbd::ImageCtx
*ictx
;
123 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
125 journal::Journaler
*journaler
= create_journaler(ictx
);
126 ASSERT_TRUE(journaler
!= NULL
);
128 std::string
buffer(512, '1');
130 write_bl
.append(buffer
);
132 C_SaferCond cond_ctx
;
133 auto c
= librbd::io::AioCompletion::create(&cond_ctx
);
135 ictx
->io_work_queue
->aio_write(c
, 123, buffer
.size(), std::move(write_bl
), 0);
136 ASSERT_EQ(0, c
->wait_for_complete());
139 ASSERT_TRUE(wait_for_entries_available(ictx
));
141 journal::ReplayEntry replay_entry
;
142 ASSERT_TRUE(journaler
->try_pop_front(&replay_entry
));
144 librbd::journal::EventEntry event_entry
;
145 ASSERT_TRUE(get_event_entry(replay_entry
, &event_entry
));
147 ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_WRITE
,
148 event_entry
.get_event_type());
150 librbd::journal::AioWriteEvent aio_write_event
=
151 boost::get
<librbd::journal::AioWriteEvent
>(event_entry
.event
);
152 ASSERT_EQ(123U, aio_write_event
.offset
);
153 ASSERT_EQ(buffer
.size(), aio_write_event
.length
);
155 bufferlist buffer_bl
;
156 buffer_bl
.append(buffer
);
157 ASSERT_TRUE(aio_write_event
.data
.contents_equal(buffer_bl
));
159 ASSERT_EQ(librbd::journal::AioWriteEvent::get_fixed_size() +
160 aio_write_event
.data
.length(), replay_entry
.get_data().length());
163 TEST_F(TestJournalEntries
, AioDiscard
) {
164 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
166 CephContext
* cct
= reinterpret_cast<CephContext
*>(_rados
.cct());
167 REQUIRE(!cct
->_conf
->rbd_skip_partial_discard
);
169 librbd::ImageCtx
*ictx
;
170 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
172 journal::Journaler
*journaler
= create_journaler(ictx
);
173 ASSERT_TRUE(journaler
!= NULL
);
175 C_SaferCond cond_ctx
;
176 auto c
= librbd::io::AioCompletion::create(&cond_ctx
);
178 ictx
->io_work_queue
->aio_discard(c
, 123, 234, cct
->_conf
->rbd_skip_partial_discard
);
179 ASSERT_EQ(0, c
->wait_for_complete());
182 ASSERT_TRUE(wait_for_entries_available(ictx
));
184 journal::ReplayEntry replay_entry
;
185 ASSERT_TRUE(journaler
->try_pop_front(&replay_entry
));
187 librbd::journal::EventEntry event_entry
;
188 ASSERT_TRUE(get_event_entry(replay_entry
, &event_entry
));
190 ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_DISCARD
,
191 event_entry
.get_event_type());
193 librbd::journal::AioDiscardEvent aio_discard_event
=
194 boost::get
<librbd::journal::AioDiscardEvent
>(event_entry
.event
);
195 ASSERT_EQ(123U, aio_discard_event
.offset
);
196 ASSERT_EQ(234U, aio_discard_event
.length
);
199 TEST_F(TestJournalEntries
, AioFlush
) {
200 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
202 librbd::ImageCtx
*ictx
;
203 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
205 journal::Journaler
*journaler
= create_journaler(ictx
);
206 ASSERT_TRUE(journaler
!= NULL
);
208 C_SaferCond cond_ctx
;
209 auto c
= librbd::io::AioCompletion::create(&cond_ctx
);
211 ictx
->io_work_queue
->aio_flush(c
);
212 ASSERT_EQ(0, c
->wait_for_complete());
215 ASSERT_TRUE(wait_for_entries_available(ictx
));
217 journal::ReplayEntry replay_entry
;
218 ASSERT_TRUE(journaler
->try_pop_front(&replay_entry
));
220 librbd::journal::EventEntry event_entry
;
221 ASSERT_TRUE(get_event_entry(replay_entry
, &event_entry
));
223 ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_FLUSH
,
224 event_entry
.get_event_type());