foyer_storage/engine/
mod.rs

1// Copyright 2025 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::{any::Any, fmt::Debug, sync::Arc};
16
17use foyer_common::{
18    code::{StorageKey, StorageValue},
19    metrics::Metrics,
20    properties::{Populated, Properties},
21};
22use foyer_memory::Piece;
23use futures_core::future::BoxFuture;
24
25use crate::{error::Result, filter::StorageFilterResult, io::engine::IoEngine, keeper::PieceRef, Device, Runtime};
26
27/// Load result.
28#[derive(Debug)]
29pub enum Load<K, V, P> {
30    /// Load entry success.
31    Entry {
32        /// The key of the entry.
33        key: K,
34        /// The value of the entry.
35        value: V,
36        /// The populated source context of the entry.
37        populated: Populated,
38    },
39    /// Load entry success from disk cache write queue.
40    Piece {
41        /// The piece of the entry.
42        piece: Piece<K, V, P>,
43        /// The populated source context of the entry.
44        populated: Populated,
45    },
46    /// The entry may be in the disk cache, the read io is throttled.
47    Throttled,
48    /// Disk cache miss.
49    Miss,
50}
51
52impl<K, V, P> Load<K, V, P> {
53    /// Return `Some` with the entry if load success, otherwise return `None`.
54    pub fn entry(self) -> Option<(K, V, Populated)> {
55        match self {
56            Load::Entry { key, value, populated } => Some((key, value, populated)),
57            _ => None,
58        }
59    }
60
61    /// Return `Some` with the entry if load success, otherwise return `None`.
62    ///
63    /// Only key and value will be returned.
64    pub fn kv(self) -> Option<(K, V)> {
65        match self {
66            Load::Entry { key, value, .. } => Some((key, value)),
67            _ => None,
68        }
69    }
70
71    /// Check if the load result is a cache miss.
72    pub fn is_miss(&self) -> bool {
73        matches!(self, Load::Miss)
74    }
75
76    /// Check if the load result is miss caused by io throttled.
77    pub fn is_throttled(&self) -> bool {
78        matches!(self, Load::Throttled)
79    }
80}
81
82/// The recover mode of the disk cache.
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
84#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
85#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
86pub enum RecoverMode {
87    /// Do not recover disk cache.
88    ///
89    /// For updatable cache, either [`RecoverMode::None`] or the tombstone log must be used to prevent from phantom
90    /// entry when reopen.
91    None,
92    /// Recover disk cache and skip errors.
93    #[default]
94    Quiet,
95    /// Recover disk cache and panic on errors.
96    Strict,
97}
98
99/// Context for building the disk cache engine.
100pub struct EngineBuildContext {
101    /// IO engine for the disk cache engine.
102    pub io_engine: Arc<dyn IoEngine>,
103    /// Shared metrics for all components.
104    pub metrics: Arc<Metrics>,
105    /// The runtime for the disk cache engine.
106    pub runtime: Runtime,
107    /// The recover mode of the disk cache engine.
108    pub recover_mode: RecoverMode,
109}
110
111/// Disk cache engine builder trait.
112#[expect(clippy::type_complexity)]
113pub trait EngineConfig<K, V, P>: Send + Sync + 'static + Debug
114where
115    K: StorageKey,
116    V: StorageValue,
117    P: Properties,
118{
119    /// Build the engine with the given configurations.
120    fn build(self: Box<Self>, ctx: EngineBuildContext) -> BoxFuture<'static, Result<Arc<dyn Engine<K, V, P>>>>;
121
122    /// Box the builder.
123    fn boxed(self) -> Box<Self>
124    where
125        Self: Sized,
126    {
127        Box::new(self)
128    }
129}
130
131/// Disk cache engine trait.
132pub trait Engine<K, V, P>: Send + Sync + 'static + Debug + Any
133where
134    K: StorageKey,
135    V: StorageValue,
136    P: Properties,
137{
138    /// Get the device used by this disk cache engine.
139    fn device(&self) -> &Arc<dyn Device>;
140
141    /// Return if the given key can be picked by the disk cache engine.
142    fn filter(&self, hash: u64, estimated_size: usize) -> StorageFilterResult;
143
144    /// Push a in-memory cache piece to the disk cache write queue.
145    fn enqueue(&self, piece: PieceRef<K, V, P>, estimated_size: usize);
146
147    /// Load a cache entry from the disk cache.
148    ///
149    /// `load` may return a false-positive result on entry key hash collision. It's the caller's responsibility to
150    /// check if the returned key matches the given key.
151    fn load(&self, hash: u64) -> BoxFuture<'static, Result<Load<K, V, P>>>;
152
153    /// Delete the cache entry with the given key from the disk cache.
154    fn delete(&self, hash: u64);
155
156    /// Check if the disk cache contains a cached entry with the given key.
157    ///
158    /// `contains` may return a false-positive result if there is a hash collision with the given key.
159    fn may_contains(&self, hash: u64) -> bool;
160
161    /// Delete all cached entries of the disk cache.
162    fn destroy(&self) -> BoxFuture<'static, Result<()>>;
163
164    /// Wait for the ongoing flush and reclaim tasks to finish.
165    fn wait(&self) -> BoxFuture<'static, ()>;
166
167    /// Close the disk cache gracefully.
168    ///
169    /// `close` will wait for all ongoing flush and reclaim tasks to finish.
170    fn close(&self) -> BoxFuture<'static, Result<()>>;
171}
172
173pub mod block;
174pub mod noop;