Skip to content

Commit e2ef125

Browse files
committed
common/io_exerciser: Add simple sequences for testing error injects
Add sequences to test IOs with simple error injects, along with some small fixes for previous error inject implementation. Signed-off-by: Jon Bailey <[email protected]>
1 parent 347ba63 commit e2ef125

File tree

12 files changed

+888
-63
lines changed

12 files changed

+888
-63
lines changed

src/common/io_exerciser/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_library(object_io_exerciser STATIC
66
ObjectModel.cc
77
RadosIo.cc
88
JsonStructures.cc
9+
EcIoSequence.cc
910
)
1011

1112
target_link_libraries(object_io_exerciser

src/common/io_exerciser/DataGenerator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ namespace ceph {
6565
: DataGenerator(model) {}
6666

6767
virtual bufferptr generate_block(uint64_t offset);
68-
virtual bufferlist generate_data(uint64_t length, uint64_t offset);
68+
virtual bufferlist generate_data(uint64_t length, uint64_t offset) override;
6969
virtual bufferptr generate_wrong_block(uint64_t offset);
7070
virtual bufferlist generate_wrong_data(uint64_t offset, uint64_t length) override;
7171
};
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
#include "EcIoSequence.h"
2+
3+
#include <memory>
4+
5+
using IoOp = ceph::io_exerciser::IoOp;
6+
using Sequence = ceph::io_exerciser::Sequence;
7+
using IoSequence = ceph::io_exerciser::IoSequence;
8+
using EcIoSequence = ceph::io_exerciser::EcIoSequence;
9+
using ReadInjectSequence = ceph::io_exerciser::ReadInjectSequence;
10+
11+
bool EcIoSequence::is_supported(Sequence sequence) const
12+
{
13+
return true;
14+
}
15+
16+
std::unique_ptr<IoSequence> EcIoSequence::generate_sequence(Sequence sequence,
17+
std::pair<int,int> obj_size_range,
18+
int k,
19+
int m,
20+
int seed)
21+
{
22+
switch(sequence)
23+
{
24+
case Sequence::SEQUENCE_SEQ0:
25+
[[ fallthrough ]];
26+
case Sequence::SEQUENCE_SEQ1:
27+
[[ fallthrough ]];
28+
case Sequence::SEQUENCE_SEQ2:
29+
[[ fallthrough ]];
30+
case Sequence::SEQUENCE_SEQ3:
31+
[[ fallthrough ]];
32+
case Sequence::SEQUENCE_SEQ4:
33+
[[ fallthrough ]];
34+
case Sequence::SEQUENCE_SEQ5:
35+
[[ fallthrough ]];
36+
case Sequence::SEQUENCE_SEQ6:
37+
[[ fallthrough ]];
38+
case Sequence::SEQUENCE_SEQ7:
39+
[[ fallthrough ]];
40+
case Sequence::SEQUENCE_SEQ8:
41+
[[ fallthrough ]];
42+
case Sequence::SEQUENCE_SEQ9:
43+
return std::make_unique<ReadInjectSequence>(obj_size_range, seed,
44+
sequence, k, m);
45+
case Sequence::SEQUENCE_SEQ10:
46+
return std::make_unique<Seq10>(obj_size_range, seed, k, m);
47+
default:
48+
ceph_abort_msg("Unrecognised sequence");
49+
}
50+
}
51+
52+
EcIoSequence::EcIoSequence(std::pair<int,int> obj_size_range, int seed) :
53+
IoSequence(obj_size_range, seed),
54+
setup_inject(false), clear_inject(false), shard_to_inject(std::nullopt)
55+
{
56+
57+
}
58+
59+
void EcIoSequence::select_random_data_shard_to_inject_read_error(int k, int m)
60+
{
61+
shard_to_inject = rng(k - 1);
62+
setup_inject = true;
63+
}
64+
65+
void EcIoSequence::select_random_data_shard_to_inject_write_error(int k, int m)
66+
{
67+
// Write errors do not support injecting to the primary OSD
68+
shard_to_inject = rng(1, k - 1);
69+
setup_inject = true;
70+
}
71+
72+
void EcIoSequence::select_random_shard_to_inject_read_error(int k, int m)
73+
{
74+
shard_to_inject = rng(k + m - 1);
75+
setup_inject = true;
76+
}
77+
78+
void EcIoSequence::select_random_shard_to_inject_write_error(int k, int m)
79+
{
80+
// Write errors do not support injecting to the primary OSD
81+
shard_to_inject = rng(1, k + m - 1);
82+
setup_inject = true;
83+
}
84+
85+
void EcIoSequence::generate_random_read_inject_type()
86+
{
87+
inject_op_type = static_cast<InjectOpType>(rng(static_cast<int>(InjectOpType::ReadEIO),
88+
static_cast<int>(InjectOpType::ReadMissingShard)));
89+
}
90+
91+
void EcIoSequence::generate_random_write_inject_type()
92+
{
93+
inject_op_type = static_cast<InjectOpType>(rng(static_cast<int>(InjectOpType::WriteFailAndRollback),
94+
static_cast<int>(InjectOpType::WriteOSDAbort)));
95+
}
96+
97+
ceph::io_exerciser::ReadInjectSequence::ReadInjectSequence(std::pair<int,int> obj_size_range,
98+
int seed,
99+
Sequence s,
100+
int k, int m) :
101+
EcIoSequence(obj_size_range, seed)
102+
{
103+
child_sequence = IoSequence::generate_sequence(s, obj_size_range, seed);
104+
select_random_data_shard_to_inject_read_error(k, m);
105+
generate_random_read_inject_type();
106+
}
107+
108+
Sequence ceph::io_exerciser::ReadInjectSequence::get_id() const
109+
{
110+
return child_sequence->get_id();
111+
}
112+
113+
std::string ceph::io_exerciser::ReadInjectSequence::get_name() const
114+
{
115+
return child_sequence->get_name() +
116+
" running with read errors injected on shard "
117+
+ std::to_string(*shard_to_inject);
118+
}
119+
120+
std::unique_ptr<IoOp> ReadInjectSequence::next()
121+
{
122+
step++;
123+
124+
if (nextOp)
125+
{
126+
std::unique_ptr<IoOp> retOp = nullptr;
127+
nextOp.swap(retOp);
128+
return retOp;
129+
}
130+
131+
std::unique_ptr<IoOp> childOp = child_sequence->next();
132+
133+
switch(childOp->getOpType())
134+
{
135+
case OpType::Remove:
136+
nextOp.swap(childOp);
137+
switch(inject_op_type)
138+
{
139+
case InjectOpType::ReadEIO:
140+
return ClearReadErrorInjectOp::generate(*shard_to_inject, 0);
141+
case InjectOpType::ReadMissingShard:
142+
return ClearReadErrorInjectOp::generate(*shard_to_inject, 1);
143+
case InjectOpType::WriteFailAndRollback:
144+
return ClearWriteErrorInjectOp::generate(*shard_to_inject, 0);
145+
case InjectOpType::WriteOSDAbort:
146+
return ClearWriteErrorInjectOp::generate(*shard_to_inject, 3);
147+
case InjectOpType::None:
148+
[[ fallthrough ]];
149+
default:
150+
ceph_abort_msg("Unsupported operation");
151+
}
152+
break;
153+
case OpType::Create:
154+
switch(inject_op_type)
155+
{
156+
case InjectOpType::ReadEIO:
157+
nextOp = InjectReadErrorOp::generate(*shard_to_inject, 0, 0, std::numeric_limits<uint64_t>::max());
158+
break;
159+
case InjectOpType::ReadMissingShard:
160+
nextOp = InjectReadErrorOp::generate(*shard_to_inject, 1, 0, std::numeric_limits<uint64_t>::max());
161+
break;
162+
case InjectOpType::WriteFailAndRollback:
163+
nextOp = InjectWriteErrorOp::generate(*shard_to_inject, 0, 0, std::numeric_limits<uint64_t>::max());
164+
break;
165+
case InjectOpType::WriteOSDAbort:
166+
nextOp = InjectWriteErrorOp::generate(*shard_to_inject, 3, 0, std::numeric_limits<uint64_t>::max());
167+
break;
168+
case InjectOpType::None:
169+
[[ fallthrough ]];
170+
default:
171+
ceph_abort_msg("Unsupported operation");
172+
}
173+
break;
174+
default:
175+
// Do nothing in default case
176+
break;
177+
}
178+
179+
return childOp;
180+
}
181+
182+
std::unique_ptr<ceph::io_exerciser::IoOp> ceph::io_exerciser::ReadInjectSequence::_next()
183+
{
184+
ceph_abort_msg("Should not reach this point, "
185+
"this sequence should only consume complete sequences");
186+
187+
return DoneOp::generate();
188+
}
189+
190+
191+
192+
ceph::io_exerciser::Seq10::Seq10(std::pair<int,int> obj_size_range, int seed,
193+
int k, int m) :
194+
EcIoSequence(obj_size_range, seed), offset(0), length(1),
195+
failed_write_done(false), read_done(false), successful_write_done(false),
196+
test_all_lengths(false), // Only test length(1) due to time constraints
197+
test_all_sizes(false) // Only test obj_size(rand()) due to time constraints
198+
{
199+
select_random_shard_to_inject_write_error(k, m);
200+
// We will inject specifically as part of our sequence in this sequence
201+
setup_inject = false;
202+
if (!test_all_sizes)
203+
{
204+
select_random_object_size();
205+
}
206+
}
207+
208+
Sequence ceph::io_exerciser::Seq10::get_id() const
209+
{
210+
return Sequence::SEQUENCE_SEQ10;
211+
}
212+
213+
std::string ceph::io_exerciser::Seq10::get_name() const
214+
{
215+
return "Sequential writes of length " + std::to_string(length) +
216+
" with queue depth 1"
217+
" first injecting a failed write and read it to ensure it rolls back, then"
218+
" successfully writing the data and reading the write the ensure it is applied";
219+
}
220+
221+
std::unique_ptr<ceph::io_exerciser::IoOp> ceph::io_exerciser::Seq10::_next()
222+
{
223+
if (!inject_error_done)
224+
{
225+
inject_error_done = true;
226+
return InjectWriteErrorOp::generate(*shard_to_inject, 0, 0,
227+
std::numeric_limits<uint64_t>::max());
228+
}
229+
else if (!failed_write_done)
230+
{
231+
failed_write_done = true;
232+
read_done = false;
233+
barrier = true;
234+
return SingleFailedWriteOp::generate(offset, length);
235+
}
236+
else if (failed_write_done && !read_done)
237+
{
238+
read_done = true;
239+
barrier = true;
240+
return SingleReadOp::generate(offset, length);
241+
}
242+
else if (!clear_inject_done)
243+
{
244+
clear_inject_done = true;
245+
return ClearWriteErrorInjectOp::generate(*shard_to_inject, 0);
246+
}
247+
else if (!successful_write_done)
248+
{
249+
successful_write_done = true;
250+
read_done = false;
251+
barrier = true;
252+
return SingleWriteOp::generate(offset, length);
253+
}
254+
else if (successful_write_done && !read_done)
255+
{
256+
read_done = true;
257+
return SingleReadOp::generate(offset, length);
258+
}
259+
else if (successful_write_done && read_done)
260+
{
261+
offset++;
262+
inject_error_done = false;
263+
failed_write_done = false;
264+
read_done = false;
265+
clear_inject_done = false;
266+
successful_write_done = false;
267+
268+
if (offset + length >= obj_size) {
269+
if (!test_all_lengths)
270+
{
271+
done = true;
272+
return BarrierOp::generate();
273+
}
274+
275+
offset = 0;
276+
length++;
277+
if (length > obj_size) {
278+
if (!test_all_sizes)
279+
{
280+
done = true;
281+
return BarrierOp::generate();
282+
}
283+
284+
length = 1;
285+
return increment_object_size();
286+
}
287+
}
288+
289+
return BarrierOp::generate();
290+
}
291+
else
292+
{
293+
ceph_abort_msg("Sequence in undefined state. Aborting");
294+
return DoneOp::generate();
295+
}
296+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "IoSequence.h"
2+
3+
namespace ceph
4+
{
5+
namespace io_exerciser
6+
{
7+
class EcIoSequence : public IoSequence
8+
{
9+
public:
10+
virtual bool is_supported(Sequence sequence) const override;
11+
static std::unique_ptr<IoSequence>
12+
generate_sequence(Sequence s,
13+
std::pair<int,int> obj_size_range,
14+
int k,
15+
int m,
16+
int seed );
17+
18+
protected:
19+
bool setup_inject;
20+
bool clear_inject;
21+
std::optional<uint64_t> shard_to_inject;
22+
InjectOpType inject_op_type;
23+
24+
EcIoSequence(std::pair<int,int> obj_size_range, int seed);
25+
26+
// Writes cannot be sent to injected on shard zero, so selections seperated out
27+
void select_random_data_shard_to_inject_read_error(int k, int m);
28+
void select_random_data_shard_to_inject_write_error(int k, int m);
29+
void select_random_shard_to_inject_read_error(int k, int m);
30+
void select_random_shard_to_inject_write_error(int k, int m);
31+
void generate_random_read_inject_type();
32+
void generate_random_write_inject_type();
33+
};
34+
35+
class ReadInjectSequence : public EcIoSequence
36+
{
37+
public:
38+
ReadInjectSequence(std::pair<int,int> obj_size_range, int seed, Sequence s, int k, int m);
39+
40+
Sequence get_id() const override;
41+
std::string get_name() const override;
42+
virtual std::unique_ptr<IoOp> next() override;
43+
std::unique_ptr<IoOp> _next() override;
44+
45+
private:
46+
std::unique_ptr<IoSequence> child_sequence;
47+
std::unique_ptr<IoOp> nextOp;
48+
};
49+
50+
class Seq10: public EcIoSequence {
51+
public:
52+
Seq10(std::pair<int,int> obj_size_range, int seed, int k, int m);
53+
54+
Sequence get_id() const override;
55+
std::string get_name() const override;
56+
std::unique_ptr<IoOp> _next() override;
57+
58+
private:
59+
uint64_t offset;
60+
uint64_t length;
61+
62+
bool inject_error_done;
63+
bool failed_write_done;
64+
bool read_done;
65+
bool clear_inject_done;
66+
bool successful_write_done;
67+
bool test_all_lengths;
68+
bool test_all_sizes;
69+
};
70+
}
71+
}

0 commit comments

Comments
 (0)