use std::sync::{Arc, RwLock};
use foyer_common::error::{Error, Result};
use crate::io::device::{statistics::Statistics, Device, DeviceBuilder, Partition, PartitionId};
#[derive(Debug)]
pub struct PartialDeviceBuilder {
device: Arc<dyn Device>,
capacity: usize,
}
impl PartialDeviceBuilder {
pub fn new(device: Arc<dyn Device>) -> Self {
let capacity = device.capacity();
Self { device, capacity }
}
pub fn with_capacity(mut self, capacity: usize) -> Self {
assert!(capacity <= self.device.capacity());
self.capacity = capacity;
self
}
}
impl DeviceBuilder for PartialDeviceBuilder {
fn build(self) -> Result<Arc<dyn Device>> {
Ok(Arc::new(PartialDevice {
inner: self.device,
capacity: self.capacity,
partitions: RwLock::new(vec![]),
}))
}
}
#[derive(Debug)]
pub struct PartialDevice {
inner: Arc<dyn Device>,
capacity: usize,
partitions: RwLock<Vec<Arc<PartialPartition>>>,
}
impl Device for PartialDevice {
fn capacity(&self) -> usize {
self.capacity
}
fn allocated(&self) -> usize {
self.partitions.read().unwrap().iter().map(|p| p.size()).sum()
}
fn create_partition(&self, size: usize) -> Result<Arc<dyn Partition>> {
let mut partitions = self.partitions.write().unwrap();
let allocated = partitions.iter().map(|p| p.size()).sum::<usize>();
if allocated + size > self.capacity {
return Err(Error::no_space(self.capacity, allocated, allocated + size));
}
self.inner.create_partition(size).map(|inner| {
let partition = PartialPartition {
inner,
id: partitions.len() as PartitionId,
};
let partition = Arc::new(partition);
partitions.push(partition.clone());
partition as Arc<dyn Partition>
})
}
fn partitions(&self) -> usize {
self.partitions.read().unwrap().len()
}
fn partition(&self, id: PartitionId) -> Arc<dyn Partition> {
self.partitions.read().unwrap()[id as usize].clone()
}
fn statistics(&self) -> &Arc<Statistics> {
self.inner.statistics()
}
}
#[derive(Debug)]
pub struct PartialPartition {
inner: Arc<dyn Partition>,
id: PartitionId,
}
impl Partition for PartialPartition {
fn id(&self) -> PartitionId {
self.id
}
fn size(&self) -> usize {
self.inner.size()
}
fn translate(&self, address: u64) -> (super::RawFile, u64) {
self.inner.translate(address)
}
fn statistics(&self) -> &Arc<Statistics> {
self.inner.statistics()
}
}