summaryrefslogtreecommitdiffstats
path: root/src/librbd/io/ObjectRequest.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/librbd/io/ObjectRequest.h')
-rw-r--r--src/librbd/io/ObjectRequest.h502
1 files changed, 502 insertions, 0 deletions
diff --git a/src/librbd/io/ObjectRequest.h b/src/librbd/io/ObjectRequest.h
new file mode 100644
index 000000000..89ca224cc
--- /dev/null
+++ b/src/librbd/io/ObjectRequest.h
@@ -0,0 +1,502 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_IO_OBJECT_REQUEST_H
+#define CEPH_LIBRBD_IO_OBJECT_REQUEST_H
+
+#include "include/int_types.h"
+#include "include/buffer.h"
+#include "include/neorados/RADOS.hpp"
+#include "include/rados/librados.hpp"
+#include "common/zipkin_trace.h"
+#include "librbd/ObjectMap.h"
+#include "librbd/Types.h"
+#include "librbd/io/Types.h"
+#include <map>
+
+class Context;
+class ObjectExtent;
+
+namespace neorados { struct WriteOp; }
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace io {
+
+struct AioCompletion;
+template <typename> class CopyupRequest;
+
+/**
+ * This class represents an I/O operation to a single RBD data object.
+ * Its subclasses encapsulate logic for dealing with special cases
+ * for I/O due to layering.
+ */
+template <typename ImageCtxT = ImageCtx>
+class ObjectRequest {
+public:
+ static ObjectRequest* create_write(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
+ ceph::bufferlist&& data, IOContext io_context, int op_flags,
+ int write_flags, std::optional<uint64_t> assert_version,
+ const ZTracer::Trace &parent_trace, Context *completion);
+ static ObjectRequest* create_discard(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
+ uint64_t object_len, IOContext io_context, int discard_flags,
+ const ZTracer::Trace &parent_trace, Context *completion);
+ static ObjectRequest* create_write_same(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
+ uint64_t object_len, ceph::bufferlist&& data, IOContext io_context,
+ int op_flags, const ZTracer::Trace &parent_trace, Context *completion);
+ static ObjectRequest* create_compare_and_write(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
+ ceph::bufferlist&& cmp_data, ceph::bufferlist&& write_data,
+ IOContext io_context, uint64_t *mismatch_offset, int op_flags,
+ const ZTracer::Trace &parent_trace, Context *completion);
+
+ ObjectRequest(ImageCtxT *ictx, uint64_t objectno, IOContext io_context,
+ const char *trace_name, const ZTracer::Trace &parent_trace,
+ Context *completion);
+ virtual ~ObjectRequest() {
+ m_trace.event("finish");
+ }
+
+ static void add_write_hint(ImageCtxT& image_ctx,
+ neorados::WriteOp *wr);
+
+ virtual void send() = 0;
+
+ bool has_parent() const {
+ return m_has_parent;
+ }
+
+ virtual const char *get_op_type() const = 0;
+
+protected:
+ bool compute_parent_extents(Extents *parent_extents, bool read_request);
+
+ ImageCtxT *m_ictx;
+ uint64_t m_object_no;
+ IOContext m_io_context;
+ Context *m_completion;
+ ZTracer::Trace m_trace;
+
+ void async_finish(int r);
+ void finish(int r);
+
+private:
+ bool m_has_parent = false;
+};
+
+template <typename ImageCtxT = ImageCtx>
+class ObjectReadRequest : public ObjectRequest<ImageCtxT> {
+public:
+ static ObjectReadRequest* create(
+ ImageCtxT *ictx, uint64_t objectno, ReadExtents* extents,
+ IOContext io_context, int op_flags, int read_flags,
+ const ZTracer::Trace &parent_trace, uint64_t* version,
+ Context *completion) {
+ return new ObjectReadRequest(ictx, objectno, extents, io_context, op_flags,
+ read_flags, parent_trace, version, completion);
+ }
+
+ ObjectReadRequest(
+ ImageCtxT *ictx, uint64_t objectno, ReadExtents* extents,
+ IOContext io_context, int op_flags, int read_flags,
+ const ZTracer::Trace &parent_trace, uint64_t* version,
+ Context *completion);
+
+ void send() override;
+
+ const char *get_op_type() const override {
+ return "read";
+ }
+
+private:
+ /**
+ * @verbatim
+ *
+ * <start>
+ * |
+ * |
+ * v
+ * READ_OBJECT
+ * |
+ * v (skip if not needed)
+ * READ_PARENT
+ * |
+ * v (skip if not needed)
+ * COPYUP
+ * |
+ * v
+ * <finish>
+ *
+ * @endverbatim
+ */
+
+ ReadExtents* m_extents;
+ int m_op_flags;
+ int m_read_flags;
+ uint64_t* m_version;
+
+ void read_object();
+ void handle_read_object(int r);
+
+ void read_parent();
+ void handle_read_parent(int r);
+
+ void copyup();
+};
+
+template <typename ImageCtxT = ImageCtx>
+class AbstractObjectWriteRequest : public ObjectRequest<ImageCtxT> {
+public:
+ AbstractObjectWriteRequest(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, uint64_t len,
+ IOContext io_context, const char *trace_name,
+ const ZTracer::Trace &parent_trace, Context *completion);
+
+ virtual bool is_empty_write_op() const {
+ return false;
+ }
+
+ virtual uint8_t get_pre_write_object_map_state() const {
+ return OBJECT_EXISTS;
+ }
+
+ virtual void add_copyup_ops(neorados::WriteOp *wr) {
+ add_write_ops(wr);
+ }
+
+ void handle_copyup(int r);
+
+ void send() override;
+
+protected:
+ uint64_t m_object_off;
+ uint64_t m_object_len;
+ bool m_full_object = false;
+ bool m_copyup_enabled = true;
+
+ virtual bool is_no_op_for_nonexistent_object() const {
+ return false;
+ }
+ virtual bool is_object_map_update_enabled() const {
+ return true;
+ }
+ virtual bool is_post_copyup_write_required() const {
+ return false;
+ }
+ virtual bool is_non_existent_post_write_object_map_state() const {
+ return false;
+ }
+
+ virtual void add_write_hint(neorados::WriteOp *wr);
+ virtual void add_write_ops(neorados::WriteOp *wr) = 0;
+
+ virtual int filter_write_result(int r) const {
+ return r;
+ }
+
+ virtual Extents get_copyup_overwrite_extents() const {
+ return {{m_object_off, m_object_len}};
+ }
+
+private:
+ /**
+ * @verbatim
+ *
+ * <start>
+ * |
+ * v (no-op write request)
+ * DETECT_NO_OP . . . . . . . . . . . . . . . . . . .
+ * | .
+ * v (skip if not required/disabled) .
+ * PRE_UPDATE_OBJECT_MAP .
+ * | . .
+ * | . (child dne) .
+ * | . . . . . . . . . .
+ * | . .
+ * | (post-copyup write) . .
+ * | . . . . . . . . . . . . . .
+ * | . . . .
+ * v v . v .
+ * WRITE . . . . . . . . > COPYUP (if required) .
+ * | | .
+ * |/----------------------/ .
+ * | .
+ * v (skip if not required/disabled) .
+ * POST_UPDATE_OBJECT_MAP .
+ * | .
+ * v .
+ * <finish> < . . . . . . . . . . . . . . . . . . . .
+ *
+ * @endverbatim
+ */
+
+ Extents m_parent_extents;
+ bool m_object_may_exist = false;
+ bool m_copyup_in_progress = false;
+ bool m_guarding_migration_write = false;
+
+ void compute_parent_info();
+
+ void pre_write_object_map_update();
+ void handle_pre_write_object_map_update(int r);
+
+ void write_object();
+ void handle_write_object(int r);
+
+ void copyup();
+
+ void post_write_object_map_update();
+ void handle_post_write_object_map_update(int r);
+
+};
+
+template <typename ImageCtxT = ImageCtx>
+class ObjectWriteRequest : public AbstractObjectWriteRequest<ImageCtxT> {
+public:
+ ObjectWriteRequest(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
+ ceph::bufferlist&& data, IOContext io_context, int op_flags,
+ int write_flags, std::optional<uint64_t> assert_version,
+ const ZTracer::Trace &parent_trace, Context *completion)
+ : AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off,
+ data.length(), io_context, "write",
+ parent_trace, completion),
+ m_write_data(std::move(data)), m_op_flags(op_flags),
+ m_write_flags(write_flags), m_assert_version(assert_version) {
+ }
+
+ bool is_empty_write_op() const override {
+ return (m_write_data.length() == 0);
+ }
+
+ const char *get_op_type() const override {
+ return "write";
+ }
+
+protected:
+ void add_write_ops(neorados::WriteOp *wr) override;
+ void add_write_hint(neorados::WriteOp *wr) override;
+
+private:
+ ceph::bufferlist m_write_data;
+ int m_op_flags;
+ int m_write_flags;
+ std::optional<uint64_t> m_assert_version;
+};
+
+template <typename ImageCtxT = ImageCtx>
+class ObjectDiscardRequest : public AbstractObjectWriteRequest<ImageCtxT> {
+public:
+ ObjectDiscardRequest(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
+ uint64_t object_len, IOContext io_context, int discard_flags,
+ const ZTracer::Trace &parent_trace, Context *completion)
+ : AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off,
+ object_len, io_context, "discard",
+ parent_trace, completion),
+ m_discard_flags(discard_flags) {
+ if (this->m_full_object) {
+ if ((m_discard_flags & OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE) != 0 &&
+ this->has_parent()) {
+ if (!this->m_copyup_enabled) {
+ // need to hide the parent object instead of child object
+ m_discard_action = DISCARD_ACTION_REMOVE_TRUNCATE;
+ } else {
+ m_discard_action = DISCARD_ACTION_TRUNCATE;
+ }
+ } else {
+ m_discard_action = DISCARD_ACTION_REMOVE;
+ }
+ } else if (object_off + object_len == ictx->layout.object_size) {
+ m_discard_action = DISCARD_ACTION_TRUNCATE;
+ } else {
+ m_discard_action = DISCARD_ACTION_ZERO;
+ }
+ }
+
+ const char* get_op_type() const override {
+ switch (m_discard_action) {
+ case DISCARD_ACTION_REMOVE:
+ return "remove";
+ case DISCARD_ACTION_REMOVE_TRUNCATE:
+ return "remove (create+truncate)";
+ case DISCARD_ACTION_TRUNCATE:
+ return "truncate";
+ case DISCARD_ACTION_ZERO:
+ return "zero";
+ }
+ ceph_abort();
+ return nullptr;
+ }
+
+ uint8_t get_pre_write_object_map_state() const override {
+ if (m_discard_action == DISCARD_ACTION_REMOVE) {
+ return OBJECT_PENDING;
+ }
+ return OBJECT_EXISTS;
+ }
+
+protected:
+ bool is_no_op_for_nonexistent_object() const override {
+ return (!this->has_parent());
+ }
+ bool is_object_map_update_enabled() const override {
+ return (
+ (m_discard_flags & OBJECT_DISCARD_FLAG_DISABLE_OBJECT_MAP_UPDATE) == 0);
+ }
+ bool is_non_existent_post_write_object_map_state() const override {
+ return (m_discard_action == DISCARD_ACTION_REMOVE);
+ }
+
+ void add_write_hint(neorados::WriteOp *wr) override {
+ // no hint for discard
+ }
+
+ void add_write_ops(neorados::WriteOp *wr) override;
+
+private:
+ enum DiscardAction {
+ DISCARD_ACTION_REMOVE,
+ DISCARD_ACTION_REMOVE_TRUNCATE,
+ DISCARD_ACTION_TRUNCATE,
+ DISCARD_ACTION_ZERO
+ };
+
+ DiscardAction m_discard_action;
+ int m_discard_flags;
+
+};
+
+template <typename ImageCtxT = ImageCtx>
+class ObjectWriteSameRequest : public AbstractObjectWriteRequest<ImageCtxT> {
+public:
+ ObjectWriteSameRequest(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
+ uint64_t object_len, ceph::bufferlist&& data, IOContext io_context,
+ int op_flags, const ZTracer::Trace &parent_trace, Context *completion)
+ : AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off,
+ object_len, io_context, "writesame",
+ parent_trace, completion),
+ m_write_data(std::move(data)), m_op_flags(op_flags) {
+ }
+
+ const char *get_op_type() const override {
+ return "writesame";
+ }
+
+protected:
+ void add_write_ops(neorados::WriteOp *wr) override;
+
+private:
+ ceph::bufferlist m_write_data;
+ int m_op_flags;
+};
+
+template <typename ImageCtxT = ImageCtx>
+class ObjectCompareAndWriteRequest : public AbstractObjectWriteRequest<ImageCtxT> {
+public:
+ ObjectCompareAndWriteRequest(
+ ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
+ ceph::bufferlist&& cmp_bl, ceph::bufferlist&& write_bl,
+ IOContext io_context, uint64_t *mismatch_offset, int op_flags,
+ const ZTracer::Trace &parent_trace, Context *completion)
+ : AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off,
+ cmp_bl.length(), io_context,
+ "compare_and_write", parent_trace,
+ completion),
+ m_cmp_bl(std::move(cmp_bl)), m_write_bl(std::move(write_bl)),
+ m_mismatch_offset(mismatch_offset), m_op_flags(op_flags) {
+ }
+
+ const char *get_op_type() const override {
+ return "compare_and_write";
+ }
+
+ void add_copyup_ops(neorados::WriteOp *wr) override {
+ // no-op on copyup
+ }
+
+protected:
+ virtual bool is_post_copyup_write_required() const {
+ return true;
+ }
+
+ void add_write_ops(neorados::WriteOp *wr) override;
+
+ int filter_write_result(int r) const override;
+
+ Extents get_copyup_overwrite_extents() const override {
+ return {};
+ }
+
+private:
+ ceph::bufferlist m_cmp_bl;
+ ceph::bufferlist m_write_bl;
+ uint64_t *m_mismatch_offset;
+ int m_op_flags;
+};
+
+template <typename ImageCtxT = ImageCtx>
+class ObjectListSnapsRequest : public ObjectRequest<ImageCtxT> {
+public:
+ static ObjectListSnapsRequest* create(
+ ImageCtxT *ictx, uint64_t objectno, Extents&& object_extents,
+ SnapIds&& snap_ids, int list_snaps_flags,
+ const ZTracer::Trace &parent_trace, SnapshotDelta* snapshot_delta,
+ Context *completion) {
+ return new ObjectListSnapsRequest(ictx, objectno,
+ std::move(object_extents),
+ std::move(snap_ids), list_snaps_flags,
+ parent_trace, snapshot_delta, completion);
+ }
+
+ ObjectListSnapsRequest(
+ ImageCtxT *ictx, uint64_t objectno, Extents&& object_extents,
+ SnapIds&& snap_ids, int list_snaps_flags,
+ const ZTracer::Trace &parent_trace, SnapshotDelta* snapshot_delta,
+ Context *completion);
+
+ void send() override;
+
+ const char *get_op_type() const override {
+ return "snap_list";
+ }
+
+private:
+ Extents m_object_extents;
+ SnapIds m_snap_ids;
+ int m_list_snaps_flags;
+ SnapshotDelta* m_snapshot_delta;
+
+ neorados::SnapSet m_snap_set;
+ boost::system::error_code m_ec;
+
+ SnapshotDelta m_parent_snapshot_delta;
+
+ void list_snaps();
+ void handle_list_snaps(int r);
+
+ void list_from_parent();
+ void handle_list_from_parent(int r);
+
+ void zero_extent(uint64_t snap_id, bool dne);
+};
+
+} // namespace io
+} // namespace librbd
+
+extern template class librbd::io::ObjectRequest<librbd::ImageCtx>;
+extern template class librbd::io::ObjectReadRequest<librbd::ImageCtx>;
+extern template class librbd::io::AbstractObjectWriteRequest<librbd::ImageCtx>;
+extern template class librbd::io::ObjectWriteRequest<librbd::ImageCtx>;
+extern template class librbd::io::ObjectDiscardRequest<librbd::ImageCtx>;
+extern template class librbd::io::ObjectWriteSameRequest<librbd::ImageCtx>;
+extern template class librbd::io::ObjectCompareAndWriteRequest<librbd::ImageCtx>;
+extern template class librbd::io::ObjectListSnapsRequest<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_IO_OBJECT_REQUEST_H