1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use std::{fmt::Debug, hash::Hash};

use anyhow::Result;
use derivative::Derivative;
use moka::sync::SegmentedCache;
use tracing::debug;

use crate::cache::Cache;

pub struct LocalCache<K, V> {
    data: SegmentedCache<K, V>,
}

#[derive(Derivative)]
#[derivative(Default)]
pub struct LocalCacheOption {
    #[derivative(Default(value = "8"))]
    pub segments: usize,
    #[derivative(Default(value = "std::time::Duration::from_secs(5 * 60)"))]
    pub ttl: std::time::Duration,
    #[derivative(Default(value = "1024"))]
    pub max_capacity: u64,
}

impl<K, V> LocalCache<K, V>
where
    K: Hash + Eq + Sync + Send + Clone + 'static,
    V: Sync + Send + Clone + 'static,
{
    pub fn new(opts: LocalCacheOption) -> Self {
        let data = SegmentedCache::builder(opts.segments)
            .time_to_live(opts.ttl)
            .max_capacity(opts.max_capacity)
            .build();

        Self { data }
    }
}

impl<K, V> Cache for LocalCache<K, V>
where
    K: Hash + Eq + Sync + Send + Clone + Debug + 'static,
    V: Sync + Send + Clone + 'static,
{
    type Key = K;
    type Value = V;

    async fn mget(&self, keys: &[Self::Key]) -> Result<Vec<Self::Value>> {
        debug!("autocache: localcache: mget keys: {keys:?}");

        Ok(keys
            .iter()
            .filter_map(|key| self.data.get(key).clone())
            .collect::<Vec<_>>())
    }

    async fn mset(&self, kvs: &[(Self::Key, Self::Value)]) -> Result<()> {
        debug!(
            "autocache: localcache: mset keys: {:?}",
            kvs.iter().map(|(k, _)| k).collect::<Vec<_>>()
        );

        for kv in kvs.into_iter() {
            self.data.insert(kv.0.clone(), kv.1.clone());
        }

        Ok(())
    }

    async fn mdel(&self, keys: &[Self::Key]) -> Result<()> {
        debug!("autocache: localcache: mdel keys: {keys:?}");

        keys.iter().for_each(|key| {
            self.data.remove(key);
        });

        Ok(())
    }

    fn name(&self) -> &'static str {
        "localcache"
    }
}