1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #ifndef CEPH_LIBRBD_IO_OBJECT_REQUEST_H
5 #define CEPH_LIBRBD_IO_OBJECT_REQUEST_H
7 #include "include/int_types.h"
8 #include "include/buffer.h"
9 #include "include/rados/librados.hpp"
10 #include "common/snap_types.h"
11 #include "common/zipkin_trace.h"
12 #include "librbd/ObjectMap.h"
13 #include "librbd/io/Types.h"
26 template <typename
> class CopyupRequest
;
29 * This class represents an I/O operation to a single RBD data object.
30 * Its subclasses encapsulate logic for dealing with special cases
31 * for I/O due to layering.
33 template <typename ImageCtxT
= ImageCtx
>
36 static ObjectRequest
* create_write(
37 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
,
38 ceph::bufferlist
&& data
, const ::SnapContext
&snapc
, int op_flags
,
39 const ZTracer::Trace
&parent_trace
, Context
*completion
);
40 static ObjectRequest
* create_discard(
41 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
,
42 uint64_t object_len
, const ::SnapContext
&snapc
, int discard_flags
,
43 const ZTracer::Trace
&parent_trace
, Context
*completion
);
44 static ObjectRequest
* create_write_same(
45 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
,
46 uint64_t object_len
, ceph::bufferlist
&& data
, const ::SnapContext
&snapc
,
47 int op_flags
, const ZTracer::Trace
&parent_trace
, Context
*completion
);
48 static ObjectRequest
* create_compare_and_write(
49 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
,
50 ceph::bufferlist
&& cmp_data
, ceph::bufferlist
&& write_data
,
51 const ::SnapContext
&snapc
, uint64_t *mismatch_offset
, int op_flags
,
52 const ZTracer::Trace
&parent_trace
, Context
*completion
);
54 ObjectRequest(ImageCtxT
*ictx
, uint64_t objectno
, uint64_t off
, uint64_t len
,
55 librados::snap_t snap_id
, const char *trace_name
,
56 const ZTracer::Trace
&parent_trace
, Context
*completion
);
57 virtual ~ObjectRequest() {
58 m_trace
.event("finish");
61 static void add_write_hint(ImageCtxT
& image_ctx
,
62 librados::ObjectWriteOperation
*wr
);
64 virtual void send() = 0;
66 bool has_parent() const {
70 virtual const char *get_op_type() const = 0;
73 bool compute_parent_extents(Extents
*parent_extents
, bool read_request
);
76 uint64_t m_object_no
, m_object_off
, m_object_len
;
77 librados::snap_t m_snap_id
;
78 Context
*m_completion
;
79 ZTracer::Trace m_trace
;
81 void async_finish(int r
);
85 bool m_has_parent
= false;
88 template <typename ImageCtxT
= ImageCtx
>
89 class ObjectReadRequest
: public ObjectRequest
<ImageCtxT
> {
91 typedef std::map
<uint64_t, uint64_t> ExtentMap
;
93 static ObjectReadRequest
* create(
94 ImageCtxT
*ictx
, uint64_t objectno
, uint64_t offset
, uint64_t len
,
95 librados::snap_t snap_id
, int op_flags
,
96 const ZTracer::Trace
&parent_trace
, ceph::bufferlist
* read_data
,
97 ExtentMap
* extent_map
, Context
*completion
) {
98 return new ObjectReadRequest(ictx
, objectno
, offset
, len
,
99 snap_id
, op_flags
, parent_trace
, read_data
,
100 extent_map
, completion
);
104 ImageCtxT
*ictx
, uint64_t objectno
, uint64_t offset
, uint64_t len
,
105 librados::snap_t snap_id
, int op_flags
,
106 const ZTracer::Trace
&parent_trace
, ceph::bufferlist
* read_data
,
107 ExtentMap
* extent_map
, Context
*completion
);
109 void send() override
;
111 const char *get_op_type() const override
{
125 * v (skip if not needed)
128 * v (skip if not needed)
139 ceph::bufferlist
* m_read_data
;
140 ExtentMap
* m_extent_map
;
143 void handle_read_object(int r
);
146 void handle_read_parent(int r
);
151 template <typename ImageCtxT
= ImageCtx
>
152 class AbstractObjectWriteRequest
: public ObjectRequest
<ImageCtxT
> {
154 AbstractObjectWriteRequest(
155 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
, uint64_t len
,
156 const ::SnapContext
&snapc
, const char *trace_name
,
157 const ZTracer::Trace
&parent_trace
, Context
*completion
);
159 virtual bool is_empty_write_op() const {
163 virtual uint8_t get_pre_write_object_map_state() const {
164 return OBJECT_EXISTS
;
167 virtual void add_copyup_ops(librados::ObjectWriteOperation
*wr
) {
171 void handle_copyup(int r
);
173 void send() override
;
176 bool m_full_object
= false;
177 bool m_copyup_enabled
= true;
179 virtual bool is_no_op_for_nonexistent_object() const {
182 virtual bool is_object_map_update_enabled() const {
185 virtual bool is_post_copyup_write_required() const {
188 virtual bool is_non_existent_post_write_object_map_state() const {
192 virtual void add_write_hint(librados::ObjectWriteOperation
*wr
);
193 virtual void add_write_ops(librados::ObjectWriteOperation
*wr
) = 0;
195 virtual int filter_write_result(int r
) const {
205 * v (no-op write request)
206 * DETECT_NO_OP . . . . . . . . . . . . . . . . . . .
208 * v (skip if not required/disabled) .
209 * PRE_UPDATE_OBJECT_MAP .
212 * | . . . . . . . . . .
214 * | (post-copyup write) . .
215 * | . . . . . . . . . . . . . .
218 * WRITE . . . . . . . . > COPYUP (if required) .
220 * |/----------------------/ .
222 * v (skip if not required/disabled) .
223 * POST_UPDATE_OBJECT_MAP .
226 * <finish> < . . . . . . . . . . . . . . . . . . . .
232 std::vector
<librados::snap_t
> m_snaps
;
234 Extents m_parent_extents
;
235 bool m_object_may_exist
= false;
236 bool m_copyup_in_progress
= false;
237 bool m_guarding_migration_write
= false;
239 void compute_parent_info();
241 void pre_write_object_map_update();
242 void handle_pre_write_object_map_update(int r
);
245 void handle_write_object(int r
);
249 void post_write_object_map_update();
250 void handle_post_write_object_map_update(int r
);
254 template <typename ImageCtxT
= ImageCtx
>
255 class ObjectWriteRequest
: public AbstractObjectWriteRequest
<ImageCtxT
> {
258 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
,
259 ceph::bufferlist
&& data
, const ::SnapContext
&snapc
, int op_flags
,
260 const ZTracer::Trace
&parent_trace
, Context
*completion
)
261 : AbstractObjectWriteRequest
<ImageCtxT
>(ictx
, object_no
, object_off
,
262 data
.length(), snapc
, "write",
263 parent_trace
, completion
),
264 m_write_data(std::move(data
)), m_op_flags(op_flags
) {
267 bool is_empty_write_op() const override
{
268 return (m_write_data
.length() == 0);
271 const char *get_op_type() const override
{
276 void add_write_ops(librados::ObjectWriteOperation
*wr
) override
;
279 ceph::bufferlist m_write_data
;
283 template <typename ImageCtxT
= ImageCtx
>
284 class ObjectDiscardRequest
: public AbstractObjectWriteRequest
<ImageCtxT
> {
286 ObjectDiscardRequest(
287 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
,
288 uint64_t object_len
, const ::SnapContext
&snapc
, int discard_flags
,
289 const ZTracer::Trace
&parent_trace
, Context
*completion
)
290 : AbstractObjectWriteRequest
<ImageCtxT
>(ictx
, object_no
, object_off
,
291 object_len
, snapc
, "discard",
292 parent_trace
, completion
),
293 m_discard_flags(discard_flags
) {
294 if (this->m_full_object
) {
295 if ((m_discard_flags
& OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE
) != 0 &&
296 this->has_parent()) {
297 if (!this->m_copyup_enabled
) {
298 // need to hide the parent object instead of child object
299 m_discard_action
= DISCARD_ACTION_REMOVE_TRUNCATE
;
301 m_discard_action
= DISCARD_ACTION_TRUNCATE
;
303 this->m_object_len
= 0;
305 m_discard_action
= DISCARD_ACTION_REMOVE
;
307 } else if (object_off
+ object_len
== ictx
->layout
.object_size
) {
308 m_discard_action
= DISCARD_ACTION_TRUNCATE
;
310 m_discard_action
= DISCARD_ACTION_ZERO
;
314 const char* get_op_type() const override
{
315 switch (m_discard_action
) {
316 case DISCARD_ACTION_REMOVE
:
318 case DISCARD_ACTION_REMOVE_TRUNCATE
:
319 return "remove (create+truncate)";
320 case DISCARD_ACTION_TRUNCATE
:
322 case DISCARD_ACTION_ZERO
:
329 uint8_t get_pre_write_object_map_state() const override
{
330 if (m_discard_action
== DISCARD_ACTION_REMOVE
) {
331 return OBJECT_PENDING
;
333 return OBJECT_EXISTS
;
337 bool is_no_op_for_nonexistent_object() const override
{
338 return (!this->has_parent());
340 bool is_object_map_update_enabled() const override
{
342 (m_discard_flags
& OBJECT_DISCARD_FLAG_DISABLE_OBJECT_MAP_UPDATE
) == 0);
344 bool is_non_existent_post_write_object_map_state() const override
{
345 return (m_discard_action
== DISCARD_ACTION_REMOVE
);
348 void add_write_hint(librados::ObjectWriteOperation
*wr
) override
{
349 // no hint for discard
352 void add_write_ops(librados::ObjectWriteOperation
*wr
) override
{
353 switch (m_discard_action
) {
354 case DISCARD_ACTION_REMOVE
:
357 case DISCARD_ACTION_REMOVE_TRUNCATE
:
360 case DISCARD_ACTION_TRUNCATE
:
361 wr
->truncate(this->m_object_off
);
363 case DISCARD_ACTION_ZERO
:
364 wr
->zero(this->m_object_off
, this->m_object_len
);
374 DISCARD_ACTION_REMOVE
,
375 DISCARD_ACTION_REMOVE_TRUNCATE
,
376 DISCARD_ACTION_TRUNCATE
,
380 DiscardAction m_discard_action
;
385 template <typename ImageCtxT
= ImageCtx
>
386 class ObjectWriteSameRequest
: public AbstractObjectWriteRequest
<ImageCtxT
> {
388 ObjectWriteSameRequest(
389 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
,
390 uint64_t object_len
, ceph::bufferlist
&& data
, const ::SnapContext
&snapc
,
391 int op_flags
, const ZTracer::Trace
&parent_trace
, Context
*completion
)
392 : AbstractObjectWriteRequest
<ImageCtxT
>(ictx
, object_no
, object_off
,
393 object_len
, snapc
, "writesame",
394 parent_trace
, completion
),
395 m_write_data(std::move(data
)), m_op_flags(op_flags
) {
398 const char *get_op_type() const override
{
403 void add_write_ops(librados::ObjectWriteOperation
*wr
) override
;
406 ceph::bufferlist m_write_data
;
410 template <typename ImageCtxT
= ImageCtx
>
411 class ObjectCompareAndWriteRequest
: public AbstractObjectWriteRequest
<ImageCtxT
> {
413 ObjectCompareAndWriteRequest(
414 ImageCtxT
*ictx
, uint64_t object_no
, uint64_t object_off
,
415 ceph::bufferlist
&& cmp_bl
, ceph::bufferlist
&& write_bl
,
416 const ::SnapContext
&snapc
, uint64_t *mismatch_offset
, int op_flags
,
417 const ZTracer::Trace
&parent_trace
, Context
*completion
)
418 : AbstractObjectWriteRequest
<ImageCtxT
>(ictx
, object_no
, object_off
,
419 cmp_bl
.length(), snapc
,
420 "compare_and_write", parent_trace
,
422 m_cmp_bl(std::move(cmp_bl
)), m_write_bl(std::move(write_bl
)),
423 m_mismatch_offset(mismatch_offset
), m_op_flags(op_flags
) {
426 const char *get_op_type() const override
{
427 return "compare_and_write";
430 void add_copyup_ops(librados::ObjectWriteOperation
*wr
) override
{
435 virtual bool is_post_copyup_write_required() const {
439 void add_write_ops(librados::ObjectWriteOperation
*wr
) override
;
441 int filter_write_result(int r
) const override
;
444 ceph::bufferlist m_cmp_bl
;
445 ceph::bufferlist m_write_bl
;
446 uint64_t *m_mismatch_offset
;
451 } // namespace librbd
453 extern template class librbd::io::ObjectRequest
<librbd::ImageCtx
>;
454 extern template class librbd::io::ObjectReadRequest
<librbd::ImageCtx
>;
455 extern template class librbd::io::AbstractObjectWriteRequest
<librbd::ImageCtx
>;
456 extern template class librbd::io::ObjectWriteRequest
<librbd::ImageCtx
>;
457 extern template class librbd::io::ObjectDiscardRequest
<librbd::ImageCtx
>;
458 extern template class librbd::io::ObjectWriteSameRequest
<librbd::ImageCtx
>;
459 extern template class librbd::io::ObjectCompareAndWriteRequest
<librbd::ImageCtx
>;
461 #endif // CEPH_LIBRBD_IO_OBJECT_REQUEST_H