Files
agilulf
agilulf_driver
agilulf_fs
agilulf_protocol
agilulf_server
agilulf_skiplist
  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(())
    }
}