From 4f3ef50fd8a0884e22c8ab717b4357cab9723ad8 Mon Sep 17 00:00:00 2001 From: JonBailey1993 Date: Tue, 1 Oct 2024 11:25:48 +0100 Subject: [PATCH] src/common/io_exerciser: Code readability improvements Implement inheritence for ceph::io_exerciser::IoOp to allow better differentiation between the different Op types and allow more complex Operations to be implemented Signed-off-by: Jon Bailey --- src/common/io_exerciser/IoOp.cc | 375 ++++++++++++-------- src/common/io_exerciser/IoOp.h | 179 ++++++---- src/common/io_exerciser/IoSequence.cc | 94 ++--- src/common/io_exerciser/IoSequence.h | 13 +- src/common/io_exerciser/ObjectModel.cc | 155 ++++---- src/common/io_exerciser/OpType.h | 66 ++++ src/common/io_exerciser/RadosIo.cc | 232 +++++------- src/common/io_exerciser/RadosIo.h | 23 +- src/test/osd/ceph_test_rados_io_sequence.cc | 129 ++++--- 9 files changed, 738 insertions(+), 528 deletions(-) create mode 100644 src/common/io_exerciser/OpType.h diff --git a/src/common/io_exerciser/IoOp.cc b/src/common/io_exerciser/IoOp.cc index cd855ba6fff..2a5a60e4a24 100644 --- a/src/common/io_exerciser/IoOp.cc +++ b/src/common/io_exerciser/IoOp.cc @@ -1,188 +1,265 @@ #include "IoOp.h" +#include "fmt/format.h" + using IoOp = ceph::io_exerciser::IoOp; +using OpType = ceph::io_exerciser::OpType; + +using DoneOp = ceph::io_exerciser::DoneOp; +using BarrierOp = ceph::io_exerciser::BarrierOp; +using CreateOp = ceph::io_exerciser::CreateOp; +using RemoveOp = ceph::io_exerciser::RemoveOp; +using SingleReadOp = ceph::io_exerciser::SingleReadOp; +using DoubleReadOp = ceph::io_exerciser::DoubleReadOp; +using TripleReadOp = ceph::io_exerciser::TripleReadOp; +using SingleWriteOp = ceph::io_exerciser::SingleWriteOp; +using DoubleWriteOp = ceph::io_exerciser::DoubleWriteOp; +using TripleWriteOp = ceph::io_exerciser::TripleWriteOp; + +namespace +{ + std::string value_to_string(uint64_t v) + { + if (v < 1024 || (v % 1024) != 0) + { + return std::to_string(v); + } + else if (v < 1024*1024 || (v % (1024 * 1024)) != 0 ) + { + return std::to_string(v / 1024) + "K"; + } + else + { + return std::to_string(v / 1024 / 1024) + "M"; + } + } +} -IoOp::IoOp( OpType op, - uint64_t offset1, uint64_t length1, - uint64_t offset2, uint64_t length2, - uint64_t offset3, uint64_t length3) : - op(op), - offset1(offset1), length1(length1), - offset2(offset2), length2(length2), - offset3(offset3), length3(length3) +IoOp::IoOp() { } -std::string IoOp::value_to_string(uint64_t v) const +template +ceph::io_exerciser::TestOp::TestOp() : IoOp() { - if (v < 1024 || (v % 1024) != 0) { - return std::to_string(v); - }else if (v < 1024*1024 || (v % (1024 * 1024)) != 0 ) { - return std::to_string(v / 1024) + "K"; - }else{ - return std::to_string(v / 1024 / 1024) + "M"; - } + } -std::unique_ptr IoOp - ::generate_done() { +DoneOp::DoneOp() : TestOp() +{ - return std::make_unique(OpType::Done); } -std::unique_ptr IoOp - ::generate_barrier() { +std::string DoneOp::to_string(uint64_t block_size) const +{ + return "Done"; +} - return std::make_unique(OpType::BARRIER); +std::unique_ptr DoneOp::generate() +{ + return std::make_unique(); } -std::unique_ptr IoOp - ::generate_create(uint64_t size) { +BarrierOp::BarrierOp() : TestOp() +{ - return std::make_unique(OpType::CREATE,0,size); } -std::unique_ptr IoOp - ::generate_remove() { +std::unique_ptr BarrierOp::generate() +{ + return std::make_unique(); +} - return std::make_unique(OpType::REMOVE); +std::string BarrierOp::to_string(uint64_t block_size) const +{ + return "Barrier"; } -std::unique_ptr IoOp - ::generate_read(uint64_t offset, uint64_t length) { +CreateOp::CreateOp(uint64_t size) : TestOp(), + size(size) +{ - return std::make_unique(OpType::READ, offset, length); } -std::unique_ptr IoOp - ::generate_read2(uint64_t offset1, uint64_t length1, - uint64_t offset2, uint64_t length2) { +std::unique_ptr CreateOp::generate(uint64_t size) +{ + return std::make_unique(size); +} - if (offset1 < offset2) { - ceph_assert( offset1 + length1 <= offset2 ); - } else { - ceph_assert( offset2 + length2 <= offset1 ); - } +std::string CreateOp::to_string(uint64_t block_size) const +{ + return "Create (size=" + value_to_string(size * block_size) + ")"; +} + +RemoveOp::RemoveOp() : TestOp() +{ + +} - return std::make_unique(OpType::READ2, - offset1, length1, - offset2, length2); +std::unique_ptr RemoveOp::generate() +{ + return std::make_unique(); } -std::unique_ptr IoOp - ::generate_read3(uint64_t offset1, uint64_t length1, - uint64_t offset2, uint64_t length2, - uint64_t offset3, uint64_t length3) { +std::string RemoveOp::to_string(uint64_t block_size) const +{ + return "Remove"; +} - if (offset1 < offset2) { - ceph_assert( offset1 + length1 <= offset2 ); - } else { - ceph_assert( offset2 + length2 <= offset1 ); +template +ceph::io_exerciser::ReadWriteOp + ::ReadWriteOp(std::array&& offset, + std::array&& length) : + TestOp(), + offset(offset), + length(length) +{ + auto compare = [](uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2) + { + if (offset1 < offset2) + { + ceph_assert( offset1 + length1 <= offset2 ); + } + else + { + ceph_assert( offset2 + length2 <= offset1 ); + } + }; + + if (numIOs > 1) + { + for (int i = 0; i < numIOs-1; i++) + { + for (int j = i + 1; j < numIOs; j++) + { + compare(offset[i], length[i], offset[j], length[j]); + } + } } - if (offset1 < offset3) { - ceph_assert( offset1 + length1 <= offset3 ); - } else { - ceph_assert( offset3 + length3 <= offset1 ); +} + +template +std::string ceph::io_exerciser::ReadWriteOp + ::to_string(uint64_t block_size) const +{ + std::string offset_length_desc; + if (numIOs > 0) + { + offset_length_desc += fmt::format("offset1={}", + value_to_string(this->offset[0] * block_size)); + offset_length_desc += fmt::format(",length1={}", + value_to_string(this->length[0] * block_size)); + for (int i = 1; i < numIOs; i++) + { + offset_length_desc += fmt::format(",offset{}={}", + i+1, + value_to_string(this->offset[i] * block_size)); + offset_length_desc += fmt::format(",length{}={}", + i+1, + value_to_string(this->length[i] * block_size)); + } } - if (offset2 < offset3) { - ceph_assert( offset2 + length2 <= offset3 ); - } else { - ceph_assert( offset3 + length3 <= offset2 ); + switch(opType) + { + case OpType::Read: + [[fallthrough]]; + case OpType::Read2: + [[fallthrough]]; + case OpType::Read3: + return fmt::format("Read{} ({})", numIOs, offset_length_desc); + case OpType::Write: + [[fallthrough]]; + case OpType::Write2: + [[fallthrough]]; + case OpType::Write3: + return fmt::format("Write{} ({})", numIOs, offset_length_desc); + default: + ceph_abort_msg(fmt::format("Unsupported op type by ReadWriteOp ({})", opType)); } - return std::make_unique(OpType::READ3, - offset1, length1, - offset2, length2, - offset3, length3); } -std::unique_ptr IoOp::generate_write(uint64_t offset, uint64_t length) { - return std::make_unique(OpType::WRITE, offset, length); +SingleReadOp::SingleReadOp(uint64_t offset, uint64_t length) : + ReadWriteOp({offset}, {length}) +{ + } -std::unique_ptr IoOp::generate_write2(uint64_t offset1, uint64_t length1, - uint64_t offset2, uint64_t length2) { - if (offset1 < offset2) { - ceph_assert( offset1 + length1 <= offset2 ); - } else { - ceph_assert( offset2 + length2 <= offset1 ); - } - return std::make_unique(OpType::WRITE2, - offset1, length1, - offset2, length2); -} - -std::unique_ptr IoOp::generate_write3(uint64_t offset1, uint64_t length1, - uint64_t offset2, uint64_t length2, - uint64_t offset3, uint64_t length3) { - if (offset1 < offset2) { - ceph_assert( offset1 + length1 <= offset2 ); - } else { - ceph_assert( offset2 + length2 <= offset1 ); - } - if (offset1 < offset3) { - ceph_assert( offset1 + length1 <= offset3 ); - } else { - ceph_assert( offset3 + length3 <= offset1 ); - } - if (offset2 < offset3) { - ceph_assert( offset2 + length2 <= offset3 ); - } else { - ceph_assert( offset3 + length3 <= offset2 ); - } - return std::make_unique(OpType::WRITE3, - offset1, length1, - offset2, length2, - offset3, length3); -} - -bool IoOp::done() { - return (op == OpType::Done); -} - -std::string IoOp::to_string(uint64_t block_size) const -{ - switch (op) { - case OpType::Done: - return "Done"; - case OpType::BARRIER: - return "Barrier"; - case OpType::CREATE: - return "Create (size=" + value_to_string(length1 * block_size) + ")"; - case OpType::REMOVE: - return "Remove"; - case OpType::READ: - return "Read (offset=" + value_to_string(offset1 * block_size) + - ",length=" + value_to_string(length1 * block_size) + ")"; - case OpType::READ2: - return "Read2 (offset1=" + value_to_string(offset1 * block_size) + - ",length1=" + value_to_string(length1 * block_size) + - ",offset2=" + value_to_string(offset2 * block_size) + - ",length2=" + value_to_string(length2 * block_size) + ")"; - case OpType::READ3: - return "Read3 (offset1=" + value_to_string(offset1 * block_size) + - ",length1=" + value_to_string(length1 * block_size) + - ",offset2=" + value_to_string(offset2 * block_size) + - ",length2=" + value_to_string(length2 * block_size) + - ",offset3=" + value_to_string(offset3 * block_size) + - ",length3=" + value_to_string(length3 * block_size) + ")"; - case OpType::WRITE: - return "Write (offset=" + value_to_string(offset1 * block_size) + - ",length=" + value_to_string(length1 * block_size) + ")"; - case OpType::WRITE2: - return "Write2 (offset1=" + value_to_string(offset1 * block_size) + - ",length1=" + value_to_string(length1 * block_size) + - ",offset2=" + value_to_string(offset2 * block_size) + - ",length2=" + value_to_string(length2 * block_size) + ")"; - case OpType::WRITE3: - return "Write3 (offset1=" + value_to_string(offset1 * block_size) + - ",length1=" + value_to_string(length1 * block_size) + - ",offset2=" + value_to_string(offset2 * block_size) + - ",length2=" + value_to_string(length2 * block_size) + - ",offset3=" + value_to_string(offset3 * block_size) + - ",length3=" + value_to_string(length3 * block_size) + ")"; - default: - break; - } - return "Unknown"; +std::unique_ptr SingleReadOp::generate(uint64_t offset, + uint64_t length) +{ + return std::make_unique(offset, length); +} + +DoubleReadOp::DoubleReadOp(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2) : + ReadWriteOp({offset1, offset2}, {length1, length2}) +{ + +} + +std::unique_ptr DoubleReadOp::generate(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2) +{ + return std::make_unique(offset1, length1, offset2, length2); +} + +TripleReadOp::TripleReadOp(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2, + uint64_t offset3, uint64_t length3) : + ReadWriteOp({offset1, offset2, offset3}, + {length1, length2, length3}) +{ + +} + +std::unique_ptr TripleReadOp::generate(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2, + uint64_t offset3, uint64_t length3) +{ + return std::make_unique(offset1, length1, + offset2, length2, + offset3, length3); +} + +SingleWriteOp::SingleWriteOp(uint64_t offset, uint64_t length) : + ReadWriteOp({offset}, {length}) +{ + +} + +std::unique_ptr SingleWriteOp::generate(uint64_t offset, uint64_t length) +{ + return std::make_unique(offset, length); +} + +DoubleWriteOp::DoubleWriteOp(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2) : + ReadWriteOp({offset1, offset2}, {length1, length2}) +{ + +} + +std::unique_ptr DoubleWriteOp::generate(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2) +{ + return std::make_unique(offset1, length1, offset2, length2); +} + +TripleWriteOp::TripleWriteOp(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2, + uint64_t offset3, uint64_t length3) : + ReadWriteOp({offset1, offset2, offset3}, {length1, length2, length3}) +{ + +} + +std::unique_ptr TripleWriteOp::generate(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2, + uint64_t offset3, uint64_t length3) +{ + return std::make_unique(offset1, length1, + offset2, length2, + offset3, length3); } \ No newline at end of file diff --git a/src/common/io_exerciser/IoOp.h b/src/common/io_exerciser/IoOp.h index 60c02a93d4e..2f9f169d954 100644 --- a/src/common/io_exerciser/IoOp.h +++ b/src/common/io_exerciser/IoOp.h @@ -1,13 +1,13 @@ #pragma once +#include #include #include #include "include/ceph_assert.h" +#include "OpType.h" + /* Overview - * - * enum OpType - * Enumeration of different types of I/O operation * * class IoOp * Stores details for an I/O operation. Generated by IoSequences @@ -17,78 +17,133 @@ namespace ceph { namespace io_exerciser { - enum class OpType { - Done, // End of I/O sequence - BARRIER, // Barrier - all prior I/Os must complete - CREATE, // Create object and pattern with data - REMOVE, // Remove object - READ, // Read - READ2, // 2 Reads in one op - READ3, // 3 Reads in one op - WRITE, // Write - WRITE2, // 2 Writes in one op - WRITE3 // 3 Writes in one op + class IoOp + { + public: + IoOp(); + virtual ~IoOp() = default; + virtual std::string to_string(uint64_t block_size) const = 0; + virtual constexpr OpType getOpType() const = 0; }; - class IoOp { - protected: - std::string value_to_string(uint64_t v) const; - - public: - OpType op; - uint64_t offset1; - uint64_t length1; - uint64_t offset2; - uint64_t length2; - uint64_t offset3; - uint64_t length3; - - IoOp( OpType op, - uint64_t offset1 = 0, uint64_t length1 = 0, - uint64_t offset2 = 0, uint64_t length2 = 0, - uint64_t offset3 = 0, uint64_t length3 = 0 ); - - static std::unique_ptr generate_done(); + template + class TestOp : public IoOp + { + public: + TestOp(); + constexpr OpType getOpType() const override { return opType; } + }; - static std::unique_ptr generate_barrier(); + class DoneOp : public TestOp + { + public: + DoneOp(); + static std::unique_ptr generate(); + std::string to_string(uint64_t block_size) const override; + }; - static std::unique_ptr generate_create(uint64_t size); + class BarrierOp : public TestOp + { + public: + BarrierOp(); + static std::unique_ptr generate(); + std::string to_string(uint64_t block_size) const override; + }; - static std::unique_ptr generate_remove(); + class CreateOp : public TestOp + { + public: + CreateOp(uint64_t size); + static std::unique_ptr generate(uint64_t size); + std::string to_string(uint64_t block_size) const override; + uint64_t size; + }; - static std::unique_ptr generate_read(uint64_t offset, - uint64_t length); + class RemoveOp : public TestOp + { + public: + RemoveOp(); + static std::unique_ptr generate(); + std::string to_string(uint64_t block_size) const override; + }; - static std::unique_ptr generate_read2(uint64_t offset1, - uint64_t length1, - uint64_t offset2, - uint64_t length2); + template + class ReadWriteOp : public TestOp + { + public: + std::array offset; + std::array length; + + protected: + ReadWriteOp(std::array&& offset, + std::array&& length); + std::string to_string(uint64_t block_size) const override; + }; - static std::unique_ptr generate_read3(uint64_t offset1, - uint64_t length1, - uint64_t offset2, - uint64_t length2, - uint64_t offset3, - uint64_t length3); + class SingleReadOp : public ReadWriteOp + { + public: + SingleReadOp(uint64_t offset, uint64_t length); + static std::unique_ptr generate(uint64_t offset, + uint64_t length); + }; - static std::unique_ptr generate_write(uint64_t offset, - uint64_t length); + class DoubleReadOp : public ReadWriteOp + { + public: + DoubleReadOp(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2); + static std::unique_ptr generate(uint64_t offset1, + uint64_t length1, + uint64_t offset2, + uint64_t length2); + }; - static std::unique_ptr generate_write2(uint64_t offset1, - uint64_t length1, - uint64_t offset2, - uint64_t length2); + class TripleReadOp : public ReadWriteOp + { + public: + TripleReadOp(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2, + uint64_t offset3, uint64_t length3); + static std::unique_ptr generate(uint64_t offset1, + uint64_t length1, + uint64_t offset2, + uint64_t length2, + uint64_t offset3, + uint64_t length3); + }; - static std::unique_ptr generate_write3(uint64_t offset1, - uint64_t length1, - uint64_t offset2, - uint64_t length2, - uint64_t offset3, - uint64_t length3); + class SingleWriteOp : public ReadWriteOp + { + public: + SingleWriteOp(uint64_t offset, uint64_t length); + static std::unique_ptr generate(uint64_t offset, + uint64_t length); + }; - bool done(); + class DoubleWriteOp : public ReadWriteOp + { + public: + DoubleWriteOp(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2); + static std::unique_ptr generate(uint64_t offset1, + uint64_t length1, + uint64_t offset2, + uint64_t length2); + }; - std::string to_string(uint64_t block_size) const; + class TripleWriteOp : public ReadWriteOp + { + public: + TripleWriteOp(uint64_t offset1, uint64_t length1, + uint64_t offset2, uint64_t length2, + uint64_t offset3, uint64_t length3); + static std::unique_ptr generate(uint64_t offset1, + uint64_t length1, + uint64_t offset2, + uint64_t length2, + uint64_t offset3, + uint64_t length3); }; } } \ No newline at end of file diff --git a/src/common/io_exerciser/IoSequence.cc b/src/common/io_exerciser/IoSequence.cc index 4a7ca0593d1..d4b7af40b41 100644 --- a/src/common/io_exerciser/IoSequence.cc +++ b/src/common/io_exerciser/IoSequence.cc @@ -1,5 +1,6 @@ #include "IoSequence.h" +using IoOp = ceph::io_exerciser::IoOp; using Sequence = ceph::io_exerciser::Sequence; using IoSequence = ceph::io_exerciser::IoSequence; @@ -44,15 +45,6 @@ std::ostream& ceph::io_exerciser::operator<<(std::ostream& os, const Sequence& s return os; } -IoSequence::IoSequence(std::pair obj_size_range, - int seed) : - min_obj_size(obj_size_range.first), max_obj_size(obj_size_range.second), - create(true), barrier(false), done(false), remove(false), - obj_size(min_obj_size), step(-1), seed(seed) -{ - rng.seed(seed); -} - std::unique_ptr IoSequence::generate_sequence(Sequence s, std::pair obj_size_range, int seed) @@ -84,6 +76,15 @@ std::unique_ptr IoSequence::generate_sequence(Sequence s, return nullptr; } +IoSequence::IoSequence(std::pair obj_size_range, + int seed) : + min_obj_size(obj_size_range.first), max_obj_size(obj_size_range.second), + create(true), barrier(false), done(false), remove(false), + obj_size(min_obj_size), step(-1), seed(seed) +{ + rng.seed(seed); +} + int IoSequence::get_step() const { return step; @@ -120,7 +121,7 @@ void IoSequence::select_random_object_size() } } -std::unique_ptr IoSequence::increment_object_size() +std::unique_ptr IoSequence::increment_object_size() { obj_size++; if (obj_size > max_obj_size) { @@ -129,27 +130,27 @@ std::unique_ptr IoSequence::increment_object_size() create = true; barrier = true; remove = true; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } -std::unique_ptr IoSequence::next() +std::unique_ptr IoSequence::next() { step++; if (remove) { remove = false; - return IoOp::generate_remove(); + return RemoveOp::generate(); } if (barrier) { barrier = false; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } if (done) { - return IoOp::generate_done(); + return DoneOp::generate(); } if (create) { create = false; barrier = true; - return IoOp::generate_create(obj_size); + return CreateOp::generate(obj_size); } return _next(); } @@ -176,12 +177,12 @@ std::unique_ptr ceph::io_exerciser::Seq0::_next() done = true; barrier = true; remove = true; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } if (offset + length > obj_size) { - r = IoOp::generate_read(offset, obj_size - offset); + r = SingleReadOp::generate(offset, obj_size - offset); } else { - r = IoOp::generate_read(offset, length); + r = SingleReadOp::generate(offset, length); } offset += length; return r; @@ -208,13 +209,20 @@ std::unique_ptr ceph::io_exerciser::Seq1::_next() if (count-- == 0) { done = true; remove = true; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } uint64_t offset = rng(obj_size - 1); uint64_t length = 1 + rng(obj_size - 1 - offset); - return (rng(2) != 0) ? IoOp::generate_write(offset, length) : - IoOp::generate_read(offset, length); + + if (rng(2) != 0) + { + return SingleWriteOp::generate(offset, length); + } + else + { + return SingleReadOp::generate(offset, length); + } } @@ -239,7 +247,7 @@ std::unique_ptr ceph::io_exerciser::Seq2::_next() return increment_object_size(); } } - return IoOp::generate_read(offset, length); + return SingleReadOp::generate(offset, length); } @@ -267,7 +275,7 @@ std::unique_ptr ceph::io_exerciser::Seq3::_next() return increment_object_size(); } } - return IoOp::generate_read2(offset1, 1, offset1 + offset2, 1); + return DoubleReadOp::generate(offset1, 1, offset1 + offset2, 1); } @@ -295,9 +303,7 @@ std::unique_ptr ceph::io_exerciser::Seq4::_next() return increment_object_size(); } } - return IoOp::generate_read3(offset1, 1, - offset1 + offset2, 1, - (offset1 * 2 + offset2)/2, 1); + return TripleReadOp::generate(offset1, 1, (offset1 + offset2), 1, (offset1 * 2 + offset2) / 2, 1); } @@ -317,11 +323,11 @@ std::unique_ptr ceph::io_exerciser::Seq5::_next() if (!doneread) { if (!donebarrier) { donebarrier = true; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } doneread = true; barrier = true; - return IoOp::generate_read(0, obj_size); + return SingleReadOp::generate(0, obj_size); } doneread = false; donebarrier = false; @@ -333,7 +339,7 @@ std::unique_ptr ceph::io_exerciser::Seq5::_next() } } uint64_t io_len = (offset + length > obj_size) ? (obj_size - offset) : length; - std::unique_ptr r = IoOp::generate_write(offset, io_len); + std::unique_ptr r = SingleWriteOp::generate(offset, io_len); offset += io_len; return r; } @@ -355,11 +361,11 @@ std::unique_ptr ceph::io_exerciser::Seq6::_next() if (!doneread) { if (!donebarrier) { donebarrier = true; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } doneread = true; barrier = true; - return IoOp::generate_read(0, obj_size); + return SingleReadOp::generate(0, obj_size); } doneread = false; donebarrier = false; @@ -374,7 +380,7 @@ std::unique_ptr ceph::io_exerciser::Seq6::_next() if (io_len == 0) { io_len = length; } - std::unique_ptr r = IoOp::generate_write(offset, io_len); + std::unique_ptr r = SingleWriteOp::generate(offset, io_len); offset += io_len; return r; } @@ -398,11 +404,11 @@ std::unique_ptr ceph::io_exerciser::Seq7::_next() if (!doneread) { if (!donebarrier) { donebarrier = true; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } doneread = true; barrier = true; - return IoOp::generate_read(0, obj_size); + return SingleReadOp::generate(0, obj_size); } if (offset == 0) { doneread = false; @@ -416,7 +422,7 @@ std::unique_ptr ceph::io_exerciser::Seq7::_next() } doneread = false; donebarrier = false; - return IoOp::generate_write2(offset, 1, obj_size/2, 1); + return DoubleReadOp::generate(offset, 1, obj_size/2, 1); } @@ -437,11 +443,11 @@ std::unique_ptr ceph::io_exerciser::Seq8::_next() if (!doneread) { if (!donebarrier) { donebarrier = true; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } doneread = true; barrier = true; - return IoOp::generate_read(0, obj_size); + return SingleReadOp::generate(0, obj_size); } offset2++; if (offset2 >= obj_size - offset1) { @@ -455,9 +461,7 @@ std::unique_ptr ceph::io_exerciser::Seq8::_next() } doneread = false; donebarrier = false; - return IoOp::generate_write3(offset1, 1, - offset1 + offset2, 1, - (offset1 * 2 + offset2)/2, 1); + return TripleWriteOp::generate(offset1, 1, offset1 + offset2, 1, (offset1 * 2 + offset2)/2, 1); } @@ -465,7 +469,7 @@ std::unique_ptr ceph::io_exerciser::Seq8::_next() ceph::io_exerciser::Seq9::Seq9(std::pair obj_size_range, int seed) : IoSequence(obj_size_range, seed), offset(0), length(0) { - + } std::string ceph::io_exerciser::Seq9::get_name() const @@ -478,11 +482,11 @@ std::unique_ptr ceph::io_exerciser::Seq9::_next() if (!doneread) { if (!donebarrier) { donebarrier = true; - return IoOp::generate_barrier(); + return BarrierOp::generate(); } doneread = true; barrier = true; - return IoOp::generate_read(0, obj_size); + return SingleReadOp::generate(0, obj_size); } length++; if (length > obj_size - offset) { @@ -496,5 +500,5 @@ std::unique_ptr ceph::io_exerciser::Seq9::_next() } doneread = false; donebarrier = false; - return IoOp::generate_write(offset, length); + return SingleWriteOp::generate(offset, length); } \ No newline at end of file diff --git a/src/common/io_exerciser/IoSequence.h b/src/common/io_exerciser/IoSequence.h index 114ff76303f..ccce4336c22 100644 --- a/src/common/io_exerciser/IoSequence.h +++ b/src/common/io_exerciser/IoSequence.h @@ -64,10 +64,12 @@ namespace ceph { int get_step() const; int get_seed() const; - std::unique_ptr next(); + virtual std::unique_ptr next(); static std::unique_ptr - generate_sequence(Sequence s, std::pair obj_size_range, int seed ); + generate_sequence(Sequence s, + std::pair obj_size_range, + int seed ); protected: uint64_t min_obj_size; @@ -90,7 +92,6 @@ namespace ceph { void set_max_object_size(uint64_t size); void select_random_object_size(); std::unique_ptr increment_object_size(); - }; class Seq0: public IoSequence { @@ -105,7 +106,7 @@ namespace ceph { uint64_t length; }; - class Seq1: public IoSequence { + class Seq1: public IoSequence { public: Seq1(std::pair obj_size_range, int seed); @@ -115,14 +116,14 @@ namespace ceph { private: int count; }; - + class Seq2: public IoSequence { public: Seq2(std::pair obj_size_range, int seed); std::string get_name() const override; std::unique_ptr _next() override; - + private: uint64_t offset; uint64_t length; diff --git a/src/common/io_exerciser/ObjectModel.cc b/src/common/io_exerciser/ObjectModel.cc index 589f6434282..350b8e5756b 100644 --- a/src/common/io_exerciser/ObjectModel.cc +++ b/src/common/io_exerciser/ObjectModel.cc @@ -55,27 +55,72 @@ bool ObjectModel::readyForIoOp(IoOp& op) void ObjectModel::applyIoOp(IoOp& op) { - auto generate_random = [&rng = rng]() { + auto generate_random = [&rng = rng]() + { return rng(); }; - switch (op.op) { - case OpType::BARRIER: + auto verify_and_record_read_op = [ &contents = contents, + &created = created, + &num_io = num_io, + &reads = reads, + &writes = writes ] + + (ReadWriteOp& readOp) + { + ceph_assert(created); + for (int i = 0; i < N; i++) + { + ceph_assert(readOp.offset[i] + readOp.length[i] <= contents.size()); + // Not allowed: read overlapping with parallel write + ceph_assert(!writes.intersects(readOp.offset[i], readOp.length[i])); + reads.union_insert(readOp.offset[i], readOp.length[i]); + } + num_io++; + }; + + auto verify_write_and_record_and_generate_seed = [ &generate_random, + &contents = contents, + &created = created, + &num_io = num_io, + &reads = reads, + &writes = writes ] + + (ReadWriteOp writeOp) + { + ceph_assert(created); + for (int i = 0; i < N; i++) + { + // Not allowed: write overlapping with parallel read or write + ceph_assert(!reads.intersects(writeOp.offset[i], writeOp.length[i])); + ceph_assert(!writes.intersects(writeOp.offset[i], writeOp.length[i])); + writes.union_insert(writeOp.offset[i], writeOp.length[i]); + ceph_assert(writeOp.offset[i] + writeOp.length[i] <= contents.size()); + std::generate(std::execution::seq, + std::next(contents.begin(), writeOp.offset[i]), + std::next(contents.begin(), writeOp.offset[i] + writeOp.length[i]), + generate_random); + } + num_io++; + }; + + switch (op.getOpType()) { + case OpType::Barrier: reads.clear(); writes.clear(); break; - case OpType::CREATE: + case OpType::Create: ceph_assert(!created); ceph_assert(reads.empty()); ceph_assert(writes.empty()); created = true; - contents.resize(op.length1); + contents.resize(static_cast(op).size); std::generate(std::execution::seq, contents.begin(), contents.end(), generate_random); break; - case OpType::REMOVE: + case OpType::Remove: ceph_assert(created); ceph_assert(reads.empty()); ceph_assert(writes.empty()); @@ -83,70 +128,44 @@ void ObjectModel::applyIoOp(IoOp& op) contents.resize(0); break; - case OpType::READ3: - ceph_assert(created); - ceph_assert(op.offset3 + op.length3 <= contents.size()); - // Not allowed: read overlapping with parallel write - ceph_assert(!writes.intersects(op.offset3, op.length3)); - reads.union_insert(op.offset3, op.length3); - [[fallthrough]]; - - case OpType::READ2: - ceph_assert(created); - ceph_assert(op.offset2 + op.length2 <= contents.size()); - // Not allowed: read overlapping with parallel write - ceph_assert(!writes.intersects(op.offset2, op.length2)); - reads.union_insert(op.offset2, op.length2); - [[fallthrough]]; - - case OpType::READ: - ceph_assert(created); - ceph_assert(op.offset1 + op.length1 <= contents.size()); - // Not allowed: read overlapping with parallel write - ceph_assert(!writes.intersects(op.offset1, op.length1)); - reads.union_insert(op.offset1, op.length1); - num_io++; - break; - - case OpType::WRITE3: - ceph_assert(created); - // Not allowed: write overlapping with parallel read or write - ceph_assert(!reads.intersects(op.offset3, op.length3)); - ceph_assert(!writes.intersects(op.offset3, op.length3)); - writes.union_insert(op.offset3, op.length3); - ceph_assert(op.offset3 + op.length3 <= contents.size()); - std::generate(std::execution::seq, - std::next(contents.begin(), op.offset3), - std::next(contents.begin(), op.offset3 + op.length3), - generate_random); - [[fallthrough]]; - - case OpType::WRITE2: - ceph_assert(created); - // Not allowed: write overlapping with parallel read or write - ceph_assert(!reads.intersects(op.offset2, op.length2)); - ceph_assert(!writes.intersects(op.offset2, op.length2)); - writes.union_insert(op.offset2, op.length2); - ceph_assert(op.offset2 + op.length2 <= contents.size()); - std::generate(std::execution::seq, - std::next(contents.begin(), op.offset2), - std::next(contents.begin(), op.offset2 + op.length2), - generate_random); - [[fallthrough]]; + case OpType::Read: + { + SingleReadOp& readOp = static_cast(op); + verify_and_record_read_op(readOp); + } + break; + case OpType::Read2: + { + DoubleReadOp& readOp = static_cast(op); + verify_and_record_read_op(readOp); + } + break; + case OpType::Read3: + { + TripleReadOp& readOp = static_cast(op); + verify_and_record_read_op(readOp); + } + break; - case OpType::WRITE: + case OpType::Write: + { ceph_assert(created); - // Not allowed: write overlapping with parallel read or write - ceph_assert(!reads.intersects(op.offset1, op.length1)); - ceph_assert(!writes.intersects(op.offset1, op.length1)); - writes.union_insert(op.offset1, op.length1); - ceph_assert(op.offset1 + op.length1 <= contents.size()); - std::generate(std::execution::seq, - std::next(contents.begin(), op.offset1), - std::next(contents.begin(), op.offset1 + op.length1), - generate_random); - num_io++; - break; + SingleWriteOp& writeOp = static_cast(op); + verify_write_and_record_and_generate_seed(writeOp); + } + break; + case OpType::Write2: + { + DoubleWriteOp& writeOp = static_cast(op); + verify_write_and_record_and_generate_seed(writeOp); + } + break; + case OpType::Write3: + { + TripleWriteOp& writeOp = static_cast(op); + verify_write_and_record_and_generate_seed(writeOp); + } + break; default: break; } diff --git a/src/common/io_exerciser/OpType.h b/src/common/io_exerciser/OpType.h new file mode 100644 index 00000000000..408645f6c25 --- /dev/null +++ b/src/common/io_exerciser/OpType.h @@ -0,0 +1,66 @@ +#pragma once + +#include + +/* Overview + * + * enum OpType + * Enumeration of different types of I/O operation + * + */ + +namespace ceph +{ + namespace io_exerciser + { + enum class OpType + { + Done, // End of I/O sequence + Barrier, // Barrier - all prior I/Os must complete + Create, // Create object and pattern with data + Remove, // Remove object + Read, // Read + Read2, // Two reads in a single op + Read3, // Three reads in a single op + Write, // Write + Write2, // Two writes in a single op + Write3 // Three writes in a single op + }; + } +} + +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) + { + return ctx.begin(); + } + + auto format(ceph::io_exerciser::OpType opType, fmt::format_context& ctx) const -> fmt::format_context::iterator + { + switch (opType) + { + case ceph::io_exerciser::OpType::Done: + return fmt::format_to(ctx.out(), "Done"); + case ceph::io_exerciser::OpType::Barrier: + return fmt::format_to(ctx.out(), "Barrier"); + case ceph::io_exerciser::OpType::Create: + return fmt::format_to(ctx.out(), "Create"); + case ceph::io_exerciser::OpType::Remove: + return fmt::format_to(ctx.out(), "Remove"); + case ceph::io_exerciser::OpType::Read: + return fmt::format_to(ctx.out(), "Read"); + case ceph::io_exerciser::OpType::Read2: + return fmt::format_to(ctx.out(), "Read2"); + case ceph::io_exerciser::OpType::Read3: + return fmt::format_to(ctx.out(), "Read3"); + case ceph::io_exerciser::OpType::Write: + return fmt::format_to(ctx.out(), "Write"); + case ceph::io_exerciser::OpType::Write2: + return fmt::format_to(ctx.out(), "Write2"); + case ceph::io_exerciser::OpType::Write3: + return fmt::format_to(ctx.out(), "Write3"); + } + } +}; \ No newline at end of file diff --git a/src/common/io_exerciser/RadosIo.cc b/src/common/io_exerciser/RadosIo.cc index 44b82260263..4d68c60626e 100644 --- a/src/common/io_exerciser/RadosIo.cc +++ b/src/common/io_exerciser/RadosIo.cc @@ -2,6 +2,8 @@ #include "DataGenerator.h" +#include + using RadosIo = ceph::io_exerciser::RadosIo; RadosIo::RadosIo(librados::Rados& rados, @@ -69,12 +71,9 @@ void RadosIo::allow_ec_overwrites(bool allow) ceph_assert(rc == 0); } -RadosIo::AsyncOpInfo::AsyncOpInfo(uint64_t offset1, uint64_t length1, - uint64_t offset2, uint64_t length2, - uint64_t offset3, uint64_t length3 ) : - offset1(offset1), length1(length1), - offset2(offset2), length2(length2), - offset3(offset3), length3(length3) +template +RadosIo::AsyncOpInfo::AsyncOpInfo(const std::array& offset, const std::array& length) : + offset(offset), length(length) { } @@ -82,42 +81,92 @@ RadosIo::AsyncOpInfo::AsyncOpInfo(uint64_t offset1, uint64_t length1, bool RadosIo::readyForIoOp(IoOp &op) { ceph_assert(ceph_mutex_is_locked_by_me(lock)); //Must be called with lock held - if (!om->readyForIoOp(op)) { + if (!om->readyForIoOp(op)) + { return false; } - switch (op.op) { + + switch (op.getOpType()) + { case OpType::Done: - case OpType::BARRIER: + case OpType::Barrier: return outstanding_io == 0; default: return outstanding_io < threads; } } -void RadosIo::applyIoOp(IoOp &op) +void RadosIo::applyIoOp(IoOp& op) { - std::shared_ptr op_info; - om->applyIoOp(op); // If there are thread concurrent I/Os in flight then wait for // at least one I/O to complete wait_for_io(threads-1); - - switch (op.op) { + + auto applyReadOp = [this](ReadWriteOp readOp) + { + auto op_info = std::make_shared>(readOp.offset, readOp.length); + + for (int i = 0; i < N; i++) + { + op_info->rop.read(readOp.offset[i] * block_size, + readOp.length[i] * block_size, + &op_info->bufferlist[i], nullptr); + } + auto read_cb = [this, op_info] (boost::system::error_code ec, + version_t ver, + bufferlist bl) + { + ceph_assert(ec == boost::system::errc::success); + for (int i = 0; i < N; i++) + { + ceph_assert(db->validate(op_info->bufferlist[i], + op_info->offset[i], + op_info->length[i])); + } + finish_io(); + }; + librados::async_operate(asio, io, oid, + &op_info->rop, 0, nullptr, read_cb); + num_io++; + }; + + auto applyWriteOp = [this](ReadWriteOp writeOp) + { + auto op_info = std::make_shared>(writeOp.offset, writeOp.length); + for (int i = 0; i < N; i++) + { + op_info->bufferlist[i] = db->generate_data(writeOp.offset[i], writeOp.length[i]); + op_info->wop.write(writeOp.offset[i] * block_size, op_info->bufferlist[i]); + } + auto write_cb = [this] (boost::system::error_code ec, + version_t ver) + { + ceph_assert(ec == boost::system::errc::success); + finish_io(); + }; + librados::async_operate(asio, io, oid, + &op_info->wop, 0, nullptr, write_cb); + num_io++; + }; + + switch (op.getOpType()) + { case OpType::Done: [[ fallthrough ]]; - case OpType::BARRIER: + case OpType::Barrier: // Wait for all outstanding I/O to complete wait_for_io(0); - break; + break; - case OpType::CREATE: + case OpType::Create: { start_io(); - op_info = std::make_shared(0, op.length1); - op_info->bl1 = db->generate_data(0, op.length1); - op_info->wop.write_full(op_info->bl1); + uint64_t opSize = static_cast(op).size; + std::shared_ptr> op_info = std::make_shared>(std::array{0}, std::array{opSize}); + op_info->bufferlist[0] = db->generate_data(0, opSize); + op_info->wop.write_full(op_info->bufferlist[0]); auto create_cb = [this] (boost::system::error_code ec, version_t ver) { ceph_assert(ec == boost::system::errc::success); @@ -128,10 +177,10 @@ void RadosIo::applyIoOp(IoOp &op) } break; - case OpType::REMOVE: + case OpType::Remove: { start_io(); - op_info = std::make_shared(); + auto op_info = std::make_shared>(); op_info->wop.remove(); auto remove_cb = [this] (boost::system::error_code ec, version_t ver) { @@ -143,154 +192,51 @@ void RadosIo::applyIoOp(IoOp &op) } break; - case OpType::READ: + case OpType::Read: { start_io(); - op_info = std::make_shared(op.offset1, op.length1); - op_info->rop.read(op.offset1 * block_size, - op.length1 * block_size, - &op_info->bl1, nullptr); - auto read_cb = [this, op_info] (boost::system::error_code ec, - version_t ver, - bufferlist bl) { - ceph_assert(ec == boost::system::errc::success); - ceph_assert(db->validate(op_info->bl1, - op_info->offset1, - op_info->length1)); - finish_io(); - }; - librados::async_operate(asio, io, oid, - &op_info->rop, 0, nullptr, read_cb); - num_io++; + SingleReadOp& readOp = static_cast(op); + applyReadOp(readOp); } break; - case OpType::READ2: + case OpType::Read2: { start_io(); - op_info = std::make_shared(op.offset1, - op.length1, - op.offset2, - op.length2); - - op_info->rop.read(op.offset1 * block_size, - op.length1 * block_size, - &op_info->bl1, nullptr); - op_info->rop.read(op.offset2 * block_size, - op.length2 * block_size, - &op_info->bl2, nullptr); - auto read2_cb = [this, op_info] (boost::system::error_code ec, - version_t ver, - bufferlist bl) { - ceph_assert(ec == boost::system::errc::success); - ceph_assert(db->validate(op_info->bl1, - op_info->offset1, - op_info->length1)); - ceph_assert(db->validate(op_info->bl2, - op_info->offset2, - op_info->length2)); - finish_io(); - }; - librados::async_operate(asio, io, oid, - &op_info->rop, 0, nullptr, read2_cb); - num_io++; + DoubleReadOp& readOp = static_cast(op); + applyReadOp(readOp); } break; - case OpType::READ3: + case OpType::Read3: { start_io(); - op_info = std::make_shared(op.offset1, op.length1, - op.offset2, op.length2, - op.offset3, op.length3); - op_info->rop.read(op.offset1 * block_size, - op.length1 * block_size, - &op_info->bl1, nullptr); - op_info->rop.read(op.offset2 * block_size, - op.length2 * block_size, - &op_info->bl2, nullptr); - op_info->rop.read(op.offset3 * block_size, - op.length3 * block_size, - &op_info->bl3, nullptr); - auto read3_cb = [this, op_info] (boost::system::error_code ec, - version_t ver, - bufferlist bl) { - ceph_assert(ec == boost::system::errc::success); - ceph_assert(db->validate(op_info->bl1, - op_info->offset1, - op_info->length1)); - ceph_assert(db->validate(op_info->bl2, - op_info->offset2, - op_info->length2)); - ceph_assert(db->validate(op_info->bl3, - op_info->offset3, - op_info->length3)); - finish_io(); - }; - librados::async_operate(asio, io, oid, - &op_info->rop, 0, nullptr, read3_cb); - num_io++; + TripleReadOp& readOp = static_cast(op); + applyReadOp(readOp); } break; - case OpType::WRITE: + case OpType::Write: { start_io(); - op_info = std::make_shared(op.offset1, op.length1); - op_info->bl1 = db->generate_data(op.offset1, op.length1); - - op_info->wop.write(op.offset1 * block_size, op_info->bl1); - auto write_cb = [this] (boost::system::error_code ec, - version_t ver) { - ceph_assert(ec == boost::system::errc::success); - finish_io(); - }; - librados::async_operate(asio, io, oid, - &op_info->wop, 0, nullptr, write_cb); - num_io++; + SingleWriteOp& writeOp = static_cast(op); + applyWriteOp(writeOp); } break; - case OpType::WRITE2: + case OpType::Write2: { start_io(); - op_info = std::make_shared(op.offset1, op.length1, - op.offset2, op.length2); - op_info->bl1 = db->generate_data(op.offset1, op.length1); - op_info->bl2 = db->generate_data(op.offset2, op.length2); - op_info->wop.write(op.offset1 * block_size, op_info->bl1); - op_info->wop.write(op.offset2 * block_size, op_info->bl2); - auto write2_cb = [this] (boost::system::error_code ec, - version_t ver) { - ceph_assert(ec == boost::system::errc::success); - finish_io(); - }; - librados::async_operate(asio, io, oid, - &op_info->wop, 0, nullptr, write2_cb); - num_io++; + DoubleWriteOp& writeOp = static_cast(op); + applyWriteOp(writeOp); } break; - case OpType::WRITE3: + case OpType::Write3: { start_io(); - op_info = std::make_shared(op.offset1, op.length1, - op.offset2, op.length2, - op.offset3, op.length3); - op_info->bl1 = db->generate_data(op.offset1, op.length1); - op_info->bl2 = db->generate_data(op.offset2, op.length2); - op_info->bl3 = db->generate_data(op.offset3, op.length3); - op_info->wop.write(op.offset1 * block_size, op_info->bl1); - op_info->wop.write(op.offset2 * block_size, op_info->bl2); - op_info->wop.write(op.offset3 * block_size, op_info->bl3); - auto write3_cb = [this] (boost::system::error_code ec, - version_t ver) { - ceph_assert(ec == boost::system::errc::success); - finish_io(); - }; - librados::async_operate(asio, io, oid, - &op_info->wop, 0, nullptr, write3_cb); - num_io++; + TripleWriteOp& writeOp = static_cast(op); + applyWriteOp(writeOp); } break; diff --git a/src/common/io_exerciser/RadosIo.h b/src/common/io_exerciser/RadosIo.h index 179c5bba3ae..eba80a24368 100644 --- a/src/common/io_exerciser/RadosIo.h +++ b/src/common/io_exerciser/RadosIo.h @@ -18,7 +18,7 @@ namespace ceph { namespace data_generation { class DataGenerator; } - + class RadosIo: public Model { protected: librados::Rados& rados; @@ -35,7 +35,7 @@ namespace ceph { void start_io(); void finish_io(); void wait_for_io(int count); - + public: RadosIo(librados::Rados& rados, boost::asio::io_context& asio, @@ -51,29 +51,22 @@ namespace ceph { void allow_ec_overwrites(bool allow); + template class AsyncOpInfo { public: librados::ObjectReadOperation rop; librados::ObjectWriteOperation wop; - ceph::buffer::list bl1; - ceph::buffer::list bl2; - ceph::buffer::list bl3; - uint64_t offset1; - uint64_t length1; - uint64_t offset2; - uint64_t length2; - uint64_t offset3; - uint64_t length3; + std::array bufferlist; + std::array offset; + std::array length; - AsyncOpInfo(uint64_t offset1 = 0, uint64_t length1 = 0, - uint64_t offset2 = 0, uint64_t length2 = 0, - uint64_t offset3 = 0, uint64_t length3 = 0 ); + AsyncOpInfo(const std::array& offset = {}, + const std::array& length = {}); ~AsyncOpInfo() = default; }; // Must be called with lock held bool readyForIoOp(IoOp& op); - void applyIoOp(IoOp& op); }; } diff --git a/src/test/osd/ceph_test_rados_io_sequence.cc b/src/test/osd/ceph_test_rados_io_sequence.cc index 4a768a016e2..7d473382dc8 100644 --- a/src/test/osd/ceph_test_rados_io_sequence.cc +++ b/src/test/osd/ceph_test_rados_io_sequence.cc @@ -28,6 +28,19 @@ #define dout_subsys ceph_subsys_rados #define dout_context g_ceph_context +using OpType = ceph::io_exerciser::OpType; + +using DoneOp = ceph::io_exerciser::DoneOp; +using BarrierOp = ceph::io_exerciser::BarrierOp; +using CreateOp = ceph::io_exerciser::CreateOp; +using RemoveOp = ceph::io_exerciser::RemoveOp; +using SingleReadOp = ceph::io_exerciser::SingleReadOp; +using DoubleReadOp = ceph::io_exerciser::DoubleReadOp; +using TripleReadOp = ceph::io_exerciser::TripleReadOp; +using SingleWriteOp = ceph::io_exerciser::SingleWriteOp; +using DoubleWriteOp = ceph::io_exerciser::DoubleWriteOp; +using TripleWriteOp = ceph::io_exerciser::TripleWriteOp; + namespace { struct Size {}; void validate(boost::any& v, const std::vector& values, @@ -465,25 +478,33 @@ bool ceph::io_sequence::tester::TestObject::readyForIo() bool ceph::io_sequence::tester::TestObject::next() { - if (!done) { - if (verbose) { + if (!done) + { + if (verbose) + { dout(0) << exerciser_model->get_oid() << " Step " << seq->get_step() << ": " << op->to_string(exerciser_model->get_block_size()) << dendl; - } else { + } + else + { dout(5) << exerciser_model->get_oid() << " Step " << seq->get_step() << ": " << op->to_string(exerciser_model->get_block_size()) << dendl; } exerciser_model->applyIoOp(*op); - if (op->done()) { + if (op->getOpType() == ceph::io_exerciser::OpType::Done) + { ++curseq; - if (curseq == seq_range.second) { + if (curseq == seq_range.second) + { done = true; dout(0) << exerciser_model->get_oid() << " Number of IOs = " << exerciser_model->get_num_io() << dendl; - } else { + } + else + { seq = ceph::io_exerciser::IoSequence::generate_sequence(curseq, obj_size_range, seqseed.value_or(rng())); @@ -492,7 +513,9 @@ bool ceph::io_sequence::tester::TestObject::next() << " ==" <next(); } - } else { + } + else + { op = seq->next(); } } @@ -556,7 +579,8 @@ ceph::io_sequence::tester::TestRunner::~TestRunner() void ceph::io_sequence::tester::TestRunner::help() { std::cout << get_options_description() << std::endl; - for (auto line : usage) { + for (auto line : usage) + { std::cout << line << std::endl; } } @@ -567,7 +591,8 @@ void ceph::io_sequence::tester::TestRunner::list_sequence() std::pair obj_size_range = sos.choose(); for (ceph::io_exerciser::Sequence s = ceph::io_exerciser::Sequence::SEQUENCE_BEGIN; - s < ceph::io_exerciser::Sequence::SEQUENCE_END; ++s) { + s < ceph::io_exerciser::Sequence::SEQUENCE_END; ++s) + { std::unique_ptr seq = ceph::io_exerciser::IoSequence::generate_sequence(s, obj_size_range, @@ -630,11 +655,14 @@ bool ceph::io_sequence::tester::TestRunner::run_interactive_test() std::unique_ptr ioop; std::unique_ptr model; - if (dryrun) { + if (dryrun) + { model = std::make_unique(object_name, sbs.choose(), rng()); - } else { + } + else + { const std::string pool = spo.choose(); model = std::make_unique(rados, asio, pool, object_name, sbs.choose(), @@ -642,64 +670,84 @@ bool ceph::io_sequence::tester::TestRunner::run_interactive_test() lock, cond); } - while (!done) { + while (!done) + { const std::string op = get_token(); - if (!op.compare("done") || !op.compare("q") || !op.compare("quit")) { - ioop = ceph::io_exerciser::IoOp::generate_done(); - } else if (!op.compare("create")) { - ioop = ceph::io_exerciser::IoOp::generate_create(get_numeric_token()); - } else if (!op.compare("remove") || !op.compare("delete")) { - ioop = ceph::io_exerciser::IoOp::generate_remove(); - } else if (!op.compare("read")) { + if (!op.compare("done") || !op.compare("q") || !op.compare("quit")) + { + ioop = DoneOp::generate(); + } + else if (!op.compare("create")) + { + ioop = CreateOp::generate(get_numeric_token()); + } + else if (!op.compare("remove") || !op.compare("delete")) + { + ioop = RemoveOp::generate(); + } + else if (!op.compare("read")) + { uint64_t offset = get_numeric_token(); uint64_t length = get_numeric_token(); - ioop = ceph::io_exerciser::IoOp::generate_read(offset, length); - } else if (!op.compare("read2")) { + ioop = SingleReadOp::generate(offset, length); + } + else if (!op.compare("read2")) + { uint64_t offset1 = get_numeric_token(); uint64_t length1 = get_numeric_token(); uint64_t offset2 = get_numeric_token(); uint64_t length2 = get_numeric_token(); - ioop = ceph::io_exerciser::IoOp::generate_read2(offset1, length1, - offset2, length2); - } else if (!op.compare("read3")) { + ioop = DoubleReadOp::generate(offset1, length1, + offset2, length2); + } + else if (!op.compare("read3")) + { uint64_t offset1 = get_numeric_token(); uint64_t length1 = get_numeric_token(); uint64_t offset2 = get_numeric_token(); uint64_t length2 = get_numeric_token(); uint64_t offset3 = get_numeric_token(); uint64_t length3 = get_numeric_token(); - ioop = ceph::io_exerciser::IoOp::generate_read3(offset1, length1, - offset2, length2, - offset3, length3); - } else if (!op.compare("write")) { + ioop = TripleReadOp::generate(offset1, length1, + offset2, length2, + offset3, length3); + } + else if (!op.compare("write")) + { uint64_t offset = get_numeric_token(); uint64_t length = get_numeric_token(); - ioop = ceph::io_exerciser::IoOp::generate_write(offset, length); - } else if (!op.compare("write2")) { + ioop = SingleWriteOp::generate(offset, length); + } + else if (!op.compare("write2")) + { uint64_t offset1 = get_numeric_token(); uint64_t length1 = get_numeric_token(); uint64_t offset2 = get_numeric_token(); uint64_t length2 = get_numeric_token(); - ioop = ceph::io_exerciser::IoOp::generate_write2(offset1, length1, - offset2, length2); - } else if (!op.compare("write3")) { + ioop = DoubleWriteOp::generate(offset1, length1, + offset2, length2); + } + else if (!op.compare("write3")) + { uint64_t offset1 = get_numeric_token(); uint64_t length1 = get_numeric_token(); uint64_t offset2 = get_numeric_token(); uint64_t length2 = get_numeric_token(); uint64_t offset3 = get_numeric_token(); uint64_t length3 = get_numeric_token(); - ioop = ceph::io_exerciser::IoOp::generate_write3(offset1, length1, - offset2, length2, - offset3, length3); - } else { + ioop = TripleWriteOp::generate(offset1, length1, + offset2, length2, + offset3, length3); + } + else + { throw std::runtime_error("Invalid operation "+op); } dout(0) << ioop->to_string(model->get_block_size()) << dendl; model->applyIoOp(*ioop); - done = ioop->done(); + done = ioop->getOpType() == OpType::Done; if (!done) { - ioop = ceph::io_exerciser::IoOp::generate_barrier(); + ioop = BarrierOp::generate(); model->applyIoOp(*ioop); } } @@ -731,7 +779,8 @@ bool ceph::io_sequence::tester::TestRunner::run_automated_test() ) ); } - if (!dryrun) { + if (!dryrun) + { rados.wait_for_latest_osdmap(); } -- 2.39.5