]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: use object map when doing snap rollback 23110/head
authorsongweibin <song.weibin@zte.com.cn>
Wed, 18 Jul 2018 02:22:25 +0000 (10:22 +0800)
committersongweibin <song.weibin@zte.com.cn>
Tue, 14 Aug 2018 08:07:19 +0000 (16:07 +0800)
If both the object of head and snapshot are not exist,
skip for this object.

Signed-off-by: songweibin <song.weibin@zte.com.cn>
src/librbd/operation/SnapshotRollbackRequest.cc
src/librbd/operation/SnapshotRollbackRequest.h
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc

index 7072e72ce599fe378b4e564500f8dd6bad06eab1..0bf166014709764a1b26922f60bcdc935ffe174b 100644 (file)
@@ -32,9 +32,12 @@ template <typename I>
 class C_RollbackObject : public C_AsyncObjectThrottle<I> {
 public:
   C_RollbackObject(AsyncObjectThrottle<I> &throttle, I *image_ctx,
-                   uint64_t snap_id, uint64_t object_num)
+                   uint64_t snap_id, uint64_t object_num,
+                   uint64_t head_num_objects,
+                   decltype(I::object_map) snap_object_map)
     : C_AsyncObjectThrottle<I>(throttle, *image_ctx), m_snap_id(snap_id),
-      m_object_num(object_num) {
+      m_object_num(object_num), m_head_num_objects(head_num_objects),
+      m_snap_object_map(snap_object_map) {
   }
 
   int send() override {
@@ -43,6 +46,16 @@ public:
     ldout(cct, 20) << "C_RollbackObject: " << __func__ << ": object_num="
                    << m_object_num << dendl;
 
+    {
+      RWLock::RLocker snap_locker(image_ctx.snap_lock);
+      if (m_object_num < m_head_num_objects &&
+          m_snap_object_map != nullptr &&
+          !m_snap_object_map->object_may_exist(m_object_num) &&
+          !image_ctx.object_map->object_may_exist(m_object_num)) {
+        return 1;
+      }
+    }
+
     std::string oid = image_ctx.get_object_name(m_object_num);
 
     librados::ObjectWriteOperation op;
@@ -58,6 +71,8 @@ public:
 private:
   uint64_t m_snap_id;
   uint64_t m_object_num;
+  uint64_t m_head_num_objects;
+  decltype(I::object_map) m_snap_object_map;
 };
 
 } // anonymous namespace
@@ -72,7 +87,8 @@ SnapshotRollbackRequest<I>::SnapshotRollbackRequest(I &image_ctx,
                                                     ProgressContext &prog_ctx)
   : Request<I>(image_ctx, on_finish), m_snap_namespace(snap_namespace),
     m_snap_name(snap_name), m_snap_id(snap_id),
-    m_snap_size(snap_size), m_prog_ctx(prog_ctx), m_object_map(nullptr) {
+    m_snap_size(snap_size), m_prog_ctx(prog_ctx),
+    m_object_map(nullptr), m_snap_object_map(nullptr) {
 }
 
 template <typename I>
@@ -82,6 +98,7 @@ SnapshotRollbackRequest<I>::~SnapshotRollbackRequest() {
     image_ctx.io_work_queue->unblock_writes();
   }
   delete m_object_map;
+  delete m_snap_object_map;
 }
 
 template <typename I>
@@ -127,8 +144,10 @@ void SnapshotRollbackRequest<I>::send_resize_image() {
     current_size = image_ctx.get_image_size(CEPH_NOSNAP);
   }
 
+  m_head_num_objects = Striper::get_num_objects(image_ctx.layout, current_size);
+
   if (current_size == m_snap_size) {
-    send_rollback_object_map();
+    send_get_snap_object_map();
     return;
   }
 
@@ -156,6 +175,54 @@ Context *SnapshotRollbackRequest<I>::handle_resize_image(int *result) {
     return this->create_context_finisher(*result);
   }
 
+  send_get_snap_object_map();
+  return nullptr;
+}
+
+template <typename I>
+void SnapshotRollbackRequest<I>::send_get_snap_object_map() {
+  I &image_ctx = this->m_image_ctx;
+
+  uint64_t flags = 0;
+  bool object_map_enabled;
+  CephContext *cct = image_ctx.cct;
+  {
+    RWLock::RLocker owner_locker(image_ctx.owner_lock);
+    RWLock::RLocker snap_locker(image_ctx.snap_lock);
+    object_map_enabled = (image_ctx.object_map != nullptr);
+    int r = image_ctx.get_flags(m_snap_id, &flags);
+    if (r < 0) {
+      object_map_enabled = false;
+    }
+  }
+  if (object_map_enabled &&
+      (flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) {
+    lderr(cct) << "warning: object-map is invalid for snapshot" << dendl;
+    object_map_enabled = false;
+  }
+  if (!object_map_enabled) {
+    send_rollback_object_map();
+    return;
+  }
+
+  ldout(cct, 5) << this << " " << __func__ << dendl;
+
+  m_snap_object_map = image_ctx.create_object_map(m_snap_id);
+
+  Context *ctx = create_context_callback<
+    SnapshotRollbackRequest<I>,
+    &SnapshotRollbackRequest<I>::handle_get_snap_object_map>(this);
+  m_snap_object_map->open(ctx);
+  return;
+}
+
+template <typename I>
+Context *SnapshotRollbackRequest<I>::handle_get_snap_object_map(int *result) {
+  I &image_ctx = this->m_image_ctx;
+  CephContext *cct = image_ctx.cct;
+  ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
+
+  assert(*result == 0);
   send_rollback_object_map();
   return nullptr;
 }
@@ -213,7 +280,8 @@ void SnapshotRollbackRequest<I>::send_rollback_objects() {
     &SnapshotRollbackRequest<I>::handle_rollback_objects>(this);
   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));
