]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: convert op state machines to templates
authorJason Dillaman <dillaman@redhat.com>
Wed, 19 Aug 2015 17:10:57 +0000 (13:10 -0400)
committerJason Dillaman <dillaman@redhat.com>
Wed, 2 Dec 2015 16:11:11 +0000 (11:11 -0500)
Using templates allows the creation of mocked test cases to
verify non-librados expectations.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
26 files changed:
src/librbd/ImageCtx.h
src/librbd/internal.cc
src/librbd/operation/FlattenRequest.cc
src/librbd/operation/FlattenRequest.h
src/librbd/operation/RebuildObjectMapRequest.cc
src/librbd/operation/RebuildObjectMapRequest.h
src/librbd/operation/RenameRequest.cc
src/librbd/operation/RenameRequest.h
src/librbd/operation/Request.cc
src/librbd/operation/Request.h
src/librbd/operation/ResizeRequest.cc
src/librbd/operation/ResizeRequest.h
src/librbd/operation/SnapshotCreateRequest.cc
src/librbd/operation/SnapshotCreateRequest.h
src/librbd/operation/SnapshotProtectRequest.cc
src/librbd/operation/SnapshotProtectRequest.h
src/librbd/operation/SnapshotRemoveRequest.cc
src/librbd/operation/SnapshotRemoveRequest.h
src/librbd/operation/SnapshotRenameRequest.cc
src/librbd/operation/SnapshotRenameRequest.h
src/librbd/operation/SnapshotRollbackRequest.cc
src/librbd/operation/SnapshotRollbackRequest.h
src/librbd/operation/SnapshotUnprotectRequest.cc
src/librbd/operation/SnapshotUnprotectRequest.h
src/librbd/operation/TrimRequest.cc
src/librbd/operation/TrimRequest.h

index fdebf8943eb6b34a5e9fb50bdee7d4a72186eade..4e00fe5a4596979f88cfb4533c94f1cbf887d94d 100644 (file)
@@ -49,7 +49,7 @@ namespace librbd {
   class AioCompletion;
 
   namespace operation {
-  class ResizeRequest;
+  template <typename> class ResizeRequest;
   }
 
   struct ImageCtx {
@@ -140,7 +140,7 @@ namespace librbd {
 
     atomic_t async_request_seq;
 
-    xlist<operation::ResizeRequest*> resize_reqs;
+    xlist<operation::ResizeRequest<ImageCtx>*> resize_reqs;
 
     AioImageRequestWQ *aio_work_queue;
     xlist<AioCompletion*> completed_reqs;
index 260effcb2c5aeb525e19a2a9e3b05cf3190c0cbe..1c7617459b54f81f1923b3ae9ce3bdf958b89da5 100644 (file)
@@ -332,7 +332,7 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
 
     C_SaferCond ctx;
     ictx->snap_lock.get_read();
-    operation::TrimRequest *req = new operation::TrimRequest(
+    operation::TrimRequest<> *req = new operation::TrimRequest<>(
       *ictx, &ctx, ictx->size, newsize, prog_ctx);
     ictx->snap_lock.put_read();
     req->send();
@@ -732,8 +732,8 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       return;
     }
 
-    operation::SnapshotCreateRequest *req =
-      new operation::SnapshotCreateRequest(*ictx, ctx, snap_name);
+    operation::SnapshotCreateRequest<> *req =
+      new operation::SnapshotCreateRequest<>(*ictx, ctx, snap_name);
     req->send();
   }
 
@@ -825,8 +825,8 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       }
     }
 
-    operation::SnapshotRemoveRequest *req =
-      new operation::SnapshotRemoveRequest(*ictx, ctx, snap_name, snap_id);
+    operation::SnapshotRemoveRequest<> *req =
+      new operation::SnapshotRemoveRequest<>(*ictx, ctx, snap_name, snap_id);
     req->send();
   }
 
@@ -896,8 +896,8 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       return;
     }
 
-    operation::SnapshotRenameRequest *req =
-      new operation::SnapshotRenameRequest(*ictx, ctx, src_snap_id, dst_name);
+    operation::SnapshotRenameRequest<> *req =
+      new operation::SnapshotRenameRequest<>(*ictx, ctx, src_snap_id, dst_name);
     req->send();
   }
 
@@ -969,8 +969,8 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       return;
     }
 
-    operation::SnapshotProtectRequest *request =
-      new operation::SnapshotProtectRequest(*ictx, ctx, snap_name);
+    operation::SnapshotProtectRequest<> *request =
+      new operation::SnapshotProtectRequest<>(*ictx, ctx, snap_name);
     request->send();
   }
 
@@ -1044,8 +1044,8 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       return;
     }
 
-    operation::SnapshotUnprotectRequest *request =
-      new operation::SnapshotUnprotectRequest(*ictx, ctx, snap_name);
+    operation::SnapshotUnprotectRequest<> *request =
+      new operation::SnapshotUnprotectRequest<>(*ictx, ctx, snap_name);
     request->send();
   }
 
@@ -1635,8 +1635,8 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       return;
     }
 
-    operation::RenameRequest *req =
-      new operation::RenameRequest(*ictx, ctx, dstname);
+    operation::RenameRequest<> *req =
+      new operation::RenameRequest<>(*ictx, ctx, dstname);
     req->send();
   }
 
@@ -2197,7 +2197,7 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       }
     }
 
-    operation::ResizeRequest *req = new operation::ResizeRequest(
+    operation::ResizeRequest<> *req = new operation::ResizeRequest<>(
       *ictx, ctx, size, prog_ctx);
     req->send();
   }
@@ -2563,9 +2563,9 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
 
     // TODO need to wait for journal replay to complete (if enabled)
     C_SaferCond cond_ctx;
-    operation::SnapshotRollbackRequest *request =
-      new operation::SnapshotRollbackRequest(*ictx, &cond_ctx, snap_name,
-                                             snap_id, new_size, prog_ctx);
+    operation::SnapshotRollbackRequest<> *request =
+      new operation::SnapshotRollbackRequest<>(*ictx, &cond_ctx, snap_name,
+                                               snap_id, new_size, prog_ctx);
     request->send();
     r = cond_ctx.wait();
     if (r < 0) {
@@ -3061,7 +3061,7 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       overlap_objects = Striper::get_num_objects(ictx->layout, overlap);
     }
 
-    operation::FlattenRequest *req = new operation::FlattenRequest(
+    operation::FlattenRequest<> *req = new operation::FlattenRequest<>(
       *ictx, ctx, object_size, overlap_objects, snapc, prog_ctx);
     req->send();
   }
@@ -3114,8 +3114,8 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
       return;
     }
 
-    operation::RebuildObjectMapRequest *req =
-      new operation::RebuildObjectMapRequest(*ictx, ctx, prog_ctx);
+    operation::RebuildObjectMapRequest<> *req =
+      new operation::RebuildObjectMapRequest<>(*ictx, ctx, prog_ctx);
     req->send();
   }
 
