@@ -61,6 +61,7 @@ use std::hash::Hash;
61
61
use hashbrown:: hash_map:: DefaultHashBuilder ;
62
62
use hashlink:: linked_hash_map;
63
63
use hashlink:: LinkedHashMap ;
64
+ use indexmap:: IndexMap ;
64
65
65
66
use crate :: cache:: Cache ;
66
67
use crate :: meter:: count_meter:: Count ;
@@ -75,7 +76,8 @@ pub struct LruCache<
75
76
M : CountableMeter < K , V > = Count ,
76
77
> {
77
78
map : LinkedHashMap < K , V , S > ,
78
- visited : LinkedHashMap < K , bool > ,
79
+ visited : IndexMap < K , bool > ,
80
+ hand : u64 ,
79
81
current_measure : M :: Measure ,
80
82
max_capacity : u64 ,
81
83
meter : M ,
@@ -93,7 +95,8 @@ impl<K: Eq + Hash + Clone, V> LruCache<K, V> {
93
95
pub fn new ( capacity : u64 ) -> Self {
94
96
LruCache {
95
97
map : LinkedHashMap :: new ( ) ,
96
- visited : LinkedHashMap :: new ( ) ,
98
+ visited : IndexMap :: new ( ) ,
99
+ hand : 0 ,
97
100
current_measure : ( ) ,
98
101
max_capacity : capacity,
99
102
meter : Count ,
@@ -138,7 +141,8 @@ impl<K: Eq + Hash + Clone, V, M: CountableMeter<K, V>> LruCache<K, V, DefaultHas
138
141
pub fn with_meter ( capacity : u64 , meter : M ) -> LruCache < K , V , DefaultHashBuilder , M > {
139
142
LruCache {
140
143
map : LinkedHashMap :: new ( ) ,
141
- visited : LinkedHashMap :: new ( ) ,
144
+ visited : IndexMap :: new ( ) ,
145
+ hand : 0 ,
142
146
current_measure : Default :: default ( ) ,
143
147
max_capacity : capacity,
144
148
meter,
@@ -151,7 +155,8 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher> LruCache<K, V, S, Count> {
151
155
pub fn with_hasher ( capacity : u64 , hash_builder : S ) -> LruCache < K , V , S , Count > {
152
156
LruCache {
153
157
map : LinkedHashMap :: with_hasher ( hash_builder) ,
154
- visited : LinkedHashMap :: new ( ) ,
158
+ visited : IndexMap :: new ( ) ,
159
+ hand : 0 ,
155
160
current_measure : ( ) ,
156
161
max_capacity : capacity,
157
162
meter : Count ,
@@ -161,24 +166,39 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher> LruCache<K, V, S, Count> {
161
166
162
167
impl < K : Eq + Hash + Clone , V , S : BuildHasher , M : CountableMeter < K , V > > LruCache < K , V , S , M > {
163
168
fn find_evict_candidate ( & mut self ) -> Option < K > {
169
+ let length = self . visited . len ( ) as u64 ;
164
170
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 ;
171
180
}
181
+ count = count + 1 ;
182
+ * value = false ;
172
183
}
184
+ self . hand = count;
173
185
p
174
186
}
175
187
176
188
fn peek_evict_candidate ( & self ) -> Option < K > {
189
+ let length = self . visited . len ( ) as u64 ;
177
190
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 ;
181
200
}
201
+ count = count + 1 ;
182
202
}
183
203
p
184
204
}
@@ -192,7 +212,8 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
192
212
fn with_meter_and_hasher ( capacity : u64 , meter : M , hash_builder : S ) -> Self {
193
213
LruCache {
194
214
map : LinkedHashMap :: with_hasher ( hash_builder) ,
195
- visited : LinkedHashMap :: new ( ) ,
215
+ visited : IndexMap :: new ( ) ,
216
+ hand : 0 ,
196
217
current_measure : Default :: default ( ) ,
197
218
max_capacity : capacity,
198
219
meter,
@@ -225,19 +246,10 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
225
246
K : Borrow < Q > ,
226
247
Q : Hash + Eq + ?Sized ,
227
248
{
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 ;
240
251
}
252
+ self . map . get ( k)
241
253
}
242
254
243
255
/// 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,
283
295
if let Some ( old_key) = self . peek_evict_candidate ( ) {
284
296
self . map . get_key_value ( & old_key)
285
297
} else {
286
- self . map . front ( )
298
+ None
287
299
}
288
300
}
289
301
@@ -325,19 +337,12 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
325
337
fn put ( & mut self , k : K , v : V ) -> Option < V > {
326
338
let new_size = self . meter . measure ( & k, & v) ;
327
339
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) => {
336
342
self . current_measure = self
337
343
. 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 ) ; }
341
346
}
342
347
let old_val = self . map . replace ( k, v) ;
343
348
while self . size ( ) > self . capacity ( ) {
@@ -395,20 +400,14 @@ impl<K: Eq + Hash + Clone, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K,
395
400
fn pop_by_policy ( & mut self ) -> Option < ( K , V ) > {
396
401
if let Some ( old_key) = self . find_evict_candidate ( ) {
397
402
self . map . remove_entry ( & old_key) . map ( |( k, v) | {
398
- self . visited . remove_entry ( & old_key) ;
403
+ self . visited . remove ( & old_key) ;
399
404
self . current_measure = self
400
405
. meter
401
406
. sub ( self . current_measure , self . meter . measure ( & k, & v) ) ;
402
407
( k, v)
403
408
} )
404
409
} 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
412
411
}
413
412
}
414
413
0 commit comments