]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: initial implementation for image IO dispatcher
authorJason Dillaman <dillaman@redhat.com>
Wed, 29 Apr 2020 13:52:33 +0000 (09:52 -0400)
committerJason Dillaman <dillaman@redhat.com>
Thu, 14 May 2020 15:56:45 +0000 (11:56 -0400)
This is similar to the object IO dispatcher but it expects image extents
for IO operations.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/CMakeLists.txt
src/librbd/io/ImageDispatch.cc [new file with mode: 0644]
src/librbd/io/ImageDispatch.h [new file with mode: 0644]
src/librbd/io/ImageDispatchInterface.h [new file with mode: 0644]
src/librbd/io/ImageDispatchSpec.cc
src/librbd/io/ImageDispatchSpec.h
src/librbd/io/ImageDispatcher.cc [new file with mode: 0644]
src/librbd/io/ImageDispatcher.h [new file with mode: 0644]
src/librbd/io/ImageDispatcherInterface.h [new file with mode: 0644]

index aa536e86ecfdbd869b375852754b79c0a7cff690..edc17aedc3fe013260e0d69371b75d668b6fba8e 100644 (file)
@@ -73,7 +73,9 @@ set(librbd_internal_srcs
   io/AioCompletion.cc
   io/AsyncOperation.cc
   io/CopyupRequest.cc
+  io/ImageDispatch.cc
   io/ImageDispatchSpec.cc
+  io/ImageDispatcher.cc
   io/ImageRequest.cc
   io/ImageRequestWQ.cc
   io/ObjectDispatch.cc
diff --git a/src/librbd/io/ImageDispatch.cc b/src/librbd/io/ImageDispatch.cc
new file mode 100644 (file)
index 0000000..2cd9f7a
--- /dev/null
@@ -0,0 +1,121 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/io/ImageDispatch.h"
+#include "common/dout.h"
+#include "common/WorkQueue.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/io/ImageRequest.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::io::ImageDispatch: " << this << " " \
+                           << __func__ << ": "
+
+namespace librbd {
+namespace io {
+
+template <typename I>
+void ImageDispatch<I>::shut_down(Context* on_finish) {
+  on_finish->complete(0);
+}
+
+template <typename I>
+bool ImageDispatch<I>::read(
+    AioCompletion* aio_comp, Extents &&image_extents, ReadResult &&read_result,
+    int op_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+    std::atomic<uint32_t>* image_dispatch_flags,
+    DispatchResult* dispatch_result, Context* on_dispatched) {
+  auto cct = m_image_ctx->cct;
+  ldout(cct, 20) << "image_extents=" << image_extents << dendl;
+
+  *dispatch_result = DISPATCH_RESULT_COMPLETE;
+  ImageRequest<I>::aio_read(
+    m_image_ctx, aio_comp, std::move(image_extents), std::move(read_result),
+    op_flags, parent_trace);
+  return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::write(
+    AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&bl,
+    int op_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+    std::atomic<uint32_t>* image_dispatch_flags,
+    DispatchResult* dispatch_result, Context* on_dispatched) {
+  auto cct = m_image_ctx->cct;
+  ldout(cct, 20) << "image_extents=" << image_extents << dendl;
+
+  *dispatch_result = DISPATCH_RESULT_COMPLETE;
+  ImageRequest<I>::aio_write(
+    m_image_ctx, aio_comp, std::move(image_extents), std::move(bl), op_flags,
+    parent_trace);
+  return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::discard(
+    AioCompletion* aio_comp, Extents &&image_extents,
+    uint32_t discard_granularity_bytes, const ZTracer::Trace &parent_trace,
+    uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
+    DispatchResult* dispatch_result, Context* on_dispatched) {
+  auto cct = m_image_ctx->cct;
+  ldout(cct, 20) << "image_extents=" << image_extents << dendl;
+
+  *dispatch_result = DISPATCH_RESULT_COMPLETE;
+  ImageRequest<I>::aio_discard(
+    m_image_ctx, aio_comp, std::move(image_extents), discard_granularity_bytes,
+    parent_trace);
+  return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::write_same(
+    AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&bl,
+    int op_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+    std::atomic<uint32_t>* image_dispatch_flags,
+    DispatchResult* dispatch_result, Context* on_dispatched) {
+  auto cct = m_image_ctx->cct;
+  ldout(cct, 20) << "image_extents=" << image_extents << dendl;
+
+  *dispatch_result = DISPATCH_RESULT_COMPLETE;
+  ImageRequest<I>::aio_writesame(
+    m_image_ctx, aio_comp, std::move(image_extents), std::move(bl), op_flags,
+    parent_trace);
+  return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::compare_and_write(
+    AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&cmp_bl,
+    bufferlist &&bl, uint64_t *mismatch_offset, int op_flags,
+    const ZTracer::Trace &parent_trace, uint64_t tid,
+    std::atomic<uint32_t>* image_dispatch_flags,
+    DispatchResult* dispatch_result, Context* on_dispatched) {
+  auto cct = m_image_ctx->cct;
+  ldout(cct, 20) << "image_extents=" << image_extents << dendl;
+
+  *dispatch_result = DISPATCH_RESULT_COMPLETE;
+  ImageRequest<I>::aio_compare_and_write(
+    m_image_ctx, aio_comp, std::move(image_extents), std::move(cmp_bl),
+    std::move(bl), mismatch_offset, op_flags, parent_trace);
+  return true;
+}
+
+template <typename I>
+bool ImageDispatch<I>::flush(
+    AioCompletion* aio_comp, FlushSource flush_source,
+    const ZTracer::Trace &parent_trace, uint64_t tid,
+    std::atomic<uint32_t>* image_dispatch_flags,
+    DispatchResult* dispatch_result, Context* on_dispatched) {
+  auto cct = m_image_ctx->cct;
+  ldout(cct, 20) << dendl;
+
+  *dispatch_result = DISPATCH_RESULT_COMPLETE;
+  ImageRequest<I>::aio_flush(m_image_ctx, aio_comp, flush_source, parent_trace);
+  return true;
+}
+
+} // namespace io
+} // namespace librbd
+
+template class librbd::io::ImageDispatch<librbd::ImageCtx>;
diff --git a/src/librbd/io/ImageDispatch.h b/src/librbd/io/ImageDispatch.h
new file mode 100644 (file)
index 0000000..cc56264
--- /dev/null
@@ -0,0 +1,82 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_IO_IMAGE_DISPATCH_H
+#define CEPH_LIBRBD_IO_IMAGE_DISPATCH_H
+
+#include "librbd/io/ImageDispatchInterface.h"
+#include "include/int_types.h"
+#include "include/buffer.h"
+#include "common/zipkin_trace.h"
+#include "librbd/io/ReadResult.h"
+#include "librbd/io/Types.h"
+
+struct Context;
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace io {
+
+struct AioCompletion;
+
+template <typename ImageCtxT>
+class ImageDispatch : public ImageDispatchInterface {
+public:
+  ImageDispatch(ImageCtxT* image_ctx) : m_image_ctx(image_ctx) {
+  }
+
+  ImageDispatchLayer get_dispatch_layer() const override {
+    return IMAGE_DISPATCH_LAYER_CORE;
+  }
+
+  void shut_down(Context* on_finish) override;
+
+  bool read(
+      AioCompletion* aio_comp, Extents &&image_extents,
+      ReadResult &&read_result, int op_flags,
+      const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) override;
+  bool write(
+      AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&bl,
+      int op_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) override;
+  bool discard(
+      AioCompletion* aio_comp, Extents &&image_extents,
+      uint32_t discard_granularity_bytes,
+      const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) override;
+  bool write_same(
+      AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&bl,
+      int op_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) override;
+  bool compare_and_write(
+      AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&cmp_bl,
+      bufferlist &&bl, uint64_t *mismatch_offset, int op_flags,
+      const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) override;
+  bool flush(
+      AioCompletion* aio_comp, FlushSource flush_source,
+      const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) override;
+
+  void handle_finished(int r, uint64_t tid) override {}
+
+private:
+  ImageCtxT* m_image_ctx;
+
+};
+
+} // namespace io
+} // namespace librbd
+
+extern template class librbd::io::ImageDispatch<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_IO_IMAGE_DISPATCH_H
diff --git a/src/librbd/io/ImageDispatchInterface.h b/src/librbd/io/ImageDispatchInterface.h
new file mode 100644 (file)
index 0000000..d96cb92
--- /dev/null
@@ -0,0 +1,74 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_IO_IMAGE_DISPATCH_INTERFACE_H
+#define CEPH_LIBRBD_IO_IMAGE_DISPATCH_INTERFACE_H
+
+#include "include/int_types.h"
+#include "include/buffer.h"
+#include "common/zipkin_trace.h"
+#include "librbd/io/ReadResult.h"
+#include "librbd/io/Types.h"
+#include <atomic>
+
+struct Context;
+
+namespace librbd {
+namespace io {
+
+struct AioCompletion;
+template <typename> struct ImageDispatchSpec;
+
+struct ImageDispatchInterface {
+  typedef ImageDispatchLayer DispatchLayer;
+  typedef ImageDispatchSpec<librbd::ImageCtx> DispatchSpec;
+
+  virtual ~ImageDispatchInterface() {
+  }
+
+  virtual ImageDispatchLayer get_dispatch_layer() const = 0;
+
+  virtual void shut_down(Context* on_finish) = 0;
+
+  virtual bool read(
+      AioCompletion* aio_comp, Extents &&image_extents,
+      ReadResult &&read_result, int op_flags,
+      const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) = 0;
+  virtual bool write(
+      AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&bl,
+      int op_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) = 0;
+  virtual bool discard(
+      AioCompletion* aio_comp, Extents &&image_extents,
+      uint32_t discard_granularity_bytes,
+      const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) = 0;
+  virtual bool write_same(
+      AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&bl,
+      int op_flags, const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) = 0;
+  virtual bool compare_and_write(
+      AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&cmp_bl,
+      bufferlist &&bl, uint64_t *mismatch_offset, int op_flags,
+      const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) = 0;
+  virtual bool flush(
+      AioCompletion* aio_comp, FlushSource flush_source,
+      const ZTracer::Trace &parent_trace, uint64_t tid,
+      std::atomic<uint32_t>* image_dispatch_flags,
+      DispatchResult* dispatch_result, Context* on_dispatched) = 0;
+
+  virtual void handle_finished(int r, uint64_t tid) = 0;
+
+};
+
+} // namespace io
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_IO_IMAGE_DISPATCH_INTERFACE_H
index 1854a6af44bde70a779a4a3cc65fb42830d18416..285d462737d4f3b6d6aaa1f59e71ca0fe14be192 100644 (file)
@@ -5,6 +5,7 @@
 #include "librbd/ImageCtx.h"
 #include "librbd/io/AioCompletion.h"
 #include "librbd/io/ImageRequest.h"
+#include "librbd/io/ImageDispatcherInterface.h"
 #include <boost/variant.hpp>
 
 namespace librbd {
@@ -53,40 +54,40 @@ struct ImageDispatchSpec<I>::SendVisitor
 
   void operator()(Read& read) const {
     ImageRequest<I>::aio_read(
-      &spec->m_image_ctx, spec->m_aio_comp, std::move(spec->m_image_extents),
-      std::move(read.read_result), spec->m_op_flags, spec->m_parent_trace);
+      &spec->m_image_ctx, spec->aio_comp, std::move(spec->image_extents),
+      std::move(read.read_result), spec->op_flags, spec->parent_trace);
   }
 
   void operator()(Discard& discard) const {
     ImageRequest<I>::aio_discard(
-      &spec->m_image_ctx, spec->m_aio_comp, std::move(spec->m_image_extents),
-      discard.discard_granularity_bytes, spec->m_parent_trace);
+      &spec->m_image_ctx, spec->aio_comp, std::move(spec->image_extents),
+      discard.discard_granularity_bytes, spec->parent_trace);
   }
 
   void operator()(Write& write) const {
     ImageRequest<I>::aio_write(
-      &spec->m_image_ctx, spec->m_aio_comp, std::move(spec->m_image_extents),
-      std::move(write.bl), spec->m_op_flags, spec->m_parent_trace);
+      &spec->m_image_ctx, spec->aio_comp, std::move(spec->image_extents),
+      std::move(write.bl), spec->op_flags, spec->parent_trace);
   }
 
   void operator()(WriteSame& write_same) const {
     ImageRequest<I>::aio_writesame(
-      &spec->m_image_ctx, spec->m_aio_comp, std::move(spec->m_image_extents),
-      std::move(write_same.bl), spec->m_op_flags, spec->m_parent_trace);
+      &spec->m_image_ctx, spec->aio_comp, std::move(spec->image_extents),
+      std::move(write_same.bl), spec->op_flags, spec->parent_trace);
   }
 
   void operator()(CompareAndWrite& compare_and_write) const {
     ImageRequest<I>::aio_compare_and_write(
-      &spec->m_image_ctx, spec->m_aio_comp, std::move(spec->m_image_extents),
+      &spec->m_image_ctx, spec->aio_comp, std::move(spec->image_extents),
       std::move(compare_and_write.cmp_bl), std::move(compare_and_write.bl),
-      compare_and_write.mismatch_offset, spec->m_op_flags,
-      spec->m_parent_trace);
+      compare_and_write.mismatch_offset, spec->op_flags,
+      spec->parent_trace);
   }
 
   void operator()(Flush& flush) const {
     ImageRequest<I>::aio_flush(
-      &spec->m_image_ctx, spec->m_aio_comp, flush.flush_source,
-      spec->m_parent_trace);
+      &spec->m_image_ctx, spec->aio_comp, flush.flush_source,
+      spec->parent_trace);
   }
 };
 
