1extern crate alloc;
2
3use alloc::sync::Arc;
4use alloc::vec;
5use alloc::vec::Vec;
6
7use smallvec::SmallVec;
8
9use crate::errors::Error;
10use crate::{Field, ReconstructShard};
11
12#[cfg(feature = "std")]
13use rayon::prelude::*;
14#[cfg(feature = "std")]
15use std::sync::atomic::Ordering;
16
17#[cfg(not(feature = "std"))]
18use super::ReedSolomon;
19#[cfg(feature = "std")]
20use super::{ParallelPolicy, ReedSolomon};
21
22impl<F: Field> ReedSolomon<F> {
23 #[cfg(feature = "std")]
24 pub(crate) fn code_some_slices_par_raw(
25 &self,
26 matrix_rows: &[&[F::Elem]],
27 inputs: &[&[F::Elem]],
28 outputs: &mut [&mut [F::Elem]],
29 ) where
30 F::Elem: Send + Sync,
31 {
32 let shard_len = inputs.first().map(|input| input.len()).unwrap_or(0);
33 if shard_len == 0 {
34 return;
35 }
36
37 if outputs.len() <= 2 {
38 self.code_some_slices_one_or_two_outputs_reconstruct_data_par_raw(
39 matrix_rows,
40 inputs,
41 outputs,
42 );
43 return;
44 }
45
46 let decision = self.parallel_policy(shard_len, outputs.len());
47 if !decision.use_parallel {
48 self.code_some_slices_chunked(matrix_rows, inputs, outputs);
49 return;
50 }
51 self.code_some_slices_par_chunked(matrix_rows, inputs, outputs, decision.chunk_len);
52 }
53
54 #[cfg(feature = "std")]
55 pub(crate) fn code_some_slices_with_policy_raw(
56 &self,
57 matrix_rows: &[&[F::Elem]],
58 inputs: &[&[F::Elem]],
59 outputs: &mut [&mut [F::Elem]],
60 policy: ParallelPolicy,
61 ) where
62 F::Elem: Send + Sync,
63 {
64 let shard_len = inputs.first().map(|input| input.len()).unwrap_or(0);
65 if shard_len == 0 {
66 return;
67 }
68
69 if outputs.len() <= 2 {
70 self.code_some_slices_one_or_two_outputs_reconstruct_data_par_raw(
71 matrix_rows,
72 inputs,
73 outputs,
74 );
75 return;
76 }
77
78 let decision = policy.decide(
79 shard_len,
80 self.data_shard_count,
81 outputs.len(),
82 self.policy_cache.available_parallelism,
83 );
84 self.runtime_profile_metrics
85 .record_parallel_policy(decision);
86 if !decision.use_parallel {
87 self.code_some_slices_chunked(matrix_rows, inputs, outputs);
88 return;
89 }
90 self.code_some_slices_par_chunked(matrix_rows, inputs, outputs, decision.chunk_len);
91 }
92
93 #[cfg(feature = "std")]
94 pub(crate) fn code_some_slices_two_outputs_reconstruct_data_par_raw(
95 &self,
96 matrix_rows: &[&[F::Elem]],
97 inputs: &[&[F::Elem]],
98 outputs: &mut [&mut [F::Elem]],
99 ) where
100 F::Elem: Send + Sync,
101 {
102 debug_assert_eq!(2, matrix_rows.len());
103 debug_assert_eq!(2, outputs.len());
104
105 let shard_len = inputs.first().map(|input| input.len()).unwrap_or(0);
106 if shard_len == 0 {
107 return;
108 }
109
110 let decision = self.parallel_policy(shard_len, outputs.len());
111 self.runtime_profile_metrics
112 .record_parallel_policy(decision);
113 if !decision.use_parallel {
114 self.code_some_slices_chunked(matrix_rows, inputs, outputs);
115 return;
116 }
117
118 let chunk_len = if self.data_shard_count <= 16 {
119 core::cmp::min(shard_len, core::cmp::max(decision.chunk_len, 512 * 1024))
120 } else {
121 decision.chunk_len
122 };
123 self.runtime_profile_metrics.record_code_some(
124 true,
125 shard_len,
126 inputs.len(),
127 outputs.len(),
128 chunk_len,
129 );
130
131 let data_shard_count = self.data_shard_count;
132 outputs
133 .par_iter_mut()
134 .enumerate()
135 .for_each(|(i_row, output)| {
136 let matrix_row = matrix_rows[i_row];
137
138 let mut start = 0;
139 while start < shard_len {
140 let end = core::cmp::min(start + chunk_len, shard_len);
141 let output_chunk = &mut output[start..end];
142
143 F::mul_slice(matrix_row[0], &inputs[0][start..end], output_chunk);
144 for i_input in 1..data_shard_count {
145 F::mul_slice_add(
146 matrix_row[i_input],
147 &inputs[i_input][start..end],
148 output_chunk,
149 );
150 }
151
152 start = end;
153 }
154 });
155 }
156
157 #[cfg(feature = "std")]
158 pub(crate) fn code_some_slices_one_or_two_outputs_reconstruct_data_par_raw(
159 &self,
160 matrix_rows: &[&[F::Elem]],
161 inputs: &[&[F::Elem]],
162 outputs: &mut [&mut [F::Elem]],
163 ) where
164 F::Elem: Send + Sync,
165 {
166 debug_assert!((1..=2).contains(&outputs.len()));
167
168 if outputs.len() == 1 {
169 let shard_len = inputs.first().map(|input| input.len()).unwrap_or(0);
170 if shard_len == 0 {
171 return;
172 }
173
174 let decision = self.parallel_policy(shard_len, outputs.len());
175 self.runtime_profile_metrics
176 .record_parallel_policy(decision);
177 if !decision.use_parallel {
178 self.code_some_slices_chunked(matrix_rows, inputs, outputs);
179 return;
180 }
181
182 self.runtime_profile_metrics.record_code_some(
183 true,
184 shard_len,
185 inputs.len(),
186 outputs.len(),
187 decision.chunk_len,
188 );
189
190 let data_shard_count = self.data_shard_count;
191 let matrix_row = matrix_rows[0];
192 outputs[0]
193 .par_chunks_mut(decision.chunk_len)
194 .enumerate()
195 .for_each(|(chunk_idx, output_chunk)| {
196 let start = chunk_idx * decision.chunk_len;
197 let end = start + output_chunk.len();
198
199 F::mul_slice(matrix_row[0], &inputs[0][start..end], output_chunk);
200 for i_input in 1..data_shard_count {
201 F::mul_slice_add(
202 matrix_row[i_input],
203 &inputs[i_input][start..end],
204 output_chunk,
205 );
206 }
207 });
208 return;
209 }
210
211 self.code_some_slices_two_outputs_reconstruct_data_par_raw(matrix_rows, inputs, outputs);
212 }
213
214 #[cfg(feature = "std")]
215 pub(crate) fn reconstruct_internal_option_vec_par(
216 &self,
217 shards: &mut [Option<Vec<F::Elem>>],
218 data_only: bool,
219 ) -> Result<(), Error>
220 where
221 F::Elem: Send + Sync,
222 {
223 let (data_policy, parity_policy) = self.policy_cache.reconstruct_stage_policies(data_only);
224 self.reconstruct_internal_option_vec_par_with_stage_policies(
225 shards,
226 data_only,
227 data_policy,
228 parity_policy,
229 )
230 }
231
232 #[cfg(feature = "std")]
233 pub(crate) fn reconstruct_internal_option_vec_par_with_stage_policies(
234 &self,
235 shards: &mut [Option<Vec<F::Elem>>],
236 data_only: bool,
237 data_policy: ParallelPolicy,
238 parity_policy: ParallelPolicy,
239 ) -> Result<(), Error>
240 where
241 F::Elem: Send + Sync,
242 {
243 check_piece_count!(all => self, shards);
244
245 let data_shard_count = self.data_shard_count;
246
247 let mut number_present = 0;
248 let mut shard_len = None;
249 for shard in shards.iter() {
250 if let Some(shard) = shard.as_ref() {
251 let len = shard.len();
252 if len == 0 {
253 return Err(Error::EmptyShard);
254 }
255 number_present += 1;
256 if let Some(old_len) = shard_len
257 && len != old_len
258 {
259 return Err(Error::IncorrectShardSize);
260 }
261 shard_len = Some(len);
262 }
263 }
264
265 if number_present == self.total_shard_count {
266 self.runtime_profile_metrics
267 .record_reconstruct(data_only, 0, 0, true);
268 return Ok(());
269 }
270 if number_present < data_shard_count {
271 return Err(Error::TooFewShardsPresent);
272 }
273
274 let shard_len = shard_len.expect("at least one shard present; qed");
278
279 let mut valid_indices: SmallVec<[usize; 32]> = SmallVec::with_capacity(data_shard_count);
280 let mut invalid_indices: SmallVec<[usize; 32]> =
281 SmallVec::with_capacity(self.total_shard_count);
282 let mut missing_data_indices: SmallVec<[usize; 32]> = SmallVec::new();
283 let mut missing_parity_indices: SmallVec<[usize; 32]> = SmallVec::new();
284
285 for (matrix_row, shard) in shards.iter().enumerate() {
286 match shard.as_ref() {
287 Some(_shard) => {
288 if valid_indices.len() < data_shard_count {
289 valid_indices.push(matrix_row);
290 }
291 }
292 None => {
293 invalid_indices.push(matrix_row);
294 if matrix_row < data_shard_count {
295 missing_data_indices.push(matrix_row);
296 } else if !data_only {
297 missing_parity_indices.push(matrix_row);
298 }
299 }
300 }
301 }
302
303 self.runtime_profile_metrics.record_reconstruct(
304 data_only,
305 missing_data_indices.len(),
306 missing_parity_indices.len(),
307 false,
308 );
309
310 let data_decode_matrix = self.get_data_decode_matrix(&valid_indices, &invalid_indices)?;
311
312 if !missing_data_indices.is_empty() {
313 #[cfg(feature = "std")]
314 self.runtime_profile_metrics
315 .record_reconstruct_data_stage(shard_len, missing_data_indices.len());
316 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
317 SmallVec::with_capacity(missing_data_indices.len());
318 for &idx in &missing_data_indices {
319 matrix_rows.push(data_decode_matrix.get_row(idx));
320 }
321
322 let mut recovered_data: Vec<Vec<F::Elem>> = missing_data_indices
323 .iter()
324 .map(|_| vec![F::zero(); shard_len])
325 .collect();
326
327 {
328 let mut sub_shards: SmallVec<[&[F::Elem]; 32]> =
329 SmallVec::with_capacity(data_shard_count);
330 for &idx in &valid_indices {
331 let shard = shards[idx].as_deref().ok_or(Error::TooFewShardsPresent)?;
332 sub_shards.push(shard);
333 }
334
335 let mut outputs: SmallVec<[&mut [F::Elem]; 32]> = recovered_data
336 .iter_mut()
337 .map(|shard| shard.as_mut_slice())
338 .collect();
339
340 if data_only && outputs.len() <= 2 {
341 self.runtime_profile_metrics
342 .record_reconstruct_data_small_output_specialized();
343 self.code_some_slices_one_or_two_outputs_reconstruct_data_par_raw(
344 &matrix_rows,
345 &sub_shards,
346 &mut outputs,
347 );
348 } else {
349 self.code_some_slices_with_policy_raw(
350 &matrix_rows,
351 &sub_shards,
352 &mut outputs,
353 data_policy,
354 );
355 }
356 }
357
358 for (idx, recovered) in missing_data_indices.into_iter().zip(recovered_data) {
359 shards[idx] = Some(recovered);
360 }
361 }
362
363 if data_only {
364 return Ok(());
365 }
366
367 if missing_parity_indices.is_empty() {
368 return Ok(());
369 }
370
371 #[cfg(feature = "std")]
372 self.runtime_profile_metrics
373 .record_reconstruct_parity_stage(shard_len, missing_parity_indices.len());
374 let parity_rows = self.get_parity_rows();
375 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
376 SmallVec::with_capacity(missing_parity_indices.len());
377 for &idx in &missing_parity_indices {
378 matrix_rows.push(parity_rows[idx - data_shard_count]);
379 }
380
381 let mut recovered_parity: Vec<Vec<F::Elem>> = missing_parity_indices
382 .iter()
383 .map(|_| vec![F::zero(); shard_len])
384 .collect();
385
386 {
387 let mut all_data: SmallVec<[&[F::Elem]; 32]> =
388 SmallVec::with_capacity(data_shard_count);
389 for shard in shards.iter().take(data_shard_count) {
390 let shard = shard.as_deref().ok_or(Error::TooFewShardsPresent)?;
391 all_data.push(shard);
392 }
393
394 let mut outputs: SmallVec<[&mut [F::Elem]; 32]> = recovered_parity
395 .iter_mut()
396 .map(|shard| shard.as_mut_slice())
397 .collect();
398
399 self.code_some_slices_with_policy_raw(
400 &matrix_rows,
401 &all_data,
402 &mut outputs,
403 parity_policy,
404 );
405 }
406 for (idx, recovered) in missing_parity_indices.into_iter().zip(recovered_parity) {
407 shards[idx] = Some(recovered);
408 }
409 Ok(())
410 }
411
412 #[cfg(feature = "std")]
413 pub(crate) fn reconstruct_internal_option_vec_par_with_policy(
414 &self,
415 shards: &mut [Option<Vec<F::Elem>>],
416 data_only: bool,
417 policy: ParallelPolicy,
418 ) -> Result<(), Error>
419 where
420 F::Elem: Send + Sync,
421 {
422 self.reconstruct_internal_option_vec_par_with_stage_policies(
423 shards, data_only, policy, policy,
424 )
425 }
426
427 pub fn reconstruct<T: ReconstructShard<F>>(&self, slices: &mut [T]) -> Result<(), Error> {
431 if self.is_leopard_gf8_family() {
432 return self.reconstruct_leopard_gf8(slices, false);
433 }
434 if self.is_leopard_gf16_family() {
435 return self.reconstruct_leopard_gf16(slices, false);
436 }
437 self.ensure_classic_family_execution()?;
438 self.reconstruct_internal(slices, false)
439 }
440
441 pub fn reconstruct_data<T: ReconstructShard<F>>(&self, slices: &mut [T]) -> Result<(), Error> {
443 if self.is_leopard_gf8_family() {
444 return self.reconstruct_leopard_gf8(slices, true);
445 }
446 if self.is_leopard_gf16_family() {
447 return self.reconstruct_leopard_gf16(slices, true);
448 }
449 self.ensure_classic_family_execution()?;
450 self.reconstruct_internal(slices, true)
451 }
452
453 pub fn reconstruct_some<T: ReconstructShard<F>>(
455 &self,
456 shards: &mut [T],
457 required: &[bool],
458 ) -> Result<(), Error> {
459 if self.is_leopard_gf8_family() {
460 self.reconstruct_leopard_gf8(shards, false)?;
463 return Ok(());
464 }
465 if self.is_leopard_gf16_family() {
466 self.reconstruct_leopard_gf16(shards, false)?;
467 return Ok(());
468 }
469 self.ensure_classic_family_execution()?;
470 if required.len() != self.total_shard_count {
471 return Err(Error::InvalidShardFlags);
472 }
473
474 check_piece_count!(all => self, shards);
475
476 let mut number_present = 0;
477 let mut shard_len = None;
478
479 for shard in shards.iter_mut() {
480 if let Some(len) = shard.len() {
481 if len == 0 {
482 return Err(Error::EmptyShard);
483 }
484 number_present += 1;
485 if let Some(old_len) = shard_len
486 && len != old_len
487 {
488 return Err(Error::IncorrectShardSize);
489 }
490 shard_len = Some(len);
491 }
492 }
493
494 if number_present == self.total_shard_count {
495 return Ok(());
496 }
497
498 if number_present < self.data_shard_count {
499 return Err(Error::TooFewShardsPresent);
500 }
501
502 let shard_len = shard_len.expect("at least one shard present; qed");
506 let required_data_only = required
507 .iter()
508 .enumerate()
509 .all(|(i, required)| !*required || i < self.data_shard_count);
510
511 let originally_missing: Vec<bool> = shards
512 .iter_mut()
513 .map(|shard| shard.get().is_none())
514 .collect();
515
516 if required_data_only {
517 let mut valid_indices: SmallVec<[usize; 32]> =
518 SmallVec::with_capacity(self.data_shard_count);
519 let mut invalid_indices: SmallVec<[usize; 32]> =
520 SmallVec::with_capacity(self.total_shard_count);
521 let mut required_missing_data_indices: SmallVec<[usize; 32]> = SmallVec::new();
522
523 for (index, is_missing) in originally_missing.iter().copied().enumerate() {
524 if is_missing {
525 invalid_indices.push(index);
526 if index < self.data_shard_count && required[index] {
527 required_missing_data_indices.push(index);
528 }
529 } else if valid_indices.len() < self.data_shard_count {
530 valid_indices.push(index);
531 }
532 }
533
534 if required_missing_data_indices.is_empty() {
535 return Ok(());
536 }
537
538 let data_decode_matrix =
539 self.get_data_decode_matrix(&valid_indices, &invalid_indices)?;
540 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
541 SmallVec::with_capacity(required_missing_data_indices.len());
542 for &idx in &required_missing_data_indices {
543 matrix_rows.push(data_decode_matrix.get_row(idx));
544 }
545
546 let mut sub_shard_ptrs: SmallVec<[(*const F::Elem, usize); 32]> =
550 SmallVec::with_capacity(valid_indices.len());
551 for &idx in &valid_indices {
552 let shard = shards[idx]
553 .get()
554 .expect("valid shard index must be present");
555 sub_shard_ptrs.push((shard.as_ptr(), shard.len()));
556 }
557
558 let sub_shards: SmallVec<[&[F::Elem]; 32]> = sub_shard_ptrs
559 .iter()
560 .map(|&(ptr, len)| {
561 unsafe { core::slice::from_raw_parts(ptr, len) }
568 })
569 .collect();
570 let mut output_ptrs: SmallVec<[(*mut F::Elem, usize); 32]> =
571 SmallVec::with_capacity(required_missing_data_indices.len());
572 for &idx in &required_missing_data_indices {
573 match shards[idx].get_or_initialize(shard_len) {
574 Ok(dst) | Err(Ok(dst)) => output_ptrs.push((dst.as_mut_ptr(), dst.len())),
575 Err(Err(err)) => return Err(err),
576 }
577 }
578 let mut outputs: SmallVec<[&mut [F::Elem]; 32]> = output_ptrs
579 .iter()
580 .map(|&(ptr, len)| {
581 unsafe { core::slice::from_raw_parts_mut(ptr, len) }
586 })
587 .collect();
588 self.code_some_slices(&matrix_rows, &sub_shards, &mut outputs);
589 drop(outputs);
590 } else {
591 let mut working: Vec<Option<Vec<F::Elem>>> = shards
592 .iter_mut()
593 .map(|shard| shard.get().map(|data| data.to_vec()))
594 .collect();
595 self.reconstruct(&mut working)?;
596
597 for (i, shard) in shards.iter_mut().enumerate() {
598 if !required[i] || !originally_missing[i] {
599 continue;
600 }
601
602 let recovered = working[i]
603 .as_ref()
604 .expect("recovered shard must be present");
605 match shard.get_or_initialize(shard_len) {
606 Ok(dst) | Err(Ok(dst)) => dst.copy_from_slice(recovered),
607 Err(Err(err)) => return Err(err),
608 }
609 }
610 }
611
612 Ok(())
613 }
614
615 #[allow(clippy::needless_range_loop, clippy::type_complexity)]
625 fn reconstruct_leopard_impl<T: ReconstructShard<F>>(
626 &self,
627 slices: &mut [T],
628 reconstruct_fn: fn(
629 &[bool],
630 &mut [&mut [u8]],
631 &[Option<&[u8]>],
632 usize,
633 usize,
634 ) -> Result<(), Error>,
635 ) -> Result<(), Error> {
636 check_piece_count!(all => self, slices);
637
638 let total = self.total_shard_count;
639 let shard_len_opt: Option<usize> = slices.iter().find_map(|s| s.len());
640 let Some(shard_len) = shard_len_opt else {
641 return Err(Error::EmptyShard);
642 };
643
644 let mut present = vec![false; total];
646 let mut raw_data: Vec<Option<*const u8>> = vec![None; total];
647 for i in 0..total {
648 if let Some(data) = slices[i].get() {
649 present[i] = true;
650 raw_data[i] = Some(data as *const [F::Elem] as *const u8);
651 }
652 }
653
654 let mut output_bufs: Vec<Vec<u8>> = (0..total).map(|_| vec![0u8; shard_len]).collect();
658
659 let mut outputs: Vec<&mut [u8]> = output_bufs
660 .iter_mut()
661 .map(|buf| buf.as_mut_slice())
662 .collect();
663
664 let mut input_data: Vec<Option<&[u8]>> = Vec::with_capacity(total);
665 for i in 0..total {
666 if let Some(ptr) = raw_data[i] {
667 let src: &[u8] = unsafe { core::slice::from_raw_parts(ptr, shard_len) };
671 input_data.push(Some(src));
672 } else {
673 input_data.push(None);
674 }
675 }
676
677 reconstruct_fn(
678 &present,
679 &mut outputs,
680 &input_data,
681 self.data_shard_count,
682 self.parity_shard_count,
683 )?;
684
685 for i in 0..total {
686 if present[i] {
687 continue;
688 }
689 let elem_slice: &[F::Elem] =
692 unsafe { &*(output_bufs[i].as_slice() as *const [u8] as *const [F::Elem]) };
693 match slices[i].get_or_initialize(shard_len) {
694 Ok(dst) | Err(Ok(dst)) => dst.copy_from_slice(elem_slice),
695 Err(Err(err)) => return Err(err),
696 }
697 }
698
699 Ok(())
700 }
701
702 fn reconstruct_leopard_gf8<T: ReconstructShard<F>>(
703 &self,
704 slices: &mut [T],
705 _data_only: bool,
706 ) -> Result<(), Error> {
707 self.reconstruct_leopard_impl(slices, super::leopard_gf8::reconstruct_with_tables)
708 }
709
710 fn reconstruct_leopard_gf16<T: ReconstructShard<F>>(
711 &self,
712 slices: &mut [T],
713 _data_only: bool,
714 ) -> Result<(), Error> {
715 self.reconstruct_leopard_impl(slices, super::leopard::leopard_gf16_reconstruct)
716 }
717
718 pub(crate) fn get_data_decode_matrix(
719 &self,
720 valid_indices: &[usize],
721 invalid_indices: &[usize],
722 ) -> Result<Arc<crate::matrix::Matrix<F>>, Error> {
723 if valid_indices.len() != self.data_shard_count {
724 return Err(Error::TooFewShardsPresent);
725 }
726
727 if self.options.inversion_cache {
728 #[cfg(feature = "std")]
729 self.reconstruction_cache_metrics
730 .requests
731 .fetch_add(1, Ordering::Relaxed);
732
733 let mut cache = self.data_decode_matrix_cache.lock();
734 if let Some(entry) = cache.get(invalid_indices) {
735 #[cfg(feature = "std")]
736 self.reconstruction_cache_metrics
737 .hits
738 .fetch_add(1, Ordering::Relaxed);
739 return Ok(entry.clone());
740 }
741
742 #[cfg(feature = "std")]
743 self.reconstruction_cache_metrics
744 .misses
745 .fetch_add(1, Ordering::Relaxed);
746 }
747 let mut sub_matrix =
748 crate::matrix::Matrix::new(self.data_shard_count, self.data_shard_count);
749 for (sub_matrix_row, &valid_index) in valid_indices.iter().enumerate() {
750 for c in 0..self.data_shard_count {
751 sub_matrix.set(sub_matrix_row, c, self.matrix.get(valid_index, c));
752 }
753 }
754 let data_decode_matrix = Arc::new(
755 sub_matrix
756 .invert()
757 .map_err(|_| Error::InvalidCustomMatrix)?,
758 );
759 if self.options.inversion_cache {
760 let data_decode_matrix = data_decode_matrix.clone();
761 let mut cache = self.data_decode_matrix_cache.lock();
762 #[cfg(feature = "std")]
763 let before_len = cache.len();
764 #[cfg(feature = "std")]
765 let capacity = cache.capacity();
766 cache.insert(Vec::from(invalid_indices), data_decode_matrix);
767 #[cfg(feature = "std")]
768 if capacity > 0 && before_len >= capacity {
769 self.reconstruction_cache_metrics
770 .evictions
771 .fetch_add(1, Ordering::Relaxed);
772 }
773 #[cfg(feature = "std")]
774 self.reconstruction_cache_metrics
775 .inserts
776 .fetch_add(1, Ordering::Relaxed);
777 }
778 Ok(data_decode_matrix)
779 }
780
781 fn reconstruct_internal<T: ReconstructShard<F>>(
782 &self,
783 shards: &mut [T],
784 data_only: bool,
785 ) -> Result<(), Error> {
786 check_piece_count!(all => self, shards);
787
788 let data_shard_count = self.data_shard_count;
789
790 let mut number_present = 0;
791 let mut shard_len = None;
792
793 for shard in shards.iter_mut() {
794 if let Some(len) = shard.len() {
795 if len == 0 {
796 return Err(Error::EmptyShard);
797 }
798 number_present += 1;
799 if let Some(old_len) = shard_len
800 && len != old_len
801 {
802 return Err(Error::IncorrectShardSize);
803 }
804 shard_len = Some(len);
805 }
806 }
807
808 if number_present == self.total_shard_count {
809 #[cfg(feature = "std")]
810 self.runtime_profile_metrics
811 .record_reconstruct(data_only, 0, 0, true);
812 return Ok(());
813 }
814
815 if number_present < data_shard_count {
816 return Err(Error::TooFewShardsPresent);
817 }
818
819 let shard_len = shard_len.expect("at least one shard present; qed");
823
824 let mut sub_shards: SmallVec<[&[F::Elem]; 32]> = SmallVec::with_capacity(data_shard_count);
825 let mut missing_data_slices: SmallVec<[&mut [F::Elem]; 32]> =
826 SmallVec::with_capacity(self.parity_shard_count);
827 let mut missing_parity_slices: SmallVec<[&mut [F::Elem]; 32]> =
828 SmallVec::with_capacity(self.parity_shard_count);
829 let mut valid_indices: SmallVec<[usize; 32]> = SmallVec::with_capacity(data_shard_count);
830 let mut invalid_indices: SmallVec<[usize; 32]> = SmallVec::with_capacity(data_shard_count);
831
832 for (matrix_row, shard) in shards.iter_mut().enumerate() {
833 let shard_data = if matrix_row >= data_shard_count && data_only {
834 shard.get().ok_or(None)
835 } else {
836 shard.get_or_initialize(shard_len).map_err(Some)
837 };
838
839 match shard_data {
840 Ok(shard) => {
841 if sub_shards.len() < data_shard_count {
842 sub_shards.push(shard);
843 valid_indices.push(matrix_row);
844 }
845 }
846 Err(None) => {
847 invalid_indices.push(matrix_row);
848 }
849 Err(Some(x)) => {
850 let shard = x?;
851 if matrix_row < data_shard_count {
852 missing_data_slices.push(shard);
853 } else {
854 missing_parity_slices.push(shard);
855 }
856
857 invalid_indices.push(matrix_row);
858 }
859 }
860 }
861
862 #[cfg(feature = "std")]
863 {
864 let missing_data_count = invalid_indices
865 .iter()
866 .filter(|&&i| i < data_shard_count)
867 .count();
868 let missing_parity_count = if data_only {
869 0
870 } else {
871 invalid_indices
872 .iter()
873 .filter(|&&i| i >= data_shard_count)
874 .count()
875 };
876 self.runtime_profile_metrics.record_reconstruct(
877 data_only,
878 missing_data_count,
879 missing_parity_count,
880 false,
881 );
882 }
883
884 let data_decode_matrix = self.get_data_decode_matrix(&valid_indices, &invalid_indices)?;
885
886 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
887 SmallVec::with_capacity(self.parity_shard_count);
888
889 for i_slice in invalid_indices
890 .iter()
891 .cloned()
892 .take_while(|i| i < &data_shard_count)
893 {
894 matrix_rows.push(data_decode_matrix.get_row(i_slice));
895 }
896
897 #[cfg(feature = "std")]
898 self.runtime_profile_metrics
899 .record_reconstruct_data_stage(shard_len, matrix_rows.len());
900 self.code_some_slices(&matrix_rows, &sub_shards, &mut missing_data_slices);
901
902 if data_only {
903 Ok(())
904 } else {
905 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
906 SmallVec::with_capacity(self.parity_shard_count);
907 let parity_rows = self.get_parity_rows();
908
909 for i_slice in invalid_indices
910 .iter()
911 .cloned()
912 .skip_while(|i| i < &data_shard_count)
913 {
914 matrix_rows.push(parity_rows[i_slice - data_shard_count]);
915 }
916 #[cfg(feature = "std")]
917 self.runtime_profile_metrics
918 .record_reconstruct_parity_stage(shard_len, matrix_rows.len());
919 {
920 let mut i_old_data_slice = 0;
921 let mut i_new_data_slice = 0;
922
923 let mut all_data_slices: SmallVec<[&[F::Elem]; 32]> =
924 SmallVec::with_capacity(data_shard_count);
925
926 let mut next_maybe_good = 0;
927 let mut push_good_up_to = move |data_slices: &mut SmallVec<_>, up_to| {
928 for _ in next_maybe_good..up_to {
929 data_slices.push(sub_shards[i_old_data_slice]);
930 i_old_data_slice += 1;
931 }
932
933 next_maybe_good = up_to + 1;
934 };
935
936 for i_slice in invalid_indices
937 .iter()
938 .cloned()
939 .take_while(|i| i < &data_shard_count)
940 {
941 push_good_up_to(&mut all_data_slices, i_slice);
942 all_data_slices.push(missing_data_slices[i_new_data_slice]);
943 i_new_data_slice += 1;
944 }
945 push_good_up_to(&mut all_data_slices, data_shard_count);
946
947 self.code_some_slices(&matrix_rows, &all_data_slices, &mut missing_parity_slices);
948 }
949
950 Ok(())
951 }
952 }
953}