feoxdb/storage/
metadata.rs1use crate::constants::*;
2use crate::error::{FeoxError, Result};
3use crate::storage::seq_token::crc32c;
4
5const METADATA_VERSION: u32 = 3;
10const METADATA_ENCODED_SIZE: usize = 136;
11const VERSION_OFFSET: usize = 8;
12const TOTAL_RECORDS_OFFSET: usize = 16;
13const TOTAL_SIZE_OFFSET: usize = 24;
14const DEVICE_SIZE_OFFSET: usize = 32;
15const BLOCK_SIZE_OFFSET: usize = 40;
16const FRAGMENTATION_OFFSET: usize = 44;
17const CREATION_TIME_OFFSET: usize = 48;
18const LAST_UPDATE_TIME_OFFSET: usize = 56;
19const RESERVED_OFFSET: usize = 64;
20const RESERVED_SIZE: usize = 68;
21const CHECKSUM_MAGIC: &[u8; 4] = b"FM3C";
22const CHECKSUM_OFFSET: usize = 4;
23const CHECKSUM_COMPLEMENT_OFFSET: usize = 8;
24const CHECKSUM_DATA_OFFSET: usize = 12;
25const GENERATION_OFFSET: usize = 12;
26
27#[derive(Debug, Clone, Copy)]
28pub struct Metadata {
29 pub signature: [u8; FEOX_SIGNATURE_SIZE],
30 pub version: u32,
31 pub total_records: u64,
32 pub total_size: u64,
33 pub device_size: u64,
34 pub block_size: u32,
35 pub fragmentation: u32,
36 pub creation_time: u64,
37 pub last_update_time: u64,
38 reserved: [u8; RESERVED_SIZE],
39}
40
41impl Default for Metadata {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47impl Metadata {
48 pub fn new() -> Self {
49 let now = std::time::SystemTime::now()
50 .duration_since(std::time::UNIX_EPOCH)
51 .unwrap_or_else(|_| std::time::Duration::from_secs(0))
52 .as_secs();
53
54 let mut metadata = Self {
55 signature: *FEOX_SIGNATURE,
56 version: METADATA_VERSION,
57 total_records: 0,
58 total_size: 0,
59 device_size: 0,
60 block_size: FEOX_BLOCK_SIZE as u32,
61 fragmentation: 0,
62 creation_time: now,
63 last_update_time: now,
64 reserved: [0; RESERVED_SIZE],
65 };
66 metadata.refresh_checksum();
67 metadata
68 }
69
70 pub fn validate(&self) -> bool {
71 if self.signature != *FEOX_SIGNATURE {
72 return false;
73 }
74
75 if self.block_size != FEOX_BLOCK_SIZE as u32 {
76 return false;
77 }
78
79 if self.version == 0 || self.version > METADATA_VERSION {
80 return false;
81 }
82
83 if self.device_size == 0 || self.device_size > MAX_DEVICE_SIZE {
84 return false;
85 }
86
87 let has_checksum = &self.reserved[..CHECKSUM_MAGIC.len()] == CHECKSUM_MAGIC;
88 if self.version >= 3 && !has_checksum {
89 return false;
90 }
91 if !has_checksum {
92 return true;
93 }
94
95 let checksum = u32::from_le_bytes(
96 self.reserved[CHECKSUM_OFFSET..CHECKSUM_OFFSET + 4]
97 .try_into()
98 .unwrap(),
99 );
100 let complement = u32::from_le_bytes(
101 self.reserved[CHECKSUM_COMPLEMENT_OFFSET..CHECKSUM_COMPLEMENT_OFFSET + 4]
102 .try_into()
103 .unwrap(),
104 );
105 complement == !checksum && checksum == self.checksum()
106 }
107
108 pub fn update(&mut self) {
109 self.last_update_time = std::time::SystemTime::now()
110 .duration_since(std::time::UNIX_EPOCH)
111 .unwrap_or_else(|_| std::time::Duration::from_secs(0))
112 .as_secs();
113 self.refresh_checksum();
114 }
115
116 pub fn encode(&self) -> [u8; METADATA_ENCODED_SIZE] {
117 let mut bytes = [0; METADATA_ENCODED_SIZE];
118 bytes[..FEOX_SIGNATURE_SIZE].copy_from_slice(&self.signature);
119 bytes[VERSION_OFFSET..VERSION_OFFSET + 4].copy_from_slice(&self.version.to_le_bytes());
120 bytes[TOTAL_RECORDS_OFFSET..TOTAL_RECORDS_OFFSET + 8]
121 .copy_from_slice(&self.total_records.to_le_bytes());
122 bytes[TOTAL_SIZE_OFFSET..TOTAL_SIZE_OFFSET + 8]
123 .copy_from_slice(&self.total_size.to_le_bytes());
124 bytes[DEVICE_SIZE_OFFSET..DEVICE_SIZE_OFFSET + 8]
125 .copy_from_slice(&self.device_size.to_le_bytes());
126 bytes[BLOCK_SIZE_OFFSET..BLOCK_SIZE_OFFSET + 4]
127 .copy_from_slice(&self.block_size.to_le_bytes());
128 bytes[FRAGMENTATION_OFFSET..FRAGMENTATION_OFFSET + 4]
129 .copy_from_slice(&self.fragmentation.to_le_bytes());
130 bytes[CREATION_TIME_OFFSET..CREATION_TIME_OFFSET + 8]
131 .copy_from_slice(&self.creation_time.to_le_bytes());
132 bytes[LAST_UPDATE_TIME_OFFSET..LAST_UPDATE_TIME_OFFSET + 8]
133 .copy_from_slice(&self.last_update_time.to_le_bytes());
134 bytes[RESERVED_OFFSET..RESERVED_OFFSET + RESERVED_SIZE].copy_from_slice(&self.reserved);
135 bytes
136 }
137
138 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
139 if bytes.len() < METADATA_ENCODED_SIZE {
140 return None;
141 }
142
143 let metadata = Self {
144 signature: bytes[..FEOX_SIGNATURE_SIZE].try_into().ok()?,
145 version: u32::from_le_bytes(bytes[VERSION_OFFSET..VERSION_OFFSET + 4].try_into().ok()?),
146 total_records: u64::from_le_bytes(
147 bytes[TOTAL_RECORDS_OFFSET..TOTAL_RECORDS_OFFSET + 8]
148 .try_into()
149 .ok()?,
150 ),
151 total_size: u64::from_le_bytes(
152 bytes[TOTAL_SIZE_OFFSET..TOTAL_SIZE_OFFSET + 8]
153 .try_into()
154 .ok()?,
155 ),
156 device_size: u64::from_le_bytes(
157 bytes[DEVICE_SIZE_OFFSET..DEVICE_SIZE_OFFSET + 8]
158 .try_into()
159 .ok()?,
160 ),
161 block_size: u32::from_le_bytes(
162 bytes[BLOCK_SIZE_OFFSET..BLOCK_SIZE_OFFSET + 4]
163 .try_into()
164 .ok()?,
165 ),
166 fragmentation: u32::from_le_bytes(
167 bytes[FRAGMENTATION_OFFSET..FRAGMENTATION_OFFSET + 4]
168 .try_into()
169 .ok()?,
170 ),
171 creation_time: u64::from_le_bytes(
172 bytes[CREATION_TIME_OFFSET..CREATION_TIME_OFFSET + 8]
173 .try_into()
174 .ok()?,
175 ),
176 last_update_time: u64::from_le_bytes(
177 bytes[LAST_UPDATE_TIME_OFFSET..LAST_UPDATE_TIME_OFFSET + 8]
178 .try_into()
179 .ok()?,
180 ),
181 reserved: bytes[RESERVED_OFFSET..RESERVED_OFFSET + RESERVED_SIZE]
182 .try_into()
183 .ok()?,
184 };
185
186 if metadata.validate() {
187 Some(metadata)
188 } else {
189 None
190 }
191 }
192
193 pub(crate) fn generation(&self) -> u64 {
194 u64::from_le_bytes(
195 self.reserved[GENERATION_OFFSET..GENERATION_OFFSET + 8]
196 .try_into()
197 .unwrap(),
198 )
199 }
200
201 pub(crate) fn advance_generation(&mut self) -> Result<()> {
202 let generation = self
203 .generation()
204 .checked_add(1)
205 .ok_or(FeoxError::InvalidMetadata)?;
206 self.reserved[GENERATION_OFFSET..GENERATION_OFFSET + 8]
207 .copy_from_slice(&generation.to_le_bytes());
208 self.refresh_checksum();
209 Ok(())
210 }
211
212 fn refresh_checksum(&mut self) {
213 self.reserved[..CHECKSUM_MAGIC.len()].copy_from_slice(CHECKSUM_MAGIC);
214 let checksum = self.checksum();
215 self.reserved[CHECKSUM_OFFSET..CHECKSUM_OFFSET + 4]
216 .copy_from_slice(&checksum.to_le_bytes());
217 self.reserved[CHECKSUM_COMPLEMENT_OFFSET..CHECKSUM_COMPLEMENT_OFFSET + 4]
218 .copy_from_slice(&(!checksum).to_le_bytes());
219 }
220
221 fn checksum(&self) -> u32 {
222 let mut checksum = crc32c(0, &self.signature);
223 checksum = crc32c(checksum, &self.version.to_le_bytes());
224 checksum = crc32c(checksum, &self.total_records.to_le_bytes());
225 checksum = crc32c(checksum, &self.total_size.to_le_bytes());
226 checksum = crc32c(checksum, &self.device_size.to_le_bytes());
227 checksum = crc32c(checksum, &self.block_size.to_le_bytes());
228 checksum = crc32c(checksum, &self.fragmentation.to_le_bytes());
229 checksum = crc32c(checksum, &self.creation_time.to_le_bytes());
230 checksum = crc32c(checksum, &self.last_update_time.to_le_bytes());
231 crc32c(checksum, &self.reserved[CHECKSUM_DATA_OFFSET..])
232 }
233}