@@ -40,11 +40,13 @@ fn get_cache() -> &'static RwLock<HashMap<CrcParamsCacheKey, [u64; 23]>> {
40
40
/// 2. If cache miss, generates keys outside of any lock
41
41
/// 3. Then acquires write lock to store the generated keys
42
42
///
43
- /// Falls back to direct key generation if lock poisoning occurs
43
+ /// All cache operations are best-effort with graceful degradation - if any cache
44
+ /// operation fails, the function falls back to direct key generation
44
45
pub fn get_or_generate_keys ( width : u8 , poly : u64 , reflected : bool ) -> [ u64 ; 23 ] {
45
46
let cache_key = CrcParamsCacheKey :: new ( width, poly, reflected) ;
46
47
47
48
// Try cache read first - multiple threads can read simultaneously
49
+ // If lock is poisoned or read fails, continue to key generation
48
50
if let Ok ( cache) = get_cache ( ) . read ( ) {
49
51
if let Some ( keys) = cache. get ( & cache_key) {
50
52
return * keys;
@@ -55,9 +57,73 @@ pub fn get_or_generate_keys(width: u8, poly: u64, reflected: bool) -> [u64; 23]
55
57
let keys = generate:: keys ( width, poly, reflected) ;
56
58
57
59
// Try to cache the result (best effort - if this fails, we still return valid keys)
58
- if let Ok ( mut cache) = get_cache ( ) . write ( ) {
59
- cache. insert ( cache_key, keys) ;
60
- }
60
+ // Lock poisoning or write failure doesn't affect functionality
61
+ let _ = get_cache ( ) . write ( ) . map ( |mut cache| {
62
+ cache. insert ( cache_key, keys)
63
+ } ) ;
61
64
62
65
keys
66
+ }
67
+
68
+ /// Clear all cached CRC parameter keys
69
+ ///
70
+ /// This function is primarily intended for testing and memory management.
71
+ /// It performs a best-effort clear operation - if the cache lock is poisoned
72
+ /// or unavailable, the operation silently fails without affecting program execution.
73
+ ///
74
+ /// # Thread Safety
75
+ /// This function is thread-safe and can be called concurrently with other cache operations.
76
+ /// However, clearing the cache while other threads are actively using it may reduce
77
+ /// performance temporarily as keys will need to be regenerated.
78
+ pub fn clear_cache ( ) {
79
+ // Best-effort cache clear - if lock is poisoned or unavailable, silently continue
80
+ // This ensures the function never panics or blocks program execution
81
+ let _ = get_cache ( ) . write ( ) . map ( |mut cache| {
82
+ cache. clear ( )
83
+ } ) ;
84
+ }
85
+
86
+ #[ cfg( test) ]
87
+ mod tests {
88
+ use super :: * ;
89
+
90
+ #[ test]
91
+ fn test_cache_management_utilities ( ) {
92
+ // Clear cache to start with clean state
93
+ clear_cache ( ) ;
94
+
95
+ // Generate and cache some keys
96
+ let keys1 = get_or_generate_keys ( 32 , 0x04C11DB7 , true ) ;
97
+ let keys2 = get_or_generate_keys ( 64 , 0x42F0E1EBA9EA3693 , false ) ;
98
+
99
+ // Verify cache hits return same keys
100
+ let cached_keys1 = get_or_generate_keys ( 32 , 0x04C11DB7 , true ) ;
101
+ let cached_keys2 = get_or_generate_keys ( 64 , 0x42F0E1EBA9EA3693 , false ) ;
102
+
103
+ assert_eq ! ( keys1, cached_keys1) ;
104
+ assert_eq ! ( keys2, cached_keys2) ;
105
+
106
+ // Clear cache
107
+ clear_cache ( ) ;
108
+
109
+ // Verify cache was cleared by checking that new calls still work
110
+ // (we can't directly verify cache is empty, but we can verify functionality)
111
+ let new_keys1 = get_or_generate_keys ( 32 , 0x04C11DB7 , true ) ;
112
+ assert_eq ! ( keys1, new_keys1) ; // Should be same values, but freshly generated
113
+ }
114
+
115
+ #[ test]
116
+ fn test_cache_error_handling ( ) {
117
+ // Test that cache operations don't panic even if called multiple times
118
+ clear_cache ( ) ;
119
+ clear_cache ( ) ; // Should not panic on empty cache
120
+
121
+ // Test that get_or_generate_keys works even after multiple clears
122
+ let keys = get_or_generate_keys ( 32 , 0x04C11DB7 , true ) ;
123
+ clear_cache ( ) ;
124
+ let keys2 = get_or_generate_keys ( 32 , 0x04C11DB7 , true ) ;
125
+
126
+ // Keys should be identical (same parameters produce same keys)
127
+ assert_eq ! ( keys, keys2) ;
128
+ }
63
129
}
0 commit comments