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 {
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;
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
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>
image_ctx.io_work_queue->unblock_writes();
}
delete m_object_map;
+ delete m_snap_object_map;
}
template <typename I>
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;
}
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;
}
&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);
&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) {
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);
}
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);
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);
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);
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);
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);
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);
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);
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);