doublecrypt_core/
allocator.rs1use crate::error::{FsError, FsResult};
2use crate::model::FIRST_DATA_BLOCK;
3use std::collections::BTreeSet;
4use std::sync::Mutex;
5
6pub trait SlotAllocator: Send + Sync {
8 fn allocate(&self) -> FsResult<u64>;
10
11 fn free(&self, block_id: u64) -> FsResult<()>;
13
14 fn is_allocated(&self, block_id: u64) -> bool;
16}
17
18pub struct BitmapAllocator {
20 total_blocks: u64,
21 state: Mutex<AllocatorState>,
22}
23
24struct AllocatorState {
25 free_set: BTreeSet<u64>,
27 allocated: BTreeSet<u64>,
29}
30
31impl BitmapAllocator {
32 pub fn new(total_blocks: u64) -> Self {
35 let mut free_set = BTreeSet::new();
36 for id in FIRST_DATA_BLOCK..total_blocks {
37 free_set.insert(id);
38 }
39 Self {
40 total_blocks,
41 state: Mutex::new(AllocatorState {
42 free_set,
43 allocated: BTreeSet::new(),
44 }),
45 }
46 }
47
48 pub fn mark_allocated(&self, block_id: u64) -> FsResult<()> {
50 let mut state = self.state.lock().map_err(|e| FsError::Internal(e.to_string()))?;
51 state.free_set.remove(&block_id);
52 state.allocated.insert(block_id);
53 Ok(())
54 }
55
56 pub fn free_count(&self) -> u64 {
58 let state = self.state.lock().unwrap();
59 state.free_set.len() as u64
60 }
61
62 pub fn free_block_ids(&self) -> Vec<u64> {
64 let state = self.state.lock().unwrap();
65 state.free_set.iter().copied().collect()
66 }
67}
68
69impl SlotAllocator for BitmapAllocator {
70 fn allocate(&self) -> FsResult<u64> {
71 let mut state = self.state.lock().map_err(|e| FsError::Internal(e.to_string()))?;
72 let block_id = *state.free_set.iter().next().ok_or(FsError::NoFreeBlocks)?;
73 state.free_set.remove(&block_id);
74 state.allocated.insert(block_id);
75 Ok(block_id)
76 }
77
78 fn free(&self, block_id: u64) -> FsResult<()> {
79 if block_id >= self.total_blocks || block_id < FIRST_DATA_BLOCK {
80 return Err(FsError::BlockOutOfRange(block_id));
81 }
82 let mut state = self.state.lock().map_err(|e| FsError::Internal(e.to_string()))?;
83 state.allocated.remove(&block_id);
84 state.free_set.insert(block_id);
85 Ok(())
86 }
87
88 fn is_allocated(&self, block_id: u64) -> bool {
89 let state = self.state.lock().unwrap();
90 state.allocated.contains(&block_id)
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_allocate_and_free() {
100 let alloc = BitmapAllocator::new(10);
101 let id = alloc.allocate().unwrap();
102 assert!(id >= FIRST_DATA_BLOCK);
103 assert!(alloc.is_allocated(id));
104 alloc.free(id).unwrap();
105 assert!(!alloc.is_allocated(id));
106 }
107
108 #[test]
109 fn test_exhaustion() {
110 let alloc = BitmapAllocator::new(4);
112 let _id = alloc.allocate().unwrap();
113 assert!(alloc.allocate().is_err());
114 }
115}