1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
use memmap::{MmapMut, MmapOptions}; use std::marker::PhantomData; use std::mem::size_of; use std::sync::atomic::{AtomicUsize, Ordering}; quick_error! { #[derive(Debug)] pub enum LogError { FSError(err: agilulf_fs::FSError) { from() } IOError(err: std::io::Error) { from() } } } pub type Result<T> = std::result::Result<T, LogError>; pub trait JudgeReal { fn is_real(&self) -> bool; fn set_real(&mut self, real: bool); } pub struct LogIterator<'a, T> { inner_mmap: &'a MmapMut, index: usize, phantom: PhantomData<T>, } impl<'a, T: Clone + JudgeReal> Iterator for LogIterator<'a, T> { type Item = T; fn next(&mut self) -> Option<Self::Item> { let record = self.inner_mmap[(self.index * size_of::<T>())..].as_ref() as *const [u8] as *mut T; unsafe { if (*record).is_real() { self.index += 1; return Some((*record).clone()); } else { return None; } } } } pub struct LogManager<T: JudgeReal + Clone> { inner_mmap: MmapMut, index: AtomicUsize, phantom: PhantomData<T>, path: String, } impl<T: JudgeReal + Clone> LogManager<T> { pub fn create_new(path: &str, length: usize) -> Result<LogManager<T>> { std::fs::OpenOptions::new() .create(true) .write(true) .truncate(true) .open(path)?; LogManager::open(path, length) } pub fn open(path: &str, length: usize) -> Result<LogManager<T>> { log::info!("Opening log from {:#?}", path); { let file = agilulf_fs::File::open(path)?; file.fallocate(0, (size_of::<T>() * length) as i64)?; } let file = std::fs::OpenOptions::new() .read(true) .write(true) .create(true) .open(path)?; let mmap = unsafe { MmapOptions::new().map_mut(&file)? }; let records = mmap.as_ref() as *const [u8] as *mut [T]; let mut index = 0; unsafe { let records = &(*records); loop { if records[index].is_real() { index += 1; } else { break; } } } Ok(Self { inner_mmap: mmap, index: AtomicUsize::new(index), phantom: PhantomData, path: path.to_string(), }) } pub fn iter(&self) -> LogIterator<T> { LogIterator { inner_mmap: &self.inner_mmap, index: 0, phantom: PhantomData, } } pub fn add_entry(&self, data: T) { let index = self.index.fetch_add(1, Ordering::SeqCst); unsafe { let record = self.inner_mmap[(index * size_of::<T>())..].as_ref() as *const [u8] as *mut T; (*record).clone_from(&data); } } pub fn rename(&self, new_path: &str) -> Result<()> { std::fs::rename(self.path.as_str(), new_path)?; Ok(()) } }