]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/io/AioCompletion.h
import ceph nautilus 14.2.2
[ceph.git] / ceph / src / librbd / io / AioCompletion.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_LIBRBD_IO_AIO_COMPLETION_H
5 #define CEPH_LIBRBD_IO_AIO_COMPLETION_H
6
7 #include "common/Cond.h"
8 #include "common/Mutex.h"
9 #include "common/ceph_time.h"
10 #include "include/Context.h"
11 #include "include/utime.h"
12 #include "include/rbd/librbd.hpp"
13
14 #include "librbd/ImageCtx.h"
15 #include "librbd/io/AsyncOperation.h"
16 #include "librbd/io/ReadResult.h"
17 #include "librbd/io/Types.h"
18
19 class CephContext;
20
21 namespace librbd {
22 namespace io {
23
24
25 /**
26 * AioCompletion is the overall completion for a single
27 * rbd I/O request. It may be composed of many AioObjectRequests,
28 * which each go to a single object.
29 *
30 * The retrying of individual requests is handled at a lower level,
31 * so all AioCompletion cares about is the count of outstanding
32 * requests. The number of expected individual requests should be
33 * set initially using set_request_count() prior to issuing the
34 * requests. This ensures that the completion will not be completed
35 * within the caller's thread of execution (instead via a librados
36 * context or via a thread pool context for cache read hits).
37 */
38 struct AioCompletion {
39 typedef enum {
40 AIO_STATE_PENDING = 0,
41 AIO_STATE_CALLBACK,
42 AIO_STATE_COMPLETE,
43 } aio_state_t;
44
45 mutable Mutex lock;
46 Cond cond;
47 aio_state_t state;
48 ssize_t rval;
49 callback_t complete_cb;
50 void *complete_arg;
51 rbd_completion_t rbd_comp;
52 uint32_t pending_count; ///< number of requests
53 int ref;
54 bool released;
55 ImageCtx *ictx;
56 coarse_mono_time start_time;
57 aio_type_t aio_type;
58
59 ReadResult read_result;
60
61 AsyncOperation async_op;
62
63 xlist<AioCompletion*>::item m_xlist_item;
64 bool event_notify;
65
66 template <typename T, void (T::*MF)(int)>
67 static void callback_adapter(completion_t cb, void *arg) {
68 AioCompletion *comp = reinterpret_cast<AioCompletion *>(cb);
69 T *t = reinterpret_cast<T *>(arg);
70 (t->*MF)(comp->get_return_value());
71 comp->release();
72 }
73
74 static AioCompletion *create(void *cb_arg, callback_t cb_complete,
75 rbd_completion_t rbd_comp) {
76 AioCompletion *comp = new AioCompletion();
77 comp->set_complete_cb(cb_arg, cb_complete);
78 comp->rbd_comp = (rbd_comp != nullptr ? rbd_comp : comp);
79 return comp;
80 }
81
82 template <typename T, void (T::*MF)(int) = &T::complete>
83 static AioCompletion *create(T *obj) {
84 AioCompletion *comp = new AioCompletion();
85 comp->set_complete_cb(obj, &callback_adapter<T, MF>);
86 comp->rbd_comp = comp;
87 return comp;
88 }
89
90 template <typename T, void (T::*MF)(int) = &T::complete>
91 static AioCompletion *create(T *obj, ImageCtx *image_ctx, aio_type_t type) {
92 AioCompletion *comp = create<T, MF>(obj);
93 comp->init_time(image_ctx, type);
94 return comp;
95 }
96
97 template <typename T, void (T::*MF)(int) = &T::complete>
98 static AioCompletion *create_and_start(T *obj, ImageCtx *image_ctx,
99 aio_type_t type) {
100 AioCompletion *comp = create<T, MF>(obj, image_ctx, type);
101 comp->start_op();
102 return comp;
103 }
104
105 AioCompletion() : lock("AioCompletion::lock", true, false),
106 state(AIO_STATE_PENDING), rval(0), complete_cb(NULL),
107 complete_arg(NULL), rbd_comp(NULL),
108 pending_count(0), ref(1), released(false), ictx(NULL),
109 aio_type(AIO_TYPE_NONE), m_xlist_item(this),
110 event_notify(false) {
111 }
112
113 ~AioCompletion() {
114 }
115
116 int wait_for_complete();
117
118 void finalize(ssize_t rval);
119
120 inline bool is_initialized(aio_type_t type) const {
121 Mutex::Locker locker(lock);
122 return ((ictx != nullptr) && (aio_type == type));
123 }
124 inline bool is_started() const {
125 Mutex::Locker locker(lock);
126 return async_op.started();
127 }
128
129 void init_time(ImageCtx *i, aio_type_t t);
130 void start_op(bool ignore_type = false);
131 void fail(int r);
132
133 void complete();
134
135 void set_complete_cb(void *cb_arg, callback_t cb) {
136 complete_cb = cb;
137 complete_arg = cb_arg;
138 }
139
140 void set_request_count(uint32_t num);
141 void add_request() {
142 lock.Lock();
143 ceph_assert(pending_count > 0);
144 lock.Unlock();
145 get();
146 }
147 void complete_request(ssize_t r);
148
149 bool is_complete();
150
151 ssize_t get_return_value();
152
153 void get() {
154 lock.Lock();
155 ceph_assert(ref > 0);
156 ref++;
157 lock.Unlock();
158 }
159 void release() {
160 lock.Lock();
161 ceph_assert(!released);
162 released = true;
163 put_unlock();
164 }
165 void put() {
166 lock.Lock();
167 put_unlock();
168 }
169 void put_unlock() {
170 ceph_assert(ref > 0);
171 int n = --ref;
172 lock.Unlock();
173 if (!n) {
174 if (ictx != nullptr && event_notify) {
175 ictx->completed_reqs_lock.Lock();
176 m_xlist_item.remove_myself();
177 ictx->completed_reqs_lock.Unlock();
178 }
179 delete this;
180 }
181 }
182
183 void set_event_notify(bool s) {
184 Mutex::Locker l(lock);
185 event_notify = s;
186 }
187
188 void *get_arg() {
189 return complete_arg;
190 }
191 };
192
193 class C_AioRequest : public Context {
194 public:
195 C_AioRequest(AioCompletion *completion) : m_completion(completion) {
196 m_completion->add_request();
197 }
198 ~C_AioRequest() override {}
199 void finish(int r) override {
200 m_completion->complete_request(r);
201 }
202 protected:
203 AioCompletion *m_completion;
204 };
205
206 } // namespace io
207 } // namespace librbd
208
209 #endif // CEPH_LIBRBD_IO_AIO_COMPLETION_H