OXYGENHUB
# f2f91ceb0e9f oxygen / vendor / crc-fast / .kiro / specs / crc-params-caching / design.md
8.1 KiB · Markdown · last changed Strata: the cloud stores send through ureq, so every release target links 1 month ago renderedsource blame history raw
1
# Design Document
2
3
## Overview
4
5
The CRC parameters caching system will add a thread-safe, memory-efficient cache to the `CrcParams::new()` method. The cache will store pre-computed folding keys indexed by the input parameters, eliminating redundant key generation for identical parameter sets. The design prioritizes performance, thread safety, and minimal memory overhead while maintaining complete API compatibility.
6
7
## Architecture
8
9
### Cache Structure
10
11
The caching system will use a global, thread-safe cache implemented with:
12
13
- **Cache Storage**: `std::collections::HashMap<CrcParamsCacheKey, [u64; 23]>`
14
- **Thread Safety**: `std::sync::RwLock` for concurrent read access with exclusive write access
15
- **Cache Key**: Custom struct containing all parameters that affect key generation
16
- **Lazy Initialization**: `std::sync::OnceLock` to initialize the cache on first use
17
18
### Cache Key Design
19
20
```rust
21
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22
struct CrcParamsCacheKey {
23
    width: u8,
24
    poly: u64,
25
    reflected: bool,
26
}
27
```
28
29
The cache key includes only the parameters that directly affect key generation (`width`, `poly`, `reflected`), excluding parameters like `name`, `init`, `xorout`, and `check` which don't influence the mathematical key computation.
30
31
### Cache Access Pattern
32
33
1. **Cache Hit Path**: Read lock → HashMap lookup → Return cached keys
34
2. **Cache Miss Path**: Read lock → Cache miss → Generate keys → Write lock → Store in cache → Return keys
35
3. **Concurrent Access**: Multiple readers can access simultaneously; writers get exclusive access
36
37
## Components and Interfaces
38
39
### Core Components
40
41
#### 1. Cache Module (`src/cache.rs`)
42
43
```rust
44
use std::collections::HashMap;
45
use std::sync::{OnceLock, RwLock};
46
47
static CACHE: OnceLock<RwLock<HashMap<CrcParamsCacheKey, [u64; 23]>>> = OnceLock::new();
48
49
pub fn get_or_generate_keys(width: u8, poly: u64, reflected: bool) -> [u64; 23]
50
pub fn clear_cache()  // For testing and memory management
51
```
52
53
#### 2. Cache Key Structure
54
55
```rust
56
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
57
struct CrcParamsCacheKey {
58
    width: u8,
59
    poly: u64,
60
    reflected: bool,
61
}
62
```
63
64
#### 3. Modified CrcParams Implementation
65
66
The existing `CrcParams::new()` method will be updated to use the cache:
67
68
```rust
69
impl CrcParams {
70
    pub fn new(
71
        name: &'static str,
72
        width: u8,
73
        poly: u64,
74
        init: u64,
75
        reflected: bool,
76
        xorout: u64,
77
        check: u64,
78
    ) -> Self {
79
        let keys = cache::get_or_generate_keys(width, poly, reflected);
80
        
81
        let algorithm = match width {
82
            32 => CrcAlgorithm::Crc32Custom,
83
            64 => CrcAlgorithm::Crc64Custom,
84
            _ => panic!("Unsupported width: {}", width),
85
        };
86
87
        Self {
88
            algorithm,
89
            name,
90
            width,
91
            poly,
92
            init,
93
            refin: reflected,
94
            refout: reflected,
95
            xorout,
96
            check,
97
            keys,
98
        }
99
    }
100
}
101
```
102
103
### Interface Design
104
105
#### Public Interface
106
- No changes to existing public APIs
107
- `CrcParams::new()` maintains identical signature and behavior
108
- Cache operations are completely internal
109
110
#### Internal Interface
111
- `cache::get_or_generate_keys()` - Primary cache interface
112
- `cache::clear_cache()` - For testing and memory management
113
- Cache key creation and hashing handled internally
114
115
## Data Models
116
117
### Cache Key Model
118
```rust
119
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
120
struct CrcParamsCacheKey {
121
    width: u8,      // CRC width (32 or 64)
122
    poly: u64,      // Polynomial value
123
    reflected: bool, // Reflection mode
124
}
125
```
126
127
### Cache Storage Model
128
```rust
129
type CacheStorage = HashMap<CrcParamsCacheKey, [u64; 23]>;
130
type ThreadSafeCache = RwLock<CacheStorage>;
131
```
132
133
### Memory Layout Considerations
134
- Cache keys: ~17 bytes per entry (8 + 8 + 1 bytes + HashMap overhead)
135
- Cache values: 184 bytes per entry (23 × 8 bytes)
136
- Total per entry: ~201 bytes + HashMap overhead
137
- Expected usage: 1-10 unique parameter sets in typical applications (single parameter set most common)
138
139
## Error Handling
140
141
### Cache Access Errors
142
- **RwLock Poisoning**: If a thread panics while holding the write lock, subsequent accesses will fall back to direct key generation
143
- **Memory Allocation**: HashMap growth failures will be handled by Rust's standard allocation error handling
144
145
### Fallback Strategy
146
```rust
147
fn get_or_generate_keys(width: u8, poly: u64, reflected: bool) -> [u64; 23] {
148
    let cache_key = CrcParamsCacheKey { width, poly, reflected };
149
    
150
    // Try cache read first
151
    if let Ok(cache) = get_cache().read() {
152
        if let Some(keys) = cache.get(&cache_key) {
153
            return *keys;
154
        }
155
    }
156
    
157
    // Generate keys outside of write lock to minimize lock hold time
158
    let keys = generate::keys(width, poly, reflected);
159
    
160
    // Try to cache the result (best effort)
161
    if let Ok(mut cache) = get_cache().write() {
162
        cache.insert(cache_key, keys);
163
    }
164
    
165
    keys
166
}
167
```
168
169
### Error Recovery
170
- Lock poisoning: Continue with direct key generation
171
- Memory pressure: Cache operations become no-ops, functionality preserved
172
- Hash collisions: Handled by HashMap implementation
173
174
## Testing Strategy
175
176
### Unit Tests
177
1. **Cache Functionality**
178
   - Verify cache hits return identical keys
