@@ -23,7 +23,7 @@ pub trait CacheBacking<K, V>
2323
2424#[ cfg( feature = "lru-cache" ) ]
2525pub struct LruCacheBacking < K , V > {
26- lru : LruCache < K , V >
26+ lru : LruCache < K , V > ,
2727}
2828
2929#[ cfg( feature = "lru-cache" ) ]
@@ -93,10 +93,27 @@ impl<
9393#[ cfg( feature = "ttl-cache" ) ]
9494pub struct TtlCacheBacking < K , V > {
9595 ttl : Duration ,
96- expiry_queue : VecDeque < ( K , Instant ) > ,
96+ expiry_queue : VecDeque < TTlEntry < K > > ,
9797 map : HashMap < K , ( V , Instant ) > ,
9898}
9999
100+ #[ cfg( feature = "ttl-cache" ) ]
101+ struct TTlEntry < K > {
102+ key : K ,
103+ expiry : Instant ,
104+
105+ }
106+
107+ #[ cfg( feature = "ttl-cache" ) ]
108+ impl < K > From < ( K , Instant ) > for TTlEntry < K > {
109+ fn from ( tuple : ( K , Instant ) ) -> Self {
110+ Self {
111+ key : tuple. 0 ,
112+ expiry : tuple. 1 ,
113+ }
114+ }
115+ }
116+
100117#[ cfg( feature = "ttl-cache" ) ]
101118impl <
102119 K : Eq + Hash + Sized + Clone + Send ,
@@ -117,21 +134,21 @@ impl<
117134 fn set ( & mut self , key : K , value : V ) -> Option < V > {
118135 self . remove_old ( ) ;
119136 let expiry = Instant :: now ( ) . add ( self . ttl ) ;
120- let option = self . map . insert ( key. clone ( ) , ( value, expiry) ) ;
121- if option. is_some ( ) {
122- self . expiry_queue . retain ( |( vec_key, _) | vec_key. ne ( & key) ) ;
137+ let result = self . replace ( key. clone ( ) , value, expiry) ;
138+ match self . expiry_queue . binary_search_by_key ( & expiry, |entry| entry. expiry ) {
139+ Ok ( found) => {
140+ self . expiry_queue . insert ( found + 1 , ( key, expiry) . into ( ) ) ;
141+ }
142+ Err ( idx) => {
143+ self . expiry_queue . insert ( idx, ( key, expiry) . into ( ) ) ;
144+ }
123145 }
124- self . expiry_queue . push_back ( ( key, expiry) ) ;
125- option. map ( |( value, _) | value)
146+ result
126147 }
127148
128149 fn remove ( & mut self , key : & K ) -> Option < V > {
129150 self . remove_old ( ) ;
130- let option = self . map . remove ( key) ;
131- if option. is_some ( ) {
132- self . expiry_queue . retain ( |( vec_key, _) | vec_key. ne ( & key) ) ;
133- }
134- option. map ( |( value, _) | value)
151+ self . remove_key ( key)
135152 }
136153
137154 fn contains_key ( & self , key : & K ) -> bool {
@@ -154,7 +171,8 @@ impl<
154171 . collect :: < Vec < K > > ( ) ;
155172 for key in keys. into_iter ( ) {
156173 self . map . remove ( & key) ;
157- self . expiry_queue . retain ( |( expiry_key, _) | expiry_key. ne ( & key) )
174+ // optimize looping through expiry_queue multiple times?
175+ self . expiry_queue . retain ( |entry| entry. key . ne ( & key) )
158176 }
159177 }
160178
@@ -165,7 +183,7 @@ impl<
165183}
166184
167185#[ cfg( feature = "ttl-cache" ) ]
168- impl < K : Hash + Sized + PartialEq + Eq , V > TtlCacheBacking < K , V > {
186+ impl < K : Eq + Hash + Sized + Clone + Send , V : Sized + Clone + Send > TtlCacheBacking < K , V > {
169187 pub fn new ( ttl : Duration ) -> TtlCacheBacking < K , V > {
170188 TtlCacheBacking {
171189 ttl,
@@ -176,18 +194,80 @@ impl<K: Hash + Sized + PartialEq + Eq, V> TtlCacheBacking<K, V> {
176194
177195 fn remove_old ( & mut self ) {
178196 let now = Instant :: now ( ) ;
179- while let Some ( ( key , expiry ) ) = self . expiry_queue . pop_front ( ) {
180- if now. lt ( & expiry) {
181- self . expiry_queue . push_front ( ( key , expiry ) ) ;
197+ while let Some ( entry ) = self . expiry_queue . pop_front ( ) {
198+ if now. lt ( & entry . expiry ) {
199+ self . expiry_queue . push_front ( entry ) ;
182200 break ;
183201 }
184- self . map . remove ( & key) ;
202+ self . map . remove ( & entry. key ) ;
203+ }
204+ }
205+
206+ fn replace ( & mut self , key : K , value : V , expiry : Instant ) -> Option < V > {
207+ let entry = self . map . insert ( key. clone ( ) , ( value, expiry) ) ;
208+ self . cleanup_expiry ( entry, & key)
209+ }
210+
211+ fn remove_key ( & mut self , key : & K ) -> Option < V > {
212+ let entry = self . map . remove ( key) ;
213+ self . cleanup_expiry ( entry, key)
214+ }
215+
216+ fn cleanup_expiry ( & mut self , entry : Option < ( V , Instant ) > , key : & K ) -> Option < V > {
217+ if let Some ( ( value, old_expiry) ) = entry {
218+ match self . expiry_queue . binary_search_by_key ( & old_expiry, |entry| entry. expiry ) {
219+ Ok ( found) => {
220+ let index = self . expiry_index_on_key_eq ( found, & old_expiry, key) ;
221+ if let Some ( index) = index {
222+ self . expiry_queue . remove ( index) ;
223+ } else {
224+ // expiry not found (key)???
225+ }
226+ }
227+ Err ( _) => {
228+ // expiry not found???
229+ }
230+ }
231+ Some ( value)
232+ } else {
233+ None
234+ }
235+ }
236+
237+ fn expiry_index_on_key_eq ( & self , idx : usize , expiry : & Instant , key : & K ) -> Option < usize > {
238+ let entry = self . expiry_queue . get ( idx) . unwrap ( ) ;
239+ if entry. key . eq ( key) {
240+ return Some ( idx) ;
241+ }
242+
243+ let mut offset = 0 ;
244+ while idx - offset > 0 {
245+ offset += 1 ;
246+ let entry = self . expiry_queue . get ( idx - offset) . unwrap ( ) ;
247+ if !entry. expiry . eq ( expiry) {
248+ break ;
249+ }
250+ if entry. key . eq ( key) {
251+ return Some ( idx - offset) ;
252+ }
253+ }
254+ offset = 0 ;
255+ while idx + offset < self . expiry_queue . len ( ) {
256+ offset += 1 ;
257+ let entry = self . expiry_queue . get ( idx + offset) . unwrap ( ) ;
258+ if !entry. expiry . eq ( expiry) {
259+ break ;
260+ }
261+ if entry. key . eq ( key) {
262+ return Some ( idx + offset) ;
263+ }
185264 }
265+ None
186266 }
187267}
188268
189269pub struct HashMapBacking < K , V > {
190- map : HashMap < K , V >
270+ map : HashMap < K , V > ,
191271}
192272
193273impl <
0 commit comments