]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-mirror: integrate trash watcher within image deleter
authorJason Dillaman <dillaman@redhat.com>
Wed, 13 Dec 2017 21:30:53 +0000 (16:30 -0500)
committerJason Dillaman <dillaman@redhat.com>
Tue, 19 Dec 2017 14:09:13 +0000 (09:09 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/test/rbd_mirror/test_ImageDeleter.cc
src/test/rbd_mirror/test_ImageReplayer.cc
src/test/rbd_mirror/test_mock_ImageReplayer.cc
src/tools/rbd_mirror/ImageDeleter.cc
src/tools/rbd_mirror/ImageDeleter.h
src/tools/rbd_mirror/ImageReplayer.cc
src/tools/rbd_mirror/image_deleter/TrashWatcher.h

index 3325297155b7399458a69567712b5a79469513f5..d2e36793aa48719c8bee2de66a169ec4b2e35e1a 100644 (file)
@@ -78,12 +78,23 @@ public:
 
   void TearDown() override {
     remove_image();
+
+    C_SaferCond ctx;
+    m_deleter->shut_down(&ctx);
+    ctx.wait();
+
     delete m_deleter;
     m_service_daemon.reset();
 
     TestFixture::TearDown();
   }
 
+  void init_image_deleter() {
+    C_SaferCond ctx;
+    m_deleter->init(&ctx);
+    ASSERT_EQ(0, ctx.wait());
+  }
+
   void remove_image(bool force=false) {
     if (!force) {
       cls::rbd::MirrorImage mirror_image;
@@ -203,7 +214,6 @@ public:
                                                     &mirror_image));
   }
 
-
   librbd::RBD rbd;
   std::string m_local_image_id;
   std::unique_ptr<rbd::mirror::ServiceDaemon<>> m_service_daemon;
