Skip to content

Commit 18cc5d3

Browse files
committedJun 24, 2024·
add ttl
1 parent 4cd9314 commit 18cc5d3

File tree

8 files changed

+987
-119
lines changed

8 files changed

+987
-119
lines changed
 

‎Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[package]
22
name = "algorithm"
3-
version = "0.1.6"
3+
version = "0.1.7"
44
edition = "2021"
55
authors = ["tickbh <tickdream125@hotmail.com>"]
6-
description = "about algorithm data structure, now has lru/lru-k/lfu/slab/rbtree/roaring_bitmap/timer_wheelss, 关于算法常用的数据结构"
6+
description = "about algorithm data structure, now has ttl with lru/lru-k/lfu/arc and slab/rbtree/roaring_bitmap/timer_wheelss, 关于算法常用的数据结构"
77
repository = "https://github.com/tickbh/algorithm-rs"
88
license = "Apache-2.0"
99
keywords = ["arc", "lru", "lfu", "timerwheel", "slab"]
@@ -24,5 +24,6 @@ opt-level = 3
2424
debug = true
2525

2626
[features]
27+
default = ["hashbrown", "ttl"]
2728
hashbrown=[]
2829
ttl=[]

‎src/arr/fix_vec.rs

+17-39
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::cmp::Ordering;
2-
use std::ptr::NonNull;
32

43
#[derive(Debug)]
54
struct FixedVecNode<T> {
@@ -400,10 +399,16 @@ impl<T> FixedVec<T> {
400399
/// ```
401400
#[inline]
402401
pub fn iter_mut(&mut self) -> FixedVecIterMut<'_, T> {
403-
let head = self.head;
404-
let tail = self.tail;
405-
let len = self.len();
406-
FixedVecIterMut::new(&mut self.nodes, head, tail, len)
402+
FixedVecIterMut {
403+
head: self.head,
404+
tail: self.tail,
405+
len: self.len(),
406+
list: self,
407+
}
408+
// let head = self.head;
409+
// let tail = self.tail;
410+
// let len = self.len();
411+
// FixedVecIterMut::new(self, head, tail, len)
407412
}
408413

409414
fn reorder(&mut self) {
@@ -670,46 +675,23 @@ impl<'a, T> DoubleEndedIterator for FixedVecIter<'a, T> {
670675
}
671676
}
672677

678+
#[derive(Debug)]
673679
pub struct FixedVecIterMut<'a, T> {
674-
ptr: NonNull<Option<FixedVecNode<T>>>,
680+
list: &'a mut FixedVec<T>,
675681
head: usize,
676682
tail: usize,
677683
len: usize,
678-
_marker: std::marker::PhantomData<&'a mut T>,
679-
}
680-
681-
impl<'a, T> FixedVecIterMut<'a, T> {
682-
#[allow(unsafe_code)]
683-
fn new(
684-
slice: &'a mut [Option<FixedVecNode<T>>],
685-
head: usize,
686-
tail: usize,
687-
len: usize,
688-
) -> Self {
689-
let ptr = slice.as_mut_ptr();
690-
Self {
691-
ptr: unsafe { NonNull::new_unchecked(ptr) },
692-
head,
693-
tail,
694-
len,
695-
_marker: std::marker::PhantomData,
696-
}
697-
}
698684
}
699685

