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
--- /dev/null
+// -*- 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>;
--- /dev/null
+// -*- 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
--- /dev/null
+// -*- 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
#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 {
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);
}
};
template <typename I>
void ImageDispatchSpec<I>::send() {
- boost::apply_visitor(SendVisitor{this}, m_request);
+ boost::apply_visitor(SendVisitor{this}, request);
}
template <typename I>
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;
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
#include "librbd/io/Types.h"
#include "librbd/io/ReadResult.h"
#include <boost/variant/variant.hpp>
+#include <atomic>
namespace librbd {
namespace io {
+struct ImageDispatcherInterface;
+
template <typename ImageCtxT = ImageCtx>
class ImageDispatchSpec {
private:
}
};
+ 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,
}
~ImageDispatchSpec() {
- m_aio_comp->put();
+ aio_comp->put();
}
void send();
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;
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);
--- /dev/null
+// -*- 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>;
--- /dev/null
+// -*- 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
--- /dev/null
+// -*- 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