]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
src/common/io_exerciser: Code readability improvements
authorJonBailey1993 <jonathan.bailey1@ibm.com>
Tue, 1 Oct 2024 10:25:48 +0000 (11:25 +0100)
committerJon Bailey <jonathan.bailey1@ibm.com>
Tue, 7 Jan 2025 11:40:32 +0000 (11:40 +0000)
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>
src/common/io_exerciser/IoOp.cc
src/common/io_exerciser/IoOp.h
src/common/io_exerciser/IoSequence.cc
src/common/io_exerciser/IoSequence.h
src/common/io_exerciser/ObjectModel.cc
src/common/io_exerciser/OpType.h [new file with mode: 0644]
src/common/io_exerciser/RadosIo.cc
src/common/io_exerciser/RadosIo.h
src/test/osd/ceph_test_rados_io_sequence.cc

index cd855ba6fff8a9024bc619ab9490c5d859543a77..2a5a60e4a24733b764853b1b614ac340c48f5629 100644 (file)
 #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
index 60c02a93d4e221891567d5448ea041e6ea198fbd..2f9f169d954031e621ea25320ade9ac11a4ec108 100644 (file)
@@ -1,13 +1,13 @@
 #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
index 4a7ca0593d1d2a956f9d17e69683ecaa8e6fbccf..d4b7af40b413747c496b88d0febeeb56bff86f44 100644 (file)
@@ -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<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)
@@ -84,6 +76,15 @@ std::unique_ptr<IoSequence> IoSequence::generate_sequence(Sequence s,
   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;
@@ -120,7 +121,7 @@ void IoSequence::select_random_object_size()
   }
 }
 
-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) {
@@ -129,27 +130,27 @@ std::unique_ptr<ceph::io_exerciser::IoOp> IoSequence::increment_object_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();
 }
@@ -176,12 +177,12 @@ std::unique_ptr<ceph::io_exerciser::IoOp> 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::IoOp> 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::IoOp> 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::IoOp> 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::IoOp> 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::IoOp> 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::IoOp> ceph::io_exerciser::Seq5::_next()
     }
   }
   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;
 }
@@ -355,11 +361,11 @@ std::unique_ptr<ceph::io_exerciser::IoOp> 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::IoOp> ceph::io_exerciser::Seq6::_next()
   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;
 }
@@ -398,11 +404,11 @@ std::unique_ptr<ceph::io_exerciser::IoOp> 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::IoOp> 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::IoOp> 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::IoOp> 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::IoOp> ceph::io_exerciser::Seq8::_next()
 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
@@ -478,11 +482,11 @@ std::unique_ptr<ceph::io_exerciser::IoOp> 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::IoOp> 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
index 114ff76303f468523a45b8279dbae74b8e50f736..ccce4336c226fe7063cb2513e312adfaee348439 100644 (file)
@@ -64,10 +64,12 @@ namespace ceph {
       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;
@@ -90,7 +92,6 @@ namespace ceph {
       void set_max_object_size(uint64_t size);
       void select_random_object_size();
       std::unique_ptr<IoOp> 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<int,int> obj_size_range, int seed);
 
@@ -115,14 +116,14 @@ namespace ceph {
     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;
index 589f6434282b360db00ce899df4952101f62c9bd..350b8e5756b1edaeb4b6026559ec2f75fe24df1f 100644 (file)
@@ -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  ]
+                                    <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());
@@ -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<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;
   }
diff --git a/src/common/io_exerciser/OpType.h b/src/common/io_exerciser/OpType.h
new file mode 100644 (file)
index 0000000..408645f
--- /dev/null
@@ -0,0 +1,66 @@
+#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
index 44b82260263a209e94cc70881398990be23fddd2..4d68c60626e4824231ec02d0c7d9d9cc21442d31 100644 (file)
@@ -2,6 +2,8 @@
 
 #include "DataGenerator.h"
 
+#include <ranges>
+
 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 <int N>
+RadosIo::AsyncOpInfo<N>::AsyncOpInfo(const std::array<uint64_t, N>& offset, const std::array<uint64_t, N>& 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(IoOpop)
 {
-  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);
@@ -128,10 +177,10 @@ void RadosIo::applyIoOp(IoOp &op)
     }
     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) {
@@ -143,154 +192,51 @@ void RadosIo::applyIoOp(IoOp &op)
     }
     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;
 
index 179c5bba3aea0a8ce16470623896ccb7fa91dce2..eba80a243681a169f42ad45b921cf0fdad6d56ad 100644 (file)
@@ -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 <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);
     };
   }
index 4a768a016e28c8641025b58080e9643ba7278fab..7d473382dc85185bafcab88dd509aa6c818d7c39 100644 (file)
 #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,
@@ -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()
                 << " ==" <<dendl;
         op = seq->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<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,
@@ -630,11 +655,14 @@ bool ceph::io_sequence::tester::TestRunner::run_interactive_test()
   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(),
@@ -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();
   }