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");
275
276 let mut valid_indices: SmallVec<[usize; 32]> = SmallVec::with_capacity(data_shard_count);
277 let mut invalid_indices: SmallVec<[usize; 32]> =
278 SmallVec::with_capacity(self.total_shard_count);
279 let mut missing_data_indices: SmallVec<[usize; 32]> = SmallVec::new();
280 let mut missing_parity_indices: SmallVec<[usize; 32]> = SmallVec::new();
281
282 for (matrix_row, shard) in shards.iter().enumerate() {
283 match shard.as_ref() {
284 Some(_shard) => {
285 if valid_indices.len() < data_shard_count {
286 valid_indices.push(matrix_row);
287 }
288 }
289 None => {
290 invalid_indices.push(matrix_row);
291 if matrix_row < data_shard_count {
292 missing_data_indices.push(matrix_row);
293 } else if !data_only {
294 missing_parity_indices.push(matrix_row);
295 }
296 }
297 }
298 }
299
300 self.runtime_profile_metrics.record_reconstruct(
301 data_only,
302 missing_data_indices.len(),
303 missing_parity_indices.len(),
304 false,
305 );
306
307 let data_decode_matrix = self.get_data_decode_matrix(&valid_indices, &invalid_indices)?;
308
309 if !missing_data_indices.is_empty() {
310 #[cfg(feature = "std")]
311 self.runtime_profile_metrics
312 .record_reconstruct_data_stage(shard_len, missing_data_indices.len());
313 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
314 SmallVec::with_capacity(missing_data_indices.len());
315 for &idx in &missing_data_indices {
316 matrix_rows.push(data_decode_matrix.get_row(idx));
317 }
318
319 let mut recovered_data: Vec<Vec<F::Elem>> = missing_data_indices
320 .iter()
321 .map(|_| vec![F::zero(); shard_len])
322 .collect();
323
324 {
325 let mut sub_shards: SmallVec<[&[F::Elem]; 32]> =
326 SmallVec::with_capacity(data_shard_count);
327 for &idx in &valid_indices {
328 let shard = shards[idx].as_deref().ok_or(Error::TooFewShardsPresent)?;
329 sub_shards.push(shard);
330 }
331
332 let mut outputs: SmallVec<[&mut [F::Elem]; 32]> = recovered_data
333 .iter_mut()
334 .map(|shard| shard.as_mut_slice())
335 .collect();
336
337 if data_only && outputs.len() <= 2 {
338 self.runtime_profile_metrics
339 .record_reconstruct_data_small_output_specialized();
340 self.code_some_slices_one_or_two_outputs_reconstruct_data_par_raw(
341 &matrix_rows,
342 &sub_shards,
343 &mut outputs,
344 );
345 } else {
346 self.code_some_slices_with_policy_raw(
347 &matrix_rows,
348 &sub_shards,
349 &mut outputs,
350 data_policy,
351 );
352 }
353 }
354
355 for (idx, recovered) in missing_data_indices.into_iter().zip(recovered_data) {
356 shards[idx] = Some(recovered);
357 }
358 }
359
360 if data_only {
361 return Ok(());
362 }
363
364 if missing_parity_indices.is_empty() {
365 return Ok(());
366 }
367
368 #[cfg(feature = "std")]
369 self.runtime_profile_metrics
370 .record_reconstruct_parity_stage(shard_len, missing_parity_indices.len());
371 let parity_rows = self.get_parity_rows();
372 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
373 SmallVec::with_capacity(missing_parity_indices.len());
374 for &idx in &missing_parity_indices {
375 matrix_rows.push(parity_rows[idx - data_shard_count]);
376 }
377
378 let mut recovered_parity: Vec<Vec<F::Elem>> = missing_parity_indices
379 .iter()
380 .map(|_| vec![F::zero(); shard_len])
381 .collect();
382
383 {
384 let mut all_data: SmallVec<[&[F::Elem]; 32]> =
385 SmallVec::with_capacity(data_shard_count);
386 for shard in shards.iter().take(data_shard_count) {
387 let shard = shard.as_deref().ok_or(Error::TooFewShardsPresent)?;
388 all_data.push(shard);
389 }
390
391 let mut outputs: SmallVec<[&mut [F::Elem]; 32]> = recovered_parity
392 .iter_mut()
393 .map(|shard| shard.as_mut_slice())
394 .collect();
395
396 self.code_some_slices_with_policy_raw(
397 &matrix_rows,
398 &all_data,
399 &mut outputs,
400 parity_policy,
401 );
402 }
403 for (idx, recovered) in missing_parity_indices.into_iter().zip(recovered_parity) {
404 shards[idx] = Some(recovered);
405 }
406 Ok(())
407 }
408
409 #[cfg(feature = "std")]
410 pub(crate) fn reconstruct_internal_option_vec_par_with_policy(
411 &self,
412 shards: &mut [Option<Vec<F::Elem>>],
413 data_only: bool,
414 policy: ParallelPolicy,
415 ) -> Result<(), Error>
416 where
417 F::Elem: Send + Sync,
418 {
419 self.reconstruct_internal_option_vec_par_with_stage_policies(
420 shards, data_only, policy, policy,
421 )
422 }
423
424 pub fn reconstruct<T: ReconstructShard<F>>(&self, slices: &mut [T]) -> Result<(), Error> {
428 if self.is_leopard_gf8_family() {
429 return self.reconstruct_leopard_gf8(slices, false);
430 }
431 if self.is_leopard_gf16_family() {
432 return self.reconstruct_leopard_gf16(slices, false);
433 }
434 self.ensure_classic_family_execution()?;
435 self.reconstruct_internal(slices, false)
436 }
437
438 pub fn reconstruct_data<T: ReconstructShard<F>>(&self, slices: &mut [T]) -> Result<(), Error> {
440 if self.is_leopard_gf8_family() {
441 return self.reconstruct_leopard_gf8(slices, true);
442 }
443 if self.is_leopard_gf16_family() {
444 return self.reconstruct_leopard_gf16(slices, true);
445 }
446 self.ensure_classic_family_execution()?;
447 self.reconstruct_internal(slices, true)
448 }
449
450 pub fn reconstruct_some<T: ReconstructShard<F>>(
452 &self,
453 shards: &mut [T],
454 required: &[bool],
455 ) -> Result<(), Error> {
456 if self.is_leopard_gf8_family() {
457 self.reconstruct_leopard_gf8(shards, false)?;
460 return Ok(());
461 }
462 if self.is_leopard_gf16_family() {
463 self.reconstruct_leopard_gf16(shards, false)?;
464 return Ok(());
465 }
466 self.ensure_classic_family_execution()?;
467 if required.len() != self.total_shard_count {
468 return Err(Error::InvalidShardFlags);
469 }
470
471 check_piece_count!(all => self, shards);
472
473 let mut number_present = 0;
474 let mut shard_len = None;
475
476 for shard in shards.iter_mut() {
477 if let Some(len) = shard.len() {
478 if len == 0 {
479 return Err(Error::EmptyShard);
480 }
481 number_present += 1;
482 if let Some(old_len) = shard_len
483 && len != old_len
484 {
485 return Err(Error::IncorrectShardSize);
486 }
487 shard_len = Some(len);
488 }
489 }
490
491 if number_present == self.total_shard_count {
492 return Ok(());
493 }
494
495 if number_present < self.data_shard_count {
496 return Err(Error::TooFewShardsPresent);
497 }
498
499 let shard_len = shard_len.expect("at least one shard present; qed");
500 let required_data_only = required
501 .iter()
502 .enumerate()
503 .all(|(i, required)| !*required || i < self.data_shard_count);
504
505 let originally_missing: Vec<bool> = shards
506 .iter_mut()
507 .map(|shard| shard.get().is_none())
508 .collect();
509
510 if required_data_only {
511 let mut valid_indices: SmallVec<[usize; 32]> =
512 SmallVec::with_capacity(self.data_shard_count);
513 let mut invalid_indices: SmallVec<[usize; 32]> =
514 SmallVec::with_capacity(self.total_shard_count);
515 let mut required_missing_data_indices: SmallVec<[usize; 32]> = SmallVec::new();
516
517 for (index, is_missing) in originally_missing.iter().copied().enumerate() {
518 if is_missing {
519 invalid_indices.push(index);
520 if index < self.data_shard_count && required[index] {
521 required_missing_data_indices.push(index);
522 }
523 } else if valid_indices.len() < self.data_shard_count {
524 valid_indices.push(index);
525 }
526 }
527
528 if required_missing_data_indices.is_empty() {
529 return Ok(());
530 }
531
532 let data_decode_matrix =
533 self.get_data_decode_matrix(&valid_indices, &invalid_indices)?;
534 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
535 SmallVec::with_capacity(required_missing_data_indices.len());
536 for &idx in &required_missing_data_indices {
537 matrix_rows.push(data_decode_matrix.get_row(idx));
538 }
539
540 let mut sub_shard_ptrs: SmallVec<[(*const F::Elem, usize); 32]> =
544 SmallVec::with_capacity(valid_indices.len());
545 for &idx in &valid_indices {
546 let shard = shards[idx]
547 .get()
548 .expect("valid shard index must be present");
549 sub_shard_ptrs.push((shard.as_ptr(), shard.len()));
550 }
551
552 let sub_shards: SmallVec<[&[F::Elem]; 32]> = sub_shard_ptrs
553 .iter()
554 .map(|&(ptr, len)| {
555 unsafe { core::slice::from_raw_parts(ptr, len) }
562 })
563 .collect();
564 let mut output_ptrs: SmallVec<[(*mut F::Elem, usize); 32]> =
565 SmallVec::with_capacity(required_missing_data_indices.len());
566 for &idx in &required_missing_data_indices {
567 match shards[idx].get_or_initialize(shard_len) {
568 Ok(dst) | Err(Ok(dst)) => output_ptrs.push((dst.as_mut_ptr(), dst.len())),
569 Err(Err(err)) => return Err(err),
570 }
571 }
572 let mut outputs: SmallVec<[&mut [F::Elem]; 32]> = output_ptrs
573 .iter()
574 .map(|&(ptr, len)| {
575 unsafe { core::slice::from_raw_parts_mut(ptr, len) }
580 })
581 .collect();
582 self.code_some_slices(&matrix_rows, &sub_shards, &mut outputs);
583 drop(outputs);
584 } else {
585 let mut working: Vec<Option<Vec<F::Elem>>> = shards
586 .iter_mut()
587 .map(|shard| shard.get().map(|data| data.to_vec()))
588 .collect();
589 self.reconstruct(&mut working)?;
590
591 for (i, shard) in shards.iter_mut().enumerate() {
592 if !required[i] || !originally_missing[i] {
593 continue;
594 }
595
596 let recovered = working[i]
597 .as_ref()
598 .expect("recovered shard must be present");
599 match shard.get_or_initialize(shard_len) {
600 Ok(dst) | Err(Ok(dst)) => dst.copy_from_slice(recovered),
601 Err(Err(err)) => return Err(err),
602 }
603 }
604 }
605
606 Ok(())
607 }
608
609 #[allow(clippy::needless_range_loop, clippy::type_complexity)]
619 fn reconstruct_leopard_impl<T: ReconstructShard<F>>(
620 &self,
621 slices: &mut [T],
622 reconstruct_fn: fn(
623 &[bool],
624 &mut [&mut [u8]],
625 &[Option<&[u8]>],
626 usize,
627 usize,
628 ) -> Result<(), Error>,
629 ) -> Result<(), Error> {
630 check_piece_count!(all => self, slices);
631
632 let total = self.total_shard_count;
633 let shard_len_opt: Option<usize> = slices.iter().find_map(|s| s.len());
634 let Some(shard_len) = shard_len_opt else {
635 return Err(Error::EmptyShard);
636 };
637
638 let mut present = vec![false; total];
640 let mut raw_data: Vec<Option<*const u8>> = vec![None; total];
641 for i in 0..total {
642 if let Some(data) = slices[i].get() {
643 present[i] = true;
644 raw_data[i] = Some(data as *const [F::Elem] as *const u8);
645 }
646 }
647
648 let mut output_bufs: Vec<Vec<u8>> = (0..total).map(|_| vec![0u8; shard_len]).collect();
652
653 let mut outputs: Vec<&mut [u8]> = output_bufs
654 .iter_mut()
655 .map(|buf| buf.as_mut_slice())
656 .collect();
657
658 let mut input_data: Vec<Option<&[u8]>> = Vec::with_capacity(total);
659 for i in 0..total {
660 if let Some(ptr) = raw_data[i] {
661 let src: &[u8] = unsafe { core::slice::from_raw_parts(ptr, shard_len) };
662 input_data.push(Some(src));
663 } else {
664 input_data.push(None);
665 }
666 }
667
668 reconstruct_fn(
669 &present,
670 &mut outputs,
671 &input_data,
672 self.data_shard_count,
673 self.parity_shard_count,
674 )?;
675
676 for i in 0..total {
677 if present[i] {
678 continue;
679 }
680 let elem_slice: &[F::Elem] =
681 unsafe { &*(output_bufs[i].as_slice() as *const [u8] as *const [F::Elem]) };
682 match slices[i].get_or_initialize(shard_len) {
683 Ok(dst) | Err(Ok(dst)) => dst.copy_from_slice(elem_slice),
684 Err(Err(err)) => return Err(err),
685 }
686 }
687
688 Ok(())
689 }
690
691 fn reconstruct_leopard_gf8<T: ReconstructShard<F>>(
692 &self,
693 slices: &mut [T],
694 _data_only: bool,
695 ) -> Result<(), Error> {
696 self.reconstruct_leopard_impl(slices, super::leopard_gf8::reconstruct_with_tables)
697 }
698
699 fn reconstruct_leopard_gf16<T: ReconstructShard<F>>(
700 &self,
701 slices: &mut [T],
702 _data_only: bool,
703 ) -> Result<(), Error> {
704 self.reconstruct_leopard_impl(slices, super::leopard::leopard_gf16_reconstruct)
705 }
706
707 pub(crate) fn get_data_decode_matrix(
708 &self,
709 valid_indices: &[usize],
710 invalid_indices: &[usize],
711 ) -> Result<Arc<crate::matrix::Matrix<F>>, Error> {
712 if valid_indices.len() != self.data_shard_count {
713 return Err(Error::TooFewShardsPresent);
714 }
715
716 if self.options.inversion_cache {
717 #[cfg(feature = "std")]
718 self.reconstruction_cache_metrics
719 .requests
720 .fetch_add(1, Ordering::Relaxed);
721
722 let mut cache = self.data_decode_matrix_cache.lock();
723 if let Some(entry) = cache.get(invalid_indices) {
724 #[cfg(feature = "std")]
725 self.reconstruction_cache_metrics
726 .hits
727 .fetch_add(1, Ordering::Relaxed);
728 return Ok(entry.clone());
729 }
730
731 #[cfg(feature = "std")]
732 self.reconstruction_cache_metrics
733 .misses
734 .fetch_add(1, Ordering::Relaxed);
735 }
736 let mut sub_matrix =
737 crate::matrix::Matrix::new(self.data_shard_count, self.data_shard_count);
738 for (sub_matrix_row, &valid_index) in valid_indices.iter().enumerate() {
739 for c in 0..self.data_shard_count {
740 sub_matrix.set(sub_matrix_row, c, self.matrix.get(valid_index, c));
741 }
742 }
743 let data_decode_matrix = Arc::new(
744 sub_matrix
745 .invert()
746 .map_err(|_| Error::InvalidCustomMatrix)?,
747 );
748 if self.options.inversion_cache {
749 let data_decode_matrix = data_decode_matrix.clone();
750 let mut cache = self.data_decode_matrix_cache.lock();
751 #[cfg(feature = "std")]
752 let before_len = cache.len();
753 #[cfg(feature = "std")]
754 let capacity = cache.capacity();
755 cache.insert(Vec::from(invalid_indices), data_decode_matrix);
756 #[cfg(feature = "std")]
757 if capacity > 0 && before_len >= capacity {
758 self.reconstruction_cache_metrics
759 .evictions
760 .fetch_add(1, Ordering::Relaxed);
761 }
762 #[cfg(feature = "std")]
763 self.reconstruction_cache_metrics
764 .inserts
765 .fetch_add(1, Ordering::Relaxed);
766 }
767 Ok(data_decode_matrix)
768 }
769
770 fn reconstruct_internal<T: ReconstructShard<F>>(
771 &self,
772 shards: &mut [T],
773 data_only: bool,
774 ) -> Result<(), Error> {
775 check_piece_count!(all => self, shards);
776
777 let data_shard_count = self.data_shard_count;
778
779 let mut number_present = 0;
780 let mut shard_len = None;
781
782 for shard in shards.iter_mut() {
783 if let Some(len) = shard.len() {
784 if len == 0 {
785 return Err(Error::EmptyShard);
786 }
787 number_present += 1;
788 if let Some(old_len) = shard_len
789 && len != old_len
790 {
791 return Err(Error::IncorrectShardSize);
792 }
793 shard_len = Some(len);
794 }
795 }
796
797 if number_present == self.total_shard_count {
798 #[cfg(feature = "std")]
799 self.runtime_profile_metrics
800 .record_reconstruct(data_only, 0, 0, true);
801 return Ok(());
802 }
803
804 if number_present < data_shard_count {
805 return Err(Error::TooFewShardsPresent);
806 }
807
808 let shard_len = shard_len.expect("at least one shard present; qed");
809
810 let mut sub_shards: SmallVec<[&[F::Elem]; 32]> = SmallVec::with_capacity(data_shard_count);
811 let mut missing_data_slices: SmallVec<[&mut [F::Elem]; 32]> =
812 SmallVec::with_capacity(self.parity_shard_count);
813 let mut missing_parity_slices: SmallVec<[&mut [F::Elem]; 32]> =
814 SmallVec::with_capacity(self.parity_shard_count);
815 let mut valid_indices: SmallVec<[usize; 32]> = SmallVec::with_capacity(data_shard_count);
816 let mut invalid_indices: SmallVec<[usize; 32]> = SmallVec::with_capacity(data_shard_count);
817
818 for (matrix_row, shard) in shards.iter_mut().enumerate() {
819 let shard_data = if matrix_row >= data_shard_count && data_only {
820 shard.get().ok_or(None)
821 } else {
822 shard.get_or_initialize(shard_len).map_err(Some)
823 };
824
825 match shard_data {
826 Ok(shard) => {
827 if sub_shards.len() < data_shard_count {
828 sub_shards.push(shard);
829 valid_indices.push(matrix_row);
830 }
831 }
832 Err(None) => {
833 invalid_indices.push(matrix_row);
834 }
835 Err(Some(x)) => {
836 let shard = x?;
837 if matrix_row < data_shard_count {
838 missing_data_slices.push(shard);
839 } else {
840 missing_parity_slices.push(shard);
841 }
842
843 invalid_indices.push(matrix_row);
844 }
845 }
846 }
847
848 #[cfg(feature = "std")]
849 {
850 let missing_data_count = invalid_indices
851 .iter()
852 .filter(|&&i| i < data_shard_count)
853 .count();
854 let missing_parity_count = if data_only {
855 0
856 } else {
857 invalid_indices
858 .iter()
859 .filter(|&&i| i >= data_shard_count)
860 .count()
861 };
862 self.runtime_profile_metrics.record_reconstruct(
863 data_only,
864 missing_data_count,
865 missing_parity_count,
866 false,
867 );
868 }
869
870 let data_decode_matrix = self.get_data_decode_matrix(&valid_indices, &invalid_indices)?;
871
872 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
873 SmallVec::with_capacity(self.parity_shard_count);
874
875 for i_slice in invalid_indices
876 .iter()
877 .cloned()
878 .take_while(|i| i < &data_shard_count)
879 {
880 matrix_rows.push(data_decode_matrix.get_row(i_slice));
881 }
882
883 #[cfg(feature = "std")]
884 self.runtime_profile_metrics
885 .record_reconstruct_data_stage(shard_len, matrix_rows.len());
886 self.code_some_slices(&matrix_rows, &sub_shards, &mut missing_data_slices);
887
888 if data_only {
889 Ok(())
890 } else {
891 let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
892 SmallVec::with_capacity(self.parity_shard_count);
893 let parity_rows = self.get_parity_rows();
894
895 for i_slice in invalid_indices
896 .iter()
897 .cloned()
898 .skip_while(|i| i < &data_shard_count)
899 {
900 matrix_rows.push(parity_rows[i_slice - data_shard_count]);
901 }
902 #[cfg(feature = "std")]
903 self.runtime_profile_metrics
904 .record_reconstruct_parity_stage(shard_len, matrix_rows.len());
905 {
906 let mut i_old_data_slice = 0;
907 let mut i_new_data_slice = 0;
908
909 let mut all_data_slices: SmallVec<[&[F::Elem]; 32]> =
910 SmallVec::with_capacity(data_shard_count);
911
912 let mut next_maybe_good = 0;
913 let mut push_good_up_to = move |data_slices: &mut SmallVec<_>, up_to| {
914 for _ in next_maybe_good..up_to {
915 data_slices.push(sub_shards[i_old_data_slice]);
916 i_old_data_slice += 1;
917 }
918
919 next_maybe_good = up_to + 1;
920 };
921
922 for i_slice in invalid_indices
923 .iter()
924 .cloned()
925 .take_while(|i| i < &data_shard_count)
926 {
927 push_good_up_to(&mut all_data_slices, i_slice);
928 all_data_slices.push(missing_data_slices[i_new_data_slice]);
929 i_new_data_slice += 1;
930 }
931 push_good_up_to(&mut all_data_slices, data_shard_count);
932
933 self.code_some_slices(&matrix_rows, &all_data_slices, &mut missing_parity_slices);
934 }
935
936 Ok(())
937 }
938 }
939}