use anyhow::{anyhow, Result}; use std::collections::BTreeSet; use std::sync::{Arc, Mutex}; use crate::checksum; use crate::io_engine::*; use crate::pdata::space_map::*; //------------------------------------------ #[derive(Clone)] pub struct WriteBatcher { pub engine: Arc, // FIXME: this doesn't need to be in a mutex pub sm: Arc>, batch_size: usize, queue: Vec, allocations: BTreeSet, } impl WriteBatcher { pub fn new( engine: Arc, sm: Arc>, batch_size: usize, ) -> WriteBatcher { WriteBatcher { engine, sm, batch_size, queue: Vec::with_capacity(batch_size), allocations: BTreeSet::new(), } } pub fn alloc(&mut self) -> Result { let mut sm = self.sm.lock().unwrap(); let b = sm.alloc()?; if b.is_none() { return Err(anyhow!("out of metadata space")); } self.allocations.insert(b.unwrap()); Ok(Block::new(b.unwrap())) } pub fn alloc_zeroed(&mut self) -> Result { let mut sm = self.sm.lock().unwrap(); let b = sm.alloc()?; if b.is_none() { return Err(anyhow!("out of metadata space")); } self.allocations.insert(b.unwrap()); Ok(Block::zeroed(b.unwrap())) } pub fn clear_allocations(&mut self) -> BTreeSet { let mut tmp = BTreeSet::new(); std::mem::swap(&mut tmp, &mut self.allocations); tmp } pub fn write(&mut self, b: Block, kind: checksum::BT) -> Result<()> { checksum::write_checksum(&mut b.get_data(), kind)?; if self.queue.len() == self.batch_size { let mut tmp = Vec::new(); std::mem::swap(&mut tmp, &mut self.queue); self.flush_(tmp)?; } self.queue.push(b); Ok(()) } pub fn read(&mut self, blocknr: u64) -> Result { for b in self.queue.iter().rev() { if b.loc == blocknr { let r = Block::new(b.loc); r.get_data().copy_from_slice(b.get_data()); return Ok(r); } } self.engine .read(blocknr) .map_err(|_| anyhow!("read block error")) } pub fn flush_(&mut self, queue: Vec) -> Result<()> { self.engine.write_many(&queue)?; Ok(()) } pub fn flush(&mut self) -> Result<()> { let mut tmp = Vec::new(); std::mem::swap(&mut tmp, &mut self.queue); self.flush_(tmp)?; Ok(()) } } //------------------------------------------