+      boost::lambda::_1, &image_ctx, m_snap_id, boost::lambda::_2,
+      m_head_num_objects, m_snap_object_map));
   AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
     this, image_ctx, context_factory, ctx, &m_prog_ctx, 0, num_objects);
   throttle->start_ops(image_ctx.concurrent_management_ops);
index a32a84dc27b0cf504ddc8d16b968bb28681314d5..e58a618f2ecf47c6da19d48df7c6bf9f24663f6e 100644 (file)
@@ -35,6 +35,9 @@ public:
    *            STATE_RESIZE_IMAGE (skip if resize not
    *                  |             required)
    *                  v
+   *            STATE_GET_SNAP_OBJECT_MAP (skip if object)
+   *                  |                    map disabled)
+   *                  v
    *            STATE_ROLLBACK_OBJECT_MAP (skip if object
    *                  |                    map disabled)
    *                  v
@@ -78,12 +81,14 @@ private:
   std::string m_snap_name;
   uint64_t m_snap_id;
   uint64_t m_snap_size;
+  uint64_t m_head_num_objects;
   ProgressContext &m_prog_ctx;
 
   NoOpProgressContext m_no_op_prog_ctx;
 
   bool m_blocking_writes = false;
   decltype(ImageCtxT::object_map) m_object_map;
+  decltype(ImageCtxT::object_map) m_snap_object_map;
 
   void send_block_writes();
   Context *handle_block_writes(int *result);
@@ -91,6 +96,9 @@ private:
   void send_resize_image();
   Context *handle_resize_image(int *result);
 
+  void send_get_snap_object_map();
+  Context *handle_get_snap_object_map(int *result);
+
   void send_rollback_object_map();
   Context *handle_rollback_object_map(int *result);
 
index 44ade806c755c0143aa5faeb5aee5db2bdaffd55..17fa29b837031a3087946a052ee499926005d740 100644 (file)
@@ -156,6 +156,8 @@ struct MockImageCtx {
   MOCK_CONST_METHOD1(get_image_size, uint64_t(librados::snap_t));
   MOCK_CONST_METHOD1(get_object_count, uint64_t(librados::snap_t));
   MOCK_CONST_METHOD1(get_read_flags, int(librados::snap_t));
+  MOCK_CONST_METHOD2(get_flags, int(librados::snap_t in_snap_id,
+                     uint64_t *flags));
   MOCK_CONST_METHOD2(get_snap_id,
                     librados::snap_t(cls::rbd::SnapshotNamespace snap_namespace,
                                      std::string in_snap_name));
index e41b795a1a32f87a3f77281c8e826265c61281ed..1d849928f52cffc9e0a45b8ff965ee78aefa1baa 100644 (file)
@@ -108,6 +108,30 @@ public:
                                           &mock_image_ctx));
   }
 
