]>
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 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2016 SUSE LINUX GmbH | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
c07f9fc5 | 14 | |
7c673cae FG |
15 | #include "include/rados/librados.hpp" |
16 | #include "common/Formatter.h" | |
17 | #include "common/admin_socket.h" | |
18 | #include "common/debug.h" | |
19 | #include "common/errno.h" | |
11fdf7f2 | 20 | #include "common/Timer.h" |
7c673cae FG |
21 | #include "common/WorkQueue.h" |
22 | #include "global/global_context.h" | |
23 | #include "librbd/internal.h" | |
24 | #include "librbd/ImageCtx.h" | |
25 | #include "librbd/ImageState.h" | |
7c673cae | 26 | #include "librbd/Operations.h" |
7c673cae FG |
27 | #include "cls/rbd/cls_rbd_client.h" |
28 | #include "cls/rbd/cls_rbd_types.h" | |
29 | #include "librbd/Utils.h" | |
30 | #include "ImageDeleter.h" | |
11fdf7f2 | 31 | #include "tools/rbd_mirror/Threads.h" |
9f95a23c | 32 | #include "tools/rbd_mirror/Throttler.h" |
11fdf7f2 | 33 | #include "tools/rbd_mirror/image_deleter/TrashMoveRequest.h" |
eafe8130 | 34 | #include "tools/rbd_mirror/image_deleter/TrashRemoveRequest.h" |
11fdf7f2 TL |
35 | #include "tools/rbd_mirror/image_deleter/TrashWatcher.h" |
36 | #include <map> | |
37 | #include <sstream> | |
7c673cae FG |
38 | |
39 | #define dout_context g_ceph_context | |
40 | #define dout_subsys ceph_subsys_rbd_mirror | |
7c673cae FG |
41 | |
42 | using std::string; | |
7c673cae FG |
43 | using std::stringstream; |
44 | using std::vector; | |
45 | using std::pair; | |
46 | using std::make_pair; | |
47 | ||
48 | using librados::IoCtx; | |
49 | using namespace librbd; | |
50 | ||
51 | namespace rbd { | |
52 | namespace mirror { | |
53 | ||
9f95a23c TL |
54 | using librbd::util::create_async_context_callback; |
55 | ||
7c673cae FG |
56 | namespace { |
57 | ||
58 | class ImageDeleterAdminSocketCommand { | |
59 | public: | |
60 | virtual ~ImageDeleterAdminSocketCommand() {} | |
9f95a23c | 61 | virtual int call(Formatter *f) = 0; |
7c673cae FG |
62 | }; |
63 | ||
c07f9fc5 | 64 | template <typename I> |
7c673cae FG |
65 | class StatusCommand : public ImageDeleterAdminSocketCommand { |
66 | public: | |
c07f9fc5 | 67 | explicit StatusCommand(ImageDeleter<I> *image_del) : image_del(image_del) {} |
7c673cae | 68 | |
9f95a23c TL |
69 | int call(Formatter *f) override { |
70 | image_del->print_status(f); | |
71 | return 0; | |
7c673cae FG |
72 | } |
73 | ||
74 | private: | |
c07f9fc5 | 75 | ImageDeleter<I> *image_del; |
7c673cae FG |
76 | }; |
77 | ||
7c673cae FG |
78 | } // anonymous namespace |
79 | ||
c07f9fc5 | 80 | template <typename I> |
7c673cae FG |
81 | class ImageDeleterAdminSocketHook : public AdminSocketHook { |
82 | public: | |
11fdf7f2 TL |
83 | ImageDeleterAdminSocketHook(CephContext *cct, const std::string& pool_name, |
84 | ImageDeleter<I> *image_del) : | |
7c673cae FG |
85 | admin_socket(cct->get_admin_socket()) { |
86 | ||
87 | std::string command; | |
88 | int r; | |
89 | ||
11fdf7f2 | 90 | command = "rbd mirror deletion status " + pool_name; |
9f95a23c | 91 | r = admin_socket->register_command(command, this, |
7c673cae FG |
92 | "get status for image deleter"); |
93 | if (r == 0) { | |
c07f9fc5 | 94 | commands[command] = new StatusCommand<I>(image_del); |
7c673cae FG |
95 | } |
96 | ||
97 | } | |
98 | ||
99 | ~ImageDeleterAdminSocketHook() override { | |
9f95a23c | 100 | (void)admin_socket->unregister_commands(this); |
7c673cae FG |
101 | for (Commands::const_iterator i = commands.begin(); i != commands.end(); |
102 | ++i) { | |
7c673cae FG |
103 | delete i->second; |
104 | } | |
105 | } | |
106 | ||
9f95a23c TL |
107 | int call(std::string_view command, const cmdmap_t& cmdmap, |
108 | Formatter *f, | |
109 | std::ostream& errss, | |
110 | bufferlist& out) override { | |
7c673cae | 111 | Commands::const_iterator i = commands.find(command); |
11fdf7f2 | 112 | ceph_assert(i != commands.end()); |
9f95a23c | 113 | return i->second->call(f); |
7c673cae FG |
114 | } |
115 | ||
116 | private: | |
11fdf7f2 TL |
117 | typedef std::map<std::string, ImageDeleterAdminSocketCommand*, |
118 | std::less<>> Commands; | |
7c673cae FG |
119 | AdminSocket *admin_socket; |
120 | Commands commands; | |
121 | }; | |
122 | ||
c07f9fc5 | 123 | template <typename I> |
9f95a23c TL |
124 | ImageDeleter<I>::ImageDeleter( |
125 | librados::IoCtx& local_io_ctx, Threads<librbd::ImageCtx>* threads, | |
126 | Throttler<librbd::ImageCtx>* image_deletion_throttler, | |
127 | ServiceDaemon<librbd::ImageCtx>* service_daemon) | |
11fdf7f2 | 128 | : m_local_io_ctx(local_io_ctx), m_threads(threads), |
9f95a23c | 129 | m_image_deletion_throttler(image_deletion_throttler), |
11fdf7f2 | 130 | m_service_daemon(service_daemon), m_trash_listener(this), |
9f95a23c TL |
131 | m_lock(ceph::make_mutex( |
132 | librbd::util::unique_lock_name("rbd::mirror::ImageDeleter::m_lock", | |
133 | this))) { | |
7c673cae FG |
134 | } |
135 | ||
11fdf7f2 TL |
136 | #undef dout_prefix |
137 | #define dout_prefix *_dout << "rbd::mirror::ImageDeleter: " << " " \ | |
138 | << __func__ << ": " | |
139 | ||
c07f9fc5 | 140 | template <typename I> |
11fdf7f2 TL |
141 | void ImageDeleter<I>::trash_move(librados::IoCtx& local_io_ctx, |
142 | const std::string& global_image_id, | |
143 | bool resync, | |
144 | ContextWQ* work_queue, Context* on_finish) { | |
145 | dout(10) << "global_image_id=" << global_image_id << ", " | |
146 | << "resync=" << resync << dendl; | |
147 | ||
148 | auto req = rbd::mirror::image_deleter::TrashMoveRequest<>::create( | |
149 | local_io_ctx, global_image_id, resync, work_queue, on_finish); | |
150 | req->send(); | |
151 | } | |
7c673cae | 152 | |
11fdf7f2 TL |
153 | #undef dout_prefix |
154 | #define dout_prefix *_dout << "rbd::mirror::ImageDeleter: " << this << " " \ | |
155 | << __func__ << ": " | |
7c673cae | 156 | |
11fdf7f2 TL |
157 | template <typename I> |
158 | void ImageDeleter<I>::init(Context* on_finish) { | |
159 | dout(10) << dendl; | |
160 | ||
161 | m_asok_hook = new ImageDeleterAdminSocketHook<I>( | |
162 | g_ceph_context, m_local_io_ctx.get_pool_name(), this); | |
163 | ||
164 | m_trash_watcher = image_deleter::TrashWatcher<I>::create(m_local_io_ctx, | |
165 | m_threads, | |
166 | m_trash_listener); | |
167 | m_trash_watcher->init(on_finish); | |
7c673cae FG |
168 | } |
169 | ||
c07f9fc5 | 170 | template <typename I> |
11fdf7f2 TL |
171 | void ImageDeleter<I>::shut_down(Context* on_finish) { |
172 | dout(10) << dendl; | |
7c673cae | 173 | |
11fdf7f2 TL |
174 | delete m_asok_hook; |
175 | m_asok_hook = nullptr; | |
7c673cae | 176 | |
9f95a23c TL |
177 | m_image_deletion_throttler->drain(m_local_io_ctx.get_namespace(), |
178 | -ESTALE); | |
179 | ||
11fdf7f2 TL |
180 | shut_down_trash_watcher(on_finish); |
181 | } | |
7c673cae | 182 | |
11fdf7f2 TL |
183 | template <typename I> |
184 | void ImageDeleter<I>::shut_down_trash_watcher(Context* on_finish) { | |
185 | dout(10) << dendl; | |
186 | ceph_assert(m_trash_watcher); | |
9f95a23c | 187 | auto ctx = new LambdaContext([this, on_finish](int r) { |
11fdf7f2 TL |
188 | delete m_trash_watcher; |
189 | m_trash_watcher = nullptr; | |
190 | ||
191 | wait_for_ops(on_finish); | |
192 | }); | |
193 | m_trash_watcher->shut_down(ctx); | |
7c673cae FG |
194 | } |
195 | ||
c07f9fc5 | 196 | template <typename I> |
11fdf7f2 TL |
197 | void ImageDeleter<I>::wait_for_ops(Context* on_finish) { |
198 | { | |
9f95a23c | 199 | std::scoped_lock locker{m_threads->timer_lock, m_lock}; |
11fdf7f2 TL |
200 | m_running = false; |
201 | cancel_retry_timer(); | |
202 | } | |
7c673cae | 203 | |
9f95a23c | 204 | auto ctx = new LambdaContext([this, on_finish](int) { |
11fdf7f2 TL |
205 | cancel_all_deletions(on_finish); |
206 | }); | |
207 | m_async_op_tracker.wait_for_ops(ctx); | |
208 | } | |
7c673cae | 209 | |
11fdf7f2 TL |
210 | template <typename I> |
211 | void ImageDeleter<I>::cancel_all_deletions(Context* on_finish) { | |
9f95a23c TL |
212 | m_image_deletion_throttler->drain(m_local_io_ctx.get_namespace(), |
213 | -ECANCELED); | |
11fdf7f2 | 214 | { |
9f95a23c | 215 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
216 | // wake up any external state machines waiting on deletions |
217 | ceph_assert(m_in_flight_delete_queue.empty()); | |
218 | for (auto& queue : {&m_delete_queue, &m_retry_delete_queue}) { | |
219 | for (auto& info : *queue) { | |
220 | notify_on_delete(info->image_id, -ECANCELED); | |
221 | } | |
222 | queue->clear(); | |
c07f9fc5 | 223 | } |
7c673cae | 224 | } |
11fdf7f2 | 225 | on_finish->complete(0); |
7c673cae FG |
226 | } |
227 | ||
c07f9fc5 | 228 | template <typename I> |
11fdf7f2 TL |
229 | void ImageDeleter<I>::wait_for_deletion(const std::string& image_id, |
230 | bool scheduled_only, | |
231 | Context* on_finish) { | |
232 | dout(5) << "image_id=" << image_id << dendl; | |
7c673cae | 233 | |
9f95a23c | 234 | on_finish = new LambdaContext([this, on_finish](int r) { |
11fdf7f2 | 235 | m_threads->work_queue->queue(on_finish, r); |
7c673cae FG |
236 | }); |
237 | ||
9f95a23c | 238 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
239 | auto del_info = find_delete_info(image_id); |
240 | if (!del_info && scheduled_only) { | |
7c673cae | 241 | // image not scheduled for deletion |
11fdf7f2 | 242 | on_finish->complete(0); |
7c673cae FG |
243 | return; |
244 | } | |
245 | ||
11fdf7f2 TL |
246 | notify_on_delete(image_id, -ESTALE); |
247 | m_on_delete_contexts[image_id] = on_finish; | |
248 | } | |
7c673cae | 249 | |
11fdf7f2 TL |
250 | template <typename I> |
251 | void ImageDeleter<I>::complete_active_delete(DeleteInfoRef* delete_info, | |
252 | int r) { | |
253 | dout(20) << "info=" << *delete_info << ", r=" << r << dendl; | |
9f95a23c | 254 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
255 | notify_on_delete((*delete_info)->image_id, r); |
256 | delete_info->reset(); | |
7c673cae FG |
257 | } |
258 | ||
c07f9fc5 | 259 | template <typename I> |
11fdf7f2 TL |
260 | void ImageDeleter<I>::enqueue_failed_delete(DeleteInfoRef* delete_info, |
261 | int error_code, | |
262 | double retry_delay) { | |
263 | dout(20) << "info=" << *delete_info << ", r=" << error_code << dendl; | |
264 | if (error_code == -EBLACKLISTED) { | |
9f95a23c | 265 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
266 | derr << "blacklisted while deleting local image" << dendl; |
267 | complete_active_delete(delete_info, error_code); | |
7c673cae FG |
268 | return; |
269 | } | |
270 | ||
9f95a23c | 271 | std::scoped_lock locker{m_threads->timer_lock, m_lock}; |
11fdf7f2 TL |
272 | auto& delete_info_ref = *delete_info; |
273 | notify_on_delete(delete_info_ref->image_id, error_code); | |
274 | delete_info_ref->error_code = error_code; | |
275 | ++delete_info_ref->retries; | |
9f95a23c TL |
276 | delete_info_ref->retry_time = (clock_t::now() + |
277 | ceph::make_timespan(retry_delay)); | |
11fdf7f2 TL |
278 | m_retry_delete_queue.push_back(delete_info_ref); |
279 | ||
280 | schedule_retry_timer(); | |
7c673cae FG |
281 | } |
282 | ||
c07f9fc5 | 283 | template <typename I> |
11fdf7f2 TL |
284 | typename ImageDeleter<I>::DeleteInfoRef |
285 | ImageDeleter<I>::find_delete_info(const std::string &image_id) { | |
9f95a23c | 286 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
11fdf7f2 TL |
287 | DeleteQueue delete_queues[] = {m_in_flight_delete_queue, |
288 | m_retry_delete_queue, | |
289 | m_delete_queue}; | |
290 | ||
291 | DeleteInfo delete_info{image_id}; | |
292 | for (auto& queue : delete_queues) { | |
293 | auto it = std::find_if(queue.begin(), queue.end(), | |
294 | [&delete_info](const DeleteInfoRef& ref) { | |
295 | return delete_info == *ref; | |
296 | }); | |
297 | if (it != queue.end()) { | |
298 | return *it; | |
299 | } | |
7c673cae | 300 | } |
11fdf7f2 TL |
301 | return {}; |
302 | } | |
7c673cae | 303 | |
11fdf7f2 | 304 | template <typename I> |
9f95a23c | 305 | void ImageDeleter<I>::print_status(Formatter *f) { |
11fdf7f2 | 306 | dout(20) << dendl; |
7c673cae | 307 | |
9f95a23c TL |
308 | f->open_object_section("image_deleter_status"); |
309 | f->open_array_section("delete_images_queue"); | |
7c673cae | 310 | |
9f95a23c | 311 | std::lock_guard l{m_lock}; |
11fdf7f2 | 312 | for (const auto& image : m_delete_queue) { |
9f95a23c | 313 | image->print_status(f); |
7c673cae FG |
314 | } |
315 | ||
9f95a23c TL |
316 | f->close_section(); |
317 | f->open_array_section("failed_deletes_queue"); | |
11fdf7f2 | 318 | for (const auto& image : m_retry_delete_queue) { |
9f95a23c | 319 | image->print_status(f, true); |
7c673cae FG |
320 | } |
321 | ||
9f95a23c TL |
322 | f->close_section(); |
323 | f->close_section(); | |
11fdf7f2 | 324 | } |
7c673cae | 325 | |
11fdf7f2 TL |
326 | template <typename I> |
327 | vector<string> ImageDeleter<I>::get_delete_queue_items() { | |
328 | vector<string> items; | |
7c673cae | 329 | |
9f95a23c | 330 | std::lock_guard l{m_lock}; |
11fdf7f2 TL |
331 | for (const auto& del_info : m_delete_queue) { |
332 | items.push_back(del_info->image_id); | |
333 | } | |
7c673cae | 334 | |
11fdf7f2 TL |
335 | return items; |
336 | } | |
7c673cae | 337 | |
11fdf7f2 TL |
338 | template <typename I> |
339 | vector<pair<string, int> > ImageDeleter<I>::get_failed_queue_items() { | |
340 | vector<pair<string, int> > items; | |
7c673cae | 341 | |
9f95a23c | 342 | std::lock_guard l{m_lock}; |
11fdf7f2 TL |
343 | for (const auto& del_info : m_retry_delete_queue) { |
344 | items.push_back(make_pair(del_info->image_id, | |
345 | del_info->error_code)); | |
346 | } | |
7c673cae | 347 | |
11fdf7f2 TL |
348 | return items; |
349 | } | |
7c673cae | 350 | |
11fdf7f2 TL |
351 | template <typename I> |
352 | void ImageDeleter<I>::remove_images() { | |
353 | dout(10) << dendl; | |
354 | ||
9f95a23c TL |
355 | std::lock_guard locker{m_lock}; |
356 | while (m_running && !m_delete_queue.empty()) { | |
7c673cae | 357 | |
11fdf7f2 TL |
358 | DeleteInfoRef delete_info = m_delete_queue.front(); |
359 | m_delete_queue.pop_front(); | |
7c673cae | 360 | |
11fdf7f2 | 361 | ceph_assert(delete_info); |
9f95a23c TL |
362 | |
363 | auto on_start = create_async_context_callback( | |
364 | m_threads->work_queue, new LambdaContext( | |
365 | [this, delete_info](int r) { | |
366 | if (r < 0) { | |
367 | notify_on_delete(delete_info->image_id, r); | |
368 | return; | |
369 | } | |
370 | remove_image(delete_info); | |
371 | })); | |
372 | ||
373 | m_image_deletion_throttler->start_op(m_local_io_ctx.get_namespace(), | |
374 | delete_info->image_id, on_start); | |
7c673cae | 375 | } |
11fdf7f2 | 376 | } |
7c673cae | 377 | |
11fdf7f2 TL |
378 | template <typename I> |
379 | void ImageDeleter<I>::remove_image(DeleteInfoRef delete_info) { | |
380 | dout(10) << "info=" << *delete_info << dendl; | |
9f95a23c TL |
381 | |
382 | std::lock_guard locker{m_lock}; | |
7c673cae | 383 | |
11fdf7f2 TL |
384 | m_in_flight_delete_queue.push_back(delete_info); |
385 | m_async_op_tracker.start_op(); | |
7c673cae | 386 | |
9f95a23c | 387 | auto ctx = new LambdaContext([this, delete_info](int r) { |
11fdf7f2 TL |
388 | handle_remove_image(delete_info, r); |
389 | m_async_op_tracker.finish_op(); | |
390 | }); | |
7c673cae | 391 | |
eafe8130 | 392 | auto req = image_deleter::TrashRemoveRequest<I>::create( |
11fdf7f2 TL |
393 | m_local_io_ctx, delete_info->image_id, &delete_info->error_result, |
394 | m_threads->work_queue, ctx); | |
395 | req->send(); | |
7c673cae FG |
396 | } |
397 | ||
c07f9fc5 | 398 | template <typename I> |
11fdf7f2 TL |
399 | void ImageDeleter<I>::handle_remove_image(DeleteInfoRef delete_info, |
400 | int r) { | |
401 | dout(10) << "info=" << *delete_info << ", r=" << r << dendl; | |
7c673cae | 402 | |
9f95a23c TL |
403 | m_image_deletion_throttler->finish_op(m_local_io_ctx.get_namespace(), |
404 | delete_info->image_id); | |
11fdf7f2 | 405 | { |
9f95a23c TL |
406 | std::lock_guard locker{m_lock}; |
407 | ceph_assert(ceph_mutex_is_locked(m_lock)); | |
11fdf7f2 TL |
408 | auto it = std::find(m_in_flight_delete_queue.begin(), |
409 | m_in_flight_delete_queue.end(), delete_info); | |
410 | ceph_assert(it != m_in_flight_delete_queue.end()); | |
411 | m_in_flight_delete_queue.erase(it); | |
412 | } | |
7c673cae | 413 | |
11fdf7f2 TL |
414 | if (r < 0) { |
415 | if (delete_info->error_result == image_deleter::ERROR_RESULT_COMPLETE) { | |
416 | complete_active_delete(&delete_info, r); | |
417 | } else if (delete_info->error_result == | |
418 | image_deleter::ERROR_RESULT_RETRY_IMMEDIATELY) { | |
419 | enqueue_failed_delete(&delete_info, r, m_busy_interval); | |
420 | } else { | |
421 | auto cct = reinterpret_cast<CephContext *>(m_local_io_ctx.cct()); | |
422 | double failed_interval = cct->_conf.get_val<double>( | |
423 | "rbd_mirror_delete_retry_interval"); | |
424 | enqueue_failed_delete(&delete_info, r, failed_interval); | |
425 | } | |
426 | } else { | |
427 | complete_active_delete(&delete_info, 0); | |
428 | } | |
7c673cae | 429 | |
11fdf7f2 TL |
430 | // process the next queued image to delete |
431 | remove_images(); | |
7c673cae FG |
432 | } |
433 | ||
c07f9fc5 | 434 | template <typename I> |
11fdf7f2 | 435 | void ImageDeleter<I>::schedule_retry_timer() { |
9f95a23c TL |
436 | ceph_assert(ceph_mutex_is_locked(m_threads->timer_lock)); |
437 | ceph_assert(ceph_mutex_is_locked(m_lock)); | |
11fdf7f2 | 438 | if (!m_running || m_timer_ctx != nullptr || m_retry_delete_queue.empty()) { |
7c673cae FG |
439 | return; |
440 | } | |
441 | ||
11fdf7f2 TL |
442 | dout(10) << dendl; |
443 | auto &delete_info = m_retry_delete_queue.front(); | |
9f95a23c | 444 | m_timer_ctx = new LambdaContext([this](int r) { |
11fdf7f2 TL |
445 | handle_retry_timer(); |
446 | }); | |
447 | m_threads->timer->add_event_at(delete_info->retry_time, m_timer_ctx); | |
7c673cae FG |
448 | } |
449 | ||
c07f9fc5 | 450 | template <typename I> |
11fdf7f2 TL |
451 | void ImageDeleter<I>::cancel_retry_timer() { |
452 | dout(10) << dendl; | |
9f95a23c | 453 | ceph_assert(ceph_mutex_is_locked(m_threads->timer_lock)); |
11fdf7f2 TL |
454 | if (m_timer_ctx != nullptr) { |
455 | bool canceled = m_threads->timer->cancel_event(m_timer_ctx); | |
456 | m_timer_ctx = nullptr; | |
457 | ceph_assert(canceled); | |
7c673cae FG |
458 | } |
459 | } | |
460 | ||
c07f9fc5 | 461 | template <typename I> |
11fdf7f2 TL |
462 | void ImageDeleter<I>::handle_retry_timer() { |
463 | dout(10) << dendl; | |
9f95a23c TL |
464 | ceph_assert(ceph_mutex_is_locked(m_threads->timer_lock)); |
465 | std::lock_guard locker{m_lock}; | |
11fdf7f2 TL |
466 | |
467 | ceph_assert(m_timer_ctx != nullptr); | |
468 | m_timer_ctx = nullptr; | |
469 | ||
470 | ceph_assert(m_running); | |
471 | ceph_assert(!m_retry_delete_queue.empty()); | |
472 | ||
473 | // move all ready-to-ready items back to main queue | |
9f95a23c | 474 | auto now = clock_t::now(); |
11fdf7f2 TL |
475 | while (!m_retry_delete_queue.empty()) { |
476 | auto &delete_info = m_retry_delete_queue.front(); | |
477 | if (delete_info->retry_time > now) { | |
478 | break; | |
7c673cae | 479 | } |
7c673cae | 480 | |
11fdf7f2 TL |
481 | m_delete_queue.push_back(delete_info); |
482 | m_retry_delete_queue.pop_front(); | |
7c673cae FG |
483 | } |
484 | ||
11fdf7f2 TL |
485 | // schedule wake up for any future retries |
486 | schedule_retry_timer(); | |
487 | ||
488 | // start (concurrent) removal of images | |
489 | m_async_op_tracker.start_op(); | |
9f95a23c | 490 | auto ctx = new LambdaContext([this](int r) { |
11fdf7f2 TL |
491 | remove_images(); |
492 | m_async_op_tracker.finish_op(); | |
493 | }); | |
494 | m_threads->work_queue->queue(ctx, 0); | |
7c673cae FG |
495 | } |
496 | ||
c07f9fc5 | 497 | template <typename I> |
11fdf7f2 | 498 | void ImageDeleter<I>::handle_trash_image(const std::string& image_id, |
9f95a23c TL |
499 | const ImageDeleter<I>::clock_t::time_point& deferment_end_time) { |
500 | std::scoped_lock locker{m_threads->timer_lock, m_lock}; | |
7c673cae | 501 | |
11fdf7f2 TL |
502 | auto del_info = find_delete_info(image_id); |
503 | if (del_info != nullptr) { | |
504 | dout(20) << "image " << image_id << " " | |
505 | << "was already scheduled for deletion" << dendl; | |
506 | return; | |
7c673cae FG |
507 | } |
508 | ||
11fdf7f2 | 509 | dout(10) << "image_id=" << image_id << ", " |
9f95a23c | 510 | << "deferment_end_time=" << utime_t{deferment_end_time} << dendl; |
7c673cae | 511 | |
11fdf7f2 TL |
512 | del_info.reset(new DeleteInfo(image_id)); |
513 | del_info->retry_time = deferment_end_time; | |
514 | m_retry_delete_queue.push_back(del_info); | |
7c673cae | 515 | |
11fdf7f2 | 516 | schedule_retry_timer(); |
7c673cae FG |
517 | } |
518 | ||
c07f9fc5 | 519 | template <typename I> |
11fdf7f2 TL |
520 | void ImageDeleter<I>::notify_on_delete(const std::string& image_id, |
521 | int r) { | |
522 | dout(10) << "image_id=" << image_id << ", r=" << r << dendl; | |
523 | auto it = m_on_delete_contexts.find(image_id); | |
524 | if (it == m_on_delete_contexts.end()) { | |
525 | return; | |
7c673cae | 526 | } |
7c673cae | 527 | |
11fdf7f2 TL |
528 | it->second->complete(r); |
529 | m_on_delete_contexts.erase(it); | |
7c673cae FG |
530 | } |
531 | ||
c07f9fc5 | 532 | template <typename I> |
9f95a23c | 533 | void ImageDeleter<I>::DeleteInfo::print_status(Formatter *f, |
c07f9fc5 | 534 | bool print_failure_info) { |
9f95a23c TL |
535 | f->open_object_section("delete_info"); |
536 | f->dump_string("image_id", image_id); | |
537 | if (print_failure_info) { | |
538 | f->dump_string("error_code", cpp_strerror(error_code)); | |
539 | f->dump_int("retries", retries); | |
7c673cae | 540 | } |
9f95a23c | 541 | f->close_section(); |
7c673cae FG |
542 | } |
543 | ||
544 | } // namespace mirror | |
545 | } // namespace rbd | |
c07f9fc5 FG |
546 | |
547 | template class rbd::mirror::ImageDeleter<librbd::ImageCtx>; |