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}