use super::error::{Error, Result};
use crate::vault::Init;
use bincode;
use std::{
cell::Cell,
fs::{File, OpenOptions},
io::{Read, Seek, SeekFrom},
path::Path,
rc::Rc,
};
const USED_SPACE_FILENAME: &str = "used_space";
#[derive(Debug)]
pub(super) struct UsedSpace {
total_value: Rc<Cell<u64>>,
local_value: u64,
local_record: File,
}
impl UsedSpace {
pub fn new<T: AsRef<Path>>(
dir: T,
total_used_space: Rc<Cell<u64>>,
init_mode: Init,
) -> Result<Self> {
let mut local_record = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(dir.as_ref().join(USED_SPACE_FILENAME))?;
let local_value = if init_mode == Init::Load {
let mut buffer = vec![];
let _ = local_record.read_to_end(&mut buffer)?;
bincode::deserialize::<u64>(&buffer)?
} else {
bincode::serialize_into(&mut local_record, &0_u64)?;
0
};
Ok(Self {
total_value: total_used_space,
local_value,
local_record,
})
}
pub fn total(&self) -> u64 {
self.total_value.get()
}
pub fn increase(&mut self, consumed: u64) -> Result<()> {
let new_total = self
.total_value
.get()
.checked_add(consumed)
.ok_or(Error::NotEnoughSpace)?;
let new_local = self
.local_value
.checked_add(consumed)
.ok_or(Error::NotEnoughSpace)?;
self.record_new_values(new_total, new_local)
}
pub fn decrease(&mut self, released: u64) -> Result<()> {
let new_total = self.total_value.get().saturating_sub(released);
let new_local = self.local_value.saturating_sub(released);
self.record_new_values(new_total, new_local)
}
fn record_new_values(&mut self, total: u64, local: u64) -> Result<()> {
self.local_record.set_len(0)?;
let _ = self.local_record.seek(SeekFrom::Start(0))?;
bincode::serialize_into(&self.local_record, &local)?;
self.total_value.set(total);
self.local_value = local;
Ok(())
}
}