#include "librbd/Utils.h"
#include "librbd/io/AioCompletion.h"
#include "librbd/io/ReadResult.h"
-#include "librbd/migration/FileStream.h"
+#include "librbd/migration/SnapshotInterface.h"
#include "librbd/migration/SourceSpecBuilder.h"
-#include "librbd/migration/StreamInterface.h"
-
-#define dout_subsys ceph_subsys_rbd
-#undef dout_prefix
-#define dout_prefix *_dout << "librbd::migration::RawFormat: " << this \
- << " " << __func__ << ": "
namespace librbd {
namespace migration {
#define dout_subsys ceph_subsys_rbd
-#undef dout_prefix
-#define dout_prefix *_dout << "librbd::migration::RawFormat::OpenRequest " \
- << this << " " << __func__ << ": "
-
-template <typename I>
-struct RawFormat<I>::OpenRequest {
- RawFormat* raw_format;
- Context* on_finish;
-
- uint64_t image_size = 0;
-
- OpenRequest(RawFormat* raw_format, Context* on_finish)
- : raw_format(raw_format), on_finish(on_finish) {
- }
-
- void send() {
- open_stream();
- }
-
- void open_stream() {
- auto cct = raw_format->m_image_ctx->cct;
- ldout(cct, 10) << dendl;
-
- auto ctx = util::create_context_callback<
- OpenRequest, &OpenRequest::handle_open_stream>(this);
- raw_format->m_stream->open(ctx);
- }
-
- void handle_open_stream(int r) {
- auto cct = raw_format->m_image_ctx->cct;
- ldout(cct, 10) << "r=" << r << dendl;
-
- if (r < 0) {
- lderr(cct) << "failed to open stream: " << cpp_strerror(r) << dendl;
- finish(r);
- return;
- }
-
- get_image_size();
- }
-
- void get_image_size() {
- auto cct = raw_format->m_image_ctx->cct;
- ldout(cct, 10) << dendl;
-
- auto ctx = util::create_context_callback<
- OpenRequest, &OpenRequest::handle_get_image_size>(this);
- raw_format->get_image_size(CEPH_NOSNAP, &image_size, ctx);
- }
-
- void handle_get_image_size(int r) {
- auto cct = raw_format->m_image_ctx->cct;
- ldout(cct, 10) << "r=" << r << dendl;
-
- if (r < 0) {
- lderr(cct) << "failed to open stream: " << cpp_strerror(r) << dendl;
- finish(r);
- return;
- }
-
- raw_format->m_image_ctx->image_lock.lock();
- raw_format->m_image_ctx->size = image_size;
- raw_format->m_image_ctx->image_lock.unlock();
-
- finish(0);
- }
-
- void finish(int r) {
- auto cct = raw_format->m_image_ctx->cct;
- ldout(cct, 10) << "r=" << r << dendl;
-
- if (r < 0) {
- raw_format->m_image_ctx->state->close(new LambdaContext(
- [r, on_finish=on_finish](int _) { on_finish->complete(r); }));
- } else {
- on_finish->complete(0);
- }
-
- delete this;
- }
-};
-
#undef dout_prefix
#define dout_prefix *_dout << "librbd::migration::RawFormat: " << this \
<< " " << __func__ << ": "
auto cct = m_image_ctx->cct;
ldout(cct, 10) << dendl;
- int r = m_source_spec_builder->build_stream(m_json_object, &m_stream);
+ on_finish = new LambdaContext([this, on_finish](int r) {
+ handle_open(r, on_finish); });
+
+ // treat the base image as a HEAD-revision snapshot
+ int r = m_source_spec_builder->build_snapshot(m_json_object, CEPH_NOSNAP,
+ &m_snapshots[CEPH_NOSNAP]);
+ if (r < 0) {
+ lderr(cct) << "failed to build HEAD revision handler: " << cpp_strerror(r)
+ << dendl;
+ on_finish->complete(r);
+ return;
+ }
+
+ auto gather_ctx = new C_Gather(cct, on_finish);
+ SnapshotInterface* previous_snapshot = nullptr;
+ for (auto& [_, snapshot] : m_snapshots) {
+ snapshot->open(previous_snapshot, gather_ctx->new_sub());
+ previous_snapshot = snapshot.get();
+ }
+ gather_ctx->activate();
+}
+
+template <typename I>
+void RawFormat<I>::handle_open(int r, Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 10) << "r=" << r << dendl;
+
if (r < 0) {
- lderr(cct) << "failed to build migration stream handler" << cpp_strerror(r)
+ lderr(cct) << "failed to open raw image: " << cpp_strerror(r)
<< dendl;
- m_image_ctx->state->close(
- new LambdaContext([r, on_finish](int _) { on_finish->complete(r); }));
+ m_image_ctx->state->close(new LambdaContext(
+ [r, on_finish=on_finish](int _) { on_finish->complete(r); }));
return;
}
- auto req = new OpenRequest(this, on_finish);
- req->send();
+ auto head_snapshot = m_snapshots[CEPH_NOSNAP];
+ ceph_assert(head_snapshot);
+
+ m_image_ctx->image_lock.lock();
+ m_image_ctx->size = head_snapshot->get_snap_info().size;
+ m_image_ctx->image_lock.unlock();
+ on_finish->complete(0);
}
template <typename I>
auto cct = m_image_ctx->cct;
ldout(cct, 10) << dendl;
- if (!m_stream) {
- on_finish->complete(0);
- return;
+ auto gather_ctx = new C_Gather(cct, on_finish);
+ for (auto& [snap_id, snapshot] : m_snapshots) {
+ snapshot->close(gather_ctx->new_sub());
}
- m_stream->close(on_finish);
+ gather_ctx->activate();
}
template <typename I>
ldout(cct, 10) << dendl;
snap_infos->clear();
+ for (auto& [snap_id, snapshot] : m_snapshots) {
+ if (snap_id == CEPH_NOSNAP) {
+ continue;
+ }
+ snap_infos->emplace(snap_id, snapshot->get_snap_info());
+ }
on_finish->complete(0);
}
auto cct = m_image_ctx->cct;
ldout(cct, 10) << dendl;
- if (snap_id != CEPH_NOSNAP) {
- on_finish->complete(-EINVAL);
+ auto snapshot_it = m_snapshots.find(snap_id);
+ if (snapshot_it == m_snapshots.end()) {
+ on_finish->complete(-ENOENT);
return;
}
- m_stream->get_size(size, on_finish);
+ *size = snapshot_it->second->get_snap_info().size;
+ on_finish->complete(0);
}
template <typename I>
auto cct = m_image_ctx->cct;
ldout(cct, 20) << "image_extents=" << image_extents << dendl;
- if (snap_id != CEPH_NOSNAP) {
- aio_comp->fail(-EINVAL);
+ auto snapshot_it = m_snapshots.find(snap_id);
+ if (snapshot_it == m_snapshots.end()) {
+ aio_comp->fail(-ENOENT);
return true;
}
- aio_comp->read_result = std::move(read_result);
- aio_comp->read_result.set_image_extents(image_extents);
-
- aio_comp->set_request_count(1);
- auto ctx = new io::ReadResult::C_ImageReadRequest(aio_comp,
- 0, image_extents);
-
- // raw directly maps the image-extent IO down to a byte IO extent
- m_stream->read(std::move(image_extents), &ctx->bl, ctx);
+ snapshot_it->second->read(aio_comp, std::move(image_extents),
+ std::move(read_result), op_flags, read_flags,
+ parent_trace);
return true;
}
#include "test/librbd/test_mock_fixture.h"
#include "test/librbd/test_support.h"
-#include "test/librbd/mock/migration/MockStreamInterface.h"
+#include "test/librbd/mock/migration/MockSnapshotInterface.h"
#include "include/rbd_types.h"
#include "common/ceph_mutex.h"
-#include "librbd/migration/FileStream.h"
#include "librbd/migration/RawFormat.h"
#include "librbd/migration/SourceSpecBuilder.h"
#include "gtest/gtest.h"
template<>
struct SourceSpecBuilder<librbd::MockTestImageCtx> {
- MOCK_CONST_METHOD2(build_stream, int(const json_spirit::mObject&,
- std::shared_ptr<StreamInterface>*));
+ MOCK_CONST_METHOD3(build_snapshot, int(const json_spirit::mObject&, uint64_t,
+ std::shared_ptr<SnapshotInterface>*));
};
using ::testing::_;
using ::testing::InSequence;
using ::testing::Invoke;
+using ::testing::ReturnRef;
+using ::testing::WithArg;
using ::testing::WithArgs;
namespace librbd {
json_object["stream"] = stream_obj;
}
- void expect_build_stream(MockSourceSpecBuilder& mock_source_spec_builder,
- MockStreamInterface* mock_stream_interface, int r) {
- EXPECT_CALL(mock_source_spec_builder, build_stream(_, _))
- .WillOnce(WithArgs<1>(Invoke([mock_stream_interface, r]
- (std::shared_ptr<StreamInterface>* ptr) {
- ptr->reset(mock_stream_interface);
+ void expect_build_snapshot(MockSourceSpecBuilder& mock_source_spec_builder,
+ uint64_t index,
+ MockSnapshotInterface* mock_snapshot_interface,
+ int r) {
+ EXPECT_CALL(mock_source_spec_builder, build_snapshot(_, index, _))
+ .WillOnce(WithArgs<2>(Invoke([mock_snapshot_interface, r]
+ (std::shared_ptr<SnapshotInterface>* ptr) {
+ ptr->reset(mock_snapshot_interface);
return r;
})));
}
- void expect_stream_open(MockStreamInterface& mock_stream_interface, int r) {
- EXPECT_CALL(mock_stream_interface, open(_))
- .WillOnce(Invoke([r](Context* ctx) { ctx->complete(r); }));
+ void expect_snapshot_open(MockSnapshotInterface& mock_snapshot_interface,
+ int r) {
+ EXPECT_CALL(mock_snapshot_interface, open(_, _))
+ .WillOnce(WithArg<1>(Invoke([r](Context* ctx) { ctx->complete(r); })));
}
- void expect_stream_close(MockStreamInterface& mock_stream_interface, int r) {
- EXPECT_CALL(mock_stream_interface, close(_))
+ void expect_snapshot_close(MockSnapshotInterface& mock_snapshot_interface,
+ int r) {
+ EXPECT_CALL(mock_snapshot_interface, close(_))
.WillOnce(Invoke([r](Context* ctx) { ctx->complete(r); }));
}
- void expect_stream_get_size(MockStreamInterface& mock_stream_interface,
- uint64_t size, int r) {
- EXPECT_CALL(mock_stream_interface, get_size(_, _))
- .WillOnce(Invoke([size, r](uint64_t* out_size, Context* ctx) {
- *out_size = size;
- ctx->complete(r);
- }));
+ void expect_snapshot_get_info(MockSnapshotInterface& mock_snapshot_interface,
+ const SnapInfo& snap_info) {
+ EXPECT_CALL(mock_snapshot_interface, get_snap_info())
+ .WillOnce(ReturnRef(snap_info));
}
- void expect_stream_read(MockStreamInterface& mock_stream_interface,
- const io::Extents& byte_extents,
- const bufferlist& bl, int r) {
- EXPECT_CALL(mock_stream_interface, read(byte_extents, _, _))
- .WillOnce(WithArgs<1, 2>(Invoke([bl, r]
- (bufferlist* out_bl, Context* ctx) {
- *out_bl = bl;
+ void expect_snapshot_read(MockSnapshotInterface& mock_snapshot_interface,
+ const io::Extents& image_extents,
+ const bufferlist& bl, int r) {
+ EXPECT_CALL(mock_snapshot_interface, read(_, image_extents, _))
+ .WillOnce(WithArgs<0, 2>(Invoke([bl, image_extents, r]
+ (io::AioCompletion* aio_comp, io::ReadResult& read_result) {
+ aio_comp->read_result = std::move(read_result);
+ aio_comp->read_result.set_image_extents(image_extents);
+ aio_comp->set_request_count(1);
+ auto ctx = new io::ReadResult::C_ImageReadRequest(aio_comp, 0,
+ image_extents);
+ ctx->bl = std::move(bl);
ctx->complete(r);
})));
}
InSequence seq;
MockSourceSpecBuilder mock_source_spec_builder;
- auto mock_stream_interface = new MockStreamInterface();
- expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0);
+ auto mock_snapshot_interface = new MockSnapshotInterface();
+ expect_build_snapshot(mock_source_spec_builder, CEPH_NOSNAP,
+ mock_snapshot_interface, 0);
- expect_stream_open(*mock_stream_interface, 0);
- expect_stream_get_size(*mock_stream_interface, 0, 0);
+ expect_snapshot_open(*mock_snapshot_interface, 0);
+ SnapInfo snap_info{{}, {}, 123, {}, 0, 0, {}};
+ expect_snapshot_get_info(*mock_snapshot_interface, snap_info);
- expect_stream_close(*mock_stream_interface, 0);
+ expect_snapshot_close(*mock_snapshot_interface, 0);
MockRawFormat mock_raw_format(&mock_image_ctx, json_object,
&mock_source_spec_builder);
InSequence seq;
MockSourceSpecBuilder mock_source_spec_builder;
- auto mock_stream_interface = new MockStreamInterface();
- expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0);
+ auto mock_snapshot_interface = new MockSnapshotInterface();
+ expect_build_snapshot(mock_source_spec_builder, CEPH_NOSNAP,
+ mock_snapshot_interface, 0);
- expect_stream_open(*mock_stream_interface, -ENOENT);
+ expect_snapshot_open(*mock_snapshot_interface, -ENOENT);
expect_close(mock_image_ctx, 0);
InSequence seq;
MockSourceSpecBuilder mock_source_spec_builder;
- auto mock_stream_interface = new MockStreamInterface();
- expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0);
+ auto mock_snapshot_interface = new MockSnapshotInterface();
+ expect_build_snapshot(mock_source_spec_builder, CEPH_NOSNAP,
+ mock_snapshot_interface, 0);
- expect_stream_open(*mock_stream_interface, 0);
- expect_stream_get_size(*mock_stream_interface, 0, 0);
+ expect_snapshot_open(*mock_snapshot_interface, 0);
+ SnapInfo snap_info{{}, {}, 123, {}, 0, 0, {}};
+ expect_snapshot_get_info(*mock_snapshot_interface, snap_info);
- expect_stream_close(*mock_stream_interface, 0);
+ expect_snapshot_close(*mock_snapshot_interface, 0);
MockRawFormat mock_raw_format(&mock_image_ctx, json_object,
&mock_source_spec_builder);
InSequence seq;
MockSourceSpecBuilder mock_source_spec_builder;
- auto mock_stream_interface = new MockStreamInterface();
- expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0);
+ auto mock_snapshot_interface = new MockSnapshotInterface();
+ expect_build_snapshot(mock_source_spec_builder, CEPH_NOSNAP,
+ mock_snapshot_interface, 0);
- expect_stream_open(*mock_stream_interface, 0);
- expect_stream_get_size(*mock_stream_interface, 0, 0);
+ expect_snapshot_open(*mock_snapshot_interface, 0);
+ SnapInfo snap_info{{}, {}, 123, {}, 0, 0, {}};
+ expect_snapshot_get_info(*mock_snapshot_interface, snap_info);
- expect_stream_get_size(*mock_stream_interface, 123, 0);
+ expect_snapshot_get_info(*mock_snapshot_interface, snap_info);
- expect_stream_close(*mock_stream_interface, 0);
+ expect_snapshot_close(*mock_snapshot_interface, 0);
MockRawFormat mock_raw_format(&mock_image_ctx, json_object,
&mock_source_spec_builder);
ASSERT_EQ(0, ctx3.wait());
}
-TEST_F(TestMockMigrationRawFormat, GetImageSizeSnapshot) {
+TEST_F(TestMockMigrationRawFormat, GetImageSizeSnapshotDNE) {
MockTestImageCtx mock_image_ctx(*m_image_ctx);
InSequence seq;
MockSourceSpecBuilder mock_source_spec_builder;
- auto mock_stream_interface = new MockStreamInterface();
- expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0);
+ auto mock_snapshot_interface = new MockSnapshotInterface();
+ expect_build_snapshot(mock_source_spec_builder, CEPH_NOSNAP,
+ mock_snapshot_interface, 0);
- expect_stream_open(*mock_stream_interface, 0);
- expect_stream_get_size(*mock_stream_interface, 0, 0);
+ expect_snapshot_open(*mock_snapshot_interface, 0);
+ SnapInfo snap_info{{}, {}, 123, {}, 0, 0, {}};
+ expect_snapshot_get_info(*mock_snapshot_interface, snap_info);
- expect_stream_close(*mock_stream_interface, 0);
+ expect_snapshot_close(*mock_snapshot_interface, 0);
MockRawFormat mock_raw_format(&mock_image_ctx, json_object,
&mock_source_spec_builder);
C_SaferCond ctx2;
uint64_t size;
mock_raw_format.get_image_size(0, &size, &ctx2);
- ASSERT_EQ(-EINVAL, ctx2.wait());
+ ASSERT_EQ(-ENOENT, ctx2.wait());
C_SaferCond ctx3;
mock_raw_format.close(&ctx3);
InSequence seq;
MockSourceSpecBuilder mock_source_spec_builder;
- auto mock_stream_interface = new MockStreamInterface();
- expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0);
+ auto mock_snapshot_interface = new MockSnapshotInterface();
+ expect_build_snapshot(mock_source_spec_builder, CEPH_NOSNAP,
+ mock_snapshot_interface, 0);
- expect_stream_open(*mock_stream_interface, 0);
- expect_stream_get_size(*mock_stream_interface, 0, 0);
+ expect_snapshot_open(*mock_snapshot_interface, 0);
+ SnapInfo snap_info{{}, {}, 123, {}, 0, 0, {}};
+ expect_snapshot_get_info(*mock_snapshot_interface, snap_info);
bufferlist expect_bl;
expect_bl.append(std::string(123, '1'));
- expect_stream_read(*mock_stream_interface, {{123, 123}}, expect_bl, 0);
+ expect_snapshot_read(*mock_snapshot_interface, {{123, 123}}, expect_bl, 0);
- expect_stream_close(*mock_stream_interface, 0);
+ expect_snapshot_close(*mock_snapshot_interface, 0);
MockRawFormat mock_raw_format(&mock_image_ctx, json_object,
&mock_source_spec_builder);
InSequence seq;
MockSourceSpecBuilder mock_source_spec_builder;
- auto mock_stream_interface = new MockStreamInterface();
- expect_build_stream(mock_source_spec_builder, mock_stream_interface, 0);
+ auto mock_snapshot_interface = new MockSnapshotInterface();
+ expect_build_snapshot(mock_source_spec_builder, CEPH_NOSNAP,
+ mock_snapshot_interface, 0);
- expect_stream_open(*mock_stream_interface, 0);
- expect_stream_get_size(*mock_stream_interface, 0, 0);
+ expect_snapshot_open(*mock_snapshot_interface, 0);
+ SnapInfo snap_info{{}, {}, 123, {}, 0, 0, {}};
+ expect_snapshot_get_info(*mock_snapshot_interface, snap_info);
- expect_stream_close(*mock_stream_interface, 0);
+ expect_snapshot_close(*mock_snapshot_interface, 0);
MockRawFormat mock_raw_format(&mock_image_ctx, json_object,
&mock_source_spec_builder);