io/AioCompletion.cc
io/AsyncOperation.cc
io/CopyupRequest.cc
+ io/ImageDispatchSpec.cc
io/ImageRequest.cc
io/ImageRequestWQ.cc
io/ObjectRequest.cc
auto aio_comp = io::AioCompletion::create_and_start(on_finish, &m_image_ctx,
io::AIO_TYPE_DISCARD);
- io::ImageDiscardRequest<I> req(m_image_ctx, aio_comp, offset, length,
+ io::ImageDiscardRequest<I> req(m_image_ctx, aio_comp, {{offset, length}},
skip_partial_discard, {});
req.set_bypass_image_cache();
req.send();
auto aio_comp = io::AioCompletion::create_and_start(on_finish, &m_image_ctx,
io::AIO_TYPE_WRITESAME);
- io::ImageWriteSameRequest<I> req(m_image_ctx, aio_comp, offset, length,
+ io::ImageWriteSameRequest<I> req(m_image_ctx, aio_comp, {{offset, length}},
std::move(bl), fadvise_flags, {});
req.set_bypass_image_cache();
req.send();
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/io/ImageDispatchSpec.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/io/AioCompletion.h"
+#include "librbd/io/ImageRequest.h"
+#include <boost/variant.hpp>
+
+namespace librbd {
+namespace io {
+
+template <typename I>
+struct ImageDispatchSpec<I>::SendVisitor
+ : public boost::static_visitor<void> {
+ ImageDispatchSpec* spec;
+
+ SendVisitor(ImageDispatchSpec* spec)
+ : spec(spec) {
+ }
+
+ 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);
+ }
+
+ void operator()(Discard& discard) const {
+ ImageRequest<I>::aio_discard(
+ &spec->m_image_ctx, spec->m_aio_comp, std::move(spec->m_image_extents),
+ discard.skip_partial_discard, spec->m_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);
+ }
+
+ 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);
+ }
+
+ 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),
+ 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);
+ }
+
+ void operator()(Flush& flush) const {
+ ImageRequest<I>::aio_flush(
+ &spec->m_image_ctx, spec->m_aio_comp,
+ spec->m_parent_trace);
+ }
+};
+
+template <typename I>
+struct ImageDispatchSpec<I>::IsWriteOpVisitor
+ : public boost::static_visitor<bool> {
+ bool operator()(const Read&) const {
+ return false;
+ }
+
+ template <typename T>
+ bool operator()(const T&) const {
+ return true;
+ }
+};
+
+template <typename I>
+void ImageDispatchSpec<I>::send() {
+ boost::apply_visitor(SendVisitor{this}, m_request);
+}
+
+template <typename I>
+void ImageDispatchSpec<I>::fail(int r) {
+ m_aio_comp->get();
+ m_aio_comp->fail(r);
+}
+
+template <typename I>
+bool ImageDispatchSpec<I>::is_write_op() const {
+ return boost::apply_visitor(IsWriteOpVisitor{}, m_request);
+}
+
+template <typename I>
+void ImageDispatchSpec<I>::start_op() {
+ m_aio_comp->start_op();
+}
+
+} // namespace io
+} // namespace librbd
+
+template class librbd::io::ImageDispatchSpec<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_SPEC_H
+#define CEPH_LIBRBD_IO_IMAGE_DISPATCH_SPEC_H
+
+#include "include/int_types.h"
+#include "include/buffer.h"
+#include "common/zipkin_trace.h"
+#include "librbd/io/Types.h"
+#include "librbd/io/ReadResult.h"
+#include <boost/variant/variant.hpp>
+
+namespace librbd {
+
+class ImageCtx;
+
+namespace io {
+
+class AioCompletion;
+
+template <typename ImageCtxT = ImageCtx>
+class ImageDispatchSpec {
+public:
+ struct Read {
+ ReadResult read_result;
+
+ Read(ReadResult &&read_result) : read_result(std::move(read_result)) {
+ }
+ };
+
+ struct Discard {
+ bool skip_partial_discard;
+
+ Discard(bool skip_partial_discard)
+ : skip_partial_discard(skip_partial_discard) {
+ }
+ };
+
+ struct Write {
+ bufferlist bl;
+
+ Write(bufferlist&& bl) : bl(std::move(bl)) {
+ }
+ };
+
+ struct WriteSame {
+ bufferlist bl;
+
+ WriteSame(bufferlist&& bl) : bl(std::move(bl)) {
+ }
+ };
+
+ struct CompareAndWrite {
+ bufferlist cmp_bl;
+ bufferlist bl;
+ uint64_t *mismatch_offset;
+
+ CompareAndWrite(bufferlist&& cmp_bl, bufferlist&& bl,
+ uint64_t *mismatch_offset)
+ : cmp_bl(std::move(cmp_bl)), bl(std::move(bl)),
+ mismatch_offset(mismatch_offset) {
+ }
+ };
+
+ struct Flush {
+ };
+
+ static ImageDispatchSpec* create_read_request(
+ ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents,
+ ReadResult &&read_result, int op_flags,
+ const ZTracer::Trace &parent_trace) {
+ return new ImageDispatchSpec(image_ctx, aio_comp,
+ std::move(image_extents),
+ Read{std::move(read_result)},
+ op_flags, parent_trace);
+ }
+
+ static ImageDispatchSpec* create_discard_request(
+ ImageCtxT &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len,
+ bool skip_partial_discard, const ZTracer::Trace &parent_trace) {
+ return new ImageDispatchSpec(image_ctx, aio_comp, {{off, len}},
+ Discard{skip_partial_discard}, 0,
+ parent_trace);
+ }
+
+ static ImageDispatchSpec* create_write_request(
+ ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents,
+ bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace) {
+ return new ImageDispatchSpec(image_ctx, aio_comp, std::move(image_extents),
+ Write{std::move(bl)}, op_flags, parent_trace);
+ }
+
+ static ImageDispatchSpec* create_write_same_request(
+ ImageCtxT &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len,
+ bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace) {
+ return new ImageDispatchSpec(image_ctx, aio_comp, {{off, len}},
+ WriteSame{std::move(bl)}, op_flags,
+ parent_trace);
+ }
+
+ static ImageDispatchSpec* create_compare_and_write_request(
+ ImageCtxT &image_ctx, AioCompletion *aio_comp, Extents &&image_extents,
+ bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset,
+ int op_flags, const ZTracer::Trace &parent_trace) {
+ return new ImageDispatchSpec(image_ctx, aio_comp,
+ std::move(image_extents),
+ CompareAndWrite{std::move(cmp_bl),
+ std::move(bl),
+ mismatch_offset},
+ op_flags, parent_trace);
+ }
+
+ static ImageDispatchSpec* create_flush_request(
+ ImageCtxT &image_ctx, AioCompletion *aio_comp,
+ const ZTracer::Trace &parent_trace) {
+ return new ImageDispatchSpec(image_ctx, aio_comp, {}, Flush{}, 0,
+ parent_trace);
+ }
+
+ void send();
+ void fail(int r);
+
+ bool is_write_op() const;
+
+ void start_op();
+
+ bool was_throttled() {
+ return m_throttled;
+ }
+ void set_throttled() {
+ m_throttled = true;
+ }
+
+private:
+ typedef boost::variant<Read,
+ Discard,
+ Write,
+ WriteSame,
+ CompareAndWrite,
+ Flush> Request;
+
+ struct SendVisitor;
+ struct IsWriteOpVisitor;
+
+ ImageDispatchSpec(ImageCtxT& image_ctx, AioCompletion* aio_comp,
+ Extents&& image_extents, Request&& request,
+ int op_flags, const ZTracer::Trace& parent_trace)
+ : 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) {
+ }
+
+ ImageCtxT& m_image_ctx;
+ AioCompletion* m_aio_comp;
+ Extents m_image_extents;
+ Request m_request;
+ int m_op_flags;
+ ZTracer::Trace m_parent_trace;
+
+ bool m_throttled = false;
+
+};
+
+} // namespace io
+} // namespace librbd
+
+extern template class librbd::io::ImageDispatchSpec<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_IO_IMAGE_DISPATCH_SPEC_H
} // anonymous namespace
-template <typename I>
-ImageRequest<I>* ImageRequest<I>::create_read_request(
- I &image_ctx, AioCompletion *aio_comp, Extents &&image_extents,
- ReadResult &&read_result, int op_flags,
- const ZTracer::Trace &parent_trace) {
- return new ImageReadRequest<I>(image_ctx, aio_comp,
- std::move(image_extents),
- std::move(read_result), op_flags,
- parent_trace);
-}
-
-template <typename I>
-ImageRequest<I>* ImageRequest<I>::create_write_request(
- I &image_ctx, AioCompletion *aio_comp, Extents &&image_extents,
- bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace) {
- return new ImageWriteRequest<I>(image_ctx, aio_comp, std::move(image_extents),
- std::move(bl), op_flags, parent_trace);
-}
-
-template <typename I>
-ImageRequest<I>* ImageRequest<I>::create_discard_request(
- I &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len,
- bool skip_partial_discard, const ZTracer::Trace &parent_trace) {
- return new ImageDiscardRequest<I>(image_ctx, aio_comp, off, len,
- skip_partial_discard, parent_trace);
-}
-
-template <typename I>
-ImageRequest<I>* ImageRequest<I>::create_flush_request(
- I &image_ctx, AioCompletion *aio_comp,
- const ZTracer::Trace &parent_trace) {
- return new ImageFlushRequest<I>(image_ctx, aio_comp, parent_trace);
-}
-
-template <typename I>
-ImageRequest<I>* ImageRequest<I>::create_writesame_request(
- I &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len,
- bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace) {
- return new ImageWriteSameRequest<I>(image_ctx, aio_comp, off, len,
- std::move(bl), op_flags, parent_trace);
-}
-
-template <typename I>
-ImageRequest<I>* ImageRequest<I>::create_compare_and_write_request(
- I &image_ctx, AioCompletion *c, Extents &&image_extents,
- bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset,
- int op_flags, const ZTracer::Trace &parent_trace) {
- return new ImageCompareAndWriteRequest<I>(image_ctx, c,
- std::move(image_extents),
- std::move(cmp_bl),
- std::move(bl), mismatch_offset,
- op_flags, parent_trace);
-}
-
template <typename I>
void ImageRequest<I>::aio_read(I *ictx, AioCompletion *c,
Extents &&image_extents,
template <typename I>
void ImageRequest<I>::aio_discard(I *ictx, AioCompletion *c,
- uint64_t off, uint64_t len,
+ Extents &&image_extents,
bool skip_partial_discard,
const ZTracer::Trace &parent_trace) {
- ImageDiscardRequest<I> req(*ictx, c, off, len, skip_partial_discard,
- parent_trace);
+ ImageDiscardRequest<I> req(*ictx, c, std::move(image_extents),
+ skip_partial_discard, parent_trace);
req.send();
}
template <typename I>
void ImageRequest<I>::aio_writesame(I *ictx, AioCompletion *c,
- uint64_t off, uint64_t len,
+ Extents &&image_extents,
bufferlist &&bl, int op_flags,
const ZTracer::Trace &parent_trace) {
- ImageWriteSameRequest<I> req(*ictx, c, off, len, std::move(bl), op_flags,
- parent_trace);
+ ImageWriteSameRequest<I> req(*ictx, c, std::move(image_extents),
+ std::move(bl), op_flags, parent_trace);
req.send();
}
return 0;
}
-template <typename I>
-void ImageRequest<I>::start_op() {
- m_aio_comp->start_op();
-}
-
-template <typename I>
-void ImageRequest<I>::fail(int r) {
- AioCompletion *aio_comp = this->m_aio_comp;
- aio_comp->get();
- aio_comp->fail(r);
-}
-
template <typename I>
ImageReadRequest<I>::ImageReadRequest(I &image_ctx, AioCompletion *aio_comp,
Extents &&image_extents,
m_trace.event("finish");
}
- static ImageRequest* create_read_request(ImageCtxT &image_ctx,
- AioCompletion *aio_comp,
- Extents &&image_extents,
- ReadResult &&read_result,
- int op_flags,
- const ZTracer::Trace &parent_trace);
- static ImageRequest* create_write_request(ImageCtxT &image_ctx,
- AioCompletion *aio_comp,
- Extents &&image_extents,
- bufferlist &&bl, int op_flags,
- const ZTracer::Trace &parent_trace);
- static ImageRequest* create_discard_request(ImageCtxT &image_ctx,
- AioCompletion *aio_comp,
- uint64_t off, uint64_t len,
- bool skip_partial_discard,
- const ZTracer::Trace &parent_trace);
- static ImageRequest* create_flush_request(ImageCtxT &image_ctx,
- AioCompletion *aio_comp,
- const ZTracer::Trace &parent_trace);
- static ImageRequest* create_writesame_request(ImageCtxT &image_ctx,
- AioCompletion *aio_comp,
- uint64_t off, uint64_t len,
- bufferlist &&bl, int op_flags,
- const ZTracer::Trace &parent_trace);
- static ImageRequest* create_compare_and_write_request(
- ImageCtxT &image_ctx, AioCompletion *c, Extents &&image_extents,
- bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset,
- int op_flags, const ZTracer::Trace &parent_trace);
-
static void aio_read(ImageCtxT *ictx, AioCompletion *c,
Extents &&image_extents, ReadResult &&read_result,
int op_flags, const ZTracer::Trace &parent_trace);
static void aio_write(ImageCtxT *ictx, AioCompletion *c,
Extents &&image_extents, bufferlist &&bl, int op_flags,
const ZTracer::Trace &parent_trace);
- static void aio_discard(ImageCtxT *ictx, AioCompletion *c, uint64_t off,
- uint64_t len, bool skip_partial_discard,
+ static void aio_discard(ImageCtxT *ictx, AioCompletion *c,
+ Extents &&image_extents, bool skip_partial_discard,
const ZTracer::Trace &parent_trace);
static void aio_flush(ImageCtxT *ictx, AioCompletion *c,
const ZTracer::Trace &parent_trace);
- static void aio_writesame(ImageCtxT *ictx, AioCompletion *c, uint64_t off,
- uint64_t len, bufferlist &&bl, int op_flags,
- const ZTracer::Trace &parent_trace);
+ static void aio_writesame(ImageCtxT *ictx, AioCompletion *c,
+ Extents &&image_extents, bufferlist &&bl,
+ int op_flags, const ZTracer::Trace &parent_trace);
static void aio_compare_and_write(ImageCtxT *ictx, AioCompletion *c,
Extents &&image_extents, bufferlist &&cmp_bl,
bufferlist &&bl, uint64_t *mismatch_offset,
int op_flags, const ZTracer::Trace &parent_trace);
- virtual bool is_write_op() const {
- return false;
- }
-
- void start_op();
-
void send();
- void fail(int r);
void set_bypass_image_cache() {
m_bypass_image_cache = true;
return m_trace;
}
- bool was_throttled() {
- return m_throttled;
- }
-
- void set_throttled() {
- m_throttled = true;
- }
-
protected:
typedef std::list<ObjectRequestHandle *> ObjectRequests;
Extents m_image_extents;
ZTracer::Trace m_trace;
bool m_bypass_image_cache = false;
- bool m_throttled = false;
ImageRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp,
Extents &&image_extents, const char *trace_name,
m_trace(util::create_trace(image_ctx, trace_name, parent_trace)) {
m_trace.event("start");
}
-
+
virtual int clip_request();
virtual void send_request() = 0;
template <typename ImageCtxT = ImageCtx>
class AbstractImageWriteRequest : public ImageRequest<ImageCtxT> {
public:
- bool is_write_op() const override {
- return true;
- }
-
inline void flag_synchronous() {
m_synchronous = true;
}
class ImageDiscardRequest : public AbstractImageWriteRequest<ImageCtxT> {
public:
ImageDiscardRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp,
- uint64_t off, uint64_t len, bool skip_partial_discard,
+ Extents&& image_extents, bool skip_partial_discard,
const ZTracer::Trace &parent_trace)
: AbstractImageWriteRequest<ImageCtxT>(
- image_ctx, aio_comp, {{off, len}}, "discard", parent_trace),
+ image_ctx, aio_comp, std::move(image_extents), "discard", parent_trace),
m_skip_partial_discard(skip_partial_discard) {
}
: ImageRequest<ImageCtxT>(image_ctx, aio_comp, {}, "flush", parent_trace) {
}
- bool is_write_op() const override {
- return true;
- }
-
protected:
using typename ImageRequest<ImageCtxT>::ObjectRequests;
class ImageWriteSameRequest : public AbstractImageWriteRequest<ImageCtxT> {
public:
ImageWriteSameRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp,
- uint64_t off, uint64_t len, bufferlist &&bl,
+ Extents&& image_extents, bufferlist &&bl,
int op_flags, const ZTracer::Trace &parent_trace)
: AbstractImageWriteRequest<ImageCtxT>(
- image_ctx, aio_comp, {{off, len}}, "writesame", parent_trace),
+ image_ctx, aio_comp, std::move(image_extents), "writesame",
+ parent_trace),
m_data_bl(std::move(bl)), m_op_flags(op_flags) {
}
#include "librbd/exclusive_lock/Policy.h"
#include "librbd/io/AioCompletion.h"
#include "librbd/io/ImageRequest.h"
+#include "librbd/io/ImageDispatchSpec.h"
#include "common/EventTrace.h"
#define dout_subsys ceph_subsys_rbd
template <typename I>
struct ImageRequestWQ<I>::C_AcquireLock : public Context {
ImageRequestWQ *work_queue;
- ImageRequest<I> *image_request;
+ ImageDispatchSpec<I> *image_request;
- C_AcquireLock(ImageRequestWQ *work_queue, ImageRequest<I> *image_request)
+ C_AcquireLock(ImageRequestWQ *work_queue, ImageDispatchSpec<I> *image_request)
: work_queue(work_queue), image_request(image_request) {
}
template <typename I>
struct ImageRequestWQ<I>::C_RefreshFinish : public Context {
ImageRequestWQ *work_queue;
- ImageRequest<I> *image_request;
+ ImageDispatchSpec<I> *image_request;
C_RefreshFinish(ImageRequestWQ *work_queue,
- ImageRequest<I> *image_request)
+ ImageDispatchSpec<I> *image_request)
: work_queue(work_queue), image_request(image_request) {
}
void finish(int r) override {
template <typename I>
ImageRequestWQ<I>::ImageRequestWQ(I *image_ctx, const string &name,
time_t ti, ThreadPool *tp)
- : ThreadPool::PointerWQ<ImageRequest<I> >(name, ti, 0, tp),
+ : ThreadPool::PointerWQ<ImageDispatchSpec<I> >(name, ti, 0, tp),
m_image_ctx(*image_ctx),
m_lock(util::unique_lock_name("ImageRequestWQ<I>::m_lock", this)) {
CephContext *cct = m_image_ctx.cct;
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.non_blocking_aio || writes_blocked() || !writes_empty() ||
require_lock_on_read()) {
- queue(ImageRequest<I>::create_read_request(
+ queue(ImageDispatchSpec<I>::create_read_request(
m_image_ctx, c, {{off, len}}, std::move(read_result), op_flags,
trace));
} else {
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.non_blocking_aio || writes_blocked()) {
- queue(ImageRequest<I>::create_write_request(
+ queue(ImageDispatchSpec<I>::create_write_request(
m_image_ctx, c, {{off, len}}, std::move(bl), op_flags, trace));
} else {
c->start_op();
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.non_blocking_aio || writes_blocked()) {
- queue(ImageRequest<I>::create_discard_request(
+ queue(ImageDispatchSpec<I>::create_discard_request(
m_image_ctx, c, off, len, skip_partial_discard, trace));
} else {
c->start_op();
- ImageRequest<I>::aio_discard(&m_image_ctx, c, off, len,
+ ImageRequest<I>::aio_discard(&m_image_ctx, c, {{off, len}},
skip_partial_discard, trace);
finish_in_flight_io();
}
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.non_blocking_aio || writes_blocked() || !writes_empty()) {
- queue(ImageRequest<I>::create_flush_request(m_image_ctx, c, trace));
+ queue(ImageDispatchSpec<I>::create_flush_request(m_image_ctx, c, trace));
} else {
ImageRequest<I>::aio_flush(&m_image_ctx, c, trace);
finish_in_flight_io();
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.non_blocking_aio || writes_blocked()) {
- queue(ImageRequest<I>::create_writesame_request(
+ queue(ImageDispatchSpec<I>::create_write_same_request(
m_image_ctx, c, off, len, std::move(bl), op_flags, trace));
} else {
c->start_op();
- ImageRequest<I>::aio_writesame(&m_image_ctx, c, off, len, std::move(bl),
+ ImageRequest<I>::aio_writesame(&m_image_ctx, c, {{off, len}}, std::move(bl),
op_flags, trace);
finish_in_flight_io();
}
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.non_blocking_aio || writes_blocked()) {
- queue(ImageRequest<I>::create_compare_and_write_request(
+ queue(ImageDispatchSpec<I>::create_compare_and_write_request(
m_image_ctx, c, {{off, len}}, std::move(cmp_bl), std::move(bl),
mismatch_off, op_flags, trace));
} else {
}
template <typename I>
-void ImageRequestWQ<I>::handle_iops_throttle_ready(int r,
- ImageRequest<I> *item) {
+void ImageRequestWQ<I>::handle_iops_throttle_ready(
+ int r, ImageDispatchSpec<I> *item) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 15) << "r=" << r << ", " << "req=" << item << dendl;
template <typename I>
void *ImageRequestWQ<I>::_void_dequeue() {
CephContext *cct = m_image_ctx.cct;
- ImageRequest<I> *peek_item = this->front();
+ ImageDispatchSpec<I> *peek_item = this->front();
// no queued IO requests or all IO is blocked/stalled
if (peek_item == nullptr || m_io_blockers.load() > 0) {
if (!peek_item->was_throttled() &&
iops_throttle->get<
- ImageRequestWQ<I>, ImageRequest<I>,
+ ImageRequestWQ<I>, ImageDispatchSpec<I>,
&ImageRequestWQ<I>::handle_iops_throttle_ready>(1, this, peek_item)) {
ldout(cct, 15) << "throttling IO " << peek_item << dendl;
// dequeue the throttled item and block future IO
- ThreadPool::PointerWQ<ImageRequest<I> >::_void_dequeue();
+ ThreadPool::PointerWQ<ImageDispatchSpec<I> >::_void_dequeue();
++m_io_blockers;
return nullptr;
}
}
}
- ImageRequest<I> *item = reinterpret_cast<ImageRequest<I> *>(
- ThreadPool::PointerWQ<ImageRequest<I> >::_void_dequeue());
+ auto item = reinterpret_cast<ImageDispatchSpec<I> *>(
+ ThreadPool::PointerWQ<ImageDispatchSpec<I> >::_void_dequeue());
assert(peek_item == item);
if (lock_required) {
}
template <typename I>
-void ImageRequestWQ<I>::process(ImageRequest<I> *req) {
+void ImageRequestWQ<I>::process(ImageDispatchSpec<I> *req) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 20) << "ictx=" << &m_image_ctx << ", "
<< "req=" << req << dendl;
}
template <typename I>
-void ImageRequestWQ<I>::finish_queued_io(ImageRequest<I> *req) {
+void ImageRequestWQ<I>::finish_queued_io(ImageDispatchSpec<I> *req) {
RWLock::RLocker locker(m_lock);
if (req->is_write_op()) {
assert(m_queued_writes > 0);
}
template <typename I>
-void ImageRequestWQ<I>::fail_in_flight_io(int r, ImageRequest<I> *req) {
+void ImageRequestWQ<I>::fail_in_flight_io(
+ int r, ImageDispatchSpec<I> *req) {
this->process_finish();
req->fail(r);
finish_queued_io(req);
}
template <typename I>
-void ImageRequestWQ<I>::queue(ImageRequest<I> *req) {
+void ImageRequestWQ<I>::queue(ImageDispatchSpec<I> *req) {
assert(m_image_ctx.owner_lock.is_locked());
CephContext *cct = m_image_ctx.cct;
m_queued_reads++;
}
- ThreadPool::PointerWQ<ImageRequest<I> >::queue(req);
+ ThreadPool::PointerWQ<ImageDispatchSpec<I> >::queue(req);
}
template <typename I>
-void ImageRequestWQ<I>::handle_acquire_lock(int r, ImageRequest<I> *req) {
+void ImageRequestWQ<I>::handle_acquire_lock(
+ int r, ImageDispatchSpec<I> *req) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 5) << "r=" << r << ", " << "req=" << req << dendl;
}
template <typename I>
-void ImageRequestWQ<I>::handle_refreshed(int r, ImageRequest<I> *req) {
+void ImageRequestWQ<I>::handle_refreshed(
+ int r, ImageDispatchSpec<I> *req) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 5) << "resuming IO after image refresh: r=" << r << ", "
<< "req=" << req << dendl;
namespace io {
class AioCompletion;
-template <typename> class ImageRequest;
+template <typename> class ImageDispatchSpec;
class ReadResult;
template <typename ImageCtxT = librbd::ImageCtx>
class ImageRequestWQ
- : public ThreadPool::PointerWQ<ImageRequest<ImageCtxT> > {
+ : public ThreadPool::PointerWQ<ImageDispatchSpec<ImageCtxT> > {
public:
ImageRequestWQ(ImageCtxT *image_ctx, const string &name, time_t ti,
ThreadPool *tp);
bufferlist &&bl, uint64_t *mismatch_off,
int op_flags, bool native_async=true);
- using ThreadPool::PointerWQ<ImageRequest<ImageCtxT> >::drain;
-
- using ThreadPool::PointerWQ<ImageRequest<ImageCtxT> >::empty;
+ using ThreadPool::PointerWQ<ImageDispatchSpec<ImageCtxT> >::drain;
+ using ThreadPool::PointerWQ<ImageDispatchSpec<ImageCtxT> >::empty;
void shut_down(Context *on_shutdown);
protected:
void *_void_dequeue() override;
- void process(ImageRequest<ImageCtxT> *req) override;
+ void process(ImageDispatchSpec<ImageCtxT> *req) override;
private:
typedef std::list<Context *> Contexts;
return (m_queued_writes == 0);
}
- void finish_queued_io(ImageRequest<ImageCtxT> *req);
+ void finish_queued_io(ImageDispatchSpec<ImageCtxT> *req);
void finish_in_flight_write();
int start_in_flight_io(AioCompletion *c);
void finish_in_flight_io();
- void fail_in_flight_io(int r, ImageRequest<ImageCtxT> *req);
+ void fail_in_flight_io(int r, ImageDispatchSpec<ImageCtxT> *req);
- void queue(ImageRequest<ImageCtxT> *req);
+ void queue(ImageDispatchSpec<ImageCtxT> *req);
- void handle_acquire_lock(int r, ImageRequest<ImageCtxT> *req);
- void handle_refreshed(int r, ImageRequest<ImageCtxT> *req);
+ void handle_acquire_lock(int r, ImageDispatchSpec<ImageCtxT> *req);
+ void handle_refreshed(int r, ImageDispatchSpec<ImageCtxT> *req);
void handle_blocked_writes(int r);
- void handle_iops_throttle_ready(int r, ImageRequest<ImageCtxT> *item);
+ void handle_iops_throttle_ready(int r, ImageDispatchSpec<ImageCtxT> *item);
};
} // namespace io
return;
}
- io::ImageRequest<I>::aio_discard(&m_image_ctx, aio_comp, event.offset,
- event.length, event.skip_partial_discard,
- {});
+ io::ImageRequest<I>::aio_discard(&m_image_ctx, aio_comp,
+ {{event.offset, event.length}},
+ event.skip_partial_discard, {});
if (flush_required) {
m_lock.Lock();
auto flush_comp = create_aio_flush_completion(nullptr);
return;
}
- io::ImageRequest<I>::aio_writesame(&m_image_ctx, aio_comp, event.offset,
- event.length, std::move(data), 0, {});
+ io::ImageRequest<I>::aio_writesame(&m_image_ctx, aio_comp,
+ {{event.offset, event.length}},
+ std::move(data), 0, {});
if (flush_required) {
m_lock.Lock();
auto flush_comp = create_aio_flush_completion(nullptr);
AioCompletion *aio_comp = AioCompletion::create_and_start(
&aio_comp_ctx, ictx, AIO_TYPE_DISCARD);
MockImageDiscardRequest mock_aio_image_discard(mock_image_ctx, aio_comp,
- 0, 1,
+ {{0, 1}},
ictx->skip_partial_discard,
{});
{
bufferlist bl;
bl.append("1");
MockImageWriteSameRequest mock_aio_image_writesame(mock_image_ctx, aio_comp,
- 0, 1, std::move(bl), 0,
+ {{0, 1}}, std::move(bl), 0,
{});
{
RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
#include "test/librbd/test_support.h"
#include "test/librbd/mock/MockImageCtx.h"
#include "test/librbd/mock/exclusive_lock/MockPolicy.h"
+#include "librbd/io/ImageDispatchSpec.h"
#include "librbd/io/ImageRequestWQ.h"
#include "librbd/io/ImageRequest.h"
static ImageRequest* s_instance;
AioCompletion *aio_comp = nullptr;
- static ImageRequest* create_write_request(librbd::MockTestImageCtx &image_ctx,
- AioCompletion *aio_comp,
- Extents &&image_extents,
- bufferlist &&bl, int op_flags,
- const ZTracer::Trace &parent_trace) {
- assert(s_instance != nullptr);
- s_instance->aio_comp = aio_comp;
- return s_instance;
- }
static void aio_write(librbd::MockTestImageCtx *ictx, AioCompletion *c,
Extents &&image_extents, bufferlist &&bl, int op_flags,
const ZTracer::Trace &parent_trace) {
}
+ ImageRequest() {
+ s_instance = this;
+ }
+};
+
+template <>
+struct ImageDispatchSpec<librbd::MockTestImageCtx> {
+ static ImageDispatchSpec* s_instance;
+ AioCompletion *aio_comp = nullptr;
+
+ static ImageDispatchSpec* create_write_request(
+ librbd::MockTestImageCtx &image_ctx, AioCompletion *aio_comp,
+ Extents &&image_extents, bufferlist &&bl, int op_flags,
+ const ZTracer::Trace &parent_trace) {
+ assert(s_instance != nullptr);
+ s_instance->aio_comp = aio_comp;
+ return s_instance;
+ }
MOCK_CONST_METHOD0(is_write_op, bool());
MOCK_CONST_METHOD0(start_op, void());
MOCK_CONST_METHOD0(was_throttled, bool());
MOCK_CONST_METHOD0(set_throttled, void());
- ImageRequest() {
+ ImageDispatchSpec() {
s_instance = this;
}
};
-
} // namespace io
namespace util {
} // namespace librbd
template <>
-struct ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>> {
- typedef librbd::io::ImageRequest<librbd::MockTestImageCtx> ImageRequest;
+struct ThreadPool::PointerWQ<librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>> {
+ typedef librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx> ImageDispatchSpec;
static PointerWQ* s_instance;
Mutex m_lock;
MOCK_METHOD0(signal, void());
MOCK_METHOD0(process_finish, void());
- MOCK_METHOD0(front, ImageRequest*());
- MOCK_METHOD1(requeue, void(ImageRequest*));
+ MOCK_METHOD0(front, ImageDispatchSpec*());
+ MOCK_METHOD1(requeue, void(ImageDispatchSpec*));
MOCK_METHOD0(dequeue, void*());
- MOCK_METHOD1(queue, void(ImageRequest*));
+ MOCK_METHOD1(queue, void(ImageDispatchSpec*));
void register_work_queue() {
// no-op
Mutex::Locker locker(m_lock);
return _void_dequeue();
}
- void invoke_process(ImageRequest *image_request) {
+ void invoke_process(ImageDispatchSpec *image_request) {
process(image_request);
}
virtual void *_void_dequeue() {
return dequeue();
}
- virtual void process(ImageRequest *req) = 0;
+ virtual void process(ImageDispatchSpec *req) = 0;
};
-ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>*
- ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>::s_instance = nullptr;
+ThreadPool::PointerWQ<librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>>*
+ ThreadPool::PointerWQ<librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>>::s_instance = nullptr;
librbd::io::ImageRequest<librbd::MockTestImageCtx>*
librbd::io::ImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>*
+ librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>::s_instance = nullptr;
#include "librbd/io/ImageRequestWQ.cc"
struct TestMockIoImageRequestWQ : public TestMockFixture {
typedef ImageRequestWQ<librbd::MockTestImageCtx> MockImageRequestWQ;
typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
+ typedef ImageDispatchSpec<librbd::MockTestImageCtx> MockImageDispatchSpec;
- void expect_is_write_op(MockImageRequest &image_request, bool write_op) {
+ void expect_is_write_op(MockImageDispatchSpec &image_request,
+ bool write_op) {
EXPECT_CALL(image_request, is_write_op()).WillOnce(Return(write_op));
}
}
void expect_front(MockImageRequestWQ &image_request_wq,
- MockImageRequest *image_request) {
+ MockImageDispatchSpec *image_request) {
EXPECT_CALL(image_request_wq, front()).WillOnce(Return(image_request));
}
}
void expect_dequeue(MockImageRequestWQ &image_request_wq,
- MockImageRequest *image_request) {
+ MockImageDispatchSpec *image_request) {
EXPECT_CALL(image_request_wq, dequeue()).WillOnce(Return(image_request));
}
EXPECT_CALL(mock_image_request_wq, process_finish()).Times(1);
}
- void expect_fail(MockImageRequest &mock_image_request, int r) {
+ void expect_fail(MockImageDispatchSpec &mock_image_request, int r) {
EXPECT_CALL(mock_image_request, fail(r))
.WillOnce(Invoke([&mock_image_request](int r) {
mock_image_request.aio_comp->get();
}));
}
- void expect_was_throttled(MockImageRequest &mock_image_request,
+ void expect_was_throttled(MockImageDispatchSpec &mock_image_request,
bool throttled) {
EXPECT_CALL(mock_image_request, was_throttled())
.WillOnce(Return(throttled));
expect_signal(mock_image_request_wq);
mock_image_request_wq.set_require_lock(DIRECTION_WRITE, true);
- auto mock_image_request = new MockImageRequest();
- expect_is_write_op(*mock_image_request, true);
+ auto mock_queued_image_request = new MockImageDispatchSpec();
+ expect_is_write_op(*mock_queued_image_request, true);
expect_queue(mock_image_request_wq);
auto *aio_comp = new librbd::io::AioCompletion();
mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
librbd::exclusive_lock::MockPolicy mock_exclusive_lock_policy;
- expect_front(mock_image_request_wq, mock_image_request);
- expect_was_throttled(*mock_image_request, false);
+ expect_front(mock_image_request_wq, mock_queued_image_request);
+ expect_was_throttled(*mock_queued_image_request, false);
expect_is_refresh_request(mock_image_ctx, false);
- expect_is_write_op(*mock_image_request, true);
- expect_dequeue(mock_image_request_wq, mock_image_request);
+ expect_is_write_op(*mock_queued_image_request, true);
+ expect_dequeue(mock_image_request_wq, mock_queued_image_request);
expect_get_exclusive_lock_policy(mock_image_ctx, mock_exclusive_lock_policy);
expect_may_auto_request_lock(mock_exclusive_lock_policy, true);
Context *on_acquire = nullptr;
ASSERT_TRUE(on_acquire != nullptr);
expect_process_finish(mock_image_request_wq);
- expect_fail(*mock_image_request, -EPERM);
- expect_is_write_op(*mock_image_request, true);
+ expect_fail(*mock_queued_image_request, -EPERM);
+ expect_is_write_op(*mock_queued_image_request, true);
expect_signal(mock_image_request_wq);
on_acquire->complete(-EPERM);
InSequence seq;
MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
- auto mock_image_request = new MockImageRequest();
- expect_is_write_op(*mock_image_request, true);
+ auto mock_queued_image_request = new MockImageDispatchSpec();
+ expect_is_write_op(*mock_queued_image_request, true);
expect_queue(mock_image_request_wq);
auto *aio_comp = new librbd::io::AioCompletion();
mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
- expect_front(mock_image_request_wq, mock_image_request);
- expect_was_throttled(*mock_image_request, false);
+ expect_front(mock_image_request_wq, mock_queued_image_request);
+ expect_was_throttled(*mock_queued_image_request, false);
expect_is_refresh_request(mock_image_ctx, true);
- expect_is_write_op(*mock_image_request, true);
- expect_dequeue(mock_image_request_wq, mock_image_request);
+ expect_is_write_op(*mock_queued_image_request, true);
+ expect_dequeue(mock_image_request_wq, mock_queued_image_request);
Context *on_refresh = nullptr;
expect_refresh(mock_image_ctx, &on_refresh);
ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
ASSERT_TRUE(on_refresh != nullptr);
expect_process_finish(mock_image_request_wq);
- expect_fail(*mock_image_request, -EPERM);
- expect_is_write_op(*mock_image_request, true);
+ expect_fail(*mock_queued_image_request, -EPERM);
+ expect_is_write_op(*mock_queued_image_request, true);
expect_signal(mock_image_request_wq);
on_refresh->complete(-EPERM);
s_instance->aio_write(c, image_extents, bl, op_flags);
}
- MOCK_METHOD4(aio_discard, void(AioCompletion *c, uint64_t off, uint64_t len,
+ MOCK_METHOD3(aio_discard, void(AioCompletion *c, const Extents& image_extents,
bool skip_partial_discard));
static void aio_discard(MockReplayImageCtx *ictx, AioCompletion *c,
- uint64_t off, uint64_t len,
- bool skip_partial_discard,
+ Extents&& image_extents, bool skip_partial_discard,
const ZTracer::Trace &parent_trace) {
assert(s_instance != nullptr);
- s_instance->aio_discard(c, off, len, skip_partial_discard);
+ s_instance->aio_discard(c, image_extents, skip_partial_discard);
}
MOCK_METHOD1(aio_flush, void(AioCompletion *c));
s_instance->aio_flush(c);
}
- MOCK_METHOD5(aio_writesame, void(AioCompletion *c, uint64_t off, uint64_t len,
+ MOCK_METHOD4(aio_writesame, void(AioCompletion *c,
+ const Extents& image_extents,
const bufferlist &bl, int op_flags));
static void aio_writesame(MockReplayImageCtx *ictx, AioCompletion *c,
- uint64_t off, uint64_t len, bufferlist &&bl,
+ Extents&& image_extents, bufferlist &&bl,
int op_flags, const ZTracer::Trace &parent_trace) {
assert(s_instance != nullptr);
- s_instance->aio_writesame(c, off, len, bl, op_flags);
+ s_instance->aio_writesame(c, image_extents, bl, op_flags);
}
MOCK_METHOD6(aio_compare_and_write, void(AioCompletion *c, const Extents &image_extents,
void expect_aio_discard(MockIoImageRequest &mock_io_image_request,
io::AioCompletion **aio_comp, uint64_t off,
uint64_t len, bool skip_partial_discard) {
- EXPECT_CALL(mock_io_image_request, aio_discard(_, off, len, skip_partial_discard))
+ EXPECT_CALL(mock_io_image_request, aio_discard(_, io::Extents{{off, len}},
+ skip_partial_discard))
.WillOnce(SaveArg<0>(aio_comp));
}
io::AioCompletion **aio_comp, uint64_t off,
uint64_t len, const char *data) {
EXPECT_CALL(mock_io_image_request,
- aio_writesame(_, off, len, BufferlistEqual(data), _))
+ aio_writesame(_, io::Extents{{off, len}},
+ BufferlistEqual(data), _))
.WillOnce(SaveArg<0>(aio_comp));
}
void expect_aio_compare_and_write(MockIoImageRequest &mock_io_image_request,
io::AioCompletion **aio_comp, uint64_t off,
- uint64_t len, const char *cmp_data, const char *data,
+ uint64_t len, const char *cmp_data,
+ const char *data,
uint64_t *mismatch_offset) {
EXPECT_CALL(mock_io_image_request,
aio_compare_and_write(_, io::Extents{{off, len}},
- BufferlistEqual(cmp_data), BufferlistEqual(data), mismatch_offset, _))
+ BufferlistEqual(cmp_data),
+ BufferlistEqual(data),
+ mismatch_offset, _))
.WillOnce(SaveArg<0>(aio_comp));
}