From: Jason Dillaman Date: Tue, 15 Dec 2015 15:34:24 +0000 (-0500) Subject: librbd: move journal support classes to journal namespace X-Git-Tag: v10.0.3~24^2~25 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=588ccfb633ee8992b79b7a5fd7821fe6a2fa9f3c;p=ceph.git librbd: move journal support classes to journal namespace Signed-off-by: Jason Dillaman --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2c4cfda6242..10d86c2ab7f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -974,8 +974,6 @@ if(${WITH_RBD}) librbd/ImageWatcher.cc librbd/internal.cc librbd/Journal.cc - librbd/JournalReplay.cc - librbd/JournalTypes.cc librbd/librbd.cc librbd/LibrbdAdminSocketHook.cc librbd/LibrbdWriteback.cc @@ -988,6 +986,8 @@ if(${WITH_RBD}) 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 diff --git a/src/librbd/AioImageRequest.cc b/src/librbd/AioImageRequest.cc index 104148b49b20..975096f3fbcd 100644 --- a/src/librbd/AioImageRequest.cc +++ b/src/librbd/AioImageRequest.cc @@ -10,7 +10,7 @@ #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" diff --git a/src/librbd/Journal.cc b/src/librbd/Journal.cc index 903a4581a81d..fa5448e1ea48 100644 --- a/src/librbd/Journal.cc +++ b/src/librbd/Journal.cc @@ -7,8 +7,8 @@ #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" @@ -498,7 +498,7 @@ void Journal::handle_initialized(int r) { } 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); } diff --git a/src/librbd/Journal.h b/src/librbd/Journal.h index 0ea9ae428827..d9a48dbb76b9 100644 --- a/src/librbd/Journal.h +++ b/src/librbd/Journal.h @@ -26,10 +26,10 @@ namespace librbd { class AioCompletion; class AioObjectRequest; class ImageCtx; -class JournalReplay; namespace journal { class EventEntry; +class Replay; } class Journal { @@ -217,7 +217,7 @@ private: 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); diff --git a/src/librbd/JournalReplay.cc b/src/librbd/JournalReplay.cc deleted file mode 100644 index 3379f11cf326..000000000000 --- a/src/librbd/JournalReplay.cc +++ /dev/null @@ -1,192 +0,0 @@ -// -*- 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( - 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(arg); - AioCompletion *aio_comp = reinterpret_cast(cb); - - journal_replay->handle_aio_completion(aio_comp); - aio_comp->release(); -} - -} // namespace librbd diff --git a/src/librbd/JournalReplay.h b/src/librbd/JournalReplay.h deleted file mode 100644 index 6b5711a5adc0..000000000000 --- a/src/librbd/JournalReplay.h +++ /dev/null @@ -1,77 +0,0 @@ -// -*- 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 -#include - -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 AioCompletions; - - struct EventVisitor : public boost::static_visitor { - JournalReplay *journal_replay; - Context *on_safe; - - EventVisitor(JournalReplay *_journal_replay, Context *_on_safe) - : journal_replay(_journal_replay), on_safe(_on_safe) { - } - - template - 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 diff --git a/src/librbd/JournalTypes.cc b/src/librbd/JournalTypes.cc deleted file mode 100644 index cda35aabb2f1..000000000000 --- a/src/librbd/JournalTypes.cc +++ /dev/null @@ -1,353 +0,0 @@ -// -*- 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 { -public: - template - inline EventType operator()(const Event &event) const { - return Event::EVENT_TYPE; - } -}; - -class EncodeEventVisitor : public boost::static_visitor { -public: - EncodeEventVisitor(bufferlist &bl) : m_bl(bl) { - } - - template - inline void operator()(const Event &event) const { - ::encode(static_cast(Event::EVENT_TYPE), m_bl); - event.encode(m_bl); - } -private: - bufferlist &m_bl; -}; - -class DecodeEventVisitor : public boost::static_visitor { -public: - DecodeEventVisitor(__u8 version, bufferlist::iterator &iter) - : m_version(version), m_iter(iter) { - } - - template - 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 { -public: - DumpEventVisitor(Formatter *formatter) : m_formatter(formatter) {} - - template - 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 &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(type) << ")"; - break; - } - return out; -} diff --git a/src/librbd/JournalTypes.h b/src/librbd/JournalTypes.h deleted file mode 100644 index ce8ff03b7801..000000000000 --- a/src/librbd/JournalTypes.h +++ /dev/null @@ -1,284 +0,0 @@ -// -*- 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 -#include - -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(-1); - - void encode(bufferlist& bl) const; - void decode(__u8 version, bufferlist::iterator& it); - void dump(Formatter *f) const; -}; - -typedef boost::variant 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 &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 diff --git a/src/librbd/Makefile.am b/src/librbd/Makefile.am index 153b69e4c817..c02ca981abe9 100644 --- a/src/librbd/Makefile.am +++ b/src/librbd/Makefile.am @@ -1,5 +1,5 @@ librbd_types_la_SOURCES = \ - librbd/JournalTypes.cc \ + librbd/journal/Entries.cc \ librbd/WatchNotifyTypes.cc noinst_LTLIBRARIES += librbd_types.la @@ -23,7 +23,6 @@ librbd_internal_la_SOURCES = \ librbd/ImageWatcher.cc \ librbd/internal.cc \ librbd/Journal.cc \ - librbd/JournalReplay.cc \ librbd/LibrbdAdminSocketHook.cc \ librbd/LibrbdWriteback.cc \ librbd/ObjectMap.cc \ @@ -35,6 +34,7 @@ librbd_internal_la_SOURCES = \ 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 \ @@ -97,8 +97,6 @@ noinst_HEADERS += \ librbd/ImageWatcher.h \ librbd/internal.h \ librbd/Journal.h \ - librbd/JournalReplay.h \ - librbd/JournalTypes.h \ librbd/LibrbdAdminSocketHook.h \ librbd/LibrbdWriteback.h \ librbd/ObjectMap.h \ @@ -114,6 +112,8 @@ noinst_HEADERS += \ 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 \ diff --git a/src/librbd/journal/Entries.cc b/src/librbd/journal/Entries.cc new file mode 100644 index 000000000000..fb4106bcfdd0 --- /dev/null +++ b/src/librbd/journal/Entries.cc @@ -0,0 +1,353 @@ +// -*- 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 { +public: + template + inline EventType operator()(const Event &event) const { + return Event::EVENT_TYPE; + } +}; + +class EncodeEventVisitor : public boost::static_visitor { +public: + EncodeEventVisitor(bufferlist &bl) : m_bl(bl) { + } + + template + inline void operator()(const Event &event) const { + ::encode(static_cast(Event::EVENT_TYPE), m_bl); + event.encode(m_bl); + } +private: + bufferlist &m_bl; +}; + +class DecodeEventVisitor : public boost::static_visitor { +public: + DecodeEventVisitor(__u8 version, bufferlist::iterator &iter) + : m_version(version), m_iter(iter) { + } + + template + 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 { +public: + DumpEventVisitor(Formatter *formatter) : m_formatter(formatter) {} + + template + 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 &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(type) << ")"; + break; + } + return out; +} diff --git a/src/librbd/journal/Entries.h b/src/librbd/journal/Entries.h new file mode 100644 index 000000000000..089644e77431 --- /dev/null +++ b/src/librbd/journal/Entries.h @@ -0,0 +1,284 @@ +// -*- 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 +#include + +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(-1); + + void encode(bufferlist& bl) const; + void decode(__u8 version, bufferlist::iterator& it); + void dump(Formatter *f) const; +}; + +typedef boost::variant 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 &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 diff --git a/src/librbd/journal/Replay.cc b/src/librbd/journal/Replay.cc new file mode 100644 index 000000000000..8cc5375c2b33 --- /dev/null +++ b/src/librbd/journal/Replay.cc @@ -0,0 +1,194 @@ +// -*- 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( + 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(arg); + AioCompletion *aio_comp = reinterpret_cast(cb); + + replay->handle_aio_completion(aio_comp); + aio_comp->release(); +} + +} // namespace journal +} // namespace librbd diff --git a/src/librbd/journal/Replay.h b/src/librbd/journal/Replay.h new file mode 100644 index 000000000000..dc82745db132 --- /dev/null +++ b/src/librbd/journal/Replay.h @@ -0,0 +1,80 @@ +// -*- 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 +#include + +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 AioCompletions; + + struct EventVisitor : public boost::static_visitor { + Replay *replay; + Context *on_safe; + + EventVisitor(Replay *_replay, Context *_on_safe) + : replay(_replay), on_safe(_on_safe) { + } + + template + 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 diff --git a/src/librbd/operation/Request.h b/src/librbd/operation/Request.h index c0dd3cbbcadb..68b22db746e8 100644 --- a/src/librbd/operation/Request.h +++ b/src/librbd/operation/Request.h @@ -6,7 +6,7 @@ #include "librbd/AsyncRequest.h" #include "include/Context.h" -#include "librbd/JournalTypes.h" +#include "librbd/journal/Entries.h" namespace librbd { diff --git a/src/test/Makefile-client.am b/src/test/Makefile-client.am index 4458654285d7..b8f7575359b6 100644 --- a/src/test/Makefile-client.am +++ b/src/test/Makefile-client.am @@ -344,9 +344,9 @@ librbd_test_la_SOURCES = \ 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 diff --git a/src/test/encoding/types.h b/src/test/encoding/types.h index add2a0d680d4..e63dc8de8cf5 100644 --- a/src/test/encoding/types.h +++ b/src/test/encoding/types.h @@ -236,7 +236,7 @@ TYPE(ETableServer) 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) diff --git a/src/test/librbd/journal/test_Entries.cc b/src/test/librbd/journal/test_Entries.cc new file mode 100644 index 000000000000..d651d6f07bbe --- /dev/null +++ b/src/test/librbd/journal/test_Entries.cc @@ -0,0 +1,214 @@ +// -*- 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 +#include + +void register_test_journal_entries() { +} + +class TestJournalEntries : public TestFixture { +public: + typedef std::list 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(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(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()); +} diff --git a/src/test/librbd/journal/test_Replay.cc b/src/test/librbd/journal/test_Replay.cc new file mode 100644 index 000000000000..ab8d54e59831 --- /dev/null +++ b/src/test/librbd/journal/test_Replay.cc @@ -0,0 +1,162 @@ +// -*- 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); +} + diff --git a/src/test/librbd/mock/MockJournal.h b/src/test/librbd/mock/MockJournal.h index e0c8d1f719ae..f20acd353b43 100644 --- a/src/test/librbd/mock/MockJournal.h +++ b/src/test/librbd/mock/MockJournal.h @@ -5,8 +5,8 @@ #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 { diff --git a/src/test/librbd/test_JournalEntries.cc b/src/test/librbd/test_JournalEntries.cc deleted file mode 100644 index 1b8e08235df7..000000000000 --- a/src/test/librbd/test_JournalEntries.cc +++ /dev/null @@ -1,214 +0,0 @@ -// -*- 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 -#include - -void register_test_journal_entries() { -} - -class TestJournalEntries : public TestFixture { -public: - typedef std::list 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(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(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()); -} diff --git a/src/test/librbd/test_JournalReplay.cc b/src/test/librbd/test_JournalReplay.cc deleted file mode 100644 index c5a6ad63d414..000000000000 --- a/src/test/librbd/test_JournalReplay.cc +++ /dev/null @@ -1,162 +0,0 @@ -// -*- 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); -} - diff --git a/src/tools/rbd/action/Journal.cc b/src/tools/rbd/action/Journal.cc index e00665b24250..cd4213aaa3cc 100644 --- a/src/tools/rbd/action/Journal.cc +++ b/src/tools/rbd/action/Journal.cc @@ -21,7 +21,7 @@ #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 {