index 2a08e4562dc2717a3346fad0d932f13aff538751..4b089b4c806dee3fe4e4e71bf492265999cf1e8d 100644 (file)
 namespace librbd {
 namespace operation {
 
-class C_FlattenObject : public C_AsyncObjectThrottle<> {
+template <typename I>
+class C_FlattenObject : public C_AsyncObjectThrottle<I> {
 public:
-  C_FlattenObject(AsyncObjectThrottle<> &throttle, ImageCtx *image_ctx,
+  C_FlattenObject(AsyncObjectThrottle<I> &throttle, I *image_ctx,
                   uint64_t object_size, ::SnapContext snapc, uint64_t object_no)
-    : C_AsyncObjectThrottle(throttle, *image_ctx), m_object_size(object_size),
+    : C_AsyncObjectThrottle<I>(throttle, *image_ctx), m_object_size(object_size),
       m_snapc(snapc), m_object_no(object_no)
   {
   }
 
   virtual int send() {
-    assert(m_image_ctx.owner_lock.is_locked());
-    CephContext *cct = m_image_ctx.cct;
+    I &image_ctx = this->m_image_ctx;
+    assert(image_ctx.owner_lock.is_locked());
+    CephContext *cct = image_ctx.cct;
 
-    if (m_image_ctx.image_watcher->is_lock_supported() &&
-        !m_image_ctx.image_watcher->is_lock_owner()) {
+    if (image_ctx.image_watcher->is_lock_supported() &&
+        !image_ctx.image_watcher->is_lock_owner()) {
       ldout(cct, 1) << "lost exclusive lock during flatten" << dendl;
       return -ERESTART;
     }
 
     bufferlist bl;
-    string oid = m_image_ctx.get_object_name(m_object_no);
-    AioObjectWrite *req = new AioObjectWrite(&m_image_ctx, oid, m_object_no, 0,
+    string oid = image_ctx.get_object_name(m_object_no);
+    AioObjectWrite *req = new AioObjectWrite(&image_ctx, oid, m_object_no, 0,
                                              bl, m_snapc, this);
     if (!req->has_parent()) {
       // stop early if the parent went away - it just means
@@ -59,15 +61,17 @@ private:
   uint64_t m_object_no;
 };
 
-bool FlattenRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool FlattenRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " should_complete: " << " r=" << r << dendl;
   if (r < 0 && !(r == -ENOENT && m_ignore_enoent) ) {
     lderr(cct) << "flatten encountered an error: " << cpp_strerror(r) << dendl;
     return true;
   }
 
-  RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
+  RWLock::RLocker owner_locker(image_ctx.owner_lock);
   switch (m_state) {
   case STATE_FLATTEN_OBJECTS:
     ldout(cct, 5) << "FLATTEN_OBJECTS" << dendl;
@@ -89,74 +93,80 @@ bool FlattenRequest::should_complete(int r) {
   return false;
 }
 
-void FlattenRequest::send_op() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+void FlattenRequest<I>::send_op() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " send" << dendl;
 
   m_state = STATE_FLATTEN_OBJECTS;
-  AsyncObjectThrottle<>::ContextFactory context_factory(
-    boost::lambda::bind(boost::lambda::new_ptr<C_FlattenObject>(),
-      boost::lambda::_1, &m_image_ctx, m_object_size, m_snapc,
+  typename AsyncObjectThrottle<I>::ContextFactory context_factory(
+    boost::lambda::bind(boost::lambda::new_ptr<C_FlattenObject<I> >(),
+      boost::lambda::_1, &image_ctx, m_object_size, m_snapc,
       boost::lambda::_2));
-  AsyncObjectThrottle<> *throttle = new AsyncObjectThrottle<>(
-    this, m_image_ctx, context_factory, create_callback_context(), &m_prog_ctx,
+  AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
+    this, image_ctx, context_factory, this->create_callback_context(), &m_prog_ctx,
     0, m_overlap_objects);
-  throttle->start_ops(m_image_ctx.concurrent_management_ops);
+  throttle->start_ops(image_ctx.concurrent_management_ops);
 }
 
-bool FlattenRequest::send_update_header() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool FlattenRequest<I>::send_update_header() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  CephContext *cct = image_ctx.cct;
 
   ldout(cct, 5) << this << " send_update_header" << dendl;
   m_state = STATE_UPDATE_HEADER;
 
   // should have been canceled prior to releasing lock
-  assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-         m_image_ctx.image_watcher->is_lock_owner());
+  assert(!image_ctx.image_watcher->is_lock_supported() ||
+         image_ctx.image_watcher->is_lock_owner());
 
   {
-    RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
+    RWLock::RLocker parent_locker(image_ctx.parent_lock);
     // stop early if the parent went away - it just means
     // another flatten finished first, so this one is useless.
-    if (!m_image_ctx.parent) {
+    if (!image_ctx.parent) {
       ldout(cct, 5) << "image already flattened" << dendl;
       return true;
     }
-    m_parent_spec = m_image_ctx.parent_md.spec;
+    m_parent_spec = image_ctx.parent_md.spec;
   }
   m_ignore_enoent = true;
 
   // remove parent from this (base) image
   librados::ObjectWriteOperation op;
-  if (m_image_ctx.image_watcher->is_lock_supported()) {
-    m_image_ctx.image_watcher->assert_header_locked(&op);
+  if (image_ctx.image_watcher->is_lock_supported()) {
+    image_ctx.image_watcher->assert_header_locked(&op);
   }
   cls_client::remove_parent(&op);
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
+  librados::AioCompletion *rados_completion = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid,
                                         rados_completion, &op);
   assert(r == 0);
   rados_completion->release();
   return false;
 }
 
-bool FlattenRequest::send_update_children() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool FlattenRequest<I>::send_update_children() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  CephContext *cct = image_ctx.cct;
 
   // should have been canceled prior to releasing lock
-  assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-         m_image_ctx.image_watcher->is_lock_owner());
+  assert(!image_ctx.image_watcher->is_lock_supported() ||
+         image_ctx.image_watcher->is_lock_owner());
 
   // if there are no snaps, remove from the children object as well
   // (if snapshots remain, they have their own parent info, and the child
   // will be removed when the last snap goes away)
-  RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-  if ((m_image_ctx.features & RBD_FEATURE_DEEP_FLATTEN) == 0 &&
-      !m_image_ctx.snaps.empty()) {
+  RWLock::RLocker snap_locker(image_ctx.snap_lock);
+  if ((image_ctx.features & RBD_FEATURE_DEEP_FLATTEN) == 0 &&
+      !image_ctx.snaps.empty()) {
     return true;
   }
 
@@ -164,10 +174,10 @@ bool FlattenRequest::send_update_children() {
   m_state = STATE_UPDATE_CHILDREN;
 
   librados::ObjectWriteOperation op;
-  cls_client::remove_child(&op, m_parent_spec, m_image_ctx.id);
+  cls_client::remove_child(&op, m_parent_spec, image_ctx.id);
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(RBD_CHILDREN, rados_completion,
+  librados::AioCompletion *rados_completion = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(RBD_CHILDREN, rados_completion,
                                     &op);
   assert(r == 0);
   rados_completion->release();
@@ -176,3 +186,5 @@ bool FlattenRequest::send_update_children() {
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::FlattenRequest<librbd::ImageCtx>;
index 7a2b86e35df6b098f65403495cae5eff6d70fb12..693b051e14cf8f05bf342ad7cf503139176c2f9d 100644 (file)
@@ -14,13 +14,14 @@ class ProgressContext;
 
 namespace operation {
 
-class FlattenRequest : public Request
+template <typename ImageCtxT = ImageCtx>
+class FlattenRequest : public Request<ImageCtxT>
 {
 public:
-  FlattenRequest(ImageCtx &image_ctx, Context *on_finish,
-                     uint64_t object_size, uint64_t overlap_objects,
-                     const ::SnapContext &snapc, ProgressContext &prog_ctx)
-    : Request(image_ctx, on_finish), m_object_size(object_size),
+  FlattenRequest(ImageCtxT &image_ctx, Context *on_finish,
+                uint64_t object_size, uint64_t overlap_objects,
+                const ::SnapContext &snapc, ProgressContext &prog_ctx)
+    : Request<ImageCtxT>(image_ctx, on_finish), m_object_size(object_size),
       m_overlap_objects(overlap_objects), m_snapc(snapc), m_prog_ctx(prog_ctx),
       m_ignore_enoent(false)
   {
@@ -84,4 +85,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::FlattenRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_FLATTEN_REQUEST_H
index 803083c848c5cc2ad7e4ee004ce4b254395f4e28..2ed0cbecf9f5d00ae161e5dcbe5798b95661f844 100644 (file)
@@ -23,22 +23,25 @@ namespace operation {
 
 namespace {
 
-class C_VerifyObject : public C_AsyncObjectThrottle<> {
+template <typename I>
+class C_VerifyObject : public C_AsyncObjectThrottle<I> {
 public:
-  C_VerifyObject(AsyncObjectThrottle<> &throttle, ImageCtx *image_ctx,
+  C_VerifyObject(AsyncObjectThrottle<I> &throttle, I *image_ctx,
                  uint64_t snap_id, uint64_t object_no)
-    : C_AsyncObjectThrottle(throttle, *image_ctx), m_snap_id(snap_id),
-      m_object_no(object_no), m_oid(m_image_ctx.get_object_name(m_object_no))
+    : C_AsyncObjectThrottle<I>(throttle, *image_ctx), m_snap_id(snap_id),
+      m_object_no(object_no),
+      m_oid(image_ctx->get_object_name(m_object_no))
   {
-    m_io_ctx.dup(m_image_ctx.md_ctx);
+    m_io_ctx.dup(image_ctx->md_ctx);
     m_io_ctx.snap_set_read(CEPH_SNAPDIR);
   }
 
   virtual void complete(int r) {
+    I &image_ctx = this->m_image_ctx;
     if (should_complete(r)) {
-      ldout(m_image_ctx.cct, 20) << m_oid << " C_VerifyObject completed "
+      ldout(image_ctx.cct, 20) << m_oid << " C_VerifyObject completed "
                                  << dendl;
-      finish(r);
+      this->finish(r);
       delete this;
     }
   }
@@ -58,7 +61,8 @@ private:
   int m_snap_list_ret;
 
   bool should_complete(int r) {
-    CephContext *cct = m_image_ctx.cct;
+    I &image_ctx = this->m_image_ctx;
+    CephContext *cct = image_ctx.cct;
     if (r == 0) {
       r = m_snap_list_ret;
     }
@@ -74,9 +78,10 @@ private:
   }
 
   void send_list_snaps() {
-    assert(m_image_ctx.owner_lock.is_locked());
-    ldout(m_image_ctx.cct, 5) << m_oid << " C_VerifyObject::send_list_snaps"
-                              << dendl;
+    I &image_ctx = this->m_image_ctx;
+    assert(image_ctx.owner_lock.is_locked());
+    ldout(image_ctx.cct, 5) << m_oid << " C_VerifyObject::send_list_snaps"
+                            << dendl;
 
     librados::AioCompletion *comp = librados::Rados::aio_create_completion(
       this, NULL, rados_ctx_cb);
@@ -90,7 +95,8 @@ private:
   }
 
   uint8_t get_object_state() {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+    I &image_ctx = this->m_image_ctx;
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
     for (std::vector<librados::clone_info_t>::const_iterator r =
            m_snap_set.clones.begin(); r != m_snap_set.clones.end(); ++r) {
       librados::snap_t from_snap_id;
@@ -109,7 +115,7 @@ private:
         break;
       }
 
-      if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0 &&
+      if ((image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0 &&
           from_snap_id != m_snap_id) {
         return OBJECT_EXISTS_CLEAN;
       }
@@ -119,26 +125,28 @@ private:
   }
 
   uint64_t next_valid_snap_id(uint64_t snap_id) {
-    assert(m_image_ctx.snap_lock.is_locked());
+    I &image_ctx = this->m_image_ctx;
+    assert(image_ctx.snap_lock.is_locked());
 
     std::map<librados::snap_t, SnapInfo>::iterator it =
-      m_image_ctx.snap_info.lower_bound(snap_id);
-    if (it == m_image_ctx.snap_info.end()) {
+      image_ctx.snap_info.lower_bound(snap_id);
+    if (it == image_ctx.snap_info.end()) {
       return CEPH_NOSNAP;
     }
     return it->first;
   }
 
   bool update_object_map(uint8_t new_state) {
-    RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
-    CephContext *cct = m_image_ctx.cct;
+    I &image_ctx = this->m_image_ctx;
+    RWLock::RLocker owner_locker(image_ctx.owner_lock);
+    CephContext *cct = image_ctx.cct;
 
     // should have been canceled prior to releasing lock
-    assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-           m_image_ctx.image_watcher->is_lock_owner());
+    assert(!image_ctx.image_watcher->is_lock_supported() ||
+           image_ctx.image_watcher->is_lock_owner());
 
-    RWLock::WLocker l(m_image_ctx.object_map_lock);
-    uint8_t state = m_image_ctx.object_map[m_object_no];
+    RWLock::WLocker l(image_ctx.object_map_lock);
+    uint8_t state = image_ctx.object_map[m_object_no];
     if (state == OBJECT_EXISTS && new_state == OBJECT_NONEXISTENT &&
         m_snap_id == CEPH_NOSNAP) {
       // might be writing object to OSD concurrently
@@ -149,7 +157,7 @@ private:
       ldout(cct, 15) << m_oid << " C_VerifyObject::update_object_map "
                      << static_cast<uint32_t>(state) << "->"
                      << static_cast<uint32_t>(new_state) << dendl;
-      m_image_ctx.object_map[m_object_no] = new_state;
+      image_ctx.object_map[m_object_no] = new_state;
     }
     return true;
   }
@@ -157,12 +165,13 @@ private:
 
 } // anonymous namespace
 
-
-void RebuildObjectMapRequest::send() {
+template <typename I>
+void RebuildObjectMapRequest<I>::send() {
   send_resize_object_map();
 }
 
-bool RebuildObjectMapRequest::should_complete(int r) {
+template <typename I>
+bool RebuildObjectMapRequest<I>::should_complete(int r) {
   CephContext *cct = m_image_ctx.cct;
   ldout(cct, 5) << this << " should_complete: " << " r=" << r << dendl;
 
@@ -220,7 +229,8 @@ bool RebuildObjectMapRequest::should_complete(int r) {
   return false;
 }
 
-void RebuildObjectMapRequest::send_resize_object_map() {
+template <typename I>
+void RebuildObjectMapRequest<I>::send_resize_object_map() {
   assert(m_image_ctx.owner_lock.is_locked());
   CephContext *cct = m_image_ctx.cct;
 
@@ -244,10 +254,11 @@ void RebuildObjectMapRequest::send_resize_object_map() {
   assert(!m_image_ctx.image_watcher->is_lock_supported() ||
          m_image_ctx.image_watcher->is_lock_owner());
   m_image_ctx.object_map.aio_resize(size, OBJECT_NONEXISTENT,
-                                    create_callback_context());
+                                    this->create_callback_context());
 }
 
-void RebuildObjectMapRequest::send_trim_image() {
+template <typename I>
+void RebuildObjectMapRequest<I>::send_trim_image() {
   CephContext *cct = m_image_ctx.cct;
 
   RWLock::RLocker l(m_image_ctx.owner_lock);
@@ -266,12 +277,14 @@ void RebuildObjectMapRequest::send_trim_image() {
     orig_size = m_image_ctx.get_object_size() *
                 m_image_ctx.object_map.size();
   }
-  TrimRequest *req = new TrimRequest(m_image_ctx, create_callback_context(),
-                                     orig_size, new_size, m_prog_ctx);
+  TrimRequest<I> *req = new TrimRequest<I>(m_image_ctx,
+                                           this->create_callback_context(),
+                                           orig_size, new_size, m_prog_ctx);
   req->send();
 }
 
-void RebuildObjectMapRequest::send_verify_objects() {
+template <typename I>
+void RebuildObjectMapRequest<I>::send_verify_objects() {
   assert(m_image_ctx.owner_lock.is_locked());
   CephContext *cct = m_image_ctx.cct;
 
@@ -292,16 +305,17 @@ void RebuildObjectMapRequest::send_verify_objects() {
   m_state = STATE_VERIFY_OBJECTS;
   ldout(cct, 5) << this << " send_verify_objects" << dendl;
 
-  AsyncObjectThrottle<>::ContextFactory context_factory(
-    boost::lambda::bind(boost::lambda::new_ptr<C_VerifyObject>(),
+  typename AsyncObjectThrottle<I>::ContextFactory context_factory(
+    boost::lambda::bind(boost::lambda::new_ptr<C_VerifyObject<I> >(),
       boost::lambda::_1, &m_image_ctx, snap_id, boost::lambda::_2));
-  AsyncObjectThrottle<> *throttle = new AsyncObjectThrottle<>(
-    this, m_image_ctx, context_factory, create_callback_context(), &m_prog_ctx,
-    0, num_objects);
+  AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
+    this, m_image_ctx, context_factory, this->create_callback_context(),
+    &m_prog_ctx, 0, num_objects);
   throttle->start_ops(cct->_conf->rbd_concurrent_management_ops);
 }
 
-void RebuildObjectMapRequest::send_save_object_map() {
+template <typename I>
+void RebuildObjectMapRequest<I>::send_save_object_map() {
   assert(m_image_ctx.owner_lock.is_locked());
   CephContext *cct = m_image_ctx.cct;
 
@@ -311,10 +325,11 @@ void RebuildObjectMapRequest::send_save_object_map() {
   // should have been canceled prior to releasing lock
   assert(!m_image_ctx.image_watcher->is_lock_supported() ||
          m_image_ctx.image_watcher->is_lock_owner());
-  m_image_ctx.object_map.aio_save(create_callback_context());
+  m_image_ctx.object_map.aio_save(this->create_callback_context());
 }
 
-void RebuildObjectMapRequest::send_update_header() {
+template <typename I>
+void RebuildObjectMapRequest<I>::send_update_header() {
   assert(m_image_ctx.owner_lock.is_locked());
 
   // should have been canceled prior to releasing lock
@@ -332,7 +347,7 @@ void RebuildObjectMapRequest::send_update_header() {
   uint64_t flags = RBD_FLAG_OBJECT_MAP_INVALID | RBD_FLAG_FAST_DIFF_INVALID;
   cls_client::set_flags(&op, m_image_ctx.snap_id, 0, flags);
 
-  librados::AioCompletion *comp = create_callback_completion();
+  librados::AioCompletion *comp = this->create_callback_completion();
   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op);
   assert(r == 0);
   comp->release();
@@ -341,7 +356,8 @@ void RebuildObjectMapRequest::send_update_header() {
   m_image_ctx.update_flags(m_image_ctx.snap_id, flags, false);
 }
 
-uint64_t RebuildObjectMapRequest::get_image_size() const {
+template <typename I>
+uint64_t RebuildObjectMapRequest<I>::get_image_size() const {
   assert(m_image_ctx.snap_lock.is_locked());
   if (m_image_ctx.snap_id == CEPH_NOSNAP) {
     if (!m_image_ctx.resize_reqs.empty()) {
@@ -355,3 +371,5 @@ uint64_t RebuildObjectMapRequest::get_image_size() const {
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::RebuildObjectMapRequest<librbd::ImageCtx>;
index 3ed49ba5d7f63a79c1ac550bcea2325500972b6d..28361872ce331aef06f5fe9ccdf4705303e2275d 100644 (file)
@@ -13,12 +13,13 @@ class ProgressContext;
 
 namespace operation {
 
-class RebuildObjectMapRequest : public AsyncRequest<> {
+template <typename ImageCtxT = ImageCtx>
+class RebuildObjectMapRequest : public AsyncRequest<ImageCtxT> {
 public:
 
-  RebuildObjectMapRequest(ImageCtx &image_ctx, Context *on_finish,
+  RebuildObjectMapRequest(ImageCtxT &image_ctx, Context *on_finish,
                           ProgressContext &prog_ctx)
-    : AsyncRequest(image_ctx, on_finish), m_image_ctx(image_ctx),
+    : AsyncRequest<ImageCtxT>(image_ctx, on_finish), m_image_ctx(image_ctx),
       m_prog_ctx(prog_ctx), m_attempted_trim(false)
   {
   }
@@ -60,7 +61,7 @@ private:
     STATE_UPDATE_HEADER
   };
 
-  ImageCtx &m_image_ctx;
+  ImageCtxT &m_image_ctx;
   ProgressContext &m_prog_ctx;
   State m_state;
   bool m_attempted_trim;
@@ -78,4 +79,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::RebuildObjectMapRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_REBUILD_OBJECT_MAP_REQUEST_H
index 1a9c82da7bd1eb624b8c836937037868adbbf620..316229c66c7dc11df031726fbca45fbaa9a4bcbb 100644 (file)
@@ -17,19 +17,20 @@ namespace operation {
 
 namespace {
 
+template <typename I>
 std::ostream& operator<<(std::ostream& os,
-                         const RenameRequest::State& state) {
+                         const typename RenameRequest<I>::State& state) {
   switch(state) {
-  case RenameRequest::STATE_READ_SOURCE_HEADER:
+  case RenameRequest<I>::STATE_READ_SOURCE_HEADER:
     os << "READ_SOURCE_HEADER";
     break;
-  case RenameRequest::STATE_WRITE_DEST_HEADER:
+  case RenameRequest<I>::STATE_WRITE_DEST_HEADER:
     os << "WRITE_DEST_HEADER";
     break;
-  case RenameRequest::STATE_UPDATE_DIRECTORY:
+  case RenameRequest<I>::STATE_UPDATE_DIRECTORY:
     os << "UPDATE_DIRECTORY";
     break;
-  case RenameRequest::STATE_REMOVE_SOURCE_HEADER:
+  case RenameRequest<I>::STATE_REMOVE_SOURCE_HEADER:
     os << "REMOVE_SOURCE_HEADER";
     break;
   default:
@@ -41,21 +42,25 @@ std::ostream& operator<<(std::ostream& os,
 
 } // anonymous namespace
 
-RenameRequest::RenameRequest(ImageCtx &image_ctx, Context *on_finish,
-                             const std::string &dest_name)
-  : Request(image_ctx, on_finish), m_dest_name(dest_name),
+template <typename I>
+RenameRequest<I>::RenameRequest(I &image_ctx, Context *on_finish,
+                               const std::string &dest_name)
+  : Request<I>(image_ctx, on_finish), m_dest_name(dest_name),
     m_source_oid(image_ctx.old_format ? old_header_name(image_ctx.name) :
                                         id_obj_name(image_ctx.name)),
     m_dest_oid(image_ctx.old_format ? old_header_name(dest_name) :
                                       id_obj_name(dest_name)) {
 }
 
-void RenameRequest::send_op() {
+template <typename I>
+void RenameRequest<I>::send_op() {
   send_read_source_header();
 }
 
-bool RenameRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool RenameRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
                 << "r=" << r << dendl;
   r = filter_state_return_code(r);
@@ -64,7 +69,7 @@ bool RenameRequest::should_complete(int r) {
     return true;
   }
 
-  RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+  RWLock::RLocker owner_lock(image_ctx.owner_lock);
   bool finished = false;
   switch (m_state) {
   case STATE_READ_SOURCE_HEADER:
@@ -86,8 +91,10 @@ bool RenameRequest::should_complete(int r) {
   return finished;
 }
 
-int RenameRequest::filter_state_return_code(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+int RenameRequest<I>::filter_state_return_code(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
 
   if (m_state == STATE_REMOVE_SOURCE_HEADER && r < 0) {
     if (r != -ENOENT) {
@@ -99,8 +106,10 @@ int RenameRequest::filter_state_return_code(int r) {
   return r;
 }
 
-void RenameRequest::send_read_source_header() {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+void RenameRequest<I>::send_read_source_header() {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_READ_SOURCE_HEADER;
 
@@ -109,15 +118,17 @@ void RenameRequest::send_read_source_header() {
 
   // TODO: old code read omap values but there are no omap values on the
   //       old format header nor the new format id object
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_source_oid, rados_completion, &op,
-                                         &m_header_bl);
+  librados::AioCompletion *rados_completion = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(m_source_oid, rados_completion, &op,
+                                       &m_header_bl);
   assert(r == 0);
   rados_completion->release();
 }
 
-void RenameRequest::send_write_destination_header() {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+void RenameRequest<I>::send_write_destination_header() {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_WRITE_DEST_HEADER;
 
@@ -125,51 +136,57 @@ void RenameRequest::send_write_destination_header() {
   op.create(true);
   op.write_full(m_header_bl);
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_dest_oid, rados_completion, &op);
+  librados::AioCompletion *rados_completion = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(m_dest_oid, rados_completion, &op);
   assert(r == 0);
   rados_completion->release();
 }
 
-void RenameRequest::send_update_directory() {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+void RenameRequest<I>::send_update_directory() {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_UPDATE_DIRECTORY;
 
   librados::ObjectWriteOperation op;
-  if (m_image_ctx.old_format) {
+  if (image_ctx.old_format) {
     bufferlist cmd_bl;
     bufferlist empty_bl;
     ::encode(static_cast<__u8>(CEPH_OSD_TMAP_SET), cmd_bl);
     ::encode(m_dest_name, cmd_bl);
     ::encode(empty_bl, cmd_bl);
     ::encode(static_cast<__u8>(CEPH_OSD_TMAP_RM), cmd_bl);
-    ::encode(m_image_ctx.name, cmd_bl);
+    ::encode(image_ctx.name, cmd_bl);
     op.tmap_update(cmd_bl);
   } else {
-    cls_client::dir_rename_image(&op, m_image_ctx.name, m_dest_name,
-                                 m_image_ctx.id);
+    cls_client::dir_rename_image(&op, image_ctx.name, m_dest_name,
+                                 image_ctx.id);
   }
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(RBD_DIRECTORY, rados_completion, &op);
+  librados::AioCompletion *rados_completion = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(RBD_DIRECTORY, rados_completion, &op);
   assert(r == 0);
   rados_completion->release();
 }
 
-void RenameRequest::send_remove_source_header() {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+void RenameRequest<I>::send_remove_source_header() {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_REMOVE_SOURCE_HEADER;
 
   librados::ObjectWriteOperation op;
   op.remove();
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_source_oid, rados_completion, &op);
+  librados::AioCompletion *rados_completion = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(m_source_oid, rados_completion, &op);
   assert(r == 0);
   rados_completion->release();
 }
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::RenameRequest<librbd::ImageCtx>;
index ab7a87b8c168e86f2529af820f41a4fc7f616e1c..e67f75c241492991988ae0a28c8f2633261bdaca 100644 (file)
@@ -16,7 +16,8 @@ class ImageCtx;
 
 namespace operation {
 
-class RenameRequest : public Request
+template <typename ImageCtxT = ImageCtx>
+class RenameRequest : public Request<ImageCtxT>
 {
 public:
   /**
@@ -51,7 +52,7 @@ public:
     STATE_REMOVE_SOURCE_HEADER
   };
 
-  RenameRequest(ImageCtx &image_ctx, Context *on_finish,
+  RenameRequest(ImageCtxT &image_ctx, Context *on_finish,
                 const std::string &dest_name);
 
 protected:
@@ -84,4 +85,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::RenameRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_RENAME_REQUEST_H
index a1fe76003cf221536e1ed95ff9a04ae3e4a1319b..ce036842d753ec4dde9c14de818893da179416e6 100644 (file)
@@ -8,50 +8,59 @@
 namespace librbd {
 namespace operation {
 
-Request::Request(ImageCtx &image_ctx, Context *on_finish)
-  : AsyncRequest(image_ctx, on_finish), m_tid(0) {
+template <typename I>
+Request<I>::Request(I &image_ctx, Context *on_finish)
+  : AsyncRequest<I>(image_ctx, on_finish), m_tid(0) {
 }
 
-void Request::send() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void Request<I>::send() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    if (m_image_ctx.journal != NULL &&
-        !m_image_ctx.journal->is_journal_replaying()) {
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    if (image_ctx.journal != NULL &&
+        !image_ctx.journal->is_journal_replaying()) {
       // journal might be replaying -- wait for it to complete
-      if (!m_image_ctx.journal->is_journal_ready()) {
-        m_image_ctx.journal->wait_for_journal_ready(
+      if (!image_ctx.journal->is_journal_ready()) {
+        image_ctx.journal->wait_for_journal_ready(
           new C_WaitForJournalReady(this));
         return;
       }
 
       journal::EventEntry event_entry(create_event());
-      m_tid = m_image_ctx.journal->append_op_event(event_entry);
+      m_tid = image_ctx.journal->append_op_event(event_entry);
     }
   }
 
   send_op();
 }
 
-void Request::finish(int r) {
-  AsyncRequest::finish(r);
+template <typename I>
+void Request<I>::finish(int r) {
+  AsyncRequest<I>::finish(r);
 
-  RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+  I &image_ctx = this->m_image_ctx;
+  RWLock::RLocker snap_locker(image_ctx.snap_lock);
   if (m_tid != 0 &&
-      m_image_ctx.journal != NULL &&
-      !m_image_ctx.journal->is_journal_replaying()) {
+      image_ctx.journal != NULL &&
+      !image_ctx.journal->is_journal_replaying()) {
     // ops will be canceled / completed before closing journal
-    assert(m_image_ctx.journal->is_journal_ready());
+    assert(image_ctx.journal->is_journal_ready());
 
-    m_image_ctx.journal->commit_op_event(m_tid, r);
+    image_ctx.journal->commit_op_event(m_tid, r);
   }
 }
 
-void Request::handle_journal_ready() {
-  RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
+template <typename I>
+void Request<I>::handle_journal_ready() {
+  I &image_ctx = this->m_image_ctx;
+  RWLock::RLocker owner_locker(image_ctx.owner_lock);
   send();
 }
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::Request<librbd::ImageCtx>;
index 705c4115d8ef1327dad181f315de84ef64eebac2..c0dd3cbbcadb308ee5db1e19869ca7d93855ac4e 100644 (file)
@@ -9,11 +9,15 @@
 #include "librbd/JournalTypes.h"
 
 namespace librbd {
+
+class ImageCtx;
+
 namespace operation {
 
-class Request : public AsyncRequest<> {
+template <typename ImageCtxT = ImageCtx>
+class Request : public AsyncRequest<ImageCtxT> {
 public:
-  Request(ImageCtx &image_ctx, Context *on_finish);
+  Request(ImageCtxT &image_ctx, Context *on_finish);
 
   virtual void send();
 
@@ -43,4 +47,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::Request<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_REQUEST_H
index cb5699f5a35c7a2d6bc56483023139557e5fba16..282572e967eec6b2aa0b7b3c30e8a27a84500310 100644 (file)
 namespace librbd {
 namespace operation {
 
-ResizeRequest::ResizeRequest(ImageCtx &image_ctx, Context *on_finish,
-                                       uint64_t new_size,
-                                       ProgressContext &prog_ctx)
-  : Request(image_ctx, on_finish),
-    m_original_size(0), m_new_size(new_size),
-    m_prog_ctx(prog_ctx), m_new_parent_overlap(0),
-    m_xlist_item(this)
+template <typename I>
+ResizeRequest<I>::ResizeRequest(I &image_ctx, Context *on_finish,
+                                uint64_t new_size, ProgressContext &prog_ctx)
+  : Request<I>(image_ctx, on_finish),
+    m_original_size(0), m_new_size(new_size), m_prog_ctx(prog_ctx),
+    m_new_parent_overlap(0), m_xlist_item(this)
 {
 }
 
-ResizeRequest::~ResizeRequest() {
+template <typename I>
+ResizeRequest<I>::~ResizeRequest() {
+  I &image_ctx = this->m_image_ctx;
   ResizeRequest *next_req = NULL;
   {
-    RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+    RWLock::WLocker snap_locker(image_ctx.snap_lock);
     assert(m_xlist_item.remove_myself());
-    if (!m_image_ctx.resize_reqs.empty()) {
-      next_req = m_image_ctx.resize_reqs.front();
+    if (!image_ctx.resize_reqs.empty()) {
+      next_req = image_ctx.resize_reqs.front();
     }
   }
 
   if (next_req != NULL) {
-    RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
+    RWLock::RLocker owner_locker(image_ctx.owner_lock);
     next_req->send();
   }
 }
 
-bool ResizeRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool ResizeRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " should_complete: " << " r=" << r << dendl;
 
   if (r < 0) {
@@ -56,7 +59,7 @@ bool ResizeRequest::should_complete(int r) {
     return true;
   }
 
-  RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+  RWLock::RLocker owner_lock(image_ctx.owner_lock);
   switch (m_state) {
   case STATE_FLUSH:
     ldout(cct, 5) << "FLUSH" << dendl;
@@ -99,37 +102,41 @@ bool ResizeRequest::should_complete(int r) {
   return false;
 }
 
-void ResizeRequest::send() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void ResizeRequest<I>::send() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
   {
-    RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+    RWLock::WLocker snap_locker(image_ctx.snap_lock);
     if (!m_xlist_item.is_on_list()) {
-      m_image_ctx.resize_reqs.push_back(&m_xlist_item);
-      if (m_image_ctx.resize_reqs.front() != this) {
+      image_ctx.resize_reqs.push_back(&m_xlist_item);
+      if (image_ctx.resize_reqs.front() != this) {
         return;
       }
     }
 
-    assert(m_image_ctx.resize_reqs.front() == this);
-    m_original_size = m_image_ctx.size;
+    assert(image_ctx.resize_reqs.front() == this);
+    m_original_size = image_ctx.size;
     compute_parent_overlap();
   }
 
-  Request::send();
+  Request<I>::send();
 }
 
-void ResizeRequest::send_op() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void ResizeRequest<I>::send_op() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
-  if (is_canceled()) {
-    async_complete(-ERESTART);
+  CephContext *cct = image_ctx.cct;
+  if (this->is_canceled()) {
+    this->async_complete(-ERESTART);
   } else if (m_original_size == m_new_size) {
     ldout(cct, 2) << this << " no change in size (" << m_original_size
                  << " -> " << m_new_size << ")" << dendl;
     m_state = STATE_FINISHED;
-    async_complete(0);
+    this->async_complete(0);
   } else if (m_new_size > m_original_size) {
     ldout(cct, 2) << this << " expanding image (" << m_original_size
                  << " -> " << m_new_size << ")" << dendl;
@@ -141,133 +148,154 @@ void ResizeRequest::send_op() {
   }
 }
 
-void ResizeRequest::send_flush() {
-  ldout(m_image_ctx.cct, 5) << this << " send_flush: "
-                            << " original_size=" << m_original_size
-                            << " new_size=" << m_new_size << dendl;
+template <typename I>
+void ResizeRequest<I>::send_flush() {
+  I &image_ctx = this->m_image_ctx;
+  ldout(image_ctx.cct, 5) << this << " send_flush: "
+                          << " original_size=" << m_original_size
+                          << " new_size=" << m_new_size << dendl;
   m_state = STATE_FLUSH;
 
   // with clipping adjusted, ensure that write / copy-on-read operations won't
   // (re-)create objects that we just removed. need async callback to ensure
   // we don't have cache_lock already held
-  m_image_ctx.flush_async_operations(create_async_callback_context());
+  image_ctx.flush_async_operations(this->create_async_callback_context());
 }
 
-void ResizeRequest::send_invalidate_cache() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  ldout(m_image_ctx.cct, 5) << this << " send_invalidate_cache: "
-                            << " original_size=" << m_original_size
-                            << " new_size=" << m_new_size << dendl;
+template <typename I>
+void ResizeRequest<I>::send_invalidate_cache() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  ldout(image_ctx.cct, 5) << this << " send_invalidate_cache: "
+                          << " original_size=" << m_original_size
+                          << " new_size=" << m_new_size << dendl;
   m_state = STATE_INVALIDATE_CACHE;
 
   // need to invalidate since we're deleting objects, and
   // ObjectCacher doesn't track non-existent objects
-  m_image_ctx.invalidate_cache(create_callback_context());
+  image_ctx.invalidate_cache(this->create_callback_context());
 }
 
-void ResizeRequest::send_trim_image() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  ldout(m_image_ctx.cct, 5) << this << " send_trim_image: "
-                            << " original_size=" << m_original_size
-                            << " new_size=" << m_new_size << dendl;
+template <typename I>
+void ResizeRequest<I>::send_trim_image() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  ldout(image_ctx.cct, 5) << this << " send_trim_image: "
+                          << " original_size=" << m_original_size
+                          << " new_size=" << m_new_size << dendl;
   m_state = STATE_TRIM_IMAGE;
 
-  TrimRequest *req = new TrimRequest(m_image_ctx, create_callback_context(),
-                                    m_original_size, m_new_size, m_prog_ctx);
+  TrimRequest<I> *req = new TrimRequest<I>(image_ctx,
+                                           this->create_callback_context(),
+                                          m_original_size, m_new_size,
+                                           m_prog_ctx);
   req->send();
 }
 
-void ResizeRequest::send_grow_object_map() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  if (!m_image_ctx.object_map.enabled()) {
+template <typename I>
+void ResizeRequest<I>::send_grow_object_map() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  if (!image_ctx.object_map.enabled()) {
     send_update_header();
     return;
   }
 
-  ldout(m_image_ctx.cct, 5) << this << " send_grow_object_map: "
-                            << " original_size=" << m_original_size
-                            << " new_size=" << m_new_size << dendl;
+  ldout(image_ctx.cct, 5) << this << " send_grow_object_map: "
+                          << " original_size=" << m_original_size
+                          << " new_size=" << m_new_size << dendl;
   m_state = STATE_GROW_OBJECT_MAP;
 
   // should have been canceled prior to releasing lock
-  assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-         m_image_ctx.image_watcher->is_lock_owner());
+  assert(!image_ctx.image_watcher->is_lock_supported() ||
+         image_ctx.image_watcher->is_lock_owner());
 
-  m_image_ctx.object_map.aio_resize(m_new_size, OBJECT_NONEXISTENT,
-                                   create_callback_context());
+  image_ctx.object_map.aio_resize(m_new_size, OBJECT_NONEXISTENT,
+                                 this->create_callback_context());
 }
 
-bool ResizeRequest::send_shrink_object_map() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  if (!m_image_ctx.object_map.enabled() || m_new_size > m_original_size) {
+template <typename I>
+bool ResizeRequest<I>::send_shrink_object_map() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  if (!image_ctx.object_map.enabled() || m_new_size > m_original_size) {
     return true;
   }
 
-  ldout(m_image_ctx.cct, 5) << this << " send_shrink_object_map: "
+  ldout(image_ctx.cct, 5) << this << " send_shrink_object_map: "
                            << " original_size=" << m_original_size
                            << " new_size=" << m_new_size << dendl;
   m_state = STATE_SHRINK_OBJECT_MAP;
 
   // should have been canceled prior to releasing lock
-  assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-         m_image_ctx.image_watcher->is_lock_owner());
+  assert(!image_ctx.image_watcher->is_lock_supported() ||
+         image_ctx.image_watcher->is_lock_owner());
 
-  m_image_ctx.object_map.aio_resize(m_new_size, OBJECT_NONEXISTENT,
-                                   create_callback_context());
+  image_ctx.object_map.aio_resize(m_new_size, OBJECT_NONEXISTENT,
+                                 this->create_callback_context());
   return false;
 }
 
-void ResizeRequest::send_update_header() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void ResizeRequest<I>::send_update_header() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  ldout(m_image_ctx.cct, 5) << this << " send_update_header: "
+  ldout(image_ctx.cct, 5) << this << " send_update_header: "
                             << " original_size=" << m_original_size
                             << " new_size=" << m_new_size << dendl;
   m_state = STATE_UPDATE_HEADER;
 
   // should have been canceled prior to releasing lock
-  assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-         m_image_ctx.image_watcher->is_lock_owner());
+  assert(!image_ctx.image_watcher->is_lock_supported() ||
+         image_ctx.image_watcher->is_lock_owner());
 
   librados::ObjectWriteOperation op;
-  if (m_image_ctx.old_format) {
+  if (image_ctx.old_format) {
     // rewrite only the size field of the header
     // NOTE: format 1 image headers are not stored in fixed endian format
     bufferlist bl;
     bl.append(reinterpret_cast<const char*>(&m_new_size), sizeof(m_new_size));
     op.write(offsetof(rbd_obj_header_ondisk, image_size), bl);
   } else {
-    if (m_image_ctx.image_watcher->is_lock_supported()) {
-      m_image_ctx.image_watcher->assert_header_locked(&op);
+    if (image_ctx.image_watcher->is_lock_supported()) {
+      image_ctx.image_watcher->assert_header_locked(&op);
     }
     cls_client::set_size(&op, m_new_size);
   }
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
-                                    rados_completion, &op);
+  librados::AioCompletion *rados_completion =
+    this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid,
+                                      rados_completion, &op);
   assert(r == 0);
   rados_completion->release();
 }
 
-void ResizeRequest::compute_parent_overlap() {
-  RWLock::RLocker l2(m_image_ctx.parent_lock);
-  if (m_image_ctx.parent == NULL) {
+template <typename I>
+void ResizeRequest<I>::compute_parent_overlap() {
+  I &image_ctx = this->m_image_ctx;
+  RWLock::RLocker l2(image_ctx.parent_lock);
+  if (image_ctx.parent == NULL) {
     m_new_parent_overlap = 0;
   } else {
-    m_new_parent_overlap = MIN(m_new_size, m_image_ctx.parent_md.overlap);
+    m_new_parent_overlap = MIN(m_new_size, image_ctx.parent_md.overlap);
   }
 }
 
-void ResizeRequest::update_size_and_overlap() {
-  RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
-  m_image_ctx.size = m_new_size;
+template <typename I>
+void ResizeRequest<I>::update_size_and_overlap() {
+  I &image_ctx = this->m_image_ctx;
+  RWLock::WLocker snap_locker(image_ctx.snap_lock);
+  image_ctx.size = m_new_size;
 
-  RWLock::WLocker parent_locker(m_image_ctx.parent_lock);
-  if (m_image_ctx.parent != NULL && m_new_size < m_original_size) {
-    m_image_ctx.parent_md.overlap = m_new_parent_overlap;
+  RWLock::WLocker parent_locker(image_ctx.parent_lock);
+  if (image_ctx.parent != NULL && m_new_size < m_original_size) {
+    image_ctx.parent_md.overlap = m_new_parent_overlap;
   }
 }
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::ResizeRequest<librbd::ImageCtx>;
index 242a8d68be7a8bfd2c332399e4a359e6f6e5d477..dc36ae399a3682ebda90ede79c5185605093432c 100644 (file)
@@ -14,11 +14,11 @@ class ProgressContext;
 
 namespace operation {
 
-class ResizeRequest : public Request
-{
+template <typename ImageCtxT = ImageCtx>
+class ResizeRequest : public Request<ImageCtxT> {
 public:
-  ResizeRequest(ImageCtx &image_ctx, Context *on_finish, uint64_t new_size,
-                     ProgressContext &prog_ctx);
+  ResizeRequest(ImageCtxT &image_ctx, Context *on_finish, uint64_t new_size,
+                ProgressContext &prog_ctx);
   virtual ~ResizeRequest();
 
   inline bool shrinking() const {
@@ -90,7 +90,7 @@ private:
   ProgressContext &m_prog_ctx;
   uint64_t m_new_parent_overlap;
 
-  xlist<ResizeRequest *>::item m_xlist_item;
+  typename xlist<ResizeRequest<ImageCtxT>*>::item m_xlist_item;
 
   void send_flush();
   void send_invalidate_cache();
@@ -107,4 +107,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::ResizeRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_RESIZE_REQUEST_H
index 26aaadaf62d2bc779963ab15e7d8d7410fa2a41b..5caad146803263be962ad0b5a7fe593961025e06 100644 (file)
@@ -18,25 +18,26 @@ namespace operation {
 
 namespace {
 
+template <typename I>
 std::ostream& operator<<(std::ostream& os,
-                         const SnapshotCreateRequest::State& state) {
+                         const typename SnapshotCreateRequest<I>::State& state) {
   switch(state) {
-  case SnapshotCreateRequest::STATE_SUSPEND_REQUESTS:
+  case SnapshotCreateRequest<I>::STATE_SUSPEND_REQUESTS:
     os << "SUSPEND_REQUESTS";
     break;
-  case SnapshotCreateRequest::STATE_SUSPEND_AIO:
+  case SnapshotCreateRequest<I>::STATE_SUSPEND_AIO:
     os << "SUSPEND_AIO";
     break;
-  case SnapshotCreateRequest::STATE_ALLOCATE_SNAP_ID:
+  case SnapshotCreateRequest<I>::STATE_ALLOCATE_SNAP_ID:
     os << "ALLOCATE_SNAP_ID";
     break;
-  case SnapshotCreateRequest::STATE_CREATE_SNAP:
+  case SnapshotCreateRequest<I>::STATE_CREATE_SNAP:
     os << "CREATE_SNAP";
     break;
-  case SnapshotCreateRequest::STATE_CREATE_OBJECT_MAP:
+  case SnapshotCreateRequest<I>::STATE_CREATE_OBJECT_MAP:
     os << "CREATE_OBJECT_MAP";
     break;
-  case SnapshotCreateRequest::STATE_RELEASE_SNAP_ID:
+  case SnapshotCreateRequest<I>::STATE_RELEASE_SNAP_ID:
     os << "RELEASE_SNAP_ID";
     break;
   default:
@@ -48,20 +49,24 @@ std::ostream& operator<<(std::ostream& os,
 
 } // anonymous namespace
 
-SnapshotCreateRequest::SnapshotCreateRequest(ImageCtx &image_ctx,
-                                             Context *on_finish,
-                                             const std::string &snap_name)
-  : Request(image_ctx, on_finish), m_snap_name(snap_name), m_ret_val(0),
+template <typename I>
+SnapshotCreateRequest<I>::SnapshotCreateRequest(I &image_ctx,
+                                                Context *on_finish,
+                                                const std::string &snap_name)
+  : Request<I>(image_ctx, on_finish), m_snap_name(snap_name), m_ret_val(0),
     m_aio_suspended(false), m_requests_suspended(false),
     m_snap_id(CEPH_NOSNAP), m_snap_created(false) {
 }
 
-void SnapshotCreateRequest::send_op() {
+template <typename I>
+void SnapshotCreateRequest<I>::send_op() {
   send_suspend_requests();
 }
 
-bool SnapshotCreateRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool SnapshotCreateRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
                 << "r=" << r << dendl;
   r = filter_state_return_code(r);
@@ -76,7 +81,7 @@ bool SnapshotCreateRequest::should_complete(int r) {
     return should_complete_error();
   }
 
-  RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+  RWLock::RLocker owner_lock(image_ctx.owner_lock);
   bool finished = false;
   switch (m_state) {
   case STATE_SUSPEND_REQUESTS:
@@ -112,8 +117,10 @@ bool SnapshotCreateRequest::should_complete(int r) {
   return finished;
 }
 
-bool SnapshotCreateRequest::should_complete_error() {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool SnapshotCreateRequest<I>::should_complete_error() {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   lderr(cct) << this << " " << __func__ << ": "
              << "ret_val=" << m_ret_val << dendl;
 
@@ -130,120 +137,138 @@ bool SnapshotCreateRequest::should_complete_error() {
   return finished;
 }
 
-void SnapshotCreateRequest::send_suspend_requests() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotCreateRequest<I>::send_suspend_requests() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
   // TODO suspend (shrink) resize to ensure consistent RBD mirror
   send_suspend_aio();
 }
 
-void SnapshotCreateRequest::send_suspend_aio() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotCreateRequest<I>::send_suspend_aio() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
 
   m_state = STATE_SUSPEND_AIO;
   m_aio_suspended = true;
 
   // can issue a re-entrant callback if no IO in-progress
-  m_image_ctx.aio_work_queue->block_writes(create_async_callback_context());
+  image_ctx.aio_work_queue->block_writes(this->create_async_callback_context());
 }
 
-void SnapshotCreateRequest::send_allocate_snap_id() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotCreateRequest<I>::send_allocate_snap_id() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_ALLOCATE_SNAP_ID;
 
   // TODO create an async version of selfmanaged_snap_create
-  int r = m_image_ctx.md_ctx.selfmanaged_snap_create(&m_snap_id);
-  async_complete(r);
+  int r = image_ctx.md_ctx.selfmanaged_snap_create(&m_snap_id);
+  this->async_complete(r);
 }
 
-void SnapshotCreateRequest::send_create_snap() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-  RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
+template <typename I>
+void SnapshotCreateRequest<I>::send_create_snap() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  RWLock::RLocker snap_locker(image_ctx.snap_lock);
+  RWLock::RLocker parent_locker(image_ctx.parent_lock);
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_CREATE_SNAP;
 
   // should have been canceled prior to releasing lock
-  assert(!m_image_ctx.image_watcher->is_lock_supported(m_image_ctx.snap_lock) ||
-         m_image_ctx.image_watcher->is_lock_owner());
+  assert(!image_ctx.image_watcher->is_lock_supported(image_ctx.snap_lock) ||
+         image_ctx.image_watcher->is_lock_owner());
 
   // save current size / parent info for creating snapshot record in ImageCtx
-  m_size = m_image_ctx.size;
-  m_parent_info = m_image_ctx.parent_md;
+  m_size = image_ctx.size;
+  m_parent_info = image_ctx.parent_md;
 
   librados::ObjectWriteOperation op;
-  if (m_image_ctx.old_format) {
+  if (image_ctx.old_format) {
     cls_client::old_snapshot_add(&op, m_snap_id, m_snap_name);
   } else {
-    if (m_image_ctx.image_watcher->is_lock_owner()) {
-      m_image_ctx.image_watcher->assert_header_locked(&op);
+    if (image_ctx.image_watcher->is_lock_owner()) {
+      image_ctx.image_watcher->assert_header_locked(&op);
     }
     cls_client::snapshot_add(&op, m_snap_id, m_snap_name);
   }
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
+  librados::AioCompletion *rados_completion =
+    this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid,
                                          rados_completion, &op);
   assert(r == 0);
   rados_completion->release();
 }
 
-bool SnapshotCreateRequest::send_create_object_map() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+bool SnapshotCreateRequest<I>::send_create_object_map() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    RWLock::RLocker object_map_lock(m_image_ctx.object_map_lock);
-    if (m_image_ctx.object_map.enabled(m_image_ctx.object_map_lock)) {
-      CephContext *cct = m_image_ctx.cct;
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    RWLock::RLocker object_map_lock(image_ctx.object_map_lock);
+    if (image_ctx.object_map.enabled(image_ctx.object_map_lock)) {
+      CephContext *cct = image_ctx.cct;
       ldout(cct, 5) << this << " " << __func__ << dendl;
       m_state = STATE_CREATE_OBJECT_MAP;
 
-      m_image_ctx.object_map.snapshot_add(m_snap_id, create_callback_context());
+      image_ctx.object_map.snapshot_add(m_snap_id,
+                                        this->create_callback_context());
       return false;
     }
   }
   return true;
 }
 
-bool SnapshotCreateRequest::send_release_snap_id() {
+template <typename I>
+bool SnapshotCreateRequest<I>::send_release_snap_id() {
+  I &image_ctx = this->m_image_ctx;
   if (m_snap_id != CEPH_NOSNAP && !m_snap_created) {
-    CephContext *cct = m_image_ctx.cct;
+    CephContext *cct = image_ctx.cct;
     ldout(cct, 5) << this << " " << __func__ << ": snap_id=" << m_snap_id
                   << dendl;
     m_state = STATE_RELEASE_SNAP_ID;
 
     // TODO add async version of selfmanaged_snap_remove
-    int r = m_image_ctx.data_ctx.selfmanaged_snap_remove(m_snap_id);
+    int r = image_ctx.data_ctx.selfmanaged_snap_remove(m_snap_id);
     m_snap_id = CEPH_NOSNAP;
 
-    async_complete(r);
+    this->async_complete(r);
     return false;
   }
   return true;
 }
 
-void SnapshotCreateRequest::resume_aio() {
+template <typename I>
+void SnapshotCreateRequest<I>::resume_aio() {
+  I &image_ctx = this->m_image_ctx;
   if (m_aio_suspended) {
-    CephContext *cct = m_image_ctx.cct;
+    CephContext *cct = image_ctx.cct;
     ldout(cct, 5) << this << " " << __func__ << dendl;
 
-    m_image_ctx.aio_work_queue->unblock_writes();
+    image_ctx.aio_work_queue->unblock_writes();
     m_aio_suspended = false;
   }
 }
 
-void SnapshotCreateRequest::resume_requests() {
+template <typename I>
+void SnapshotCreateRequest<I>::resume_requests() {
+  I &image_ctx = this->m_image_ctx;
   if (m_requests_suspended) {
-    CephContext *cct = m_image_ctx.cct;
+    CephContext *cct = image_ctx.cct;
     ldout(cct, 5) << this << " " << __func__ << dendl;
 
     // TODO
@@ -251,42 +276,46 @@ void SnapshotCreateRequest::resume_requests() {
   }
 }
 
-void SnapshotCreateRequest::update_snap_context() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotCreateRequest<I>::update_snap_context() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
   m_snap_created = true;
 
-  RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
-  if (m_image_ctx.old_format) {
+  RWLock::WLocker snap_locker(image_ctx.snap_lock);
+  if (image_ctx.old_format) {
     return;
   }
 
-  if (m_image_ctx.get_snap_info(m_snap_id) != NULL) {
+  if (image_ctx.get_snap_info(m_snap_id) != NULL) {
     return;
   }
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
 
   // should have been canceled prior to releasing lock
-  assert(!m_image_ctx.image_watcher->is_lock_supported(m_image_ctx.snap_lock) ||
-         m_image_ctx.image_watcher->is_lock_owner());
+  assert(!image_ctx.image_watcher->is_lock_supported(image_ctx.snap_lock) ||
+         image_ctx.image_watcher->is_lock_owner());
 
   // immediately add a reference to the new snapshot
-  m_image_ctx.add_snap(m_snap_name, m_snap_id, m_size, m_parent_info,
-                       RBD_PROTECTION_STATUS_UNPROTECTED, 0);
+  image_ctx.add_snap(m_snap_name, m_snap_id, m_size, m_parent_info,
+                     RBD_PROTECTION_STATUS_UNPROTECTED, 0);
 
   // immediately start using the new snap context if we
   // own the exclusive lock
   std::vector<snapid_t> snaps;
   snaps.push_back(m_snap_id);
-  snaps.insert(snaps.end(), m_image_ctx.snapc.snaps.begin(),
-               m_image_ctx.snapc.snaps.end());
+  snaps.insert(snaps.end(), image_ctx.snapc.snaps.begin(),
+               image_ctx.snapc.snaps.end());
 
-  m_image_ctx.snapc.seq = m_snap_id;
-  m_image_ctx.snapc.snaps.swap(snaps);
-  m_image_ctx.data_ctx.selfmanaged_snap_set_write_ctx(
-    m_image_ctx.snapc.seq, m_image_ctx.snaps);
+  image_ctx.snapc.seq = m_snap_id;
+  image_ctx.snapc.snaps.swap(snaps);
+  image_ctx.data_ctx.selfmanaged_snap_set_write_ctx(
+    image_ctx.snapc.seq, image_ctx.snaps);
 }
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::SnapshotCreateRequest<librbd::ImageCtx>;
index 5db8441fef8f1fabffdfa0037471e45424a54c09..249bcafbc2e577a3924515e1eb7637dfce946ec7 100644 (file)
@@ -17,7 +17,8 @@ class ImageCtx;
 
 namespace operation {
 
-class SnapshotCreateRequest : public Request {
+template <typename ImageCtxT = ImageCtx>
+class SnapshotCreateRequest : public Request<ImageCtxT> {
 public:
   /**
    * Snap Create goes through the following state machine:
@@ -64,7 +65,7 @@ public:
     STATE_RELEASE_SNAP_ID
   };
 
-  SnapshotCreateRequest(ImageCtx &image_ctx, Context *on_finish,
+  SnapshotCreateRequest(ImageCtxT &image_ctx, Context *on_finish,
                        const std::string &snap_name);
 
 protected:
@@ -121,4 +122,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::SnapshotCreateRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_SNAPSHOT_CREATE_REQUEST_H
index 3e8a396981fdf2520c8db8949e3527b7073ccf05..9ba415e4cf9dc88a4f25d03786ef30d55c70894c 100644 (file)
@@ -15,10 +15,11 @@ namespace operation {
 
 namespace {
 
+template <typename I>
 std::ostream& operator<<(std::ostream& os,
-                         const SnapshotProtectRequest::State& state) {
+                         const typename SnapshotProtectRequest<I>::State& state) {
   switch(state) {
-  case SnapshotProtectRequest::STATE_PROTECT_SNAP:
+  case SnapshotProtectRequest<I>::STATE_PROTECT_SNAP:
     os << "PROTECT_SNAP";
     break;
   }
@@ -27,18 +28,22 @@ std::ostream& operator<<(std::ostream& os,
 
 } // anonymous namespace
 
-SnapshotProtectRequest::SnapshotProtectRequest(ImageCtx &image_ctx,
-                                               Context *on_finish,
-                                               const std::string &snap_name)
-  : Request(image_ctx, on_finish), m_snap_name(snap_name) {
+template <typename I>
+SnapshotProtectRequest<I>::SnapshotProtectRequest(I &image_ctx,
+                                                  Context *on_finish,
+                                                  const std::string &snap_name)
+  : Request<I>(image_ctx, on_finish), m_snap_name(snap_name) {
 }
 
-void SnapshotProtectRequest::send_op() {
+template <typename I>
+void SnapshotProtectRequest<I>::send_op() {
   send_protect_snap();
 }
 
-bool SnapshotProtectRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool SnapshotProtectRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
                 << "r=" << r << dendl;
   if (r < 0) {
@@ -47,38 +52,42 @@ bool SnapshotProtectRequest::should_complete(int r) {
   return true;
 }
 
-void SnapshotProtectRequest::send_protect_snap() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotProtectRequest<I>::send_protect_snap() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
 
   m_state = STATE_PROTECT_SNAP;
 
   int r = verify_and_send_protect_snap();
   if (r < 0) {
-    async_complete(r);
+    this->async_complete(r);
     return;
   }
 }
 
-int SnapshotProtectRequest::verify_and_send_protect_snap() {
-  RWLock::RLocker md_locker(m_image_ctx.md_lock);
-  RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+template <typename I>
+int SnapshotProtectRequest<I>::verify_and_send_protect_snap() {
+  I &image_ctx = this->m_image_ctx;
+  RWLock::RLocker md_locker(image_ctx.md_lock);
+  RWLock::RLocker snap_locker(image_ctx.snap_lock);
 
-  CephContext *cct = m_image_ctx.cct;
-  if ((m_image_ctx.features & RBD_FEATURE_LAYERING) == 0) {
+  CephContext *cct = image_ctx.cct;
+  if ((image_ctx.features & RBD_FEATURE_LAYERING) == 0) {
     lderr(cct) << "image must support layering" << dendl;
     return -ENOSYS;
   }
 
-  uint64_t snap_id = m_image_ctx.get_snap_id(m_snap_name);
+  uint64_t snap_id = image_ctx.get_snap_id(m_snap_name);
   if (snap_id == CEPH_NOSNAP) {
     return -ENOENT;
   }
 
   bool is_protected;
-  int r = m_image_ctx.is_snap_protected(snap_id, &is_protected);
+  int r = image_ctx.is_snap_protected(snap_id, &is_protected);
   if (r < 0) {
     return r;
   }
@@ -91,8 +100,9 @@ int SnapshotProtectRequest::verify_and_send_protect_snap() {
   cls_client::set_protection_status(&op, snap_id,
                                     RBD_PROTECTION_STATUS_PROTECTED);
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, rados_completion,
+  librados::AioCompletion *rados_completion =
+    this->create_callback_completion();
+  r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, rados_completion,
                                      &op);
   assert(r == 0);
   rados_completion->release();
@@ -102,3 +112,4 @@ int SnapshotProtectRequest::verify_and_send_protect_snap() {
 } // namespace operation
 } // namespace librbd
 
+template class librbd::operation::SnapshotProtectRequest<librbd::ImageCtx>;
index e2953f9c97fe6f08ef3d71f0f1aab2d86399d9b1..02484e98e74281c4e09c56f748912c2f258ac37d 100644 (file)
@@ -16,7 +16,8 @@ class ImageCtx;
 
 namespace operation {
 
-class SnapshotProtectRequest : public Request {
+template <typename ImageCtxT = ImageCtx>
+class SnapshotProtectRequest : public Request<ImageCtxT> {
 public:
   /**
    * Snap Protect goes through the following state machine:
@@ -38,7 +39,7 @@ public:
     STATE_PROTECT_SNAP
   };
 
-  SnapshotProtectRequest(ImageCtx &image_ctx, Context *on_finish,
+  SnapshotProtectRequest(ImageCtxT &image_ctx, Context *on_finish,
                         const std::string &snap_name);
 
 protected:
@@ -61,4 +62,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::SnapshotProtectRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_SNAPSHOT_PROTECT_REQUEST_H
index e8e76b09d86a0f99577c14baba7c4048cb352ebd..5d8035c0e87ceaec8e0a18b6b429cb4e2e7313a0 100644 (file)
@@ -17,19 +17,20 @@ namespace operation {
 
 namespace {
 
+template <typename I>
 std::ostream& operator<<(std::ostream& os,
-                         const SnapshotRemoveRequest::State& state) {
+                         const typename SnapshotRemoveRequest<I>::State& state) {
   switch(state) {
-  case SnapshotRemoveRequest::STATE_REMOVE_OBJECT_MAP:
+  case SnapshotRemoveRequest<I>::STATE_REMOVE_OBJECT_MAP:
     os << "REMOVE_OBJECT_MAP";
     break;
-  case SnapshotRemoveRequest::STATE_REMOVE_CHILD:
+  case SnapshotRemoveRequest<I>::STATE_REMOVE_CHILD:
     os << "REMOVE_CHILD";
     break;
-  case SnapshotRemoveRequest::STATE_REMOVE_SNAP:
+  case SnapshotRemoveRequest<I>::STATE_REMOVE_SNAP:
     os << "REMOVE_SNAP";
     break;
-  case SnapshotRemoveRequest::STATE_RELEASE_SNAP_ID:
+  case SnapshotRemoveRequest<I>::STATE_RELEASE_SNAP_ID:
     os << "RELEASE_SNAP_ID";
     break;
   default:
@@ -41,20 +42,24 @@ std::ostream& operator<<(std::ostream& os,
 
 } // anonymous namespace
 
-SnapshotRemoveRequest::SnapshotRemoveRequest(ImageCtx &image_ctx,
-                                             Context *on_finish,
-                                             const std::string &snap_name,
-                                             uint64_t snap_id)
-  : Request(image_ctx, on_finish), m_snap_name(snap_name),
+template <typename I>
+SnapshotRemoveRequest<I>::SnapshotRemoveRequest(I &image_ctx,
+                                               Context *on_finish,
+                                               const std::string &snap_name,
+                                               uint64_t snap_id)
+  : Request<I>(image_ctx, on_finish), m_snap_name(snap_name),
     m_snap_id(snap_id) {
 }
 
-void SnapshotRemoveRequest::send_op() {
+template <typename I>
+void SnapshotRemoveRequest<I>::send_op() {
   send_remove_object_map();
 }
 
-bool SnapshotRemoveRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool SnapshotRemoveRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
                 << "r=" << r << dendl;
   r = filter_state_return_code(r);
@@ -62,7 +67,7 @@ bool SnapshotRemoveRequest::should_complete(int r) {
     return true;
   }
 
-  RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+  RWLock::RLocker owner_lock(image_ctx.owner_lock);
   bool finished = false;
   switch (m_state) {
   case STATE_REMOVE_OBJECT_MAP:
@@ -86,52 +91,56 @@ bool SnapshotRemoveRequest::should_complete(int r) {
   return finished;
 }
 
-void SnapshotRemoveRequest::send_remove_object_map() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotRemoveRequest<I>::send_remove_object_map() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
   {
-    RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
-    RWLock::RLocker object_map_locker(m_image_ctx.object_map_lock);
-    if (m_image_ctx.object_map.enabled(m_image_ctx.object_map_lock)) {
-      CephContext *cct = m_image_ctx.cct;
+    RWLock::WLocker snap_locker(image_ctx.snap_lock);
+    RWLock::RLocker object_map_locker(image_ctx.object_map_lock);
+    if (image_ctx.object_map.enabled(image_ctx.object_map_lock)) {
+      CephContext *cct = image_ctx.cct;
       ldout(cct, 5) << this << " " << __func__ << dendl;
       m_state = STATE_REMOVE_OBJECT_MAP;
 
-      m_image_ctx.object_map.snapshot_remove(
-        m_snap_id, create_callback_context());
+      image_ctx.object_map.snapshot_remove(
+        m_snap_id, this->create_callback_context());
       return;
     }
   }
   send_remove_child();
 }
 
-void SnapshotRemoveRequest::send_remove_child() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotRemoveRequest<I>::send_remove_child() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    RWLock::RLocker parent_locker(image_ctx.parent_lock);
 
     parent_spec our_pspec;
-    int r = m_image_ctx.get_parent_spec(m_snap_id, &our_pspec);
+    int r = image_ctx.get_parent_spec(m_snap_id, &our_pspec);
     if (r < 0) {
       lderr(cct) << "failed to retrieve parent spec" << dendl;
-      async_complete(r);
+      this->async_complete(r);
       return;
     }
 
-    if (m_image_ctx.parent_md.spec != our_pspec &&
+    if (image_ctx.parent_md.spec != our_pspec &&
         (scan_for_parents(our_pspec) == -ENOENT)) {
       // no other references to the parent image
       ldout(cct, 5) << this << " " << __func__ << dendl;
       m_state = STATE_REMOVE_CHILD;
 
       librados::ObjectWriteOperation op;
-      cls_client::remove_child(&op, our_pspec, m_image_ctx.id);
+      cls_client::remove_child(&op, our_pspec, image_ctx.id);
 
-      librados::AioCompletion *rados_completion = create_callback_completion();
-      r = m_image_ctx.md_ctx.aio_operate(RBD_CHILDREN, rados_completion, &op);
+      librados::AioCompletion *rados_completion = this->create_callback_completion();
+      r = image_ctx.md_ctx.aio_operate(RBD_CHILDREN, rados_completion, &op);
       assert(r == 0);
       rados_completion->release();
       return;
@@ -142,60 +151,68 @@ void SnapshotRemoveRequest::send_remove_child() {
   send_remove_snap();
 }
 
-void SnapshotRemoveRequest::send_remove_snap() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotRemoveRequest<I>::send_remove_snap() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_REMOVE_SNAP;
 
   librados::ObjectWriteOperation op;
-  if (m_image_ctx.old_format) {
+  if (image_ctx.old_format) {
     cls_client::old_snapshot_remove(&op, m_snap_name);
   } else {
-    if (m_image_ctx.image_watcher->is_lock_owner()) {
-      m_image_ctx.image_watcher->assert_header_locked(&op);
+    if (image_ctx.image_watcher->is_lock_owner()) {
+      image_ctx.image_watcher->assert_header_locked(&op);
     }
     cls_client::snapshot_remove(&op, m_snap_id);
   }
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
-                                         rados_completion, &op);
+  librados::AioCompletion *rados_completion = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid,
+                                       rados_completion, &op);
   assert(r == 0);
   rados_completion->release();
 }
 
-void SnapshotRemoveRequest::send_release_snap_id() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotRemoveRequest<I>::send_release_snap_id() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": "
                 << "snap_name=" << m_snap_name << ", "
                 << "snap_id=" << m_snap_id << dendl;
   m_state = STATE_RELEASE_SNAP_ID;
 
   // TODO add async version of selfmanaged_snap_remove
-  m_image_ctx.data_ctx.selfmanaged_snap_remove(m_snap_id);
-  async_complete(0);
+  image_ctx.data_ctx.selfmanaged_snap_remove(m_snap_id);
+  this->async_complete(0);
 }
 
-void SnapshotRemoveRequest::remove_snap_context() {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+void SnapshotRemoveRequest<I>::remove_snap_context() {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
 
-  RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
-  m_image_ctx.rm_snap(m_snap_name, m_snap_id);
+  RWLock::WLocker snap_locker(image_ctx.snap_lock);
+  image_ctx.rm_snap(m_snap_name, m_snap_id);
 }
 
-int SnapshotRemoveRequest::scan_for_parents(parent_spec &pspec) {
-  assert(m_image_ctx.snap_lock.is_locked());
-  assert(m_image_ctx.parent_lock.is_locked());
+template <typename I>
+int SnapshotRemoveRequest<I>::scan_for_parents(parent_spec &pspec) {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.snap_lock.is_locked());
+  assert(image_ctx.parent_lock.is_locked());
 
   if (pspec.pool_id != -1) {
     map<uint64_t, SnapInfo>::iterator it;
-    for (it = m_image_ctx.snap_info.begin();
-         it != m_image_ctx.snap_info.end(); ++it) {
+    for (it = image_ctx.snap_info.begin();
+         it != image_ctx.snap_info.end(); ++it) {
       // skip our snap id (if checking base image, CEPH_NOSNAP won't match)
       if (it->first == m_snap_id) {
         continue;
@@ -204,7 +221,7 @@ int SnapshotRemoveRequest::scan_for_parents(parent_spec &pspec) {
         break;
       }
     }
-    if (it == m_image_ctx.snap_info.end()) {
+    if (it == image_ctx.snap_info.end()) {
       return -ENOENT;
     }
   }
@@ -213,3 +230,5 @@ int SnapshotRemoveRequest::scan_for_parents(parent_spec &pspec) {
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::SnapshotRemoveRequest<librbd::ImageCtx>;
index 621f3ee2c763188afb0e2f432f07cc6dc07f7795..ea950a55d3571c3f7d19d2443b2de6543a4ce54f 100644 (file)
@@ -16,7 +16,8 @@ class ImageCtx;
 
 namespace operation {
 
-class SnapshotRemoveRequest : public Request {
+template <typename ImageCtxT = ImageCtx>
+class SnapshotRemoveRequest : public Request<ImageCtxT> {
 public:
   /**
    * Snap Remove goes through the following state machine:
@@ -54,7 +55,7 @@ public:
     STATE_RELEASE_SNAP_ID
   };
 
-  SnapshotRemoveRequest(ImageCtx &image_ctx, Context *on_finish,
+  SnapshotRemoveRequest(ImageCtxT &image_ctx, Context *on_finish,
                        const std::string &snap_name, uint64_t snap_id);
 
 protected:
@@ -90,4 +91,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::SnapshotRemoveRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_SNAPSHOT_REMOVE_REQUEST_H
index c5804afc771b7b78c4d7c3536ce180c9d404756b..53ffb382567779ae8ebcd7974d1ba385aff2312d 100644 (file)
@@ -16,10 +16,11 @@ namespace operation {
 
 namespace {
 
+template <typename I>
 std::ostream& operator<<(std::ostream& os,
-                         const SnapshotRenameRequest::State& state) {
+                         const typename SnapshotRenameRequest<I>::State& state) {
   switch(state) {
-  case SnapshotRenameRequest::STATE_RENAME_SNAP:
+  case SnapshotRenameRequest<I>::STATE_RENAME_SNAP:
     os << "RENAME_SNAP";
     break;
   }
@@ -28,19 +29,23 @@ std::ostream& operator<<(std::ostream& os,
 
 } // anonymous namespace
 
-SnapshotRenameRequest::SnapshotRenameRequest(ImageCtx &image_ctx,
-                                             Context *on_finish,
-                                             uint64_t snap_id,
-                                             const std::string &snap_name)
-  : Request(image_ctx, on_finish), m_snap_id(snap_id), m_snap_name(snap_name) {
+template <typename I>
+SnapshotRenameRequest<I>::SnapshotRenameRequest(I &image_ctx,
+                                               Context *on_finish,
+                                               uint64_t snap_id,
+                                               const std::string &snap_name)
+  : Request<I>(image_ctx, on_finish), m_snap_id(snap_id), m_snap_name(snap_name) {
 }
 
-void SnapshotRenameRequest::send_op() {
+template <typename I>
+void SnapshotRenameRequest<I>::send_op() {
   send_rename_snap();
 }
 
-bool SnapshotRenameRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool SnapshotRenameRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
                 << "r=" << r << dendl;
   if (r < 0) {
@@ -49,29 +54,31 @@ bool SnapshotRenameRequest::should_complete(int r) {
   return true;
 }
 
-void SnapshotRenameRequest::send_rename_snap() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  RWLock::RLocker md_locker(m_image_ctx.md_lock);
-  RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+template <typename I>
+void SnapshotRenameRequest<I>::send_rename_snap() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  RWLock::RLocker md_locker(image_ctx.md_lock);
+  RWLock::RLocker snap_locker(image_ctx.snap_lock);
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
 
   m_state = STATE_RENAME_SNAP;
 
   librados::ObjectWriteOperation op;
-  if (m_image_ctx.old_format) {
+  if (image_ctx.old_format) {
     cls_client::old_snapshot_rename(&op, m_snap_id, m_snap_name);
   } else {
-    if (m_image_ctx.image_watcher->is_lock_owner()) {
-      m_image_ctx.image_watcher->assert_header_locked(&op);
+    if (image_ctx.image_watcher->is_lock_owner()) {
+      image_ctx.image_watcher->assert_header_locked(&op);
     }
     cls_client::snapshot_rename(&op, m_snap_id, m_snap_name);
   }
 
-  librados::AioCompletion *rados_completion = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
-                                         rados_completion, &op);
+  librados::AioCompletion *rados_completion = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid,
+                                       rados_completion, &op);
   assert(r == 0);
   rados_completion->release();
 }
@@ -79,3 +86,4 @@ void SnapshotRenameRequest::send_rename_snap() {
 } // namespace operation
 } // namespace librbd
 
+template class librbd::operation::SnapshotRenameRequest<librbd::ImageCtx>;
index 8be3459086295bd9ef62d1db8aa29f62588dbed9..19a72c75a50ae8f9f4074ddeb201eca2269ff2f0 100644 (file)
@@ -16,7 +16,8 @@ class ImageCtx;
 
 namespace operation {
 
-class SnapshotRenameRequest : public Request {
+template <typename ImageCtxT = ImageCtx>
+class SnapshotRenameRequest : public Request<ImageCtxT> {
 public:
   /**
    * Snap Rename goes through the following state machine:
@@ -38,7 +39,7 @@ public:
     STATE_RENAME_SNAP
   };
 
-  SnapshotRenameRequest(ImageCtx &image_ctx, Context *on_finish,
+  SnapshotRenameRequest(ImageCtxT &image_ctx, Context *on_finish,
                         uint64_t snap_id, const std::string &snap_name);
 
   virtual journal::Event create_event() const {
@@ -60,4 +61,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::SnapshotRenameRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_SNAPSHOT_RENAME_REQUEST_H
index bde4a3a5cfb4d8305365c71ba8bea0312e21aa27..2acd2aef0421f5dc0683514a4e2844d2c6e81e6c 100644 (file)
@@ -22,19 +22,20 @@ namespace operation {
 
 namespace {
 
+template <typename I>
 std::ostream& operator<<(std::ostream& os,
-                         const SnapshotRollbackRequest::State& state) {
+                         const typename SnapshotRollbackRequest<I>::State& state) {
   switch(state) {
-  case SnapshotRollbackRequest::STATE_RESIZE_IMAGE:
+  case SnapshotRollbackRequest<I>::STATE_RESIZE_IMAGE:
     os << "RESIZE_IMAGE";
     break;
-  case SnapshotRollbackRequest::STATE_ROLLBACK_OBJECT_MAP:
+  case SnapshotRollbackRequest<I>::STATE_ROLLBACK_OBJECT_MAP:
     os << "ROLLBACK_OBJECT_MAP";
     break;
-  case SnapshotRollbackRequest::STATE_ROLLBACK_OBJECTS:
+  case SnapshotRollbackRequest<I>::STATE_ROLLBACK_OBJECTS:
     os << "ROLLBACK_OBJECTS";
     break;
-  case SnapshotRollbackRequest::STATE_INVALIDATE_CACHE:
+  case SnapshotRollbackRequest<I>::STATE_INVALIDATE_CACHE:
     os << "INVALIDATE_CACHE";
     break;
   default:
@@ -44,26 +45,28 @@ std::ostream& operator<<(std::ostream& os,
   return os;
 }
 
+template <typename I>
 class C_RollbackObject : public C_AsyncObjectThrottle<> {
 public:
-  C_RollbackObject(AsyncObjectThrottle<> &throttle, ImageCtx *image_ctx,
+  C_RollbackObject(AsyncObjectThrottle<> &throttle, I *image_ctx,
                    uint64_t snap_id, uint64_t object_num)
     : C_AsyncObjectThrottle(throttle, *image_ctx), m_snap_id(snap_id),
       m_object_num(object_num) {
   }
 
   virtual int send() {
-    CephContext *cct = m_image_ctx.cct;
+    I &image_ctx = this->m_image_ctx;
+    CephContext *cct = image_ctx.cct;
     ldout(cct, 20) << "C_RollbackObject: " << __func__ << ": object_num="
                    << m_object_num << dendl;
 
-    std::string oid = m_image_ctx.get_object_name(m_object_num);
+    std::string oid = image_ctx.get_object_name(m_object_num);
 
     librados::AioCompletion *rados_completion =
       librados::Rados::aio_create_completion(this, NULL, rados_ctx_cb);
     librados::ObjectWriteOperation op;
     op.selfmanaged_snap_rollback(m_snap_id);
-    m_image_ctx.data_ctx.aio_operate(oid, rados_completion, &op);
+    image_ctx.data_ctx.aio_operate(oid, rados_completion, &op);
     rados_completion->release();
     return 0;
   }
@@ -75,22 +78,26 @@ private:
 
 } // anonymous namespace
 
-SnapshotRollbackRequest::SnapshotRollbackRequest(ImageCtx &image_ctx,
-                                                 Context *on_finish,
-                                                 const std::string &snap_name,
-                                                 uint64_t snap_id,
-                                                 uint64_t snap_size,
-                                                 ProgressContext &prog_ctx)
-  : Request(image_ctx, on_finish), m_snap_name(snap_name), m_snap_id(snap_id),
-    m_snap_size(snap_size), m_prog_ctx(prog_ctx) {
+template <typename I>
+SnapshotRollbackRequest<I>::SnapshotRollbackRequest(I &image_ctx,
+                                                    Context *on_finish,
+                                                    const std::string &snap_name,
+                                                    uint64_t snap_id,
+                                                    uint64_t snap_size,
+                                                    ProgressContext &prog_ctx)
+  : Request<I>(image_ctx, on_finish), m_snap_name(snap_name),
+    m_snap_id(snap_id), m_snap_size(snap_size), m_prog_ctx(prog_ctx) {
 }
 
-void SnapshotRollbackRequest::send_op() {
+template <typename I>
+void SnapshotRollbackRequest<I>::send_op() {
   send_resize_image();
 }
 
-bool SnapshotRollbackRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool SnapshotRollbackRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
                 << "r=" << r << dendl;
   if (r < 0) {
@@ -98,7 +105,7 @@ bool SnapshotRollbackRequest::should_complete(int r) {
     return true;
   }
 
-  RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+  RWLock::RLocker owner_lock(image_ctx.owner_lock);
   bool finished = false;
   switch (m_state) {
   case STATE_RESIZE_IMAGE:
@@ -120,13 +127,15 @@ bool SnapshotRollbackRequest::should_complete(int r) {
   return finished;
 }
 
-void SnapshotRollbackRequest::send_resize_image() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotRollbackRequest<I>::send_resize_image() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
   uint64_t current_size;
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    current_size = m_image_ctx.get_image_size(CEPH_NOSNAP);
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    current_size = image_ctx.get_image_size(CEPH_NOSNAP);
   }
 
   if (current_size == m_snap_size) {
@@ -134,27 +143,30 @@ void SnapshotRollbackRequest::send_resize_image() {
     return;
   }
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_RESIZE_IMAGE;
 
-  ResizeRequest *req = new ResizeRequest(m_image_ctx, create_callback_context(),
-                                         m_snap_size, m_no_op_prog_ctx);
+  ResizeRequest<I> *req = new ResizeRequest<I>(image_ctx,
+                                               this->create_callback_context(),
+                                               m_snap_size, m_no_op_prog_ctx);
   req->send();
 }
 
-void SnapshotRollbackRequest::send_rollback_object_map() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotRollbackRequest<I>::send_rollback_object_map() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    RWLock::WLocker object_map_lock(m_image_ctx.object_map_lock);
-    if (m_image_ctx.object_map.enabled(m_image_ctx.object_map_lock)) {
-      CephContext *cct = m_image_ctx.cct;
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    RWLock::WLocker object_map_lock(image_ctx.object_map_lock);
+    if (image_ctx.object_map.enabled(image_ctx.object_map_lock)) {
+      CephContext *cct = image_ctx.cct;
       ldout(cct, 5) << this << " " << __func__ << dendl;
       m_state = STATE_ROLLBACK_OBJECT_MAP;
 
-      m_image_ctx.object_map.rollback(m_snap_id, create_callback_context());
+      image_ctx.object_map.rollback(m_snap_id, this->create_callback_context());
       return;
     }
   }
@@ -162,43 +174,49 @@ void SnapshotRollbackRequest::send_rollback_object_map() {
   send_rollback_objects();
 }
 
-void SnapshotRollbackRequest::send_rollback_objects() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotRollbackRequest<I>::send_rollback_objects() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_ROLLBACK_OBJECTS;
 
   uint64_t num_objects;
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    num_objects = Striper::get_num_objects(m_image_ctx.layout,
-                                           m_image_ctx.get_current_size());
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    num_objects = Striper::get_num_objects(image_ctx.layout,
+                                           image_ctx.get_current_size());
   }
 
-  Context *ctx = create_callback_context();
-  AsyncObjectThrottle<>::ContextFactory context_factory(
-    boost::lambda::bind(boost::lambda::new_ptr<C_RollbackObject>(),
-      boost::lambda::_1, &m_image_ctx, m_snap_id, boost::lambda::_2));
-  AsyncObjectThrottle<> *throttle = new AsyncObjectThrottle<>(
-    this, m_image_ctx, context_factory, ctx, &m_prog_ctx, 0, num_objects);
-  throttle->start_ops(m_image_ctx.concurrent_management_ops);
+  Context *ctx = this->create_callback_context();
+  typename AsyncObjectThrottle<I>::ContextFactory context_factory(
+    boost::lambda::bind(boost::lambda::new_ptr<C_RollbackObject<I> >(),
+      boost::lambda::_1, &image_ctx, m_snap_id, boost::lambda::_2));
+  AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<>(
+    this, image_ctx, context_factory, ctx, &m_prog_ctx, 0, num_objects);
+  throttle->start_ops(image_ctx.concurrent_management_ops);
 }
 
-bool SnapshotRollbackRequest::send_invalidate_cache() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+bool SnapshotRollbackRequest<I>::send_invalidate_cache() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  if (m_image_ctx.object_cacher == NULL) {
+  if (image_ctx.object_cacher == NULL) {
     return true;
   }
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_INVALIDATE_CACHE;
 
-  m_image_ctx.invalidate_cache(create_callback_context());
+  image_ctx.invalidate_cache(this->create_callback_context());
   return false;
 }
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::SnapshotRollbackRequest<librbd::ImageCtx>;
index f074e488465cfdad2f731d2d03648b3770dff262..f66fc5ba0b1115e242d78ea1c82419146ca21f30 100644 (file)
@@ -17,7 +17,8 @@ class ProgressContext;
 
 namespace operation {
 
-class SnapshotRollbackRequest : public Request {
+template <typename ImageCtxT = ImageCtx>
+class SnapshotRollbackRequest : public Request<ImageCtxT> {
 public:
   /**
    * Snap Rollback goes through the following state machine:
@@ -54,7 +55,7 @@ public:
     STATE_INVALIDATE_CACHE
   };
 
-  SnapshotRollbackRequest(ImageCtx &image_ctx, Context *on_finish,
+  SnapshotRollbackRequest(ImageCtxT &image_ctx, Context *on_finish,
                           const std::string &snap_name, uint64_t snap_id,
                           uint64_t snap_size, ProgressContext &prog_ctx);
 
@@ -85,4 +86,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::SnapshotRollbackRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_SNAPSHOT_ROLLBACK_REQUEST_H
index 6d6d334f40ce479079b671b9d7e1a2c851fced17..c9c8f54224c46866537aebfabd79713b17ed65bb 100644 (file)
@@ -28,19 +28,20 @@ namespace {
 typedef std::pair<int64_t, std::string> Pool;
 typedef std::vector<Pool> Pools;
 
+template <typename I>
 std::ostream& operator<<(std::ostream& os,
-                         const SnapshotUnprotectRequest::State& state) {
+                         const typename SnapshotUnprotectRequest<I>::State& state) {
   switch(state) {
-  case SnapshotUnprotectRequest::STATE_UNPROTECT_SNAP_START:
+  case SnapshotUnprotectRequest<I>::STATE_UNPROTECT_SNAP_START:
     os << "UNPROTECT_SNAP_START";
     break;
-  case SnapshotUnprotectRequest::STATE_SCAN_POOL_CHILDREN:
+  case SnapshotUnprotectRequest<I>::STATE_SCAN_POOL_CHILDREN:
     os << "SCAN_POOL_CHILDREN";
     break;
-  case SnapshotUnprotectRequest::STATE_UNPROTECT_SNAP_FINISH:
+  case SnapshotUnprotectRequest<I>::STATE_UNPROTECT_SNAP_FINISH:
     os << "UNPROTECT_SNAP_FINISH";
     break;
-  case SnapshotUnprotectRequest::STATE_UNPROTECT_SNAP_ROLLBACK:
+  case SnapshotUnprotectRequest<I>::STATE_UNPROTECT_SNAP_ROLLBACK:
     os << "UNPROTECT_SNAP_ROLLBACK";
     break;
   default:
@@ -50,23 +51,25 @@ std::ostream& operator<<(std::ostream& os,
   return os;
 }
 
-class C_ScanPoolChildren : public C_AsyncObjectThrottle<> {
+template <typename I>
+class C_ScanPoolChildren : public C_AsyncObjectThrottle<I> {
 public:
-  C_ScanPoolChildren(AsyncObjectThrottle<> &throttle, ImageCtx *image_ctx,
+  C_ScanPoolChildren(AsyncObjectThrottle<I> &throttle, I *image_ctx,
                      const parent_spec &pspec, const Pools &pools,
                      size_t pool_idx)
-    : C_AsyncObjectThrottle(throttle, *image_ctx), m_pspec(pspec),
+    : C_AsyncObjectThrottle<I>(throttle, *image_ctx), m_pspec(pspec),
       m_pool(pools[pool_idx]) {
   }
 
   virtual int send() {
-    assert(m_image_ctx.owner_lock.is_locked());
+    I &image_ctx = this->m_image_ctx;
+    assert(image_ctx.owner_lock.is_locked());
 
-    CephContext *cct = m_image_ctx.cct;
+    CephContext *cct = image_ctx.cct;
     ldout(cct, 10) << this << " scanning pool '" << m_pool.second << "'"
                    << dendl;
 
-    librados::Rados rados(m_image_ctx.md_ctx);
+    librados::Rados rados(image_ctx.md_ctx);
     int64_t base_tier;
     int r = rados.pool_get_base_tier(m_pool.first, &base_tier);
     if (r == -ENOENT) {
@@ -101,7 +104,8 @@ public:
 
 protected:
   virtual void finish(int r) {
-    CephContext *cct = m_image_ctx.cct;
+    I &image_ctx = this->m_image_ctx;
+    CephContext *cct = image_ctx.cct;
     ldout(cct, 10) << this << " retrieved children: r=" << r << dendl;
 
     if (r == -ENOENT) {
@@ -118,7 +122,7 @@ protected:
                  << "in pool '" << m_pool.second << "'" << dendl;
       r = -EBUSY;
     }
-    C_AsyncObjectThrottle::finish(r);
+    C_AsyncObjectThrottle<I>::finish(r);
   }
 
 private:
@@ -132,19 +136,23 @@ private:
 
 } // anonymous namespace
 
-SnapshotUnprotectRequest::SnapshotUnprotectRequest(ImageCtx &image_ctx,
-                                               Context *on_finish,
-                                               const std::string &snap_name)
-  : Request(image_ctx, on_finish), m_snap_name(snap_name), m_ret_val(0),
+template <typename I>
+SnapshotUnprotectRequest<I>::SnapshotUnprotectRequest(I &image_ctx,
+                                                      Context *on_finish,
+                                                      const std::string &snap_name)
+  : Request<I>(image_ctx, on_finish), m_snap_name(snap_name), m_ret_val(0),
     m_snap_id(CEPH_NOSNAP) {
 }
 
-void SnapshotUnprotectRequest::send_op() {
+template <typename I>
+void SnapshotUnprotectRequest<I>::send_op() {
   send_unprotect_snap_start();
 }
 
-bool SnapshotUnprotectRequest::should_complete(int r) {
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool SnapshotUnprotectRequest<I>::should_complete(int r) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", "
                 << "r=" << r << dendl;
   if (r < 0) {
@@ -159,7 +167,7 @@ bool SnapshotUnprotectRequest::should_complete(int r) {
     return should_complete_error();
   }
 
-  RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+  RWLock::RLocker owner_lock(image_ctx.owner_lock);
   bool finished = false;
   switch (m_state) {
   case STATE_UNPROTECT_SNAP_START:
@@ -178,9 +186,11 @@ bool SnapshotUnprotectRequest::should_complete(int r) {
   return finished;
 }
 
-bool SnapshotUnprotectRequest::should_complete_error() {
-  RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+bool SnapshotUnprotectRequest<I>::should_complete_error() {
+  I &image_ctx = this->m_image_ctx;
+  RWLock::RLocker owner_locker(image_ctx.owner_lock);
+  CephContext *cct = image_ctx.cct;
   lderr(cct) << this << " " << __func__ << ": "
              << "ret_val=" << m_ret_val << dendl;
 
@@ -193,54 +203,59 @@ bool SnapshotUnprotectRequest::should_complete_error() {
   return finished;
 }
 
-void SnapshotUnprotectRequest::send_unprotect_snap_start() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotUnprotectRequest<I>::send_unprotect_snap_start() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
 
   m_state = STATE_UNPROTECT_SNAP_START;
 
   int r = verify_and_send_unprotect_snap_start();
   if (r < 0) {
-    async_complete(r);
+    this->async_complete(r);
     return;
   }
 }
 
-void SnapshotUnprotectRequest::send_scan_pool_children() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotUnprotectRequest<I>::send_scan_pool_children() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
   m_state = STATE_SCAN_POOL_CHILDREN;
 
   // search all pools for children depending on this snapshot
   // TODO add async version of wait_for_latest_osdmap
-  librados::Rados rados(m_image_ctx.md_ctx);
+  librados::Rados rados(image_ctx.md_ctx);
   rados.wait_for_latest_osdmap();
 
   // protect against pools being renamed/deleted
   std::list<Pool> pool_list;
   rados.pool_list2(pool_list);
 
-  parent_spec pspec(m_image_ctx.md_ctx.get_id(), m_image_ctx.id, m_snap_id);
+  parent_spec pspec(image_ctx.md_ctx.get_id(), image_ctx.id, m_snap_id);
   Pools pools(pool_list.begin(), pool_list.end());
 
-  Context *ctx = create_callback_context();
-  AsyncObjectThrottle<>::ContextFactory context_factory(
-    boost::lambda::bind(boost::lambda::new_ptr<C_ScanPoolChildren>(),
-      boost::lambda::_1, &m_image_ctx, pspec, pools, boost::lambda::_2));
-  AsyncObjectThrottle<> *throttle = new AsyncObjectThrottle<>(
-    this, m_image_ctx, context_factory, ctx, NULL, 0,
-    pools.size());
-  throttle->start_ops(m_image_ctx.concurrent_management_ops);
+  Context *ctx = this->create_callback_context();
+  typename AsyncObjectThrottle<I>::ContextFactory context_factory(
+    boost::lambda::bind(boost::lambda::new_ptr<C_ScanPoolChildren<I> >(),
+      boost::lambda::_1, &image_ctx, pspec, pools, boost::lambda::_2));
+  AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
+    this, image_ctx, context_factory, ctx, NULL, 0, pools.size());
+  throttle->start_ops(image_ctx.concurrent_management_ops);
 }
 
-void SnapshotUnprotectRequest::send_unprotect_snap_finish() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotUnprotectRequest<I>::send_unprotect_snap_finish() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
 
   m_state = STATE_UNPROTECT_SNAP_FINISH;
@@ -249,16 +264,18 @@ void SnapshotUnprotectRequest::send_unprotect_snap_finish() {
   cls_client::set_protection_status(&op, m_snap_id,
                                     RBD_PROTECTION_STATUS_UNPROTECTED);
 
-  librados::AioCompletion *comp = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op);
+  librados::AioCompletion *comp = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
   assert(r == 0);
   comp->release();
 }
 
-void SnapshotUnprotectRequest::send_unprotect_snap_rollback() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void SnapshotUnprotectRequest<I>::send_unprotect_snap_rollback() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " " << __func__ << dendl;
 
   m_state = STATE_UNPROTECT_SNAP_ROLLBACK;
@@ -267,29 +284,31 @@ void SnapshotUnprotectRequest::send_unprotect_snap_rollback() {
   cls_client::set_protection_status(&op, m_snap_id,
                                     RBD_PROTECTION_STATUS_PROTECTED);
 
-  librados::AioCompletion *comp = create_callback_completion();
-  int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op);
+  librados::AioCompletion *comp = this->create_callback_completion();
+  int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
   assert(r == 0);
   comp->release();
 }
 
-int SnapshotUnprotectRequest::verify_and_send_unprotect_snap_start() {
-  RWLock::RLocker md_locker(m_image_ctx.md_lock);
-  RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+template <typename I>
+int SnapshotUnprotectRequest<I>::verify_and_send_unprotect_snap_start() {
+  I &image_ctx = this->m_image_ctx;
+  RWLock::RLocker md_locker(image_ctx.md_lock);
+  RWLock::RLocker snap_locker(image_ctx.snap_lock);
 
-  CephContext *cct = m_image_ctx.cct;
-  if ((m_image_ctx.features & RBD_FEATURE_LAYERING) == 0) {
+  CephContext *cct = image_ctx.cct;
+  if ((image_ctx.features & RBD_FEATURE_LAYERING) == 0) {
     lderr(cct) << "image must support layering" << dendl;
     return -ENOSYS;
   }
 
-  m_snap_id = m_image_ctx.get_snap_id(m_snap_name);
+  m_snap_id = image_ctx.get_snap_id(m_snap_name);
   if (m_snap_id == CEPH_NOSNAP) {
     return -ENOENT;
   }
 
   bool is_unprotected;
-  int r = m_image_ctx.is_snap_unprotected(m_snap_id, &is_unprotected);
+  int r = image_ctx.is_snap_unprotected(m_snap_id, &is_unprotected);
   if (r < 0) {
     return r;
   }
@@ -303,8 +322,8 @@ int SnapshotUnprotectRequest::verify_and_send_unprotect_snap_start() {
   cls_client::set_protection_status(&op, m_snap_id,
                                     RBD_PROTECTION_STATUS_UNPROTECTING);
 
-  librados::AioCompletion *comp = create_callback_completion();
-  r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op);
+  librados::AioCompletion *comp = this->create_callback_completion();
+  r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
   assert(r == 0);
   comp->release();
 
@@ -315,3 +334,4 @@ int SnapshotUnprotectRequest::verify_and_send_unprotect_snap_start() {
 } // namespace operation
 } // namespace librbd
 
+template class librbd::operation::SnapshotUnprotectRequest<librbd::ImageCtx>;
index 3eacc3e71bec0965d562a847c41252f8de379e6c..3b940c3acb4e55c59abfeaad3d65ee47a8fdc080 100644 (file)
@@ -16,7 +16,8 @@ class ImageCtx;
 
 namespace operation {
 
-class SnapshotUnprotectRequest : public Request {
+template <typename ImageCtxT = ImageCtx>
+class SnapshotUnprotectRequest : public Request<ImageCtxT> {
 public:
   /**
    * Snap Unprotect goes through the following state machine:
@@ -49,7 +50,7 @@ public:
     STATE_UNPROTECT_SNAP_ROLLBACK
   };
 
-  SnapshotUnprotectRequest(ImageCtx &image_ctx, Context *on_finish,
+  SnapshotUnprotectRequest(ImageCtxT &image_ctx, Context *on_finish,
                           const std::string &snap_name);
 
 protected:
@@ -87,4 +88,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::SnapshotUnprotectRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_SNAPSHOT_UNPROTECT_REQUEST_H
index 71b1546ef6d2e3d428cfe6360ff1b18e03adab79..da5a3bb4bc3fa1b870b0d8a53e13e71ebe973963 100644 (file)
 namespace librbd {
 namespace operation {
 
-class C_CopyupObject : public C_AsyncObjectThrottle<> {
+template <typename I>
+class C_CopyupObject : public C_AsyncObjectThrottle<I> {
 public:
-  C_CopyupObject(AsyncObjectThrottle<> &throttle, ImageCtx *image_ctx,
+  C_CopyupObject(AsyncObjectThrottle<I> &throttle, I *image_ctx,
                  ::SnapContext snapc, uint64_t object_no)
-    : C_AsyncObjectThrottle(throttle, *image_ctx), m_snapc(snapc),
+    : C_AsyncObjectThrottle<I>(throttle, *image_ctx), m_snapc(snapc),
       m_object_no(object_no)
   {
   }
 
   virtual int send() {
-    assert(m_image_ctx.owner_lock.is_locked());
-    assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-           m_image_ctx.image_watcher->is_lock_owner());
+    I &image_ctx = this->m_image_ctx;
+    assert(image_ctx.owner_lock.is_locked());
+    assert(!image_ctx.image_watcher->is_lock_supported() ||
+           image_ctx.image_watcher->is_lock_owner());
 
-    string oid = m_image_ctx.get_object_name(m_object_no);
-    ldout(m_image_ctx.cct, 10) << "removing (with copyup) " << oid << dendl;
+    string oid = image_ctx.get_object_name(m_object_no);
+    ldout(image_ctx.cct, 10) << "removing (with copyup) " << oid << dendl;
 
-    AioObjectRequest *req = new AioObjectTrim(&m_image_ctx, oid, m_object_no,
+    AioObjectRequest *req = new AioObjectTrim(&image_ctx, oid, m_object_no,
                                               m_snapc, this);
     req->send();
     return 0;
@@ -52,28 +54,30 @@ private:
   uint64_t m_object_no;
 };
 
-class C_RemoveObject : public C_AsyncObjectThrottle<> {
+template <typename I>
+class C_RemoveObject : public C_AsyncObjectThrottle<I> {
 public:
-  C_RemoveObject(AsyncObjectThrottle<> &throttle, ImageCtx *image_ctx,
+  C_RemoveObject(AsyncObjectThrottle<I> &throttle, ImageCtx *image_ctx,
                  uint64_t object_no)
-    : C_AsyncObjectThrottle(throttle, *image_ctx), m_object_no(object_no)
+    : C_AsyncObjectThrottle<I>(throttle, *image_ctx), m_object_no(object_no)
   {
   }
 
   virtual int send() {
-    assert(m_image_ctx.owner_lock.is_locked());
-    assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-           m_image_ctx.image_watcher->is_lock_owner());
-    if (!m_image_ctx.object_map.object_may_exist(m_object_no)) {
+    I &image_ctx = this->m_image_ctx;
+    assert(image_ctx.owner_lock.is_locked());
+    assert(!image_ctx.image_watcher->is_lock_supported() ||
+           image_ctx.image_watcher->is_lock_owner());
+    if (!image_ctx.object_map.object_may_exist(m_object_no)) {
       return 1;
     }
 
-    string oid = m_image_ctx.get_object_name(m_object_no);
-    ldout(m_image_ctx.cct, 10) << "removing " << oid << dendl;
+    string oid = image_ctx.get_object_name(m_object_no);
+    ldout(image_ctx.cct, 10) << "removing " << oid << dendl;
 
     librados::AioCompletion *rados_completion =
       librados::Rados::aio_create_completion(this, NULL, rados_ctx_cb);
-    int r = m_image_ctx.data_ctx.aio_remove(oid, rados_completion);
+    int r = image_ctx.data_ctx.aio_remove(oid, rados_completion);
     assert(r == 0);
     rados_completion->release();
     return 0;
@@ -83,20 +87,21 @@ private:
   uint64_t m_object_no;
 };
 
-TrimRequest::TrimRequest(ImageCtx &image_ctx, Context *on_finish,
-                         uint64_t original_size, uint64_t new_size,
-                         ProgressContext &prog_ctx)
-  : AsyncRequest(image_ctx, on_finish), m_new_size(new_size),
+template <typename I>
+TrimRequest<I>::TrimRequest(I &image_ctx, Context *on_finish,
+                            uint64_t original_size, uint64_t new_size,
+                            ProgressContext &prog_ctx)
+  : AsyncRequest<I>(image_ctx, on_finish), m_new_size(new_size),
     m_prog_ctx(prog_ctx)
 {
-  uint64_t period = m_image_ctx.get_stripe_period();
+  uint64_t period = image_ctx.get_stripe_period();
   uint64_t new_num_periods = ((m_new_size + period - 1) / period);
   m_delete_off = MIN(new_num_periods * period, original_size);
   // first object we can delete free and clear
-  m_delete_start = new_num_periods * m_image_ctx.get_stripe_count();
-  m_num_objects = Striper::get_num_objects(m_image_ctx.layout, original_size);
+  m_delete_start = new_num_periods * image_ctx.get_stripe_count();
+  m_num_objects = Striper::get_num_objects(image_ctx.layout, original_size);
 
-  CephContext *cct = m_image_ctx.cct;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 10) << this << " trim image " << original_size << " -> "
                 << m_new_size << " periods " << new_num_periods
                  << " discard to offset " << m_delete_off
@@ -104,17 +109,18 @@ TrimRequest::TrimRequest(ImageCtx &image_ctx, Context *on_finish,
                  << " to " << m_num_objects << dendl;
 }
 
-
-bool TrimRequest::should_complete(int r)
+template <typename I>
+bool TrimRequest<I>::should_complete(int r)
 {
-  CephContext *cct = m_image_ctx.cct;
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
   ldout(cct, 5) << this << " should_complete: r=" << r << dendl;
   if (r < 0) {
     lderr(cct) << "trim encountered an error: " << cpp_strerror(r) << dendl;
     return true;
   }
 
-  RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
+  RWLock::RLocker owner_lock(image_ctx.owner_lock);
   switch (m_state) {
   case STATE_COPYUP_OBJECTS:
     ldout(cct, 5) << " COPYUP_OBJECTS" << dendl;
@@ -153,14 +159,17 @@ bool TrimRequest::should_complete(int r)
   return false;
 }
 
-void TrimRequest::send() {
+template <typename I>
+void TrimRequest<I>::send() {
   send_copyup_objects();
 }
 
-void TrimRequest::send_copyup_objects() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-         m_image_ctx.image_watcher->is_lock_owner());
+template <typename I>
+void TrimRequest<I>::send_copyup_objects() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  assert(!image_ctx.image_watcher->is_lock_supported() ||
+         image_ctx.image_watcher->is_lock_owner());
 
   if (m_delete_start >= m_num_objects) {
     send_clean_boundary();
@@ -171,18 +180,18 @@ void TrimRequest::send_copyup_objects() {
   bool has_snapshots;
   uint64_t parent_overlap;
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    RWLock::RLocker parent_locker(image_ctx.parent_lock);
 
-    snapc = m_image_ctx.snapc;
-    has_snapshots = !m_image_ctx.snaps.empty();
-    int r = m_image_ctx.get_parent_overlap(m_image_ctx.get_copyup_snap_id(),
+    snapc = image_ctx.snapc;
+    has_snapshots = !image_ctx.snaps.empty();
+    int r = image_ctx.get_parent_overlap(image_ctx.get_copyup_snap_id(),
                                            &parent_overlap);
     assert(r == 0);
   }
 
   // copyup is only required for portion of image that overlaps parent
-  uint64_t copyup_end = Striper::get_num_objects(m_image_ctx.layout,
+  uint64_t copyup_end = Striper::get_num_objects(image_ctx.layout,
                                                  parent_overlap);
   // TODO: protect against concurrent shrink and snap create?
   if (copyup_end <= m_delete_start || !has_snapshots) {
@@ -193,41 +202,45 @@ void TrimRequest::send_copyup_objects() {
   uint64_t copyup_start = m_delete_start;
   m_delete_start = copyup_end;
 
-  ldout(m_image_ctx.cct, 5) << this << " send_copyup_objects: "
+  ldout(image_ctx.cct, 5) << this << " send_copyup_objects: "
                            << " start object=" << copyup_start << ", "
                            << " end object=" << copyup_end << dendl;
   m_state = STATE_COPYUP_OBJECTS;
 
-  Context *ctx = create_callback_context();
-  AsyncObjectThrottle<>::ContextFactory context_factory(
-    boost::lambda::bind(boost::lambda::new_ptr<C_CopyupObject>(),
-      boost::lambda::_1, &m_image_ctx, snapc, boost::lambda::_2));
-  AsyncObjectThrottle<> *throttle = new AsyncObjectThrottle<>(
-    this, m_image_ctx, context_factory, ctx, &m_prog_ctx, copyup_start,
+  Context *ctx = this->create_callback_context();
+  typename AsyncObjectThrottle<I>::ContextFactory context_factory(
+    boost::lambda::bind(boost::lambda::new_ptr<C_CopyupObject<I> >(),
+      boost::lambda::_1, &image_ctx, snapc, boost::lambda::_2));
+  AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
+    this, image_ctx, context_factory, ctx, &m_prog_ctx, copyup_start,
     copyup_end);
-  throttle->start_ops(m_image_ctx.concurrent_management_ops);
+  throttle->start_ops(image_ctx.concurrent_management_ops);
 }
 
-void TrimRequest::send_remove_objects() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void TrimRequest<I>::send_remove_objects() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
-  ldout(m_image_ctx.cct, 5) << this << " send_remove_objects: "
+  ldout(image_ctx.cct, 5) << this << " send_remove_objects: "
                            << " delete_start=" << m_delete_start
                            << " num_objects=" << m_num_objects << dendl;
   m_state = STATE_REMOVE_OBJECTS;
 
-  Context *ctx = create_callback_context();
-  AsyncObjectThrottle<>::ContextFactory context_factory(
-    boost::lambda::bind(boost::lambda::new_ptr<C_RemoveObject>(),
-      boost::lambda::_1, &m_image_ctx, boost::lambda::_2));
-  AsyncObjectThrottle<> *throttle = new AsyncObjectThrottle<>(
-    this, m_image_ctx, context_factory, ctx, &m_prog_ctx, m_delete_start,
+  Context *ctx = this->create_callback_context();
+  typename AsyncObjectThrottle<I>::ContextFactory context_factory(
+    boost::lambda::bind(boost::lambda::new_ptr<C_RemoveObject<I> >(),
+      boost::lambda::_1, &image_ctx, boost::lambda::_2));
+  AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
+    this, image_ctx, context_factory, ctx, &m_prog_ctx, m_delete_start,
     m_num_objects);
-  throttle->start_ops(m_image_ctx.concurrent_management_ops);
+  throttle->start_ops(image_ctx.concurrent_management_ops);
 }
 
-void TrimRequest::send_pre_remove() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void TrimRequest<I>::send_pre_remove() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
   if (m_delete_start >= m_num_objects) {
     send_clean_boundary();
     return;
@@ -235,21 +248,21 @@ void TrimRequest::send_pre_remove() {
 
   bool remove_objects = false;
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    if (!m_image_ctx.object_map.enabled()) {
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    if (!image_ctx.object_map.enabled()) {
       remove_objects = true;
     } else {
-      ldout(m_image_ctx.cct, 5) << this << " send_pre_remove: "
+      ldout(image_ctx.cct, 5) << this << " send_pre_remove: "
                                << " delete_start=" << m_delete_start
                                << " num_objects=" << m_num_objects << dendl;
       m_state = STATE_PRE_REMOVE;
 
-      assert(m_image_ctx.image_watcher->is_lock_owner());
+      assert(image_ctx.image_watcher->is_lock_owner());
 
       // flag the objects as pending deletion
-      Context *ctx = create_callback_context();
-      RWLock::WLocker object_map_locker(m_image_ctx.object_map_lock);
-      if (!m_image_ctx.object_map.aio_update(m_delete_start, m_num_objects,
+      Context *ctx = this->create_callback_context();
+      RWLock::WLocker object_map_locker(image_ctx.object_map_lock);
+      if (!image_ctx.object_map.aio_update(m_delete_start, m_num_objects,
                                             OBJECT_PENDING, OBJECT_EXISTS,
                                              ctx)) {
         delete ctx;
@@ -265,26 +278,28 @@ void TrimRequest::send_pre_remove() {
   }
 }
 
-void TrimRequest::send_post_remove() {
-  assert(m_image_ctx.owner_lock.is_locked());
+template <typename I>
+void TrimRequest<I>::send_post_remove() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
 
   bool clean_boundary = false;
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    if (!m_image_ctx.object_map.enabled()) {
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    if (!image_ctx.object_map.enabled()) {
       clean_boundary = true;
     } else {
-      ldout(m_image_ctx.cct, 5) << this << " send_post_remove: "
+      ldout(image_ctx.cct, 5) << this << " send_post_remove: "
                                << " delete_start=" << m_delete_start
                                << " num_objects=" << m_num_objects << dendl;
       m_state = STATE_POST_REMOVE;
 
-      assert(m_image_ctx.image_watcher->is_lock_owner());
+      assert(image_ctx.image_watcher->is_lock_owner());
 
       // flag the pending objects as removed
-      Context *ctx = create_callback_context();
-      RWLock::WLocker object_map_locker(m_image_ctx.object_map_lock);
-      if (!m_image_ctx.object_map.aio_update(m_delete_start, m_num_objects,
+      Context *ctx = this->create_callback_context();
+      RWLock::WLocker object_map_locker(image_ctx.object_map_lock);
+      if (!image_ctx.object_map.aio_update(m_delete_start, m_num_objects,
                                             OBJECT_NONEXISTENT,
                                             OBJECT_PENDING, ctx)) {
         delete ctx;
@@ -300,37 +315,39 @@ void TrimRequest::send_post_remove() {
   }
 }
 
-void TrimRequest::send_clean_boundary() {
-  assert(m_image_ctx.owner_lock.is_locked());
-  CephContext *cct = m_image_ctx.cct;
+template <typename I>
+void TrimRequest<I>::send_clean_boundary() {
+  I &image_ctx = this->m_image_ctx;
+  assert(image_ctx.owner_lock.is_locked());
+  CephContext *cct = image_ctx.cct;
   if (m_delete_off <= m_new_size) {
     send_finish(0);
     return;
   }
 
   // should have been canceled prior to releasing lock
-  assert(!m_image_ctx.image_watcher->is_lock_supported() ||
-         m_image_ctx.image_watcher->is_lock_owner());
+  assert(!image_ctx.image_watcher->is_lock_supported() ||
+         image_ctx.image_watcher->is_lock_owner());
   uint64_t delete_len = m_delete_off - m_new_size;
-  ldout(m_image_ctx.cct, 5) << this << " send_clean_boundary: "
+  ldout(image_ctx.cct, 5) << this << " send_clean_boundary: "
                            << " delete_off=" << m_delete_off
                            << " length=" << delete_len << dendl;
   m_state = STATE_CLEAN_BOUNDARY;
 
   ::SnapContext snapc;
   {
-    RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
-    snapc = m_image_ctx.snapc;
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    snapc = image_ctx.snapc;
   }
 
   // discard the weird boundary
   std::vector<ObjectExtent> extents;
-  Striper::file_to_extents(cct, m_image_ctx.format_string,
-                          &m_image_ctx.layout, m_new_size, delete_len, 0,
+  Striper::file_to_extents(cct, image_ctx.format_string,
+                          &image_ctx.layout, m_new_size, delete_len, 0,
                            extents);
 
   ContextCompletion *completion =
-    new ContextCompletion(create_async_callback_context(), true);
+    new ContextCompletion(this->create_async_callback_context(), true);
   for (vector<ObjectExtent>::iterator p = extents.begin();
        p != extents.end(); ++p) {
     ldout(cct, 20) << " ex " << *p << dendl;
@@ -338,10 +355,10 @@ void TrimRequest::send_clean_boundary() {
 
     AioObjectRequest *req;
     if (p->offset == 0) {
-      req = new AioObjectTrim(&m_image_ctx, p->oid.name, p->objectno, snapc,
+      req = new AioObjectTrim(&image_ctx, p->oid.name, p->objectno, snapc,
                               req_comp);
     } else {
-      req = new AioObjectTruncate(&m_image_ctx, p->oid.name, p->objectno,
+      req = new AioObjectTruncate(&image_ctx, p->oid.name, p->objectno,
                                   p->offset, snapc, req_comp);
     }
     req->send();
@@ -349,10 +366,13 @@ void TrimRequest::send_clean_boundary() {
   completion->finish_adding_requests();
 }
 
-void TrimRequest::send_finish(int r) {
+template <typename I>
+void TrimRequest<I>::send_finish(int r) {
   m_state = STATE_FINISHED;
-  async_complete(r);
+  this->async_complete(r);
 }
 
 } // namespace operation
 } // namespace librbd
+
+template class librbd::operation::TrimRequest<librbd::ImageCtx>;
index d8b9358297ac4d43c3b2680681f2e4ce93908a27..6e6c50c9f4fc0b9c214005eed088618d0b2f7444 100644 (file)
@@ -13,12 +13,13 @@ class ProgressContext;
 
 namespace operation {
 
-class TrimRequest : public AsyncRequest<>
+template <typename ImageCtxT = ImageCtx>
+class TrimRequest : public AsyncRequest<ImageCtxT>
 {
 public:
-  TrimRequest(ImageCtx &image_ctx, Context *on_finish,
-                  uint64_t original_size, uint64_t new_size,
-                  ProgressContext &prog_ctx);
+  TrimRequest(ImageCtxT &image_ctx, Context *on_finish,
+             uint64_t original_size, uint64_t new_size,
+             ProgressContext &prog_ctx);
 
   virtual void send();
 
@@ -90,4 +91,6 @@ private:
 } // namespace operation
 } // namespace librbd
 
+extern template class librbd::operation::TrimRequest<librbd::ImageCtx>;
+
 #endif // CEPH_LIBRBD_OPERATION_TRIM_REQUEST_H