reed_solomon_erasure/
core.rs

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::errors::SBSError;
11
12use crate::matrix::Matrix;
13
14use lru::LruCache;
15
16#[cfg(feature = "std")]
17use parking_lot::Mutex;
18#[cfg(not(feature = "std"))]
19use spin::Mutex;
20
21use super::Field;
22use super::ReconstructShard;
23
24const DATA_DECODE_MATRIX_CACHE_CAPACITY: usize = 254;
25
26// /// Parameters for parallelism.
27// #[derive(PartialEq, Debug, Clone, Copy)]
28// pub struct ParallelParam {
29//     /// Number of bytes to split the slices into for computations
30//     /// which can be done in parallel.
31//     ///
32//     /// Default is 32768.
33//     pub bytes_per_encode: usize,
34// }
35
36// impl ParallelParam {
37//     /// Create a new `ParallelParam` with the given split arity.
38//     pub fn new(bytes_per_encode: usize) -> ParallelParam {
39//         ParallelParam { bytes_per_encode }
40//     }
41// }
42
43// impl Default for ParallelParam {
44//     fn default() -> Self {
45//         ParallelParam::new(32768)
46//     }
47// }
48
49/// Bookkeeper for shard by shard encoding.
50///
51/// This is useful for avoiding incorrect use of
52/// `encode_single` and `encode_single_sep`
53///
54/// # Use cases
55///
56/// Shard by shard encoding is useful for streamed data encoding
57/// where you do not have all the needed data shards immediately,
58/// but you want to spread out the encoding workload rather than
59/// doing the encoding after everything is ready.
60///
61/// A concrete example would be network packets encoding,
62/// where encoding packet by packet as you receive them may be more efficient
63/// than waiting for N packets then encode them all at once.
64///
65/// # Example
66///
67/// ```
68/// # #[macro_use] extern crate reed_solomon_erasure;
69/// # use reed_solomon_erasure::*;
70/// # fn main () {
71/// use reed_solomon_erasure::galois_8::Field;
72/// let r: ReedSolomon<Field> = ReedSolomon::new(3, 2).unwrap();
73///
74/// let mut sbs = ShardByShard::new(&r);
75///
76/// let mut shards = shards!([0u8,  1,  2,  3,  4],
77///                          [5,  6,  7,  8,  9],
78///                          // say we don't have the 3rd data shard yet
79///                          // and we want to fill it in later
80///                          [0,  0,  0,  0,  0],
81///                          [0,  0,  0,  0,  0],
82///                          [0,  0,  0,  0,  0]);
83///
84/// // encode 1st and 2nd data shard
85/// sbs.encode(&mut shards).unwrap();
86/// sbs.encode(&mut shards).unwrap();
87///
88/// // fill in 3rd data shard
89/// shards[2][0] = 10.into();
90/// shards[2][1] = 11.into();
91/// shards[2][2] = 12.into();
92/// shards[2][3] = 13.into();
93/// shards[2][4] = 14.into();
94///
95/// // now do the encoding
96/// sbs.encode(&mut shards).unwrap();
97///
98/// assert!(r.verify(&shards).unwrap());
99/// # }
100/// ```
101#[derive(PartialEq, Debug)]
102pub struct ShardByShard<'a, F: 'a + Field> {
103    codec: &'a ReedSolomon<F>,
104    cur_input: usize,
105}
106
107impl<'a, F: 'a + Field> ShardByShard<'a, F> {
108    /// Creates a new instance of the bookkeeping struct.
109    pub fn new(codec: &'a ReedSolomon<F>) -> ShardByShard<'a, F> {
110        ShardByShard {
111            codec,
112            cur_input: 0,
113        }
114    }
115
116    /// Checks if the parity shards are ready to use.
117    pub fn parity_ready(&self) -> bool {
118        self.cur_input == self.codec.data_shard_count
119    }
120
121    /// Resets the bookkeeping data.
122    ///
123    /// You should call this when you have added and encoded
124    /// all data shards, and have finished using the parity shards.
125    ///
126    /// Returns `SBSError::LeftoverShards` when there are shards encoded
127    /// but parity shards are not ready to use.
128    pub fn reset(&mut self) -> Result<(), SBSError> {
129        if self.cur_input > 0 && !self.parity_ready() {
130            return Err(SBSError::LeftoverShards);
131        }
132
133        self.cur_input = 0;
134
135        Ok(())
136    }
137
138    /// Resets the bookkeeping data without checking.
139    pub fn reset_force(&mut self) {
140        self.cur_input = 0;
141    }
142
143    /// Returns the current input shard index.
144    pub fn cur_input_index(&self) -> usize {
145        self.cur_input
146    }
147
148    fn return_ok_and_incre_cur_input(&mut self) -> Result<(), SBSError> {
149        self.cur_input += 1;
150        Ok(())
151    }
152
153    fn sbs_encode_checks<U: AsRef<[F::Elem]> + AsMut<[F::Elem]>>(
154        &mut self,
155        slices: &mut [U],
156    ) -> Result<(), SBSError> {
157        let internal_checks = |codec: &ReedSolomon<F>, data: &mut [U]| {
158            check_piece_count!(all => codec, data);
159            check_slices!(multi => data);
160
161            Ok(())
162        };
163
164        if self.parity_ready() {
165            return Err(SBSError::TooManyCalls);
166        }
167
168        match internal_checks(self.codec, slices) {
169            Ok(()) => Ok(()),
170            Err(e) => Err(SBSError::RSError(e)),
171        }
172    }
173
174    fn sbs_encode_sep_checks<T: AsRef<[F::Elem]>, U: AsRef<[F::Elem]> + AsMut<[F::Elem]>>(
175        &mut self,
176        data: &[T],
177        parity: &mut [U],
178    ) -> Result<(), SBSError> {
179        let internal_checks = |codec: &ReedSolomon<F>, data: &[T], parity: &mut [U]| {
180            check_piece_count!(data => codec, data);
181            check_piece_count!(parity => codec, parity);
182            check_slices!(multi => data, multi => parity);
183
184            Ok(())
185        };
186
187        if self.parity_ready() {
188            return Err(SBSError::TooManyCalls);
189        }
190
191        match internal_checks(self.codec, data, parity) {
192            Ok(()) => Ok(()),
193            Err(e) => Err(SBSError::RSError(e)),
194        }
195    }
196
197    /// Constructs the parity shards partially using the current input data shard.
198    ///
199    /// Returns `SBSError::TooManyCalls` when all input data shards
200    /// have already been filled in via `encode`
201    pub fn encode<T, U>(&mut self, mut shards: T) -> Result<(), SBSError>
202    where
203        T: AsRef<[U]> + AsMut<[U]>,
204        U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
205    {
206        let shards = shards.as_mut();
207        self.sbs_encode_checks(shards)?;
208
209        self.codec.encode_single(self.cur_input, shards).unwrap();
210
211        self.return_ok_and_incre_cur_input()
212    }
213
214    /// Constructs the parity shards partially using the current input data shard.
215    ///
216    /// Returns `SBSError::TooManyCalls` when all input data shards
217    /// have already been filled in via `encode`
218    pub fn encode_sep<T: AsRef<[F::Elem]>, U: AsRef<[F::Elem]> + AsMut<[F::Elem]>>(
219        &mut self,
220        data: &[T],
221        parity: &mut [U],
222    ) -> Result<(), SBSError> {
223        self.sbs_encode_sep_checks(data, parity)?;
224
225        self.codec
226            .encode_single_sep(self.cur_input, data[self.cur_input].as_ref(), parity)
227            .unwrap();
228
229        self.return_ok_and_incre_cur_input()
230    }
231}
232
233/// Reed-Solomon erasure code encoder/decoder.
234///
235/// # Common error handling
236///
237/// ## For `encode`, `encode_shards`, `verify`, `verify_shards`, `reconstruct`, `reconstruct_data`, `reconstruct_shards`, `reconstruct_data_shards`
238///
239/// Return `Error::TooFewShards` or `Error::TooManyShards`
240/// when the number of provided shards
241/// does not match the codec's one.
242///
243/// Return `Error::EmptyShard` when the first shard provided is
244/// of zero length.
245///
246/// Return `Error::IncorrectShardSize` when the provided shards
247/// are of different lengths.
248///
249/// ## For `reconstruct`, `reconstruct_data`, `reconstruct_shards`, `reconstruct_data_shards`
250///
251/// Return `Error::TooFewShardsPresent` when there are not
252/// enough shards for reconstruction.
253///
254/// Return `Error::InvalidShardFlags` when the number of flags does not match
255/// the total number of shards.
256///
257/// # Variants of encoding methods
258///
259/// ## `sep`
260///
261/// Methods ending in `_sep` takes an immutable reference to data shards,
262/// and a mutable reference to parity shards.
263///
264/// They are useful as they do not need to borrow the data shards mutably,
265/// and other work that only needs read-only access to data shards can be done
266/// in parallel/concurrently during the encoding.
267///
268/// Following is a table of all the `sep` variants
269///
270/// | not `sep` | `sep` |
271/// | --- | --- |
272/// | `encode_single` | `encode_single_sep` |
273/// | `encode`        | `encode_sep` |
274///
275/// The `sep` variants do similar checks on the provided data shards and
276/// parity shards.
277///
278/// Return `Error::TooFewDataShards`, `Error::TooManyDataShards`,
279/// `Error::TooFewParityShards`, or `Error::TooManyParityShards` when applicable.
280///
281/// ## `single`
282///
283/// Methods containing `single` facilitate shard by shard encoding, where
284/// the parity shards are partially constructed using one data shard at a time.
285/// See `ShardByShard` struct for more details on how shard by shard encoding
286/// can be useful.
287///
288/// They are prone to **misuse**, and it is recommended to use the `ShardByShard`
289/// bookkeeping struct instead for shard by shard encoding.
290///
291/// The ones that are also `sep` are **ESPECIALLY** prone to **misuse**.
292/// Only use them when you actually need the flexibility.
293///
294/// Following is a table of all the shard by shard variants
295///
296/// | all shards at once | shard by shard |
297/// | --- | --- |
298/// | `encode` | `encode_single` |
299/// | `encode_sep` | `encode_single_sep` |
300///
301/// The `single` variants do similar checks on the provided data shards and parity shards,
302/// and also do index check on `i_data`.
303///
304/// Return `Error::InvalidIndex` if `i_data >= data_shard_count`.
305///
306/// # Encoding behaviour
307/// ## For `encode`
308///
309/// You do not need to clear the parity shards beforehand, as the methods
310/// will overwrite them completely.
311///
312/// ## For `encode_single`, `encode_single_sep`
313///
314/// Calling them with `i_data` being `0` will overwrite the parity shards
315/// completely. If you are using the methods correctly, then you do not need
316/// to clear the parity shards beforehand.
317///
318/// # Variants of verifying methods
319///
320/// `verify` allocate sa buffer on the heap of the same size
321/// as the parity shards, and encode the input once using the buffer to store
322/// the computed parity shards, then check if the provided parity shards
323/// match the computed ones.
324///
325/// `verify_with_buffer`, allows you to provide
326/// the buffer to avoid making heap allocation(s) for the buffer in every call.
327///
328/// The `with_buffer` variants also guarantee that the buffer contains the correct
329/// parity shards if the result is `Ok(_)` (i.e. it does not matter whether the
330/// verification passed or not, as long as the result is not an error, the buffer
331/// will contain the correct parity shards after the call).
332///
333/// Following is a table of all the `with_buffer` variants
334///
335/// | not `with_buffer` | `with_buffer` |
336/// | --- | --- |
337/// | `verify` | `verify_with_buffer` |
338///
339/// The `with_buffer` variants also check the dimensions of the buffer and return
340/// `Error::TooFewBufferShards`, `Error::TooManyBufferShards`, `Error::EmptyShard`,
341/// or `Error::IncorrectShardSize` when applicable.
342///
343#[derive(Debug)]
344pub struct ReedSolomon<F: Field> {
345    data_shard_count: usize,
346    parity_shard_count: usize,
347    total_shard_count: usize,
348    matrix: Matrix<F>,
349    data_decode_matrix_cache: Mutex<LruCache<Vec<usize>, Arc<Matrix<F>>>>,
350}
351
352impl<F: Field> Clone for ReedSolomon<F> {
353    fn clone(&self) -> ReedSolomon<F> {
354        ReedSolomon::new(self.data_shard_count, self.parity_shard_count)
355            .expect("basic checks already passed as precondition of existence of self")
356    }
357}
358
359impl<F: Field> PartialEq for ReedSolomon<F> {
360    fn eq(&self, rhs: &ReedSolomon<F>) -> bool {
361        self.data_shard_count == rhs.data_shard_count
362            && self.parity_shard_count == rhs.parity_shard_count
363    }
364}
365
366impl<F: Field> ReedSolomon<F> {
367    // AUDIT
368    //
369    // Error detection responsibilities
370    //
371    // Terminologies and symbols:
372    //   X =A, B, C=> Y: X delegates error checking responsibilities A, B, C to Y
373    //   X:= A, B, C: X needs to handle responsibilities A, B, C
374    //
375    // Encode methods
376    //
377    // `encode_single`:=
378    //   - check index `i_data` within range [0, data shard count)
379    //   - check length of `slices` matches total shard count exactly
380    //   - check consistency of length of individual slices
381    // `encode_single_sep`:=
382    //   - check index `i_data` within range [0, data shard count)
383    //   - check length of `parity` matches parity shard count exactly
384    //   - check consistency of length of individual parity slices
385    //   - check length of `single_data` matches length of first parity slice
386    // `encode`:=
387    //   - check length of `slices` matches total shard count exactly
388    //   - check consistency of length of individual slices
389    // `encode_sep`:=
390    //   - check length of `data` matches data shard count exactly
391    //   - check length of `parity` matches parity shard count exactly
392    //   - check consistency of length of individual data slices
393    //   - check consistency of length of individual parity slices
394    //   - check length of first parity slice matches length of first data slice
395    //
396    // Verify methods
397    //
398    // `verify`:=
399    //   - check length of `slices` matches total shard count exactly
400    //   - check consistency of length of individual slices
401    //
402    //   Generates buffer then passes control to verify_with_buffer
403    //
404    // `verify_with_buffer`:=
405    //   - check length of `slices` matches total shard count exactly
406    //   - check length of `buffer` matches parity shard count exactly
407    //   - check consistency of length of individual slices
408    //   - check consistency of length of individual slices in buffer
409    //   - check length of first slice in buffer matches length of first slice
410    //
411    // Reconstruct methods
412    //
413    // `reconstruct` =ALL=> `reconstruct_internal`
414    // `reconstruct_data`=ALL=> `reconstruct_internal`
415    // `reconstruct_internal`:=
416    //   - check length of `slices` matches total shard count exactly
417    //   - check consistency of length of individual slices
418    //   - check length of `slice_present` matches length of `slices`
419
420    fn get_parity_rows(&self) -> SmallVec<[&[F::Elem]; 32]> {
421        let mut parity_rows = SmallVec::with_capacity(self.parity_shard_count);
422        let matrix = &self.matrix;
423        for i in self.data_shard_count..self.total_shard_count {
424            parity_rows.push(matrix.get_row(i));
425        }
426
427        parity_rows
428    }
429
430    fn build_matrix(data_shards: usize, total_shards: usize) -> Matrix<F> {
431        let vandermonde = Matrix::vandermonde(total_shards, data_shards);
432
433        let top = vandermonde.sub_matrix(0, 0, data_shards, data_shards);
434
435        vandermonde.multiply(&top.invert().unwrap())
436    }
437
438    /// Creates a new instance of Reed-Solomon erasure code encoder/decoder.
439    ///
440    /// Returns `Error::TooFewDataShards` if `data_shards == 0`.
441    ///
442    /// Returns `Error::TooFewParityShards` if `parity_shards == 0`.
443    ///
444    /// Returns `Error::TooManyShards` if `data_shards + parity_shards > F::ORDER`.
445    pub fn new(data_shards: usize, parity_shards: usize) -> Result<ReedSolomon<F>, Error> {
446        if data_shards == 0 {
447            return Err(Error::TooFewDataShards);
448        }
449        if parity_shards == 0 {
450            return Err(Error::TooFewParityShards);
451        }
452        if data_shards + parity_shards > F::ORDER {
453            return Err(Error::TooManyShards);
454        }
455
456        let total_shards = data_shards + parity_shards;
457
458        let matrix = Self::build_matrix(data_shards, total_shards);
459
460        Ok(ReedSolomon {
461            data_shard_count: data_shards,
462            parity_shard_count: parity_shards,
463            total_shard_count: total_shards,
464            matrix,
465            data_decode_matrix_cache: Mutex::new(LruCache::new(DATA_DECODE_MATRIX_CACHE_CAPACITY)),
466        })
467    }
468
469    pub fn data_shard_count(&self) -> usize {
470        self.data_shard_count
471    }
472
473    pub fn parity_shard_count(&self) -> usize {
474        self.parity_shard_count
475    }
476
477    pub fn total_shard_count(&self) -> usize {
478        self.total_shard_count
479    }
480
481    fn code_some_slices<T: AsRef<[F::Elem]>, U: AsMut<[F::Elem]>>(
482        &self,
483        matrix_rows: &[&[F::Elem]],
484        inputs: &[T],
485        outputs: &mut [U],
486    ) {
487        for i_input in 0..self.data_shard_count {
488            self.code_single_slice(matrix_rows, i_input, inputs[i_input].as_ref(), outputs);
489        }
490    }
491
492    fn code_single_slice<U: AsMut<[F::Elem]>>(
493        &self,
494        matrix_rows: &[&[F::Elem]],
495        i_input: usize,
496        input: &[F::Elem],
497        outputs: &mut [U],
498    ) {
499        outputs.iter_mut().enumerate().for_each(|(i_row, output)| {
500            let matrix_row_to_use = matrix_rows[i_row][i_input];
501            let output = output.as_mut();
502
503            if i_input == 0 {
504                F::mul_slice(matrix_row_to_use, input, output);
505            } else {
506                F::mul_slice_add(matrix_row_to_use, input, output);
507            }
508        })
509    }
510
511    fn check_some_slices_with_buffer<T, U>(
512        &self,
513        matrix_rows: &[&[F::Elem]],
514        inputs: &[T],
515        to_check: &[T],
516        buffer: &mut [U],
517    ) -> bool
518    where
519        T: AsRef<[F::Elem]>,
520        U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
521    {
522        self.code_some_slices(matrix_rows, inputs, buffer);
523
524        let at_least_one_mismatch_present = buffer
525            .iter_mut()
526            .enumerate()
527            .map(|(i, expected_parity_shard)| {
528                expected_parity_shard.as_ref() == to_check[i].as_ref()
529            })
530            .any(|x| !x); // find the first false (some slice is different from the expected one)
531        !at_least_one_mismatch_present
532    }
533
534    /// Constructs the parity shards partially using only the data shard
535    /// indexed by `i_data`.
536    ///
537    /// The slots where the parity shards sit at will be overwritten.
538    ///
539    /// # Warning
540    ///
541    /// You must apply this method on the data shards in strict sequential order (0..data shard count),
542    /// otherwise the parity shards will be incorrect.
543    ///
544    /// It is recommended to use the `ShardByShard` bookkeeping struct instead of this method directly.
545    pub fn encode_single<T, U>(&self, i_data: usize, mut shards: T) -> Result<(), Error>
546    where
547        T: AsRef<[U]> + AsMut<[U]>,
548        U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
549    {
550        let slices = shards.as_mut();
551
552        check_slice_index!(data => self, i_data);
553        check_piece_count!(all=> self, slices);
554        check_slices!(multi => slices);
555
556        // Get the slice of output buffers.
557        let (mut_input, output) = slices.split_at_mut(self.data_shard_count);
558
559        let input = mut_input[i_data].as_ref();
560
561        self.encode_single_sep(i_data, input, output)
562    }
563
564    /// Constructs the parity shards partially using only the data shard provided.
565    ///
566    /// The data shard must match the index `i_data`.
567    ///
568    /// The slots where the parity shards sit at will be overwritten.
569    ///
570    /// # Warning
571    ///
572    /// You must apply this method on the data shards in strict sequential order (0..data shard count),
573    /// otherwise the parity shards will be incorrect.
574    ///
575    /// It is recommended to use the `ShardByShard` bookkeeping struct instead of this method directly.
576    pub fn encode_single_sep<U: AsRef<[F::Elem]> + AsMut<[F::Elem]>>(
577        &self,
578        i_data: usize,
579        single_data: &[F::Elem],
580        parity: &mut [U],
581    ) -> Result<(), Error> {
582        check_slice_index!(data => self, i_data);
583        check_piece_count!(parity => self, parity);
584        check_slices!(multi => parity, single => single_data);
585
586        let parity_rows = self.get_parity_rows();
587
588        // Do the coding.
589        self.code_single_slice(&parity_rows, i_data, single_data, parity);
590
591        Ok(())
592    }
593
594    /// Constructs the parity shards.
595    ///
596    /// The slots where the parity shards sit at will be overwritten.
597    pub fn encode<T, U>(&self, mut shards: T) -> Result<(), Error>
598    where
599        T: AsRef<[U]> + AsMut<[U]>,
600        U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
601    {
602        let slices: &mut [U] = shards.as_mut();
603
604        check_piece_count!(all => self, slices);
605        check_slices!(multi => slices);
606
607        // Get the slice of output buffers.
608        let (input, output) = slices.split_at_mut(self.data_shard_count);
609
610        self.encode_sep(&*input, output)
611    }
612
613    /// Constructs the parity shards using a read-only view into the
614    /// data shards.
615    ///
616    /// The slots where the parity shards sit at will be overwritten.
617    pub fn encode_sep<T: AsRef<[F::Elem]>, U: AsRef<[F::Elem]> + AsMut<[F::Elem]>>(
618        &self,
619        data: &[T],
620        parity: &mut [U],
621    ) -> Result<(), Error> {
622        check_piece_count!(data => self, data);
623        check_piece_count!(parity => self, parity);
624        check_slices!(multi => data, multi => parity);
625
626        let parity_rows = self.get_parity_rows();
627
628        // Do the coding.
629        self.code_some_slices(&parity_rows, data, parity);
630
631        Ok(())
632    }
633
634    /// Checks if the parity shards are correct.
635    ///
636    /// This is a wrapper of `verify_with_buffer`.
637    pub fn verify<T: AsRef<[F::Elem]>>(&self, slices: &[T]) -> Result<bool, Error> {
638        check_piece_count!(all => self, slices);
639        check_slices!(multi => slices);
640
641        let slice_len = slices[0].as_ref().len();
642
643        let mut buffer: SmallVec<[Vec<F::Elem>; 32]> =
644            SmallVec::with_capacity(self.parity_shard_count);
645
646        for _ in 0..self.parity_shard_count {
647            buffer.push(vec![F::zero(); slice_len]);
648        }
649
650        self.verify_with_buffer(slices, &mut buffer)
651    }
652
653    /// Checks if the parity shards are correct.
654    pub fn verify_with_buffer<T, U>(&self, slices: &[T], buffer: &mut [U]) -> Result<bool, Error>
655    where
656        T: AsRef<[F::Elem]>,
657        U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
658    {
659        check_piece_count!(all => self, slices);
660        check_piece_count!(parity_buf => self, buffer);
661        check_slices!(multi => slices, multi => buffer);
662
663        let data = &slices[0..self.data_shard_count];
664        let to_check = &slices[self.data_shard_count..];
665
666        let parity_rows = self.get_parity_rows();
667
668        Ok(self.check_some_slices_with_buffer(&parity_rows, data, to_check, buffer))
669    }
670
671    /// Reconstructs all shards.
672    ///
673    /// The shards marked not present are only overwritten when no error
674    /// is detected. All provided shards must have the same length.
675    ///
676    /// This means if the method returns an `Error`, then nothing is touched.
677    ///
678    /// `reconstruct`, `reconstruct_data`, `reconstruct_shards`,
679    /// `reconstruct_data_shards` share the same core code base.
680    pub fn reconstruct<T: ReconstructShard<F>>(&self, slices: &mut [T]) -> Result<(), Error> {
681        self.reconstruct_internal(slices, false)
682    }
683
684    /// Reconstructs only the data shards.
685    ///
686    /// The shards marked not present are only overwritten when no error
687    /// is detected. All provided shards must have the same length.
688    ///
689    /// This means if the method returns an `Error`, then nothing is touched.
690    ///
691    /// `reconstruct`, `reconstruct_data`, `reconstruct_shards`,
692    /// `reconstruct_data_shards` share the same core code base.
693    pub fn reconstruct_data<T: ReconstructShard<F>>(&self, slices: &mut [T]) -> Result<(), Error> {
694        self.reconstruct_internal(slices, true)
695    }
696
697    fn get_data_decode_matrix(
698        &self,
699        valid_indices: &[usize],
700        invalid_indices: &[usize],
701    ) -> Arc<Matrix<F>> {
702        {
703            let mut cache = self.data_decode_matrix_cache.lock();
704            if let Some(entry) = cache.get(invalid_indices) {
705                return entry.clone();
706            }
707        }
708        // Pull out the rows of the matrix that correspond to the shards that
709        // we have and build a square matrix. This matrix could be used to
710        // generate the shards that we have from the original data.
711        let mut sub_matrix = Matrix::new(self.data_shard_count, self.data_shard_count);
712        for (sub_matrix_row, &valid_index) in valid_indices.iter().enumerate() {
713            for c in 0..self.data_shard_count {
714                sub_matrix.set(sub_matrix_row, c, self.matrix.get(valid_index, c));
715            }
716        }
717        // Invert the matrix, so we can go from the encoded shards back to the
718        // original data. Then pull out the row that generates the shard that
719        // we want to decode. Note that since this matrix maps back to the
720        // original data, it can be used to create a data shard, but not a
721        // parity shard.
722        let data_decode_matrix = Arc::new(sub_matrix.invert().unwrap());
723        // Cache the inverted matrix for future use keyed on the indices of the
724        // invalid rows.
725        {
726            let data_decode_matrix = data_decode_matrix.clone();
727            let mut cache = self.data_decode_matrix_cache.lock();
728            cache.put(Vec::from(invalid_indices), data_decode_matrix);
729        }
730        data_decode_matrix
731    }
732
733    fn reconstruct_internal<T: ReconstructShard<F>>(
734        &self,
735        shards: &mut [T],
736        data_only: bool,
737    ) -> Result<(), Error> {
738        check_piece_count!(all => self, shards);
739
740        let data_shard_count = self.data_shard_count;
741
742        // Quick check: are all of the shards present?  If so, there's
743        // nothing to do.
744        let mut number_present = 0;
745        let mut shard_len = None;
746
747        for shard in shards.iter_mut() {
748            if let Some(len) = shard.len() {
749                if len == 0 {
750                    return Err(Error::EmptyShard);
751                }
752                number_present += 1;
753                if let Some(old_len) = shard_len {
754                    if len != old_len {
755                        // mismatch between shards.
756                        return Err(Error::IncorrectShardSize);
757                    }
758                }
759                shard_len = Some(len);
760            }
761        }
762
763        if number_present == self.total_shard_count {
764            // Cool.  All of the shards are there.  We don't
765            // need to do anything.
766            return Ok(());
767        }
768
769        // More complete sanity check
770        if number_present < data_shard_count {
771            return Err(Error::TooFewShardsPresent);
772        }
773
774        let shard_len = shard_len.expect("at least one shard present; qed");
775
776        // Pull out an array holding just the shards that
777        // correspond to the rows of the submatrix.  These shards
778        // will be the input to the decoding process that re-creates
779        // the missing data shards.
780        //
781        // Also, create an array of indices of the valid rows we do have
782        // and the invalid rows we don't have.
783        //
784        // The valid indices are used to construct the data decode matrix,
785        // the invalid indices are used to key the data decode matrix
786        // in the data decode matrix cache.
787        //
788        // We only need exactly N valid indices, where N = `data_shard_count`,
789        // as the data decode matrix is a N x N matrix, thus only needs
790        // N valid indices for determining the N rows to pick from
791        // `self.matrix`.
792        let mut sub_shards: SmallVec<[&[F::Elem]; 32]> = SmallVec::with_capacity(data_shard_count);
793        let mut missing_data_slices: SmallVec<[&mut [F::Elem]; 32]> =
794            SmallVec::with_capacity(self.parity_shard_count);
795        let mut missing_parity_slices: SmallVec<[&mut [F::Elem]; 32]> =
796            SmallVec::with_capacity(self.parity_shard_count);
797        let mut valid_indices: SmallVec<[usize; 32]> = SmallVec::with_capacity(data_shard_count);
798        let mut invalid_indices: SmallVec<[usize; 32]> = SmallVec::with_capacity(data_shard_count);
799
800        // Separate the shards into groups
801        for (matrix_row, shard) in shards.iter_mut().enumerate() {
802            // get or initialize the shard so we can reconstruct in-place,
803            // but if we are only reconstructing data shard,
804            // do not initialize if the shard is not a data shard
805            let shard_data = if matrix_row >= data_shard_count && data_only {
806                shard.get().ok_or(None)
807            } else {
808                shard.get_or_initialize(shard_len).map_err(Some)
809            };
810
811            match shard_data {
812                Ok(shard) => {
813                    if sub_shards.len() < data_shard_count {
814                        sub_shards.push(shard);
815                        valid_indices.push(matrix_row);
816                    } else {
817                        // Already have enough shards in `sub_shards`
818                        // as we only need N shards, where N = `data_shard_count`,
819                        // for the data decode matrix
820                        //
821                        // So nothing to do here
822                    }
823                }
824                Err(None) => {
825                    // the shard data is not meant to be initialized here,
826                    // but we should still note it missing.
827                    invalid_indices.push(matrix_row);
828                }
829                Err(Some(x)) => {
830                    // initialized missing shard data.
831                    let shard = x?;
832                    if matrix_row < data_shard_count {
833                        missing_data_slices.push(shard);
834                    } else {
835                        missing_parity_slices.push(shard);
836                    }
837
838                    invalid_indices.push(matrix_row);
839                }
840            }
841        }
842
843        let data_decode_matrix = self.get_data_decode_matrix(&valid_indices, &invalid_indices);
844
845        // Re-create any data shards that were missing.
846        //
847        // The input to the coding is all of the shards we actually
848        // have, and the output is the missing data shards. The computation
849        // is done using the special decode matrix we just built.
850        let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
851            SmallVec::with_capacity(self.parity_shard_count);
852
853        for i_slice in invalid_indices
854            .iter()
855            .cloned()
856            .take_while(|i| i < &data_shard_count)
857        {
858            matrix_rows.push(data_decode_matrix.get_row(i_slice));
859        }
860
861        self.code_some_slices(&matrix_rows, &sub_shards, &mut missing_data_slices);
862
863        if data_only {
864            Ok(())
865        } else {
866            // Now that we have all of the data shards intact, we can
867            // compute any of the parity that is missing.
868            //
869            // The input to the coding is ALL of the data shards, including
870            // any that we just calculated.  The output is whichever of the
871            // parity shards were missing.
872            let mut matrix_rows: SmallVec<[&[F::Elem]; 32]> =
873                SmallVec::with_capacity(self.parity_shard_count);
874            let parity_rows = self.get_parity_rows();
875
876            for i_slice in invalid_indices
877                .iter()
878                .cloned()
879                .skip_while(|i| i < &data_shard_count)
880            {
881                matrix_rows.push(parity_rows[i_slice - data_shard_count]);
882            }
883            {
884                // Gather up all the data shards.
885                // old data shards are in `sub_shards`,
886                // new ones are in `missing_data_slices`.
887                let mut i_old_data_slice = 0;
888                let mut i_new_data_slice = 0;
889
890                let mut all_data_slices: SmallVec<[&[F::Elem]; 32]> =
891                    SmallVec::with_capacity(data_shard_count);
892
893                let mut next_maybe_good = 0;
894                let mut push_good_up_to = move |data_slices: &mut SmallVec<_>, up_to| {
895                    // if next_maybe_good == up_to, this loop is a no-op.
896                    for _ in next_maybe_good..up_to {
897                        // push all good indices we just skipped.
898                        data_slices.push(sub_shards[i_old_data_slice]);
899                        i_old_data_slice += 1;
900                    }
901
902                    next_maybe_good = up_to + 1;
903                };
904
905                for i_slice in invalid_indices
906                    .iter()
907                    .cloned()
908                    .take_while(|i| i < &data_shard_count)
909                {
910                    push_good_up_to(&mut all_data_slices, i_slice);
911                    all_data_slices.push(missing_data_slices[i_new_data_slice]);
912                    i_new_data_slice += 1;
913                }
914                push_good_up_to(&mut all_data_slices, data_shard_count);
915
916                // Now do the actual computation for the missing
917                // parity shards
918                self.code_some_slices(&matrix_rows, &all_data_slices, &mut missing_parity_slices);
919            }
920
921            Ok(())
922        }
923    }
924}