+  void expect_get_flags(MockOperationImageCtx &mock_image_ctx,
+                        uint64_t snap_id, int r) {
+    EXPECT_CALL(mock_image_ctx, get_flags(snap_id, _))
+                  .WillOnce(Return(r));
+  }
+
+  void expect_object_may_exist(MockOperationImageCtx &mock_image_ctx,
+                               uint64_t object_no, bool exists) {
+    if (mock_image_ctx.object_map != nullptr) {
+      EXPECT_CALL(*mock_image_ctx.object_map, object_may_exist(object_no))
+                    .WillOnce(Return(exists));
+    }
+  }
+
+  void expect_get_snap_object_map(MockOperationImageCtx &mock_image_ctx,
+                                  MockObjectMap *mock_object_map, uint64_t snap_id) {
+    if (mock_image_ctx.object_map != nullptr) {
+      EXPECT_CALL(mock_image_ctx, create_object_map(snap_id))
+                    .WillOnce(Return(mock_object_map));
+      EXPECT_CALL(*mock_object_map, open(_))
+                    .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
+    }
+  }
+
   void expect_rollback_object_map(MockOperationImageCtx &mock_image_ctx,
                                   MockObjectMap &mock_object_map) {
     if (mock_image_ctx.object_map != nullptr) {
@@ -136,6 +160,7 @@ public:
 
   void expect_rollback(MockOperationImageCtx &mock_image_ctx, int r) {
     expect_get_current_size(mock_image_ctx, 1);
+    expect_object_may_exist(mock_image_ctx, 0, true);
     expect_get_object_name(mock_image_ctx, 0);
     expect_rollback_snap_id(mock_image_ctx, "object-name-0", r);
   }
@@ -190,6 +215,7 @@ TEST_F(TestMockOperationSnapshotRollbackRequest, Success) {
   MockExclusiveLock mock_exclusive_lock;
   MockJournal mock_journal;
   MockObjectMap *mock_object_map = new MockObjectMap();
+  MockObjectMap *mock_snap_object_map = new MockObjectMap();
   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
                       *mock_object_map);
   expect_op_work_queue(mock_image_ctx);
@@ -199,6 +225,8 @@ TEST_F(TestMockOperationSnapshotRollbackRequest, Success) {
   expect_append_op_event(mock_image_ctx, false, 0);
   expect_block_writes(mock_image_ctx, 0);
   expect_resize(mock_image_ctx, mock_resize_request, 0);
+  expect_get_flags(mock_image_ctx, 123, 0);
+  expect_get_snap_object_map(mock_image_ctx, mock_snap_object_map, 123);
   expect_rollback_object_map(mock_image_ctx, *mock_object_map);
   expect_rollback(mock_image_ctx, 0);
   expect_refresh_object_map(mock_image_ctx, *mock_object_map);
@@ -236,6 +264,7 @@ TEST_F(TestMockOperationSnapshotRollbackRequest, SkipResize) {
   MockExclusiveLock mock_exclusive_lock;
   MockJournal mock_journal;
   MockObjectMap *mock_object_map = new MockObjectMap();
+  MockObjectMap *mock_snap_object_map = new MockObjectMap();
   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
                       *mock_object_map);
   expect_op_work_queue(mock_image_ctx);
@@ -244,6 +273,8 @@ TEST_F(TestMockOperationSnapshotRollbackRequest, SkipResize) {
   expect_append_op_event(mock_image_ctx, false, 0);
   expect_block_writes(mock_image_ctx, 0);
   expect_get_image_size(mock_image_ctx, 345);
+  expect_get_flags(mock_image_ctx, 123, 0);
+  expect_get_snap_object_map(mock_image_ctx, mock_snap_object_map, 123);
   expect_rollback_object_map(mock_image_ctx, *mock_object_map);
   expect_rollback(mock_image_ctx, 0);
   expect_refresh_object_map(mock_image_ctx, *mock_object_map);
@@ -283,6 +314,7 @@ TEST_F(TestMockOperationSnapshotRollbackRequest, RollbackObjectsError) {
   MockExclusiveLock mock_exclusive_lock;
   MockJournal mock_journal;
   MockObjectMap mock_object_map;
+  MockObjectMap *mock_snap_object_map = new MockObjectMap();
   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
                       mock_object_map);
   expect_op_work_queue(mock_image_ctx);
@@ -292,6 +324,8 @@ TEST_F(TestMockOperationSnapshotRollbackRequest, RollbackObjectsError) {
   expect_append_op_event(mock_image_ctx, false, 0);
   expect_block_writes(mock_image_ctx, 0);
   expect_resize(mock_image_ctx, mock_resize_request, 0);
+  expect_get_flags(mock_image_ctx, 123, 0);
+  expect_get_snap_object_map(mock_image_ctx, mock_snap_object_map, 123);
   expect_rollback_object_map(mock_image_ctx, mock_object_map);
   expect_rollback(mock_image_ctx, -EINVAL);
   expect_commit_op_event(mock_image_ctx, -EINVAL);
@@ -308,6 +342,7 @@ TEST_F(TestMockOperationSnapshotRollbackRequest, InvalidateCacheError) {
   MockExclusiveLock mock_exclusive_lock;
   MockJournal mock_journal;
   MockObjectMap *mock_object_map = new MockObjectMap();
+  MockObjectMap *mock_snap_object_map = new MockObjectMap();
   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
                       *mock_object_map);
   expect_op_work_queue(mock_image_ctx);
@@ -317,6 +352,8 @@ TEST_F(TestMockOperationSnapshotRollbackRequest, InvalidateCacheError) {
   expect_append_op_event(mock_image_ctx, false, 0);
   expect_block_writes(mock_image_ctx, 0);
   expect_resize(mock_image_ctx, mock_resize_request, 0);
+  expect_get_flags(mock_image_ctx, 123, 0);
+  expect_get_snap_object_map(mock_image_ctx, mock_snap_object_map, 123);
   expect_rollback_object_map(mock_image_ctx, *mock_object_map);
   expect_rollback(mock_image_ctx, 0);
   expect_refresh_object_map(mock_image_ctx, *mock_object_map);