1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "rbd_replay/ActionTypes.h"
5 #include "include/ceph_assert.h"
6 #include "include/byteorder.h"
7 #include "include/stringify.h"
8 #include "common/Formatter.h"
10 #include <boost/variant.hpp>
12 namespace rbd_replay
{
17 bool byte_swap_required(__u8 version
) {
18 #if defined(CEPH_LITTLE_ENDIAN)
19 return (version
== 0);
25 void decode_big_endian_string(std::string
&str
, bufferlist::const_iterator
&it
) {
27 #if defined(CEPH_LITTLE_ENDIAN)
30 length
= swab(length
);
38 class EncodeVisitor
: public boost::static_visitor
<void> {
40 explicit EncodeVisitor(bufferlist
&bl
) : m_bl(bl
) {
43 template <typename Action
>
44 inline void operator()(const Action
&action
) const {
46 encode(static_cast<uint8_t>(Action::ACTION_TYPE
), m_bl
);
53 class DecodeVisitor
: public boost::static_visitor
<void> {
55 DecodeVisitor(__u8 version
, bufferlist::const_iterator
&iter
)
56 : m_version(version
), m_iter(iter
) {
59 template <typename Action
>
60 inline void operator()(Action
&action
) const {
61 action
.decode(m_version
, m_iter
);
65 bufferlist::const_iterator
&m_iter
;
68 class DumpVisitor
: public boost::static_visitor
<void> {
70 explicit DumpVisitor(Formatter
*formatter
) : m_formatter(formatter
) {}
72 template <typename Action
>
73 inline void operator()(const Action
&action
) const {
74 ActionType action_type
= Action::ACTION_TYPE
;
75 m_formatter
->dump_string("action_type", stringify(action_type
));
76 action
.dump(m_formatter
);
79 ceph::Formatter
*m_formatter
;
82 } // anonymous namespace
84 void Dependency::encode(bufferlist
&bl
) const {
87 encode(time_delta
, bl
);
90 void Dependency::decode(bufferlist::const_iterator
&it
) {
94 void Dependency::decode(__u8 version
, bufferlist::const_iterator
&it
) {
97 decode(time_delta
, it
);
98 if (byte_swap_required(version
)) {
100 time_delta
= swab(time_delta
);
104 void Dependency::dump(Formatter
*f
) const {
105 f
->dump_unsigned("id", id
);
106 f
->dump_unsigned("time_delta", time_delta
);
109 void Dependency::generate_test_instances(std::list
<Dependency
*> &o
) {
110 o
.push_back(new Dependency());
111 o
.push_back(new Dependency(1, 123456789));
114 void ActionBase::encode(bufferlist
&bl
) const {
117 encode(thread_id
, bl
);
118 encode(dependencies
, bl
);
121 void ActionBase::decode(__u8 version
, bufferlist::const_iterator
&it
) {
124 decode(thread_id
, it
);
126 uint32_t num_successors
;
127 decode(num_successors
, it
);
129 uint32_t num_completion_successors
;
130 decode(num_completion_successors
, it
);
133 if (byte_swap_required(version
)) {
135 thread_id
= swab(thread_id
);
138 decode(dep_count
, it
);
139 dep_count
= swab(dep_count
);
140 dependencies
.resize(dep_count
);
141 for (uint32_t i
= 0; i
< dep_count
; ++i
) {
142 dependencies
[i
].decode(0, it
);
145 decode(dependencies
, it
);
149 void ActionBase::dump(Formatter
*f
) const {
150 f
->dump_unsigned("id", id
);
151 f
->dump_unsigned("thread_id", thread_id
);
152 f
->open_array_section("dependencies");
153 for (size_t i
= 0; i
< dependencies
.size(); ++i
) {
154 f
->open_object_section("dependency");
155 dependencies
[i
].dump(f
);
161 void ImageActionBase::encode(bufferlist
&bl
) const {
163 ActionBase::encode(bl
);
164 encode(imagectx_id
, bl
);
167 void ImageActionBase::decode(__u8 version
, bufferlist::const_iterator
&it
) {
169 ActionBase::decode(version
, it
);
170 decode(imagectx_id
, it
);
171 if (byte_swap_required(version
)) {
172 imagectx_id
= swab(imagectx_id
);
176 void ImageActionBase::dump(Formatter
*f
) const {
178 f
->dump_unsigned("imagectx_id", imagectx_id
);
181 void IoActionBase::encode(bufferlist
&bl
) const {
183 ImageActionBase::encode(bl
);
188 void IoActionBase::decode(__u8 version
, bufferlist::const_iterator
&it
) {
190 ImageActionBase::decode(version
, it
);
193 if (byte_swap_required(version
)) {
194 offset
= swab(offset
);
195 length
= swab(length
);
199 void IoActionBase::dump(Formatter
*f
) const {
200 ImageActionBase::dump(f
);
201 f
->dump_unsigned("offset", offset
);
202 f
->dump_unsigned("length", length
);
205 void OpenImageAction::encode(bufferlist
&bl
) const {
207 ImageActionBase::encode(bl
);
209 encode(snap_name
, bl
);
210 encode(read_only
, bl
);
213 void OpenImageAction::decode(__u8 version
, bufferlist::const_iterator
&it
) {
215 ImageActionBase::decode(version
, it
);
216 if (byte_swap_required(version
)) {
217 decode_big_endian_string(name
, it
);
218 decode_big_endian_string(snap_name
, it
);
221 decode(snap_name
, it
);
223 decode(read_only
, it
);
226 void OpenImageAction::dump(Formatter
*f
) const {
227 ImageActionBase::dump(f
);
228 f
->dump_string("name", name
);
229 f
->dump_string("snap_name", snap_name
);
230 f
->dump_bool("read_only", read_only
);
233 void AioOpenImageAction::encode(bufferlist
&bl
) const {
235 ImageActionBase::encode(bl
);
237 encode(snap_name
, bl
);
238 encode(read_only
, bl
);
241 void AioOpenImageAction::decode(__u8 version
, bufferlist::const_iterator
&it
) {
243 ImageActionBase::decode(version
, it
);
244 if (byte_swap_required(version
)) {
245 decode_big_endian_string(name
, it
);
246 decode_big_endian_string(snap_name
, it
);
249 decode(snap_name
, it
);
251 decode(read_only
, it
);
254 void AioOpenImageAction::dump(Formatter
*f
) const {
255 ImageActionBase::dump(f
);
256 f
->dump_string("name", name
);
257 f
->dump_string("snap_name", snap_name
);
258 f
->dump_bool("read_only", read_only
);
261 void UnknownAction::encode(bufferlist
&bl
) const {
265 void UnknownAction::decode(__u8 version
, bufferlist::const_iterator
&it
) {
268 void UnknownAction::dump(Formatter
*f
) const {
271 void ActionEntry::encode(bufferlist
&bl
) const {
272 ENCODE_START(1, 1, bl
);
273 boost::apply_visitor(EncodeVisitor(bl
), action
);
277 void ActionEntry::decode(bufferlist::const_iterator
&it
) {
279 decode(struct_v
, it
);
283 void ActionEntry::decode_unversioned(bufferlist::const_iterator
&it
) {
287 void ActionEntry::decode(__u8 version
, bufferlist::const_iterator
&it
) {
290 decode(action_type
, it
);
292 // select the correct action variant based upon the action_type
293 switch (action_type
) {
294 case ACTION_TYPE_START_THREAD
:
295 action
= StartThreadAction();
297 case ACTION_TYPE_STOP_THREAD
:
298 action
= StopThreadAction();
300 case ACTION_TYPE_READ
:
301 action
= ReadAction();
303 case ACTION_TYPE_WRITE
:
304 action
= WriteAction();
306 case ACTION_TYPE_DISCARD
:
307 action
= DiscardAction();
309 case ACTION_TYPE_AIO_READ
:
310 action
= AioReadAction();
312 case ACTION_TYPE_AIO_WRITE
:
313 action
= AioWriteAction();
315 case ACTION_TYPE_AIO_DISCARD
:
316 action
= AioDiscardAction();
318 case ACTION_TYPE_OPEN_IMAGE
:
319 action
= OpenImageAction();
321 case ACTION_TYPE_CLOSE_IMAGE
:
322 action
= CloseImageAction();
324 case ACTION_TYPE_AIO_OPEN_IMAGE
:
325 action
= AioOpenImageAction();
327 case ACTION_TYPE_AIO_CLOSE_IMAGE
:
328 action
= AioCloseImageAction();
332 boost::apply_visitor(DecodeVisitor(version
, it
), action
);
335 void ActionEntry::dump(Formatter
*f
) const {
336 boost::apply_visitor(DumpVisitor(f
), action
);
339 void ActionEntry::generate_test_instances(std::list
<ActionEntry
*> &o
) {
340 Dependencies dependencies
;
341 dependencies
.push_back(Dependency(3, 123456789));
342 dependencies
.push_back(Dependency(4, 234567890));
344 o
.push_back(new ActionEntry(StartThreadAction()));
345 o
.push_back(new ActionEntry(StartThreadAction(1, 123456789, dependencies
)));
346 o
.push_back(new ActionEntry(StopThreadAction()));
347 o
.push_back(new ActionEntry(StopThreadAction(1, 123456789, dependencies
)));
349 o
.push_back(new ActionEntry(ReadAction()));
350 o
.push_back(new ActionEntry(ReadAction(1, 123456789, dependencies
, 3, 4, 5)));
351 o
.push_back(new ActionEntry(WriteAction()));
352 o
.push_back(new ActionEntry(WriteAction(1, 123456789, dependencies
, 3, 4,
354 o
.push_back(new ActionEntry(DiscardAction()));
355 o
.push_back(new ActionEntry(DiscardAction(1, 123456789, dependencies
, 3, 4,
357 o
.push_back(new ActionEntry(AioReadAction()));
358 o
.push_back(new ActionEntry(AioReadAction(1, 123456789, dependencies
, 3, 4,
360 o
.push_back(new ActionEntry(AioWriteAction()));
361 o
.push_back(new ActionEntry(AioWriteAction(1, 123456789, dependencies
, 3, 4,
363 o
.push_back(new ActionEntry(AioDiscardAction()));
364 o
.push_back(new ActionEntry(AioDiscardAction(1, 123456789, dependencies
, 3, 4,
367 o
.push_back(new ActionEntry(OpenImageAction()));
368 o
.push_back(new ActionEntry(OpenImageAction(1, 123456789, dependencies
, 3,
369 "image_name", "snap_name",
371 o
.push_back(new ActionEntry(CloseImageAction()));
372 o
.push_back(new ActionEntry(CloseImageAction(1, 123456789, dependencies
, 3)));
374 o
.push_back(new ActionEntry(AioOpenImageAction()));
375 o
.push_back(new ActionEntry(AioOpenImageAction(1, 123456789, dependencies
, 3,
376 "image_name", "snap_name",
378 o
.push_back(new ActionEntry(AioCloseImageAction()));
379 o
.push_back(new ActionEntry(AioCloseImageAction(1, 123456789, dependencies
, 3)));
382 std::ostream
&operator<<(std::ostream
&out
,
383 const ActionType
&type
) {
384 using namespace rbd_replay::action
;
387 case ACTION_TYPE_START_THREAD
:
388 out
<< "StartThread";
390 case ACTION_TYPE_STOP_THREAD
:
393 case ACTION_TYPE_READ
:
396 case ACTION_TYPE_WRITE
:
399 case ACTION_TYPE_DISCARD
:
402 case ACTION_TYPE_AIO_READ
:
405 case ACTION_TYPE_AIO_WRITE
:
408 case ACTION_TYPE_AIO_DISCARD
:
411 case ACTION_TYPE_OPEN_IMAGE
:
414 case ACTION_TYPE_CLOSE_IMAGE
:
417 case ACTION_TYPE_AIO_OPEN_IMAGE
:
418 out
<< "AioOpenImage";
420 case ACTION_TYPE_AIO_CLOSE_IMAGE
:
421 out
<< "AioCloseImage";
424 out
<< "Unknown (" << static_cast<uint32_t>(type
) << ")";
430 } // namespace action
431 } // namespace rbd_replay