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"
25 class ObjectRemoveRequest
;
26 class ObjectTruncateRequest
;
27 class ObjectWriteRequest
;
28 class ObjectZeroRequest
;
30 struct ObjectRequestHandle
{
31 virtual ~ObjectRequestHandle() {
34 virtual void complete(int r
) = 0;
35 virtual void send() = 0;
39 * This class represents an I/O operation to a single RBD data object.
40 * Its subclasses encapsulate logic for dealing with special cases
41 * for I/O due to layering.
43 template <typename ImageCtxT
= ImageCtx
>
44 class ObjectRequest
: public ObjectRequestHandle
{
46 typedef std::vector
<std::pair
<uint64_t, uint64_t> > Extents
;
48 static ObjectRequest
* create_remove(ImageCtxT
*ictx
,
49 const std::string
&oid
,
51 const ::SnapContext
&snapc
,
52 const ZTracer::Trace
&parent_trace
,
54 static ObjectRequest
* create_truncate(ImageCtxT
*ictx
,
55 const std::string
&oid
,
58 const ::SnapContext
&snapc
,
59 const ZTracer::Trace
&parent_trace
,
61 static ObjectRequest
* create_write(ImageCtxT
*ictx
, const std::string
&oid
,
64 const ceph::bufferlist
&data
,
65 const ::SnapContext
&snapc
, int op_flags
,
66 const ZTracer::Trace
&parent_trace
,
68 static ObjectRequest
* create_zero(ImageCtxT
*ictx
, const std::string
&oid
,
69 uint64_t object_no
, uint64_t object_off
,
71 const ::SnapContext
&snapc
,
72 const ZTracer::Trace
&parent_trace
,
74 static ObjectRequest
* create_writesame(ImageCtxT
*ictx
,
75 const std::string
&oid
,
79 const ceph::bufferlist
&data
,
80 const ::SnapContext
&snapc
,
82 const ZTracer::Trace
&parent_trace
,
84 static ObjectRequest
* create_compare_and_write(ImageCtxT
*ictx
,
85 const std::string
&oid
,
88 const ceph::bufferlist
&cmp_data
,
89 const ceph::bufferlist
&write_data
,
90 const ::SnapContext
&snapc
,
91 uint64_t *mismatch_offset
, int op_flags
,
92 const ZTracer::Trace
&parent_trace
,
95 ObjectRequest(ImageCtx
*ictx
, const std::string
&oid
,
96 uint64_t objectno
, uint64_t off
, uint64_t len
,
97 librados::snap_t snap_id
, bool hide_enoent
,
98 const char *trace_name
, const ZTracer::Trace
&parent_trace
,
100 ~ObjectRequest() override
{
101 m_trace
.event("finish");
104 virtual void add_copyup_ops(librados::ObjectWriteOperation
*wr
,
108 virtual void complete(int r
);
110 virtual bool should_complete(int r
) = 0;
111 void send() override
= 0;
113 bool has_parent() const {
117 virtual bool is_op_payload_empty() const {
121 virtual const char *get_op_type() const = 0;
122 virtual bool pre_object_map_update(uint8_t *new_state
) = 0;
125 bool compute_parent_extents();
129 uint64_t m_object_no
, m_object_off
, m_object_len
;
130 librados::snap_t m_snap_id
;
131 Context
*m_completion
;
132 Extents m_parent_extents
;
134 ZTracer::Trace m_trace
;
137 bool m_has_parent
= false;
140 template <typename ImageCtxT
= ImageCtx
>
141 class ObjectReadRequest
: public ObjectRequest
<ImageCtxT
> {
143 typedef std::vector
<std::pair
<uint64_t, uint64_t> > Extents
;
144 typedef std::map
<uint64_t, uint64_t> ExtentMap
;
146 static ObjectReadRequest
* create(ImageCtxT
*ictx
, const std::string
&oid
,
147 uint64_t objectno
, uint64_t offset
,
148 uint64_t len
, Extents
&buffer_extents
,
149 librados::snap_t snap_id
, bool sparse
,
151 const ZTracer::Trace
&parent_trace
,
152 Context
*completion
) {
153 return new ObjectReadRequest(ictx
, oid
, objectno
, offset
, len
,
154 buffer_extents
, snap_id
, sparse
, op_flags
,
155 parent_trace
, completion
);
158 ObjectReadRequest(ImageCtxT
*ictx
, const std::string
&oid
,
159 uint64_t objectno
, uint64_t offset
, uint64_t len
,
160 Extents
& buffer_extents
, librados::snap_t snap_id
,
161 bool sparse
, int op_flags
,
162 const ZTracer::Trace
&parent_trace
, Context
*completion
);
164 bool should_complete(int r
) override
;
165 void send() override
;
168 inline uint64_t get_offset() const {
169 return this->m_object_off
;
171 inline uint64_t get_length() const {
172 return this->m_object_len
;
174 ceph::bufferlist
&data() {
177 const Extents
&get_buffer_extents() const {
178 return m_buffer_extents
;
180 ExtentMap
&get_extent_map() {
184 const char *get_op_type() const override
{
188 bool pre_object_map_update(uint8_t *new_state
) override
{
193 Extents m_buffer_extents
;
197 ceph::bufferlist m_read_data
;
201 * Reads go through the following state machine to deal with
205 * LIBRBD_AIO_READ_GUARD ---------------> LIBRBD_AIO_READ_COPYUP
208 * done <------------------------------------/
211 * LIBRBD_AIO_READ_FLAT
213 * Reads start in LIBRBD_AIO_READ_GUARD or _FLAT, depending on
214 * whether there is a parent or not.
217 LIBRBD_AIO_READ_GUARD
,
218 LIBRBD_AIO_READ_COPYUP
,
222 read_state_d m_state
;
226 void read_from_parent(Extents
&& image_extents
);
229 class AbstractObjectWriteRequest
: public ObjectRequest
<> {
231 AbstractObjectWriteRequest(ImageCtx
*ictx
, const std::string
&oid
,
232 uint64_t object_no
, uint64_t object_off
,
233 uint64_t len
, const ::SnapContext
&snapc
,
234 bool hide_enoent
, const char *trace_name
,
235 const ZTracer::Trace
&parent_trace
,
236 Context
*completion
);
238 void add_copyup_ops(librados::ObjectWriteOperation
*wr
,
239 bool set_hints
) override
241 add_write_ops(wr
, set_hints
);
244 bool should_complete(int r
) override
;
245 void send() override
;
248 * Writes go through the following state machine to deal with
249 * layering and the object map:
255 * | ---------------------------------> LIBRBD_AIO_WRITE_PRE
259 * | . . . . > LIBRBD_AIO_WRITE_FLAT. . .
263 * v need copyup (copyup performs pre) | .
264 * LIBRBD_AIO_WRITE_GUARD -----------> LIBRBD_AIO_WRITE_COPYUP | .
269 * . \-------------------\ | /-------------------/ .
272 * . LIBRBD_AIO_WRITE_POST . .
274 * . | . . . . . . . . .
277 * . . . . . . . . . . . . . . > <finish> < . . . . . . . . . . . . . .
279 * The _PRE/_POST states are skipped if the object map is disabled.
280 * The write starts in _WRITE_GUARD or _FLAT depending on whether or not
281 * there is a parent overlap.
285 LIBRBD_AIO_WRITE_GUARD
,
286 LIBRBD_AIO_WRITE_COPYUP
,
287 LIBRBD_AIO_WRITE_FLAT
,
288 LIBRBD_AIO_WRITE_PRE
,
289 LIBRBD_AIO_WRITE_POST
,
290 LIBRBD_AIO_WRITE_ERROR
293 write_state_d m_state
;
294 librados::ObjectWriteOperation m_write
;
296 std::vector
<librados::snap_t
> m_snaps
;
300 virtual void add_write_ops(librados::ObjectWriteOperation
*wr
,
302 virtual void guard_write();
303 virtual bool post_object_map_update() {
306 virtual void send_write();
307 virtual void send_write_op();
308 virtual void handle_write_guard();
310 void send_pre_object_map_update();
313 bool send_post_object_map_update();
317 class ObjectWriteRequest
: public AbstractObjectWriteRequest
{
319 ObjectWriteRequest(ImageCtx
*ictx
, const std::string
&oid
, uint64_t object_no
,
320 uint64_t object_off
, const ceph::bufferlist
&data
,
321 const ::SnapContext
&snapc
, int op_flags
,
322 const ZTracer::Trace
&parent_trace
, Context
*completion
)
323 : AbstractObjectWriteRequest(ictx
, oid
, object_no
, object_off
,
324 data
.length(), snapc
, false, "write",
325 parent_trace
, completion
),
326 m_write_data(data
), m_op_flags(op_flags
) {
329 bool is_op_payload_empty() const override
{
330 return (m_write_data
.length() == 0);
333 const char *get_op_type() const override
{
337 bool pre_object_map_update(uint8_t *new_state
) override
{
338 *new_state
= OBJECT_EXISTS
;
343 void add_write_ops(librados::ObjectWriteOperation
*wr
,
344 bool set_hints
) override
;
346 void send_write() override
;
349 ceph::bufferlist m_write_data
;
353 class ObjectRemoveRequest
: public AbstractObjectWriteRequest
{
355 ObjectRemoveRequest(ImageCtx
*ictx
, const std::string
&oid
,
356 uint64_t object_no
, const ::SnapContext
&snapc
,
357 const ZTracer::Trace
&parent_trace
, Context
*completion
)
358 : AbstractObjectWriteRequest(ictx
, oid
, object_no
, 0, 0, snapc
, true,
359 "remote", parent_trace
, completion
),
360 m_object_state(OBJECT_NONEXISTENT
) {
363 const char* get_op_type() const override
{
365 return "remove (trunc)";
370 bool pre_object_map_update(uint8_t *new_state
) override
{
372 m_object_state
= OBJECT_EXISTS
;
374 m_object_state
= OBJECT_PENDING
;
376 *new_state
= m_object_state
;
380 bool post_object_map_update() override
{
381 if (m_object_state
== OBJECT_EXISTS
) {
387 void guard_write() override
;
388 void send_write() override
;
391 void add_write_ops(librados::ObjectWriteOperation
*wr
,
392 bool set_hints
) override
{
401 uint8_t m_object_state
;
404 class ObjectTrimRequest
: public AbstractObjectWriteRequest
{
406 // we'd need to only conditionally specify if a post object map
407 // update is needed. pre update is decided as usual (by checking
408 // the state of the object in the map).
409 ObjectTrimRequest(ImageCtx
*ictx
, const std::string
&oid
, uint64_t object_no
,
410 const ::SnapContext
&snapc
, bool post_object_map_update
,
412 : AbstractObjectWriteRequest(ictx
, oid
, object_no
, 0, 0, snapc
, true,
413 "trim", {}, completion
),
414 m_post_object_map_update(post_object_map_update
) {
417 const char* get_op_type() const override
{
418 return "remove (trim)";
421 bool pre_object_map_update(uint8_t *new_state
) override
{
422 *new_state
= OBJECT_PENDING
;
426 bool post_object_map_update() override
{
427 return m_post_object_map_update
;
431 void add_write_ops(librados::ObjectWriteOperation
*wr
,
432 bool set_hints
) override
{
437 bool m_post_object_map_update
;
440 class ObjectTruncateRequest
: public AbstractObjectWriteRequest
{
442 ObjectTruncateRequest(ImageCtx
*ictx
, const std::string
&oid
,
443 uint64_t object_no
, uint64_t object_off
,
444 const ::SnapContext
&snapc
,
445 const ZTracer::Trace
&parent_trace
, Context
*completion
)
446 : AbstractObjectWriteRequest(ictx
, oid
, object_no
, object_off
, 0, snapc
,
447 true, "truncate", parent_trace
, completion
) {
450 const char* get_op_type() const override
{
454 bool pre_object_map_update(uint8_t *new_state
) override
{
455 if (!m_object_exist
&& !has_parent())
456 *new_state
= OBJECT_NONEXISTENT
;
458 *new_state
= OBJECT_EXISTS
;
462 void send_write() override
;
465 void add_write_ops(librados::ObjectWriteOperation
*wr
,
466 bool set_hints
) override
{
467 wr
->truncate(m_object_off
);
471 class ObjectZeroRequest
: public AbstractObjectWriteRequest
{
473 ObjectZeroRequest(ImageCtx
*ictx
, const std::string
&oid
, uint64_t object_no
,
474 uint64_t object_off
, uint64_t object_len
,
475 const ::SnapContext
&snapc
,
476 const ZTracer::Trace
&parent_trace
, Context
*completion
)
477 : AbstractObjectWriteRequest(ictx
, oid
, object_no
, object_off
, object_len
,
478 snapc
, true, "zero", parent_trace
,
482 const char* get_op_type() const override
{
486 bool pre_object_map_update(uint8_t *new_state
) override
{
487 *new_state
= OBJECT_EXISTS
;
491 void send_write() override
;
494 void add_write_ops(librados::ObjectWriteOperation
*wr
,
495 bool set_hints
) override
{
496 wr
->zero(m_object_off
, m_object_len
);
500 class ObjectWriteSameRequest
: public AbstractObjectWriteRequest
{
502 ObjectWriteSameRequest(ImageCtx
*ictx
, const std::string
&oid
,
503 uint64_t object_no
, uint64_t object_off
,
504 uint64_t object_len
, const ceph::bufferlist
&data
,
505 const ::SnapContext
&snapc
, int op_flags
,
506 const ZTracer::Trace
&parent_trace
,
508 : AbstractObjectWriteRequest(ictx
, oid
, object_no
, object_off
,
509 object_len
, snapc
, false, "writesame",
510 parent_trace
, completion
),
511 m_write_data(data
), m_op_flags(op_flags
) {
514 const char *get_op_type() const override
{
518 bool pre_object_map_update(uint8_t *new_state
) override
{
519 *new_state
= OBJECT_EXISTS
;
524 void add_write_ops(librados::ObjectWriteOperation
*wr
,
525 bool set_hints
) override
;
527 void send_write() override
;
530 ceph::bufferlist m_write_data
;
534 class ObjectCompareAndWriteRequest
: public AbstractObjectWriteRequest
{
536 typedef std::vector
<std::pair
<uint64_t, uint64_t> > Extents
;
538 ObjectCompareAndWriteRequest(ImageCtx
*ictx
, const std::string
&oid
,
539 uint64_t object_no
, uint64_t object_off
,
540 const ceph::bufferlist
&cmp_bl
,
541 const ceph::bufferlist
&write_bl
,
542 const ::SnapContext
&snapc
,
543 uint64_t *mismatch_offset
, int op_flags
,
544 const ZTracer::Trace
&parent_trace
,
546 : AbstractObjectWriteRequest(ictx
, oid
, object_no
, object_off
,
547 cmp_bl
.length(), snapc
, false, "compare_and_write",
548 parent_trace
, completion
),
549 m_cmp_bl(cmp_bl
), m_write_bl(write_bl
),
550 m_mismatch_offset(mismatch_offset
), m_op_flags(op_flags
) {
553 const char *get_op_type() const override
{
554 return "compare_and_write";
557 bool pre_object_map_update(uint8_t *new_state
) override
{
558 *new_state
= OBJECT_EXISTS
;
562 void complete(int r
) override
;
564 void add_write_ops(librados::ObjectWriteOperation
*wr
,
565 bool set_hints
) override
;
567 void send_write() override
;
570 ceph::bufferlist m_cmp_bl
;
571 ceph::bufferlist m_write_bl
;
572 uint64_t *m_mismatch_offset
;
577 } // namespace librbd
579 extern template class librbd::io::ObjectRequest
<librbd::ImageCtx
>;
580 extern template class librbd::io::ObjectReadRequest
<librbd::ImageCtx
>;
582 #endif // CEPH_LIBRBD_IO_OBJECT_REQUEST_H