Skip to main content

rustfs_erasure_codec/core/
mod.rs

1extern crate alloc;
2
3#[cfg(feature = "std")]
4pub(crate) mod cache_detect;
5mod codec;
6mod encode;
7mod leopard;
8pub(crate) mod leopard_gf16;
9pub(crate) mod leopard_gf8;
10mod metrics;
11mod options;
12#[cfg(feature = "std")]
13mod parallel;
14mod reconstruct;
15mod shard_by_shard;
16#[cfg(feature = "std")]
17pub mod stream;
18mod verify;
19mod workspace;
20
21use alloc::sync::Arc;
22use alloc::vec::Vec;
23
24use hashlink::LruCache;
25#[cfg(feature = "std")]
26use parking_lot::Mutex;
27#[cfg(not(feature = "std"))]
28use spin::Mutex;
29
30use crate::Field;
31use crate::matrix::Matrix;
32
33use leopard::FamilyState;
34
35#[cfg(feature = "std")]
36pub use leopard_gf8::LeopardGf8ProfileStats;
37#[cfg(feature = "std")]
38pub(crate) use leopard_gf8::{leopard_gf8_profile_stats, reset_leopard_gf8_profile_stats};
39#[cfg(feature = "std")]
40pub use metrics::{ReconstructionCacheAnalysis, ReconstructionCacheStats, RuntimeProfileStats};
41pub use options::{CodecFamily, CodecOptions, MatrixMode};
42#[cfg(feature = "std")]
43pub(crate) use parallel::RuntimeParallelPolicyCache;
44#[cfg(feature = "std")]
45pub use parallel::{PARALLEL_POLICY_VERSION, ParallelDecision, ParallelPolicy};
46pub use shard_by_shard::ShardByShard;
47pub use workspace::VerifyWorkspace;
48
49#[cfg(feature = "std")]
50use metrics::{ReconstructionCacheMetrics, RuntimeProfileMetrics};
51
52pub(crate) const DATA_DECODE_MATRIX_CACHE_MIN_CAPACITY: usize = 128;
53pub(crate) const DATA_DECODE_MATRIX_CACHE_MAX_CAPACITY: usize = 4096;
54pub(crate) const CODE_SLICE_MIN_CHUNK_BYTES: usize = 16 * 1024;
55pub(crate) const CODE_SLICE_DEFAULT_CHUNK_BYTES: usize = 64 * 1024;
56pub(crate) const CODE_SLICE_LARGE_CHUNK_BYTES: usize = 256 * 1024;
57pub(crate) const VERIFY_INLINE_SCRATCH_ELEMS: usize = 4 * 1024;
58#[cfg(feature = "std")]
59pub(crate) const PARALLEL_MIN_SHARD_BYTES: usize = 256 * 1024;
60
61#[derive(Debug)]
62pub struct ReedSolomon<F: Field> {
63    data_shard_count: usize,
64    parity_shard_count: usize,
65    total_shard_count: usize,
66    codec_family: CodecFamily,
67    pub(crate) family_state: FamilyState<F>,
68    matrix: Matrix<F>,
69    options: CodecOptions,
70    #[cfg(feature = "std")]
71    pub(crate) policy_cache: RuntimeParallelPolicyCache,
72    data_decode_matrix_cache: Mutex<LruCache<Vec<usize>, Arc<Matrix<F>>>>,
73    #[cfg(feature = "std")]
74    reconstruction_cache_metrics: ReconstructionCacheMetrics,
75    #[cfg(feature = "std")]
76    runtime_profile_metrics: RuntimeProfileMetrics,
77}
78
79impl<F: Field> Clone for ReedSolomon<F> {
80    fn clone(&self) -> ReedSolomon<F> {
81        match ReedSolomon::with_options(
82            self.data_shard_count,
83            self.parity_shard_count,
84            self.options,
85        ) {
86            Ok(codec) => codec,
87            Err(err) => {
88                debug_assert!(
89                    false,
90                    "existing codec invariants must produce a valid clone, but got error: {err:?}"
91                );
92                let mut matrix = Matrix::new(self.matrix.row_count(), self.matrix.col_count());
93                for row in 0..self.matrix.row_count() {
94                    for col in 0..self.matrix.col_count() {
95                        matrix.set(row, col, self.matrix.get(row, col));
96                    }
97                }
98
99                let family_state = crate::core::leopard::build_family_state(
100                    self.codec_family,
101                    self.data_shard_count,
102                    self.parity_shard_count,
103                    &matrix,
104                )
105                .unwrap_or_else(|_| {
106                    debug_assert!(
107                        false,
108                        "fallback clone path could not rebuild family state from stored matrix"
109                    );
110                    match self.codec_family {
111                        super::CodecFamily::Classic => FamilyState::Classic,
112                        super::CodecFamily::LeopardGF16 => FamilyState::LeopardGF16,
113                        super::CodecFamily::LeopardGF8 => {
114                            debug_assert!(
115                                false,
116                                "LeopardGF8 should have a recoverable family state"
117                            );
118                            FamilyState::Classic
119                        }
120                    }
121                });
122
123                let options = self.options;
124                #[cfg(feature = "std")]
125                let policy_cache = self.policy_cache;
126
127                ReedSolomon {
128                    data_shard_count: self.data_shard_count,
129                    parity_shard_count: self.parity_shard_count,
130                    total_shard_count: self.total_shard_count,
131                    codec_family: self.codec_family,
132                    family_state,
133                    matrix,
134                    options,
135                    #[cfg(feature = "std")]
136                    policy_cache,
137                    data_decode_matrix_cache: Mutex::new(LruCache::new(
138                        options.inversion_cache_capacity,
139                    )),
140                    #[cfg(feature = "std")]
141                    reconstruction_cache_metrics: ReconstructionCacheMetrics::default(),
142                    #[cfg(feature = "std")]
143                    runtime_profile_metrics: RuntimeProfileMetrics::default(),
144                }
145            }
146        }
147    }
148}
149
150impl<F: Field> PartialEq for ReedSolomon<F> {
151    fn eq(&self, rhs: &ReedSolomon<F>) -> bool {
152        self.data_shard_count == rhs.data_shard_count
153            && self.parity_shard_count == rhs.parity_shard_count
154            && self.codec_family == rhs.codec_family
155    }
156}
157
158impl<F: Field> ReedSolomon<F> {
159    /// Returns `Ok(())` for Classic, LeopardGF8, and LeopardGF16 families.
160    ///
161    /// Methods that are genuinely Classic-only (e.g., `update`, `decode_idx`) should
162    /// check `is_leopard_gf8_family()` / `is_leopard_gf16_family()` separately and
163    /// return an appropriate error.
164    pub(crate) fn ensure_classic_family_execution(&self) -> Result<(), crate::Error> {
165        match self.family_state {
166            FamilyState::Classic | FamilyState::LeopardGF8(_) | FamilyState::LeopardGF16 => Ok(()),
167        }
168    }
169
170    pub(crate) fn is_leopard_gf8_family(&self) -> bool {
171        matches!(self.family_state, FamilyState::LeopardGF8(_))
172    }
173
174    pub(crate) fn is_leopard_gf16_family(&self) -> bool {
175        matches!(self.family_state, FamilyState::LeopardGF16)
176    }
177}