foyer_memory/eviction/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright 2025 foyer Project Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Arc;

use foyer_common::code::{Key, Value};
use serde::{de::DeserializeOwned, Serialize};

use crate::{
    error::Result,
    record::{CacheHint, Record},
};

pub trait Hint: Send + Sync + 'static + Clone + Default + From<CacheHint> + Into<CacheHint> {}
impl<T> Hint for T where T: Send + Sync + 'static + Clone + Default + From<CacheHint> + Into<CacheHint> {}

pub trait State: Send + Sync + 'static + Default {}
impl<T> State for T where T: Send + Sync + 'static + Default {}

pub trait Config: Send + Sync + 'static + Clone + Serialize + DeserializeOwned + Default {}
impl<T> Config for T where T: Send + Sync + 'static + Clone + Serialize + DeserializeOwned + Default {}

/// Wrapper for one of the three kind of operations for the eviction container:
///
/// 1. no operation
/// 2. immutable operation
/// 3. mutable operation
#[expect(clippy::type_complexity)]
pub enum Op<E>
where
    E: Eviction,
{
    /// no operation
    Noop,
    /// immutable operation
    Immutable(Box<dyn Fn(&E, &Arc<Record<E>>) + Send + Sync + 'static>),
    /// mutable operation
    Mutable(Box<dyn FnMut(&mut E, &Arc<Record<E>>) + Send + Sync + 'static>),
}

impl<E> Op<E>
where
    E: Eviction,
{
    /// no operation
    pub fn noop() -> Self {
        Self::Noop
    }

    /// immutable operation
    pub fn immutable<F>(f: F) -> Self
    where
        F: Fn(&E, &Arc<Record<E>>) + Send + Sync + 'static,
    {
        Self::Immutable(Box::new(f))
    }

    /// mutable operation
    pub fn mutable<F>(f: F) -> Self
    where
        F: FnMut(&mut E, &Arc<Record<E>>) + Send + Sync + 'static,
    {
        Self::Mutable(Box::new(f))
    }
}

/// Cache eviction algorithm abstraction.
///
/// [`Eviction`] provides essential APIs for the plug-and-play algorithm abstraction.
///
/// [`Eviction`] is needs to be implemented to support a new cache eviction algorithm.
///
/// # Safety
///
/// The pointer can be dereferenced as a mutable reference ***iff*** the `self` reference is also mutable.
/// Dereferencing a pointer as a mutable reference when `self` is immutable will cause UB.
pub trait Eviction: Send + Sync + 'static + Sized {
    /// Cache eviction algorithm configurations.
    type Config: Config;
    /// Cache key. Generally, it is supposed to be a generic type of the implementation.
    type Key: Key;
    /// Cache value. Generally, it is supposed to be a generic type of the implementation.
    type Value: Value;
    /// Hint for a cache entry. Can be used to support priority at the entry granularity.
    type Hint: Hint;
    /// State for a cache entry. Mutable state for maintaining the cache eviction algorithm implementation.
    type State: State;

    /// Create a new cache eviction algorithm instance with the given arguments.
    fn new(capacity: usize, config: &Self::Config) -> Self;

    /// Update the arguments of the ache eviction algorithm instance.
    fn update(&mut self, capacity: usize, config: Option<&Self::Config>) -> Result<()>;

    /// Push a record into the cache eviction algorithm instance.
    ///
    /// The caller guarantees that the record is NOT in the cache eviction algorithm instance.
    ///
    /// The cache eviction algorithm instance MUST hold the record and set its `IN_EVICTION` flag to true.
    fn push(&mut self, record: Arc<Record<Self>>);

    /// Push a record from the cache eviction algorithm instance.
    ///
    /// The cache eviction algorithm instance MUST remove the record and set its `IN_EVICTION` flag to false.
    fn pop(&mut self) -> Option<Arc<Record<Self>>>;

    /// Remove a record from the cache eviction algorithm instance.
    ///
    /// The caller guarantees that the record is in the cache eviction algorithm instance.
    ///
    /// The cache eviction algorithm instance MUST remove the record and set its `IN_EVICTION` flag to false.
    fn remove(&mut self, record: &Arc<Record<Self>>);

    /// Remove all records from the cache eviction algorithm instance.
    ///
    /// The cache eviction algorithm instance MUST remove the records and set its `IN_EVICTION` flag to false.
    fn clear(&mut self) {
        while self.pop().is_some() {}
    }

    /// `acquire` is called when an external caller acquire a cache entry from the cache.
    ///
    /// The entry can be EITHER in the cache eviction algorithm instance or not.
    fn acquire() -> Op<Self>;

    /// `release` is called when the last external caller drops the cache entry.
    ///
    /// The entry can be EITHER in the cache eviction algorithm instance or not.
    fn release() -> Op<Self>;
}

pub mod fifo;
pub mod lfu;
pub mod lru;
pub mod s3fifo;

#[cfg(test)]
pub mod test_utils;