ferrum_kv/blocks/
table.rs1use ferrum_interfaces::BlockTable;
4use smallvec::SmallVec;
5
6#[derive(Debug, Clone, Default)]
8pub struct DefaultBlockTable {
9 pub physical: SmallVec<[u32; 8]>,
11 pub logical_to_physical: SmallVec<[u32; 8]>,
13 pub seq_len: usize,
15}
16
17impl DefaultBlockTable {
18 pub fn new() -> Self {
20 Self::default()
21 }
22
23 pub fn with_capacity(capacity: usize) -> Self {
25 Self {
26 physical: SmallVec::with_capacity(capacity),
27 logical_to_physical: SmallVec::with_capacity(capacity),
28 seq_len: 0,
29 }
30 }
31
32 pub fn map_block(&mut self, logical_id: u32, physical_id: u32) {
34 while self.logical_to_physical.len() <= logical_id as usize {
36 self.logical_to_physical.push(0);
37 }
38 while self.physical.len() <= physical_id as usize {
39 self.physical.push(0);
40 }
41
42 self.logical_to_physical[logical_id as usize] = physical_id;
43 self.physical[physical_id as usize] = 1; }
45
46 pub fn unmap_block(&mut self, logical_id: u32) -> Option<u32> {
48 if (logical_id as usize) < self.logical_to_physical.len() {
49 let physical_id = self.logical_to_physical[logical_id as usize];
50 if physical_id > 0 && (physical_id as usize) < self.physical.len() {
51 self.physical[physical_id as usize] = 0; self.logical_to_physical[logical_id as usize] = 0;
53 Some(physical_id)
54 } else {
55 None
56 }
57 } else {
58 None
59 }
60 }
61
62 pub fn get_physical(&self, logical_id: u32) -> Option<u32> {
64 if (logical_id as usize) < self.logical_to_physical.len() {
65 let physical_id = self.logical_to_physical[logical_id as usize];
66 if physical_id > 0 {
67 Some(physical_id)
68 } else {
69 None
70 }
71 } else {
72 None
73 }
74 }
75
76 pub fn is_physical_used(&self, physical_id: u32) -> bool {
78 if (physical_id as usize) < self.physical.len() {
79 self.physical[physical_id as usize] != 0
80 } else {
81 false
82 }
83 }
84
85 pub fn num_logical_blocks(&self) -> usize {
87 self.logical_to_physical.len()
88 }
89
90 pub fn num_physical_blocks(&self) -> usize {
92 self.physical.len()
93 }
94
95 pub fn num_used_blocks(&self) -> usize {
97 self.physical.iter().filter(|&&used| used != 0).count()
98 }
99
100 pub fn clear(&mut self) {
102 self.physical.clear();
103 self.logical_to_physical.clear();
104 self.seq_len = 0;
105 }
106
107 pub fn shrink(&mut self) {
109 while let Some(&last) = self.logical_to_physical.last() {
111 if last == 0 {
112 self.logical_to_physical.pop();
113 } else {
114 break;
115 }
116 }
117
118 while let Some(&last) = self.physical.last() {
120 if last == 0 {
121 self.physical.pop();
122 } else {
123 break;
124 }
125 }
126 }
127
128 pub fn used_physical_blocks(&self) -> Vec<u32> {
130 self.physical
131 .iter()
132 .enumerate()
133 .filter_map(|(id, &used)| if used != 0 { Some(id as u32) } else { None })
134 .collect()
135 }
136
137 pub fn extend(&self, additional_logical: usize, additional_physical: usize) -> Self {
139 let mut new_table = self.clone();
140 new_table.logical_to_physical.reserve(additional_logical);
141 new_table.physical.reserve(additional_physical);
142 new_table
143 }
144}
145
146impl From<DefaultBlockTable> for BlockTable {
147 fn from(table: DefaultBlockTable) -> Self {
148 BlockTable {
149 physical_blocks: table.physical,
150 logical_to_physical: table.logical_to_physical,
151 sequence_length: table.seq_len,
152 block_size: 16, }
154 }
155}
156
157impl From<BlockTable> for DefaultBlockTable {
158 fn from(table: BlockTable) -> Self {
159 Self {
160 physical: table.physical_blocks.iter().copied().collect(),
161 logical_to_physical: table.logical_to_physical.iter().copied().collect(),
162 seq_len: table.sequence_length,
163 }
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn test_block_table_creation() {
173 let table = DefaultBlockTable::new();
174 assert_eq!(table.num_logical_blocks(), 0);
175 assert_eq!(table.num_physical_blocks(), 0);
176 assert_eq!(table.seq_len, 0);
177 }
178
179 #[test]
180 fn test_block_mapping() {
181 let mut table = DefaultBlockTable::new();
182
183 table.map_block(0, 5);
185
186 assert_eq!(table.get_physical(0), Some(5));
187 assert!(table.is_physical_used(5));
188 assert_eq!(table.num_used_blocks(), 1);
189 }
190
191 #[test]
192 fn test_block_unmapping() {
193 let mut table = DefaultBlockTable::new();
194
195 table.map_block(0, 5);
196 assert_eq!(table.get_physical(0), Some(5));
197
198 let unmapped = table.unmap_block(0);
199 assert_eq!(unmapped, Some(5));
200 assert_eq!(table.get_physical(0), None);
201 assert!(!table.is_physical_used(5));
202 assert_eq!(table.num_used_blocks(), 0);
203 }
204
205 #[test]
206 fn test_multiple_mappings() {
207 let mut table = DefaultBlockTable::new();
208
209 table.map_block(0, 10);
210 table.map_block(1, 20);
211 table.map_block(2, 30);
212
213 assert_eq!(table.get_physical(0), Some(10));
214 assert_eq!(table.get_physical(1), Some(20));
215 assert_eq!(table.get_physical(2), Some(30));
216 assert_eq!(table.num_used_blocks(), 3);
217
218 let used_blocks = table.used_physical_blocks();
219 assert!(used_blocks.contains(&10));
220 assert!(used_blocks.contains(&20));
221 assert!(used_blocks.contains(&30));
222 }
223
224 #[test]
225 fn test_table_shrink() {
226 let mut table = DefaultBlockTable::new();
227
228 table.map_block(0, 5);
229 table.map_block(1, 6);
230 table.unmap_block(1); assert!(table.logical_to_physical.len() >= 2);
233 table.shrink();
234
235 assert_eq!(table.logical_to_physical.len(), 1);
237 assert_eq!(table.get_physical(0), Some(5));
238 }
239
240 #[test]
241 fn test_table_clear() {
242 let mut table = DefaultBlockTable::new();
243
244 table.map_block(0, 5);
245 table.map_block(1, 6);
246 table.seq_len = 100;
247
248 assert!(table.num_logical_blocks() > 0);
249 assert!(table.num_physical_blocks() > 0);
250
251 table.clear();
252
253 assert_eq!(table.num_logical_blocks(), 0);
254 assert_eq!(table.num_physical_blocks(), 0);
255 assert_eq!(table.seq_len, 0);
256 }
257
258 #[test]
259 fn test_with_capacity() {
260 let table = DefaultBlockTable::with_capacity(10);
261 assert!(table.logical_to_physical.capacity() >= 10);
262 assert!(table.physical.capacity() >= 10);
263 }
264
265 #[test]
266 fn test_extend() {
267 let table = DefaultBlockTable::new();
268 let extended = table.extend(5, 10);
269
270 assert!(extended.logical_to_physical.capacity() >= 5);
271 assert!(extended.physical.capacity() >= 10);
272 }
273
274 #[test]
275 fn test_conversion() {
276 let mut default_table = DefaultBlockTable::new();
277 default_table.map_block(0, 5);
278 default_table.seq_len = 50;
279
280 let block_table: BlockTable = default_table.clone().into();
282 assert_eq!(block_table.sequence_length, 50);
283 assert_eq!(block_table.logical_to_physical[0], 5);
284
285 let back_to_default: DefaultBlockTable = block_table.into();
287 assert_eq!(back_to_default.seq_len, 50);
288 assert_eq!(back_to_default.get_physical(0), Some(5));
289 }
290}