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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
//!File backed memory mapped storage
extern crate memmap;

use std::fs;
use std::path;
use std::io;

/// File memory map backed storage.
///
/// Attempting to resize storage results in error.
pub struct Storage {
    //In order to use regular file APIs
    //we need to drop MmapMut
    //As Rust would not let us move out
    //of &mut we need to wrap it into Option :(
    inner: Option<memmap::MmapMut>,
    file: fs::File,
    //Cursor with end
    end: usize,
    //Total size of storage
    size: usize,
}

impl Storage {
    fn inner_open(file: fs::File) -> io::Result<Self> {
        let metadata = file.metadata()?;
        let mut size = metadata.len() as usize;
        let end = size;
        if size == 0 {
            file.set_len(1)?;
            size = 1;
        }
        let mut result = Self {
            inner: None,
            file,
            end,
            size
        };

        result.mmap().map(move |_| result)
    }

    /// Creates storage by opening or creating file at the specified location.
    ///
    /// If file is newly created it is appended dummy byte.
    pub fn open<P: AsRef<path::Path>>(path: P) -> io::Result<Self> {
        let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path)?;
        Self::inner_open(file)
    }

    /// Opens storage, if it doesn't exist return error.
    pub fn open_exising<P: AsRef<path::Path>>(path: P) -> io::Result<Self> {
        let file = fs::OpenOptions::new().read(true).write(true).open(&path)?;
        Self::inner_open(file)
    }

    fn as_inner<'a>(&'a self) -> &'a memmap::MmapMut {
        match self.inner.as_ref() {
            Some(inner) => inner,
            None => unreachable!()
        }
    }

    fn as_inner_mut<'a>(&'a mut self) -> &'a mut memmap::MmapMut {
        match self.inner.as_mut() {
            Some(inner) => inner,
            None => unreachable!()
        }
    }

    fn manual_drop(&mut self) {
        self.inner.take();
    }

    fn mmap(&mut self) -> io::Result<()> {
        self.inner = unsafe {
            Some(memmap::MmapMut::map_mut(&self.file)?)
        };

        Ok(())
    }

    fn set_len(&mut self, new_size: usize) -> io::Result<()> {
        self.file.set_len(new_size as u64)?;
        self.size = new_size;
        Ok(())
    }

    #[inline]
    /// Returns slice with view on written data.
    pub fn as_slice(&self) -> &[u8] {
        &self.as_inner()[..self.end]
    }

    #[inline]
    /// Returns slice with view on written data.
    pub fn as_mut_slice(&mut self) -> &mut [u8] {
        let end = self.end;
        &mut self.as_inner_mut()[..end]
    }

    #[inline]
    /// Returns overall size of storage(including extra space).
    pub fn capacity(&self) -> usize {
        self.size
    }

    #[inline]
    /// Asynchronously flushes outstanding memory map modifications to disk.
    ///
    /// This method initiates flushing modified pages to durable storage, but it will not wait for
    /// the operation to complete before returning.
    pub fn flush_async(&self) -> io::Result<()> {
        self.as_inner().flush_async()
    }

    #[inline]
    /// Synchronously flushes outstanding memory map modifications to disk.
    pub fn flush_sync(&self) -> io::Result<()> {
        self.as_inner().flush()
    }

    /// Resizes storage by appending or truncating.
    ///
    /// It modifies file size and re-mmaps file.
    pub fn resize(&mut self, new_size: usize) -> io::Result<()> {
        self.manual_drop();
        match self.set_len(new_size) {
            Ok(_) => (),
            Err(error) => {
                //In case of error we must restore original
                //mmap otherwise we gonna use uninitialized
                //value
                self.mmap()?;
                return Err(error);
            }
        }
        self.mmap()
    }

    ///Resizes map accordingly to data and copies it.
    ///
    ///Convenience method to map buffer to file.
    pub fn put_data(&mut self, data: &[u8]) -> io::Result<()> {
        assert!(data.len() > 0);
        if self.size != data.len() {
            self.resize(data.len())?;
        }
        let size = self.size;
        self.as_inner_mut()[..size].copy_from_slice(data);
        self.end = self.size;
        Ok(())
    }

    /// Appends data to storage
    ///
    /// Note that it resizes storage if needed.
    /// Therefore error can happen.
    pub fn extend_from_slice(&mut self, data: &[u8]) -> io::Result<()> {
        if (self.size - self.end) < data.len() {
            let new_size = self.end + data.len();
            self.resize(new_size)?;
        }
        let end = self.end;
        self.as_inner_mut()[end..end+data.len()].copy_from_slice(data);
        self.end += data.len();
        Ok(())
    }

    /// Copies data from slice into storage.
    ///
    /// Function panics if data has greater len.
    ///
    /// **Note:** It copies data up to storage capacity.
    pub fn copy_from_slice(&mut self, data: &[u8]) {
        assert!(self.size >= data.len());
        self.end = data.len();
        self.as_mut_slice().copy_from_slice(data);
    }

    /// Creates `Vec` from content of storage.
    pub fn to_vec(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(self.end);
        result.extend_from_slice(self.as_slice());
        result
    }
}

impl io::Write for Storage {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.extend_from_slice(buf)?;
        Ok(buf.len())
    }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.extend_from_slice(buf)
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.as_inner().flush()
    }
}