various_data_file/
fragment.rs

1use std::{mem::size_of, num::NonZeroU64, path::Path};
2
3use file_mmap::FileMmap;
4
5use crate::DataAddress;
6
7pub(super) struct FragmentGetResult {
8    pub(super) fragment_id: NonZeroU64,
9    pub(super) addr: u64,
10}
11
12pub(super) struct Fragment {
13    filemmap: FileMmap,
14}
15
16const DATAADDRESS_SIZE: u64 = size_of::<DataAddress>() as u64;
17const COUNTER_SIZE: u64 = size_of::<u64>() as u64;
18const INIT_SIZE: u64 = COUNTER_SIZE + DATAADDRESS_SIZE;
19
20impl Fragment {
21    pub fn new<P: AsRef<Path>>(path: P) -> Self {
22        let mut filemmap = FileMmap::new(path).unwrap();
23        if filemmap.len() == 0 {
24            filemmap.set_len(INIT_SIZE).unwrap();
25        }
26        Self { filemmap }
27    }
28
29    unsafe fn list(&self) -> *const DataAddress {
30        self.filemmap.as_ptr().offset(COUNTER_SIZE as isize) as *const DataAddress
31    }
32
33    unsafe fn list_mut(&mut self) -> *mut DataAddress {
34        self.filemmap.as_ptr().offset(COUNTER_SIZE as isize) as *mut DataAddress
35    }
36
37    pub fn insert(&mut self, addr: DataAddress) {
38        let record_count = self.filemmap.as_ptr() as *mut u64;
39        let record_count = unsafe {
40            *record_count += 1;
41            *record_count
42        };
43        let size = INIT_SIZE + DATAADDRESS_SIZE * record_count;
44        if self.filemmap.len() < size {
45            self.filemmap.set_len(size).unwrap();
46        }
47        unsafe {
48            *self.list_mut().offset(record_count as isize) = addr;
49        }
50    }
51
52    pub unsafe fn release(&mut self, row: NonZeroU64, len: usize) {
53        let row = row.get() as u64;
54        let s = &mut *self.list_mut().offset(row as isize);
55        s.offset += len as i64;
56        s.len -= len as u64;
57
58        let record_count = self.filemmap.as_ptr() as *mut u64;
59        if s.len == 0 && row == *record_count {
60            *record_count -= 1;
61        }
62    }
63
64    pub fn search_blank(&self, len: usize) -> Option<FragmentGetResult> {
65        let record_count = unsafe { *(self.filemmap.as_ptr() as *const u64) };
66        if record_count != 0 {
67            for index in (-(record_count as isize)..0).map(|i| -i) {
68                let s = unsafe { &*self.list().offset(index) };
69                if s.len as usize >= len {
70                    return Some(FragmentGetResult {
71                        fragment_id: unsafe { NonZeroU64::new_unchecked(index as u64) },
72                        addr: s.offset as u64,
73                    });
74                }
75            }
76        }
77        None
78    }
79}