700686
impl<'a, T> Iterator for FixedVecIterMut<'a, T> {
701687
type Item = (usize, &'a mut T);
702688

703-
#[allow(unsafe_code)]
704689
fn next(&mut self) -> Option<Self::Item> {
705690
if self.len > 0 {
706691
let head = self.head;
707-
let node_ref = unsafe {
708-
let ptr = NonNull::new_unchecked(self.ptr.as_ptr().add(head)).as_ptr();
709-
&mut *ptr
692+
let node = unsafe {
693+
core::mem::transmute::<&'_ mut FixedVecNode<T>, &'a mut FixedVecNode<T>>(self.list.node_mut(head).unwrap())
710694
};
711-
712-
let node = node_ref.as_mut().unwrap();
713695
self.head = node.next;
714696
self.len -= 1;
715697
Some((head, &mut node.data))
@@ -724,21 +706,17 @@ impl<'a, T> Iterator for FixedVecIterMut<'a, T> {
724706
}
725707

726708
impl<'a, T> DoubleEndedIterator for FixedVecIterMut<'a, T> {
727-
#[allow(unsafe_code)]
728709
fn next_back(&mut self) -> Option<Self::Item> {
729710
if self.len > 0 {
730711
let tail = self.tail;
731-
let node_ref = unsafe {
732-
let ptr = NonNull::new_unchecked(self.ptr.as_ptr().add(tail)).as_ptr();
733-
&mut *ptr
712+
let node = unsafe {
713+
core::mem::transmute::<&'_ mut FixedVecNode<T>, &'a mut FixedVecNode<T>>(self.list.node_mut(tail).unwrap())
734714
};
735-
736-
let node = node_ref.as_mut().unwrap();
737715
self.tail = node.prev;
738716
self.len -= 1;
739717
Some((tail, &mut node.data))
740718
} else {
741719
None
742720
}
743721
}
744-
}
722+
}

‎src/cache/arc.rs

+240-18
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ use crate::{LfuCache, LruCache};
2222

2323
use super::{lfu, lru};
2424

25+
#[cfg(feature = "ttl")]
26+
use crate::get_milltimestamp;
27+
#[cfg(feature = "ttl")]
28+
const DEFAULT_CHECK_STEP: u64 = 120;
29+
2530
/// ARC(Adaptive Replacement Cache): 自适应缓存替换算法,它结合了LRU与LFU,来获得可用缓存的最佳使用。
2631
/// 设置容量之后将最大保持该容量大小的数据
2732
/// 后进的数据将会淘汰最久没有被访问的数据
@@ -51,6 +56,15 @@ pub struct ArcCache<K, V, S> {
5156
ghost_lfu: LruCache<K, V, S>,
5257

5358
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,
5468
}
5569

5670
impl<K: Hash + Eq, V> Default for ArcCache<K, V, DefaultHasher> {
@@ -78,12 +92,37 @@ impl<K, V, S: Clone> ArcCache<K, V, S> {
7892
ghost_lfu: LruCache::with_hasher(cap, hash_builder),
7993

8094
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,
81101
}
82102
}
83103
}
84104

85105
impl<K, V, S> ArcCache<K, V, S> {
86106

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+
87126
/// 获取当前容量
88127
pub fn capacity(&self) -> usize {
89128
self.cap
@@ -245,24 +284,6 @@ impl<K, V, S> ArcCache<K, V, S> {
245284
}
246285

247286
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-
// }
266287

267288
/// 弹出栈顶上的数据, 最常使用的数据
268289
///
@@ -428,6 +449,40 @@ impl<K: Hash + Eq, V, S: BuildHasher> ArcCache<K, V, S> {
428449
self.get_mut_key_value(k).map(|(_, v)| v)
429450
}
430451

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"))]
431486
pub fn get_mut_key_value<Q>(&mut self, k: &Q) -> Option<(&K, &mut V)>
432487
where
433488
K: Borrow<Q>,
@@ -470,11 +525,50 @@ impl<K: Hash + Eq, V, S: BuildHasher> ArcCache<K, V, S> {
470525
/// assert!(arc.insert("this", "arc good") == Some(&"arc"));
471526
/// }
472527
/// ```
528+
#[inline(always)]
473529
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
474530
self.capture_insert(k, v).map(|(_, v, _)| v)
475531
}
476532

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)]
477543
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)> {
478572
if let Some((key, val, same)) = self.main_lru.capture_insert(k, v) {
479573
if same {
480574
Some((key, val, true))
@@ -528,6 +622,52 @@ impl<K: Hash + Eq, V, S: BuildHasher> ArcCache<K, V, S> {
528622
}
529623

530624

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+
531671
/// 移除元素
532672
///
533673
/// ```
@@ -596,6 +736,12 @@ impl<K: Clone + Hash + Eq, V: Clone, S: Clone + BuildHasher> Clone for ArcCache<
596736
ghost_lru: self.ghost_lru.clone(),
597737
ghost_lfu: self.ghost_lfu.clone(),
598738
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,
599745
}
600746
}
601747
}
@@ -1225,4 +1371,80 @@ mod tests {
12251371

12261372
assert!(handle.join().is_ok());
12271373
}
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+
}
12281450
}

‎src/cache/lfu.rs

+315-16
Large diffs are not rendered by default.

‎src/cache/lru.rs

+60-19
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{HashMap, DefaultHasher};
1818
use super::{KeyRef, KeyWrapper};
1919

2020
#[cfg(feature = "ttl")]
21-
use crate::{get_timestamp};
21+
use crate::get_milltimestamp;
2222
#[cfg(feature = "ttl")]
2323
const DEFAULT_CHECK_STEP: u64 = 120;
2424
/// Lru节点数据
@@ -74,7 +74,7 @@ impl<K, V> LruEntry<K, V> {
7474
#[cfg(feature = "ttl")]
7575
#[inline(always)]
7676
pub fn is_expire(&self) -> bool {
77-
get_timestamp() >= self.expire
77+
get_milltimestamp() >= self.expire
7878
}
7979

8080

@@ -83,6 +83,16 @@ impl<K, V> LruEntry<K, V> {
8383
pub fn is_little(&self, time: &u64) -> bool {
8484
time >= &self.expire
8585
}
86+
87+
#[cfg(feature = "ttl")]
88+
#[inline(always)]
89+
pub fn get_ttl(&self) -> u64 {
90+
if self.expire == u64::MAX {
91+
self.expire
92+
} else {
93+
self.expire.saturating_sub(get_milltimestamp()) / 1000
94+
}
95+
}
8696
}
8797

8898

@@ -158,7 +168,7 @@ impl<K, V, S> LruCache<K, V, S> {
158168
#[cfg(feature = "ttl")]
159169
check_step: DEFAULT_CHECK_STEP,
160170
#[cfg(feature = "ttl")]
161-
check_next: get_timestamp()+DEFAULT_CHECK_STEP,
171+
check_next: get_milltimestamp()+DEFAULT_CHECK_STEP * 1000,
162172
#[cfg(feature = "ttl")]
163173
has_ttl: false,
164174
}
@@ -178,7 +188,7 @@ impl<K, V, S> LruCache<K, V, S> {
178188
#[cfg(feature="ttl")]
179189
pub fn set_check_step(&mut self, check_step: u64) {
180190
self.check_step = check_step;
181-
self.check_next = get_timestamp() + self.check_step;
191+
self.check_next = get_milltimestamp() + self.check_step * 1000;
182192
}
183193

184194
/// 获取当前容量
@@ -647,8 +657,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
647657
#[cfg(feature="ttl")]
648658
#[inline(always)]
649659
pub fn insert_with_ttl(&mut self, k: K, v: V, ttl: u64) -> Option<V> {
650-
self.has_ttl = true;
651-
self._capture_insert_with_ttl(k, v, ttl).map(|(_, v, _)| v)
660+
self.capture_insert_with_ttl(k, v, ttl).map(|(_, v, _)| v)
652661
}
653662

654663
#[inline(always)]
@@ -658,8 +667,10 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
658667

659668
#[cfg(feature = "ttl")]
660669
#[inline(always)]
661-
pub fn capture_insert_with_ttl(&mut self, k: K, v: V) -> Option<(K, V, bool)> {
662-
self._capture_insert_with_ttl(k, v, u64::MAX)
670+
pub fn capture_insert_with_ttl(&mut self, k: K, v: V, ttl: u64) -> Option<(K, V, bool)> {
671+
if ttl == 0 { return None };
672+
self.has_ttl = true;
673+
self._capture_insert_with_ttl(k, v, ttl)
663674
}
664675

665676
#[allow(unused_variables)]
@@ -676,7 +687,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
676687
}
677688
#[cfg(feature="ttl")]
678689
unsafe {
679-
(*entry_ptr).expire = ttl.saturating_add(get_timestamp());
690+
(*entry_ptr).expire = ttl.saturating_mul(1000).saturating_add(get_milltimestamp());
680691
}
681692
self.detach(entry_ptr);
682693
self.attach(entry_ptr);
@@ -689,7 +700,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
689700
self.attach(entry_ptr);
690701
#[cfg(feature="ttl")]
691702
unsafe {
692-
(*entry_ptr).expire = ttl.saturating_add(get_timestamp());
703+
(*entry_ptr).expire = ttl.saturating_mul(1000).saturating_add(get_milltimestamp());
693704
}
694705
unsafe {
695706
self.map
@@ -732,7 +743,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
732743
if !self.has_ttl {
733744
return;
734745
}
735-
let now = get_timestamp();
746+
let now = get_milltimestamp();
736747
if now < self.check_next {
737748
return;
738749
}
@@ -763,15 +774,18 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
763774
}
764775

765776
#[cfg(feature="ttl")]
766-
pub fn set_ttl<Q>(&mut self, k: &Q, expire: u64)
777+
pub fn set_ttl<Q>(&mut self, k: &Q, expire: u64) -> bool
767778
where
768779
K: Borrow<Q>,
769780
Q: Hash + Eq + ?Sized, {
770781
if let Some(v) = self.get_node(&k) {
771782
self.has_ttl = true;
772783
unsafe {
773-
(*v).expire = get_timestamp().saturating_add(expire);
784+
(*v).expire = get_milltimestamp().saturating_add(expire.saturating_mul(1000));
774785
}
786+
true
787+
} else {
788+
false
775789
}
776790
}
777791

@@ -782,11 +796,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
782796
Q: Hash + Eq + ?Sized, {
783797
if let Some(v) = self.get_node(&k) {
784798
unsafe {
785-
if (*v).expire == u64::MAX {
786-
Some((*v).expire)
787-
} else {
788-
Some((*v).expire.saturating_sub(get_timestamp()))
789-
}
799+
Some((*v).get_ttl())
790800
}
791801
} else {
792802
None
@@ -809,12 +819,43 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
809819
where
810820
K: Borrow<Q>,
811821
Q: Hash + Eq + ?Sized,
822+
{
823+
if let Some(node) = self.remove_node(k) {
824+
unsafe {
825+
Some((node.key.assume_init(), node.val.assume_init()))
826+
}
827+
} else {
828+
None
829+
}
830+
}
831+
832+
833+
#[cfg(feature="ttl")]
834+
pub fn remove_with_ttl<Q>(&mut self, k: &Q) -> Option<(K, V, u64)>
835+
where
836+
K: Borrow<Q>,
837+
Q: Hash + Eq + ?Sized,
838+
{
839+
if let Some(node) = self.remove_node(k) {
840+
unsafe {
841+
let ttl = node.get_ttl();
842+
Some((node.key.assume_init(), node.val.assume_init(), ttl))
843+
}
844+
} else {
845+
None
846+
}
847+
}
848+
849+
fn remove_node<Q>(&mut self, k: &Q) -> Option<LruEntry<K, V>>
850+
where
851+
K: Borrow<Q>,
852+
Q: Hash + Eq + ?Sized,
812853
{
813854
match self.map.remove(KeyWrapper::from_ref(k)) {
814855
Some(l) => unsafe {
815856
self.detach(l.as_ptr());
816857
let node = *Box::from_raw(l.as_ptr());
817-
Some((node.key.assume_init(), node.val.assume_init()))
858+
Some(node)
818859
},
819860
None => None,
820861
}

‎src/cache/lruk.rs

+345-23
Large diffs are not rendered by default.

‎src/cache/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ pub use lfu::LfuCache;
1313
pub use arc::ArcCache;
1414
pub use slab::{Slab, Reinit};
1515

16-
#[derive(Clone)]
1716
struct KeyRef<K> {
1817
pub k: *const K,
1918
}
@@ -24,6 +23,12 @@ impl<K> KeyRef<K> {
2423
}
2524
}
2625

26+
impl<K> Clone for KeyRef<K> {
27+
fn clone(&self) -> Self {
28+
Self { k: self.k }
29+
}
30+
}
31+
2732
impl<K: Hash> Hash for KeyRef<K> {
2833
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2934
unsafe {

0 commit comments

Comments
 (0)
Please sign in to comment.