summaryrefslogtreecommitdiffstats
path: root/src/librbd/deep_copy/ObjectCopyRequest.h
blob: a0445f3bb01bdb9340d788ce3fdff081b98edc75 (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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#ifndef CEPH_LIBRBD_DEEP_COPY_OBJECT_COPY_REQUEST_H
#define CEPH_LIBRBD_DEEP_COPY_OBJECT_COPY_REQUEST_H

#include "include/int_types.h"
#include "include/interval_set.h"
#include "include/rados/librados.hpp"
#include "common/snap_types.h"
#include "librbd/ImageCtx.h"
#include "librbd/deep_copy/Types.h"
#include "librbd/io/Types.h"
#include <list>
#include <map>
#include <string>

class Context;
class RWLock;

namespace librbd {

namespace io { class AsyncOperation; }

namespace deep_copy {

template <typename ImageCtxT = librbd::ImageCtx>
class ObjectCopyRequest {
public:
  static ObjectCopyRequest* create(ImageCtxT *src_image_ctx,
                                   ImageCtxT *dst_image_ctx,
                                   librados::snap_t src_snap_id_start,
                                   librados::snap_t dst_snap_id_start,
                                   const SnapMap &snap_map,
                                   uint64_t object_number, bool flatten,
                                   Context *on_finish) {
    return new ObjectCopyRequest(src_image_ctx, dst_image_ctx,
                                 src_snap_id_start, dst_snap_id_start, snap_map,
                                 object_number, flatten, on_finish);
  }

  ObjectCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx,
                    librados::snap_t src_snap_id_start,
                    librados::snap_t dst_snap_id_start, const SnapMap &snap_map,
                    uint64_t object_number, bool flatten, Context *on_finish);

  void send();

  // testing support
  inline librados::IoCtx &get_src_io_ctx() {
    return m_src_io_ctx;
  }
  inline librados::IoCtx &get_dst_io_ctx() {
    return m_dst_io_ctx;
  }

private:
  /**
   * @verbatim
   *
   * <start>
   *    |     /----------------------\
   *    |     |                      |
   *    v     v                      | (repeat for each src object)
   * LIST_SNAPS < * * *              |
   *    |             * (-ENOENT and snap set stale)
   *    |   * * * * * *              |
   *    |   * /-----------\          |
   *    |   * |           | (repeat for each snapshot)
   *    v   * v           |          |
   * READ_OBJECT ---------/          |
   *    |     |                      |
   *    |     \----------------------/
   *    v
   * READ_FROM_PARENT (skip if not needed)
   *    |
   *    |     /-----------\
   *    |     |           | (repeat for each snapshot)
   *    v     v           |
   * WRITE_OBJECT --------/
   *    |
   *    |     /-----------\
   *    |     |           | (repeat for each snapshot)
   *    v     v           |
   * UPDATE_OBJECT_MAP ---/ (skip if object
   *    |                    map disabled)
   *    v
   * <finish>
   *
   * @endverbatim
   */

  struct SrcObjectExtent {
    uint64_t object_no = 0;
    uint64_t offset = 0;
    uint64_t length = 0;
    bool noent = false;

    SrcObjectExtent() {
    }
    SrcObjectExtent(uint64_t object_no, uint64_t offset, uint64_t length)
      : object_no(object_no), offset(offset), length(length) {
    }
  };

  typedef std::map<uint64_t, SrcObjectExtent> SrcObjectExtents;

  enum CopyOpType {
    COPY_OP_TYPE_WRITE,
    COPY_OP_TYPE_ZERO,
    COPY_OP_TYPE_TRUNC,
    COPY_OP_TYPE_REMOVE,
    COPY_OP_TYPE_REMOVE_TRUNC,
  };

  typedef std::map<uint64_t, uint64_t> ExtentMap;

  struct CopyOp {
    CopyOp(CopyOpType type, uint64_t src_offset, uint64_t dst_offset,
           uint64_t length)
      : type(type), src_offset(src_offset), dst_offset(dst_offset),
        length(length) {
    }

    CopyOpType type;
    uint64_t src_offset;
    uint64_t dst_offset;
    uint64_t length;

    ExtentMap src_extent_map;
    ExtentMap dst_extent_map;
    bufferlist out_bl;
  };

  typedef std::list<CopyOp> CopyOps;
  typedef std::pair<librados::snap_t, librados::snap_t> WriteReadSnapIds;
  typedef std::map<librados::snap_t, uint8_t> SnapObjectStates;
  typedef std::map<librados::snap_t, std::map<uint64_t, uint64_t>> SnapObjectSizes;

  ImageCtxT *m_src_image_ctx;
  ImageCtxT *m_dst_image_ctx;
  CephContext *m_cct;
  librados::snap_t m_src_snap_id_start;
  librados::snap_t m_dst_snap_id_start;
  SnapMap m_snap_map;
  uint64_t m_dst_object_number;
  bool m_flatten;
  Context *m_on_finish;

  decltype(m_src_image_ctx->data_ctx) m_src_io_ctx;
  decltype(m_dst_image_ctx->data_ctx) m_dst_io_ctx;
  std::string m_dst_oid;

  std::set<uint64_t> m_src_objects;
  uint64_t m_src_ono;
  std::string m_src_oid;
  SrcObjectExtents m_src_object_extents;
  librados::snap_set_t m_snap_set;
  int m_snap_ret = 0;
  bool m_retry_missing_read = false;
  librados::snap_set_t m_retry_snap_set;
  bool m_read_whole_object = false;

  std::map<WriteReadSnapIds, CopyOps> m_read_ops;
  std::list<WriteReadSnapIds> m_read_snaps;
  std::map<librados::snap_t, CopyOps> m_write_ops;
  std::map<librados::snap_t, interval_set<uint64_t>> m_zero_interval;
  std::map<librados::snap_t, interval_set<uint64_t>> m_dst_zero_interval;
  std::map<librados::snap_t, uint8_t> m_dst_object_state;
  std::map<librados::snap_t, bool> m_dst_object_may_exist;
  bufferlist m_read_from_parent_data;

  io::AsyncOperation* m_src_async_op = nullptr;

  void send_list_snaps();
  void handle_list_snaps(int r);

  void send_read_object();
  void handle_read_object(int r);

  void send_read_from_parent();
  void handle_read_from_parent(int r);

  void send_write_object();
  void handle_write_object(int r);

  void send_update_object_map();
  void handle_update_object_map(int r);

  Context *start_lock_op(RWLock &owner_lock, int* r);

  uint64_t src_to_dst_object_offset(uint64_t objectno, uint64_t offset);

  void compute_src_object_extents();
  void compute_read_ops();
  void compute_read_from_parent_ops(io::Extents *image_extents);
  void merge_write_ops();
  void compute_zero_ops();

  void compute_dst_object_may_exist();

  void finish(int r);
};

} // namespace deep_copy
} // namespace librbd

extern template class librbd::deep_copy::ObjectCopyRequest<librbd::ImageCtx>;

#endif // CEPH_LIBRBD_DEEP_COPY_OBJECT_COPY_REQUEST_H