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
47impl std::io::Write for RingBuffer {
48 /// Write will abort when reaching the boundary of buffer, rewind the offset to 0 and return the bytes written.
49 /// You can use Write::write_all() provided by the trait to cover the rewinding logic.
50 #[inline]
51 fn write(&mut self, buf: &[u8]) -> Result<usize> {
52 let bound = self.inner.capacity();
53 let l = buf.len();
54 if self.end + l >= bound {
55 self.full = true;
56 let l1 = safe_copy(&mut self.inner[self.end..], &buf);
57 self.end = 0;
58 return Ok(l1);
59 } else {
60 safe_copy(&mut self.inner[self.end..], buf);
61 self.end += l;
62 return Ok(l);
63 }
64 }
65
66 #[inline]
67 fn flush(&mut self) -> Result<()> {
68 Ok(())
69 }
70}