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+ }
0 commit comments