@@ -211,6 +221,7 @@ public:
 };
 
 TEST_F(TestImageDeleter, Delete_NonPrimary_Image) {
+  init_image_deleter();
   m_deleter->schedule_image_delete(GLOBAL_IMAGE_ID, false, nullptr);
 
   C_SaferCond ctx;
@@ -224,6 +235,7 @@ TEST_F(TestImageDeleter, Delete_NonPrimary_Image) {
 }
 
 TEST_F(TestImageDeleter, Delete_Split_Brain_Image) {
+  init_image_deleter();
   promote_image();
   demote_image();
 
@@ -240,6 +252,7 @@ TEST_F(TestImageDeleter, Delete_Split_Brain_Image) {
 }
 
 TEST_F(TestImageDeleter, Fail_Delete_Primary_Image) {
+  init_image_deleter();
   promote_image();
 
   C_SaferCond ctx;
@@ -251,6 +264,7 @@ TEST_F(TestImageDeleter, Fail_Delete_Primary_Image) {
 }
 
 TEST_F(TestImageDeleter, Fail_Delete_Orphan_Image) {
+  init_image_deleter();
   promote_image();
   demote_image();
 
@@ -263,6 +277,7 @@ TEST_F(TestImageDeleter, Fail_Delete_Orphan_Image) {
 }
 
 TEST_F(TestImageDeleter, Delete_Image_With_Child) {
+  init_image_deleter();
   create_snapshot();
 
   m_deleter->schedule_image_delete(GLOBAL_IMAGE_ID, false, nullptr);
@@ -276,6 +291,7 @@ TEST_F(TestImageDeleter, Delete_Image_With_Child) {
 }
 
 TEST_F(TestImageDeleter, Delete_Image_With_Children) {
+  init_image_deleter();
   create_snapshot("snap1");
   create_snapshot("snap2");
 
@@ -290,6 +306,7 @@ TEST_F(TestImageDeleter, Delete_Image_With_Children) {
 }
 
 TEST_F(TestImageDeleter, Delete_Image_With_ProtectedChild) {
+  init_image_deleter();
   create_snapshot("snap1", true);
 
   m_deleter->schedule_image_delete(GLOBAL_IMAGE_ID, false, nullptr);
@@ -303,6 +320,7 @@ TEST_F(TestImageDeleter, Delete_Image_With_ProtectedChild) {
 }
 
 TEST_F(TestImageDeleter, Delete_Image_With_ProtectedChildren) {
+  init_image_deleter();
   create_snapshot("snap1", true);
   create_snapshot("snap2", true);
 
@@ -317,6 +335,7 @@ TEST_F(TestImageDeleter, Delete_Image_With_ProtectedChildren) {
 }
 
 TEST_F(TestImageDeleter, Delete_Image_With_Clone) {
+  init_image_deleter();
   std::string clone_id = create_clone();
 
   C_SaferCond ctx;
@@ -337,6 +356,7 @@ TEST_F(TestImageDeleter, Delete_Image_With_Clone) {
 }
 
 TEST_F(TestImageDeleter, Delete_NonExistent_Image) {
+  init_image_deleter();
   remove_image();
 
   cls::rbd::MirrorImage mirror_image(GLOBAL_IMAGE_ID,
@@ -357,6 +377,7 @@ TEST_F(TestImageDeleter, Delete_NonExistent_Image) {
 }
 
 TEST_F(TestImageDeleter, Delete_NonExistent_Image_With_MirroringState) {
+  init_image_deleter();
   remove_image(true);
 
   cls::rbd::MirrorImage mirror_image(GLOBAL_IMAGE_ID,
@@ -380,6 +401,7 @@ TEST_F(TestImageDeleter, Delete_NonExistent_Image_With_MirroringState) {
 }
 
 TEST_F(TestImageDeleter, Delete_NonExistent_Image_Without_MirroringState) {
+  init_image_deleter();
   remove_image();
 
   C_SaferCond ctx;
@@ -393,6 +415,7 @@ TEST_F(TestImageDeleter, Delete_NonExistent_Image_Without_MirroringState) {
 }
 
 TEST_F(TestImageDeleter, Fail_Delete_NonPrimary_Image) {
+  init_image_deleter();
   ImageCtx *ictx = new ImageCtx("", m_local_image_id, "", m_local_io_ctx,
                                 false);
   EXPECT_EQ(0, ictx->state->open(false));
@@ -405,6 +428,7 @@ TEST_F(TestImageDeleter, Fail_Delete_NonPrimary_Image) {
 }
 
 TEST_F(TestImageDeleter, Retry_Failed_Deletes) {
+  init_image_deleter();
   EXPECT_EQ(0, g_ceph_context->_conf->set_val("rbd_mirror_delete_retry_interval", "0.1"));
   ImageCtx *ictx = new ImageCtx("", m_local_image_id, "", m_local_io_ctx,
                                 false);
@@ -425,4 +449,3 @@ TEST_F(TestImageDeleter, Retry_Failed_Deletes) {
 
   check_image_deleted();
 }
-
index 945418bce6298d7eeb786edc7e19959dfbd60e1b..b1616195ca35c2a19afd63f167ae2d69cc2c9ba9 100644 (file)
@@ -125,6 +125,11 @@ public:
                                                             m_threads.get()));
     m_image_deleter.reset(new rbd::mirror::ImageDeleter<>(
       m_local_ioctx, m_threads.get(), m_service_daemon.get()));
+
+    C_SaferCond ctx;
+    m_image_deleter->init(&ctx);
+    EXPECT_EQ(0, ctx.wait());
+
     m_instance_watcher = rbd::mirror::InstanceWatcher<>::create(
         m_local_ioctx, m_threads->work_queue, nullptr);
     m_instance_watcher->handle_acquire_leader();
index 63919514b6491c8b0b0fbbb3811fa3c47f2d9090..869b55f795b8840c2267b48d27bee6e04a6e3445 100644 (file)
@@ -87,8 +87,8 @@ template <>
 struct ImageDeleter<librbd::MockTestImageCtx> {
   MOCK_METHOD3(schedule_image_delete, void(const std::string&, bool,
                                            Context*));
-  MOCK_METHOD3(wait_for_scheduled_deletion,
-               void(const std::string&, Context*, bool));
+  MOCK_METHOD2(wait_for_scheduled_deletion,
+               void(const std::string&, Context*));
   MOCK_METHOD1(cancel_waiter, void(const std::string&));
 };
 
@@ -385,7 +385,7 @@ public:
                                           const std::string& global_image_id,
                                           int r) {
     EXPECT_CALL(mock_image_deleter,
-                wait_for_scheduled_deletion(global_image_id, _, false))
+                wait_for_scheduled_deletion(global_image_id, _))
       .WillOnce(WithArg<1>(Invoke([this, r](Context *ctx) {
                              m_threads->work_queue->queue(ctx, r);
                            })));
index 94168ad6166d75c3c17198fed3391ef397b42de7..46a4bdc78c30114218f3894125b4e5a9862a173f 100644 (file)
 #include "ImageDeleter.h"
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/image_deleter/RemoveRequest.h"
+#include "tools/rbd_mirror/image_deleter/TrashMoveRequest.h"
+#include "tools/rbd_mirror/image_deleter/TrashWatcher.h"
 #include <map>
 #include <sstream>
 
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rbd_mirror
-#undef dout_prefix
-#define dout_prefix *_dout << "rbd::mirror::ImageDeleter: " << this << " " \
-                           << __func__ << ": "
 
 using std::string;
 using std::stringstream;
@@ -126,13 +125,33 @@ template <typename I>
 ImageDeleter<I>::ImageDeleter(librados::IoCtx& local_io_ctx,
                               Threads<librbd::ImageCtx>* threads,
                               ServiceDaemon<librbd::ImageCtx>* service_daemon)
-  : m_local_io_ctx(local_io_ctx), m_work_queue(threads->work_queue),
-    m_timer(threads->timer), m_timer_lock(&threads->timer_lock),
-    m_service_daemon(service_daemon),
+  : m_local_io_ctx(local_io_ctx), m_threads(threads),
+    m_service_daemon(service_daemon), m_trash_listener(this),
     m_lock(librbd::util::unique_lock_name("rbd::mirror::ImageDeleter::m_lock",
                                           this)) {
 }
 
+#undef dout_prefix
+#define dout_prefix *_dout << "rbd::mirror::ImageDeleter: " << " " \
+                           << __func__ << ": "
+
+template <typename I>
+void ImageDeleter<I>::trash_move(librados::IoCtx& local_io_ctx,
+                                 const std::string& global_image_id,
+                                 bool resync,
+                                 ContextWQ* work_queue, Context* on_finish) {
+  dout(10) << "global_image_id=" << global_image_id << ", "
+           << "resync=" << resync << dendl;
+
+  auto req = rbd::mirror::image_deleter::TrashMoveRequest<>::create(
+    local_io_ctx, global_image_id, resync, work_queue, on_finish);
+  req->send();
+}
+
+#undef dout_prefix
+#define dout_prefix *_dout << "rbd::mirror::ImageDeleter: " << this << " " \
+                           << __func__ << ": "
+
 template <typename I>
 void ImageDeleter<I>::init(Context* on_finish) {
   dout(10) << dendl;
@@ -140,7 +159,10 @@ void ImageDeleter<I>::init(Context* on_finish) {
   m_asok_hook = new ImageDeleterAdminSocketHook<I>(
     g_ceph_context, m_local_io_ctx.get_pool_name(), this);
 
-  on_finish->complete(0);
+  m_trash_watcher = image_deleter::TrashWatcher<I>::create(m_local_io_ctx,
+                                                           m_threads,
+                                                           m_trash_listener);
+  m_trash_watcher->init(on_finish);
 }
 
 template <typename I>
@@ -150,18 +172,31 @@ void ImageDeleter<I>::shut_down(Context* on_finish) {
   delete m_asok_hook;
   m_asok_hook = nullptr;
 
+  shut_down_trash_watcher(on_finish);
+}
+
+template <typename I>
+void ImageDeleter<I>::shut_down_trash_watcher(Context* on_finish) {
+  dout(10) << dendl;
+  assert(m_trash_watcher);
+  auto ctx = new FunctionContext([this, on_finish](int r) {
+      delete m_trash_watcher;
+      m_trash_watcher = nullptr;
+
+      wait_for_ops(on_finish);
+    });
+  m_trash_watcher->shut_down(ctx);
+}
+
+template <typename I>
+void ImageDeleter<I>::wait_for_ops(Context* on_finish) {
   {
-    Mutex::Locker timer_locker(*m_timer_lock);
+    Mutex::Locker timer_locker(m_threads->timer_lock);
     Mutex::Locker locker(m_lock);
     m_running = false;
     cancel_retry_timer();
   }
 
-  wait_for_ops(on_finish);
-}
-
-template <typename I>
-void ImageDeleter<I>::wait_for_ops(Context* on_finish) {
   auto ctx = new FunctionContext([this, on_finish](int) {
       cancel_all_deletions(on_finish);
     });
@@ -176,9 +211,7 @@ void ImageDeleter<I>::cancel_all_deletions(Context* on_finish) {
     assert(m_in_flight_delete_queue.empty());
     for (auto& queue : {&m_delete_queue, &m_retry_delete_queue}) {
       for (auto& info : *queue) {
-        if (info->on_delete != nullptr) {
-          info->on_delete->complete(-ECANCELED);
-        }
+        notify_on_delete(info->global_image_id, -ECANCELED);
       }
       queue->clear();
     }
@@ -194,12 +227,17 @@ void ImageDeleter<I>::schedule_image_delete(const std::string& global_image_id,
 
   if (on_delete != nullptr) {
     on_delete = new FunctionContext([this, on_delete](int r) {
-        m_work_queue->queue(on_delete, r);
+        m_threads->work_queue->queue(on_delete, r);
       });
   }
 
   {
     Mutex::Locker locker(m_lock);
+    notify_on_delete(global_image_id, -ESTALE);
+    if (on_delete != nullptr) {
+      m_on_delete_contexts[global_image_id] = on_delete;
+    }
+
     auto del_info = find_delete_info(global_image_id);
     if (del_info != nullptr) {
       dout(20) << "image " << global_image_id << " "
@@ -207,43 +245,35 @@ void ImageDeleter<I>::schedule_image_delete(const std::string& global_image_id,
       if (ignore_orphaned) {
         del_info->ignore_orphaned = true;
       }
-
-      if (del_info->on_delete != nullptr) {
-        del_info->on_delete->complete(-ESTALE);
-      }
-      del_info->on_delete = on_delete;
       return;
     }
 
-    m_delete_queue.emplace_back(new DeleteInfo(global_image_id, ignore_orphaned,
-                                               on_delete));
+    m_delete_queue.emplace_back(new DeleteInfo(global_image_id,
+                                               ignore_orphaned));
   }
   remove_images();
 }
 
 template <typename I>
-void ImageDeleter<I>::wait_for_scheduled_deletion(const std::string &global_image_id,
-                                                  Context *ctx,
-                                                  bool notify_on_failed_retry) {
+void ImageDeleter<I>::wait_for_deletion(const std::string& global_image_id,
+                                        bool scheduled_only,
+                                        Context* on_finish) {
   dout(5) << "global_image_id=" << global_image_id << dendl;
 
-  ctx = new FunctionContext([this, ctx](int r) {
-      m_work_queue->queue(ctx, r);
+  on_finish = new FunctionContext([this, on_finish](int r) {
+      m_threads->work_queue->queue(on_finish, r);
     });
 
   Mutex::Locker locker(m_lock);
   auto del_info = find_delete_info(global_image_id);
-  if (!del_info) {
+  if (!del_info && scheduled_only) {
     // image not scheduled for deletion
-    ctx->complete(0);
+    on_finish->complete(0);
     return;
   }
 
-  if (del_info->on_delete != nullptr) {
-    del_info->on_delete->complete(-ESTALE);
-  }
-  del_info->on_delete = ctx;
-  del_info->notify_on_failed_retry = notify_on_failed_retry;
+  notify_on_delete(global_image_id, -ESTALE);
+  m_on_delete_contexts[global_image_id] = on_finish;
 }
 
 template <typename I>
@@ -251,15 +281,7 @@ void ImageDeleter<I>::cancel_waiter(const std::string &global_image_id) {
   dout(5) << "global_image_id=" << global_image_id << dendl;
 
   Mutex::Locker locker(m_lock);
-  auto del_info = find_delete_info(global_image_id);
-  if (!del_info) {
-    return;
-  }
-
-  if (del_info->on_delete != nullptr) {
-    del_info->on_delete->complete(-ECANCELED);
-    del_info->on_delete = nullptr;
-  }
+  notify_on_delete(global_image_id, -ECANCELED);
 }
 
 template <typename I>
@@ -267,7 +289,7 @@ void ImageDeleter<I>::complete_active_delete(DeleteInfoRef* delete_info,
                                              int r) {
   dout(20) << "info=" << *delete_info << ", r=" << r << dendl;
   Mutex::Locker locker(m_lock);
-  (*delete_info)->notify(r);
+  notify_on_delete((*delete_info)->global_image_id, r);
   delete_info->reset();
 }
 
@@ -283,13 +305,12 @@ void ImageDeleter<I>::enqueue_failed_delete(DeleteInfoRef* delete_info,
     return;
   }
 
-  Mutex::Locker timer_locker(*m_timer_lock);
+  Mutex::Locker timer_locker(m_threads->timer_lock);
   Mutex::Locker locker(m_lock);
   auto& delete_info_ref = *delete_info;
-  if (delete_info_ref->notify_on_failed_retry) {
-    delete_info_ref->notify(error_code);
-  }
+  notify_on_delete(delete_info_ref->global_image_id, error_code);
   delete_info_ref->error_code = error_code;
+  ++delete_info_ref->retries;
   delete_info_ref->retry_time = ceph_clock_now();
   delete_info_ref->retry_time += retry_delay;
   m_retry_delete_queue.push_back(delete_info_ref);
@@ -410,7 +431,7 @@ void ImageDeleter<I>::remove_image(DeleteInfoRef delete_info) {
 
   auto req = image_deleter::RemoveRequest<I>::create(
     m_local_io_ctx, delete_info->global_image_id,
-    delete_info->ignore_orphaned, &delete_info->error_result, m_work_queue,
+    delete_info->ignore_orphaned, &delete_info->error_result, m_threads->work_queue,
     ctx);
   req->send();
 }
@@ -450,7 +471,7 @@ void ImageDeleter<I>::handle_remove_image(DeleteInfoRef delete_info,
 
 template <typename I>
 void ImageDeleter<I>::schedule_retry_timer() {
-  assert(m_timer_lock->is_locked());
+  assert(m_threads->timer_lock.is_locked());
   assert(m_lock.is_locked());
   if (!m_running || m_timer_ctx != nullptr || m_retry_delete_queue.empty()) {
     return;
@@ -461,15 +482,15 @@ void ImageDeleter<I>::schedule_retry_timer() {
   m_timer_ctx = new FunctionContext([this](int r) {
       handle_retry_timer();
     });
-  m_timer->add_event_at(delete_info->retry_time, m_timer_ctx);
+  m_threads->timer->add_event_at(delete_info->retry_time, m_timer_ctx);
 }
 
 template <typename I>
 void ImageDeleter<I>::cancel_retry_timer() {
   dout(10) << dendl;
-  assert(m_timer_lock->is_locked());
+  assert(m_threads->timer_lock.is_locked());
   if (m_timer_ctx != nullptr) {
-    bool canceled = m_timer->cancel_event(m_timer_ctx);
+    bool canceled = m_threads->timer->cancel_event(m_timer_ctx);
     m_timer_ctx = nullptr;
     assert(canceled);
   }
@@ -478,7 +499,7 @@ void ImageDeleter<I>::cancel_retry_timer() {
 template <typename I>
 void ImageDeleter<I>::handle_retry_timer() {
   dout(10) << dendl;
-  assert(m_timer_lock->is_locked());
+  assert(m_threads->timer_lock.is_locked());
   Mutex::Locker locker(m_lock);
 
   assert(m_timer_ctx != nullptr);
@@ -508,18 +529,44 @@ void ImageDeleter<I>::handle_retry_timer() {
       remove_images();
       m_async_op_tracker.finish_op();
     });
-  m_work_queue->queue(ctx, 0);
+  m_threads->work_queue->queue(ctx, 0);
 }
 
 template <typename I>
-void ImageDeleter<I>::DeleteInfo::notify(int r) {
-  if (on_delete) {
-    dout(20) << "executing image deletion handler r=" << r << dendl;
+void ImageDeleter<I>::handle_trash_image(const std::string& image_id,
+                                         const utime_t& deferment_end_time) {
+  Mutex::Locker timer_locker(m_threads->timer_lock);
+  Mutex::Locker locker(m_lock);
 
-    Context *ctx = on_delete;
-    on_delete = nullptr;
-    ctx->complete(r);
+  // TODO
+  auto del_info = find_delete_info(image_id);
+  if (del_info != nullptr) {
+    dout(20) << "image " << image_id << " "
+             << "was already scheduled for deletion" << dendl;
+    return;
   }
+
+  dout(10) << "image_id=" << image_id << ", "
+           << "deferment_end_time=" << deferment_end_time << dendl;
+
+  del_info.reset(new DeleteInfo(image_id, false));
+  del_info->retry_time = deferment_end_time;
+  m_retry_delete_queue.push_back(del_info);
+
+  schedule_retry_timer();
+}
+
+template <typename I>
+void ImageDeleter<I>::notify_on_delete(const std::string& global_image_id,
+                                       int r) {
+  dout(10) << "global_image_id=" << global_image_id << ", r=" << r << dendl;
+  auto it = m_on_delete_contexts.find(global_image_id);
+  if (it == m_on_delete_contexts.end()) {
+    return;
+  }
+
+  it->second->complete(r);
+  m_on_delete_contexts.erase(it);
 }
 
 template <typename I>
index 56920ee812d360f95502b23c4e0ba2c12b592ba1..f3fc953d35b6e76f853e089c56fe7e5fadb9b036 100644 (file)
@@ -23,6 +23,7 @@
 #include <atomic>
 #include <deque>
 #include <iosfwd>
+#include <map>
 #include <memory>
 #include <vector>
 
@@ -38,6 +39,8 @@ namespace mirror {
 template <typename> class ServiceDaemon;
 template <typename> class Threads;
 
+namespace image_deleter { template <typename> struct TrashWatcher; }
+
 /**
  * Manage deletion of non-primary images.
  */
@@ -51,20 +54,29 @@ public:
   ImageDeleter(const ImageDeleter&) = delete;
   ImageDeleter& operator=(const ImageDeleter&) = delete;
 
+  static void trash_move(librados::IoCtx& local_io_ctx,
+                         const std::string& global_image_id, bool resync,
+                         ContextWQ* work_queue, Context* on_finish);
+
   void init(Context* on_finish);
   void shut_down(Context* on_finish);
 
   void schedule_image_delete(const std::string& global_image_id,
                              bool ignore_orphaned,
                              Context *on_finish);
+  void wait_for_deletion(const std::string &global_image_id,
+                         bool scheduled_only, Context* on_finish);
   void wait_for_scheduled_deletion(const std::string &global_image_id,
-                                   Context *ctx,
-                                   bool notify_on_failed_retry=true);
+                                   Context* on_finish) {
+    wait_for_deletion(global_image_id, true, on_finish);
+  }
+
   void cancel_waiter(const std::string &global_image_id);
 
   void print_status(Formatter *f, std::stringstream *ss);
 
   // for testing purposes
+
   std::vector<std::string> get_delete_queue_items();
   std::vector<std::pair<std::string, int> > get_failed_queue_items();
 
@@ -73,26 +85,33 @@ public:
   }
 
 private:
+  struct TrashListener : public image_deleter::TrashListener {
+    ImageDeleter *image_deleter;
+
+    TrashListener(ImageDeleter *image_deleter) : image_deleter(image_deleter) {
+    }
+
+    void handle_trash_image(const std::string& image_id,
+                            const utime_t& deferment_end_time) override {
+      image_deleter->handle_trash_image(image_id, deferment_end_time);
+    }
+  };
 
   struct DeleteInfo {
     std::string global_image_id;
     bool ignore_orphaned = false;
-    Context *on_delete = nullptr;
 
     image_deleter::ErrorResult error_result = {};
     int error_code = 0;
     utime_t retry_time = {};
     int retries = 0;
-    bool notify_on_failed_retry = true;
 
     DeleteInfo(const std::string& global_image_id)
       : global_image_id(global_image_id) {
     }
 
-    DeleteInfo(const std::string& global_image_id,
-               bool ignore_orphaned, Context *on_delete)
-      : global_image_id(global_image_id), ignore_orphaned(ignore_orphaned),
-        on_delete(on_delete) {
+    DeleteInfo(const std::string& global_image_id, bool ignore_orphaned)
+      : global_image_id(global_image_id), ignore_orphaned(ignore_orphaned) {
     }
 
     inline bool operator==(const DeleteInfo& delete_info) const {
@@ -104,19 +123,20 @@ private:
     return os;
     }
 
-    void notify(int r);
     void print_status(Formatter *f, std::stringstream *ss,
                       bool print_failure_info=false);
   };
   typedef std::shared_ptr<DeleteInfo> DeleteInfoRef;
   typedef std::deque<DeleteInfoRef> DeleteQueue;
+  typedef std::map<std::string, Context*> OnDeleteContexts;
 
   librados::IoCtx& m_local_io_ctx;
-  ContextWQ *m_work_queue;
-  SafeTimer *m_timer;
-  Mutex *m_timer_lock;
+  Threads<librbd::ImageCtx>* m_threads;
   ServiceDaemon<librbd::ImageCtx>* m_service_daemon;
 
+  image_deleter::TrashWatcher<ImageCtxT>* m_trash_watcher = nullptr;
+  TrashListener m_trash_listener;
+
   std::atomic<unsigned> m_running { 1 };
 
   double m_busy_interval = 1;
@@ -128,6 +148,8 @@ private:
   DeleteQueue m_retry_delete_queue;
   DeleteQueue m_in_flight_delete_queue;
 
+  OnDeleteContexts m_on_delete_contexts;
+
   AdminSocketHook *m_asok_hook = nullptr;
 
   Context *m_timer_ctx = nullptr;
@@ -148,9 +170,15 @@ private:
   void cancel_retry_timer();
   void handle_retry_timer();
 
+  void handle_trash_image(const std::string& image_id,
+                          const utime_t& deferment_end_time);
+
+  void shut_down_trash_watcher(Context* on_finish);
   void wait_for_ops(Context* on_finish);
   void cancel_all_deletions(Context* on_finish);
 
+  void notify_on_delete(const std::string& global_image_id, int r);
+
 };
 
 } // namespace mirror
index 692dfe617acb3689780c4a9e6c732b63ff9bd188..a8137d44843e3a8cd9ae578b8db13f07d73299e3 100644 (file)
@@ -400,8 +400,7 @@ void ImageReplayer<I>::wait_for_deletion() {
 
   Context *ctx = create_context_callback<
     ImageReplayer, &ImageReplayer<I>::handle_wait_for_deletion>(this);
-  m_image_deleter->wait_for_scheduled_deletion(
-    m_global_image_id, ctx, false);
+  m_image_deleter->wait_for_scheduled_deletion(m_global_image_id, ctx);
 }
 
 template <typename I>
index 8d9ff09e565efbf32101ec0a459fb86d7f7b2305..b6f698331aa82d3d187fb4d2806385942cd62b30 100644 (file)
@@ -26,6 +26,12 @@ struct TrashListener;
 template <typename ImageCtxT = librbd::ImageCtx>
 class TrashWatcher : public librbd::TrashWatcher<ImageCtxT> {
 public:
+  static TrashWatcher* create(librados::IoCtx &io_ctx,
+                              Threads<ImageCtxT> *threads,
+                              TrashListener& trash_listener) {
+    return new TrashWatcher(io_ctx, threads, trash_listener);
+  }
+
   TrashWatcher(librados::IoCtx &io_ctx, Threads<ImageCtxT> *threads,
                TrashListener& trash_listener);
   TrashWatcher(const TrashWatcher&) = delete;