foyer_storage/io/device/
partial.rs

1// Copyright 2026 foyer Project Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::sync::{Arc, RwLock};
16
17use foyer_common::error::{Error, Result};
18
19use crate::io::device::{statistics::Statistics, Device, DeviceBuilder, Partition, PartitionId};
20
21/// Builder for a partial device that wraps another device and allows access to only a subset of capacity.
22#[derive(Debug)]
23pub struct PartialDeviceBuilder {
24    device: Arc<dyn Device>,
25    capacity: usize,
26}
27
28impl PartialDeviceBuilder {
29    /// Create a new partial device builder with the specified device.
30    pub fn new(device: Arc<dyn Device>) -> Self {
31        let capacity = device.capacity();
32        Self { device, capacity }
33    }
34
35    /// Set the capacity of the partial device.
36    ///
37    /// NOTE:
38    /// - The capacity must be less than or equal to the inner device's capacity.
39    /// - The sum of all capacities of the inner device's partial devices must be less than or equal to the inner
40    ///   device's capacity.
41    pub fn with_capacity(mut self, capacity: usize) -> Self {
42        assert!(capacity <= self.device.capacity());
43        self.capacity = capacity;
44        self
45    }
46}
47
48impl DeviceBuilder for PartialDeviceBuilder {
49    fn build(self) -> Result<Arc<dyn Device>> {
50        Ok(Arc::new(PartialDevice {
51            inner: self.device,
52            capacity: self.capacity,
53            partitions: RwLock::new(vec![]),
54        }))
55    }
56}
57
58/// [`PartialDevice`] is a wrapper for other device to use only a part of it.
59#[derive(Debug)]
60pub struct PartialDevice {
61    inner: Arc<dyn Device>,
62    capacity: usize,
63    partitions: RwLock<Vec<Arc<PartialPartition>>>,
64}
65
66impl Device for PartialDevice {
67    fn capacity(&self) -> usize {
68        self.capacity
69    }
70
71    fn allocated(&self) -> usize {
72        self.partitions.read().unwrap().iter().map(|p| p.size()).sum()
73    }
74
75    fn create_partition(&self, size: usize) -> Result<Arc<dyn Partition>> {
76        let mut partitions = self.partitions.write().unwrap();
77        let allocated = partitions.iter().map(|p| p.size()).sum::<usize>();
78        if allocated + size > self.capacity {
79            return Err(Error::no_space(self.capacity, allocated, allocated + size));
80        }
81        self.inner.create_partition(size).map(|inner| {
82            let partition = PartialPartition {
83                inner,
84                id: partitions.len() as PartitionId,
85            };
86            let partition = Arc::new(partition);
87            partitions.push(partition.clone());
88            partition as Arc<dyn Partition>
89        })
90    }
91
92    fn partitions(&self) -> usize {
93        self.partitions.read().unwrap().len()
94    }
95
96    fn partition(&self, id: PartitionId) -> Arc<dyn Partition> {
97        self.partitions.read().unwrap()[id as usize].clone()
98    }
99
100    fn statistics(&self) -> &Arc<Statistics> {
101        self.inner.statistics()
102    }
103}
104
105#[derive(Debug)]
106pub struct PartialPartition {
107    inner: Arc<dyn Partition>,
108    id: PartitionId,
109}
110
111impl Partition for PartialPartition {
112    fn id(&self) -> PartitionId {
113        self.id
114    }
115
116    fn size(&self) -> usize {
117        self.inner.size()
118    }
119
120    fn translate(&self, address: u64) -> (super::RawFile, u64) {
121        self.inner.translate(address)
122    }
123
124    fn statistics(&self) -> &Arc<Statistics> {
125        self.inner.statistics()
126    }
127}