@@ -144,7 +145,7 @@ struct ImageDispatchSpec<I>::TokenRequestedVisitor
 
 template <typename I>
 void ImageDispatchSpec<I>::send() {
-  boost::apply_visitor(SendVisitor{this}, m_request);
+  boost::apply_visitor(SendVisitor{this}, request);
 }
 
 template <typename I>
@@ -154,13 +155,13 @@ void ImageDispatchSpec<I>::finish(int r) {
 
 template <typename I>
 void ImageDispatchSpec<I>::fail(int r) {
-  m_aio_comp->fail(r);
+  aio_comp->fail(r);
 }
 
 template <typename I>
 uint64_t ImageDispatchSpec<I>::extents_length() {
   uint64_t length = 0;
-  auto &extents = this->m_image_extents;
+  auto &extents = this->image_extents;
 
   for (auto &extent : extents) {
     length += extent.second;
@@ -170,28 +171,28 @@ uint64_t ImageDispatchSpec<I>::extents_length() {
 
 template <typename I>
 const Extents& ImageDispatchSpec<I>::get_image_extents() const {
-   return this->m_image_extents;
+   return this->image_extents;
 }
 
 template <typename I>
 uint64_t ImageDispatchSpec<I>::get_tid() {
-  return this->m_tid;
+  return this->tid;
 }
 
 template <typename I>
 bool ImageDispatchSpec<I>::is_write_op() const {
-  return boost::apply_visitor(IsWriteOpVisitor(), m_request);
+  return boost::apply_visitor(IsWriteOpVisitor(), request);
 }
 
 template <typename I>
 bool ImageDispatchSpec<I>::tokens_requested(uint64_t flag, uint64_t *tokens) {
   return boost::apply_visitor(TokenRequestedVisitor{this, flag, tokens},
-                              m_request);
+                              request);
 }
 
 template <typename I>
 void ImageDispatchSpec<I>::start_op() {
-  m_aio_comp->start_op();
+  aio_comp->start_op();
 }
 
 } // namespace io
index a73b297eefcf57ae6e5bde75479277bd800bc74e..90eddb616d13c0f50387c6f0622458fb57a3bf57 100644 (file)
@@ -12,6 +12,7 @@
 #include "librbd/io/Types.h"
 #include "librbd/io/ReadResult.h"
 #include <boost/variant/variant.hpp>
+#include <atomic>
 
 namespace librbd {
 
@@ -19,6 +20,8 @@ class ImageCtx;
 
 namespace io {
 
+struct ImageDispatcherInterface;
+
 template <typename ImageCtxT = ImageCtx>
 class ImageDispatchSpec {
 private:
@@ -83,10 +86,28 @@ public:
     }
   };
 
+  typedef boost::variant<Read,
+                         Discard,
+                         Write,
+                         WriteSame,
+                         CompareAndWrite,
+                         Flush> Request;
+
   C_Dispatcher dispatcher_ctx;
+
+  ImageDispatcherInterface* image_dispatcher;
   ImageDispatchLayer dispatch_layer;
+  std::atomic<uint32_t> image_dispatch_flags = 0;
   DispatchResult dispatch_result = DISPATCH_RESULT_INVALID;
 
+  AioCompletion* aio_comp;
+  Extents image_extents;
+  Request request;
+  int op_flags;
+  ZTracer::Trace parent_trace;
+  uint64_t tid;
+  std::atomic<uint64_t> throttled_flag = 0;
+
   static ImageDispatchSpec* create_read_request(
       ImageCtxT &image_ctx, ImageDispatchLayer image_dispatch_layer,
       AioCompletion *aio_comp, Extents &&image_extents,
@@ -151,7 +172,7 @@ public:
   }
 
   ~ImageDispatchSpec() {
-    m_aio_comp->put();
+    aio_comp->put();
   }
 
   void send();
@@ -164,34 +185,27 @@ public:
   bool tokens_requested(uint64_t flag, uint64_t *tokens);
 
   bool was_throttled(uint64_t flag) {
-    return m_throttled_flag & flag;
+    return throttled_flag & flag;
   }
 
   void set_throttled(uint64_t flag) {
-    m_throttled_flag |= flag;
+    throttled_flag |= flag;
   }
 
   bool were_all_throttled() {
-    return (m_throttled_flag & RBD_QOS_MASK) == RBD_QOS_MASK;
+    return (throttled_flag & RBD_QOS_MASK) == RBD_QOS_MASK;
   }
 
   const Extents& get_image_extents() const;
 
   AioCompletion* get_aio_completion() const {
-    return m_aio_comp;
+    return aio_comp;
   }
 
   uint64_t get_tid();
   bool blocked = false;
 
 private:
-  typedef boost::variant<Read,
-                         Discard,
-                         Write,
-                         WriteSame,
-                         CompareAndWrite,
-                         Flush> Request;
-
   struct SendVisitor;
   struct IsWriteOpVisitor;
   struct TokenRequestedVisitor;
@@ -202,20 +216,13 @@ private:
                     Request&& request, int op_flags,
                     const ZTracer::Trace& parent_trace, uint64_t tid)
     : dispatcher_ctx(this), dispatch_layer(image_dispatch_layer),
-      m_image_ctx(image_ctx), m_aio_comp(aio_comp),
-      m_image_extents(std::move(image_extents)), m_request(std::move(request)),
-      m_op_flags(op_flags), m_parent_trace(parent_trace), m_tid(tid) {
-    m_aio_comp->get();
+      aio_comp(aio_comp), image_extents(std::move(image_extents)),
+      request(std::move(request)), op_flags(op_flags),
+      parent_trace(parent_trace), tid(tid), m_image_ctx(image_ctx) {
+    aio_comp->get();
   }
 
   ImageCtxT& m_image_ctx;
-  AioCompletion* m_aio_comp;
-  Extents m_image_extents;
-  Request m_request;
-  int m_op_flags;
-  ZTracer::Trace m_parent_trace;
-  uint64_t m_tid;
-  std::atomic<uint64_t> m_throttled_flag = 0;
 
   void finish(int r);
 
diff --git a/src/librbd/io/ImageDispatcher.cc b/src/librbd/io/ImageDispatcher.cc
new file mode 100644 (file)
index 0000000..19fdd29
--- /dev/null
@@ -0,0 +1,120 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/io/ImageDispatcher.h"
+#include "include/Context.h"
+#include "common/AsyncOpTracker.h"
+#include "common/dout.h"
+#include "common/WorkQueue.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Utils.h"
+#include "librbd/io/ImageDispatch.h"
+#include "librbd/io/ImageDispatchInterface.h"
+#include "librbd/io/ImageDispatchSpec.h"
+#include <boost/variant.hpp>
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::io::ImageDispatcher: " << this \
+                           << " " << __func__ << ": "
+
+namespace librbd {
+namespace io {
+
+template <typename I>
+struct ImageDispatcher<I>::SendVisitor : public boost::static_visitor<bool> {
+  ImageDispatchInterface* image_dispatch;
+  ImageDispatchSpec<I>* image_dispatch_spec;
+
+  SendVisitor(ImageDispatchInterface* image_dispatch,
+              ImageDispatchSpec<I>* image_dispatch_spec)
+    : image_dispatch(image_dispatch),
+      image_dispatch_spec(image_dispatch_spec) {
+  }
+
+  bool operator()(typename ImageDispatchSpec<I>::Read& read) const {
+    return image_dispatch->read(
+      image_dispatch_spec->aio_comp,
+      std::move(image_dispatch_spec->image_extents),
+      std::move(read.read_result), image_dispatch_spec->op_flags,
+      image_dispatch_spec->parent_trace, image_dispatch_spec->tid,
+      &image_dispatch_spec->image_dispatch_flags,
+      &image_dispatch_spec->dispatch_result,
+      &image_dispatch_spec->dispatcher_ctx);
+  }
+
+  bool operator()(typename ImageDispatchSpec<I>::Discard& discard) const {
+    return image_dispatch->discard(
+      image_dispatch_spec->aio_comp,
+      std::move(image_dispatch_spec->image_extents),
+      discard.discard_granularity_bytes,
+      image_dispatch_spec->parent_trace, image_dispatch_spec->tid,
+      &image_dispatch_spec->image_dispatch_flags,
+      &image_dispatch_spec->dispatch_result,
+      &image_dispatch_spec->dispatcher_ctx);
+  }
+
+  bool operator()(typename ImageDispatchSpec<I>::Write& write) const {
+    return image_dispatch->write(
+      image_dispatch_spec->aio_comp,
+      std::move(image_dispatch_spec->image_extents), std::move(write.bl),
+      image_dispatch_spec->op_flags, image_dispatch_spec->parent_trace,
+      image_dispatch_spec->tid, &image_dispatch_spec->image_dispatch_flags,
+      &image_dispatch_spec->dispatch_result,
+      &image_dispatch_spec->dispatcher_ctx);
+  }
+
+  bool  operator()(typename ImageDispatchSpec<I>::WriteSame& write_same) const {
+    return image_dispatch->write_same(
+      image_dispatch_spec->aio_comp,
+      std::move(image_dispatch_spec->image_extents), std::move(write_same.bl),
+      image_dispatch_spec->op_flags, image_dispatch_spec->parent_trace,
+      image_dispatch_spec->tid, &image_dispatch_spec->image_dispatch_flags,
+      &image_dispatch_spec->dispatch_result,
+      &image_dispatch_spec->dispatcher_ctx);
+  }
+
+  bool  operator()(
+      typename ImageDispatchSpec<I>::CompareAndWrite& compare_and_write) const {
+    return image_dispatch->compare_and_write(
+      image_dispatch_spec->aio_comp,
+      std::move(image_dispatch_spec->image_extents),
+      std::move(compare_and_write.cmp_bl), std::move(compare_and_write.bl),
+      compare_and_write.mismatch_offset, image_dispatch_spec->op_flags,
+      image_dispatch_spec->parent_trace, image_dispatch_spec->tid,
+      &image_dispatch_spec->image_dispatch_flags,
+      &image_dispatch_spec->dispatch_result,
+      &image_dispatch_spec->dispatcher_ctx);
+  }
+
+  bool operator()(typename ImageDispatchSpec<I>::Flush& flush) const {
+    return image_dispatch->flush(
+      image_dispatch_spec->aio_comp, flush.flush_source,
+      image_dispatch_spec->parent_trace, image_dispatch_spec->tid,
+      &image_dispatch_spec->image_dispatch_flags,
+      &image_dispatch_spec->dispatch_result,
+      &image_dispatch_spec->dispatcher_ctx);
+  }
+};
+
+template <typename I>
+ImageDispatcher<I>::ImageDispatcher(I* image_ctx)
+  : Dispatcher<I, ImageDispatcherInterface>(image_ctx) {
+  // configure the core image dispatch handler on startup
+  auto image_dispatch = new ImageDispatch(image_ctx);
+  this->register_dispatch(image_dispatch);
+}
+
+template <typename I>
+bool ImageDispatcher<I>::send_dispatch(
+    ImageDispatchInterface* image_dispatch,
+    ImageDispatchSpec<I>* image_dispatch_spec) {
+  return boost::apply_visitor(
+    SendVisitor{image_dispatch, image_dispatch_spec},
+    image_dispatch_spec->request);
+}
+
+} // namespace io
+} // namespace librbd
+
+template class librbd::io::ImageDispatcher<librbd::ImageCtx>;
diff --git a/src/librbd/io/ImageDispatcher.h b/src/librbd/io/ImageDispatcher.h
new file mode 100644 (file)
index 0000000..1516a76
--- /dev/null
@@ -0,0 +1,44 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_IO_IMAGE_DISPATCHER_H
+#define CEPH_LIBRBD_IO_IMAGE_DISPATCHER_H
+
+#include "include/int_types.h"
+#include "common/ceph_mutex.h"
+#include "librbd/io/Dispatcher.h"
+#include "librbd/io/ImageDispatchInterface.h"
+#include "librbd/io/ImageDispatchSpec.h"
+#include "librbd/io/ImageDispatcherInterface.h"
+#include "librbd/io/Types.h"
+#include <map>
+
+struct Context;
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace io {
+
+template <typename ImageCtxT = ImageCtx>
+class ImageDispatcher : public Dispatcher<ImageCtxT, ImageDispatcherInterface> {
+public:
+  ImageDispatcher(ImageCtxT* image_ctx);
+
+protected:
+  bool send_dispatch(
+    ImageDispatchInterface* object_dispatch,
+    ImageDispatchSpec<ImageCtxT>* object_dispatch_spec) override;
+
+private:
+  struct SendVisitor;
+
+};
+
+} // namespace io
+} // namespace librbd
+
+extern template class librbd::io::ImageDispatcher<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_IO_IMAGE_DISPATCHER_H
diff --git a/src/librbd/io/ImageDispatcherInterface.h b/src/librbd/io/ImageDispatcherInterface.h
new file mode 100644 (file)
index 0000000..7628def
--- /dev/null
@@ -0,0 +1,24 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_IO_IMAGE_DISPATCHER_INTERFACE_H
+#define CEPH_LIBRBD_IO_IMAGE_DISPATCHER_INTERFACE_H
+
+#include "include/int_types.h"
+#include "librbd/io/DispatcherInterface.h"
+#include "librbd/io/ImageDispatchInterface.h"
+
+struct Context;
+
+namespace librbd {
+namespace io {
+
+struct ImageDispatcherInterface
+  : public DispatcherInterface<ImageDispatchInterface> {
+public:
+};
+
+} // namespace io
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_IO_IMAGE_DISPATCHER_INTERFACE_H