/build/source/nativelink-util/src/evicting_map.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2024 The NativeLink Authors. All rights reserved. |
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 | | |
15 | | use std::borrow::Borrow; |
16 | | use std::cmp::Eq; |
17 | | use std::collections::BTreeSet; |
18 | | use std::fmt::Debug; |
19 | | use std::future::Future; |
20 | | use std::hash::Hash; |
21 | | use std::ops::RangeBounds; |
22 | | use std::sync::Arc; |
23 | | |
24 | | use async_lock::Mutex; |
25 | | use lru::LruCache; |
26 | | use nativelink_config::stores::EvictionPolicy; |
27 | | use nativelink_metric::MetricsComponent; |
28 | | use serde::{Deserialize, Serialize}; |
29 | | use tracing::{event, Level}; |
30 | | |
31 | | use crate::instant_wrapper::InstantWrapper; |
32 | | use crate::metrics_utils::{Counter, CounterWithTime}; |
33 | | |
34 | 0 | #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] |
35 | | pub struct SerializedLRU<K> { |
36 | | pub data: Vec<(K, i32)>, |
37 | | pub anchor_time: u64, |
38 | | } |
39 | | |
40 | | #[derive(Debug)] |
41 | | struct EvictionItem<T: LenEntry + Debug> { |
42 | | seconds_since_anchor: i32, |
43 | | data: T, |
44 | | } |
45 | | |
46 | | pub trait LenEntry: 'static { |
47 | | /// Length of referenced data. |
48 | | fn len(&self) -> u64; |
49 | | |
50 | | /// Returns `true` if `self` has zero length. |
51 | | fn is_empty(&self) -> bool; |
52 | | |
53 | | /// Called when an entry is touched. On failure, will remove the entry |
54 | | /// from the map. |
55 | | #[inline] |
56 | 4.62k | fn touch(&self) -> impl Future<Output = bool> + Send { |
57 | 4.62k | std::future::ready(true) |
58 | 4.62k | } |
59 | | |
60 | | /// This will be called when object is removed from map. |
61 | | /// Note: There may still be a reference to it held somewhere else, which |
62 | | /// is why it can't be mutable. This is a good place to mark the item |
63 | | /// to be deleted and then in the Drop call actually do the deleting. |
64 | | /// This will ensure nowhere else in the program still holds a reference |
65 | | /// to this object. |
66 | | /// You should not rely only on the Drop trait. Doing so might result in the |
67 | | /// program safely shutting down and calling the Drop method on each object, |
68 | | /// which if you are deleting items you may not want to do. |
69 | | /// It is undefined behavior to have `unref()` called more than once. |
70 | | /// During the execution of `unref()` no items can be added or removed to/from |
71 | | /// the EvictionMap globally (including inside `unref()`). |
72 | | #[inline] |
73 | 33 | fn unref(&self) -> impl Future<Output = ()> + Send { |
74 | 33 | std::future::ready(()) |
75 | 33 | } |
76 | | } |
77 | | |
78 | | impl<T: LenEntry + Send + Sync> LenEntry for Arc<T> { |
79 | | #[inline] |
80 | 235 | fn len(&self) -> u64 { |
81 | 235 | T::len(self.as_ref()) |
82 | 235 | } |
83 | | |
84 | | #[inline] |
85 | 0 | fn is_empty(&self) -> bool { |
86 | 0 | T::is_empty(self.as_ref()) |
87 | 0 | } |
88 | | |
89 | | #[inline] |
90 | 132 | async fn touch(&self) -> bool { |
91 | 132 | self.as_ref().touch().await83 |
92 | 132 | } |
93 | | |
94 | | #[inline] |
95 | 19 | async fn unref(&self) { |
96 | 19 | self.as_ref().unref().await16 ; |
97 | 19 | } |
98 | | } |
99 | | |
100 | 0 | #[derive(MetricsComponent)] |
101 | | struct State<K: Ord + Hash + Eq + Clone + Debug, T: LenEntry + Debug> { |
102 | | lru: LruCache<K, EvictionItem<T>>, |
103 | | btree: Option<BTreeSet<K>>, |
104 | | #[metric(help = "Total size of all items in the store")] |
105 | | sum_store_size: u64, |
106 | | |
107 | | #[metric(help = "Number of bytes evicted from the store")] |
108 | | evicted_bytes: Counter, |
109 | | #[metric(help = "Number of items evicted from the store")] |
110 | | evicted_items: CounterWithTime, |
111 | | #[metric(help = "Number of bytes replaced in the store")] |
112 | | replaced_bytes: Counter, |
113 | | #[metric(help = "Number of items replaced in the store")] |
114 | | replaced_items: CounterWithTime, |
115 | | #[metric(help = "Number of bytes inserted into the store since it was created")] |
116 | | lifetime_inserted_bytes: Counter, |
117 | | } |
118 | | |
119 | | impl<K: Ord + Hash + Eq + Clone + Debug, T: LenEntry + Debug + Sync> State<K, T> { |
120 | | /// Removes an item from the cache. |
121 | 52 | async fn remove<Q>(&mut self, key: &Q, eviction_item: &EvictionItem<T>, replaced: bool) |
122 | 52 | where |
123 | 52 | K: Borrow<Q>, |
124 | 52 | Q: Ord + Hash + Eq + Debug, |
125 | 52 | { |
126 | 52 | if let Some(btree0 ) = &mut self.btree { Branch (126:16): [True: 0, False: 0]
Branch (126:16): [True: 0, False: 9]
Branch (126:16): [True: 0, False: 0]
Branch (126:16): [True: 0, False: 0]
Branch (126:16): [Folded - Ignored]
Branch (126:16): [True: 0, False: 6]
Branch (126:16): [True: 0, False: 1]
Branch (126:16): [True: 0, False: 1]
Branch (126:16): [True: 0, False: 14]
Branch (126:16): [True: 0, False: 0]
Branch (126:16): [True: 0, False: 1]
Branch (126:16): [True: 0, False: 2]
Branch (126:16): [True: 0, False: 1]
Branch (126:16): [True: 0, False: 1]
Branch (126:16): [True: 0, False: 1]
Branch (126:16): [True: 0, False: 1]
Branch (126:16): [True: 0, False: 1]
Branch (126:16): [True: 0, False: 7]
Branch (126:16): [True: 0, False: 0]
Branch (126:16): [True: 0, False: 0]
Branch (126:16): [Folded - Ignored]
Branch (126:16): [True: 0, False: 6]
Branch (126:16): [True: 0, False: 0]
|
127 | 0 | btree.remove(key.borrow()); |
128 | 52 | } |
129 | 52 | self.sum_store_size -= eviction_item.data.len(); |
130 | 52 | if replaced { Branch (130:12): [True: 0, False: 0]
Branch (130:12): [True: 8, False: 1]
Branch (130:12): [True: 0, False: 0]
Branch (130:12): [True: 0, False: 0]
Branch (130:12): [Folded - Ignored]
Branch (130:12): [True: 0, False: 6]
Branch (130:12): [True: 0, False: 1]
Branch (130:12): [True: 1, False: 0]
Branch (130:12): [True: 0, False: 14]
Branch (130:12): [True: 0, False: 0]
Branch (130:12): [True: 0, False: 1]
Branch (130:12): [True: 0, False: 2]
Branch (130:12): [True: 0, False: 1]
Branch (130:12): [True: 0, False: 1]
Branch (130:12): [True: 1, False: 0]
Branch (130:12): [True: 1, False: 0]
Branch (130:12): [True: 0, False: 1]
Branch (130:12): [True: 5, False: 2]
Branch (130:12): [True: 0, False: 0]
Branch (130:12): [True: 0, False: 0]
Branch (130:12): [Folded - Ignored]
Branch (130:12): [True: 6, False: 0]
Branch (130:12): [True: 0, False: 0]
|
131 | 22 | self.replaced_items.inc(); |
132 | 22 | self.replaced_bytes.add(eviction_item.data.len()); |
133 | 30 | } else { |
134 | 30 | self.evicted_items.inc(); |
135 | 30 | self.evicted_bytes.add(eviction_item.data.len()); |
136 | 30 | } |
137 | | // Note: See comment in `unref()` requring global lock of insert/remove. |
138 | 52 | eviction_item.data.unref().await16 ; |
139 | 52 | } |
140 | | |
141 | | /// Inserts a new item into the cache. If the key already exists, the old item is returned. |
142 | 5.85k | async fn put(&mut self, key: K, eviction_item: EvictionItem<T>) -> Option<T> { |
143 | | // If we are maintaining a btree index, we need to update it. |
144 | 5.85k | if let Some(btree0 ) = &mut self.btree { Branch (144:16): [True: 0, False: 0]
Branch (144:16): [True: 0, False: 5.71k]
Branch (144:16): [True: 0, False: 0]
Branch (144:16): [True: 0, False: 0]
Branch (144:16): [Folded - Ignored]
Branch (144:16): [True: 0, False: 2]
Branch (144:16): [True: 0, False: 27]
Branch (144:16): [True: 0, False: 3]
Branch (144:16): [True: 0, False: 5]
Branch (144:16): [True: 0, False: 2]
Branch (144:16): [True: 0, False: 2]
Branch (144:16): [True: 0, False: 2]
Branch (144:16): [True: 0, False: 2]
Branch (144:16): [True: 0, False: 1]
Branch (144:16): [True: 0, False: 23]
Branch (144:16): [True: 0, False: 0]
Branch (144:16): [Folded - Ignored]
Branch (144:16): [True: 0, False: 49]
Branch (144:16): [True: 0, False: 25]
|
145 | 0 | btree.insert(key.clone()); |
146 | 5.85k | } |
147 | 5.85k | if let Some(old_item22 ) = self.lru.put(key.clone(), eviction_item) { Branch (147:16): [True: 0, False: 0]
Branch (147:16): [True: 8, False: 5.70k]
Branch (147:16): [True: 0, False: 0]
Branch (147:16): [True: 0, False: 0]
Branch (147:16): [Folded - Ignored]
Branch (147:16): [True: 1, False: 1]
Branch (147:16): [True: 0, False: 27]
Branch (147:16): [True: 0, False: 3]
Branch (147:16): [True: 0, False: 5]
Branch (147:16): [True: 0, False: 2]
Branch (147:16): [True: 0, False: 2]
Branch (147:16): [True: 1, False: 1]
Branch (147:16): [True: 1, False: 1]
Branch (147:16): [True: 0, False: 1]
Branch (147:16): [True: 5, False: 18]
Branch (147:16): [True: 0, False: 0]
Branch (147:16): [Folded - Ignored]
Branch (147:16): [True: 6, False: 43]
Branch (147:16): [True: 0, False: 25]
|
148 | 22 | self.remove(&key, &old_item, true).await12 ; |
149 | 22 | return Some(old_item.data); |
150 | 5.83k | } |
151 | 5.83k | None |
152 | 5.85k | } |
153 | | } |
154 | | |
155 | 0 | #[derive(MetricsComponent)] |
156 | | pub struct EvictingMap<K: Ord + Hash + Eq + Clone + Debug, T: LenEntry + Debug, I: InstantWrapper> { |
157 | | #[metric] |
158 | | state: Mutex<State<K, T>>, |
159 | | anchor_time: I, |
160 | | #[metric(help = "Maximum size of the store in bytes")] |
161 | | max_bytes: u64, |
162 | | #[metric(help = "Number of bytes to evict when the store is full")] |
163 | | evict_bytes: u64, |
164 | | #[metric(help = "Maximum number of seconds to keep an item in the store")] |
165 | | max_seconds: i32, |
166 | | #[metric(help = "Maximum number of items to keep in the store")] |
167 | | max_count: u64, |
168 | | } |
169 | | |
170 | | impl<K, T, I> EvictingMap<K, T, I> |
171 | | where |
172 | | K: Ord + Hash + Eq + Clone + Debug, |
173 | | T: LenEntry + Debug + Clone + Send + Sync, |
174 | | I: InstantWrapper, |
175 | | { |
176 | 373 | pub fn new(config: &EvictionPolicy, anchor_time: I) -> Self { |
177 | 373 | EvictingMap { |
178 | 373 | // We use unbounded because if we use the bounded version we can't call the delete |
179 | 373 | // function on the LenEntry properly. |
180 | 373 | state: Mutex::new(State { |
181 | 373 | lru: LruCache::unbounded(), |
182 | 373 | btree: None, |
183 | 373 | sum_store_size: 0, |
184 | 373 | evicted_bytes: Counter::default(), |
185 | 373 | evicted_items: CounterWithTime::default(), |
186 | 373 | replaced_bytes: Counter::default(), |
187 | 373 | replaced_items: CounterWithTime::default(), |
188 | 373 | lifetime_inserted_bytes: Counter::default(), |
189 | 373 | }), |
190 | 373 | anchor_time, |
191 | 373 | max_bytes: config.max_bytes as u64, |
192 | 373 | evict_bytes: config.evict_bytes as u64, |
193 | 373 | max_seconds: config.max_seconds as i32, |
194 | 373 | max_count: config.max_count, |
195 | 373 | } |
196 | 373 | } |
197 | | |
198 | 0 | pub async fn enable_filtering(&self) { |
199 | 0 | let mut state = self.state.lock().await; |
200 | 0 | if state.btree.is_none() { Branch (200:12): [Folded - Ignored]
Branch (200:12): [Folded - Ignored]
|
201 | 0 | Self::rebuild_btree_index(&mut state); |
202 | 0 | } |
203 | 0 | } |
204 | | |
205 | 2 | fn rebuild_btree_index(state: &mut State<K, T>) { |
206 | 6 | state.btree = Some(state.lru.iter().map(|(k, _)| k).cloned().collect()); |
207 | 2 | } |
208 | | |
209 | | /// Run the `handler` function on each key-value pair that matches the `prefix_range` |
210 | | /// and return the number of items that were processed. |
211 | | /// The `handler` function should return `true` to continue processing the next item |
212 | | /// or `false` to stop processing. |
213 | 11 | pub async fn range<F, Q>(&self, prefix_range: impl RangeBounds<Q>, mut handler: F) -> u64 |
214 | 11 | where |
215 | 11 | F: FnMut(&K, &T) -> bool, |
216 | 11 | K: Borrow<Q> + Ord, |
217 | 11 | Q: Ord + Hash + Eq + Debug, |
218 | 11 | { |
219 | 11 | let mut state = self.state.lock().await0 ; |
220 | 11 | let btree = if let Some(ref btree9 ) = state.btree { Branch (220:28): [True: 6, False: 1]
Branch (220:28): [Folded - Ignored]
Branch (220:28): [True: 1, False: 0]
Branch (220:28): [True: 2, False: 0]
Branch (220:28): [True: 0, False: 1]
Branch (220:28): [Folded - Ignored]
|
221 | 9 | btree |
222 | | } else { |
223 | 2 | Self::rebuild_btree_index(&mut state); |
224 | 2 | state.btree.as_ref().unwrap() |
225 | | }; |
226 | 11 | let mut continue_count = 0; |
227 | 22 | for key in btree.range(prefix_range)11 { |
228 | 22 | let value = &state.lru.peek(key.borrow()).unwrap().data; |
229 | 22 | let should_continue = handler(key, value); |
230 | 22 | if !should_continue { Branch (230:16): [True: 0, False: 13]
Branch (230:16): [Folded - Ignored]
Branch (230:16): [True: 0, False: 1]
Branch (230:16): [True: 0, False: 5]
Branch (230:16): [True: 0, False: 3]
Branch (230:16): [Folded - Ignored]
|
231 | 0 | break; |
232 | 22 | } |
233 | 22 | continue_count += 1; |
234 | | } |
235 | 11 | continue_count |
236 | 11 | } |
237 | | |
238 | | /// Returns the number of key-value pairs that are currently in the the cache. |
239 | | /// Function is not for production code paths. |
240 | 30 | pub async fn len_for_test(&self) -> usize { |
241 | 30 | self.state.lock().await0 .lru.len() |
242 | 30 | } |
243 | | |
244 | 11.0k | fn should_evict( |
245 | 11.0k | &self, |
246 | 11.0k | lru_len: usize, |
247 | 11.0k | peek_entry: &EvictionItem<T>, |
248 | 11.0k | sum_store_size: u64, |
249 | 11.0k | max_bytes: u64, |
250 | 11.0k | ) -> bool { |
251 | 11.0k | let is_over_size = max_bytes != 0 && sum_store_size >= max_bytes230 ; Branch (251:28): [True: 0, False: 0]
Branch (251:28): [True: 100, False: 10.1k]
Branch (251:28): [True: 0, False: 0]
Branch (251:28): [True: 0, False: 0]
Branch (251:28): [Folded - Ignored]
Branch (251:28): [True: 0, False: 6]
Branch (251:28): [True: 0, False: 1]
Branch (251:28): [True: 0, False: 3]
Branch (251:28): [True: 30, False: 31]
Branch (251:28): [True: 0, False: 3]
Branch (251:28): [True: 0, False: 1]
Branch (251:28): [True: 4, False: 1]
Branch (251:28): [True: 3, False: 5]
Branch (251:28): [True: 3, False: 0]
Branch (251:28): [True: 0, False: 4]
Branch (251:28): [True: 0, False: 2]
Branch (251:28): [True: 0, False: 3]
Branch (251:28): [True: 0, False: 2]
Branch (251:28): [True: 2, False: 37]
Branch (251:28): [True: 0, False: 0]
Branch (251:28): [True: 0, False: 4]
Branch (251:28): [Folded - Ignored]
Branch (251:28): [True: 34, False: 69]
Branch (251:28): [True: 54, False: 528]
|
252 | | |
253 | 11.0k | let evict_older_than_seconds = |
254 | 11.0k | (self.anchor_time.elapsed().as_secs() as i32) - self.max_seconds; |
255 | 11.0k | let old_item_exists = |
256 | 11.0k | self.max_seconds != 0 && peek_entry.seconds_since_anchor < evict_older_than_seconds615 ; Branch (256:13): [True: 0, False: 0]
Branch (256:13): [True: 0, False: 10.2k]
Branch (256:13): [True: 0, False: 0]
Branch (256:13): [True: 0, False: 0]
Branch (256:13): [Folded - Ignored]
Branch (256:13): [True: 0, False: 6]
Branch (256:13): [True: 0, False: 1]
Branch (256:13): [True: 0, False: 3]
Branch (256:13): [True: 28, False: 33]
Branch (256:13): [True: 0, False: 3]
Branch (256:13): [True: 0, False: 1]
Branch (256:13): [True: 5, False: 0]
Branch (256:13): [True: 0, False: 8]
Branch (256:13): [True: 0, False: 3]
Branch (256:13): [True: 0, False: 4]
Branch (256:13): [True: 0, False: 2]
Branch (256:13): [True: 0, False: 3]
Branch (256:13): [True: 0, False: 2]
Branch (256:13): [True: 0, False: 39]
Branch (256:13): [True: 0, False: 0]
Branch (256:13): [True: 0, False: 4]
Branch (256:13): [Folded - Ignored]
Branch (256:13): [True: 0, False: 103]
Branch (256:13): [True: 582, False: 0]
|
257 | | |
258 | 11.0k | let is_over_count = self.max_count != 0 && (lru_len as u64) > self.max_count57 ; Branch (258:29): [True: 0, False: 0]
Branch (258:29): [True: 32, False: 10.2k]
Branch (258:29): [True: 0, False: 0]
Branch (258:29): [True: 0, False: 0]
Branch (258:29): [Folded - Ignored]
Branch (258:29): [True: 0, False: 6]
Branch (258:29): [True: 0, False: 1]
Branch (258:29): [True: 3, False: 0]
Branch (258:29): [True: 8, False: 53]
Branch (258:29): [True: 0, False: 3]
Branch (258:29): [True: 0, False: 1]
Branch (258:29): [True: 0, False: 5]
Branch (258:29): [True: 0, False: 8]
Branch (258:29): [True: 0, False: 3]
Branch (258:29): [True: 4, False: 0]
Branch (258:29): [True: 2, False: 0]
Branch (258:29): [True: 3, False: 0]
Branch (258:29): [True: 0, False: 2]
Branch (258:29): [True: 5, False: 34]
Branch (258:29): [True: 0, False: 0]
Branch (258:29): [True: 0, False: 4]
Branch (258:29): [Folded - Ignored]
Branch (258:29): [True: 0, False: 103]
Branch (258:29): [True: 0, False: 582]
|
259 | | |
260 | 11.0k | is_over_size || old_item_exists11.0k || is_over_count11.0k Branch (260:9): [True: 0, False: 0]
Branch (260:25): [True: 0, False: 0]
Branch (260:9): [True: 0, False: 10.2k]
Branch (260:25): [True: 0, False: 10.2k]
Branch (260:9): [True: 0, False: 0]
Branch (260:25): [True: 0, False: 0]
Branch (260:9): [True: 0, False: 0]
Branch (260:25): [True: 0, False: 0]
Branch (260:9): [Folded - Ignored]
Branch (260:25): [Folded - Ignored]
Branch (260:9): [True: 0, False: 6]
Branch (260:25): [True: 0, False: 6]
Branch (260:9): [True: 0, False: 1]
Branch (260:25): [True: 0, False: 1]
Branch (260:9): [True: 0, False: 3]
Branch (260:25): [True: 0, False: 3]
Branch (260:9): [True: 6, False: 55]
Branch (260:25): [True: 7, False: 48]
Branch (260:9): [True: 0, False: 3]
Branch (260:25): [True: 0, False: 3]
Branch (260:9): [True: 0, False: 1]
Branch (260:25): [True: 0, False: 1]
Branch (260:9): [True: 0, False: 5]
Branch (260:25): [True: 1, False: 4]
Branch (260:9): [True: 0, False: 8]
Branch (260:25): [True: 0, False: 8]
Branch (260:9): [True: 1, False: 2]
Branch (260:25): [True: 0, False: 2]
Branch (260:9): [True: 0, False: 4]
Branch (260:25): [True: 0, False: 4]
Branch (260:9): [True: 0, False: 2]
Branch (260:25): [True: 0, False: 2]
Branch (260:9): [True: 0, False: 3]
Branch (260:25): [True: 0, False: 3]
Branch (260:9): [True: 0, False: 2]
Branch (260:25): [True: 0, False: 2]
Branch (260:9): [True: 0, False: 39]
Branch (260:25): [True: 0, False: 39]
Branch (260:9): [True: 0, False: 0]
Branch (260:25): [True: 0, False: 0]
Branch (260:9): [True: 0, False: 4]
Branch (260:25): [True: 0, False: 4]
Branch (260:9): [Folded - Ignored]
Branch (260:25): [Folded - Ignored]
Branch (260:9): [True: 0, False: 103]
Branch (260:25): [True: 0, False: 103]
Branch (260:9): [True: 0, False: 582]
Branch (260:25): [True: 0, False: 582]
|
261 | 11.0k | } |
262 | | |
263 | 10.8k | async fn evict_items(&self, state: &mut State<K, T>) { |
264 | 10.8k | let Some((_, mut peek_entry10.8k )) = state.lru.peek_lru() else { Branch (264:13): [True: 0, False: 0]
Branch (264:13): [True: 10.1k, False: 4]
Branch (264:13): [True: 0, False: 0]
Branch (264:13): [True: 0, False: 0]
Branch (264:13): [Folded - Ignored]
Branch (264:13): [True: 6, False: 0]
Branch (264:13): [True: 1, False: 0]
Branch (264:13): [True: 3, False: 0]
Branch (264:13): [True: 34, False: 0]
Branch (264:13): [True: 3, False: 0]
Branch (264:13): [True: 1, False: 0]
Branch (264:13): [True: 1, False: 0]
Branch (264:13): [True: 5, False: 0]
Branch (264:13): [True: 2, False: 0]
Branch (264:13): [True: 3, False: 0]
Branch (264:13): [True: 2, False: 0]
Branch (264:13): [True: 3, False: 0]
Branch (264:13): [True: 2, False: 0]
Branch (264:13): [True: 36, False: 0]
Branch (264:13): [True: 0, False: 0]
Branch (264:13): [True: 4, False: 0]
Branch (264:13): [Folded - Ignored]
Branch (264:13): [True: 69, False: 0]
Branch (264:13): [True: 528, False: 0]
|
265 | 4 | return; |
266 | | }; |
267 | | |
268 | 10.8k | let max_bytes = if self.max_bytes != 0 Branch (268:28): [True: 0, False: 0]
Branch (268:28): [True: 0, False: 10.1k]
Branch (268:28): [True: 0, False: 0]
Branch (268:28): [True: 0, False: 0]
Branch (268:28): [Folded - Ignored]
Branch (268:28): [True: 0, False: 6]
Branch (268:28): [True: 0, False: 1]
Branch (268:28): [True: 0, False: 3]
Branch (268:28): [True: 8, False: 26]
Branch (268:28): [True: 0, False: 3]
Branch (268:28): [True: 0, False: 1]
Branch (268:28): [True: 0, False: 1]
Branch (268:28): [True: 0, False: 5]
Branch (268:28): [True: 2, False: 0]
Branch (268:28): [True: 0, False: 3]
Branch (268:28): [True: 0, False: 2]
Branch (268:28): [True: 0, False: 3]
Branch (268:28): [True: 0, False: 2]
Branch (268:28): [True: 0, False: 36]
Branch (268:28): [True: 0, False: 0]
Branch (268:28): [True: 0, False: 4]
Branch (268:28): [Folded - Ignored]
Branch (268:28): [True: 0, False: 69]
Branch (268:28): [True: 0, False: 528]
|
269 | 10 | && self.evict_bytes != 0 Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [Folded - Ignored]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 4, False: 4]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 2]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [Folded - Ignored]
Branch (269:16): [True: 0, False: 0]
Branch (269:16): [True: 0, False: 0]
|
270 | 4 | && self.should_evict( Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [Folded - Ignored]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 1, False: 3]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [Folded - Ignored]
Branch (270:16): [True: 0, False: 0]
Branch (270:16): [True: 0, False: 0]
|
271 | 4 | state.lru.len(), |
272 | 4 | peek_entry, |
273 | 4 | state.sum_store_size, |
274 | 4 | self.max_bytes, |
275 | 4 | ) { |
276 | 1 | if self.max_bytes > self.evict_bytes { Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [Folded - Ignored]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 1, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [Folded - Ignored]
Branch (276:16): [True: 0, False: 0]
Branch (276:16): [True: 0, False: 0]
|
277 | 1 | self.max_bytes - self.evict_bytes |
278 | | } else { |
279 | 0 | 0 |
280 | | } |
281 | | } else { |
282 | 10.8k | self.max_bytes |
283 | | }; |
284 | | |
285 | 10.8k | while self.should_evict(state.lru.len(), peek_entry, state.sum_store_size, max_bytes) { Branch (285:15): [True: 0, False: 0]
Branch (285:15): [True: 1, False: 10.1k]
Branch (285:15): [True: 0, False: 0]
Branch (285:15): [True: 0, False: 0]
Branch (285:15): [Folded - Ignored]
Branch (285:15): [True: 0, False: 6]
Branch (285:15): [True: 0, False: 1]
Branch (285:15): [True: 0, False: 3]
Branch (285:15): [True: 12, False: 31]
Branch (285:15): [True: 0, False: 3]
Branch (285:15): [True: 0, False: 1]
Branch (285:15): [True: 0, False: 1]
Branch (285:15): [True: 0, False: 5]
Branch (285:15): [True: 1, False: 2]
Branch (285:15): [True: 1, False: 3]
Branch (285:15): [True: 0, False: 2]
Branch (285:15): [True: 0, False: 3]
Branch (285:15): [True: 0, False: 2]
Branch (285:15): [True: 1, False: 36]
Branch (285:15): [True: 0, False: 0]
Branch (285:15): [True: 0, False: 4]
Branch (285:15): [Folded - Ignored]
Branch (285:15): [True: 0, False: 69]
Branch (285:15): [True: 0, False: 528]
|
286 | 16 | let (key, eviction_item) = state |
287 | 16 | .lru |
288 | 16 | .pop_lru() |
289 | 16 | .expect("Tried to peek() then pop() but failed"); |
290 | 16 | event!(Level::INFO, ?key, "Evicting"0 ,); |
291 | 16 | state.remove(&key, &eviction_item, false).await3 ; |
292 | | |
293 | 16 | peek_entry = if let Some((_, entry13 )) = state.lru.peek_lru() { Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 1, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [Folded - Ignored]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 9, False: 3]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 1, False: 0]
Branch (293:33): [True: 1, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 1, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [Folded - Ignored]
Branch (293:33): [True: 0, False: 0]
Branch (293:33): [True: 0, False: 0]
|
294 | 13 | entry |
295 | | } else { |
296 | 3 | return; |
297 | | }; |
298 | | } |
299 | 10.8k | } |
300 | | |
301 | | /// Return the size of a `key`, if not found `None` is returned. |
302 | 79 | pub async fn size_for_key<Q>(&self, key: &Q) -> Option<u64> |
303 | 79 | where |
304 | 79 | K: Borrow<Q>, |
305 | 79 | Q: Ord + Hash + Eq + Debug, |
306 | 79 | { |
307 | 79 | let mut results = [None]; |
308 | 79 | self.sizes_for_keys([key], &mut results[..], false).await0 ; |
309 | 79 | results[0] |
310 | 79 | } |
311 | | |
312 | | /// Return the sizes of a collection of `keys`. Expects `results` collection |
313 | | /// to be provided for storing the resulting key sizes. Each index value in |
314 | | /// `keys` maps directly to the size value for the key in `results`. |
315 | | /// If no key is found in the internal map, `None` is filled in its place. |
316 | | /// If `peek` is set to `true`, the items are not promoted to the front of the |
317 | | /// LRU cache. Note: peek may still evict, but won't promote. |
318 | 326 | pub async fn sizes_for_keys<It, Q, R>(&self, keys: It, results: &mut [Option<u64>], peek: bool) |
319 | 326 | where |
320 | 326 | It: IntoIterator<Item = R>, |
321 | 326 | // This may look strange, but what we are doing is saying: |
322 | 326 | // * `K` must be able to borrow `Q` |
323 | 326 | // * `R` (the input stream item type) must also be able to borrow `Q` |
324 | 326 | // Note: That K and R do not need to be the same type, they just both need |
325 | 326 | // to be able to borrow a `Q`. |
326 | 326 | K: Borrow<Q>, |
327 | 326 | R: Borrow<Q>, |
328 | 326 | Q: Ord + Hash + Eq + Debug, |
329 | 326 | { |
330 | 326 | let mut state = self.state.lock().await6 ; |
331 | | |
332 | 326 | let lru_len = state.lru.len(); |
333 | 368 | for (key, result) in keys.into_iter().zip(results.iter_mut())326 { |
334 | 368 | let maybe_entry = if peek { Branch (334:34): [True: 0, False: 0]
Branch (334:34): [True: 0, False: 225]
Branch (334:34): [True: 0, False: 0]
Branch (334:34): [True: 0, False: 0]
Branch (334:34): [Folded - Ignored]
Branch (334:34): [True: 0, False: 25]
Branch (334:34): [True: 5, False: 0]
Branch (334:34): [True: 3, False: 0]
Branch (334:34): [True: 4, False: 0]
Branch (334:34): [True: 0, False: 0]
Branch (334:34): [True: 0, False: 0]
Branch (334:34): [True: 0, False: 0]
Branch (334:34): [True: 0, False: 0]
Branch (334:34): [True: 0, False: 1]
Branch (334:34): [True: 0, False: 4]
Branch (334:34): [True: 0, False: 0]
Branch (334:34): [Folded - Ignored]
Branch (334:34): [True: 0, False: 47]
Branch (334:34): [True: 0, False: 54]
|
335 | 12 | state.lru.peek_mut(key.borrow()) |
336 | | } else { |
337 | 356 | state.lru.get_mut(key.borrow()) |
338 | | }; |
339 | 368 | match maybe_entry { |
340 | 211 | Some(entry) => { |
341 | 211 | // Since we are not inserting anythign we don't need to evict based |
342 | 211 | // on the size of the store. |
343 | 211 | // Note: We need to check eviction because the item might be expired |
344 | 211 | // based on the current time. In such case, we remove the item while |
345 | 211 | // we are here. |
346 | 211 | let should_evict = self.should_evict(lru_len, entry, 0, u64::MAX); |
347 | 211 | if !should_evict && peek209 { Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [True: 100, False: 0]
Branch (347:41): [True: 0, False: 100]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [Folded - Ignored]
Branch (347:41): [Folded - Ignored]
Branch (347:24): [True: 13, False: 1]
Branch (347:41): [True: 0, False: 13]
Branch (347:24): [True: 3, False: 1]
Branch (347:41): [True: 3, False: 0]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [True: 3, False: 0]
Branch (347:41): [True: 3, False: 0]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [True: 2, False: 0]
Branch (347:41): [True: 0, False: 2]
Branch (347:24): [True: 0, False: 0]
Branch (347:41): [True: 0, False: 0]
Branch (347:24): [Folded - Ignored]
Branch (347:41): [Folded - Ignored]
Branch (347:24): [True: 34, False: 0]
Branch (347:41): [True: 0, False: 34]
Branch (347:24): [True: 54, False: 0]
Branch (347:41): [True: 0, False: 54]
|
348 | 6 | *result = Some(entry.data.len()); |
349 | 205 | } else if !should_evict && entry.data.touch()203 .await40 { Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 100, False: 0]
Branch (349:48): [True: 100, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [Folded - Ignored]
Branch (349:48): [Folded - Ignored]
Branch (349:31): [True: 13, False: 1]
Branch (349:48): [True: 13, False: 0]
Branch (349:31): [True: 0, False: 1]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [True: 2, False: 0]
Branch (349:48): [True: 1, False: 1]
Branch (349:31): [True: 0, False: 0]
Branch (349:48): [True: 0, False: 0]
Branch (349:31): [Folded - Ignored]
Branch (349:48): [Folded - Ignored]
Branch (349:31): [True: 34, False: 0]
Branch (349:48): [True: 34, False: 0]
Branch (349:31): [True: 54, False: 0]
Branch (349:48): [True: 54, False: 0]
|
350 | 202 | entry.seconds_since_anchor = self.anchor_time.elapsed().as_secs() as i32; |
351 | 202 | *result = Some(entry.data.len()); |
352 | 202 | } else { |
353 | 3 | *result = None; |
354 | 3 | if let Some((key, eviction_item)) = state.lru.pop_entry(key.borrow()) { Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [Folded - Ignored]
Branch (354:32): [True: 1, False: 0]
Branch (354:32): [True: 1, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 1, False: 0]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [Folded - Ignored]
Branch (354:32): [True: 0, False: 0]
Branch (354:32): [True: 0, False: 0]
|
355 | 3 | if should_evict { Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [Folded - Ignored]
Branch (355:32): [True: 1, False: 0]
Branch (355:32): [True: 1, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 1]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [Folded - Ignored]
Branch (355:32): [True: 0, False: 0]
Branch (355:32): [True: 0, False: 0]
|
356 | 2 | event!(Level::INFO, ?key, "Item expired, evicting"0 ); |
357 | | } else { |
358 | 1 | event!(Level::INFO, ?key, "Touch failed, evicting"0 ); |
359 | | } |
360 | 3 | state.remove(key.borrow(), &eviction_item, false).await1 ; |
361 | 0 | } |
362 | | } |
363 | | } |
364 | 157 | None => *result = None, |
365 | | } |
366 | | } |
367 | 326 | } |
368 | | |
369 | 5.00k | pub async fn get<Q>(&self, key: &Q) -> Option<T> |
370 | 5.00k | where |
371 | 5.00k | K: Borrow<Q>, |
372 | 5.00k | Q: Ord + Hash + Eq + Debug, |
373 | 5.00k | { |
374 | 5.00k | let mut state = self.state.lock().await0 ; |
375 | 5.00k | self.evict_items(&mut *state).await0 ; |
376 | | |
377 | 5.00k | let entry4.49k = state.lru.get_mut(key.borrow())?510 ; |
378 | | |
379 | 4.49k | if entry.data.touch().await43 { Branch (379:12): [True: 0, False: 0]
Branch (379:12): [True: 4.45k, False: 0]
Branch (379:12): [True: 0, False: 0]
Branch (379:12): [Folded - Ignored]
Branch (379:12): [True: 1, False: 0]
Branch (379:12): [True: 3, False: 0]
Branch (379:12): [True: 0, False: 0]
Branch (379:12): [True: 1, False: 0]
Branch (379:12): [True: 0, False: 0]
Branch (379:12): [True: 1, False: 0]
Branch (379:12): [True: 0, False: 0]
Branch (379:12): [True: 12, False: 0]
Branch (379:12): [True: 0, False: 0]
Branch (379:12): [True: 4, False: 0]
Branch (379:12): [Folded - Ignored]
Branch (379:12): [True: 20, False: 0]
Branch (379:12): [True: 3, False: 0]
|
380 | 4.49k | entry.seconds_since_anchor = self.anchor_time.elapsed().as_secs() as i32; |
381 | 4.49k | return Some(entry.data.clone()); |
382 | 0 | } |
383 | | |
384 | 0 | let (key, eviction_item) = state.lru.pop_entry(key.borrow())?; |
385 | 0 | event!(Level::INFO, ?key, "Touch failed, evicting"); |
386 | 0 | state.remove(key.borrow(), &eviction_item, false).await; |
387 | 0 | None |
388 | 5.00k | } |
389 | | |
390 | | /// Returns the replaced item if any. |
391 | 5.85k | pub async fn insert(&self, key: K, data: T) -> Option<T> { |
392 | 5.85k | self.insert_with_time(key, data, self.anchor_time.elapsed().as_secs() as i32) |
393 | 17 | .await |
394 | 5.85k | } |
395 | | |
396 | | /// Returns the replaced item if any. |
397 | 5.85k | pub async fn insert_with_time(&self, key: K, data: T, seconds_since_anchor: i32) -> Option<T> { |
398 | 5.85k | let mut state = self.state.lock().await3 ; |
399 | 5.85k | let results = self |
400 | 5.85k | .inner_insert_many(&mut state, [(key, data)], seconds_since_anchor) |
401 | 15 | .await; |
402 | 5.85k | results.into_iter().next() |
403 | 5.85k | } |
404 | | |
405 | | /// Same as insert(), but optimized for multiple inserts. |
406 | | /// Returns the replaced items if any. |
407 | 5 | pub async fn insert_many(&self, inserts: impl IntoIterator<Item = (K, T)>) -> Vec<T> { |
408 | 5 | let mut inserts = inserts.into_iter().peekable(); |
409 | 5 | // Shortcut for cases where there are no inserts, so we don't need to lock. |
410 | 5 | if inserts.peek().is_none() { Branch (410:12): [True: 0, False: 0]
Branch (410:12): [Folded - Ignored]
Branch (410:12): [True: 1, False: 1]
Branch (410:12): [True: 2, False: 1]
Branch (410:12): [Folded - Ignored]
|
411 | 3 | return Vec::new(); |
412 | 2 | } |
413 | 2 | let state = &mut self.state.lock().await0 ; |
414 | 2 | self.inner_insert_many(state, inserts, self.anchor_time.elapsed().as_secs() as i32) |
415 | 0 | .await |
416 | 5 | } |
417 | | |
418 | 5.85k | async fn inner_insert_many( |
419 | 5.85k | &self, |
420 | 5.85k | state: &mut State<K, T>, |
421 | 5.85k | inserts: impl IntoIterator<Item = (K, T)>, |
422 | 5.85k | seconds_since_anchor: i32, |
423 | 5.85k | ) -> Vec<T> { |
424 | 5.85k | let mut replaced_items = Vec::new(); |
425 | 11.7k | for (key, data5.85k ) in inserts { |
426 | 5.85k | let new_item_size = data.len(); |
427 | 5.85k | let eviction_item = EvictionItem { |
428 | 5.85k | seconds_since_anchor, |
429 | 5.85k | data, |
430 | 5.85k | }; |
431 | | |
432 | 5.85k | if let Some(old_item22 ) = state.put(key, eviction_item).await12 { Branch (432:20): [True: 0, False: 0]
Branch (432:20): [True: 8, False: 5.70k]
Branch (432:20): [True: 0, False: 0]
Branch (432:20): [True: 0, False: 0]
Branch (432:20): [True: 0, False: 0]
Branch (432:20): [Folded - Ignored]
Branch (432:20): [True: 1, False: 1]
Branch (432:20): [True: 0, False: 27]
Branch (432:20): [True: 0, False: 3]
Branch (432:20): [True: 0, False: 0]
Branch (432:20): [True: 0, False: 1]
Branch (432:20): [True: 0, False: 3]
Branch (432:20): [True: 0, False: 1]
Branch (432:20): [True: 0, False: 2]
Branch (432:20): [True: 0, False: 2]
Branch (432:20): [True: 1, False: 1]
Branch (432:20): [True: 1, False: 1]
Branch (432:20): [True: 0, False: 1]
Branch (432:20): [True: 5, False: 18]
Branch (432:20): [True: 0, False: 0]
Branch (432:20): [Folded - Ignored]
Branch (432:20): [True: 6, False: 43]
Branch (432:20): [True: 0, False: 25]
|
433 | 22 | replaced_items.push(old_item); |
434 | 5.83k | } |
435 | 5.85k | state.sum_store_size += new_item_size; |
436 | 5.85k | state.lifetime_inserted_bytes.add(new_item_size); |
437 | 5.85k | self.evict_items(state).await3 ; |
438 | | } |
439 | 5.85k | replaced_items |
440 | 5.85k | } |
441 | | |
442 | 11 | pub async fn remove<Q>(&self, key: &Q) -> bool |
443 | 11 | where |
444 | 11 | K: Borrow<Q>, |
445 | 11 | Q: Ord + Hash + Eq + Debug, |
446 | 11 | { |
447 | 11 | let mut state = self.state.lock().await0 ; |
448 | 11 | self.inner_remove(&mut state, key).await0 |
449 | 11 | } |
450 | | |
451 | 12 | async fn inner_remove<Q>(&self, state: &mut State<K, T>, key: &Q) -> bool |
452 | 12 | where |
453 | 12 | K: Borrow<Q>, |
454 | 12 | Q: Ord + Hash + Eq + Debug, |
455 | 12 | { |
456 | 12 | self.evict_items(state).await0 ; |
457 | 12 | if let Some(entry11 ) = state.lru.pop(key.borrow()) { Branch (457:16): [True: 0, False: 0]
Branch (457:16): [Folded - Ignored]
Branch (457:16): [True: 6, False: 0]
Branch (457:16): [True: 1, False: 0]
Branch (457:16): [True: 1, False: 1]
Branch (457:16): [True: 1, False: 0]
Branch (457:16): [True: 1, False: 0]
Branch (457:16): [True: 0, False: 0]
Branch (457:16): [True: 0, False: 0]
Branch (457:16): [True: 0, False: 0]
Branch (457:16): [True: 0, False: 0]
Branch (457:16): [True: 1, False: 0]
Branch (457:16): [True: 0, False: 0]
Branch (457:16): [True: 0, False: 0]
Branch (457:16): [Folded - Ignored]
Branch (457:16): [True: 0, False: 0]
|
458 | 11 | state.remove(key, &entry, false).await0 ; |
459 | 11 | return true; |
460 | 1 | } |
461 | 1 | false |
462 | 12 | } |
463 | | |
464 | | /// Same as remove(), but allows for a conditional to be applied to the entry before removal |
465 | | /// in an atomic fashion. |
466 | 1 | pub async fn remove_if<Q, F: FnOnce(&T) -> bool>(&self, key: &Q, cond: F) -> bool |
467 | 1 | where |
468 | 1 | K: Borrow<Q>, |
469 | 1 | Q: Ord + Hash + Eq + Debug, |
470 | 1 | { |
471 | 1 | let mut state = self.state.lock().await0 ; |
472 | 1 | if let Some(entry) = state.lru.get(key.borrow()) { Branch (472:16): [True: 0, False: 0]
Branch (472:16): [Folded - Ignored]
Branch (472:16): [True: 0, False: 0]
Branch (472:16): [True: 0, False: 0]
Branch (472:16): [True: 0, False: 0]
Branch (472:16): [True: 0, False: 0]
Branch (472:16): [True: 1, False: 0]
Branch (472:16): [True: 0, False: 0]
Branch (472:16): [True: 0, False: 0]
Branch (472:16): [Folded - Ignored]
Branch (472:16): [True: 0, False: 0]
|
473 | 1 | if !cond(&entry.data) { Branch (473:16): [True: 0, False: 0]
Branch (473:16): [Folded - Ignored]
Branch (473:16): [True: 0, False: 0]
Branch (473:16): [True: 0, False: 0]
Branch (473:16): [True: 0, False: 0]
Branch (473:16): [True: 0, False: 0]
Branch (473:16): [True: 0, False: 1]
Branch (473:16): [True: 0, False: 0]
Branch (473:16): [True: 0, False: 0]
Branch (473:16): [Folded - Ignored]
Branch (473:16): [True: 0, False: 0]
|
474 | 0 | return false; |
475 | 1 | } |
476 | 1 | return self.inner_remove(&mut state, key).await0 ; |
477 | 0 | } |
478 | 0 | false |
479 | 1 | } |
480 | | } |