substrate/cache/mod.rs
1//! Caching utilities.
2
3use std::{
4 any::Any,
5 sync::{Arc, Mutex},
6};
7
8use cache::{CacheHandle, Cacheable, CacheableWithState, mem::TypeCache, multi::MultiCache};
9use serde::{Serialize, de::DeserializeOwned};
10
11#[cfg(test)]
12mod tests;
13
14/// A cache with APIs for in-memory and persistent caching.
15#[derive(Default, Debug, Clone)]
16pub struct Cache {
17 inner: Arc<Mutex<CacheInner>>,
18}
19
20#[derive(Default, Debug)]
21struct CacheInner {
22 type_cache: TypeCache,
23 cache: MultiCache,
24}
25
26impl Cache {
27 /// Creates a new [`Cache`] with the provided [`MultiCache`] configuration.
28 pub fn new(cache: MultiCache) -> Self {
29 Self {
30 inner: Arc::new(Mutex::new(CacheInner {
31 type_cache: TypeCache::new(),
32 cache,
33 })),
34 }
35 }
36
37 /// Gets a handle to a cacheable object from the cache, generating the object in the background
38 /// if needed.
39 ///
40 /// If configured, persists data to disk.
41 ///
42 /// Does not cache errors, so any errors thrown should be thrown quickly. Any errors that need
43 /// to be cached should be included in the cached output or should be cached using
44 /// [`Cache::get_with_err`].
45 pub fn get<K: Cacheable>(
46 &self,
47 namespace: impl Into<String>,
48 key: K,
49 ) -> CacheHandle<Result<K::Output, K::Error>> {
50 let mut inner = self.inner.lock().unwrap();
51 inner.cache.get(namespace, key)
52 }
53
54 /// Gets a handle to a cacheable object from the cache, caching failures as well.
55 ///
56 /// Generates the object in the background if needed and persists data to disk according to
57 /// configuration.
58 pub fn get_with_err<
59 E: Send + Sync + Serialize + DeserializeOwned + Any,
60 K: Cacheable<Error = E>,
61 >(
62 &self,
63 namespace: impl Into<String>,
64 key: K,
65 ) -> CacheHandle<Result<K::Output, K::Error>> {
66 let mut inner = self.inner.lock().unwrap();
67 inner.cache.get_with_err(namespace, key)
68 }
69
70 /// Gets a handle to a cacheable object from the cache, generating the object in the background
71 /// if needed.
72 ///
73 /// If configured, persists data to disk.
74 ///
75 /// Does not cache errors, so any errors thrown should be thrown quickly. Any errors that need
76 /// to be cached should be included in the cached output or should be cached using
77 /// [`Cache::get_with_state_and_err`].
78 pub fn get_with_state<S: Send + Sync + Any, K: CacheableWithState<S>>(
79 &self,
80 namespace: impl Into<String>,
81 key: K,
82 state: S,
83 ) -> CacheHandle<Result<K::Output, K::Error>> {
84 let mut inner = self.inner.lock().unwrap();
85 inner.cache.get_with_state(namespace, key, state)
86 }
87
88 /// Gets a handle to a cacheable object from the cache, caching failures as well.
89 ///
90 /// Generates the object in the background if needed and persists data to disk according to
91 /// configuration.
92 ///
93 /// See [`Cache::get_with_err`] and [`Cache::get_with_state`] for related examples.
94 pub fn get_with_state_and_err<
95 S: Send + Sync + Any,
96 E: Send + Sync + Serialize + DeserializeOwned + Any,
97 K: CacheableWithState<S, Error = E>,
98 >(
99 &self,
100 namespace: impl Into<String>,
101 key: K,
102 state: S,
103 ) -> CacheHandle<Result<K::Output, K::Error>> {
104 let mut inner = self.inner.lock().unwrap();
105 inner.cache.get_with_state_and_err(namespace, key, state)
106 }
107
108 /// Gets a handle to a cacheable object from the cache, generating the object in the background
109 /// if needed.
110 ///
111 /// Only caches data in memory.
112 pub fn type_get<K: Cacheable>(
113 &self,
114 key: K,
115 ) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
116 let mut inner = self.inner.lock().unwrap();
117 inner.type_cache.generate(key, |key| key.generate())
118 }
119
120 /// Gets a handle to a cacheable object from the cache, generating the object in the background
121 /// if needed.
122 ///
123 /// Only caches data in memory.
124 ///
125 /// **Note:** The state is not used to determine whether the object should be regenerated. As
126 /// such, it should not impact the output of this function but rather should only be used to
127 /// store collateral or reuse computation from other function calls.
128 ///
129 /// However, the entries generated with different state types are not interchangeable. That is,
130 /// getting the same key with different states will regenerate the key several times, once for
131 /// each state type `S`.
132 pub fn type_get_with_state<S: Send + Sync + Any, K: CacheableWithState<S>>(
133 &self,
134 key: K,
135 state: S,
136 ) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
137 let mut inner = self.inner.lock().unwrap();
138 inner
139 .type_cache
140 .generate_with_state(key, state, |key, state| key.generate_with_state(state))
141 }
142}