Skip to content

Commit 82d454f

Browse files
committed
feat: better hits ratio
Signed-off-by: Chojan Shang <psiace@apache.org>
1 parent 69a907c commit 82d454f

File tree

4 files changed

+55
-54
lines changed

4 files changed

+55
-54
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/common/cache/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ heapsize = ["heapsize_"]
1919
bytes = { workspace = true }
2020
hashbrown = "0.14"
2121
hashlink = "0.8"
22+
indexmap = "1.9.2"
2223

2324
[target.'cfg(not(target_os = "macos"))'.dependencies]
2425
heapsize_ = { package = "heapsize", version = "0.4.2", optional = true }

src/common/cache/src/cache/lru.rs

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ use std::hash::Hash;
6161
use hashbrown::hash_map::DefaultHashBuilder;
6262
use hashlink::linked_hash_map;
6363
use hashlink::LinkedHashMap;
64+
use indexmap::IndexMap;
6465

6566
use crate::cache::Cache;
6667
use crate::meter::count_meter::Count;
@@ -75,7 +76,8 @@ pub struct LruCache<
7576
M: CountableMeter<K, V> = Count,
7677
> {
7778
map: LinkedHashMap<K, V, S>,
78-
visited: LinkedHashMap<K, bool>,
79+
visited: IndexMap<K, bool>,
80+
hand: u64,
7981
current_measure: M::Measure,
8082
max_capacity: u64,
8183
meter: M,
@@ -93,7 +95,8 @@ impl<K: Eq + Hash + Clone, V> LruCache<K, V> {
9395
pub fn new(capacity: u64) -> Self {
9496
LruCache {
9597
map: LinkedHashMap::new(),
96-
visited: LinkedHashMap::new(),
98+
visited: IndexMap::new(),
99+
hand: 0,
97100
current_measure: (),
98101
max_capacity: capacity,
99102
meter: Count,
@@ -138,7 +141,8 @@ impl<K: Eq + Hash + Clone, V, M: CountableMeter<K, V>> LruCache<K, V, DefaultHas
138141
pub fn with_meter(capacity: u64, meter: M) -> LruCache<K, V, DefaultHashBuilder, M> {
139142
LruCache {
140143
map: LinkedHashMap::new(),
141-
visited: LinkedHashMap::new(),
144+
visited: IndexMap::new(),
145+
hand: 0,
142146
current_measure: Default::default(),
143147
max_capacity: capacity,
144148
meter,
@@ -151,7 +155,8 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher> LruCache<K, V, S, Count> {
151155
pub fn with_hasher(capacity: u64, hash_builder: S) -> LruCache<K, V, S, Count> {
152156
LruCache {
153157
map: LinkedHashMap::with_hasher(hash_builder),
154-
visited: LinkedHashMap::new(),
158+
visited: IndexMap::new(),
159+
hand: 0,
155160
current_measure: (),
156161
max_capacity: capacity,
157162
meter: Count,
@@ -161,24 +166,39 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher> LruCache<K, V, S, Count> {
161166

162167
impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> LruCache<K, V, S, M> {
163168
fn find_evict_candidate(&mut self) -> Option<K> {
169+
let length = self.visited.len() as u64;
164170
let mut p: Option<K> = None;
165-
for (key, value) in self.visited.iter_mut() {
166-
if !(*value) && p.is_none() {
167-
p = Some(key.clone())
168-
}
169-
if *value {
170-
*value = false;
171+
let mut count = self.hand;
172+
if count > length - length / 5 {
173+
count = 0
174+
}
175+
let mut iter = self.visited.iter_mut().skip(count as usize);
176+
for (key, value) in &mut iter {
177+
if *value == false && p.is_none() {
178+
p = Some(key.clone());
179+
break;
171180
}
181+
count = count + 1;
182+
*value = false;
172183
}
184+
self.hand = count;
173185
p
174186
}
175187

176188
fn peek_evict_candidate(&self) -> Option<K> {
189+
let length = self.visited.len() as u64;
177190
let mut p: Option<K> = None;
178-
for (key, value) in self.visited.iter() {
179-
if !(*value) && p.is_none() {
180-
p = Some(key.clone())
191+
let mut count = self.hand;
192+
if count > length - length / 5 {
193+
count = 0
194+
}
195+
let iter = self.visited.iter().skip(count as usize);
196+
for (key, value) in iter {
197+
if *value == false && p.is_none() {
198+
p = Some(key.clone());
199+
break;
181200
}
201+
count = count + 1;
182202
}
183203
p
184204
}
@@ -192,7 +212,8 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
192212
fn with_meter_and_hasher(capacity: u64, meter: M, hash_builder: S) -> Self {
193213
LruCache {
194214
map: LinkedHashMap::with_hasher(hash_builder),
195-
visited: LinkedHashMap::new(),
215+
visited: IndexMap::new(),
216+
hand: 0,
196217
current_measure: Default::default(),
197218
max_capacity: capacity,
198219
meter,
@@ -225,19 +246,10 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
225246
K: Borrow<Q>,
226247
Q: Hash + Eq + ?Sized,
227248
{
228-
match self.map.raw_entry_mut().from_key(k) {
229-
linked_hash_map::RawEntryMut::Occupied(occupied) => {
230-
match self.visited.raw_entry_mut().from_key(k) {
231-
// Since the element has been accessed, we set a flag.
232-
linked_hash_map::RawEntryMut::Occupied(mut occupied) => {
233-
occupied.replace_value(true);
234-
}
235-
linked_hash_map::RawEntryMut::Vacant(_) => (),
236-
}
237-
Some(occupied.into_mut())
238-
}
239-
linked_hash_map::RawEntryMut::Vacant(_) => None,
249+
if let Some(v) = self.visited.get_mut(k) {
250+
*v = true;
240251
}
252+
self.map.get(k)
241253
}
242254

243255
/// Returns a reference to the value corresponding to the key in the cache or `None` if it is
@@ -283,7 +295,7 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
283295
if let Some(old_key) = self.peek_evict_candidate() {
284296
self.map.get_key_value(&old_key)
285297
} else {
286-
self.map.front()
298+
None
287299
}
288300
}
289301

@@ -325,19 +337,12 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
325337
fn put(&mut self, k: K, v: V) -> Option<V> {
326338
let new_size = self.meter.measure(&k, &v);
327339
self.current_measure = self.meter.add(self.current_measure, new_size);
328-
if let Some(old) = self.map.get(&k) {
329-
match self.visited.raw_entry_mut().from_key(&k) {
330-
// Since the key has been accessed, we set a flag.
331-
linked_hash_map::RawEntryMut::Occupied(mut occupied) => {
332-
occupied.replace_value(true);
333-
}
334-
linked_hash_map::RawEntryMut::Vacant(_) => (),
335-
}
340+
match self.map.get(&k) {
341+
Some(old) => {
336342
self.current_measure = self
337343
.meter
338-
.sub(self.current_measure, self.meter.measure(&k, old));
339-
} else {
340-
self.visited.replace(k.clone(), false);
344+
.sub(self.current_measure, self.meter.measure(&k, old));},
345+
None => {self.visited.insert(k.clone(), false);}
341346
}
342347
let old_val = self.map.replace(k, v);
343348
while self.size() > self.capacity() {
@@ -395,20 +400,14 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
395400
fn pop_by_policy(&mut self) -> Option<(K, V)> {
396401
if let Some(old_key) = self.find_evict_candidate() {
397402
self.map.remove_entry(&old_key).map(|(k, v)| {
398-
self.visited.remove_entry(&old_key);
403+
self.visited.remove(&old_key);
399404
self.current_measure = self
400405
.meter
401406
.sub(self.current_measure, self.meter.measure(&k, &v));
402407
(k, v)
403408
})
404409
} else {
405-
self.map.pop_front().map(|(k, v)| {
406-
self.visited.pop_front();
407-
self.current_measure = self
408-
.meter
409-
.sub(self.current_measure, self.meter.measure(&k, &v));
410-
(k, v)
411-
})
410+
None
412411
}
413412
}
414413

src/common/cache/tests/it/cache/lru.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ fn test_debug() {
9595
cache.get(&3);
9696
assert_eq!(format!("{:?}", cache), "{6: 60, 3: 30, 2: 22}");
9797
cache.set_capacity(2);
98-
assert_eq!(format!("{:?}", cache), "{6: 60, 3: 30}");
98+
assert_eq!(format!("{:?}", cache), "{3: 30, 2: 22}");
9999
}
100100

101101
#[test]
@@ -115,7 +115,7 @@ fn test_remove() {
115115
cache.put(8, 80);
116116
assert!(cache.get(&5).is_none());
117117
assert_eq!(cache.get(&6), Some(&60));
118-
assert_eq!(cache.get(&7), Some(&70));
118+
assert_eq!(cache.get(&7), None);
119119
assert_eq!(cache.get(&8), Some(&80));
120120
}
121121

@@ -139,24 +139,24 @@ fn test_iter() {
139139
cache.put(4, 40);
140140
cache.put(5, 50);
141141
assert_eq!(cache.iter().collect::<Vec<_>>(), [
142+
(&2, &20),
142143
(&3, &30),
143-
(&4, &40),
144144
(&5, &50)
145145
]);
146146
assert_eq!(cache.iter_mut().collect::<Vec<_>>(), [
147+
(&2, &mut 20),
147148
(&3, &mut 30),
148-
(&4, &mut 40),
149149
(&5, &mut 50)
150150
]);
151151
assert_eq!(cache.iter().rev().collect::<Vec<_>>(), [
152152
(&5, &50),
153-
(&4, &40),
154-
(&3, &30)
153+
(&3, &30),
154+
(&2, &20)
155155
]);
156156
assert_eq!(cache.iter_mut().rev().collect::<Vec<_>>(), [
157157
(&5, &mut 50),
158-
(&4, &mut 40),
159-
(&3, &mut 30)
158+
(&3, &mut 30),
159+
(&2, &mut 20)
160160
]);
161161
}
162162

0 commit comments

Comments
 (0)