librbd/ImageWatcher.cc
librbd/internal.cc
librbd/Journal.cc
- librbd/JournalReplay.cc
- librbd/JournalTypes.cc
librbd/librbd.cc
librbd/LibrbdAdminSocketHook.cc
librbd/LibrbdWriteback.cc
librbd/image/RefreshParentRequest.cc
librbd/image/RefreshRequest.cc
librbd/image/SetSnapRequest.cc
+ librbd/journal/Entries.cc
+ librbd/journal/Replay.cc
librbd/object_map/InvalidateRequest.cc
librbd/object_map/LockRequest.cc
librbd/object_map/Request.cc
#include "librbd/ImageWatcher.h"
#include "librbd/internal.h"
#include "librbd/Journal.h"
-#include "librbd/JournalTypes.h"
+#include "librbd/journal/Entries.h"
#include "include/rados/librados.hpp"
#include "osdc/Striper.h"
#include "librbd/AioObjectRequest.h"
#include "librbd/ExclusiveLock.h"
#include "librbd/ImageCtx.h"
-#include "librbd/JournalReplay.h"
-#include "librbd/JournalTypes.h"
+#include "librbd/journal/Entries.h"
+#include "librbd/journal/Replay.h"
#include "librbd/Utils.h"
#include "journal/Journaler.h"
#include "journal/ReplayEntry.h"
}
transition_state(STATE_REPLAYING, 0);
- m_journal_replay = new JournalReplay(m_image_ctx);
+ m_journal_replay = new journal::Replay(m_image_ctx);
m_journaler->start_replay(&m_replay_handler);
}
class AioCompletion;
class AioObjectRequest;
class ImageCtx;
-class JournalReplay;
namespace journal {
class EventEntry;
+class Replay;
}
class Journal {
bool m_blocking_writes;
- JournalReplay *m_journal_replay;
+ journal::Replay *m_journal_replay;
::journal::Future wait_event(Mutex &lock, uint64_t tid, Context *on_safe);
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "librbd/JournalReplay.h"
-#include "librbd/AioCompletion.h"
-#include "librbd/AioImageRequest.h"
-#include "librbd/ImageCtx.h"
-#include "librbd/internal.h"
-
-#define dout_subsys ceph_subsys_rbd
-#undef dout_prefix
-#define dout_prefix *_dout << "librbd::JournalReplay: "
-
-namespace librbd {
-
-JournalReplay::JournalReplay(ImageCtx &image_ctx)
- : m_image_ctx(image_ctx), m_lock("JournalReplay::m_lock"), m_ret_val(0) {
-}
-
-JournalReplay::~JournalReplay() {
- assert(m_aio_completions.empty());
-}
-
-int JournalReplay::process(bufferlist::iterator it, Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << dendl;
-
- RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
- journal::EventEntry event_entry;
- try {
- ::decode(event_entry, it);
- } catch (const buffer::error &err) {
- lderr(cct) << "failed to decode event entry: " << err.what() << dendl;
- return -EINVAL;
- }
-
- boost::apply_visitor(EventVisitor(this, on_safe), event_entry.event);
- return 0;
-}
-
-int JournalReplay::flush() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << dendl;
-
- Mutex::Locker locker(m_lock);
- while (!m_aio_completions.empty()) {
- m_cond.Wait(m_lock);
- }
- return m_ret_val;
-}
-
-void JournalReplay::handle_event(const journal::AioDiscardEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": AIO discard event" << dendl;
-
- AioCompletion *aio_comp = create_aio_completion(on_safe);
- AioImageRequest::aio_discard(&m_image_ctx, aio_comp, event.offset,
- event.length);
-}
-
-void JournalReplay::handle_event(const journal::AioWriteEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": AIO write event" << dendl;
-
- bufferlist data = event.data;
- AioCompletion *aio_comp = create_aio_completion(on_safe);
- AioImageRequest::aio_write(&m_image_ctx, aio_comp, event.offset, event.length,
- data.c_str(), 0);
-}
-
-void JournalReplay::handle_event(const journal::AioFlushEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": AIO flush event" << dendl;
-
- AioCompletion *aio_comp = create_aio_completion(on_safe);
- AioImageRequest::aio_flush(&m_image_ctx, aio_comp);
-}
-
- void JournalReplay::handle_event(const journal::OpFinishEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Op finish event" << dendl;
-}
-
-void JournalReplay::handle_event(const journal::SnapCreateEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Snap create event" << dendl;
-}
-
-void JournalReplay::handle_event(const journal::SnapRemoveEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Snap remove event" << dendl;
-}
-
-void JournalReplay::handle_event(const journal::SnapRenameEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Snap rename event" << dendl;
-}
-
-void JournalReplay::handle_event(const journal::SnapProtectEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Snap protect event" << dendl;
-}
-
-void JournalReplay::handle_event(const journal::SnapUnprotectEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Snap unprotect event"
- << dendl;
-}
-
-void JournalReplay::handle_event(const journal::SnapRollbackEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Snap rollback start event"
- << dendl;
-}
-
-void JournalReplay::handle_event(const journal::RenameEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Rename event" << dendl;
-}
-
-void JournalReplay::handle_event(const journal::ResizeEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Resize start event" << dendl;
-}
-
-void JournalReplay::handle_event(const journal::FlattenEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": Flatten start event" << dendl;
-}
-
-void JournalReplay::handle_event(const journal::UnknownEvent &event,
- Context *on_safe) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": unknown event" << dendl;
- on_safe->complete(0);
-}
-
-AioCompletion *JournalReplay::create_aio_completion(Context *on_safe) {
- Mutex::Locker locker(m_lock);
- AioCompletion *aio_comp = AioCompletion::create(this, aio_completion_callback,
- nullptr);
- m_aio_completions.insert(std::pair<AioCompletion*,Context*>(
- aio_comp, on_safe));
- return aio_comp;
-}
-
-void JournalReplay::handle_aio_completion(AioCompletion *aio_comp) {
- Mutex::Locker locker(m_lock);
-
- AioCompletions::iterator it = m_aio_completions.find(aio_comp);
- assert(it != m_aio_completions.end());
-
- int r = aio_comp->get_return_value();
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 20) << this << " " << __func__ << ": aio_comp=" << aio_comp << ", "
- << "r=" << r << dendl;
-
- Context *on_safe = it->second;
- on_safe->complete(r);
-
- if (r < 0 && m_ret_val == 0) {
- m_ret_val = r;
- }
-
- m_aio_completions.erase(it);
- if (m_aio_completions.empty())
- m_cond.Signal();
-}
-
-void JournalReplay::aio_completion_callback(completion_t cb, void *arg) {
- JournalReplay *journal_replay = reinterpret_cast<JournalReplay *>(arg);
- AioCompletion *aio_comp = reinterpret_cast<AioCompletion *>(cb);
-
- journal_replay->handle_aio_completion(aio_comp);
- aio_comp->release();
-}
-
-} // namespace librbd
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#ifndef CEPH_LIBRBD_JOURNAL_REPLAY_H
-#define CEPH_LIBRBD_JOURNAL_REPLAY_H
-
-#include "include/int_types.h"
-#include "include/buffer_fwd.h"
-#include "include/rbd/librbd.hpp"
-#include "common/Cond.h"
-#include "common/Mutex.h"
-#include "librbd/JournalTypes.h"
-#include <boost/variant.hpp>
-#include <map>
-
-namespace librbd {
-
-class AioCompletion;
-class ImageCtx;
-
-class JournalReplay {
-public:
- JournalReplay(ImageCtx &image_ctx);
- ~JournalReplay();
-
- int process(bufferlist::iterator it, Context *on_safe = NULL);
- int flush();
-
-private:
- typedef std::map<AioCompletion*,Context*> AioCompletions;
-
- struct EventVisitor : public boost::static_visitor<void> {
- JournalReplay *journal_replay;
- Context *on_safe;
-
- EventVisitor(JournalReplay *_journal_replay, Context *_on_safe)
- : journal_replay(_journal_replay), on_safe(_on_safe) {
- }
-
- template <typename Event>
- inline void operator()(const Event &event) const {
- journal_replay->handle_event(event, on_safe);
- }
- };
-
- ImageCtx &m_image_ctx;
-
- Mutex m_lock;
- Cond m_cond;
-
- AioCompletions m_aio_completions;
- int m_ret_val;
-
- void handle_event(const journal::AioDiscardEvent &event, Context *on_safe);
- void handle_event(const journal::AioWriteEvent &event, Context *on_safe);
- void handle_event(const journal::AioFlushEvent &event, Context *on_safe);
- void handle_event(const journal::OpFinishEvent &event, Context *on_safe);
- void handle_event(const journal::SnapCreateEvent &event, Context *on_safe);
- void handle_event(const journal::SnapRemoveEvent &event, Context *on_safe);
- void handle_event(const journal::SnapRenameEvent &event, Context *on_safe);
- void handle_event(const journal::SnapProtectEvent &event, Context *on_safe);
- void handle_event(const journal::SnapUnprotectEvent &event, Context *on_safe);
- void handle_event(const journal::SnapRollbackEvent &event, Context *on_safe);
- void handle_event(const journal::RenameEvent &event, Context *on_safe);
- void handle_event(const journal::ResizeEvent &event, Context *on_safe);
- void handle_event(const journal::FlattenEvent &event, Context *on_safe);
- void handle_event(const journal::UnknownEvent &event, Context *on_safe);
-
- AioCompletion *create_aio_completion(Context *on_safe);
- void handle_aio_completion(AioCompletion *aio_comp);
-
- static void aio_completion_callback(completion_t cb, void *arg);
-};
-
-} // namespace librbd
-
-#endif // CEPH_LIBRBD_JOURNAL_REPLAY_H
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "librbd/JournalTypes.h"
-#include "include/assert.h"
-#include "include/stringify.h"
-#include "common/Formatter.h"
-
-namespace librbd {
-namespace journal {
-
-namespace {
-
-class GetEventTypeVistor : public boost::static_visitor<EventType> {
-public:
- template <typename Event>
- inline EventType operator()(const Event &event) const {
- return Event::EVENT_TYPE;
- }
-};
-
-class EncodeEventVisitor : public boost::static_visitor<void> {
-public:
- EncodeEventVisitor(bufferlist &bl) : m_bl(bl) {
- }
-
- template <typename Event>
- inline void operator()(const Event &event) const {
- ::encode(static_cast<uint32_t>(Event::EVENT_TYPE), m_bl);
- event.encode(m_bl);
- }
-private:
- bufferlist &m_bl;
-};
-
-class DecodeEventVisitor : public boost::static_visitor<void> {
-public:
- DecodeEventVisitor(__u8 version, bufferlist::iterator &iter)
- : m_version(version), m_iter(iter) {
- }
-
- template <typename Event>
- inline void operator()(Event &event) const {
- event.decode(m_version, m_iter);
- }
-private:
- __u8 m_version;
- bufferlist::iterator &m_iter;
-};
-
-class DumpEventVisitor : public boost::static_visitor<void> {
-public:
- DumpEventVisitor(Formatter *formatter) : m_formatter(formatter) {}
-
- template <typename Event>
- inline void operator()(const Event &event) const {
- EventType event_type = Event::EVENT_TYPE;
- m_formatter->dump_string("event_type", stringify(event_type));
- event.dump(m_formatter);
- }
-private:
- ceph::Formatter *m_formatter;
-};
-
-} // anonymous namespace
-
-void AioDiscardEvent::encode(bufferlist& bl) const {
- ::encode(offset, bl);
- ::encode(length, bl);
-}
-
-void AioDiscardEvent::decode(__u8 version, bufferlist::iterator& it) {
- ::decode(offset, it);
- ::decode(length, it);
-}
-
-void AioDiscardEvent::dump(Formatter *f) const {
- f->dump_unsigned("offset", offset);
- f->dump_unsigned("length", length);
-}
-
-void AioWriteEvent::encode(bufferlist& bl) const {
- ::encode(offset, bl);
- ::encode(length, bl);
- ::encode(data, bl);
-}
-
-void AioWriteEvent::decode(__u8 version, bufferlist::iterator& it) {
- ::decode(offset, it);
- ::decode(length, it);
- ::decode(data, it);
-}
-
-void AioWriteEvent::dump(Formatter *f) const {
- f->dump_unsigned("offset", offset);
- f->dump_unsigned("length", length);
-}
-
-void AioFlushEvent::encode(bufferlist& bl) const {
-}
-
-void AioFlushEvent::decode(__u8 version, bufferlist::iterator& it) {
-}
-
-void AioFlushEvent::dump(Formatter *f) const {
-}
-
-void OpEventBase::encode(bufferlist& bl) const {
- ::encode(tid, bl);
-}
-
-void OpEventBase::decode(__u8 version, bufferlist::iterator& it) {
- ::decode(tid, it);
-}
-
-void OpEventBase::dump(Formatter *f) const {
- f->dump_unsigned("tid", tid);
-}
-
-void SnapEventBase::encode(bufferlist& bl) const {
- OpStartEventBase::encode(bl);
- ::encode(snap_name, bl);
-}
-
-void SnapEventBase::decode(__u8 version, bufferlist::iterator& it) {
- OpStartEventBase::decode(version, it);
- ::decode(snap_name, it);
-}
-
-void SnapEventBase::dump(Formatter *f) const {
- OpStartEventBase::dump(f);
- f->dump_string("snap_name", snap_name);
-}
-
-void SnapRenameEvent::encode(bufferlist& bl) const {
- SnapEventBase::encode(bl);
- ::encode(snap_id, bl);
-}
-
-void SnapRenameEvent::decode(__u8 version, bufferlist::iterator& it) {
- SnapEventBase::decode(version, it);
- ::decode(snap_id, it);
-}
-
-void SnapRenameEvent::dump(Formatter *f) const {
- OpStartEventBase::dump(f);
- f->dump_unsigned("src_snap_id", snap_id);
- f->dump_string("dest_snap_name", snap_name);
-}
-
-void RenameEvent::encode(bufferlist& bl) const {
- OpStartEventBase::encode(bl);
- ::encode(image_name, bl);
-}
-
-void RenameEvent::decode(__u8 version, bufferlist::iterator& it) {
- OpStartEventBase::decode(version, it);
- ::decode(image_name, it);
-}
-
-void RenameEvent::dump(Formatter *f) const {
- OpStartEventBase::dump(f);
- f->dump_string("image_name", image_name);
-}
-
-void ResizeEvent::encode(bufferlist& bl) const {
- OpStartEventBase::encode(bl);
- ::encode(size, bl);
-}
-
-void ResizeEvent::decode(__u8 version, bufferlist::iterator& it) {
- OpStartEventBase::decode(version, it);
- ::decode(size, it);
-}
-
-void ResizeEvent::dump(Formatter *f) const {
- OpStartEventBase::dump(f);
- f->dump_unsigned("size", size);
-}
-
-void UnknownEvent::encode(bufferlist& bl) const {
- assert(false);
-}
-
-void UnknownEvent::decode(__u8 version, bufferlist::iterator& it) {
-}
-
-void UnknownEvent::dump(Formatter *f) const {
-}
-
-EventType EventEntry::get_event_type() const {
- return boost::apply_visitor(GetEventTypeVistor(), event);
-}
-
-void EventEntry::encode(bufferlist& bl) const {
- ENCODE_START(1, 1, bl);
- boost::apply_visitor(EncodeEventVisitor(bl), event);
- ENCODE_FINISH(bl);
-}
-
-void EventEntry::decode(bufferlist::iterator& it) {
- DECODE_START(1, it);
-
- uint32_t event_type;
- ::decode(event_type, it);
-
- // select the correct payload variant based upon the encoded op
- switch (event_type) {
- case EVENT_TYPE_AIO_DISCARD:
- event = AioDiscardEvent();
- break;
- case EVENT_TYPE_AIO_WRITE:
- event = AioWriteEvent();
- break;
- case EVENT_TYPE_AIO_FLUSH:
- event = AioFlushEvent();
- break;
- case EVENT_TYPE_OP_FINISH:
- event = OpFinishEvent();
- break;
- case EVENT_TYPE_SNAP_CREATE:
- event = SnapCreateEvent();
- break;
- case EVENT_TYPE_SNAP_REMOVE:
- event = SnapRemoveEvent();
- break;
- case EVENT_TYPE_SNAP_RENAME:
- event = SnapRenameEvent();
- break;
- case EVENT_TYPE_SNAP_PROTECT:
- event = SnapProtectEvent();
- break;
- case EVENT_TYPE_SNAP_UNPROTECT:
- event = SnapUnprotectEvent();
- break;
- case EVENT_TYPE_SNAP_ROLLBACK:
- event = SnapRollbackEvent();
- break;
- case EVENT_TYPE_RENAME:
- event = RenameEvent();
- break;
- case EVENT_TYPE_RESIZE:
- event = ResizeEvent();
- break;
- case EVENT_TYPE_FLATTEN:
- event = FlattenEvent();
- break;
- default:
- event = UnknownEvent();
- break;
- }
-
- boost::apply_visitor(DecodeEventVisitor(struct_v, it), event);
- DECODE_FINISH(it);
-}
-
-void EventEntry::dump(Formatter *f) const {
- boost::apply_visitor(DumpEventVisitor(f), event);
-}
-
-void EventEntry::generate_test_instances(std::list<EventEntry *> &o) {
- o.push_back(new EventEntry(AioDiscardEvent()));
- o.push_back(new EventEntry(AioDiscardEvent(123, 345)));
-
- bufferlist bl;
- bl.append(std::string(32, '1'));
- o.push_back(new EventEntry(AioWriteEvent()));
- o.push_back(new EventEntry(AioWriteEvent(123, 456, bl)));
-
- o.push_back(new EventEntry(AioFlushEvent()));
-
- o.push_back(new EventEntry(OpFinishEvent(123, -1)));
-
- o.push_back(new EventEntry(SnapCreateEvent()));
- o.push_back(new EventEntry(SnapCreateEvent(234, "snap")));
-
- o.push_back(new EventEntry(SnapRemoveEvent()));
- o.push_back(new EventEntry(SnapRemoveEvent(345, "snap")));
-
- o.push_back(new EventEntry(SnapRenameEvent()));
- o.push_back(new EventEntry(SnapRenameEvent(345, 1, "snap")));
-
- o.push_back(new EventEntry(SnapProtectEvent()));
- o.push_back(new EventEntry(SnapProtectEvent(456, "snap")));
-
- o.push_back(new EventEntry(SnapUnprotectEvent()));
- o.push_back(new EventEntry(SnapUnprotectEvent(567, "snap")));
-
- o.push_back(new EventEntry(SnapRollbackEvent()));
- o.push_back(new EventEntry(SnapRollbackEvent(678, "snap")));
-
- o.push_back(new EventEntry(RenameEvent()));
- o.push_back(new EventEntry(RenameEvent(789, "image name")));
-
- o.push_back(new EventEntry(ResizeEvent()));
- o.push_back(new EventEntry(ResizeEvent(890, 1234)));
-
- o.push_back(new EventEntry(FlattenEvent(901)));
-}
-
-} // namespace journal
-} // namespace librbd
-
-std::ostream &operator<<(std::ostream &out,
- const librbd::journal::EventType &type) {
- using namespace librbd::journal;
-
- switch (type) {
- case EVENT_TYPE_AIO_DISCARD:
- out << "AioDiscard";
- break;
- case EVENT_TYPE_AIO_WRITE:
- out << "AioWrite";
- break;
- case EVENT_TYPE_AIO_FLUSH:
- out << "AioFlush";
- break;
- case EVENT_TYPE_OP_FINISH:
- out << "OpFinish";
- break;
- case EVENT_TYPE_SNAP_CREATE:
- out << "SnapCreate";
- break;
- case EVENT_TYPE_SNAP_REMOVE:
- out << "SnapRemove";
- break;
- case EVENT_TYPE_SNAP_RENAME:
- out << "SnapRename";
- break;
- case EVENT_TYPE_SNAP_PROTECT:
- out << "SnapProtect";
- break;
- case EVENT_TYPE_SNAP_UNPROTECT:
- out << "SnapUnprotect";
- break;
- case EVENT_TYPE_SNAP_ROLLBACK:
- out << "SnapRollback";
- break;
- case EVENT_TYPE_RENAME:
- out << "Rename";
- break;
- case EVENT_TYPE_RESIZE:
- out << "Resize";
- break;
- case EVENT_TYPE_FLATTEN:
- out << "Flatten";
- break;
- default:
- out << "Unknown (" << static_cast<uint32_t>(type) << ")";
- break;
- }
- return out;
-}
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#ifndef CEPH_LIBRBD_JOURNAL_TYPES_H
-#define CEPH_LIBRBD_JOURNAL_TYPES_H
-
-#include "include/int_types.h"
-#include "include/buffer.h"
-#include "include/encoding.h"
-#include "include/types.h"
-#include <iosfwd>
-#include <boost/variant.hpp>
-
-namespace ceph {
-class Formatter;
-}
-
-namespace librbd {
-namespace journal {
-
-enum EventType {
- EVENT_TYPE_AIO_DISCARD = 0,
- EVENT_TYPE_AIO_WRITE = 1,
- EVENT_TYPE_AIO_FLUSH = 2,
- EVENT_TYPE_OP_FINISH = 3,
- EVENT_TYPE_SNAP_CREATE = 4,
- EVENT_TYPE_SNAP_REMOVE = 5,
- EVENT_TYPE_SNAP_RENAME = 6,
- EVENT_TYPE_SNAP_PROTECT = 7,
- EVENT_TYPE_SNAP_UNPROTECT = 8,
- EVENT_TYPE_SNAP_ROLLBACK = 9,
- EVENT_TYPE_RENAME = 10,
- EVENT_TYPE_RESIZE = 11,
- EVENT_TYPE_FLATTEN = 12
-};
-
-struct AioDiscardEvent {
- static const EventType EVENT_TYPE = EVENT_TYPE_AIO_DISCARD;
-
- uint64_t offset;
- size_t length;
-
- AioDiscardEvent() : offset(0), length(0) {
- }
- AioDiscardEvent(uint64_t _offset, size_t _length)
- : offset(_offset), length(_length) {
- }
-
- void encode(bufferlist& bl) const;
- void decode(__u8 version, bufferlist::iterator& it);
- void dump(Formatter *f) const;
-};
-
-struct AioWriteEvent {
- static const EventType EVENT_TYPE = EVENT_TYPE_AIO_WRITE;
-
- uint64_t offset;
- size_t length;
- bufferlist data;
-
- AioWriteEvent() : offset(0), length(0) {
- }
- AioWriteEvent(uint64_t _offset, size_t _length, const bufferlist &_data)
- : offset(_offset), length(_length), data(_data) {
- }
-
- void encode(bufferlist& bl) const;
- void decode(__u8 version, bufferlist::iterator& it);
- void dump(Formatter *f) const;
-};
-
-struct AioFlushEvent {
- static const EventType EVENT_TYPE = EVENT_TYPE_AIO_FLUSH;
-
- void encode(bufferlist& bl) const;
- void decode(__u8 version, bufferlist::iterator& it);
- void dump(Formatter *f) const;
-};
-
-struct OpEventBase {
- uint64_t tid;
-
- virtual void encode(bufferlist& bl) const;
- virtual void decode(__u8 version, bufferlist::iterator& it);
- virtual void dump(Formatter *f) const;
-
-protected:
- OpEventBase() : tid(0) {
- }
- OpEventBase(uint64_t _tid) : tid(_tid) {
- }
- virtual ~OpEventBase() {}
-};
-
-struct OpStartEventBase : public OpEventBase {
-protected:
- OpStartEventBase() {
- }
- OpStartEventBase(uint64_t tid) : OpEventBase(tid) {
- }
-};
-
-struct OpFinishEvent : public OpEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_OP_FINISH;
-
- int r;
-
- OpFinishEvent() : r(0) {
- }
- OpFinishEvent(uint64_t tid, int _r) : OpEventBase(tid), r(_r) {
- }
-};
-
-struct SnapEventBase : public OpStartEventBase {
- std::string snap_name;
-
- SnapEventBase() {
- }
- SnapEventBase(uint64_t tid, const std::string &_snap_name)
- : OpStartEventBase(tid), snap_name(_snap_name) {
- }
-
- virtual void encode(bufferlist& bl) const;
- virtual void decode(__u8 version, bufferlist::iterator& it);
- virtual void dump(Formatter *f) const;
-};
-
-struct SnapCreateEvent : public SnapEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_CREATE;
-
- SnapCreateEvent() {
- }
- SnapCreateEvent(uint64_t tid, const std::string &snap_name)
- : SnapEventBase(tid, snap_name) {
- }
-};
-
-struct SnapRemoveEvent : public SnapEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_REMOVE;
-
- SnapRemoveEvent() {
- }
- SnapRemoveEvent(uint64_t tid, const std::string &snap_name)
- : SnapEventBase(tid, snap_name) {
- }
-};
-
-struct SnapRenameEvent : public SnapEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_RENAME;
-
- uint64_t snap_id;
-
- SnapRenameEvent() : snap_id(CEPH_NOSNAP) {
- }
- SnapRenameEvent(uint64_t tid, uint64_t src_snap_id,
- const std::string &dest_snap_name)
- : SnapEventBase(tid, dest_snap_name), snap_id(src_snap_id) {
- }
-
- virtual void encode(bufferlist& bl) const;
- virtual void decode(__u8 version, bufferlist::iterator& it);
- virtual void dump(Formatter *f) const;
-};
-
-struct SnapProtectEvent : public SnapEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_PROTECT;
-
- SnapProtectEvent() {
- }
- SnapProtectEvent(uint64_t tid, const std::string &snap_name)
- : SnapEventBase(tid, snap_name) {
- }
-};
-
-struct SnapUnprotectEvent : public SnapEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_UNPROTECT;
-
- SnapUnprotectEvent() {
- }
- SnapUnprotectEvent(uint64_t tid, const std::string &snap_name)
- : SnapEventBase(tid, snap_name) {
- }
-};
-
-struct SnapRollbackEvent : public SnapEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_ROLLBACK;
-
- SnapRollbackEvent() {
- }
- SnapRollbackEvent(uint64_t tid, const std::string &snap_name)
- : SnapEventBase(tid, snap_name) {
- }
-};
-
-struct RenameEvent : public OpStartEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_RENAME;
-
- std::string image_name;
-
- RenameEvent() {
- }
- RenameEvent(uint64_t tid, const std::string &_image_name)
- : OpStartEventBase(tid), image_name(_image_name) {
- }
-
- virtual void encode(bufferlist& bl) const;
- virtual void decode(__u8 version, bufferlist::iterator& it);
- virtual void dump(Formatter *f) const;
-};
-
-struct ResizeEvent : public OpStartEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_RESIZE;
-
- uint64_t size;
-
- ResizeEvent() : size(0) {
- }
- ResizeEvent(uint64_t tid, uint64_t _size)
- : OpStartEventBase(tid), size(_size) {
- }
-
- virtual void encode(bufferlist& bl) const;
- virtual void decode(__u8 version, bufferlist::iterator& it);
- virtual void dump(Formatter *f) const;
-};
-
-struct FlattenEvent : public OpStartEventBase {
- static const EventType EVENT_TYPE = EVENT_TYPE_FLATTEN;
-
- FlattenEvent() {
- }
- FlattenEvent(uint64_t tid) : OpStartEventBase(tid) {
- }
-};
-
-struct UnknownEvent {
- static const EventType EVENT_TYPE = static_cast<EventType>(-1);
-
- void encode(bufferlist& bl) const;
- void decode(__u8 version, bufferlist::iterator& it);
- void dump(Formatter *f) const;
-};
-
-typedef boost::variant<AioDiscardEvent,
- AioWriteEvent,
- AioFlushEvent,
- OpFinishEvent,
- SnapCreateEvent,
- SnapRemoveEvent,
- SnapRenameEvent,
- SnapProtectEvent,
- SnapUnprotectEvent,
- SnapRollbackEvent,
- RenameEvent,
- ResizeEvent,
- FlattenEvent,
- UnknownEvent> Event;
-
-struct EventEntry {
- EventEntry() : event(UnknownEvent()) {
- }
- EventEntry(const Event &_event) : event(_event) {
- }
-
- Event event;
-
- EventType get_event_type() const;
-
- void encode(bufferlist& bl) const;
- void decode(bufferlist::iterator& it);
- void dump(Formatter *f) const;
-
- static void generate_test_instances(std::list<EventEntry *> &o);
-};
-
-} // namespace journal
-} // namespace librbd
-
-std::ostream &operator<<(std::ostream &out,
- const librbd::journal::EventType &type);
-
-WRITE_CLASS_ENCODER(librbd::journal::EventEntry);
-
-#endif // CEPH_LIBRBD_JOURNAL_TYPES_H
librbd_types_la_SOURCES = \
- librbd/JournalTypes.cc \
+ librbd/journal/Entries.cc \
librbd/WatchNotifyTypes.cc
noinst_LTLIBRARIES += librbd_types.la
librbd/ImageWatcher.cc \
librbd/internal.cc \
librbd/Journal.cc \
- librbd/JournalReplay.cc \
librbd/LibrbdAdminSocketHook.cc \
librbd/LibrbdWriteback.cc \
librbd/ObjectMap.cc \
librbd/image/RefreshParentRequest.cc \
librbd/image/RefreshRequest.cc \
librbd/image/SetSnapRequest.cc \
+ librbd/journal/Replay.cc \
librbd/object_map/InvalidateRequest.cc \
librbd/object_map/LockRequest.cc \
librbd/object_map/Request.cc \
librbd/ImageWatcher.h \
librbd/internal.h \
librbd/Journal.h \
- librbd/JournalReplay.h \
- librbd/JournalTypes.h \
librbd/LibrbdAdminSocketHook.h \
librbd/LibrbdWriteback.h \
librbd/ObjectMap.h \
librbd/image/RefreshParentRequest.h \
librbd/image/RefreshRequest.h \
librbd/image/SetSnapRequest.h \
+ librbd/journal/Replay.h \
+ librbd/journal/Entries.h \
librbd/object_map/InvalidateRequest.h \
librbd/object_map/LockRequest.h \
librbd/object_map/Request.h \
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/journal/Entries.h"
+#include "include/assert.h"
+#include "include/stringify.h"
+#include "common/Formatter.h"
+
+namespace librbd {
+namespace journal {
+
+namespace {
+
+class GetEventTypeVistor : public boost::static_visitor<EventType> {
+public:
+ template <typename Event>
+ inline EventType operator()(const Event &event) const {
+ return Event::EVENT_TYPE;
+ }
+};
+
+class EncodeEventVisitor : public boost::static_visitor<void> {
+public:
+ EncodeEventVisitor(bufferlist &bl) : m_bl(bl) {
+ }
+
+ template <typename Event>
+ inline void operator()(const Event &event) const {
+ ::encode(static_cast<uint32_t>(Event::EVENT_TYPE), m_bl);
+ event.encode(m_bl);
+ }
+private:
+ bufferlist &m_bl;
+};
+
+class DecodeEventVisitor : public boost::static_visitor<void> {
+public:
+ DecodeEventVisitor(__u8 version, bufferlist::iterator &iter)
+ : m_version(version), m_iter(iter) {
+ }
+
+ template <typename Event>
+ inline void operator()(Event &event) const {
+ event.decode(m_version, m_iter);
+ }
+private:
+ __u8 m_version;
+ bufferlist::iterator &m_iter;
+};
+
+class DumpEventVisitor : public boost::static_visitor<void> {
+public:
+ DumpEventVisitor(Formatter *formatter) : m_formatter(formatter) {}
+
+ template <typename Event>
+ inline void operator()(const Event &event) const {
+ EventType event_type = Event::EVENT_TYPE;
+ m_formatter->dump_string("event_type", stringify(event_type));
+ event.dump(m_formatter);
+ }
+private:
+ ceph::Formatter *m_formatter;
+};
+
+} // anonymous namespace
+
+void AioDiscardEvent::encode(bufferlist& bl) const {
+ ::encode(offset, bl);
+ ::encode(length, bl);
+}
+
+void AioDiscardEvent::decode(__u8 version, bufferlist::iterator& it) {
+ ::decode(offset, it);
+ ::decode(length, it);
+}
+
+void AioDiscardEvent::dump(Formatter *f) const {
+ f->dump_unsigned("offset", offset);
+ f->dump_unsigned("length", length);
+}
+
+void AioWriteEvent::encode(bufferlist& bl) const {
+ ::encode(offset, bl);
+ ::encode(length, bl);
+ ::encode(data, bl);
+}
+
+void AioWriteEvent::decode(__u8 version, bufferlist::iterator& it) {
+ ::decode(offset, it);
+ ::decode(length, it);
+ ::decode(data, it);
+}
+
+void AioWriteEvent::dump(Formatter *f) const {
+ f->dump_unsigned("offset", offset);
+ f->dump_unsigned("length", length);
+}
+
+void AioFlushEvent::encode(bufferlist& bl) const {
+}
+
+void AioFlushEvent::decode(__u8 version, bufferlist::iterator& it) {
+}
+
+void AioFlushEvent::dump(Formatter *f) const {
+}
+
+void OpEventBase::encode(bufferlist& bl) const {
+ ::encode(tid, bl);
+}
+
+void OpEventBase::decode(__u8 version, bufferlist::iterator& it) {
+ ::decode(tid, it);
+}
+
+void OpEventBase::dump(Formatter *f) const {
+ f->dump_unsigned("tid", tid);
+}
+
+void SnapEventBase::encode(bufferlist& bl) const {
+ OpStartEventBase::encode(bl);
+ ::encode(snap_name, bl);
+}
+
+void SnapEventBase::decode(__u8 version, bufferlist::iterator& it) {
+ OpStartEventBase::decode(version, it);
+ ::decode(snap_name, it);
+}
+
+void SnapEventBase::dump(Formatter *f) const {
+ OpStartEventBase::dump(f);
+ f->dump_string("snap_name", snap_name);
+}
+
+void SnapRenameEvent::encode(bufferlist& bl) const {
+ SnapEventBase::encode(bl);
+ ::encode(snap_id, bl);
+}
+
+void SnapRenameEvent::decode(__u8 version, bufferlist::iterator& it) {
+ SnapEventBase::decode(version, it);
+ ::decode(snap_id, it);
+}
+
+void SnapRenameEvent::dump(Formatter *f) const {
+ OpStartEventBase::dump(f);
+ f->dump_unsigned("src_snap_id", snap_id);
+ f->dump_string("dest_snap_name", snap_name);
+}
+
+void RenameEvent::encode(bufferlist& bl) const {
+ OpStartEventBase::encode(bl);
+ ::encode(image_name, bl);
+}
+
+void RenameEvent::decode(__u8 version, bufferlist::iterator& it) {
+ OpStartEventBase::decode(version, it);
+ ::decode(image_name, it);
+}
+
+void RenameEvent::dump(Formatter *f) const {
+ OpStartEventBase::dump(f);
+ f->dump_string("image_name", image_name);
+}
+
+void ResizeEvent::encode(bufferlist& bl) const {
+ OpStartEventBase::encode(bl);
+ ::encode(size, bl);
+}
+
+void ResizeEvent::decode(__u8 version, bufferlist::iterator& it) {
+ OpStartEventBase::decode(version, it);
+ ::decode(size, it);
+}
+
+void ResizeEvent::dump(Formatter *f) const {
+ OpStartEventBase::dump(f);
+ f->dump_unsigned("size", size);
+}
+
+void UnknownEvent::encode(bufferlist& bl) const {
+ assert(false);
+}
+
+void UnknownEvent::decode(__u8 version, bufferlist::iterator& it) {
+}
+
+void UnknownEvent::dump(Formatter *f) const {
+}
+
+EventType EventEntry::get_event_type() const {
+ return boost::apply_visitor(GetEventTypeVistor(), event);
+}
+
+void EventEntry::encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ boost::apply_visitor(EncodeEventVisitor(bl), event);
+ ENCODE_FINISH(bl);
+}
+
+void EventEntry::decode(bufferlist::iterator& it) {
+ DECODE_START(1, it);
+
+ uint32_t event_type;
+ ::decode(event_type, it);
+
+ // select the correct payload variant based upon the encoded op
+ switch (event_type) {
+ case EVENT_TYPE_AIO_DISCARD:
+ event = AioDiscardEvent();
+ break;
+ case EVENT_TYPE_AIO_WRITE:
+ event = AioWriteEvent();
+ break;
+ case EVENT_TYPE_AIO_FLUSH:
+ event = AioFlushEvent();
+ break;
+ case EVENT_TYPE_OP_FINISH:
+ event = OpFinishEvent();
+ break;
+ case EVENT_TYPE_SNAP_CREATE:
+ event = SnapCreateEvent();
+ break;
+ case EVENT_TYPE_SNAP_REMOVE:
+ event = SnapRemoveEvent();
+ break;
+ case EVENT_TYPE_SNAP_RENAME:
+ event = SnapRenameEvent();
+ break;
+ case EVENT_TYPE_SNAP_PROTECT:
+ event = SnapProtectEvent();
+ break;
+ case EVENT_TYPE_SNAP_UNPROTECT:
+ event = SnapUnprotectEvent();
+ break;
+ case EVENT_TYPE_SNAP_ROLLBACK:
+ event = SnapRollbackEvent();
+ break;
+ case EVENT_TYPE_RENAME:
+ event = RenameEvent();
+ break;
+ case EVENT_TYPE_RESIZE:
+ event = ResizeEvent();
+ break;
+ case EVENT_TYPE_FLATTEN:
+ event = FlattenEvent();
+ break;
+ default:
+ event = UnknownEvent();
+ break;
+ }
+
+ boost::apply_visitor(DecodeEventVisitor(struct_v, it), event);
+ DECODE_FINISH(it);
+}
+
+void EventEntry::dump(Formatter *f) const {
+ boost::apply_visitor(DumpEventVisitor(f), event);
+}
+
+void EventEntry::generate_test_instances(std::list<EventEntry *> &o) {
+ o.push_back(new EventEntry(AioDiscardEvent()));
+ o.push_back(new EventEntry(AioDiscardEvent(123, 345)));
+
+ bufferlist bl;
+ bl.append(std::string(32, '1'));
+ o.push_back(new EventEntry(AioWriteEvent()));
+ o.push_back(new EventEntry(AioWriteEvent(123, 456, bl)));
+
+ o.push_back(new EventEntry(AioFlushEvent()));
+
+ o.push_back(new EventEntry(OpFinishEvent(123, -1)));
+
+ o.push_back(new EventEntry(SnapCreateEvent()));
+ o.push_back(new EventEntry(SnapCreateEvent(234, "snap")));
+
+ o.push_back(new EventEntry(SnapRemoveEvent()));
+ o.push_back(new EventEntry(SnapRemoveEvent(345, "snap")));
+
+ o.push_back(new EventEntry(SnapRenameEvent()));
+ o.push_back(new EventEntry(SnapRenameEvent(345, 1, "snap")));
+
+ o.push_back(new EventEntry(SnapProtectEvent()));
+ o.push_back(new EventEntry(SnapProtectEvent(456, "snap")));
+
+ o.push_back(new EventEntry(SnapUnprotectEvent()));
+ o.push_back(new EventEntry(SnapUnprotectEvent(567, "snap")));
+
+ o.push_back(new EventEntry(SnapRollbackEvent()));
+ o.push_back(new EventEntry(SnapRollbackEvent(678, "snap")));
+
+ o.push_back(new EventEntry(RenameEvent()));
+ o.push_back(new EventEntry(RenameEvent(789, "image name")));
+
+ o.push_back(new EventEntry(ResizeEvent()));
+ o.push_back(new EventEntry(ResizeEvent(890, 1234)));
+
+ o.push_back(new EventEntry(FlattenEvent(901)));
+}
+
+} // namespace journal
+} // namespace librbd
+
+std::ostream &operator<<(std::ostream &out,
+ const librbd::journal::EventType &type) {
+ using namespace librbd::journal;
+
+ switch (type) {
+ case EVENT_TYPE_AIO_DISCARD:
+ out << "AioDiscard";
+ break;
+ case EVENT_TYPE_AIO_WRITE:
+ out << "AioWrite";
+ break;
+ case EVENT_TYPE_AIO_FLUSH:
+ out << "AioFlush";
+ break;
+ case EVENT_TYPE_OP_FINISH:
+ out << "OpFinish";
+ break;
+ case EVENT_TYPE_SNAP_CREATE:
+ out << "SnapCreate";
+ break;
+ case EVENT_TYPE_SNAP_REMOVE:
+ out << "SnapRemove";
+ break;
+ case EVENT_TYPE_SNAP_RENAME:
+ out << "SnapRename";
+ break;
+ case EVENT_TYPE_SNAP_PROTECT:
+ out << "SnapProtect";
+ break;
+ case EVENT_TYPE_SNAP_UNPROTECT:
+ out << "SnapUnprotect";
+ break;
+ case EVENT_TYPE_SNAP_ROLLBACK:
+ out << "SnapRollback";
+ break;
+ case EVENT_TYPE_RENAME:
+ out << "Rename";
+ break;
+ case EVENT_TYPE_RESIZE:
+ out << "Resize";
+ break;
+ case EVENT_TYPE_FLATTEN:
+ out << "Flatten";
+ break;
+ default:
+ out << "Unknown (" << static_cast<uint32_t>(type) << ")";
+ break;
+ }
+ return out;
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_JOURNAL_ENTRIES_H
+#define CEPH_LIBRBD_JOURNAL_ENTRIES_H
+
+#include "include/int_types.h"
+#include "include/buffer.h"
+#include "include/encoding.h"
+#include "include/types.h"
+#include <iosfwd>
+#include <boost/variant.hpp>
+
+namespace ceph {
+class Formatter;
+}
+
+namespace librbd {
+namespace journal {
+
+enum EventType {
+ EVENT_TYPE_AIO_DISCARD = 0,
+ EVENT_TYPE_AIO_WRITE = 1,
+ EVENT_TYPE_AIO_FLUSH = 2,
+ EVENT_TYPE_OP_FINISH = 3,
+ EVENT_TYPE_SNAP_CREATE = 4,
+ EVENT_TYPE_SNAP_REMOVE = 5,
+ EVENT_TYPE_SNAP_RENAME = 6,
+ EVENT_TYPE_SNAP_PROTECT = 7,
+ EVENT_TYPE_SNAP_UNPROTECT = 8,
+ EVENT_TYPE_SNAP_ROLLBACK = 9,
+ EVENT_TYPE_RENAME = 10,
+ EVENT_TYPE_RESIZE = 11,
+ EVENT_TYPE_FLATTEN = 12
+};
+
+struct AioDiscardEvent {
+ static const EventType EVENT_TYPE = EVENT_TYPE_AIO_DISCARD;
+
+ uint64_t offset;
+ size_t length;
+
+ AioDiscardEvent() : offset(0), length(0) {
+ }
+ AioDiscardEvent(uint64_t _offset, size_t _length)
+ : offset(_offset), length(_length) {
+ }
+
+ void encode(bufferlist& bl) const;
+ void decode(__u8 version, bufferlist::iterator& it);
+ void dump(Formatter *f) const;
+};
+
+struct AioWriteEvent {
+ static const EventType EVENT_TYPE = EVENT_TYPE_AIO_WRITE;
+
+ uint64_t offset;
+ size_t length;
+ bufferlist data;
+
+ AioWriteEvent() : offset(0), length(0) {
+ }
+ AioWriteEvent(uint64_t _offset, size_t _length, const bufferlist &_data)
+ : offset(_offset), length(_length), data(_data) {
+ }
+
+ void encode(bufferlist& bl) const;
+ void decode(__u8 version, bufferlist::iterator& it);
+ void dump(Formatter *f) const;
+};
+
+struct AioFlushEvent {
+ static const EventType EVENT_TYPE = EVENT_TYPE_AIO_FLUSH;
+
+ void encode(bufferlist& bl) const;
+ void decode(__u8 version, bufferlist::iterator& it);
+ void dump(Formatter *f) const;
+};
+
+struct OpEventBase {
+ uint64_t tid;
+
+ virtual void encode(bufferlist& bl) const;
+ virtual void decode(__u8 version, bufferlist::iterator& it);
+ virtual void dump(Formatter *f) const;
+
+protected:
+ OpEventBase() : tid(0) {
+ }
+ OpEventBase(uint64_t _tid) : tid(_tid) {
+ }
+ virtual ~OpEventBase() {}
+};
+
+struct OpStartEventBase : public OpEventBase {
+protected:
+ OpStartEventBase() {
+ }
+ OpStartEventBase(uint64_t tid) : OpEventBase(tid) {
+ }
+};
+
+struct OpFinishEvent : public OpEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_OP_FINISH;
+
+ int r;
+
+ OpFinishEvent() : r(0) {
+ }
+ OpFinishEvent(uint64_t tid, int _r) : OpEventBase(tid), r(_r) {
+ }
+};
+
+struct SnapEventBase : public OpStartEventBase {
+ std::string snap_name;
+
+ SnapEventBase() {
+ }
+ SnapEventBase(uint64_t tid, const std::string &_snap_name)
+ : OpStartEventBase(tid), snap_name(_snap_name) {
+ }
+
+ virtual void encode(bufferlist& bl) const;
+ virtual void decode(__u8 version, bufferlist::iterator& it);
+ virtual void dump(Formatter *f) const;
+};
+
+struct SnapCreateEvent : public SnapEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_CREATE;
+
+ SnapCreateEvent() {
+ }
+ SnapCreateEvent(uint64_t tid, const std::string &snap_name)
+ : SnapEventBase(tid, snap_name) {
+ }
+};
+
+struct SnapRemoveEvent : public SnapEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_REMOVE;
+
+ SnapRemoveEvent() {
+ }
+ SnapRemoveEvent(uint64_t tid, const std::string &snap_name)
+ : SnapEventBase(tid, snap_name) {
+ }
+};
+
+struct SnapRenameEvent : public SnapEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_RENAME;
+
+ uint64_t snap_id;
+
+ SnapRenameEvent() : snap_id(CEPH_NOSNAP) {
+ }
+ SnapRenameEvent(uint64_t tid, uint64_t src_snap_id,
+ const std::string &dest_snap_name)
+ : SnapEventBase(tid, dest_snap_name), snap_id(src_snap_id) {
+ }
+
+ virtual void encode(bufferlist& bl) const;
+ virtual void decode(__u8 version, bufferlist::iterator& it);
+ virtual void dump(Formatter *f) const;
+};
+
+struct SnapProtectEvent : public SnapEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_PROTECT;
+
+ SnapProtectEvent() {
+ }
+ SnapProtectEvent(uint64_t tid, const std::string &snap_name)
+ : SnapEventBase(tid, snap_name) {
+ }
+};
+
+struct SnapUnprotectEvent : public SnapEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_UNPROTECT;
+
+ SnapUnprotectEvent() {
+ }
+ SnapUnprotectEvent(uint64_t tid, const std::string &snap_name)
+ : SnapEventBase(tid, snap_name) {
+ }
+};
+
+struct SnapRollbackEvent : public SnapEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_SNAP_ROLLBACK;
+
+ SnapRollbackEvent() {
+ }
+ SnapRollbackEvent(uint64_t tid, const std::string &snap_name)
+ : SnapEventBase(tid, snap_name) {
+ }
+};
+
+struct RenameEvent : public OpStartEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_RENAME;
+
+ std::string image_name;
+
+ RenameEvent() {
+ }
+ RenameEvent(uint64_t tid, const std::string &_image_name)
+ : OpStartEventBase(tid), image_name(_image_name) {
+ }
+
+ virtual void encode(bufferlist& bl) const;
+ virtual void decode(__u8 version, bufferlist::iterator& it);
+ virtual void dump(Formatter *f) const;
+};
+
+struct ResizeEvent : public OpStartEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_RESIZE;
+
+ uint64_t size;
+
+ ResizeEvent() : size(0) {
+ }
+ ResizeEvent(uint64_t tid, uint64_t _size)
+ : OpStartEventBase(tid), size(_size) {
+ }
+
+ virtual void encode(bufferlist& bl) const;
+ virtual void decode(__u8 version, bufferlist::iterator& it);
+ virtual void dump(Formatter *f) const;
+};
+
+struct FlattenEvent : public OpStartEventBase {
+ static const EventType EVENT_TYPE = EVENT_TYPE_FLATTEN;
+
+ FlattenEvent() {
+ }
+ FlattenEvent(uint64_t tid) : OpStartEventBase(tid) {
+ }
+};
+
+struct UnknownEvent {
+ static const EventType EVENT_TYPE = static_cast<EventType>(-1);
+
+ void encode(bufferlist& bl) const;
+ void decode(__u8 version, bufferlist::iterator& it);
+ void dump(Formatter *f) const;
+};
+
+typedef boost::variant<AioDiscardEvent,
+ AioWriteEvent,
+ AioFlushEvent,
+ OpFinishEvent,
+ SnapCreateEvent,
+ SnapRemoveEvent,
+ SnapRenameEvent,
+ SnapProtectEvent,
+ SnapUnprotectEvent,
+ SnapRollbackEvent,
+ RenameEvent,
+ ResizeEvent,
+ FlattenEvent,
+ UnknownEvent> Event;
+
+struct EventEntry {
+ EventEntry() : event(UnknownEvent()) {
+ }
+ EventEntry(const Event &_event) : event(_event) {
+ }
+
+ Event event;
+
+ EventType get_event_type() const;
+
+ void encode(bufferlist& bl) const;
+ void decode(bufferlist::iterator& it);
+ void dump(Formatter *f) const;
+
+ static void generate_test_instances(std::list<EventEntry *> &o);
+};
+
+} // namespace journal
+} // namespace librbd
+
+std::ostream &operator<<(std::ostream &out,
+ const librbd::journal::EventType &type);
+
+WRITE_CLASS_ENCODER(librbd::journal::EventEntry);
+
+#endif // CEPH_LIBRBD_JOURNAL_ENTRIES_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/journal/Replay.h"
+#include "librbd/AioCompletion.h"
+#include "librbd/AioImageRequest.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/internal.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::journal::Replay: "
+
+namespace librbd {
+namespace journal {
+
+Replay::Replay(ImageCtx &image_ctx)
+ : m_image_ctx(image_ctx), m_lock("Replay::m_lock"), m_ret_val(0) {
+}
+
+Replay::~Replay() {
+ assert(m_aio_completions.empty());
+}
+
+int Replay::process(bufferlist::iterator it, Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << dendl;
+
+ RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+ journal::EventEntry event_entry;
+ try {
+ ::decode(event_entry, it);
+ } catch (const buffer::error &err) {
+ lderr(cct) << "failed to decode event entry: " << err.what() << dendl;
+ return -EINVAL;
+ }
+
+ boost::apply_visitor(EventVisitor(this, on_safe), event_entry.event);
+ return 0;
+}
+
+int Replay::flush() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << dendl;
+
+ Mutex::Locker locker(m_lock);
+ while (!m_aio_completions.empty()) {
+ m_cond.Wait(m_lock);
+ }
+ return m_ret_val;
+}
+
+void Replay::handle_event(const journal::AioDiscardEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": AIO discard event" << dendl;
+
+ AioCompletion *aio_comp = create_aio_completion(on_safe);
+ AioImageRequest::aio_discard(&m_image_ctx, aio_comp, event.offset,
+ event.length);
+}
+
+void Replay::handle_event(const journal::AioWriteEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": AIO write event" << dendl;
+
+ bufferlist data = event.data;
+ AioCompletion *aio_comp = create_aio_completion(on_safe);
+ AioImageRequest::aio_write(&m_image_ctx, aio_comp, event.offset, event.length,
+ data.c_str(), 0);
+}
+
+void Replay::handle_event(const journal::AioFlushEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": AIO flush event" << dendl;
+
+ AioCompletion *aio_comp = create_aio_completion(on_safe);
+ AioImageRequest::aio_flush(&m_image_ctx, aio_comp);
+}
+
+ void Replay::handle_event(const journal::OpFinishEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Op finish event" << dendl;
+}
+
+void Replay::handle_event(const journal::SnapCreateEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Snap create event" << dendl;
+}
+
+void Replay::handle_event(const journal::SnapRemoveEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Snap remove event" << dendl;
+}
+
+void Replay::handle_event(const journal::SnapRenameEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Snap rename event" << dendl;
+}
+
+void Replay::handle_event(const journal::SnapProtectEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Snap protect event" << dendl;
+}
+
+void Replay::handle_event(const journal::SnapUnprotectEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Snap unprotect event"
+ << dendl;
+}
+
+void Replay::handle_event(const journal::SnapRollbackEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Snap rollback start event"
+ << dendl;
+}
+
+void Replay::handle_event(const journal::RenameEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Rename event" << dendl;
+}
+
+void Replay::handle_event(const journal::ResizeEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Resize start event" << dendl;
+}
+
+void Replay::handle_event(const journal::FlattenEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": Flatten start event" << dendl;
+}
+
+void Replay::handle_event(const journal::UnknownEvent &event,
+ Context *on_safe) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": unknown event" << dendl;
+ on_safe->complete(0);
+}
+
+AioCompletion *Replay::create_aio_completion(Context *on_safe) {
+ Mutex::Locker locker(m_lock);
+ AioCompletion *aio_comp = AioCompletion::create(this, aio_completion_callback,
+ nullptr);
+ m_aio_completions.insert(std::pair<AioCompletion*,Context*>(
+ aio_comp, on_safe));
+ return aio_comp;
+}
+
+void Replay::handle_aio_completion(AioCompletion *aio_comp) {
+ Mutex::Locker locker(m_lock);
+
+ AioCompletions::iterator it = m_aio_completions.find(aio_comp);
+ assert(it != m_aio_completions.end());
+
+ int r = aio_comp->get_return_value();
+
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": aio_comp=" << aio_comp << ", "
+ << "r=" << r << dendl;
+
+ Context *on_safe = it->second;
+ on_safe->complete(r);
+
+ if (r < 0 && m_ret_val == 0) {
+ m_ret_val = r;
+ }
+
+ m_aio_completions.erase(it);
+ if (m_aio_completions.empty())
+ m_cond.Signal();
+}
+
+void Replay::aio_completion_callback(completion_t cb, void *arg) {
+ Replay *replay = reinterpret_cast<Replay *>(arg);
+ AioCompletion *aio_comp = reinterpret_cast<AioCompletion *>(cb);
+
+ replay->handle_aio_completion(aio_comp);
+ aio_comp->release();
+}
+
+} // namespace journal
+} // namespace librbd
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_JOURNAL_REPLAY_H
+#define CEPH_LIBRBD_JOURNAL_REPLAY_H
+
+#include "include/int_types.h"
+#include "include/buffer_fwd.h"
+#include "include/rbd/librbd.hpp"
+#include "common/Cond.h"
+#include "common/Mutex.h"
+#include "librbd/journal/Entries.h"
+#include <boost/variant.hpp>
+#include <map>
+
+namespace librbd {
+
+class AioCompletion;
+class ImageCtx;
+
+namespace journal {
+
+class Replay {
+public:
+ Replay(ImageCtx &image_ctx);
+ ~Replay();
+
+ int process(bufferlist::iterator it, Context *on_safe = NULL);
+ int flush();
+
+private:
+ typedef std::map<AioCompletion*,Context*> AioCompletions;
+
+ struct EventVisitor : public boost::static_visitor<void> {
+ Replay *replay;
+ Context *on_safe;
+
+ EventVisitor(Replay *_replay, Context *_on_safe)
+ : replay(_replay), on_safe(_on_safe) {
+ }
+
+ template <typename Event>
+ inline void operator()(const Event &event) const {
+ replay->handle_event(event, on_safe);
+ }
+ };
+
+ ImageCtx &m_image_ctx;
+
+ Mutex m_lock;
+ Cond m_cond;
+
+ AioCompletions m_aio_completions;
+ int m_ret_val;
+
+ void handle_event(const AioDiscardEvent &event, Context *on_safe);
+ void handle_event(const AioWriteEvent &event, Context *on_safe);
+ void handle_event(const AioFlushEvent &event, Context *on_safe);
+ void handle_event(const OpFinishEvent &event, Context *on_safe);
+ void handle_event(const SnapCreateEvent &event, Context *on_safe);
+ void handle_event(const SnapRemoveEvent &event, Context *on_safe);
+ void handle_event(const SnapRenameEvent &event, Context *on_safe);
+ void handle_event(const SnapProtectEvent &event, Context *on_safe);
+ void handle_event(const SnapUnprotectEvent &event, Context *on_safe);
+ void handle_event(const SnapRollbackEvent &event, Context *on_safe);
+ void handle_event(const RenameEvent &event, Context *on_safe);
+ void handle_event(const ResizeEvent &event, Context *on_safe);
+ void handle_event(const FlattenEvent &event, Context *on_safe);
+ void handle_event(const UnknownEvent &event, Context *on_safe);
+
+ AioCompletion *create_aio_completion(Context *on_safe);
+ void handle_aio_completion(AioCompletion *aio_comp);
+
+ static void aio_completion_callback(completion_t cb, void *arg);
+};
+
+} // namespace journal
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_JOURNAL_REPLAY_H
#include "librbd/AsyncRequest.h"
#include "include/Context.h"
-#include "librbd/JournalTypes.h"
+#include "librbd/journal/Entries.h"
namespace librbd {
test/librbd/test_librbd.cc \
test/librbd/test_ImageWatcher.cc \
test/librbd/test_internal.cc \
- test/librbd/test_JournalEntries.cc \
- test/librbd/test_JournalReplay.cc \
- test/librbd/test_ObjectMap.cc
+ test/librbd/test_ObjectMap.cc \
+ test/librbd/journal/test_Entries.cc \
+ test/librbd/journal/test_Replay.cc
librbd_test_la_CXXFLAGS = $(UNITTEST_CXXFLAGS)
noinst_LTLIBRARIES += librbd_test.la
TYPE(EUpdate)
#ifdef WITH_RBD
-#include "librbd/JournalTypes.h"
+#include "librbd/journal/Entries.h"
TYPE(librbd::journal::EventEntry)
#include "librbd/WatchNotifyTypes.h"
TYPE(librbd::watch_notify::NotifyMessage)
--- /dev/null
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_fixture.h"
+#include "test/librbd/test_support.h"
+#include "librbd/AioCompletion.h"
+#include "librbd/AioImageRequestWQ.h"
+#include "librbd/internal.h"
+#include "librbd/Journal.h"
+#include "librbd/journal/Entries.h"
+#include "journal/Journaler.h"
+#include "journal/ReplayEntry.h"
+#include "journal/ReplayHandler.h"
+#include <list>
+#include <boost/variant.hpp>
+
+void register_test_journal_entries() {
+}
+
+class TestJournalEntries : public TestFixture {
+public:
+ typedef std::list<journal::Journaler *> Journalers;
+
+ struct ReplayHandler : public journal::ReplayHandler {
+ Mutex lock;
+ Cond cond;
+ bool entries_available;
+ bool complete;
+
+ ReplayHandler()
+ : lock("ReplayHandler::lock"), entries_available(false), complete(false) {
+ }
+
+ virtual void get() {
+ }
+ virtual void put() {
+ }
+
+ virtual void handle_entries_available() {
+ Mutex::Locker locker(lock);
+ entries_available = true;
+ cond.Signal();
+ }
+
+ virtual void handle_complete(int r) {
+ Mutex::Locker locker(lock);
+ complete = true;
+ cond.Signal();
+ }
+ };
+
+ ReplayHandler m_replay_handler;
+ Journalers m_journalers;
+
+ virtual void TearDown() {
+ for (Journalers::iterator it = m_journalers.begin();
+ it != m_journalers.end(); ++it) {
+ journal::Journaler *journaler = *it;
+ journaler->stop_replay();
+ delete journaler;
+ }
+
+ TestFixture::TearDown();
+ }
+
+ journal::Journaler *create_journaler(librbd::ImageCtx *ictx) {
+ journal::Journaler *journaler = new journal::Journaler(
+ ictx->md_ctx, ictx->id, "dummy client", 1);
+
+ int r = journaler->register_client("unit test client");
+ if (r < 0) {
+ ADD_FAILURE() << "failed to register journal client";
+ delete journaler;
+ return NULL;
+ }
+
+ C_SaferCond cond;
+ journaler->init(&cond);
+ r = cond.wait();
+ if (r < 0) {
+ ADD_FAILURE() << "failed to initialize journal client";
+ delete journaler;
+ return NULL;
+ }
+
+ journaler->start_live_replay(&m_replay_handler, 0.1);
+ m_journalers.push_back(journaler);
+ return journaler;
+ }
+
+ bool wait_for_entries_available(librbd::ImageCtx *ictx) {
+ Mutex::Locker locker(m_replay_handler.lock);
+ while (!m_replay_handler.entries_available) {
+ if (m_replay_handler.cond.WaitInterval(ictx->cct, m_replay_handler.lock,
+ utime_t(10, 0)) != 0) {
+ return false;
+ }
+ }
+ m_replay_handler.entries_available = false;
+ return true;
+ }
+
+ bool get_event_entry(const journal::ReplayEntry &replay_entry,
+ librbd::journal::EventEntry *event_entry) {
+ try {
+ bufferlist data_bl = replay_entry.get_data();
+ bufferlist::iterator it = data_bl.begin();
+ ::decode(*event_entry, it);
+ } catch (const buffer::error &err) {
+ return false;
+ }
+ return true;
+ }
+
+};
+
+TEST_F(TestJournalEntries, AioWrite) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ journal::Journaler *journaler = create_journaler(ictx);
+ ASSERT_TRUE(journaler != NULL);
+
+ std::string buffer(512, '1');
+ C_SaferCond cond_ctx;
+ librbd::AioCompletion *c = librbd::AioCompletion::create(&cond_ctx);
+ c->get();
+ ictx->aio_work_queue->aio_write(c, 123, buffer.size(), buffer.c_str(), 0);
+ ASSERT_EQ(0, c->wait_for_complete());
+ c->put();
+
+ ASSERT_TRUE(wait_for_entries_available(ictx));
+
+ journal::ReplayEntry replay_entry;
+ ASSERT_TRUE(journaler->try_pop_front(&replay_entry));
+
+ librbd::journal::EventEntry event_entry;
+ ASSERT_TRUE(get_event_entry(replay_entry, &event_entry));
+
+ ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_WRITE,
+ event_entry.get_event_type());
+
+ librbd::journal::AioWriteEvent aio_write_event =
+ boost::get<librbd::journal::AioWriteEvent>(event_entry.event);
+ ASSERT_EQ(123U, aio_write_event.offset);
+ ASSERT_EQ(buffer.size(), aio_write_event.length);
+
+ bufferlist buffer_bl;
+ buffer_bl.append(buffer);
+ ASSERT_TRUE(aio_write_event.data.contents_equal(buffer_bl));
+}
+
+TEST_F(TestJournalEntries, AioDiscard) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ journal::Journaler *journaler = create_journaler(ictx);
+ ASSERT_TRUE(journaler != NULL);
+
+ C_SaferCond cond_ctx;
+ librbd::AioCompletion *c = librbd::AioCompletion::create(&cond_ctx);
+ c->get();
+ ictx->aio_work_queue->aio_discard(c, 123, 234);
+ ASSERT_EQ(0, c->wait_for_complete());
+ c->put();
+
+ ASSERT_TRUE(wait_for_entries_available(ictx));
+
+ journal::ReplayEntry replay_entry;
+ ASSERT_TRUE(journaler->try_pop_front(&replay_entry));
+
+ librbd::journal::EventEntry event_entry;
+ ASSERT_TRUE(get_event_entry(replay_entry, &event_entry));
+
+ ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_DISCARD,
+ event_entry.get_event_type());
+
+ librbd::journal::AioDiscardEvent aio_discard_event =
+ boost::get<librbd::journal::AioDiscardEvent>(event_entry.event);
+ ASSERT_EQ(123U, aio_discard_event.offset);
+ ASSERT_EQ(234U, aio_discard_event.length);
+}
+
+TEST_F(TestJournalEntries, AioFlush) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ journal::Journaler *journaler = create_journaler(ictx);
+ ASSERT_TRUE(journaler != NULL);
+
+ C_SaferCond cond_ctx;
+ librbd::AioCompletion *c = librbd::AioCompletion::create(&cond_ctx);
+ c->get();
+ ictx->aio_work_queue->aio_flush(c);
+ ASSERT_EQ(0, c->wait_for_complete());
+ c->put();
+
+ ASSERT_TRUE(wait_for_entries_available(ictx));
+
+ journal::ReplayEntry replay_entry;
+ ASSERT_TRUE(journaler->try_pop_front(&replay_entry));
+
+ librbd::journal::EventEntry event_entry;
+ ASSERT_TRUE(get_event_entry(replay_entry, &event_entry));
+
+ ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_FLUSH,
+ event_entry.get_event_type());
+}
--- /dev/null
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_fixture.h"
+#include "test/librbd/test_support.h"
+#include "librbd/AioCompletion.h"
+#include "librbd/AioImageRequest.h"
+#include "librbd/AioImageRequestWQ.h"
+#include "librbd/ExclusiveLock.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ImageWatcher.h"
+#include "librbd/Journal.h"
+#include "librbd/journal/Entries.h"
+
+void register_test_journal_replay() {
+}
+
+class TestJournalReplay : public TestFixture {
+public:
+
+ int when_acquired_lock(librbd::ImageCtx *ictx) {
+ C_SaferCond lock_ctx;
+ {
+ RWLock::WLocker owner_locker(ictx->owner_lock);
+ ictx->exclusive_lock->request_lock(&lock_ctx);
+ }
+ return lock_ctx.wait();
+ }
+};
+
+TEST_F(TestJournalReplay, AioDiscardEvent) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ // write to the image w/o using the journal
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ictx->features &= ~RBD_FEATURE_JOURNALING;
+
+ std::string payload(4096, '1');
+ librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
+ ictx->aio_work_queue->aio_write(aio_comp, 0, payload.size(), payload.c_str(),
+ 0);
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ aio_comp->release();
+
+ aio_comp = new librbd::AioCompletion();
+ ictx->aio_work_queue->aio_flush(aio_comp);
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ aio_comp->release();
+
+ std::string read_payload(4096, '\0');
+ aio_comp = new librbd::AioCompletion();
+ ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
+ &read_payload[0], NULL, 0);
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ aio_comp->release();
+ ASSERT_EQ(payload, read_payload);
+ close_image(ictx);
+
+ // inject a discard operation into the journal
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ASSERT_EQ(0, when_acquired_lock(ictx));
+
+ librbd::journal::EventEntry event_entry(
+ librbd::journal::AioDiscardEvent(0, payload.size()));
+ librbd::Journal::AioObjectRequests requests;
+ {
+ RWLock::RLocker owner_locker(ictx->owner_lock);
+ ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
+ }
+
+ // re-open the journal so that it replays the new entry
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ASSERT_EQ(0, when_acquired_lock(ictx));
+
+ aio_comp = new librbd::AioCompletion();
+ ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
+ &read_payload[0], NULL, 0);
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ aio_comp->release();
+ ASSERT_EQ(std::string(read_payload.size(), '\0'), read_payload);
+}
+
+TEST_F(TestJournalReplay, AioWriteEvent) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ // inject a write operation into the journal
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ASSERT_EQ(0, when_acquired_lock(ictx));
+
+ std::string payload(4096, '1');
+ bufferlist payload_bl;
+ payload_bl.append(payload);
+ librbd::journal::EventEntry event_entry(
+ librbd::journal::AioWriteEvent(0, payload.size(), payload_bl));
+ librbd::Journal::AioObjectRequests requests;
+ {
+ RWLock::RLocker owner_locker(ictx->owner_lock);
+ ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
+ }
+
+ // re-open the journal so that it replays the new entry
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ASSERT_EQ(0, when_acquired_lock(ictx));
+
+ std::string read_payload(4096, '\0');
+ librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
+ ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
+ &read_payload[0], NULL, 0);
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ aio_comp->release();
+ ASSERT_EQ(payload, read_payload);
+}
+
+TEST_F(TestJournalReplay, AioFlushEvent) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ // inject a flush operation into the journal
+ librbd::ImageCtx *ictx;
+
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ASSERT_EQ(0, when_acquired_lock(ictx));
+
+ librbd::journal::AioFlushEvent aio_flush_event;
+ librbd::journal::EventEntry event_entry(aio_flush_event);
+ librbd::Journal::AioObjectRequests requests;
+ {
+ RWLock::RLocker owner_locker(ictx->owner_lock);
+ ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
+ }
+
+ // start an AIO write op
+ librbd::Journal *journal = ictx->journal;
+ ictx->journal = NULL;
+
+ std::string payload(m_image_size, '1');
+ librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
+ {
+ RWLock::RLocker owner_lock(ictx->owner_lock);
+ librbd::AioImageRequest::aio_write(ictx, aio_comp, 0, payload.size(),
+ payload.c_str(), 0);
+ }
+ ictx->journal = journal;
+
+ // re-open the journal so that it replays the new entry
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ASSERT_EQ(0, when_acquired_lock(ictx));
+
+ ASSERT_TRUE(aio_comp->is_complete());
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ aio_comp->release();
+
+ std::string read_payload(m_image_size, '\0');
+ aio_comp = new librbd::AioCompletion();
+ ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
+ &read_payload[0], NULL, 0);
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ aio_comp->release();
+ ASSERT_EQ(payload, read_payload);
+}
+
#define CEPH_TEST_LIBRBD_MOCK_JOURNAL_H
#include "gmock/gmock.h"
-#include "librbd/JournalTypes.h"
#include "librbd/Journal.h"
+#include "librbd/journal/Entries.h"
namespace librbd {
+++ /dev/null
-// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "test/librbd/test_fixture.h"
-#include "test/librbd/test_support.h"
-#include "librbd/AioCompletion.h"
-#include "librbd/AioImageRequestWQ.h"
-#include "librbd/internal.h"
-#include "librbd/Journal.h"
-#include "librbd/JournalTypes.h"
-#include "journal/Journaler.h"
-#include "journal/ReplayEntry.h"
-#include "journal/ReplayHandler.h"
-#include <list>
-#include <boost/variant.hpp>
-
-void register_test_journal_entries() {
-}
-
-class TestJournalEntries : public TestFixture {
-public:
- typedef std::list<journal::Journaler *> Journalers;
-
- struct ReplayHandler : public journal::ReplayHandler {
- Mutex lock;
- Cond cond;
- bool entries_available;
- bool complete;
-
- ReplayHandler()
- : lock("ReplayHandler::lock"), entries_available(false), complete(false) {
- }
-
- virtual void get() {
- }
- virtual void put() {
- }
-
- virtual void handle_entries_available() {
- Mutex::Locker locker(lock);
- entries_available = true;
- cond.Signal();
- }
-
- virtual void handle_complete(int r) {
- Mutex::Locker locker(lock);
- complete = true;
- cond.Signal();
- }
- };
-
- ReplayHandler m_replay_handler;
- Journalers m_journalers;
-
- virtual void TearDown() {
- for (Journalers::iterator it = m_journalers.begin();
- it != m_journalers.end(); ++it) {
- journal::Journaler *journaler = *it;
- journaler->stop_replay();
- delete journaler;
- }
-
- TestFixture::TearDown();
- }
-
- journal::Journaler *create_journaler(librbd::ImageCtx *ictx) {
- journal::Journaler *journaler = new journal::Journaler(
- ictx->md_ctx, ictx->id, "dummy client", 1);
-
- int r = journaler->register_client("unit test client");
- if (r < 0) {
- ADD_FAILURE() << "failed to register journal client";
- delete journaler;
- return NULL;
- }
-
- C_SaferCond cond;
- journaler->init(&cond);
- r = cond.wait();
- if (r < 0) {
- ADD_FAILURE() << "failed to initialize journal client";
- delete journaler;
- return NULL;
- }
-
- journaler->start_live_replay(&m_replay_handler, 0.1);
- m_journalers.push_back(journaler);
- return journaler;
- }
-
- bool wait_for_entries_available(librbd::ImageCtx *ictx) {
- Mutex::Locker locker(m_replay_handler.lock);
- while (!m_replay_handler.entries_available) {
- if (m_replay_handler.cond.WaitInterval(ictx->cct, m_replay_handler.lock,
- utime_t(10, 0)) != 0) {
- return false;
- }
- }
- m_replay_handler.entries_available = false;
- return true;
- }
-
- bool get_event_entry(const journal::ReplayEntry &replay_entry,
- librbd::journal::EventEntry *event_entry) {
- try {
- bufferlist data_bl = replay_entry.get_data();
- bufferlist::iterator it = data_bl.begin();
- ::decode(*event_entry, it);
- } catch (const buffer::error &err) {
- return false;
- }
- return true;
- }
-
-};
-
-TEST_F(TestJournalEntries, AioWrite) {
- REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- journal::Journaler *journaler = create_journaler(ictx);
- ASSERT_TRUE(journaler != NULL);
-
- std::string buffer(512, '1');
- C_SaferCond cond_ctx;
- librbd::AioCompletion *c = librbd::AioCompletion::create(&cond_ctx);
- c->get();
- ictx->aio_work_queue->aio_write(c, 123, buffer.size(), buffer.c_str(), 0);
- ASSERT_EQ(0, c->wait_for_complete());
- c->put();
-
- ASSERT_TRUE(wait_for_entries_available(ictx));
-
- journal::ReplayEntry replay_entry;
- ASSERT_TRUE(journaler->try_pop_front(&replay_entry));
-
- librbd::journal::EventEntry event_entry;
- ASSERT_TRUE(get_event_entry(replay_entry, &event_entry));
-
- ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_WRITE,
- event_entry.get_event_type());
-
- librbd::journal::AioWriteEvent aio_write_event =
- boost::get<librbd::journal::AioWriteEvent>(event_entry.event);
- ASSERT_EQ(123U, aio_write_event.offset);
- ASSERT_EQ(buffer.size(), aio_write_event.length);
-
- bufferlist buffer_bl;
- buffer_bl.append(buffer);
- ASSERT_TRUE(aio_write_event.data.contents_equal(buffer_bl));
-}
-
-TEST_F(TestJournalEntries, AioDiscard) {
- REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- journal::Journaler *journaler = create_journaler(ictx);
- ASSERT_TRUE(journaler != NULL);
-
- C_SaferCond cond_ctx;
- librbd::AioCompletion *c = librbd::AioCompletion::create(&cond_ctx);
- c->get();
- ictx->aio_work_queue->aio_discard(c, 123, 234);
- ASSERT_EQ(0, c->wait_for_complete());
- c->put();
-
- ASSERT_TRUE(wait_for_entries_available(ictx));
-
- journal::ReplayEntry replay_entry;
- ASSERT_TRUE(journaler->try_pop_front(&replay_entry));
-
- librbd::journal::EventEntry event_entry;
- ASSERT_TRUE(get_event_entry(replay_entry, &event_entry));
-
- ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_DISCARD,
- event_entry.get_event_type());
-
- librbd::journal::AioDiscardEvent aio_discard_event =
- boost::get<librbd::journal::AioDiscardEvent>(event_entry.event);
- ASSERT_EQ(123U, aio_discard_event.offset);
- ASSERT_EQ(234U, aio_discard_event.length);
-}
-
-TEST_F(TestJournalEntries, AioFlush) {
- REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- journal::Journaler *journaler = create_journaler(ictx);
- ASSERT_TRUE(journaler != NULL);
-
- C_SaferCond cond_ctx;
- librbd::AioCompletion *c = librbd::AioCompletion::create(&cond_ctx);
- c->get();
- ictx->aio_work_queue->aio_flush(c);
- ASSERT_EQ(0, c->wait_for_complete());
- c->put();
-
- ASSERT_TRUE(wait_for_entries_available(ictx));
-
- journal::ReplayEntry replay_entry;
- ASSERT_TRUE(journaler->try_pop_front(&replay_entry));
-
- librbd::journal::EventEntry event_entry;
- ASSERT_TRUE(get_event_entry(replay_entry, &event_entry));
-
- ASSERT_EQ(librbd::journal::EVENT_TYPE_AIO_FLUSH,
- event_entry.get_event_type());
-}
+++ /dev/null
-// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "test/librbd/test_fixture.h"
-#include "test/librbd/test_support.h"
-#include "librbd/AioCompletion.h"
-#include "librbd/AioImageRequest.h"
-#include "librbd/AioImageRequestWQ.h"
-#include "librbd/ExclusiveLock.h"
-#include "librbd/ImageCtx.h"
-#include "librbd/ImageWatcher.h"
-#include "librbd/Journal.h"
-#include "librbd/JournalTypes.h"
-
-void register_test_journal_replay() {
-}
-
-class TestJournalReplay : public TestFixture {
-public:
-
- int when_acquired_lock(librbd::ImageCtx *ictx) {
- C_SaferCond lock_ctx;
- {
- RWLock::WLocker owner_locker(ictx->owner_lock);
- ictx->exclusive_lock->request_lock(&lock_ctx);
- }
- return lock_ctx.wait();
- }
-};
-
-TEST_F(TestJournalReplay, AioDiscardEvent) {
- REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
-
- // write to the image w/o using the journal
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- ictx->features &= ~RBD_FEATURE_JOURNALING;
-
- std::string payload(4096, '1');
- librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
- ictx->aio_work_queue->aio_write(aio_comp, 0, payload.size(), payload.c_str(),
- 0);
- ASSERT_EQ(0, aio_comp->wait_for_complete());
- aio_comp->release();
-
- aio_comp = new librbd::AioCompletion();
- ictx->aio_work_queue->aio_flush(aio_comp);
- ASSERT_EQ(0, aio_comp->wait_for_complete());
- aio_comp->release();
-
- std::string read_payload(4096, '\0');
- aio_comp = new librbd::AioCompletion();
- ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
- &read_payload[0], NULL, 0);
- ASSERT_EQ(0, aio_comp->wait_for_complete());
- aio_comp->release();
- ASSERT_EQ(payload, read_payload);
- close_image(ictx);
-
- // inject a discard operation into the journal
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- ASSERT_EQ(0, when_acquired_lock(ictx));
-
- librbd::journal::EventEntry event_entry(
- librbd::journal::AioDiscardEvent(0, payload.size()));
- librbd::Journal::AioObjectRequests requests;
- {
- RWLock::RLocker owner_locker(ictx->owner_lock);
- ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
- }
-
- // re-open the journal so that it replays the new entry
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- ASSERT_EQ(0, when_acquired_lock(ictx));
-
- aio_comp = new librbd::AioCompletion();
- ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
- &read_payload[0], NULL, 0);
- ASSERT_EQ(0, aio_comp->wait_for_complete());
- aio_comp->release();
- ASSERT_EQ(std::string(read_payload.size(), '\0'), read_payload);
-}
-
-TEST_F(TestJournalReplay, AioWriteEvent) {
- REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
-
- // inject a write operation into the journal
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- ASSERT_EQ(0, when_acquired_lock(ictx));
-
- std::string payload(4096, '1');
- bufferlist payload_bl;
- payload_bl.append(payload);
- librbd::journal::EventEntry event_entry(
- librbd::journal::AioWriteEvent(0, payload.size(), payload_bl));
- librbd::Journal::AioObjectRequests requests;
- {
- RWLock::RLocker owner_locker(ictx->owner_lock);
- ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
- }
-
- // re-open the journal so that it replays the new entry
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- ASSERT_EQ(0, when_acquired_lock(ictx));
-
- std::string read_payload(4096, '\0');
- librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
- ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
- &read_payload[0], NULL, 0);
- ASSERT_EQ(0, aio_comp->wait_for_complete());
- aio_comp->release();
- ASSERT_EQ(payload, read_payload);
-}
-
-TEST_F(TestJournalReplay, AioFlushEvent) {
- REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
-
- // inject a flush operation into the journal
- librbd::ImageCtx *ictx;
-
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- ASSERT_EQ(0, when_acquired_lock(ictx));
-
- librbd::journal::AioFlushEvent aio_flush_event;
- librbd::journal::EventEntry event_entry(aio_flush_event);
- librbd::Journal::AioObjectRequests requests;
- {
- RWLock::RLocker owner_locker(ictx->owner_lock);
- ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
- }
-
- // start an AIO write op
- librbd::Journal *journal = ictx->journal;
- ictx->journal = NULL;
-
- std::string payload(m_image_size, '1');
- librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
- {
- RWLock::RLocker owner_lock(ictx->owner_lock);
- librbd::AioImageRequest::aio_write(ictx, aio_comp, 0, payload.size(),
- payload.c_str(), 0);
- }
- ictx->journal = journal;
-
- // re-open the journal so that it replays the new entry
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
- ASSERT_EQ(0, when_acquired_lock(ictx));
-
- ASSERT_TRUE(aio_comp->is_complete());
- ASSERT_EQ(0, aio_comp->wait_for_complete());
- aio_comp->release();
-
- std::string read_payload(m_image_size, '\0');
- aio_comp = new librbd::AioCompletion();
- ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
- &read_payload[0], NULL, 0);
- ASSERT_EQ(0, aio_comp->wait_for_complete());
- aio_comp->release();
- ASSERT_EQ(payload, read_payload);
-}
-
#include "journal/ReplayEntry.h"
#include "journal/ReplayHandler.h"
//#include "librbd/Journal.h" // XXXMG: for librbd::Journal::reset()
-#include "librbd/JournalTypes.h"
+#include "librbd/journal/Entries.h"
namespace rbd {
namespace action {