X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Ftest%2Frbd_mirror%2Ftest_ImageSync.cc;fp=src%2Fceph%2Fsrc%2Ftest%2Frbd_mirror%2Ftest_ImageSync.cc;h=d0401ef0d6050d77887cc7d9401d07a4d9da5226;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/test/rbd_mirror/test_ImageSync.cc b/src/ceph/src/test/rbd_mirror/test_ImageSync.cc new file mode 100644 index 0000000..d0401ef --- /dev/null +++ b/src/ceph/src/test/rbd_mirror/test_ImageSync.cc @@ -0,0 +1,320 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/rbd_mirror/test_fixture.h" +#include "include/stringify.h" +#include "include/rbd/librbd.hpp" +#include "journal/Journaler.h" +#include "journal/Settings.h" +#include "librbd/ExclusiveLock.h" +#include "librbd/ImageCtx.h" +#include "librbd/ImageState.h" +#include "librbd/internal.h" +#include "librbd/Operations.h" +#include "librbd/io/ImageRequestWQ.h" +#include "librbd/io/ReadResult.h" +#include "librbd/journal/Types.h" +#include "tools/rbd_mirror/ImageSync.h" +#include "tools/rbd_mirror/InstanceWatcher.h" +#include "tools/rbd_mirror/Threads.h" + +void register_test_image_sync() { +} + +namespace rbd { +namespace mirror { + +namespace { + +void scribble(librbd::ImageCtx *image_ctx, int num_ops, size_t max_size) +{ + max_size = MIN(image_ctx->size, max_size); + for (int i=0; isize - max_size + 1); + uint64_t len = 1 + rand() % max_size; + + if (rand() % 4 == 0) { + ASSERT_EQ((int)len, image_ctx->io_work_queue->discard(off, len, image_ctx->skip_partial_discard)); + } else { + bufferlist bl; + bl.append(std::string(len, '1')); + ASSERT_EQ((int)len, image_ctx->io_work_queue->write(off, len, + std::move(bl), 0)); + } + } + + RWLock::RLocker owner_locker(image_ctx->owner_lock); + ASSERT_EQ(0, image_ctx->flush()); +} + +} // anonymous namespace +class TestImageSync : public TestFixture { +public: + + void SetUp() override { + TestFixture::SetUp(); + create_and_open(m_local_io_ctx, &m_local_image_ctx); + create_and_open(m_remote_io_ctx, &m_remote_image_ctx); + + m_instance_watcher = rbd::mirror::InstanceWatcher<>::create( + m_local_io_ctx, m_threads->work_queue, nullptr); + m_instance_watcher->handle_acquire_leader(); + + m_remote_journaler = new ::journal::Journaler( + m_threads->work_queue, m_threads->timer, &m_threads->timer_lock, + m_remote_io_ctx, m_remote_image_ctx->id, "mirror-uuid", {}); + + m_client_meta = {"image-id"}; + + librbd::journal::ClientData client_data(m_client_meta); + bufferlist client_data_bl; + ::encode(client_data, client_data_bl); + + ASSERT_EQ(0, m_remote_journaler->register_client(client_data_bl)); + } + + void TearDown() override { + TestFixture::TearDown(); + + m_instance_watcher->handle_release_leader(); + + delete m_remote_journaler; + delete m_instance_watcher; + } + + void create_and_open(librados::IoCtx &io_ctx, librbd::ImageCtx **image_ctx) { + librbd::RBD rbd; + ASSERT_EQ(0, create_image(rbd, io_ctx, m_image_name, m_image_size)); + ASSERT_EQ(0, open_image(io_ctx, m_image_name, image_ctx)); + + C_SaferCond ctx; + { + RWLock::RLocker owner_locker((*image_ctx)->owner_lock); + (*image_ctx)->exclusive_lock->try_acquire_lock(&ctx); + } + ASSERT_EQ(0, ctx.wait()); + ASSERT_TRUE((*image_ctx)->exclusive_lock->is_lock_owner()); + } + + ImageSync<> *create_request(Context *ctx) { + return new ImageSync<>(m_local_image_ctx, m_remote_image_ctx, + m_threads->timer, &m_threads->timer_lock, + "mirror-uuid", m_remote_journaler, &m_client_meta, + m_threads->work_queue, m_instance_watcher, ctx); + } + + librbd::ImageCtx *m_remote_image_ctx; + librbd::ImageCtx *m_local_image_ctx; + rbd::mirror::InstanceWatcher<> *m_instance_watcher; + ::journal::Journaler *m_remote_journaler; + librbd::journal::MirrorPeerClientMeta m_client_meta; +}; + +TEST_F(TestImageSync, Empty) { + C_SaferCond ctx; + ImageSync<> *request = create_request(&ctx); + request->send(); + ASSERT_EQ(0, ctx.wait()); + + ASSERT_EQ(0U, m_client_meta.sync_points.size()); + ASSERT_EQ(0, m_remote_image_ctx->state->refresh()); + ASSERT_EQ(0U, m_remote_image_ctx->snap_ids.size()); + ASSERT_EQ(0, m_local_image_ctx->state->refresh()); + ASSERT_EQ(1U, m_local_image_ctx->snap_ids.size()); // deleted on journal replay +} + +TEST_F(TestImageSync, Simple) { + scribble(m_remote_image_ctx, 10, 102400); + + C_SaferCond ctx; + ImageSync<> *request = create_request(&ctx); + request->send(); + ASSERT_EQ(0, ctx.wait()); + + int64_t object_size = std::min( + m_remote_image_ctx->size, 1 << m_remote_image_ctx->order); + bufferlist read_remote_bl; + read_remote_bl.append(std::string(object_size, '1')); + bufferlist read_local_bl; + read_local_bl.append(std::string(object_size, '1')); + + for (uint64_t offset = 0; offset < m_remote_image_ctx->size; + offset += object_size) { + ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read( + offset, object_size, + librbd::io::ReadResult{&read_remote_bl}, 0)); + ASSERT_LE(0, m_local_image_ctx->io_work_queue->read( + offset, object_size, + librbd::io::ReadResult{&read_local_bl}, 0)); + ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl)); + } +} + +TEST_F(TestImageSync, Resize) { + int64_t object_size = std::min( + m_remote_image_ctx->size, 1 << m_remote_image_ctx->order); + + uint64_t off = 0; + uint64_t len = object_size / 10; + + bufferlist bl; + bl.append(std::string(len, '1')); + ASSERT_EQ((int)len, m_remote_image_ctx->io_work_queue->write(off, len, + std::move(bl), + 0)); + { + RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock); + ASSERT_EQ(0, m_remote_image_ctx->flush()); + } + + ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap", nullptr)); + + uint64_t size = object_size - 1; + librbd::NoOpProgressContext no_op_progress_ctx; + ASSERT_EQ(0, m_remote_image_ctx->operations->resize(size, true, + no_op_progress_ctx)); + + C_SaferCond ctx; + ImageSync<> *request = create_request(&ctx); + request->send(); + ASSERT_EQ(0, ctx.wait()); + + bufferlist read_remote_bl; + read_remote_bl.append(std::string(len, '\0')); + bufferlist read_local_bl; + read_local_bl.append(std::string(len, '\0')); + + ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read( + off, len, librbd::io::ReadResult{&read_remote_bl}, 0)); + ASSERT_LE(0, m_local_image_ctx->io_work_queue->read( + off, len, librbd::io::ReadResult{&read_local_bl}, 0)); + + ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl)); +} + +TEST_F(TestImageSync, Discard) { + int64_t object_size = std::min( + m_remote_image_ctx->size, 1 << m_remote_image_ctx->order); + + uint64_t off = 0; + uint64_t len = object_size / 10; + + bufferlist bl; + bl.append(std::string(len, '1')); + ASSERT_EQ((int)len, m_remote_image_ctx->io_work_queue->write(off, len, + std::move(bl), + 0)); + { + RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock); + ASSERT_EQ(0, m_remote_image_ctx->flush()); + } + + ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap", nullptr)); + + ASSERT_EQ((int)len - 2, m_remote_image_ctx->io_work_queue->discard(off + 1, + len - 2, m_remote_image_ctx->skip_partial_discard)); + { + RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock); + ASSERT_EQ(0, m_remote_image_ctx->flush()); + } + + C_SaferCond ctx; + ImageSync<> *request = create_request(&ctx); + request->send(); + ASSERT_EQ(0, ctx.wait()); + + bufferlist read_remote_bl; + read_remote_bl.append(std::string(object_size, '\0')); + bufferlist read_local_bl; + read_local_bl.append(std::string(object_size, '\0')); + + ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read( + off, len, librbd::io::ReadResult{&read_remote_bl}, 0)); + ASSERT_LE(0, m_local_image_ctx->io_work_queue->read( + off, len, librbd::io::ReadResult{&read_local_bl}, 0)); + + ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl)); +} + +TEST_F(TestImageSync, SnapshotStress) { + std::list snap_names; + + const int num_snaps = 4; + for (int idx = 0; idx <= num_snaps; ++idx) { + scribble(m_remote_image_ctx, 10, 102400); + + librbd::NoOpProgressContext no_op_progress_ctx; + uint64_t size = 1 + rand() % m_image_size; + ASSERT_EQ(0, m_remote_image_ctx->operations->resize(size, true, + no_op_progress_ctx)); + ASSERT_EQ(0, m_remote_image_ctx->state->refresh()); + + if (idx < num_snaps) { + snap_names.push_back("snap" + stringify(idx + 1)); + ASSERT_EQ(0, create_snap(m_remote_image_ctx, snap_names.back().c_str(), + nullptr)); + } else { + snap_names.push_back(""); + } + } + + C_SaferCond ctx; + ImageSync<> *request = create_request(&ctx); + request->send(); + ASSERT_EQ(0, ctx.wait()); + + int64_t object_size = std::min( + m_remote_image_ctx->size, 1 << m_remote_image_ctx->order); + bufferlist read_remote_bl; + read_remote_bl.append(std::string(object_size, '1')); + bufferlist read_local_bl; + read_local_bl.append(std::string(object_size, '1')); + + for (auto &snap_name : snap_names) { + uint64_t remote_size; + { + C_SaferCond ctx; + m_remote_image_ctx->state->snap_set(cls::rbd::UserSnapshotNamespace(), + snap_name, + &ctx); + ASSERT_EQ(0, ctx.wait()); + + RWLock::RLocker remote_snap_locker(m_remote_image_ctx->snap_lock); + remote_size = m_remote_image_ctx->get_image_size( + m_remote_image_ctx->snap_id); + } + + uint64_t local_size; + { + C_SaferCond ctx; + m_local_image_ctx->state->snap_set(cls::rbd::UserSnapshotNamespace(), + snap_name, + &ctx); + ASSERT_EQ(0, ctx.wait()); + + RWLock::RLocker snap_locker(m_local_image_ctx->snap_lock); + local_size = m_local_image_ctx->get_image_size( + m_local_image_ctx->snap_id); + bool flags_set; + ASSERT_EQ(0, m_local_image_ctx->test_flags(RBD_FLAG_OBJECT_MAP_INVALID, + m_local_image_ctx->snap_lock, + &flags_set)); + ASSERT_FALSE(flags_set); + } + + ASSERT_EQ(remote_size, local_size); + + for (uint64_t offset = 0; offset < remote_size; offset += object_size) { + ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read( + offset, object_size, + librbd::io::ReadResult{&read_remote_bl}, 0)); + ASSERT_LE(0, m_local_image_ctx->io_work_queue->read( + offset, object_size, + librbd::io::ReadResult{&read_local_bl}, 0)); + ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl)); + } + } +} + +} // namespace mirror +} // namespace rbd