]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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" | |
11fdf7f2 | 9 | #include "common/ceph_time.h" |
7c673cae FG |
10 | #include "include/Context.h" |
11 | #include "include/utime.h" | |
12 | #include "include/rbd/librbd.hpp" | |
13 | ||
7c673cae | 14 | #include "librbd/ImageCtx.h" |
31f18b77 | 15 | #include "librbd/io/AsyncOperation.h" |
7c673cae FG |
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 | |
7c673cae FG |
53 | int ref; |
54 | bool released; | |
55 | ImageCtx *ictx; | |
11fdf7f2 | 56 | coarse_mono_time start_time; |
7c673cae FG |
57 | aio_type_t aio_type; |
58 | ||
59 | ReadResult read_result; | |
60 | ||
61 | AsyncOperation async_op; | |
62 | ||
7c673cae FG |
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> | |
11fdf7f2 | 91 | static AioCompletion *create(T *obj, ImageCtx *image_ctx, aio_type_t type) { |
7c673cae FG |
92 | AioCompletion *comp = create<T, MF>(obj); |
93 | comp->init_time(image_ctx, type); | |
11fdf7f2 TL |
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); | |
7c673cae FG |
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), | |
81eedcae | 108 | pending_count(0), ref(1), released(false), ictx(NULL), |
11fdf7f2 TL |
109 | aio_type(AIO_TYPE_NONE), m_xlist_item(this), |
110 | event_notify(false) { | |
7c673cae FG |
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(); | |
11fdf7f2 | 143 | ceph_assert(pending_count > 0); |
7c673cae FG |
144 | lock.Unlock(); |
145 | get(); | |
146 | } | |
147 | void complete_request(ssize_t r); | |
148 | ||
7c673cae FG |
149 | bool is_complete(); |
150 | ||
151 | ssize_t get_return_value(); | |
152 | ||
153 | void get() { | |
154 | lock.Lock(); | |
11fdf7f2 | 155 | ceph_assert(ref > 0); |
7c673cae FG |
156 | ref++; |
157 | lock.Unlock(); | |
158 | } | |
159 | void release() { | |
160 | lock.Lock(); | |
11fdf7f2 | 161 | ceph_assert(!released); |
7c673cae FG |
162 | released = true; |
163 | put_unlock(); | |
164 | } | |
165 | void put() { | |
166 | lock.Lock(); | |
167 | put_unlock(); | |
168 | } | |
169 | void put_unlock() { | |
11fdf7f2 | 170 | ceph_assert(ref > 0); |
7c673cae FG |
171 | int n = --ref; |
172 | lock.Unlock(); | |
173 | if (!n) { | |
81eedcae TL |
174 | if (ictx != nullptr && event_notify) { |
175 | ictx->completed_reqs_lock.Lock(); | |
176 | m_xlist_item.remove_myself(); | |
177 | ictx->completed_reqs_lock.Unlock(); | |
7c673cae FG |
178 | } |
179 | delete this; | |
180 | } | |
181 | } | |
182 | ||
7c673cae FG |
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 |