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 <jonathan.bailey1@ibm.com>
#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<OpType opType>
+ceph::io_exerciser::TestOp<opType>::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> IoOp
- ::generate_done() {
+DoneOp::DoneOp() : TestOp<OpType::Done>()
+{
- return std::make_unique<IoOp>(OpType::Done);
}
-std::unique_ptr<IoOp> IoOp
- ::generate_barrier() {
+std::string DoneOp::to_string(uint64_t block_size) const
+{
+ return "Done";
+}
- return std::make_unique<IoOp>(OpType::BARRIER);
+std::unique_ptr<DoneOp> DoneOp::generate()
+{
+ return std::make_unique<DoneOp>();
}
-std::unique_ptr<IoOp> IoOp
- ::generate_create(uint64_t size) {
+BarrierOp::BarrierOp() : TestOp<OpType::Barrier>()
+{
- return std::make_unique<IoOp>(OpType::CREATE,0,size);
}
-std::unique_ptr<IoOp> IoOp
- ::generate_remove() {
+std::unique_ptr<BarrierOp> BarrierOp::generate()
+{
+ return std::make_unique<BarrierOp>();
+}
- return std::make_unique<IoOp>(OpType::REMOVE);
+std::string BarrierOp::to_string(uint64_t block_size) const
+{
+ return "Barrier";
}
-std::unique_ptr<IoOp> IoOp
- ::generate_read(uint64_t offset, uint64_t length) {
+CreateOp::CreateOp(uint64_t size) : TestOp<OpType::Create>(),
+ size(size)
+{
- return std::make_unique<IoOp>(OpType::READ, offset, length);
}
-std::unique_ptr<IoOp> IoOp
- ::generate_read2(uint64_t offset1, uint64_t length1,
- uint64_t offset2, uint64_t length2) {
+std::unique_ptr<CreateOp> CreateOp::generate(uint64_t size)
+{
+ return std::make_unique<CreateOp>(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<OpType::Remove>()
+{
+
+}
- return std::make_unique<IoOp>(OpType::READ2,
- offset1, length1,
- offset2, length2);
+std::unique_ptr<RemoveOp> RemoveOp::generate()
+{
+ return std::make_unique<RemoveOp>();
}
-std::unique_ptr<IoOp> 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<OpType opType, int numIOs>
+ceph::io_exerciser::ReadWriteOp<opType, numIOs>
+ ::ReadWriteOp(std::array<uint64_t, numIOs>&& offset,
+ std::array<uint64_t, numIOs>&& length) :
+ TestOp<opType>(),
+ 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<OpType opType, int numIOs>
+std::string ceph::io_exerciser::ReadWriteOp<opType, numIOs>
+ ::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<IoOp>(OpType::READ3,
- offset1, length1,
- offset2, length2,
- offset3, length3);
}
-std::unique_ptr<IoOp> IoOp::generate_write(uint64_t offset, uint64_t length) {
- return std::make_unique<IoOp>(OpType::WRITE, offset, length);
+SingleReadOp::SingleReadOp(uint64_t offset, uint64_t length) :
+ ReadWriteOp<OpType::Read, 1>({offset}, {length})
+{
+
}
-std::unique_ptr<IoOp> 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<IoOp>(OpType::WRITE2,
- offset1, length1,
- offset2, length2);
-}
-
-std::unique_ptr<IoOp> 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<IoOp>(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> SingleReadOp::generate(uint64_t offset,
+ uint64_t length)
+{
+ return std::make_unique<SingleReadOp>(offset, length);
+}
+
+DoubleReadOp::DoubleReadOp(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2) :
+ ReadWriteOp<OpType::Read2, 2>({offset1, offset2}, {length1, length2})
+{
+
+}
+
+std::unique_ptr<DoubleReadOp> DoubleReadOp::generate(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2)
+{
+ return std::make_unique<DoubleReadOp>(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<OpType::Read3, 3>({offset1, offset2, offset3},
+ {length1, length2, length3})
+{
+
+}
+
+std::unique_ptr<TripleReadOp> TripleReadOp::generate(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2,
+ uint64_t offset3, uint64_t length3)
+{
+ return std::make_unique<TripleReadOp>(offset1, length1,
+ offset2, length2,
+ offset3, length3);
+}
+
+SingleWriteOp::SingleWriteOp(uint64_t offset, uint64_t length) :
+ ReadWriteOp<OpType::Write, 1>({offset}, {length})
+{
+
+}
+
+std::unique_ptr<SingleWriteOp> SingleWriteOp::generate(uint64_t offset, uint64_t length)
+{
+ return std::make_unique<SingleWriteOp>(offset, length);
+}
+
+DoubleWriteOp::DoubleWriteOp(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2) :
+ ReadWriteOp<OpType::Write2, 2>({offset1, offset2}, {length1, length2})
+{
+
+}
+
+std::unique_ptr<DoubleWriteOp> DoubleWriteOp::generate(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2)
+{
+ return std::make_unique<DoubleWriteOp>(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<OpType::Write3, 3>({offset1, offset2, offset3}, {length1, length2, length3})
+{
+
+}
+
+std::unique_ptr<TripleWriteOp> TripleWriteOp::generate(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2,
+ uint64_t offset3, uint64_t length3)
+{
+ return std::make_unique<TripleWriteOp>(offset1, length1,
+ offset2, length2,
+ offset3, length3);
}
\ No newline at end of file
#pragma once
+#include <array>
#include <string>
#include <memory>
#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
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<IoOp> generate_done();
+ template<OpType opType>
+ class TestOp : public IoOp
+ {
+ public:
+ TestOp();
+ constexpr OpType getOpType() const override { return opType; }
+ };
- static std::unique_ptr<IoOp> generate_barrier();
+ class DoneOp : public TestOp<OpType::Done>
+ {
+ public:
+ DoneOp();
+ static std::unique_ptr<DoneOp> generate();
+ std::string to_string(uint64_t block_size) const override;
+ };
- static std::unique_ptr<IoOp> generate_create(uint64_t size);
+ class BarrierOp : public TestOp<OpType::Barrier>
+ {
+ public:
+ BarrierOp();
+ static std::unique_ptr<BarrierOp> generate();
+ std::string to_string(uint64_t block_size) const override;
+ };
- static std::unique_ptr<IoOp> generate_remove();
+ class CreateOp : public TestOp<OpType::Create>
+ {
+ public:
+ CreateOp(uint64_t size);
+ static std::unique_ptr<CreateOp> generate(uint64_t size);
+ std::string to_string(uint64_t block_size) const override;
+ uint64_t size;
+ };
- static std::unique_ptr<IoOp> generate_read(uint64_t offset,
- uint64_t length);
+ class RemoveOp : public TestOp<OpType::Remove>
+ {
+ public:
+ RemoveOp();
+ static std::unique_ptr<RemoveOp> generate();
+ std::string to_string(uint64_t block_size) const override;
+ };
- static std::unique_ptr<IoOp> generate_read2(uint64_t offset1,
- uint64_t length1,
- uint64_t offset2,
- uint64_t length2);
+ template<OpType opType, int numIOs>
+ class ReadWriteOp : public TestOp<opType>
+ {
+ public:
+ std::array<uint64_t, numIOs> offset;
+ std::array<uint64_t, numIOs> length;
+
+ protected:
+ ReadWriteOp(std::array<uint64_t, numIOs>&& offset,
+ std::array<uint64_t, numIOs>&& length);
+ std::string to_string(uint64_t block_size) const override;
+ };
- static std::unique_ptr<IoOp> generate_read3(uint64_t offset1,
- uint64_t length1,
- uint64_t offset2,
- uint64_t length2,
- uint64_t offset3,
- uint64_t length3);
+ class SingleReadOp : public ReadWriteOp<OpType::Read, 1>
+ {
+ public:
+ SingleReadOp(uint64_t offset, uint64_t length);
+ static std::unique_ptr<SingleReadOp> generate(uint64_t offset,
+ uint64_t length);
+ };
- static std::unique_ptr<IoOp> generate_write(uint64_t offset,
- uint64_t length);
+ class DoubleReadOp : public ReadWriteOp<OpType::Read2, 2>
+ {
+ public:
+ DoubleReadOp(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2);
+ static std::unique_ptr<DoubleReadOp> generate(uint64_t offset1,
+ uint64_t length1,
+ uint64_t offset2,
+ uint64_t length2);
+ };
- static std::unique_ptr<IoOp> generate_write2(uint64_t offset1,
- uint64_t length1,
- uint64_t offset2,
- uint64_t length2);
+ class TripleReadOp : public ReadWriteOp<OpType::Read3, 3>
+ {
+ public:
+ TripleReadOp(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2,
+ uint64_t offset3, uint64_t length3);
+ static std::unique_ptr<TripleReadOp> generate(uint64_t offset1,
+ uint64_t length1,
+ uint64_t offset2,
+ uint64_t length2,
+ uint64_t offset3,
+ uint64_t length3);
+ };
- static std::unique_ptr<IoOp> generate_write3(uint64_t offset1,
- uint64_t length1,
- uint64_t offset2,
- uint64_t length2,
- uint64_t offset3,
- uint64_t length3);
+ class SingleWriteOp : public ReadWriteOp<OpType::Write, 1>
+ {
+ public:
+ SingleWriteOp(uint64_t offset, uint64_t length);
+ static std::unique_ptr<SingleWriteOp> generate(uint64_t offset,
+ uint64_t length);
+ };
- bool done();
+ class DoubleWriteOp : public ReadWriteOp<OpType::Write2, 2>
+ {
+ public:
+ DoubleWriteOp(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2);
+ static std::unique_ptr<DoubleWriteOp> 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<OpType::Write3, 3>
+ {
+ public:
+ TripleWriteOp(uint64_t offset1, uint64_t length1,
+ uint64_t offset2, uint64_t length2,
+ uint64_t offset3, uint64_t length3);
+ static std::unique_ptr<TripleWriteOp> 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
#include "IoSequence.h"
+using IoOp = ceph::io_exerciser::IoOp;
using Sequence = ceph::io_exerciser::Sequence;
using IoSequence = ceph::io_exerciser::IoSequence;
return os;
}
-IoSequence::IoSequence(std::pair<int,int> 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> IoSequence::generate_sequence(Sequence s,
std::pair<int,int> obj_size_range,
int seed)
return nullptr;
}
+IoSequence::IoSequence(std::pair<int,int> 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;
}
}
-std::unique_ptr<ceph::io_exerciser::IoOp> IoSequence::increment_object_size()
+std::unique_ptr<IoOp> IoSequence::increment_object_size()
{
obj_size++;
if (obj_size > max_obj_size) {
create = true;
barrier = true;
remove = true;
- return IoOp::generate_barrier();
+ return BarrierOp::generate();
}
-std::unique_ptr<ceph::io_exerciser::IoOp> IoSequence::next()
+std::unique_ptr<IoOp> 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();
}
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;
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);
+ }
}
return increment_object_size();
}
}
- return IoOp::generate_read(offset, length);
+ return SingleReadOp::generate(offset, length);
}
return increment_object_size();
}
}
- return IoOp::generate_read2(offset1, 1, offset1 + offset2, 1);
+ return DoubleReadOp::generate(offset1, 1, offset1 + offset2, 1);
}
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);
}
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;
}
}
uint64_t io_len = (offset + length > obj_size) ? (obj_size - offset) : length;
- std::unique_ptr<IoOp> r = IoOp::generate_write(offset, io_len);
+ std::unique_ptr<IoOp> r = SingleWriteOp::generate(offset, io_len);
offset += io_len;
return r;
}
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;
if (io_len == 0) {
io_len = length;
}
- std::unique_ptr<IoOp> r = IoOp::generate_write(offset, io_len);
+ std::unique_ptr<IoOp> r = SingleWriteOp::generate(offset, io_len);
offset += io_len;
return r;
}
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;
}
doneread = false;
donebarrier = false;
- return IoOp::generate_write2(offset, 1, obj_size/2, 1);
+ return DoubleReadOp::generate(offset, 1, obj_size/2, 1);
}
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) {
}
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);
}
ceph::io_exerciser::Seq9::Seq9(std::pair<int,int> obj_size_range, int seed) :
IoSequence(obj_size_range, seed), offset(0), length(0)
{
-
+
}
std::string ceph::io_exerciser::Seq9::get_name() const
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) {
}
doneread = false;
donebarrier = false;
- return IoOp::generate_write(offset, length);
+ return SingleWriteOp::generate(offset, length);
}
\ No newline at end of file
int get_step() const;
int get_seed() const;
- std::unique_ptr<IoOp> next();
+ virtual std::unique_ptr<IoOp> next();
static std::unique_ptr<IoSequence>
- generate_sequence(Sequence s, std::pair<int,int> obj_size_range, int seed );
+ generate_sequence(Sequence s,
+ std::pair<int,int> obj_size_range,
+ int seed );
protected:
uint64_t min_obj_size;
void set_max_object_size(uint64_t size);
void select_random_object_size();
std::unique_ptr<IoOp> increment_object_size();
-
};
class Seq0: public IoSequence {
uint64_t length;
};
- class Seq1: public IoSequence {
+ class Seq1: public IoSequence {
public:
Seq1(std::pair<int,int> obj_size_range, int seed);
private:
int count;
};
-
+
class Seq2: public IoSequence {
public:
Seq2(std::pair<int,int> obj_size_range, int seed);
std::string get_name() const override;
std::unique_ptr<IoOp> _next() override;
-
+
private:
uint64_t offset;
uint64_t length;
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 ]
+ <OpType opType, int N>
+ (ReadWriteOp<opType, N>& 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 ]
+ <OpType opType, int N>
+ (ReadWriteOp<opType, N> 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<CreateOp&>(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());
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<SingleReadOp&>(op);
+ verify_and_record_read_op(readOp);
+ }
+ break;
+ case OpType::Read2:
+ {
+ DoubleReadOp& readOp = static_cast<DoubleReadOp&>(op);
+ verify_and_record_read_op(readOp);
+ }
+ break;
+ case OpType::Read3:
+ {
+ TripleReadOp& readOp = static_cast<TripleReadOp&>(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<SingleWriteOp&>(op);
+ verify_write_and_record_and_generate_seed(writeOp);
+ }
+ break;
+ case OpType::Write2:
+ {
+ DoubleWriteOp& writeOp = static_cast<DoubleWriteOp&>(op);
+ verify_write_and_record_and_generate_seed(writeOp);
+ }
+ break;
+ case OpType::Write3:
+ {
+ TripleWriteOp& writeOp = static_cast<TripleWriteOp&>(op);
+ verify_write_and_record_and_generate_seed(writeOp);
+ }
+ break;
default:
break;
}
--- /dev/null
+#pragma once
+
+#include <fmt/format.h>
+
+/* 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<ceph::io_exerciser::OpType>
+{
+ 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
#include "DataGenerator.h"
+#include <ranges>
+
using RadosIo = ceph::io_exerciser::RadosIo;
RadosIo::RadosIo(librados::Rados& rados,
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 <int N>
+RadosIo::AsyncOpInfo<N>::AsyncOpInfo(const std::array<uint64_t, N>& offset, const std::array<uint64_t, N>& length) :
+ offset(offset), length(length)
{
}
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<AsyncOpInfo> 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]<OpType opType, int N>(ReadWriteOp<opType, N> readOp)
+ {
+ auto op_info = std::make_shared<AsyncOpInfo<N>>(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]<OpType opType, int N>(ReadWriteOp<opType, N> writeOp)
+ {
+ auto op_info = std::make_shared<AsyncOpInfo<N>>(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<AsyncOpInfo>(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<CreateOp&>(op).size;
+ std::shared_ptr<AsyncOpInfo<1>> op_info = std::make_shared<AsyncOpInfo<1>>(std::array<uint64_t,1>{0}, std::array<uint64_t,1>{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);
}
break;
- case OpType::REMOVE:
+ case OpType::Remove:
{
start_io();
- op_info = std::make_shared<AsyncOpInfo>();
+ auto op_info = std::make_shared<AsyncOpInfo<0>>();
op_info->wop.remove();
auto remove_cb = [this] (boost::system::error_code ec,
version_t ver) {
}
break;
- case OpType::READ:
+ case OpType::Read:
{
start_io();
- op_info = std::make_shared<AsyncOpInfo>(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<SingleReadOp&>(op);
+ applyReadOp(readOp);
}
break;
- case OpType::READ2:
+ case OpType::Read2:
{
start_io();
- op_info = std::make_shared<AsyncOpInfo>(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<DoubleReadOp&>(op);
+ applyReadOp(readOp);
}
break;
- case OpType::READ3:
+ case OpType::Read3:
{
start_io();
- op_info = std::make_shared<AsyncOpInfo>(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<TripleReadOp&>(op);
+ applyReadOp(readOp);
}
break;
- case OpType::WRITE:
+ case OpType::Write:
{
start_io();
- op_info = std::make_shared<AsyncOpInfo>(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<SingleWriteOp&>(op);
+ applyWriteOp(writeOp);
}
break;
- case OpType::WRITE2:
+ case OpType::Write2:
{
start_io();
- op_info = std::make_shared<AsyncOpInfo>(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<DoubleWriteOp&>(op);
+ applyWriteOp(writeOp);
}
break;
- case OpType::WRITE3:
+ case OpType::Write3:
{
start_io();
- op_info = std::make_shared<AsyncOpInfo>(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<TripleWriteOp&>(op);
+ applyWriteOp(writeOp);
}
break;
namespace data_generation {
class DataGenerator;
}
-
+
class RadosIo: public Model {
protected:
librados::Rados& rados;
void start_io();
void finish_io();
void wait_for_io(int count);
-
+
public:
RadosIo(librados::Rados& rados,
boost::asio::io_context& asio,
void allow_ec_overwrites(bool allow);
+ template <int N>
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<ceph::bufferlist, N> bufferlist;
+ std::array<uint64_t, N> offset;
+ std::array<uint64_t, N> 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<uint64_t, N>& offset = {},
+ const std::array<uint64_t, N>& length = {});
~AsyncOpInfo() = default;
};
// Must be called with lock held
bool readyForIoOp(IoOp& op);
-
void applyIoOp(IoOp& op);
};
}
#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<std::string>& values,
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()));
<< " ==" <<dendl;
op = seq->next();
}
- } else {
+ }
+ else
+ {
op = seq->next();
}
}
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;
}
}
std::pair<int,int> 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<ceph::io_exerciser::IoSequence> seq =
ceph::io_exerciser::IoSequence::generate_sequence(s,
obj_size_range,
std::unique_ptr<ceph::io_exerciser::IoOp> ioop;
std::unique_ptr<ceph::io_exerciser::Model> model;
- if (dryrun) {
+ if (dryrun)
+ {
model = std::make_unique<ceph::io_exerciser::ObjectModel>(object_name,
sbs.choose(),
rng());
- } else {
+ }
+ else
+ {
const std::string pool = spo.choose();
model = std::make_unique<ceph::io_exerciser::RadosIo>(rados, asio, pool,
object_name, sbs.choose(),
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);
}
}
)
);
}
- if (!dryrun) {
+ if (!dryrun)
+ {
rados.wait_for_latest_osdmap();
}