]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/cache/pwl/Request.h
import ceph quincy 17.2.1
[ceph.git] / ceph / src / librbd / cache / pwl / Request.h
CommitLineData
9f95a23c
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
f67539c2
TL
4#ifndef CEPH_LIBRBD_CACHE_PWL_REQUEST_H
5#define CEPH_LIBRBD_CACHE_PWL_REQUEST_H
9f95a23c
TL
6
7#include "include/Context.h"
f67539c2
TL
8#include "librbd/cache/pwl/Types.h"
9#include "librbd/cache/pwl/LogOperation.h"
9f95a23c
TL
10
11namespace librbd {
12class BlockGuardCell;
13
14namespace cache {
f67539c2 15namespace pwl {
9f95a23c
TL
16
17class GuardedRequestFunctionContext;
18
19struct WriteRequestResources {
20 bool allocated = false;
21 std::vector<WriteBufferAllocation> buffers;
22};
23
24/**
25 * A request that can be deferred in a BlockGuard to sequence
26 * overlapping operations.
27 * This is the custodian of the BlockGuard cell for this IO, and the
28 * state information about the progress of this IO. This object lives
29 * until the IO is persisted in all (live) log replicas. User request
30 * may be completed from here before the IO persists.
31 */
32template <typename T>
33class C_BlockIORequest : public Context {
34public:
f67539c2 35 T &pwl;
9f95a23c
TL
36 io::Extents image_extents;
37 bufferlist bl;
38 int fadvise_flags;
39 Context *user_req; /* User write request */
40 ExtentsSummary<io::Extents> image_extents_summary;
41 bool detained = false; /* Detained in blockguard (overlapped with a prior IO) */
42 utime_t allocated_time; /* When allocation began */
9f95a23c 43
f67539c2 44 C_BlockIORequest(T &pwl, const utime_t arrived, io::Extents &&extents,
9f95a23c
TL
45 bufferlist&& bl, const int fadvise_flags, Context *user_req);
46 ~C_BlockIORequest() override;
47 C_BlockIORequest(const C_BlockIORequest&) = delete;
48 C_BlockIORequest &operator=(const C_BlockIORequest&) = delete;
49
50 void set_cell(BlockGuardCell *cell);
51 BlockGuardCell *get_cell(void);
52 void release_cell();
53
54 void complete_user_request(int r);
55 void finish(int r);
56 virtual void finish_req(int r) = 0;
57
58 virtual bool alloc_resources() = 0;
59
60 void deferred();
61
62 virtual void deferred_handler() = 0;
63
64 virtual void dispatch() = 0;
65
f67539c2
TL
66 virtual void copy_cache() {};
67
9f95a23c
TL
68 virtual const char *get_name() const {
69 return "C_BlockIORequest";
70 }
20effc67 71
9f95a23c
TL
72 uint64_t get_image_extents_size() {
73 return image_extents.size();
74 }
20effc67 75
9f95a23c
TL
76 std::vector<WriteBufferAllocation>& get_resources_buffers() {
77 return m_resources.buffers;
78 }
79
80 void set_allocated(bool allocated) {
81 if (allocated) {
82 m_resources.allocated = true;
83 } else {
84 m_resources.buffers.clear();
85 }
86 }
87
88 virtual void setup_buffer_resources(
f67539c2
TL
89 uint64_t *bytes_cached, uint64_t *bytes_dirtied, uint64_t *bytes_allocated,
90 uint64_t *number_lanes, uint64_t *number_log_entries,
a4b75251 91 uint64_t *number_unpublished_reserves) = 0;
9f95a23c
TL
92
93protected:
94 utime_t m_arrived_time;
95 utime_t m_dispatched_time; /* When dispatch began */
96 utime_t m_user_req_completed_time;
97 std::atomic<bool> m_deferred = {false}; /* Deferred because this or a prior IO had to wait for write resources */
98 WriteRequestResources m_resources;
99
100private:
101 std::atomic<bool> m_user_req_completed = {false};
102 std::atomic<bool> m_finish_called = {false};
103 std::atomic<bool> m_cell_released = {false};
104 BlockGuardCell* m_cell = nullptr;
105
106 template <typename U>
107 friend std::ostream &operator<<(std::ostream &os,
108 const C_BlockIORequest<U> &req);
109};
110
111/**
112 * This is the custodian of the BlockGuard cell for this write. Block
113 * guard is not released until the write persists everywhere (this is
114 * how we guarantee to each log replica that they will never see
115 * overlapping writes).
116 */
117template <typename T>
118class C_WriteRequest : public C_BlockIORequest<T> {
119public:
f67539c2
TL
120 using C_BlockIORequest<T>::pwl;
121 bool compare_succeeded = false;
122 uint64_t *mismatch_offset;
123 bufferlist cmp_bl;
124 bufferlist read_bl;
125 bool is_comp_and_write = false;
20effc67 126 std::unique_ptr<WriteLogOperationSet> op_set = nullptr;
9f95a23c 127
f67539c2 128 C_WriteRequest(T &pwl, const utime_t arrived, io::Extents &&image_extents,
9f95a23c
TL
129 bufferlist&& bl, const int fadvise_flags, ceph::mutex &lock,
130 PerfCounters *perfcounter, Context *user_req);
131
f67539c2
TL
132 C_WriteRequest(T &pwl, const utime_t arrived, io::Extents &&image_extents,
133 bufferlist&& cmp_bl, bufferlist&& bl, uint64_t *mismatch_offset,
134 int fadvise_flags, ceph::mutex &lock, PerfCounters *perfcounter,
135 Context *user_req);
136
9f95a23c
TL
137 ~C_WriteRequest() override;
138
139 void blockguard_acquired(GuardedRequestFunctionContext &guard_ctx);
140
141 /* Common finish to plain write and compare-and-write (if it writes) */
142 void finish_req(int r) override;
143
144 /* Compare and write will override this */
f67539c2
TL
145 virtual void update_req_stats(utime_t &now);
146
9f95a23c
TL
147 bool alloc_resources() override;
148
149 void deferred_handler() override { }
150
151 void dispatch() override;
152
f67539c2
TL
153 void copy_cache() override;
154
155 virtual std::shared_ptr<WriteLogOperation> create_operation(uint64_t offset,
156 uint64_t len);
157
158 virtual void setup_log_operations(DeferredContexts &on_exit);
9f95a23c
TL
159
160 bool append_write_request(std::shared_ptr<SyncPoint> sync_point);
161
162 virtual void schedule_append();
163
164 const char *get_name() const override {
165 return "C_WriteRequest";
166 }
167
168protected:
169 using C_BlockIORequest<T>::m_resources;
f67539c2 170 PerfCounters *m_perfcounter = nullptr;
9f95a23c
TL
171
172private:
173 bool m_do_early_flush = false;
174 std::atomic<int> m_appended = {0};
175 bool m_queued = false;
176 ceph::mutex &m_lock;
9f95a23c
TL
177 template <typename U>
178 friend std::ostream &operator<<(std::ostream &os,
179 const C_WriteRequest<U> &req);
180};
181
f67539c2
TL
182/**
183 * This is the custodian of the BlockGuard cell for this
184 * aio_flush. Block guard is released as soon as the new
185 * sync point (if required) is created. Subsequent IOs can
186 * proceed while this flush waits for prior IOs to complete
187 * and any required sync points to be persisted.
188 */
189template <typename T>
190class C_FlushRequest : public C_BlockIORequest<T> {
191public:
192 using C_BlockIORequest<T>::pwl;
193 bool internal = false;
194 std::shared_ptr<SyncPoint> to_append;
195
196 C_FlushRequest(T &pwl, const utime_t arrived,
197 io::Extents &&image_extents,
198 bufferlist&& bl, const int fadvise_flags,
199 ceph::mutex &lock, PerfCounters *perfcounter,
200 Context *user_req);
201
202 ~C_FlushRequest() override {}
203
204 bool alloc_resources() override;
205
206 void dispatch() override;
207
208 const char *get_name() const override {
209 return "C_FlushRequest";
210 }
211
212 void setup_buffer_resources(
213 uint64_t *bytes_cached, uint64_t *bytes_dirtied,
214 uint64_t *bytes_allocated, uint64_t *number_lanes,
215 uint64_t *number_log_entries,
216 uint64_t *number_unpublished_reserves) override;
217private:
218 std::shared_ptr<SyncPointLogOperation> op;
219 ceph::mutex &m_lock;
220 PerfCounters *m_perfcounter = nullptr;
221
222 void finish_req(int r) override;
223 void deferred_handler() override {
224 m_perfcounter->inc(l_librbd_pwl_aio_flush_def, 1);
225 }
226
227 template <typename U>
228 friend std::ostream &operator<<(std::ostream &os,
229 const C_FlushRequest<U> &req);
230};
231
232/**
233 * This is the custodian of the BlockGuard cell for this discard. As in the
234 * case of write, the block guard is not released until the discard persists
235 * everywhere.
236 */
237template <typename T>
238class C_DiscardRequest : public C_BlockIORequest<T> {
239public:
240 using C_BlockIORequest<T>::pwl;
241 std::shared_ptr<DiscardLogOperation> op;
242
243 C_DiscardRequest(T &pwl, const utime_t arrived, io::Extents &&image_extents,
244 uint32_t discard_granularity_bytes, ceph::mutex &lock,
245 PerfCounters *perfcounter, Context *user_req);
246
247 ~C_DiscardRequest() override;
248 void finish_req(int r) override {}
249
250 bool alloc_resources() override;
251
252 void deferred_handler() override { }
253
254 void setup_log_operations();
255
256 void dispatch() override;
257
258 void blockguard_acquired(GuardedRequestFunctionContext &guard_ctx);
259
260 const char *get_name() const override {
261 return "C_DiscardRequest";
262 }
263 void setup_buffer_resources(
264 uint64_t *bytes_cached, uint64_t *bytes_dirtied, uint64_t *bytes_allocated,
265 uint64_t *number_lanes, uint64_t *number_log_entries,
266 uint64_t *number_unpublished_reserves) override;
267private:
268 uint32_t m_discard_granularity_bytes;
269 ceph::mutex &m_lock;
270 PerfCounters *m_perfcounter = nullptr;
271 template <typename U>
272 friend std::ostream &operator<<(std::ostream &os,
273 const C_DiscardRequest<U> &req);
274};
275
276/**
277 * This is the custodian of the BlockGuard cell for this write same.
278 *
279 * A writesame allocates and persists a data buffer like a write, but the
280 * data buffer is usually much shorter than the write same.
281 */
282template <typename T>
283class C_WriteSameRequest : public C_WriteRequest<T> {
284public:
285 using C_BlockIORequest<T>::pwl;
286 C_WriteSameRequest(T &pwl, const utime_t arrived, io::Extents &&image_extents,
287 bufferlist&& bl, const int fadvise_flags, ceph::mutex &lock,
288 PerfCounters *perfcounter, Context *user_req);
289
290 ~C_WriteSameRequest() override;
291
292 void update_req_stats(utime_t &now) override;
293
294 std::shared_ptr<WriteLogOperation> create_operation(uint64_t offset, uint64_t len) override;
295
296 const char *get_name() const override {
297 return "C_WriteSameRequest";
298 }
299
300 template<typename U>
301 friend std::ostream &operator<<(std::ostream &os,
302 const C_WriteSameRequest<U> &req);
303};
304
9f95a23c
TL
305struct BlockGuardReqState {
306 bool barrier = false; /* This is a barrier request */
307 bool current_barrier = false; /* This is the currently active barrier */
308 bool detained = false;
309 bool queued = false; /* Queued for barrier */
310 friend std::ostream &operator<<(std::ostream &os,
f67539c2 311 const BlockGuardReqState &r) {
20effc67
TL
312 os << "barrier=" << r.barrier
313 << ", current_barrier=" << r.current_barrier
314 << ", detained=" << r.detained
315 << ", queued=" << r.queued;
f67539c2
TL
316 return os;
317 }
9f95a23c
TL
318};
319
320class GuardedRequestFunctionContext : public Context {
321public:
322 BlockGuardCell *cell = nullptr;
323 BlockGuardReqState state;
f67539c2
TL
324 GuardedRequestFunctionContext(boost::function<void(GuardedRequestFunctionContext&)> &&callback)
325 : m_callback(std::move(callback)){ }
326 ~GuardedRequestFunctionContext(void) override { };
9f95a23c
TL
327 GuardedRequestFunctionContext(const GuardedRequestFunctionContext&) = delete;
328 GuardedRequestFunctionContext &operator=(const GuardedRequestFunctionContext&) = delete;
329
330private:
331 boost::function<void(GuardedRequestFunctionContext&)> m_callback;
f67539c2
TL
332 void finish(int r) override {
333 ceph_assert(cell);
334 m_callback(*this);
335 }
9f95a23c
TL
336};
337
338class GuardedRequest {
339public:
340 const BlockExtent block_extent;
341 GuardedRequestFunctionContext *guard_ctx; /* Work to do when guard on range obtained */
342
343 GuardedRequest(const BlockExtent block_extent,
344 GuardedRequestFunctionContext *on_guard_acquire, bool barrier = false)
345 : block_extent(block_extent), guard_ctx(on_guard_acquire) {
346 guard_ctx->state.barrier = barrier;
347 }
348 friend std::ostream &operator<<(std::ostream &os,
f67539c2 349 const GuardedRequest &r) {
20effc67
TL
350 os << "guard_ctx->state=[" << r.guard_ctx->state
351 << "], block_extent.block_start=" << r.block_extent.block_start
352 << ", block_extent.block_end=" << r.block_extent.block_end;
f67539c2
TL
353 return os;
354 }
9f95a23c
TL
355};
356
f67539c2 357} // namespace pwl
9f95a23c
TL
358} // namespace cache
359} // namespace librbd
360
f67539c2 361#endif // CEPH_LIBRBD_CACHE_PWL_REQUEST_H