use crate::{buf::WriteBuffer, wmap::DataSlice, wmap::WMap, Arc, Data, Limits, Storage};
pub struct BasicAtomicFile {
stg: WriteBuffer,
upd: WriteBuffer,
pub map: WMap,
list: Vec<(u64, DataSlice)>,
size: u64,
}
impl BasicAtomicFile {
pub fn new(stg: Box<dyn Storage>, upd: Box<dyn Storage>, lim: &Limits) -> Box<Self> {
let size = stg.size();
let mut result = Box::new(Self {
stg: WriteBuffer::new(stg, lim.swbuf),
upd: WriteBuffer::new(upd, lim.uwbuf),
map: WMap::default(),
list: Vec::new(),
size,
});
result.init();
result
}
fn init(&mut self) {
let end = self.upd.stg.read_u64(0);
let size = self.upd.stg.read_u64(8);
if end == 0 {
return;
}
assert!(end == self.upd.stg.size());
let mut pos = 16;
while pos < end {
let start = self.upd.stg.read_u64(pos);
pos += 8;
let len = self.upd.stg.read_u64(pos);
pos += 8;
let mut buf = vec![0; len as usize];
self.upd.stg.read(pos, &mut buf);
pos += len;
self.stg.write(start, &buf);
}
self.stg.commit(size);
self.upd.commit(0);
}
pub fn commit_phase(&mut self, size: u64, phase: u8) {
if self.map.map.is_empty() && self.list.is_empty() {
return;
}
if phase == 1 {
for (k, v) in std::mem::take(&mut self.map.map) {
let start = k + 1 - v.len as u64;
self.list.push((start, v));
}
self.upd.write_u64(0, 0);
self.upd.write_u64(8, size);
self.upd.commit(16); let mut stg_written = false;
let mut pos: u64 = 16;
for (start, v) in self.list.iter() {
let (start, len, data) = (*start, v.len as u64, v.data());
if start >= self.size {
stg_written = true;
self.stg.write(start, data);
} else {
self.upd.write_u64(pos, start);
pos += 8;
self.upd.write_u64(pos, len);
pos += 8;
self.upd.write(pos, data);
pos += len;
}
}
if stg_written {
self.stg.commit(size);
}
self.upd.commit(pos); self.upd.write_u64(0, pos);
self.upd.write_u64(8, size);
self.upd.commit(pos);
} else {
for (start, v) in self.list.iter() {
let start = *start;
if start < self.size {
self.stg.write(start, v.data());
}
}
self.list.clear();
self.stg.commit(size);
self.upd.commit(0);
}
}
}
impl Storage for BasicAtomicFile {
fn commit(&mut self, size: u64) {
self.commit_phase(size, 1);
self.commit_phase(size, 2);
self.size = size;
}
fn size(&self) -> u64 {
self.size
}
fn read(&self, start: u64, data: &mut [u8]) {
self.map.read(start, data, &*self.stg.stg);
}
fn write_data(&mut self, start: u64, data: Data, off: usize, len: usize) {
self.map.write(start, data, off, len);
}
fn write(&mut self, start: u64, data: &[u8]) {
let len = data.len();
let d = Arc::new(data.to_vec());
self.write_data(start, d, 0, len);
}
}