@@ -22,6 +22,11 @@ use crate::{LfuCache, LruCache};
22
22
23
23
use super :: { lfu, lru} ;
24
24
25
+ #[ cfg( feature = "ttl" ) ]
26
+ use crate :: get_milltimestamp;
27
+ #[ cfg( feature = "ttl" ) ]
28
+ const DEFAULT_CHECK_STEP : u64 = 120 ;
29
+
25
30
/// ARC(Adaptive Replacement Cache): 自适应缓存替换算法,它结合了LRU与LFU,来获得可用缓存的最佳使用。
26
31
/// 设置容量之后将最大保持该容量大小的数据
27
32
/// 后进的数据将会淘汰最久没有被访问的数据
@@ -51,6 +56,15 @@ pub struct ArcCache<K, V, S> {
51
56
ghost_lfu : LruCache < K , V , S > ,
52
57
53
58
cap : usize ,
59
+ /// 下一次检查的时间点,如果大于该时间点则全部检查是否过期
60
+ #[ cfg( feature = "ttl" ) ]
61
+ check_next : u64 ,
62
+ /// 每次大检查点的时间间隔,如果不想启用该特性,可以将该值设成u64::MAX
63
+ #[ cfg( feature = "ttl" ) ]
64
+ check_step : u64 ,
65
+ /// 所有节点中是否存在带ttl的结点,如果均为普通的元素,则过期的将不进行检查
66
+ #[ cfg( feature = "ttl" ) ]
67
+ has_ttl : bool ,
54
68
}
55
69
56
70
impl < K : Hash + Eq , V > Default for ArcCache < K , V , DefaultHasher > {
@@ -78,12 +92,37 @@ impl<K, V, S: Clone> ArcCache<K, V, S> {
78
92
ghost_lfu : LruCache :: with_hasher ( cap, hash_builder) ,
79
93
80
94
cap,
95
+ #[ cfg( feature = "ttl" ) ]
96
+ check_step : DEFAULT_CHECK_STEP ,
97
+ #[ cfg( feature = "ttl" ) ]
98
+ check_next : get_milltimestamp ( ) +DEFAULT_CHECK_STEP * 1000 ,
99
+ #[ cfg( feature = "ttl" ) ]
100
+ has_ttl : false ,
81
101
}
82
102
}
83
103
}
84
104
85
105
impl < K , V , S > ArcCache < K , V , S > {
86
106
107
+ /// 获取当前检查lru的间隔
108
+ #[ cfg( feature="ttl" ) ]
109
+ pub fn get_check_step ( & self ) -> u64 {
110
+ self . check_step
111
+ }
112
+
113
+ /// 设置当前检查lru的间隔
114
+ /// 单位为秒,意思就是每隔多少秒会清理一次数据
115
+ /// 如果数据太大的话遍历一次可能会比较久的时长
116
+ /// 一次清理时间复杂度O(n)
117
+ /// 仅仅在插入时触发检查,获取时仅检查当前元素
118
+ #[ cfg( feature="ttl" ) ]
119
+ pub fn set_check_step ( & mut self , check_step : u64 ) {
120
+ self . check_step = check_step;
121
+ self . check_next = get_milltimestamp ( ) + self . check_step * 1000 ;
122
+ self . main_lru . set_check_step ( check_step) ;
123
+ self . main_lfu . set_check_step ( check_step) ;
124
+ }
125
+
87
126
/// 获取当前容量
88
127
pub fn capacity ( & self ) -> usize {
89
128
self . cap
@@ -245,24 +284,6 @@ impl<K, V, S> ArcCache<K, V, S> {
245
284
}
246
285
247
286
impl < K : Hash + Eq , V , S : BuildHasher > ArcCache < K , V , S > {
248
- // /// 排出当前数据
249
- // ///
250
- // /// ```
251
- // /// use algorithm::ArcCache;
252
- // /// fn main() {
253
- // /// let mut arc = ArcCache::new(3);
254
- // /// arc.insert("hello", "algorithm");
255
- // /// arc.insert("this", "arc");
256
- // /// {
257
- // /// let mut drain = arc.drain();
258
- // /// assert!(drain.next()==Some(("hello", "algorithm")));
259
- // /// }
260
- // /// assert!(arc.len() == 0);
261
- // /// }
262
- // /// ```
263
- // pub fn drain(&mut self) -> Drain<'_, K, V, S> {
264
- // Drain { base: self }
265
- // }
266
287
267
288
/// 弹出栈顶上的数据, 最常使用的数据
268
289
///
@@ -428,6 +449,40 @@ impl<K: Hash + Eq, V, S: BuildHasher> ArcCache<K, V, S> {
428
449
self . get_mut_key_value ( k) . map ( |( _, v) | v)
429
450
}
430
451
452
+ #[ cfg( feature="ttl" ) ]
453
+ pub fn get_mut_key_value < Q > ( & mut self , k : & Q ) -> Option < ( & K , & mut V ) >
454
+ where
455
+ K : Borrow < Q > ,
456
+ Q : Hash + Eq + ?Sized ,
457
+ {
458
+ // {
459
+ // if let Some(v) = self.main_lfu.get_mut_key_value(k) {
460
+ // return Some(v)
461
+ // }
462
+ // }
463
+ if let Some ( ( key, val, ttl) ) = self . main_lru . remove_with_ttl ( k) {
464
+ self . main_lfu . insert_with_ttl ( key, val, ttl) ;
465
+ return self . main_lfu . get_mut_key_value ( k) ;
466
+ }
467
+
468
+ if let Some ( ( key, val, ttl) ) = self . ghost_lfu . remove_with_ttl ( k) {
469
+ self . main_lfu . full_increase ( ) ;
470
+ self . main_lru . full_decrease ( ) ;
471
+ self . main_lfu . insert_with_ttl ( key, val, ttl) ;
472
+ return self . main_lfu . get_mut_key_value ( k) ;
473
+ }
474
+
475
+ if let Some ( ( key, val, ttl) ) = self . ghost_lru . remove_with_ttl ( k) {
476
+ self . main_lru . full_increase ( ) ;
477
+ self . main_lfu . full_decrease ( ) ;
478
+ self . main_lru . insert_with_ttl ( key, val, ttl) ;
479
+ return self . main_lru . get_mut_key_value ( k) ;
480
+ }
481
+ self . main_lfu . get_mut_key_value ( k)
482
+ }
483
+
484
+
485
+ #[ cfg( not( feature="ttl" ) ) ]
431
486
pub fn get_mut_key_value < Q > ( & mut self , k : & Q ) -> Option < ( & K , & mut V ) >
432
487
where
433
488
K : Borrow < Q > ,
@@ -470,11 +525,50 @@ impl<K: Hash + Eq, V, S: BuildHasher> ArcCache<K, V, S> {
470
525
/// assert!(arc.insert("this", "arc good") == Some(&"arc"));
471
526
/// }
472
527
/// ```
528
+ #[ inline( always) ]
473
529
pub fn insert ( & mut self , k : K , v : V ) -> Option < V > {
474
530
self . capture_insert ( k, v) . map ( |( _, v, _) | v)
475
531
}
476
532
533
+ /// 插入带有生存时间的元素
534
+ /// 每次获取像redis一样,并不会更新生存时间
535
+ /// 如果需要更新则需要手动的进行重新设置
536
+ #[ cfg( feature="ttl" ) ]
537
+ #[ inline( always) ]
538
+ pub fn insert_with_ttl ( & mut self , k : K , v : V , ttl : u64 ) -> Option < V > {
539
+ self . capture_insert_with_ttl ( k, v, ttl) . map ( |( _, v, _) | v)
540
+ }
541
+
542
+ #[ inline( always) ]
477
543
pub fn capture_insert ( & mut self , k : K , v : V ) -> Option < ( K , V , bool ) > {
544
+ self . _capture_insert_with_ttl ( k, v, u64:: MAX )
545
+ }
546
+
547
+ #[ cfg( feature = "ttl" ) ]
548
+ #[ inline( always) ]
549
+ pub fn capture_insert_with_ttl ( & mut self , k : K , v : V , ttl : u64 ) -> Option < ( K , V , bool ) > {
550
+ if ttl == 0 { return None } ;
551
+ self . has_ttl = true ;
552
+ self . _capture_insert_with_ttl ( k, v, ttl)
553
+ }
554
+
555
+ #[ cfg( feature = "ttl" ) ]
556
+ #[ allow( unused_variables) ]
557
+ fn _capture_insert_with_ttl ( & mut self , k : K , v : V , ttl : u64 ) -> Option < ( K , V , bool ) > {
558
+ if let Some ( ( key, val, same) ) = self . main_lru . capture_insert_with_ttl ( k, v, ttl) {
559
+ if same {
560
+ Some ( ( key, val, true ) )
561
+ } else {
562
+ self . ghost_lru . capture_insert_with_ttl ( key, val, ttl)
563
+ }
564
+ } else {
565
+ None
566
+ }
567
+ }
568
+
569
+ #[ cfg( not( feature = "ttl" ) ) ]
570
+ #[ allow( unused_variables) ]
571
+ fn _capture_insert_with_ttl ( & mut self , k : K , v : V , ttl : u64 ) -> Option < ( K , V , bool ) > {
478
572
if let Some ( ( key, val, same) ) = self . main_lru . capture_insert ( k, v) {
479
573
if same {
480
574
Some ( ( key, val, true ) )
@@ -528,6 +622,52 @@ impl<K: Hash + Eq, V, S: BuildHasher> ArcCache<K, V, S> {
528
622
}
529
623
530
624
625
+ #[ cfg( feature="ttl" ) ]
626
+ pub fn clear_expire ( & mut self ) {
627
+ if !self . has_ttl {
628
+ return ;
629
+ }
630
+ let now = get_milltimestamp ( ) ;
631
+ if now < self . check_next {
632
+ return ;
633
+ }
634
+ self . check_next = now + self . check_step ;
635
+ self . main_lfu . clear_expire ( ) ;
636
+ self . main_lru . clear_expire ( ) ;
637
+ }
638
+
639
+ #[ cfg( feature="ttl" ) ]
640
+ #[ inline( always) ]
641
+ pub fn del_ttl < Q > ( & mut self , k : & Q )
642
+ where
643
+ K : Borrow < Q > ,
644
+ Q : Hash + Eq + ?Sized , {
645
+ self . set_ttl ( k, u64:: MAX ) ;
646
+ }
647
+
648
+ #[ cfg( feature="ttl" ) ]
649
+ pub fn set_ttl < Q > ( & mut self , k : & Q , expire : u64 ) -> bool
650
+ where
651
+ K : Borrow < Q > ,
652
+ Q : Hash + Eq + ?Sized , {
653
+
654
+ if self . main_lru . set_ttl ( k, expire) {
655
+ return true
656
+ }
657
+ self . main_lfu . set_ttl ( k, expire)
658
+ }
659
+
660
+ #[ cfg( feature="ttl" ) ]
661
+ pub fn get_ttl < Q > ( & mut self , k : & Q ) -> Option < u64 >
662
+ where
663
+ K : Borrow < Q > ,
664
+ Q : Hash + Eq + ?Sized , {
665
+ if let Some ( v) = self . main_lfu . get_ttl ( k) {
666
+ return Some ( v)
667
+ }
668
+ self . main_lru . get_ttl ( k)
669
+ }
670
+
531
671
/// 移除元素
532
672
///
533
673
/// ```
@@ -596,6 +736,12 @@ impl<K: Clone + Hash + Eq, V: Clone, S: Clone + BuildHasher> Clone for ArcCache<
596
736
ghost_lru : self . ghost_lru . clone ( ) ,
597
737
ghost_lfu : self . ghost_lfu . clone ( ) ,
598
738
cap : self . cap ,
739
+ #[ cfg( feature="ttl" ) ]
740
+ check_next : self . check_next ,
741
+ #[ cfg( feature="ttl" ) ]
742
+ check_step : self . check_step ,
743
+ #[ cfg( feature="ttl" ) ]
744
+ has_ttl : self . has_ttl ,
599
745
}
600
746
}
601
747
}
@@ -1225,4 +1371,80 @@ mod tests {
1225
1371
1226
1372
assert ! ( handle. join( ) . is_ok( ) ) ;
1227
1373
}
1374
+
1375
+
1376
+ #[ test]
1377
+ #[ cfg( feature="ttl" ) ]
1378
+ fn test_ttl_cache ( ) {
1379
+ let mut lru = ArcCache :: new ( 3 ) ;
1380
+ lru. insert_with_ttl ( "help" , "ok" , 1 ) ;
1381
+ lru. insert_with_ttl ( "author" , "tickbh" , 2 ) ;
1382
+ assert_eq ! ( lru. len( ) , 2 ) ;
1383
+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
1384
+ assert_eq ! ( lru. get( "help" ) , None ) ;
1385
+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
1386
+ assert_eq ! ( lru. get( "author" ) , None ) ;
1387
+ assert_eq ! ( lru. len( ) , 0 ) ;
1388
+ }
1389
+
1390
+ #[ test]
1391
+ #[ cfg( feature="ttl" ) ]
1392
+ fn test_ttl_check_cache ( ) {
1393
+ let mut lru = ArcCache :: new ( 3 ) ;
1394
+ lru. set_check_step ( 1 ) ;
1395
+ lru. insert_with_ttl ( "help" , "ok" , 1 ) ;
1396
+ lru. insert ( "now" , "algorithm" ) ;
1397
+ assert_eq ! ( lru. len( ) , 2 ) ;
1398
+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
1399
+ assert_eq ! ( lru. len( ) , 2 ) ;
1400
+ lru. insert_with_ttl ( "author" , "tickbh" , 3 ) ;
1401
+ assert_eq ! ( lru. len( ) , 2 ) ;
1402
+ assert_eq ! ( lru. get( "help" ) , None ) ;
1403
+ assert_eq ! ( lru. len( ) , 2 ) ;
1404
+ }
1405
+
1406
+ #[ test]
1407
+ #[ cfg( feature="ttl" ) ]
1408
+ fn test_ttl_del ( ) {
1409
+ let mut lru = ArcCache :: new ( 3 ) ;
1410
+ lru. insert_with_ttl ( "help" , "ok" , 1 ) ;
1411
+ lru. insert_with_ttl ( "author" , "tickbh" , 2 ) ;
1412
+ assert_eq ! ( lru. len( ) , 2 ) ;
1413
+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
1414
+ assert_eq ! ( lru. get( "help" ) , None ) ;
1415
+ lru. del_ttl ( & "author" ) ;
1416
+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
1417
+ assert_eq ! ( lru. get( "author" ) , Some ( & "tickbh" ) ) ;
1418
+ assert_eq ! ( lru. len( ) , 1 ) ;
1419
+ }
1420
+
1421
+ #[ test]
1422
+ #[ cfg( feature="ttl" ) ]
1423
+ fn test_ttl_set ( ) {
1424
+ let mut lru = ArcCache :: new ( 3 ) ;
1425
+ lru. insert_with_ttl ( "help" , "ok" , 1 ) ;
1426
+ lru. insert_with_ttl ( "author" , "tickbh" , 2 ) ;
1427
+ lru. set_ttl ( & "help" , 3 ) ;
1428
+ assert_eq ! ( lru. len( ) , 2 ) ;
1429
+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
1430
+ assert_eq ! ( lru. get( "help" ) , Some ( & "ok" ) ) ;
1431
+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
1432
+ assert_eq ! ( lru. get( "author" ) , None ) ;
1433
+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
1434
+ assert_eq ! ( lru. get( "help" ) , None ) ;
1435
+ assert_eq ! ( lru. len( ) , 0 ) ;
1436
+ }
1437
+
1438
+
1439
+ #[ test]
1440
+ #[ cfg( feature="ttl" ) ]
1441
+ fn test_ttl_get ( ) {
1442
+ let mut lru = ArcCache :: new ( 3 ) ;
1443
+ lru. insert_with_ttl ( "help" , "ok" , 1 ) ;
1444
+ lru. insert_with_ttl ( "author" , "tickbh" , 2 ) ;
1445
+ lru. insert ( "now" , "algorithm" ) ;
1446
+ assert_eq ! ( lru. get_ttl( & "help" ) , Some ( 1 ) ) ;
1447
+ assert_eq ! ( lru. get_ttl( & "author" ) , Some ( 2 ) ) ;
1448
+ assert_eq ! ( lru. get_ttl( & "now" ) , Some ( u64 :: MAX ) ) ;
1449
+ }
1228
1450
}
0 commit comments