using SingleFailedWriteOp = ceph::io_exerciser::SingleFailedWriteOp;
using DoubleFailedWriteOp = ceph::io_exerciser::DoubleFailedWriteOp;
using TripleFailedWriteOp = ceph::io_exerciser::TripleFailedWriteOp;
+using SingleAppendOp = ceph::io_exerciser::SingleAppendOp;
namespace {
std::string value_to_string(uint64_t v) {
std::string ceph::io_exerciser::ReadWriteOp<opType, numIOs>::to_string(
uint64_t block_size) const {
std::string offset_length_desc;
+ std::string 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));
+ length_desc += fmt::format("length1={}",
+ value_to_string(this->length[0] * block_size));
+ offset_length_desc += "," + length_desc;
for (int i = 1; i < numIOs; i++) {
+ std::string length;
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));
+ length += fmt::format(",length{}={}", i + 1,
+ value_to_string(this->length[i] * block_size));
+ length_desc += length;
+ offset_length_desc += length;
}
}
switch (opType) {
[[fallthrough]];
case OpType::Write3:
return fmt::format("Write{} ({})", numIOs, offset_length_desc);
+ case OpType::Append:
+ return fmt::format("Append{} ({})", numIOs, length_desc);
case OpType::FailedWrite:
[[fallthrough]];
case OpType::FailedWrite2:
offset3, length3);
}
+SingleAppendOp::SingleAppendOp(uint64_t length)
+ : ReadWriteOp<OpType::Append, 1>({0}, {length}) {}
+
+std::unique_ptr<SingleAppendOp> SingleAppendOp::generate(uint64_t length) {
+ return std::make_unique<SingleAppendOp>(length);
+}
+
SingleFailedWriteOp::SingleFailedWriteOp(uint64_t offset, uint64_t length)
: ReadWriteOp<OpType::FailedWrite, 1>({offset}, {length}) {}
ceph::io_exerciser ::ClearWriteErrorInjectOp::generate(
int shard, const std::optional<uint64_t>& type) {
return std::make_unique<ClearWriteErrorInjectOp>(shard, type);
-}
\ No newline at end of file
+}
uint64_t offset3, uint64_t length3);
};
+class SingleAppendOp : public ReadWriteOp<OpType::Append, 1> {
+ public:
+ SingleAppendOp(uint64_t length);
+ static std::unique_ptr<SingleAppendOp> generate(uint64_t length);
+};
+
class SingleFailedWriteOp : public ReadWriteOp<OpType::FailedWrite, 1> {
public:
SingleFailedWriteOp(uint64_t offset, uint64_t length);
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());
+ if (writeOp.offset[i] + writeOp.length[i] > contents.size()) {
+ contents.resize(writeOp.offset[i] + writeOp.length[i]);
+ }
std::generate(std::execution::seq,
std::next(contents.begin(), writeOp.offset[i]),
std::next(contents.begin(),
TripleWriteOp& writeOp = static_cast<TripleWriteOp&>(op);
verify_write_and_record_and_generate_seed(writeOp);
} break;
+
+ case OpType::Append: {
+ ceph_assert(created);
+ SingleAppendOp& appendOp = static_cast<SingleAppendOp&>(op);
+ appendOp.offset[0] = contents.size();
+ verify_write_and_record_and_generate_seed(appendOp);
+ } break;
+
case OpType::FailedWrite: {
ceph_assert(created);
SingleWriteOp& writeOp = static_cast<SingleWriteOp&>(op);
case OpType::FailedWrite2: {
DoubleWriteOp& writeOp = static_cast<DoubleWriteOp&>(op);
verify_failed_write_and_record(writeOp);
+
} break;
case OpType::FailedWrite3: {
TripleWriteOp& writeOp = static_cast<TripleWriteOp&>(op);
Write, // Write
Write2, // Two writes in a single op
Write3, // Three writes in a single op
+ Append, // Append
FailedWrite, // A write which should fail
FailedWrite2, // Two writes in one op which should fail
FailedWrite3, // Three writes in one op which should fail
return fmt::format_to(ctx.out(), "Write2");
case ceph::io_exerciser::OpType::Write3:
return fmt::format_to(ctx.out(), "Write3");
+ case ceph::io_exerciser::OpType::Append:
+ return fmt::format_to(ctx.out(), "Append");
case ceph::io_exerciser::OpType::FailedWrite:
return fmt::format_to(ctx.out(), "FailedWrite");
case ceph::io_exerciser::OpType::FailedWrite2:
return fmt::format_to(ctx.out(), "Unknown OpType");
}
}
-};
\ No newline at end of file
+};
[[fallthrough]];
case OpType::Write3:
[[fallthrough]];
+ case OpType::Append:
+ [[fallthrough]];
case OpType::FailedWrite:
[[fallthrough]];
case OpType::FailedWrite2:
break;
}
+ case OpType::Append: {
+ start_io();
+ SingleAppendOp& appendOp = static_cast<SingleAppendOp&>(op);
+ applyWriteOp(appendOp);
+ break;
+ }
+
case OpType::FailedWrite: {
start_io();
SingleFailedWriteOp& writeOp = static_cast<SingleFailedWriteOp&>(op);
using SingleWriteOp = ceph::io_exerciser::SingleWriteOp;
using DoubleWriteOp = ceph::io_exerciser::DoubleWriteOp;
using TripleWriteOp = ceph::io_exerciser::TripleWriteOp;
+using SingleAppendOp = ceph::io_exerciser::SingleAppendOp;
using SingleFailedWriteOp = ceph::io_exerciser::SingleFailedWriteOp;
using DoubleFailedWriteOp = ceph::io_exerciser::DoubleFailedWriteOp;
using TripleFailedWriteOp = ceph::io_exerciser::TripleFailedWriteOp;
tokens = split.end();
}
-std::string ceph::io_sequence::tester::TestRunner::get_token() {
+std::string ceph::io_sequence::tester::TestRunner::get_token(bool allow_eof) {
while (line.empty() || tokens == split.end()) {
if (!std::getline(std::cin, line)) {
+ if (allow_eof) {
+ return "done";
+ }
throw std::runtime_error("End of input");
}
split = ceph::split(line);
}
while (!done) {
- const std::string op = get_token();
+ const std::string op = get_token(true);
if (op == "done" || op == "q" || op == "quit") {
ioop = ceph::io_exerciser::DoneOp::generate();
} else if (op == "create") {
uint64_t length3 = get_numeric_token();
ioop = TripleWriteOp::generate(offset1, length1, offset2, length2,
offset3, length3);
+ } else if (op == "append") {
+ uint64_t length = get_numeric_token();
+ ioop = SingleAppendOp::generate(length);
} else if (op == "failedwrite") {
uint64_t offset = get_numeric_token();
uint64_t length = get_numeric_token();
ceph::spliterator tokens;
void clear_tokens();
- std::string get_token();
+ std::string get_token(bool allow_eof = false);
std::optional<std::string> get_optional_token();
uint64_t get_numeric_token();
std::optional<uint64_t> get_optional_numeric_token();