diff options
Diffstat (limited to 'src/librbd/io/ObjectRequest.h')
-rw-r--r-- | src/librbd/io/ObjectRequest.h | 502 |
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 |