ranged_mmap/file/allocator/
sequential.rs

1//! Sequential range allocator implementation
2//!
3//! 顺序范围分配器实现
4
5use super::{align_up, RangeAllocator};
6use crate::file::range::AllocatedRange;
7use std::num::NonZeroU64;
8
9/// Sequential range allocator for file regions
10///
11/// 文件区域的顺序范围分配器
12///
13/// This allocator sequentially allocates non-overlapping ranges from the beginning
14/// to the end of a file. It returns [`AllocatedRange`] types, guaranteeing that all
15/// allocated ranges are valid and non-overlapping.
16///
17/// 此分配器从文件开头向结尾顺序分配不重叠的范围。
18/// 返回 [`AllocatedRange`] 类型,保证所有分配的范围都是有效且不重叠的。
19///
20/// # Example
21///
22/// ```
23/// # use ranged_mmap::allocator::{sequential::Allocator, RangeAllocator, ALIGNMENT};
24/// # use std::num::NonZeroU64;
25/// let mut allocator = Allocator::new(NonZeroU64::new(ALIGNMENT * 3).unwrap());
26///
27/// // Allocate 4K bytes (allocations are 4K aligned)
28/// // 分配 4K 字节(分配是4K对齐的)
29/// let range1 = allocator.allocate(NonZeroU64::new(ALIGNMENT).unwrap()).unwrap();
30/// assert_eq!(range1.start(), 0);
31/// assert_eq!(range1.end(), ALIGNMENT);
32///
33/// let range2 = allocator.allocate(NonZeroU64::new(ALIGNMENT).unwrap()).unwrap();
34/// assert_eq!(range2.start(), ALIGNMENT);
35/// assert_eq!(range2.end(), ALIGNMENT * 2);
36///
37/// // When remaining space is less than requested, allocate remaining space
38/// // 当剩余空间小于请求大小时,分配剩余空间
39/// let range3 = allocator.allocate(NonZeroU64::new(ALIGNMENT * 2).unwrap()).unwrap();
40/// assert_eq!(range3.start(), ALIGNMENT * 2);
41/// assert_eq!(range3.end(), ALIGNMENT * 3); // Only 4K bytes allocated
42///
43/// // Returns None when no space left
44/// // 当没有剩余空间时返回 None
45/// assert!(allocator.allocate(NonZeroU64::new(1).unwrap()).is_none());
46/// ```
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct Allocator {
49    /// Next allocation position
50    ///
51    /// 下一个分配位置
52    next_pos: u64,
53
54    /// Total file size
55    ///
56    /// 文件总大小
57    total_size: NonZeroU64,
58}
59
60impl Allocator {
61    /// Allocate a range of the specified size (4K aligned)
62    ///
63    /// 分配指定大小的范围(4K对齐)
64    ///
65    /// Allocates from the current unallocated position. The allocation size is
66    /// rounded up to 4K boundary to ensure alignment. When remaining space
67    /// is less than the aligned requested size, allocates all remaining space instead.
68    /// Returns `None` only when no space is left.
69    ///
70    /// 从当前未分配位置开始分配。分配大小会向上对齐到4K边界以确保对齐。
71    /// 当剩余空间小于对齐后的请求大小时,分配所有剩余空间。
72    /// 仅当没有剩余空间时返回 `None`。
73    ///
74    /// # Note
75    /// The actual allocated size may be larger than requested due to 4K alignment.
76    /// For example, requesting 100 bytes will allocate 4096 bytes.
77    ///
78    /// # 注意
79    /// 由于4K对齐,实际分配的大小可能大于请求的大小。
80    /// 例如,请求100字节将分配4096字节。
81    #[inline]
82    pub fn allocate(&mut self, size: NonZeroU64) -> Option<AllocatedRange> {
83        let remaining = self.total_size.get().saturating_sub(self.next_pos);
84        if remaining == 0 {
85            return None;
86        }
87
88        let start = self.next_pos;
89        // Align the requested size up to 4K boundary
90        // 将请求大小向上对齐到4K边界
91        let aligned_size = align_up(size.get());
92        // Allocate min(aligned_requested, remaining)
93        let actual_size = aligned_size.min(remaining);
94        let end = start + actual_size;
95        self.next_pos = end;
96
97        Some(AllocatedRange::from_range_unchecked(start, end))
98    }
99
100    /// Get the number of remaining allocatable bytes
101    ///
102    /// 获取剩余可分配字节数
103    #[inline]
104    pub fn remaining(&self) -> u64 {
105        self.total_size.get().saturating_sub(self.next_pos)
106    }
107
108    /// Get the next allocation position
109    ///
110    /// 获取下一个分配位置
111    #[inline]
112    pub fn next_pos(&self) -> u64 {
113        self.next_pos
114    }
115}
116
117impl RangeAllocator for Allocator {
118    #[inline]
119    fn new(total_size: NonZeroU64) -> Self {
120        Self {
121            next_pos: 0,
122            total_size,
123        }
124    }
125
126    #[inline]
127    fn total_size(&self) -> NonZeroU64 {
128        self.total_size
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use crate::allocator::ALIGNMENT;
135    use super::*;
136
137    fn non_zero(val: u64) -> NonZeroU64 {
138        NonZeroU64::new(val).unwrap()
139    }
140
141    #[test]
142    fn test_sequential_basic_allocation() {
143        // Use 4K aligned total size
144        let mut allocator = Allocator::new(non_zero(ALIGNMENT * 10)); // 40960 bytes
145
146        // Request 100 bytes, should get 4096 (aligned up)
147        let range1 = allocator.allocate(non_zero(100)).unwrap();
148        assert_eq!(range1.start(), 0);
149        assert_eq!(range1.end(), ALIGNMENT); // 4096
150        assert_eq!(range1.len(), ALIGNMENT);
151    }
152
153    #[test]
154    fn test_sequential_multiple_allocations() {
155        let mut allocator = Allocator::new(non_zero(ALIGNMENT * 10)); // 40960 bytes
156
157        // First allocation: 100 -> 4096
158        let range1 = allocator.allocate(non_zero(100)).unwrap();
159        assert_eq!(range1.start(), 0);
160        assert_eq!(range1.end(), ALIGNMENT);
161
162        // Second allocation: 150 -> 4096
163        let range2 = allocator.allocate(non_zero(150)).unwrap();
164        assert_eq!(range2.start(), ALIGNMENT);
165        assert_eq!(range2.end(), ALIGNMENT * 2);
166
167        // Third allocation: 200 -> 4096
168        let range3 = allocator.allocate(non_zero(200)).unwrap();
169        assert_eq!(range3.start(), ALIGNMENT * 2);
170        assert_eq!(range3.end(), ALIGNMENT * 3);
171    }
172
173    #[test]
174    fn test_sequential_exact_alignment() {
175        let mut allocator = Allocator::new(non_zero(ALIGNMENT * 10));
176
177        // Request exactly 4096, should get 4096
178        let range = allocator.allocate(non_zero(ALIGNMENT)).unwrap();
179        assert_eq!(range.start(), 0);
180        assert_eq!(range.end(), ALIGNMENT);
181        assert_eq!(range.len(), ALIGNMENT);
182
183        // Request 4097, should get 8192 (aligned up)
184        let range2 = allocator.allocate(non_zero(ALIGNMENT + 1)).unwrap();
185        assert_eq!(range2.start(), ALIGNMENT);
186        assert_eq!(range2.end(), ALIGNMENT * 3);
187        assert_eq!(range2.len(), ALIGNMENT * 2);
188    }
189
190    #[test]
191    fn test_sequential_partial_allocation() {
192        // Total size: 3 * 4096 = 12288
193        let mut allocator = Allocator::new(non_zero(ALIGNMENT * 3));
194
195        // First allocate 2 * 4096 = 8192
196        allocator.allocate(non_zero(ALIGNMENT)).unwrap(); // 4096
197        allocator.allocate(non_zero(ALIGNMENT)).unwrap(); // 4096
198
199        // Request more than remaining (request 8192, only 4096 left)
200        let range = allocator.allocate(non_zero(ALIGNMENT * 2)).unwrap();
201        assert_eq!(range.start(), ALIGNMENT * 2);
202        assert_eq!(range.end(), ALIGNMENT * 3);
203        assert_eq!(range.len(), ALIGNMENT);
204    }
205
206    #[test]
207    fn test_sequential_exhausted() {
208        let mut allocator = Allocator::new(non_zero(ALIGNMENT));
209
210        // Exhaust all space
211        let range = allocator.allocate(non_zero(100)).unwrap();
212        assert_eq!(range.len(), ALIGNMENT);
213
214        // No more space
215        assert!(allocator.allocate(non_zero(1)).is_none());
216    }
217
218    #[test]
219    fn test_sequential_remaining() {
220        let mut allocator = Allocator::new(non_zero(ALIGNMENT * 3)); // 12288
221
222        assert_eq!(allocator.remaining(), ALIGNMENT * 3);
223        allocator.allocate(non_zero(100)).unwrap(); // allocates 4096
224        assert_eq!(allocator.remaining(), ALIGNMENT * 2);
225        allocator.allocate(non_zero(ALIGNMENT * 2)).unwrap(); // allocates remaining
226        assert_eq!(allocator.remaining(), 0);
227    }
228
229    #[test]
230    fn test_sequential_next_pos() {
231        let mut allocator = Allocator::new(non_zero(ALIGNMENT * 10));
232
233        assert_eq!(allocator.next_pos(), 0);
234        allocator.allocate(non_zero(100)).unwrap(); // 100 -> 4096
235        assert_eq!(allocator.next_pos(), ALIGNMENT);
236        allocator.allocate(non_zero(250)).unwrap(); // 250 -> 4096
237        assert_eq!(allocator.next_pos(), ALIGNMENT * 2);
238    }
239
240    #[test]
241    fn test_sequential_total_size() {
242        let allocator = Allocator::new(non_zero(12345));
243        assert_eq!(allocator.total_size().get(), 12345);
244    }
245}