Files
daqbuffer/commonio/src/ringbuf.rs
2021-12-17 18:24:44 +01:00

155 lines
3.9 KiB
Rust

use crate::{read, seek, StatsChannel};
use err::Error;
use netpod::log::*;
use std::fmt;
use std::{borrow::BorrowMut, io::SeekFrom};
use tokio::fs::File;
pub struct RingBuf<F> {
file: Option<F>,
buf: Vec<u8>,
abs: usize,
wp: usize,
rp: usize,
stats: StatsChannel,
seek_request: u64,
seek_done: u64,
read_done: u64,
small_pos: u64,
small_neg: u64,
bytes_read: u64,
}
impl<F> RingBuf<F>
where
F: BorrowMut<File>,
{
pub async fn new(file: F, pos: u64, stats: StatsChannel) -> Result<Self, Error> {
let mut ret = Self {
file: Some(file),
buf: vec![0; 1024 * 1024],
abs: usize::MAX,
wp: 0,
rp: 0,
stats,
seek_request: 0,
seek_done: 0,
read_done: 0,
small_pos: 0,
small_neg: 0,
bytes_read: 0,
};
ret.seek(pos).await?;
Ok(ret)
}
pub fn into_file(mut self) -> F {
self.file.take().unwrap()
}
pub fn len(&self) -> usize {
self.wp - self.rp
}
pub fn adv(&mut self, n: usize) {
self.rp += n;
}
pub fn data(&self) -> &[u8] {
&self.buf[self.rp..self.wp]
}
async fn fill(&mut self) -> Result<usize, Error> {
if self.rp == self.wp {
if self.rp != 0 {
self.wp = 0;
self.rp = 0;
}
} else {
unsafe {
std::ptr::copy::<u8>(&self.buf[self.rp], &mut self.buf[0], self.len());
self.wp -= self.rp;
self.rp = 0;
}
}
let max = (self.buf.len() - self.wp).min(1024 * 8) + self.wp;
let n = read(
self.file.as_mut().unwrap().borrow_mut(),
&mut self.buf[self.wp..max],
&self.stats,
)
.await?;
self.wp += n;
self.read_done += 1;
self.bytes_read += n as u64;
Ok(n)
}
pub async fn fill_min(&mut self, min: usize) -> Result<usize, Error> {
let len = self.len();
while self.len() < min {
let n = self.fill().await?;
if n == 0 {
return Err(Error::with_msg(format!("fill_min can not read min {}", min)));
}
}
Ok(self.len() - len)
}
pub async fn seek(&mut self, pos: u64) -> Result<u64, Error> {
let dp = pos as i64 - self.rp_abs() as i64;
if dp < 0 && dp > -2048 {
debug!("small NEG seek {}", dp);
} else if dp == 0 {
// TODO check callsites, some cases could be eliminated.
//debug!("zero seek");
return Ok(pos);
} else if dp > 0 && dp < 2048 {
debug!("small POS seek {}", dp);
}
self.abs = pos as usize;
self.rp = 0;
self.wp = 0;
let ret = seek(
self.file.as_mut().unwrap().borrow_mut(),
SeekFrom::Start(pos),
&self.stats,
)
.await
.map_err(|e| Error::from(e))?;
self.seek_request += 1;
self.seek_done += 1;
Ok(ret)
}
pub fn rp_abs(&self) -> u64 {
self.abs as u64 + self.rp as u64
}
pub fn bytes_read(&self) -> u64 {
self.bytes_read
}
}
impl<F> fmt::Debug for RingBuf<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RingBuf")
.field("abs", &self.abs)
.field("wp", &self.wp)
.field("rp", &self.rp)
.field("seek_request", &self.seek_request)
.field("seek_done", &self.seek_done)
.field("read_done", &self.read_done)
.field("small_pos", &self.small_pos)
.field("small_neg", &self.small_neg)
.field("bytes_read", &self.bytes_read)
.finish()
}
}
impl<F> Drop for RingBuf<F> {
fn drop(&mut self) {
trace!("Drop {:?}", self);
}
}