179
   - Verify cache misses generate and store keys
180
   - Test cache key equality and hashing
181
182
2. **Thread Safety**
183
   - Concurrent read access tests
184
   - Read-write contention tests
185
   - Cache consistency under concurrent access
186
187
3. **Performance Tests**
188
   - Benchmark cache hit vs. miss performance
189
   - Memory usage validation
190
   - Comparison with uncached implementation
191
192
4. **Edge Cases**
193
   - Empty cache behavior
194
   - Cache with single entry
195
   - Maximum realistic cache size
196
   - Lock poisoning recovery
197
198
### Integration Tests
199
1. **API Compatibility**
200
   - Existing CrcParams::new() behavior unchanged
201
   - All existing tests continue to pass
202
   - Identical results for cached vs. uncached keys
203
204
2. **Real-world Usage Patterns**
205
   - Multiple CrcParams instances with same parameters
206
   - Mixed usage with different parameters
207
   - Long-running application simulation
208
209
### Performance Benchmarks
210
1. **Cache Hit Performance**: Measure lookup time vs. key generation time
211
2. **Cache Miss Performance**: Measure overhead of cache check + generation
212
3. **Memory Usage**: Track cache memory consumption over time
213
4. **Concurrent Access**: Measure performance under thread contention
214
215
## Implementation Phases
216
217
### Phase 1: Core Cache Implementation
218
- Create cache module with basic HashMap storage
219
- Implement thread-safe access with RwLock
220
- Add cache key structure and hashing
221
222
### Phase 2: Integration
223
- Modify CrcParams::new() to use cache
224
- Add fallback error handling
225
- Ensure API compatibility
226
227
### Phase 3: Testing and Optimization
228
- Comprehensive test suite
229
- Performance benchmarking
230
- Memory usage optimization
231
- Documentation updates
232
233
## Performance Considerations
234
235
### Cache Hit Performance
236
- Expected improvement: 50-100x faster than key generation
237
- RwLock read access: ~10-20ns overhead
238
- HashMap lookup: O(1) average case, ~50-100ns
239
240
### Cache Miss Performance
241
- Additional overhead: ~100-200ns for cache check
242
- Write lock acquisition: ~50-100ns
243
- HashMap insertion: O(1) average case
244
245
### Memory Efficiency
246
- Cache overhead per entry: ~201 bytes
247
- Expected cache size: 200 bytes - 2KB for typical applications
248
- Memory growth: Linear with unique parameter combinations
249
250
### Thread Contention
251
- Read-heavy workload: Excellent scalability
252
- Write contention: Minimal impact (writes are rare after warmup)
253
- Lock-free reads: Multiple threads can read simultaneously
254
255
## Security Considerations
256
257
### Memory Safety
258
- All cache operations use safe Rust constructs
259
- No unsafe code in cache implementation
260
- HashMap provides memory safety guarantees
261
262
### Thread Safety
263
- RwLock prevents data races
264
- Cache key immutability prevents modification after creation
265
- Atomic operations for cache initialization
266
267
### Resource Management
268
- Cache growth is bounded by unique parameter combinations
269
- No automatic eviction policy (acceptable for typical usage)
270
- Manual cache clearing available for memory management