summaryrefslogtreecommitdiffstats
path: root/src/librbd/io/CopyupRequest.h
blob: a94139421c76c7f214f3cadde9559eedd7aa1e3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#ifndef CEPH_LIBRBD_IO_COPYUP_REQUEST_H
#define CEPH_LIBRBD_IO_COPYUP_REQUEST_H

#include "include/int_types.h"
#include "include/buffer.h"
#include "include/interval_set.h"
#include "common/ceph_mutex.h"
#include "common/zipkin_trace.h"
#include "librbd/io/AsyncOperation.h"
#include "librbd/io/Types.h"

#include <map>
#include <string>
#include <vector>

namespace ZTracer { struct Trace; }

namespace librbd {

struct ImageCtx;

namespace io {

template <typename I> class AbstractObjectWriteRequest;

template <typename ImageCtxT = librbd::ImageCtx>
class CopyupRequest {
public:
  static CopyupRequest* create(ImageCtxT *ictx, uint64_t objectno,
                               Extents &&image_extents, ImageArea area,
                               const ZTracer::Trace &parent_trace) {
    return new CopyupRequest(ictx, objectno, std::move(image_extents), area,
                             parent_trace);
  }

  CopyupRequest(ImageCtxT *ictx, uint64_t objectno,
                Extents &&image_extents, ImageArea area,
                const ZTracer::Trace &parent_trace);
  ~CopyupRequest();

  void append_request(AbstractObjectWriteRequest<ImageCtxT> *req,
                      const Extents& object_extents);

  void send();

private:
  /**
   * Copyup requests go through the following state machine to read from the
   * parent image, update the object map, and copyup the object:
   *
   *
   * @verbatim
   *
   *              <start>
   *                 |
   *      /---------/ \---------\
   *      |                     |
   *      v                     v
   *  READ_FROM_PARENT      DEEP_COPY
   *      |                     |
   *      \---------\ /---------/
   *                 |
   *                 v (skip if not needed)
   *         UPDATE_OBJECT_MAPS
   *                 |
   *                 v (skip if not needed)
   *              COPYUP
   *                 |
   *                 v
   *              <finish>
   *
   * @endverbatim
   *
   * The OBJECT_MAP state is skipped if the object map isn't enabled or if
   * an object map update isn't required. The COPYUP state is skipped if
   * no data was read from the parent *and* there are no additional ops.
   */

  typedef std::vector<AbstractObjectWriteRequest<ImageCtxT> *> WriteRequests;

  ImageCtxT *m_image_ctx;
  uint64_t m_object_no;
  Extents m_image_extents;
  ImageArea m_image_area;
  ZTracer::Trace m_trace;

  bool m_flatten = false;
  bool m_copyup_required = true;
  bool m_copyup_is_zero = true;
  bool m_deep_copied = false;

  Extents m_copyup_extent_map;
  ceph::bufferlist m_copyup_data;

  AsyncOperation m_async_op;

  std::vector<uint64_t> m_snap_ids;
  bool m_first_snap_is_clean = false;

  ceph::mutex m_lock = ceph::make_mutex("CopyupRequest", false);
  WriteRequests m_pending_requests;
  unsigned m_pending_copyups = 0;
  int m_copyup_ret_val = 0;

  WriteRequests m_restart_requests;
  bool m_append_request_permitted = true;

  interval_set<uint64_t> m_write_object_extents;

  void read_from_parent();
  void handle_read_from_parent(int r);

  void deep_copy();
  void handle_deep_copy(int r);

  void update_object_maps();
  void handle_update_object_maps(int r);

  void copyup();
  void handle_copyup(int r);

  void finish(int r);
  void complete_requests(bool override_restart_retval, int r);

  void disable_append_requests();
  void remove_from_list();

  bool is_copyup_required();
  bool is_update_object_map_required(int r);
  bool is_deep_copy() const;

  void compute_deep_copy_snap_ids();
  void convert_copyup_extent_map();
  int prepare_copyup_data();
};

} // namespace io
} // namespace librbd

extern template class librbd::io::CopyupRequest<librbd::ImageCtx>;

#endif // CEPH_LIBRBD_IO_COPYUP_REQUEST_H