absurder_sql/storage/
metadata.rs

1//! Metadata module extracted from block_storage.rs
2//! This module contains the ACTUAL checksum and metadata logic moved from BlockStorage
3
4use crate::types::DatabaseError;
5#[cfg(not(target_arch = "wasm32"))]
6use parking_lot::Mutex;
7#[cfg(target_arch = "wasm32")]
8use std::cell::RefCell;
9use std::collections::HashMap;
10
11// Reentrancy-safe lock macros
12#[allow(unused_macros)]
13#[cfg(target_arch = "wasm32")]
14macro_rules! lock_mutex {
15    ($mutex:expr) => {
16        $mutex
17            .try_borrow_mut()
18            .expect("RefCell borrow failed - reentrancy detected in metadata.rs")
19    };
20}
21
22#[allow(unused_macros)]
23#[cfg(not(target_arch = "wasm32"))]
24macro_rules! lock_mutex {
25    ($mutex:expr) => {
26        $mutex.lock()
27    };
28}
29
30#[cfg(target_arch = "wasm32")]
31#[allow(unused_imports)]
32use js_sys::Date;
33
34#[cfg(not(target_arch = "wasm32"))]
35#[allow(unused_imports)]
36use std::time::{SystemTime, UNIX_EPOCH};
37
38// MOVED from block_storage.rs lines 38-41
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40#[allow(dead_code)]
41#[cfg_attr(feature = "fs_persist", derive(serde::Serialize, serde::Deserialize))]
42pub enum ChecksumAlgorithm {
43    FastHash,
44    CRC32,
45}
46
47// MOVED from block_storage.rs lines 43-54
48#[derive(Clone, Debug)]
49#[cfg_attr(feature = "fs_persist", derive(serde::Serialize, serde::Deserialize))]
50pub struct BlockMetadataPersist {
51    pub checksum: u64,
52    #[allow(dead_code)]
53    pub last_modified_ms: u64,
54    #[allow(dead_code)]
55    pub version: u32,
56    #[allow(dead_code)]
57    pub algo: ChecksumAlgorithm,
58}
59
60/// Metadata manager that encapsulates the checksum logic extracted from BlockStorage
61pub struct ChecksumManager {
62    #[cfg(target_arch = "wasm32")]
63    checksums: RefCell<HashMap<u64, u64>>,
64    #[cfg(not(target_arch = "wasm32"))]
65    checksums: Mutex<HashMap<u64, u64>>,
66
67    #[cfg(target_arch = "wasm32")]
68    checksum_algos: RefCell<HashMap<u64, ChecksumAlgorithm>>,
69    #[cfg(not(target_arch = "wasm32"))]
70    checksum_algos: Mutex<HashMap<u64, ChecksumAlgorithm>>,
71
72    /// Default algorithm for new blocks (MOVED from BlockStorage.checksum_algo_default)
73    checksum_algo_default: ChecksumAlgorithm,
74}
75
76impl ChecksumManager {
77    /// Create new checksum manager with default algorithm
78    pub fn new(default_algorithm: ChecksumAlgorithm) -> Self {
79        Self {
80            #[cfg(target_arch = "wasm32")]
81            checksums: RefCell::new(HashMap::new()),
82            #[cfg(not(target_arch = "wasm32"))]
83            checksums: Mutex::new(HashMap::new()),
84
85            #[cfg(target_arch = "wasm32")]
86            checksum_algos: RefCell::new(HashMap::new()),
87            #[cfg(not(target_arch = "wasm32"))]
88            checksum_algos: Mutex::new(HashMap::new()),
89
90            checksum_algo_default: default_algorithm,
91        }
92    }
93
94    /// Initialize with existing data (used during restoration)
95    pub fn with_data(
96        checksums: HashMap<u64, u64>,
97        checksum_algos: HashMap<u64, ChecksumAlgorithm>,
98        default_algorithm: ChecksumAlgorithm,
99    ) -> Self {
100        Self {
101            #[cfg(target_arch = "wasm32")]
102            checksums: RefCell::new(checksums),
103            #[cfg(not(target_arch = "wasm32"))]
104            checksums: Mutex::new(checksums),
105
106            #[cfg(target_arch = "wasm32")]
107            checksum_algos: RefCell::new(checksum_algos),
108            #[cfg(not(target_arch = "wasm32"))]
109            checksum_algos: Mutex::new(checksum_algos),
110
111            checksum_algo_default: default_algorithm,
112        }
113    }
114
115    /// MOVED from BlockStorage::compute_checksum_with (lines 1803-1818)
116    pub fn compute_checksum_with(data: &[u8], algo: ChecksumAlgorithm) -> u64 {
117        match algo {
118            ChecksumAlgorithm::FastHash => {
119                use std::collections::hash_map::DefaultHasher;
120                use std::hash::Hash;
121                use std::hash::Hasher;
122                let mut hasher = DefaultHasher::new();
123                data.hash(&mut hasher);
124                hasher.finish()
125            }
126            ChecksumAlgorithm::CRC32 => {
127                let mut hasher = crc32fast::Hasher::new();
128                hasher.update(data);
129                hasher.finalize() as u64
130            }
131        }
132    }
133
134    /// Store checksum for a block (MOVED from lines 2442-2444)
135    pub fn store_checksum(&self, block_id: u64, data: &[u8]) {
136        let algo = {
137            let algos = lock_mutex!(self.checksum_algos);
138            algos
139                .get(&block_id)
140                .copied()
141                .unwrap_or(self.checksum_algo_default)
142        };
143        let csum = Self::compute_checksum_with(data, algo);
144        lock_mutex!(self.checksums).insert(block_id, csum);
145        lock_mutex!(self.checksum_algos).insert(block_id, algo);
146    }
147
148    /// Validate checksum for a block (MOVED from lines 1843-1870)
149    pub fn validate_checksum(&self, block_id: u64, data: &[u8]) -> Result<(), DatabaseError> {
150        let expected_opt = lock_mutex!(self.checksums).get(&block_id).copied();
151        if let Some(expected) = expected_opt {
152            let algo = lock_mutex!(self.checksum_algos)
153                .get(&block_id)
154                .copied()
155                .unwrap_or(self.checksum_algo_default);
156            let actual = Self::compute_checksum_with(data, algo);
157            if expected != actual {
158                // Try other known algorithms to detect algorithm mismatch (MOVED from lines 1851-1869)
159                let known_algos = [ChecksumAlgorithm::FastHash, ChecksumAlgorithm::CRC32];
160                for alt in known_algos.iter().copied().filter(|a| *a != algo) {
161                    let alt_sum = Self::compute_checksum_with(data, alt);
162                    if expected == alt_sum {
163                        return Err(DatabaseError::new(
164                            "ALGO_MISMATCH",
165                            &format!(
166                                "Checksum algorithm mismatch for block {}: stored algo {:?}, but data matches {:?}",
167                                block_id, algo, alt
168                            ),
169                        ));
170                    }
171                }
172                return Err(DatabaseError::new(
173                    "CHECKSUM_MISMATCH",
174                    &format!(
175                        "Checksum mismatch for block {}: expected {}, got {}",
176                        block_id, expected, actual
177                    ),
178                ));
179            }
180        }
181        Ok(())
182    }
183
184    /// Remove checksum for a block (MOVED from lines 1709-1710)
185    pub fn remove_checksum(&self, block_id: u64) {
186        lock_mutex!(self.checksums).remove(&block_id);
187        lock_mutex!(self.checksum_algos).remove(&block_id);
188    }
189
190    /// Get checksum for a block
191    pub fn get_checksum(&self, block_id: u64) -> Option<u64> {
192        lock_mutex!(self.checksums).get(&block_id).copied()
193    }
194
195    /// Get algorithm for a block
196    pub fn get_algorithm(&self, block_id: u64) -> ChecksumAlgorithm {
197        lock_mutex!(self.checksum_algos)
198            .get(&block_id)
199            .copied()
200            .unwrap_or(self.checksum_algo_default)
201    }
202
203    /// Replace all checksums (MOVED from lines 1331-1332, 1500-1501)
204    pub fn replace_all(
205        &self,
206        new_checksums: HashMap<u64, u64>,
207        new_algos: HashMap<u64, ChecksumAlgorithm>,
208    ) {
209        *lock_mutex!(self.checksums) = new_checksums;
210        *lock_mutex!(self.checksum_algos) = new_algos;
211    }
212
213    /// Get a clone of the internal checksums map (for compatibility)
214    pub fn checksums(&self) -> HashMap<u64, u64> {
215        lock_mutex!(self.checksums).clone()
216    }
217
218    /// Get a clone of the internal algorithms map (for compatibility)
219    pub fn algorithms(&self) -> HashMap<u64, ChecksumAlgorithm> {
220        lock_mutex!(self.checksum_algos).clone()
221    }
222
223    /// Get default algorithm
224    pub fn default_algorithm(&self) -> ChecksumAlgorithm {
225        self.checksum_algo_default
226    }
227
228    /// Set checksum for testing purposes (always available for integration tests)
229    pub fn set_checksum_for_testing(&self, block_id: u64, checksum: u64) {
230        lock_mutex!(self.checksums).insert(block_id, checksum);
231    }
232
233    /// Clear all checksums (useful after database import)
234    pub fn clear_checksums(&self) {
235        lock_mutex!(self.checksums).clear();
236        lock_mutex!(self.checksum_algos).clear();
237    }
238}