]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/cache/ObjectCacherObjectDispatch.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / librbd / cache / ObjectCacherObjectDispatch.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "librbd/cache/ObjectCacherObjectDispatch.h"
5 #include "common/errno.h"
6 #include "common/WorkQueue.h"
7 #include "librbd/ImageCtx.h"
8 #include "librbd/Journal.h"
9 #include "librbd/Utils.h"
10 #include "librbd/LibrbdWriteback.h"
11 #include "librbd/io/ObjectDispatchSpec.h"
12 #include "librbd/io/ObjectDispatcher.h"
13 #include "librbd/io/Utils.h"
14 #include "osd/osd_types.h"
15 #include "osdc/WritebackHandler.h"
16 #include <vector>
17
18 #define dout_subsys ceph_subsys_rbd
19 #undef dout_prefix
20 #define dout_prefix *_dout << "librbd::cache::ObjectCacherObjectDispatch: " \
21 << this << " " << __func__ << ": "
22
23 namespace librbd {
24 namespace cache {
25
26 namespace {
27
28 typedef std::vector<ObjectExtent> ObjectExtents;
29
30 } // anonymous namespace
31
32 template <typename I>
33 struct ObjectCacherObjectDispatch<I>::C_InvalidateCache : public Context {
34 ObjectCacherObjectDispatch* dispatcher;
35 bool purge_on_error;
36 Context *on_finish;
37
38 C_InvalidateCache(ObjectCacherObjectDispatch* dispatcher,
39 bool purge_on_error, Context *on_finish)
40 : dispatcher(dispatcher), purge_on_error(purge_on_error),
41 on_finish(on_finish) {
42 }
43
44 void finish(int r) override {
45 ceph_assert(dispatcher->m_cache_lock.is_locked());
46 auto cct = dispatcher->m_image_ctx->cct;
47
48 if (r == -EBLACKLISTED) {
49 lderr(cct) << "blacklisted during flush (purging)" << dendl;
50 dispatcher->m_object_cacher->purge_set(dispatcher->m_object_set);
51 } else if (r < 0 && purge_on_error) {
52 lderr(cct) << "failed to invalidate cache (purging): "
53 << cpp_strerror(r) << dendl;
54 dispatcher->m_object_cacher->purge_set(dispatcher->m_object_set);
55 } else if (r != 0) {
56 lderr(cct) << "failed to invalidate cache: " << cpp_strerror(r) << dendl;
57 }
58
59 auto unclean = dispatcher->m_object_cacher->release_set(
60 dispatcher->m_object_set);
61 if (unclean == 0) {
62 r = 0;
63 } else {
64 lderr(cct) << "could not release all objects from cache: "
65 << unclean << " bytes remain" << dendl;
66 if (r == 0) {
67 r = -EBUSY;
68 }
69 }
70
71 on_finish->complete(r);
72 }
73 };
74
75 template <typename I>
76 ObjectCacherObjectDispatch<I>::ObjectCacherObjectDispatch(
77 I* image_ctx)
78 : m_image_ctx(image_ctx),
79 m_cache_lock(util::unique_lock_name(
80 "librbd::cache::ObjectCacherObjectDispatch::cache_lock", this)) {
81 }
82
83 template <typename I>
84 ObjectCacherObjectDispatch<I>::~ObjectCacherObjectDispatch() {
85 delete m_object_cacher;
86 delete m_object_set;
87
88 delete m_writeback_handler;
89 }
90
91 template <typename I>
92 void ObjectCacherObjectDispatch<I>::init() {
93 auto cct = m_image_ctx->cct;
94 ldout(cct, 5) << dendl;
95
96 m_cache_lock.Lock();
97 ldout(cct, 5) << "enabling caching..." << dendl;
98 m_writeback_handler = new LibrbdWriteback(m_image_ctx, m_cache_lock);
99
100 uint64_t init_max_dirty = m_image_ctx->cache_max_dirty;
101 if (m_image_ctx->cache_writethrough_until_flush) {
102 init_max_dirty = 0;
103 }
104
105 auto cache_size =
106 m_image_ctx->config.template get_val<Option::size_t>("rbd_cache_size");
107 auto target_dirty =
108 m_image_ctx->config.template get_val<Option::size_t>("rbd_cache_target_dirty");
109 auto max_dirty_age =
110 m_image_ctx->config.template get_val<double>("rbd_cache_max_dirty_age");
111 auto block_writes_upfront =
112 m_image_ctx->config.template get_val<bool>("rbd_cache_block_writes_upfront");
113 auto max_dirty_object =
114 m_image_ctx->config.template get_val<uint64_t>("rbd_cache_max_dirty_object");
115
116 ldout(cct, 5) << "Initial cache settings:"
117 << " size=" << cache_size
118 << " num_objects=" << 10
119 << " max_dirty=" << init_max_dirty
120 << " target_dirty=" << target_dirty
121 << " max_dirty_age=" << max_dirty_age << dendl;
122
123 m_object_cacher = new ObjectCacher(cct, m_image_ctx->perfcounter->get_name(),
124 *m_writeback_handler, m_cache_lock,
125 nullptr, nullptr, cache_size,
126 10, /* reset this in init */
127 init_max_dirty, target_dirty,
128 max_dirty_age, block_writes_upfront);
129
130 // size object cache appropriately
131 if (max_dirty_object == 0) {
132 max_dirty_object = std::min<uint64_t>(
133 2000, std::max<uint64_t>(10, cache_size / 100 /
134 sizeof(ObjectCacher::Object)));
135 }
136 ldout(cct, 5) << " cache bytes " << cache_size
137 << " -> about " << max_dirty_object << " objects" << dendl;
138 m_object_cacher->set_max_objects(max_dirty_object);
139
140 m_object_set = new ObjectCacher::ObjectSet(nullptr,
141 m_image_ctx->data_ctx.get_id(), 0);
142 m_object_cacher->start();
143 m_cache_lock.Unlock();
144
145 // add ourself to the IO object dispatcher chain
146 m_image_ctx->io_object_dispatcher->register_object_dispatch(this);
147 }
148
149 template <typename I>
150 void ObjectCacherObjectDispatch<I>::shut_down(Context* on_finish) {
151 auto cct = m_image_ctx->cct;
152 ldout(cct, 5) << dendl;
153
154 // chain shut down in reverse order
155
156 // shut down the cache
157 on_finish = new FunctionContext([this, on_finish](int r) {
158 m_object_cacher->stop();
159 on_finish->complete(r);
160 });
161
162 // ensure we aren't holding the cache lock post-flush
163 on_finish = util::create_async_context_callback(*m_image_ctx, on_finish);
164
165 // invalidate any remaining cache entries
166 on_finish = new C_InvalidateCache(this, true, on_finish);
167
168 // flush all pending writeback state
169 m_cache_lock.Lock();
170 m_object_cacher->release_set(m_object_set);
171 m_object_cacher->flush_set(m_object_set, on_finish);
172 m_cache_lock.Unlock();
173 }
174
175 template <typename I>
176 bool ObjectCacherObjectDispatch<I>::read(
177 const std::string &oid, uint64_t object_no, uint64_t object_off,
178 uint64_t object_len, librados::snap_t snap_id, int op_flags,
179 const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
180 io::ExtentMap* extent_map, int* object_dispatch_flags,
181 io::DispatchResult* dispatch_result, Context** on_finish,
182 Context* on_dispatched) {
183 // IO chained in reverse order
184 auto cct = m_image_ctx->cct;
185 ldout(cct, 20) << "object_no=" << object_no << " " << object_off << "~"
186 << object_len << dendl;
187
188 // ensure we aren't holding the cache lock post-read
189 on_dispatched = util::create_async_context_callback(*m_image_ctx,
190 on_dispatched);
191
192 m_image_ctx->snap_lock.get_read();
193 auto rd = m_object_cacher->prepare_read(snap_id, read_data, op_flags);
194 m_image_ctx->snap_lock.put_read();
195
196 ObjectExtent extent(oid, object_no, object_off, object_len, 0);
197 extent.oloc.pool = m_image_ctx->data_ctx.get_id();
198 extent.buffer_extents.push_back({0, object_len});
199 rd->extents.push_back(extent);
200
201 ZTracer::Trace trace(parent_trace);
202 *dispatch_result = io::DISPATCH_RESULT_COMPLETE;
203
204 m_cache_lock.Lock();
205 int r = m_object_cacher->readx(rd, m_object_set, on_dispatched, &trace);
206 m_cache_lock.Unlock();
207 if (r != 0) {
208 on_dispatched->complete(r);
209 }
210 return true;
211 }
212
213 template <typename I>
214 bool ObjectCacherObjectDispatch<I>::discard(
215 const std::string &oid, uint64_t object_no, uint64_t object_off,
216 uint64_t object_len, const ::SnapContext &snapc, int discard_flags,
217 const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
218 uint64_t* journal_tid, io::DispatchResult* dispatch_result,
219 Context** on_finish, Context* on_dispatched) {
220 auto cct = m_image_ctx->cct;
221 ldout(cct, 20) << "object_no=" << object_no << " " << object_off << "~"
222 << object_len << dendl;
223
224 ObjectExtents object_extents;
225 object_extents.emplace_back(oid, object_no, object_off, object_len, 0);
226
227 // discard the cache state after changes are committed to disk (and to
228 // prevent races w/ readahead)
229 auto ctx = *on_finish;
230 *on_finish = new FunctionContext(
231 [this, object_extents, ctx](int r) {
232 m_cache_lock.Lock();
233 m_object_cacher->discard_set(m_object_set, object_extents);
234 m_cache_lock.Unlock();
235
236 ctx->complete(r);
237 });
238
239 // ensure we aren't holding the cache lock post-write
240 on_dispatched = util::create_async_context_callback(*m_image_ctx,
241 on_dispatched);
242
243 *dispatch_result = io::DISPATCH_RESULT_CONTINUE;
244
245 // ensure any in-flight writeback is complete before advancing
246 // the discard request
247 m_cache_lock.Lock();
248 m_object_cacher->discard_writeback(m_object_set, object_extents,
249 on_dispatched);
250 m_cache_lock.Unlock();
251 return true;
252 }
253
254 template <typename I>
255 bool ObjectCacherObjectDispatch<I>::write(
256 const std::string &oid, uint64_t object_no, uint64_t object_off,
257 ceph::bufferlist&& data, const ::SnapContext &snapc, int op_flags,
258 const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
259 uint64_t* journal_tid, io::DispatchResult* dispatch_result,
260 Context** on_finish, Context* on_dispatched) {
261 auto cct = m_image_ctx->cct;
262 ldout(cct, 20) << "object_no=" << object_no << " " << object_off << "~"
263 << data.length() << dendl;
264
265 // ensure we aren't holding the cache lock post-write
266 on_dispatched = util::create_async_context_callback(*m_image_ctx,
267 on_dispatched);
268
269 m_image_ctx->snap_lock.get_read();
270 ObjectCacher::OSDWrite *wr = m_object_cacher->prepare_write(
271 snapc, data, ceph::real_time::min(), op_flags, *journal_tid);
272 m_image_ctx->snap_lock.put_read();
273
274 ObjectExtent extent(oid, 0, object_off, data.length(), 0);
275 extent.oloc.pool = m_image_ctx->data_ctx.get_id();
276 extent.buffer_extents.push_back({0, data.length()});
277 wr->extents.push_back(extent);
278
279 ZTracer::Trace trace(parent_trace);
280 *dispatch_result = io::DISPATCH_RESULT_COMPLETE;
281
282 m_cache_lock.Lock();
283 m_object_cacher->writex(wr, m_object_set, on_dispatched, &trace);
284 m_cache_lock.Unlock();
285 return true;
286 }
287
288 template <typename I>
289 bool ObjectCacherObjectDispatch<I>::write_same(
290 const std::string &oid, uint64_t object_no, uint64_t object_off,
291 uint64_t object_len, io::Extents&& buffer_extents, ceph::bufferlist&& data,
292 const ::SnapContext &snapc, int op_flags,
293 const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
294 uint64_t* journal_tid, io::DispatchResult* dispatch_result,
295 Context** on_finish, Context* on_dispatched) {
296 auto cct = m_image_ctx->cct;
297 ldout(cct, 20) << "object_no=" << object_no << " " << object_off << "~"
298 << object_len << dendl;
299
300 // ObjectCacher doesn't support write-same so convert to regular write
301 ObjectExtent extent(oid, 0, object_off, object_len, 0);
302 extent.buffer_extents = std::move(buffer_extents);
303
304 bufferlist ws_data;
305 io::util::assemble_write_same_extent(extent, data, &ws_data, true);
306
307 return write(oid, object_no, object_off, std::move(ws_data), snapc,
308 op_flags, parent_trace, object_dispatch_flags, journal_tid,
309 dispatch_result, on_finish, on_dispatched);
310 }
311
312 template <typename I>
313 bool ObjectCacherObjectDispatch<I>::compare_and_write(
314 const std::string &oid, uint64_t object_no, uint64_t object_off,
315 ceph::bufferlist&& cmp_data, ceph::bufferlist&& write_data,
316 const ::SnapContext &snapc, int op_flags,
317 const ZTracer::Trace &parent_trace, uint64_t* mismatch_offset,
318 int* object_dispatch_flags, uint64_t* journal_tid,
319 io::DispatchResult* dispatch_result, Context** on_finish,
320 Context* on_dispatched) {
321 auto cct = m_image_ctx->cct;
322 ldout(cct, 20) << "object_no=" << object_no << " " << object_off << "~"
323 << cmp_data.length() << dendl;
324
325 // pass-through the compare-and-write request since it's not a supported
326 // operation of the ObjectCacher
327
328 // ensure we aren't holding the cache lock post-flush
329 on_dispatched = util::create_async_context_callback(*m_image_ctx,
330 on_dispatched);
331
332 // flush any pending writes from the cache
333 ZTracer::Trace trace(parent_trace);
334 *dispatch_result = io::DISPATCH_RESULT_CONTINUE;
335
336 ObjectExtents object_extents;
337 object_extents.emplace_back(oid, object_no, object_off, cmp_data.length(),
338 0);
339
340 Mutex::Locker cache_locker(m_cache_lock);
341 m_object_cacher->flush_set(m_object_set, object_extents, &trace,
342 on_dispatched);
343 return true;
344 }
345
346 template <typename I>
347 bool ObjectCacherObjectDispatch<I>::flush(
348 io::FlushSource flush_source, const ZTracer::Trace &parent_trace,
349 io::DispatchResult* dispatch_result, Context** on_finish,
350 Context* on_dispatched) {
351 auto cct = m_image_ctx->cct;
352 ldout(cct, 20) << dendl;
353
354 // ensure we aren't holding the cache lock post-flush
355 on_dispatched = util::create_async_context_callback(*m_image_ctx,
356 on_dispatched);
357
358 m_cache_lock.Lock();
359 if (flush_source == io::FLUSH_SOURCE_USER && !m_user_flushed &&
360 m_image_ctx->cache_writethrough_until_flush &&
361 m_image_ctx->cache_max_dirty > 0) {
362 m_user_flushed = true;
363 m_object_cacher->set_max_dirty(m_image_ctx->cache_max_dirty);
364 ldout(cct, 5) << "saw first user flush, enabling writeback" << dendl;
365 }
366
367 *dispatch_result = io::DISPATCH_RESULT_CONTINUE;
368 m_object_cacher->flush_set(m_object_set, on_dispatched);
369 m_cache_lock.Unlock();
370 return true;
371 }
372
373 template <typename I>
374 bool ObjectCacherObjectDispatch<I>::invalidate_cache(Context* on_finish) {
375 auto cct = m_image_ctx->cct;
376 ldout(cct, 5) << dendl;
377
378 // ensure we aren't holding the cache lock post-flush
379 on_finish = util::create_async_context_callback(*m_image_ctx, on_finish);
380
381 // invalidate any remaining cache entries
382 on_finish = new C_InvalidateCache(this, false, on_finish);
383
384 m_cache_lock.Lock();
385 m_object_cacher->release_set(m_object_set);
386 m_object_cacher->flush_set(m_object_set, on_finish);
387 m_cache_lock.Unlock();
388 return true;
389 }
390
391 template <typename I>
392 bool ObjectCacherObjectDispatch<I>::reset_existence_cache(
393 Context* on_finish) {
394 auto cct = m_image_ctx->cct;
395 ldout(cct, 5) << dendl;
396
397 m_cache_lock.Lock();
398 m_object_cacher->clear_nonexistence(m_object_set);
399 m_cache_lock.Unlock();
400
401 return false;
402 }
403
404 } // namespace cache
405 } // namespace librbd
406
407 template class librbd::cache::ObjectCacherObjectDispatch<librbd::ImageCtx>;