Line data Source code
1 : use std::ops::{Deref, DerefMut};
2 : use std::time::{Duration, Instant};
3 :
4 : use moka::Expiry;
5 :
6 : use crate::control_plane::messages::ControlPlaneErrorMessage;
7 :
8 : /// Default TTL used when caching errors from control plane.
9 : pub const DEFAULT_ERROR_TTL: Duration = Duration::from_secs(30);
10 :
11 : /// A generic trait which exposes types of cache's key and value,
12 : /// as well as the notion of cache entry invalidation.
13 : /// This is useful for [`Cached`].
14 : pub(crate) trait Cache {
15 : /// Entry's key.
16 : type Key;
17 :
18 : /// Entry's value.
19 : type Value;
20 :
21 : /// Invalidate an entry using a lookup info.
22 : /// We don't have an empty default impl because it's error-prone.
23 : fn invalidate(&self, _: &Self::Key);
24 : }
25 :
26 : impl<C: Cache> Cache for &C {
27 : type Key = C::Key;
28 : type Value = C::Value;
29 :
30 6 : fn invalidate(&self, info: &Self::Key) {
31 6 : C::invalidate(self, info);
32 6 : }
33 : }
34 :
35 : /// Wrapper for convenient entry invalidation.
36 : pub(crate) struct Cached<C: Cache, V = <C as Cache>::Value> {
37 : /// Cache + lookup info.
38 : pub(crate) token: Option<(C, C::Key)>,
39 :
40 : /// The value itself.
41 : pub(crate) value: V,
42 : }
43 :
44 : impl<C: Cache, V> Cached<C, V> {
45 : /// Place any entry into this wrapper; invalidation will be a no-op.
46 1 : pub(crate) fn new_uncached(value: V) -> Self {
47 1 : Self { token: None, value }
48 1 : }
49 :
50 : /// Drop this entry from a cache if it's still there.
51 6 : pub(crate) fn invalidate(self) -> V {
52 6 : if let Some((cache, info)) = &self.token {
53 6 : cache.invalidate(info);
54 6 : }
55 6 : self.value
56 6 : }
57 :
58 : /// Tell if this entry is actually cached.
59 16 : pub(crate) fn cached(&self) -> bool {
60 16 : self.token.is_some()
61 16 : }
62 : }
63 :
64 : impl<C: Cache, V> Deref for Cached<C, V> {
65 : type Target = V;
66 :
67 0 : fn deref(&self) -> &Self::Target {
68 0 : &self.value
69 0 : }
70 : }
71 :
72 : impl<C: Cache, V> DerefMut for Cached<C, V> {
73 0 : fn deref_mut(&mut self) -> &mut Self::Target {
74 0 : &mut self.value
75 0 : }
76 : }
77 :
78 : pub type ControlPlaneResult<T> = Result<T, Box<ControlPlaneErrorMessage>>;
79 :
80 : #[derive(Clone, Copy)]
81 : pub struct CplaneExpiry {
82 : pub error: Duration,
83 : }
84 :
85 : impl Default for CplaneExpiry {
86 15 : fn default() -> Self {
87 15 : Self {
88 15 : error: DEFAULT_ERROR_TTL,
89 15 : }
90 15 : }
91 : }
92 :
93 : impl CplaneExpiry {
94 29 : pub fn expire_early<V>(
95 29 : &self,
96 29 : value: &ControlPlaneResult<V>,
97 29 : updated: Instant,
98 29 : ) -> Option<Duration> {
99 29 : match value {
100 25 : Ok(_) => None,
101 4 : Err(err) => Some(self.expire_err_early(err, updated)),
102 : }
103 29 : }
104 :
105 4 : pub fn expire_err_early(&self, err: &ControlPlaneErrorMessage, updated: Instant) -> Duration {
106 4 : err.status
107 4 : .as_ref()
108 4 : .and_then(|s| s.details.retry_info.as_ref())
109 4 : .map_or(self.error, |r| r.retry_at.into_std() - updated)
110 4 : }
111 : }
112 :
113 : impl<K, V> Expiry<K, ControlPlaneResult<V>> for CplaneExpiry {
114 24 : fn expire_after_create(
115 24 : &self,
116 24 : _key: &K,
117 24 : value: &ControlPlaneResult<V>,
118 24 : created_at: Instant,
119 24 : ) -> Option<Duration> {
120 24 : self.expire_early(value, created_at)
121 24 : }
122 :
123 5 : fn expire_after_update(
124 5 : &self,
125 5 : _key: &K,
126 5 : value: &ControlPlaneResult<V>,
127 5 : updated_at: Instant,
128 5 : _duration_until_expiry: Option<Duration>,
129 5 : ) -> Option<Duration> {
130 5 : self.expire_early(value, updated_at)
131 5 : }
132 : }
|