ring_file/
buffer.rs

1use io_buffer::{safe_copy, Buffer};
2use std::fs::*;
3use std::io::{Result, Write};
4use std::path::Path;
5
6/// The content is kept in memory when written, when offset rewinds, new content will overwrite old content,
7/// So that memory consumption is limited to buf_size.
8/// Once deadlock encountered and process hangs, no more message will be written,
9/// you can safely dump the content to disk.
10///
11/// # Example:
12///
13/// ```rust
14/// use ring_file::RingBuffer;
15/// use std::io::Write;
16/// let mut file = RingBuffer::new(512*1024*1024);
17/// file.write_all(b"log message").expect("write ok");
18/// file.dump("/tmp/ringfile.store").expect("dump ok");
19/// ```
20pub struct RingBuffer {
21    end: usize,
22    full: bool,
23    inner: Buffer,
24}
25
26impl RingBuffer {
27    /// Allocate a whole buffer specified by `buf_size`, size can not exceed 2GB.
28    pub fn new(buf_size: i32) -> Self {
29        assert!(buf_size > 0);
30        let inner = Buffer::alloc(buf_size).expect("alloc");
31        Self { end: 0, inner, full: false }
32    }
33
34    /// Will create a truncated file and write all data from mem to disk.
35    pub fn dump<P: AsRef<Path>>(&self, file_path: P) -> Result<()> {
36        let mut file =
37            OpenOptions::new().write(true).create(true).truncate(true).open(file_path.as_ref())?;
38        if self.full {
39            file.write_all(&self.inner[self.end..])?;
40            return file.write_all(&self.inner[0..self.end]);
41        } else {
42            return file.write_all(&self.inner[0..self.end]);
43        }
44    }
45
46    #[inline]
47    pub fn clear(&mut self) {
48        self.end = 0;
49        self.full = false;
50    }
51}
52
53impl std::io::Write for RingBuffer {
54    /// Write will abort when reaching the boundary of buffer, rewind the offset to 0 and return the bytes written.
55    /// You can use Write::write_all() provided by the trait to cover the rewinding logic.
56    #[inline]
57    fn write(&mut self, buf: &[u8]) -> Result<usize> {
58        let bound = self.inner.capacity();
59        let l = buf.len();
60        if self.end + l >= bound {
61            self.full = true;
62            let l1 = safe_copy(&mut self.inner[self.end..], &buf);
63            self.end = 0;
64            return Ok(l1);
65        } else {
66            safe_copy(&mut self.inner[self.end..], buf);
67            self.end += l;
68            return Ok(l);
69        }
70    }
71
72    #[inline]
73    fn flush(&mut self) -> Result<()> {
74        Ok(())
75    }
76}