1 #![deny(unsafe_code)]
2 
3 //! Caching handle into the [ArcSwapAny].
4 //!
5 //! The [Cache] keeps a copy of the internal [Arc] for faster access.
6 //!
7 //! [Arc]: std::sync::Arc
8 
9 use std::ops::Deref;
10 use std::sync::atomic::Ordering;
11 
12 use super::ref_cnt::RefCnt;
13 use super::strategy::Strategy;
14 use super::ArcSwapAny;
15 
16 /// Generalization of caches providing access to `T`.
17 ///
18 /// This abstracts over all kinds of caches that can provide a cheap access to values of type `T`.
19 /// This is useful in cases where some code doesn't care if the `T` is the whole structure or just
20 /// a part of it.
21 ///
22 /// See the example at [`Cache::map`].
23 pub trait Access<T> {
24     /// Loads the value from cache.
25     ///
26     /// This revalidates the value in the cache, then provides the access to the cached value.
load(&mut self) -> &T27     fn load(&mut self) -> &T;
28 }
29 
30 /// Caching handle for [`ArcSwapAny`][ArcSwapAny].
31 ///
32 /// Instead of loading the [`Arc`][Arc] on every request from the shared storage, this keeps
33 /// another copy inside itself. Upon request it only cheaply revalidates it is up to
34 /// date. If it is, access is significantly faster. If it is stale, the [load_full] is done and the
35 /// cache value is replaced. Under a read-heavy loads, the measured speedup are 10-25 times,
36 /// depending on the architecture.
37 ///
38 /// There are, however, downsides:
39 ///
40 /// * The handle needs to be kept around by the caller (usually, one per thread). This is fine if
41 ///   there's one global `ArcSwapAny`, but starts being tricky with eg. data structures build from
42 ///   them.
43 /// * As it keeps a copy of the [Arc] inside the cache, the old value may be kept alive for longer
44 ///   period of time ‒ it is replaced by the new value on [load][Cache::load]. You may not want to
45 ///   use this if dropping the old value in timely manner is important (possibly because of
46 ///   releasing large amount of RAM or because of closing file handles).
47 ///
48 /// # Examples
49 ///
50 /// ```rust
51 /// # fn do_something<V>(_v: V) { }
52 /// use std::sync::Arc;
53 /// use std::sync::atomic::{AtomicBool, Ordering};
54 ///
55 /// use arc_swap::{ArcSwap, Cache};
56 ///
57 /// let shared = Arc::new(ArcSwap::from_pointee(42));
58 /// # let mut threads = Vec::new();
59 /// let terminate = Arc::new(AtomicBool::new(false));
60 /// // Start 10 worker threads...
61 /// for _ in 0..10 {
62 ///     let mut cache = Cache::new(Arc::clone(&shared));
63 ///     let terminate = Arc::clone(&terminate);
64 ///     # let thread =
65 ///     std::thread::spawn(move || {
66 ///         // Keep loading it like mad..
67 ///         while !terminate.load(Ordering::Relaxed) {
68 ///             let value = cache.load();
69 ///             do_something(value);
70 ///         }
71 ///     });
72 ///     # threads.push(thread);
73 /// }
74 /// shared.store(Arc::new(12));
75 /// # terminate.store(true, Ordering::Relaxed);
76 /// # for thread in threads { thread.join().unwrap() }
77 /// ```
78 ///
79 /// Another one with using a thread local storage and explicit types:
80 ///
81 /// ```rust
82 /// # use std::sync::Arc;
83 /// # use std::ops::Deref;
84 /// # use std::cell::RefCell;
85 /// #
86 /// # use arc_swap::ArcSwap;
87 /// # use arc_swap::cache::Cache;
88 /// # use once_cell::sync::Lazy;
89 /// #
90 /// # #[derive(Debug, Default)]
91 /// # struct Config;
92 /// #
93 /// static CURRENT_CONFIG: Lazy<ArcSwap<Config>> = Lazy::new(|| ArcSwap::from_pointee(Config::default()));
94 ///
95 /// thread_local! {
96 ///     static CACHE: RefCell<Cache<&'static ArcSwap<Config>, Arc<Config>>> = RefCell::new(Cache::from(CURRENT_CONFIG.deref()));
97 /// }
98 ///
99 /// CACHE.with(|c| {
100 ///     // * RefCell needed, because load on cache is `&mut`.
101 ///     // * You want to operate inside the `with` ‒ cloning the Arc is comparably expensive as
102 ///     //   ArcSwap::load itself and whatever you'd save by the cache would be lost on that.
103 ///     println!("{:?}", c.borrow_mut().load());
104 /// });
105 /// ```
106 ///
107 /// [Arc]: std::sync::Arc
108 /// [load_full]: ArcSwapAny::load_full
109 #[derive(Clone, Debug)]
110 pub struct Cache<A, T> {
111     arc_swap: A,
112     cached: T,
113 }
114 
115 impl<A, T, S> Cache<A, T>
116 where
117     A: Deref<Target = ArcSwapAny<T, S>>,
118     T: RefCnt,
119     S: Strategy<T>,
120 {
121     /// Creates a new caching handle.
122     ///
123     /// The parameter is something dereferencing into an [`ArcSwapAny`] (eg. either to [`ArcSwap`]
124     /// or [`ArcSwapOption`]). That can be [`ArcSwapAny`] itself, but that's not very useful. But
125     /// it also can be a reference to it or `Arc`, which makes it possible to share the
126     /// [`ArcSwapAny`] with multiple caches or access it in non-cached way too.
127     ///
128     /// [`ArcSwapOption`]: crate::ArcSwapOption
129     /// [`ArcSwap`]: crate::ArcSwap
new(arc_swap: A) -> Self130     pub fn new(arc_swap: A) -> Self {
131         let cached = arc_swap.load_full();
132         Self { arc_swap, cached }
133     }
134 
135     /// Gives access to the (possibly shared) cached [`ArcSwapAny`].
arc_swap(&self) -> &A::Target136     pub fn arc_swap(&self) -> &A::Target {
137         &self.arc_swap
138     }
139 
140     /// Loads the currently held value.
141     ///
142     /// This first checks if the cached value is up to date. This check is very cheap.
143     ///
144     /// If it is up to date, the cached value is simply returned without additional costs. If it is
145     /// outdated, a load is done on the underlying shared storage. The newly loaded value is then
146     /// stored in the cache and returned.
147     #[inline]
load(&mut self) -> &T148     pub fn load(&mut self) -> &T {
149         self.revalidate();
150         self.load_no_revalidate()
151     }
152 
153     #[inline]
load_no_revalidate(&self) -> &T154     fn load_no_revalidate(&self) -> &T {
155         &self.cached
156     }
157 
158     #[inline]
revalidate(&mut self)159     fn revalidate(&mut self) {
160         let cached_ptr = RefCnt::as_ptr(&self.cached);
161         // Node: Relaxed here is fine. We do not synchronize any data through this, we already have
162         // it synchronized in self.cache. We just want to check if it changed, if it did, the
163         // load_full will be responsible for any synchronization needed.
164         let shared_ptr = self.arc_swap.ptr.load(Ordering::Relaxed);
165         if cached_ptr != shared_ptr {
166             self.cached = self.arc_swap.load_full();
167         }
168     }
169 
170     /// Turns this cache into a cache with a projection inside the cached value.
171     ///
172     /// You'd use this in case when some part of code needs access to fresh values of `U`, however
173     /// a bigger structure containing `U` is provided by this cache. The possibility of giving the
174     /// whole structure to the part of the code falls short in terms of reusability (the part of
175     /// the code could be used within multiple contexts, each with a bigger different structure
176     /// containing `U`) and code separation (the code shouldn't needs to know about the big
177     /// structure).
178     ///
179     /// # Warning
180     ///
181     /// As the provided `f` is called inside every [`load`][Access::load], this one should be
182     /// cheap. Most often it is expected to be just a closure taking reference of some inner field.
183     ///
184     /// For the same reasons, it should not have side effects and should never panic (these will
185     /// not break Rust's safety rules, but might produce behaviour you don't expect).
186     ///
187     /// # Examples
188     ///
189     /// ```rust
190     /// use arc_swap::ArcSwap;
191     /// use arc_swap::cache::{Access, Cache};
192     ///
193     /// struct InnerCfg {
194     ///     answer: usize,
195     /// }
196     ///
197     /// struct FullCfg {
198     ///     inner: InnerCfg,
199     /// }
200     ///
201     /// fn use_inner<A: Access<InnerCfg>>(cache: &mut A) {
202     ///     let value = cache.load();
203     ///     println!("The answer is: {}", value.answer);
204     /// }
205     ///
206     /// let full_cfg = ArcSwap::from_pointee(FullCfg {
207     ///     inner: InnerCfg {
208     ///         answer: 42,
209     ///     }
210     /// });
211     /// let cache = Cache::new(&full_cfg);
212     /// use_inner(&mut cache.map(|full| &full.inner));
213     ///
214     /// let inner_cfg = ArcSwap::from_pointee(InnerCfg { answer: 24 });
215     /// let mut inner_cache = Cache::new(&inner_cfg);
216     /// use_inner(&mut inner_cache);
217     /// ```
map<F, U>(self, f: F) -> MapCache<A, T, F> where F: FnMut(&T) -> &U,218     pub fn map<F, U>(self, f: F) -> MapCache<A, T, F>
219     where
220         F: FnMut(&T) -> &U,
221     {
222         MapCache {
223             inner: self,
224             projection: f,
225         }
226     }
227 }
228 
229 impl<A, T, S> Access<T::Target> for Cache<A, T>
230 where
231     A: Deref<Target = ArcSwapAny<T, S>>,
232     T: Deref<Target = <T as RefCnt>::Base> + RefCnt,
233     S: Strategy<T>,
234 {
load(&mut self) -> &T::Target235     fn load(&mut self) -> &T::Target {
236         self.load().deref()
237     }
238 }
239 
240 impl<A, T, S> From<A> for Cache<A, T>
241 where
242     A: Deref<Target = ArcSwapAny<T, S>>,
243     T: RefCnt,
244     S: Strategy<T>,
245 {
from(arc_swap: A) -> Self246     fn from(arc_swap: A) -> Self {
247         Self::new(arc_swap)
248     }
249 }
250 
251 /// An implementation of a cache with a projection into the accessed value.
252 ///
253 /// This is the implementation structure for [`Cache::map`]. It can't be created directly and it
254 /// should be used through the [`Access`] trait.
255 #[derive(Clone, Debug)]
256 pub struct MapCache<A, T, F> {
257     inner: Cache<A, T>,
258     projection: F,
259 }
260 
261 impl<A, T, S, F, U> Access<U> for MapCache<A, T, F>
262 where
263     A: Deref<Target = ArcSwapAny<T, S>>,
264     T: RefCnt,
265     S: Strategy<T>,
266     F: FnMut(&T) -> &U,
267 {
load(&mut self) -> &U268     fn load(&mut self) -> &U {
269         (self.projection)(self.inner.load())
270     }
271 }
272 
273 #[cfg(test)]
274 mod tests {
275     use std::sync::Arc;
276 
277     use super::*;
278     use crate::{ArcSwap, ArcSwapOption};
279 
280     #[test]
cached_value()281     fn cached_value() {
282         let a = ArcSwap::from_pointee(42);
283         let mut c1 = Cache::new(&a);
284         let mut c2 = Cache::new(&a);
285 
286         assert_eq!(42, **c1.load());
287         assert_eq!(42, **c2.load());
288 
289         a.store(Arc::new(43));
290         assert_eq!(42, **c1.load_no_revalidate());
291         assert_eq!(43, **c1.load());
292     }
293 
294     #[test]
cached_through_arc()295     fn cached_through_arc() {
296         let a = Arc::new(ArcSwap::from_pointee(42));
297         let mut c = Cache::new(Arc::clone(&a));
298         assert_eq!(42, **c.load());
299         a.store(Arc::new(0));
300         drop(a); // A is just one handle, the ArcSwap is kept alive by the cache.
301     }
302 
303     #[test]
cache_option()304     fn cache_option() {
305         let a = ArcSwapOption::from_pointee(42);
306         let mut c = Cache::new(&a);
307 
308         assert_eq!(42, **c.load().as_ref().unwrap());
309         a.store(None);
310         assert!(c.load().is_none());
311     }
312 
313     struct Inner {
314         answer: usize,
315     }
316 
317     struct Outer {
318         inner: Inner,
319     }
320 
321     #[test]
map_cache()322     fn map_cache() {
323         let a = ArcSwap::from_pointee(Outer {
324             inner: Inner { answer: 42 },
325         });
326 
327         let mut cache = Cache::new(&a);
328         let mut inner = cache.clone().map(|outer| &outer.inner);
329         let mut answer = cache.clone().map(|outer| &outer.inner.answer);
330 
331         assert_eq!(42, cache.load().inner.answer);
332         assert_eq!(42, inner.load().answer);
333         assert_eq!(42, *answer.load());
334 
335         a.store(Arc::new(Outer {
336             inner: Inner { answer: 24 },
337         }));
338 
339         assert_eq!(24, cache.load().inner.answer);
340         assert_eq!(24, inner.load().answer);
341         assert_eq!(24, *answer.load());
342     }
343 }
344