From 837417a69049dfcf3723881dc01783810b855de5 Mon Sep 17 00:00:00 2001 From: songweibin Date: Wed, 18 Jul 2018 10:22:25 +0800 Subject: [PATCH] librbd: use object map when doing snap rollback If both the object of head and snapshot are not exist, skip for this object. Signed-off-by: songweibin --- .../operation/SnapshotRollbackRequest.cc | 78 +++++++++++++++++-- .../operation/SnapshotRollbackRequest.h | 8 ++ src/test/librbd/mock/MockImageCtx.h | 2 + .../test_mock_SnapshotRollbackRequest.cc | 37 +++++++++ 4 files changed, 120 insertions(+), 5 deletions(-) diff --git a/src/librbd/operation/SnapshotRollbackRequest.cc b/src/librbd/operation/SnapshotRollbackRequest.cc index 7072e72ce599f..0bf1660147097 100644 --- a/src/librbd/operation/SnapshotRollbackRequest.cc +++ b/src/librbd/operation/SnapshotRollbackRequest.cc @@ -32,9 +32,12 @@ template class C_RollbackObject : public C_AsyncObjectThrottle { public: C_RollbackObject(AsyncObjectThrottle &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(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::SnapshotRollbackRequest(I &image_ctx, ProgressContext &prog_ctx) : Request(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 @@ -82,6 +98,7 @@ SnapshotRollbackRequest::~SnapshotRollbackRequest() { image_ctx.io_work_queue->unblock_writes(); } delete m_object_map; + delete m_snap_object_map; } template @@ -127,8 +144,10 @@ void SnapshotRollbackRequest::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::handle_resize_image(int *result) { return this->create_context_finisher(*result); } + send_get_snap_object_map(); + return nullptr; +} + +template +void SnapshotRollbackRequest::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, + &SnapshotRollbackRequest::handle_get_snap_object_map>(this); + m_snap_object_map->open(ctx); + return; +} + +template +Context *SnapshotRollbackRequest::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::send_rollback_objects() { &SnapshotRollbackRequest::handle_rollback_objects>(this); typename AsyncObjectThrottle::ContextFactory context_factory( boost::lambda::bind(boost::lambda::new_ptr >(), - 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 *throttle = new AsyncObjectThrottle( this, image_ctx, context_factory, ctx, &m_prog_ctx, 0, num_objects); throttle->start_ops(image_ctx.concurrent_management_ops); diff --git a/src/librbd/operation/SnapshotRollbackRequest.h b/src/librbd/operation/SnapshotRollbackRequest.h index a32a84dc27b0c..e58a618f2ecf4 100644 --- a/src/librbd/operation/SnapshotRollbackRequest.h +++ b/src/librbd/operation/SnapshotRollbackRequest.h @@ -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); diff --git a/src/test/librbd/mock/MockImageCtx.h b/src/test/librbd/mock/MockImageCtx.h index 44ade806c755c..17fa29b837031 100644 --- a/src/test/librbd/mock/MockImageCtx.h +++ b/src/test/librbd/mock/MockImageCtx.h @@ -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)); diff --git a/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc b/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc index e41b795a1a32f..1d849928f52cf 100644 --- a/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc +++ b/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc @@ -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); -- 2.39.5