sequential_storage/cache/
heap_impl.rs

1extern crate alloc;
2
3use alloc::{vec, vec::Vec};
4use core::num::NonZeroU32;
5
6use crate::{
7    PageState,
8    cache::{
9        CacheImpl, DirtTracker, Invalidate, KeyCacheImpl, PagePointersCache, PageStatesCache,
10        PrivateCacheImpl, PrivateKeyCacheImpl,
11        key_pointers::{CachedKeyPointers, KeyPointersCache, UncachedKeyPointers},
12        page_pointers::{CachedPagePointers, UncachedPagePointers},
13        page_states::CachedPageStates,
14    },
15    map::Key,
16};
17
18/// A cache object that keeps track of the page states.
19///
20/// This cache has to be kept around and passed to *every* api call to the same memory region until the cache gets discarded.
21///
22/// Valid usecase:  
23/// `Create cache 1` -> `use 1` -> `use 1` -> `create cache 2` -> `use 2` -> `use 2`
24///
25/// Invalid usecase:  
26/// `Create cache 1` -> `use 1` -> `create cache 2` -> `use 2` -> `❌ use 1 ❌`
27///
28/// Make sure the page count is correct. If the number is lower than the actual amount, the code will panic at some point.
29#[derive(Debug)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub struct HeapPageStateCache {
32    dirt_tracker: DirtTracker,
33    page_states: Vec<Option<PageState>>,
34}
35
36impl HeapPageStateCache {
37    /// Construct a new instance
38    pub fn new(pages: usize) -> Self {
39        Self {
40            dirt_tracker: DirtTracker::new(),
41            page_states: vec![None; pages],
42        }
43    }
44}
45
46impl PrivateCacheImpl for HeapPageStateCache {
47    type PSC<'a>
48        = CachedPageStates<'a>
49    where
50        Self: 'a;
51    type PPC<'a>
52        = UncachedPagePointers
53    where
54        Self: 'a;
55
56    fn dirt_tracker<R>(&mut self, f: impl FnOnce(&mut DirtTracker) -> R) -> Option<R> {
57        Some(f(&mut self.dirt_tracker))
58    }
59
60    fn page_states(&mut self) -> Self::PSC<'_> {
61        CachedPageStates::new(&mut self.page_states)
62    }
63
64    fn page_pointers(&mut self) -> Self::PPC<'_> {
65        UncachedPagePointers
66    }
67}
68
69impl CacheImpl for HeapPageStateCache {}
70impl<KEY: Key> KeyCacheImpl<KEY> for HeapPageStateCache {}
71
72impl Invalidate for HeapPageStateCache {
73    fn invalidate_cache_state(&mut self) {
74        self.dirt_tracker.unmark_dirty();
75        self.page_states().invalidate_cache_state();
76        self.page_pointers().invalidate_cache_state();
77    }
78}
79
80impl<KEY: Key> PrivateKeyCacheImpl<KEY> for HeapPageStateCache {
81    type KPC<'a>
82        = UncachedKeyPointers
83    where
84        Self: 'a;
85
86    fn key_pointers(&mut self) -> Self::KPC<'_> {
87        UncachedKeyPointers
88    }
89}
90
91/// A cache object that keeps track of the page states and some pointers to the items in the page.
92///
93/// This cache has to be kept around and passed to *every* api call to the same memory region until the cache gets discarded.
94///
95/// Valid usecase:  
96/// `Create cache 1` -> `use 1` -> `use 1` -> `create cache 2` -> `use 2` -> `use 2`
97///
98/// Invalid usecase:  
99/// `Create cache 1` -> `use 1` -> `create cache 2` -> `use 2` -> `❌ use 1 ❌`
100///
101/// Make sure the page count is correct. If the number is lower than the actual amount, the code will panic at some point.
102#[derive(Debug)]
103#[cfg_attr(feature = "defmt", derive(defmt::Format))]
104pub struct HeapPagePointerCache {
105    dirt_tracker: DirtTracker,
106    page_states: Vec<Option<PageState>>,
107    after_erased_pointers: Vec<Option<NonZeroU32>>,
108    after_written_pointers: Vec<Option<NonZeroU32>>,
109}
110
111impl HeapPagePointerCache {
112    /// Construct a new instance
113    pub fn new(pages: usize) -> Self {
114        Self {
115            dirt_tracker: DirtTracker::new(),
116            page_states: vec![None; pages],
117            after_erased_pointers: vec![None; pages],
118            after_written_pointers: vec![None; pages],
119        }
120    }
121}
122
123impl PrivateCacheImpl for HeapPagePointerCache {
124    type PSC<'a>
125        = CachedPageStates<'a>
126    where
127        Self: 'a;
128    type PPC<'a>
129        = CachedPagePointers<'a>
130    where
131        Self: 'a;
132
133    fn dirt_tracker<R>(&mut self, f: impl FnOnce(&mut DirtTracker) -> R) -> Option<R> {
134        Some(f(&mut self.dirt_tracker))
135    }
136
137    fn page_states(&mut self) -> Self::PSC<'_> {
138        CachedPageStates::new(&mut self.page_states)
139    }
140
141    fn page_pointers(&mut self) -> Self::PPC<'_> {
142        CachedPagePointers::new(
143            &mut self.after_erased_pointers,
144            &mut self.after_written_pointers,
145        )
146    }
147}
148
149impl CacheImpl for HeapPagePointerCache {}
150impl<KEY: Key> KeyCacheImpl<KEY> for HeapPagePointerCache {}
151
152impl Invalidate for HeapPagePointerCache {
153    fn invalidate_cache_state(&mut self) {
154        self.dirt_tracker.unmark_dirty();
155        self.page_states().invalidate_cache_state();
156        self.page_pointers().invalidate_cache_state();
157    }
158}
159
160impl<KEY: Key> PrivateKeyCacheImpl<KEY> for HeapPagePointerCache {
161    type KPC<'a>
162        = UncachedKeyPointers
163    where
164        Self: 'a;
165
166    fn key_pointers(&mut self) -> Self::KPC<'_> {
167        UncachedKeyPointers
168    }
169}
170
171/// An object that caches the location of the newest item with a given key.
172/// This cache also caches pages states and page pointers.
173///
174/// This cache has to be kept around and passed to *every* api call to the same memory region until the cache gets discarded.
175///
176/// Valid usecase:  
177/// `Create cache 1` -> `use 1` -> `use 1` -> `create cache 2` -> `use 2` -> `use 2`
178///
179/// Invalid usecase:  
180/// `Create cache 1` -> `use 1` -> `create cache 2` -> `use 2` -> `❌ use 1 ❌`
181///
182/// Make sure the page count is correct. If the number is lower than the actual amount, the code will panic at some point.
183///
184/// The number of key slots can be lower than the total amount of possible keys used, but this will lower
185/// the chance of a cache hit.
186/// The keys are cached in a fifo and any time its location is updated in cache it's added to the front.
187#[derive(Debug)]
188#[cfg_attr(feature = "defmt", derive(defmt::Format))]
189pub struct HeapKeyPointerCache<KEY: Key> {
190    dirt_tracker: DirtTracker,
191    page_states: Vec<Option<PageState>>,
192    after_erased_pointers: Vec<Option<NonZeroU32>>,
193    after_written_pointers: Vec<Option<NonZeroU32>>,
194    key_pointers: Vec<Option<(KEY, NonZeroU32)>>,
195}
196
197impl<KEY: Key> HeapKeyPointerCache<KEY> {
198    /// Construct a new instance
199    pub fn new(pages: usize, keys: usize) -> Self {
200        Self {
201            dirt_tracker: DirtTracker::new(),
202            page_states: vec![None; pages],
203            after_erased_pointers: vec![None; pages],
204            after_written_pointers: vec![None; pages],
205            key_pointers: vec![const { None }; keys],
206        }
207    }
208}
209
210impl<KEY: Key> PrivateCacheImpl for HeapKeyPointerCache<KEY> {
211    type PSC<'a>
212        = CachedPageStates<'a>
213    where
214        Self: 'a;
215    type PPC<'a>
216        = CachedPagePointers<'a>
217    where
218        Self: 'a;
219
220    fn dirt_tracker<R>(&mut self, f: impl FnOnce(&mut DirtTracker) -> R) -> Option<R> {
221        Some(f(&mut self.dirt_tracker))
222    }
223
224    fn page_states(&mut self) -> Self::PSC<'_> {
225        CachedPageStates::new(&mut self.page_states)
226    }
227
228    fn page_pointers(&mut self) -> Self::PPC<'_> {
229        CachedPagePointers::new(
230            &mut self.after_erased_pointers,
231            &mut self.after_written_pointers,
232        )
233    }
234}
235
236impl<KEY: Key> CacheImpl for HeapKeyPointerCache<KEY> {}
237impl<KEY: Key> KeyCacheImpl<KEY> for HeapKeyPointerCache<KEY> {}
238
239impl<KEY: Key> Invalidate for HeapKeyPointerCache<KEY> {
240    fn invalidate_cache_state(&mut self) {
241        self.dirt_tracker.unmark_dirty();
242        self.page_states().invalidate_cache_state();
243        self.page_pointers().invalidate_cache_state();
244        self.key_pointers().invalidate_cache_state();
245    }
246}
247
248impl<KEY: Key> PrivateKeyCacheImpl<KEY> for HeapKeyPointerCache<KEY> {
249    type KPC<'a>
250        = CachedKeyPointers<'a, KEY>
251    where
252        Self: 'a;
253
254    fn key_pointers(&mut self) -> Self::KPC<'_> {
255        CachedKeyPointers::new(&mut self.key_pointers)
256    }
257}