1use lru::{LruCache, DefaultHasher};
42use std::hash::Hash;
43use std::num::NonZeroUsize;
44use std::ops::DerefMut;
45use std::time::{Duration, Instant};
46use std::sync::{Arc, Condvar, Mutex};
47use std::any::Any;
48
49#[derive(Debug, PartialEq, Clone, Copy)]
50enum EntryStatus {
51 AVAILABLE,
52 CALCULATING,
53 READY,
54 FAILED,
55}
56
57#[derive(Debug, Clone)]
58struct Entry<D> {
59 data: D,
60 adhoc_code: u8,
61 expiration: Instant,
62 status: EntryStatus,
63 cond_var: Arc<Condvar>
64}
65
66impl<D: PartialEq> PartialEq for Entry<D> {
67 fn eq(&self, other: &Self) -> bool {
68 self.data == other.data &&
69 self.adhoc_code == other.adhoc_code &&
70 self.expiration == other.expiration &&
71 self.status == other.status
72 }
73}
74
75
76impl<D: Default> Entry<D> {
77
78 fn default() -> Self {
79 Entry {
80 data: Default::default(),
81 expiration: Instant::now(),
82 adhoc_code: 0,
83 status: EntryStatus::AVAILABLE,
84 cond_var: Arc::new(Condvar::new())
85 }
86 }
87
88
89 fn new(data: D, expiration: Instant, adhoc_code: u8) -> Self {
90 Entry {
91 data,
92 expiration,
93 adhoc_code,
94 status: EntryStatus::AVAILABLE,
95 cond_var: Arc::new(Condvar::new())
96 }
97 }
98
99 fn is_valid(&self) -> bool {
100 self.expiration > Instant::now()
101 }
102
103}
104
105pub type MissHandler<K, D> = fn(&K, &mut D, &mut u8, &[&dyn Any]) -> bool;
106
107pub struct Cache<K, D> {
108 lru_cache: Arc<Mutex<LruCache<K, Arc<Mutex<Entry<D>>>>>>,
109 miss_handler: MissHandler<K, D>,
110 positive_ttl: Duration, negative_ttl: Duration, }
113
114impl<K: Eq + Hash + Clone, D: Default + Clone> Cache<K, D> {
115 pub fn new(
116 size: usize,
117 miss_handler: MissHandler<K, D>,
118 positive_ttl: Duration,
119 negative_ttl: Duration,
120 ) -> Self {
121 let hash_builder = DefaultHasher::default();
122 Cache {
123 lru_cache: Arc::new(Mutex::new(LruCache::with_hasher(
124 NonZeroUsize::new(size).unwrap(),
125 hash_builder,
126 ))),
127 miss_handler,
128 positive_ttl,
129 negative_ttl,
130 }
131 }
132
133 pub fn insert(&self, key: &K, data: D) {
134 let expiration = Instant::now() + self.positive_ttl;
135 let entry = Entry::new(data, expiration, 0);
136 let entry_arc = Arc::new(Mutex::new(entry));
137 self.lru_cache.lock().unwrap().put(key.clone(), entry_arc);
138 }
139
140 pub fn get(&self, key: &K) -> Option<D> {
141 if let Some(entry_arc) = self.get_entry(&key) {
142 let entry = entry_arc.lock().unwrap();
143 return Some(entry.data.clone());
144 }
145 None
146 }
147
148 pub fn update(&self, key: &K, data: D) -> bool {
149 if let Some(entry_arc) = self.get_entry(&key) {
150 let mut entry = entry_arc.lock().unwrap();
151 entry.data = data;
152 entry.expiration = Instant::now() + self.positive_ttl;
153 entry.cond_var.notify_all(); return true;
155 }
156 false
157 }
158
159 fn get_entry(&self, key: &K) -> Option<Arc<Mutex<Entry<D>>>> {
160 let cache_entry = {
162 let mut cache = self.lru_cache.lock().unwrap();
163 cache.get(key).map(|entry| Arc::clone(entry))
164 };
165 match cache_entry {
167 None => return None,
168 Some(entry_arc) => {
169 let entry = entry_arc.lock().unwrap();
170 if entry.is_valid() {
171 return Some(Arc::clone(&entry_arc));
172 }
173 }
174 }
175 self.lru_cache.lock().unwrap().pop(key);
177 None
178 }
179
180 pub fn len(&self) -> usize {
181 self.lru_cache.lock().unwrap().len()
182 }
183
184 fn handle_hit(&self, key: &K) -> Option<(D, u8)> {
185 if let Some(entry_arc) = self.get_entry(key) {
187 let entry_arc_clone = Arc::clone(&entry_arc);
188 let entry = entry_arc.lock().unwrap();
189 match entry.status {
190 EntryStatus::AVAILABLE => {
191 eprintln!("Error: entry should not be available at this point");
193 return None;
194 }
195 EntryStatus::CALCULATING => {
196 println!("CALCULATING");
197 match entry.cond_var.wait_while(
198 entry_arc_clone.lock().unwrap(),
199 |entry: &mut Entry<D>| entry.status == EntryStatus::CALCULATING)
200 {
201 Ok(_) => {}
202 Err(e) => {
203 eprintln!("Error while waiting: {:?}", e);
204 return None;
205 }
206 }
207 }
208 _ => {}
209 }
210 return Some((entry.data.clone(), entry.adhoc_code));
211 }
212 return None;
213 }
214
215 pub fn retrieve_or_compute(&self, key: &K) -> Option<(D, u8, bool)> {
216 self.retrieve_or_compute_with_params(key, &[])
217 }
218
219 pub fn retrieve_or_compute_with_params(&self, key: &K, params: &[&dyn Any]) -> Option<(D, u8, bool)> {
220 let miss_handler = self.miss_handler;
221 let positive_ttl = self.positive_ttl;
222 let negative_ttl = self.negative_ttl;
223
224 if let Some((data, adhoc_code)) = self.handle_hit(&key) {
225 return Some((data, adhoc_code, true));
226 }
227
228 let entry_arc = {
230 let mut locked_cache = self.lru_cache.lock().unwrap();
231 let entry_arc = locked_cache.get_or_insert_mut(key.clone(), || Arc::new(Mutex::new(Entry::default())));
232 Arc::clone(&entry_arc)
233 };
234
235 let mut locked_entry = entry_arc.lock().unwrap();
236 let entry_arc_clone = Arc::clone(&entry_arc);
237 let locked_entry = locked_entry.deref_mut();
238
239 match locked_entry.status {
240 EntryStatus::AVAILABLE => {
241 {
242 locked_entry.status = EntryStatus::CALCULATING;
243 if miss_handler(&key, &mut locked_entry.data, &mut locked_entry.adhoc_code, params) {
244 locked_entry.expiration = Instant::now() + positive_ttl;
245 locked_entry.status = EntryStatus::READY;
246 } else {
247 locked_entry.expiration = Instant::now() + negative_ttl;
248 locked_entry.status = EntryStatus::FAILED;
249 }
250 }
251 locked_entry.cond_var.notify_all();
252 }
253 EntryStatus::CALCULATING => {
254 println!("CALCULATING");
255 match locked_entry.cond_var.wait_while(
256 entry_arc_clone.lock().unwrap(),
257 |entry: &mut Entry<D>| entry.status == EntryStatus::CALCULATING)
258 {
259 Ok(_) => {}
260 Err(e) => {
261 eprintln!("Error while waiting: {:?}", e);
262 return None;
263 }
264 }
265 }
266 EntryStatus::READY | EntryStatus::FAILED => {}
267 }
268
269
270 Some((locked_entry.data.clone(), locked_entry.adhoc_code, false))
271 }
272}
273
274#[cfg(test)]
279mod tests {
280
281 use std::thread;
282
283 use super::*;
284 use rstest::*;
285
286 #[fixture]
287 fn simple_cache() -> Cache<i32, i32> {
288 fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
289 if *key == -1 {
291 return false
292 }
293 *data = key * 2;
294 *adhoc_code += 1; true
296 }
297 Cache::new(
298 3,
299 miss_handler,
300 Duration::from_millis(200),
301 Duration::from_millis(100),
302 )
303 }
304
305 #[rstest]
306 fn insert_value(simple_cache: Cache<i32, i32>) {
307 let key = 1;
309 let value = 2;
310
311 simple_cache.insert(&key, value);
313
314 assert_eq!(simple_cache.len(), 1);
316 }
317
318 #[rstest]
319 fn insert_same_key(simple_cache: Cache<i32, i32>) {
320 let key = 1;
322 let value = 2;
323
324 simple_cache.insert(&key, value);
326 simple_cache.insert(&key, value);
327
328 assert_eq!(simple_cache.len(), 1);
330 }
331
332 #[rstest]
333 fn get_value(simple_cache: Cache<i32, i32>) {
334 let key = 1;
336 let value = 2;
337
338 simple_cache.insert(&key, value);
340
341 assert_eq!(simple_cache.get(&key), Some(value));
343 }
344
345 #[rstest]
346 fn get_value_not_found(simple_cache: Cache<i32, i32>) {
347 let key = 1;
349
350 assert_eq!(simple_cache.get(&key), None);
352 }
353
354 #[rstest]
355 fn insert_max_capacity(simple_cache: Cache<i32, i32>) {
356 let key1 = 1;
358 let key2 = 2;
359 let key3 = 3;
360 let key4 = 4;
361 let value = 2;
362
363 simple_cache.insert(&key1, value);
365 simple_cache.insert(&key2, value);
366 simple_cache.insert(&key3, value);
367 simple_cache.insert(&key4, value);
368
369 assert_eq!(simple_cache.len(), 3);
371 assert_eq!(simple_cache.get(&key1), None); }
373
374 #[rstest]
375 fn get_lru_change(simple_cache: Cache<i32, i32>) {
376 let key1 = 1;
378 let key2 = 2;
379 let key3 = 3;
380 let key4 = 4;
381 let value = 2;
382
383 simple_cache.insert(&key1, value);
385 simple_cache.insert(&key2, value);
386 simple_cache.get(&key1); simple_cache.insert(&key3, value);
388 simple_cache.insert(&key4, value);
389
390 assert_eq!(simple_cache.len(), 3);
392 assert_eq!(simple_cache.get(&key2), None); }
394
395 #[rstest]
396 fn ttl_expired(simple_cache: Cache<i32, i32>) {
397 let key = 1;
399 let value = 2;
400
401 simple_cache.insert(&key, value);
403 std::thread::sleep(std::time::Duration::from_millis(250));
404
405 assert_eq!(simple_cache.get(&key), None);
407 }
408
409 #[rstest]
410 fn update_value(simple_cache: Cache<i32, i32>) {
411 let key = 1;
413 let value = 2;
414
415 simple_cache.insert(&key, value);
417 let new_value = 3;
418 let success = simple_cache.update(&key, new_value);
419
420 assert!(success);
422 assert_eq!(simple_cache.get(&key), Some(new_value));
423 }
424
425 #[rstest]
426 fn update_value_not_found(simple_cache: Cache<i32, i32>) {
427 let key = 1;
429 let new_value = 3;
430
431 let success = simple_cache.update(&key, new_value);
433
434 assert!(!success);
436 }
437
438 #[rstest]
439 fn retrieve_or_compute_not_in_cache(simple_cache: Cache<i32, i32>){
440 let key = 1;
442
443 let (data, adhoc_code, is_hit) = simple_cache.retrieve_or_compute(&key).unwrap();
445
446 assert_eq!(data, 2);
448 assert_eq!(adhoc_code, 1);
449 assert_eq!(is_hit, false);
450 assert_eq!(simple_cache.len(), 1);
451 }
452
453 #[rstest]
454 fn retrieve_or_compute_already_in_cache(simple_cache: Cache<i32, i32>){
455 let key = 1;
457
458 simple_cache.retrieve_or_compute(&key);
460 simple_cache.retrieve_or_compute(&key);
461 simple_cache.retrieve_or_compute(&key);
462 simple_cache.retrieve_or_compute(&key);
463 let (data, adhoc_code, is_hit) = simple_cache.retrieve_or_compute(&key).unwrap();
464
465 assert_eq!(data, 2);
467 assert_eq!(adhoc_code, 1);
468 assert_eq!(is_hit, true);
469 assert_eq!(simple_cache.len(), 1);
470 }
471
472 #[rstest]
473 fn retrieve_or_compute_ttl_expired(simple_cache: Cache<i32, i32>){
474 let key = 1;
476 simple_cache.retrieve_or_compute(&key);
478 let entry_1 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
479 std::thread::sleep(std::time::Duration::from_millis(100));
480 simple_cache.retrieve_or_compute(&key);
481 let entry_2 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
482 std::thread::sleep(std::time::Duration::from_millis(150));
483 simple_cache.retrieve_or_compute(&key);
484 let entry_3 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
485
486 assert_eq!(entry_1.status, EntryStatus::READY);
488 assert_eq!(entry_1, entry_2); assert_ne!(entry_1, entry_3); }
491
492 #[rstest]
493 fn retrieve_or_compute_negative_ttl(simple_cache: Cache<i32, i32>){
494 let key = -1;
496
497 simple_cache.retrieve_or_compute(&key);
499 let entry_1 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
500 std::thread::sleep(std::time::Duration::from_millis(105));
501 simple_cache.retrieve_or_compute(&key);
502 let entry_2 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
503
504 assert_ne!(entry_1, entry_2); assert_eq!(entry_1.status, EntryStatus::FAILED);
507 }
508
509 #[fixture]
510 fn simple_cache_with_params () -> Cache<i32, i32> {
511 fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, params: &[&dyn Any]) -> bool {
512
513 if *key == -1 {
515 return false
516 }
517 *data = key * 2;
518 for param in params {
519 if let Some(param) = param.downcast_ref::<i32>() {
520 *data += param;
521 }
522 }
523 if params[0].downcast_ref::<&str>().is_some() {
524 *adhoc_code += 1;
525 }
526 *adhoc_code += 1; true
528 }
529 Cache::new(
530 3,
531 miss_handler,
532 Duration::from_millis(200),
533 Duration::from_millis(100),
534 )
535 }
536
537 #[rstest]
538 fn retrieve_or_compute_with_params(simple_cache_with_params: Cache<i32, i32>){
539 let key = 1;
541 let param = 3;
542
543 let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[¶m]).unwrap();
545
546 assert_eq!(data, 5);
548 assert_eq!(adhoc_code, 1);
549 assert_eq!(is_hit, false);
550 assert_eq!(simple_cache_with_params.len(), 1);
551 }
552
553 #[rstest]
554 fn retrieve_or_compute_with_multiple_params(simple_cache_with_params: Cache<i32, i32>){
555 let key = 1;
557 let param1 = 3;
558 let param2 = 4;
559
560 let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[¶m1, ¶m2]).unwrap();
562
563 assert_eq!(data, 9);
565 assert_eq!(adhoc_code, 1);
566 assert_eq!(is_hit, false);
567 assert_eq!(simple_cache_with_params.len(), 1);
568 }
569
570 #[rstest]
571 fn retrieve_or_compute_with_multiple_params_different_types(simple_cache_with_params: Cache<i32, i32>){
572 let key = 1;
574 let param1 = "hola";
575 let param2 = 3;
576 let param3 = 4;
577
578 let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[¶m1, ¶m2, ¶m3]).unwrap();
580
581 assert_eq!(data, 9);
583 assert_eq!(adhoc_code, 2);
584 assert_eq!(is_hit, false);
585 assert_eq!(simple_cache_with_params.len(), 1);
586 }
587
588 #[fixture]
589 fn time_consuming_mh() -> Cache<i32, i32> {
590 fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
591
592 std::thread::sleep(std::time::Duration::from_millis(500));
593 if *key == 3 {
594 std::thread::sleep(std::time::Duration::from_millis(500));
595 }
596
597 *data = key * 2;
598 *adhoc_code += 1; true
600 }
601 Cache::new(
602 200,
603 miss_handler,
604 Duration::from_secs(60),
605 Duration::from_secs(60),
606 )
607 }
608
609 #[rstest]
610 fn test_thread_safe_cache_same_key(time_consuming_mh: Cache<i32, i32>) {
611 let cache = Arc::new(time_consuming_mh);
613 let n_threads: i32 = 200;
614 let start = Instant::now();
615
616 let handles: Vec<_> = (0..n_threads).map(|i| {
618 let cache_clone = Arc::clone(&cache);
619 thread::spawn({
620 move || {
621 let key = 456;
622 let start = Instant::now();
623 let res = cache_clone.retrieve_or_compute(&key);
624 (res, start.elapsed())
625 }
626 })
627 }).collect();
628
629 let results: Vec<_> = handles.into_iter().map(|handle| handle.join()).collect();
631 let duration = start.elapsed();
632 for res in results {
633 assert!(res.is_ok());
635 if let (Some((data, adhoc_code, _)), elapsed) = res.as_ref().unwrap() {
636 let key = 456;
637 assert_eq!(*data, key * 2);
638 assert_eq!(*adhoc_code, 1);
639 assert!(elapsed.as_millis() < 600);
640 }
641 }
642
643 assert!(cache.len() == 1);
644 assert!(duration.as_secs() < 1);
645
646 }
647
648 #[rstest]
649 fn test_thread_safe_cache_different_keys(time_consuming_mh: Cache<i32, i32>) {
650 let cache = Arc::new(time_consuming_mh);
652 let n_threads = 20;
653 let start = Instant::now();
654
655 let handles: Vec<_> = (0..n_threads).map(|i| {
657 let cache_clone = Arc::clone(&cache);
658 thread::spawn({
659 move || {
660 let key = 456 + i as i32;
661 let start = Instant::now();
662 let res = cache_clone.retrieve_or_compute(&key);
663 (res, start.elapsed())
664 }
665 })
666 }).collect();
667let results: Vec<_> = handles.into_iter().map(|handle| handle.join()).collect();
668
669 let duration = start.elapsed();
670 for i in 0..n_threads {
672 let res = &results[i];
673 assert!(res.is_ok());
675 if let (Some((data, adhoc_code, _)), elapsed) = res.as_ref().unwrap() {
676 let key = 456 + i as i32;
677 assert_eq!(*data, key * 2);
678 assert_eq!(*adhoc_code, 1);
679 assert!(elapsed.as_millis() < 600);
680 }
681 }
682 for i in 0..n_threads {
683 let key = 456 + i as i32;
684 let data = cache.get(&key);
685 assert_eq!(data, Some(key * 2));
686 }
687 assert!(cache.len() == n_threads.try_into().unwrap());
688 assert!(duration.as_secs() < 1);
689 }
690
691 #[rstest]
692 fn test_thread_safe_cache_maximum_capacity(time_consuming_mh: Cache<i32, i32>) {
693 let cache = Arc::new(time_consuming_mh);
695 let n_threads = 202;
696 let start = Instant::now();
697
698 let handles: Vec<_> = (0..n_threads).map(|i| {
700 let cache_clone = Arc::clone(&cache);
701 thread::spawn(move || {
702 let key = 456 + i;
703 cache_clone.retrieve_or_compute(&key);
704 })
705 }).collect();
706
707 for handle in handles {
708 let res = handle.join();
709 assert!(res.is_ok());
711 res.unwrap();
712 }
713
714 let mut not_in_cache_count = 0;
716 for i in 0..n_threads {
717 let key = 456 + i;
718 let data = cache.get(&key);
719 if data == None {
720 not_in_cache_count += 1;
721 } else {
722 let key = 456 + i;
723 let data = cache.get(&key);
724 assert_eq!(data, Some(key * 2));
725 }
726 }
727 let duration = start.elapsed();
728 assert!(cache.len() == 200);
729 assert!(duration.as_secs() < 1);
730 assert_eq!(not_in_cache_count, 2);
731 }
732
733 #[rstest]
734 fn test_thread_safe_heavy_threads(time_consuming_mh: Cache<i32, i32>) {
735 let cache = Arc::new(time_consuming_mh);
736 for cicle in 0..50 {
737 let n_keys = 5;
739 let entries_per_key = 20;
740 let results = vec![((0,0), Duration::default()); n_keys * entries_per_key];
741 let results_arc = Arc::new(Mutex::new(results));
742 let mut threads = Vec::<thread::JoinHandle<_>>::with_capacity(n_keys * entries_per_key);
743
744 for i in 0..n_keys {
746 for j in 0..entries_per_key {
747 let cache_clone = Arc::clone(&cache);
748 let results_clone = Arc::clone(&results_arc);
749 threads.push(thread::spawn(move || {
750 let key = (i + 1) as i32;
751 let start = Instant::now();
752 let (data, adhoc_code, _) = cache_clone.retrieve_or_compute(&key).unwrap();
753 let mut results = results_clone.lock().unwrap();
754 results[i*entries_per_key+j] = ((data, adhoc_code), start.elapsed());
755 }));
756 }
757 }
758 for handle in threads {
759 let res = handle.join();
760 assert!(res.is_ok());
762 res.unwrap();
763 }
764
765 let mut key = 0;
767 for i in (0..n_keys * entries_per_key).step_by(entries_per_key) {
768 key += 1;
769 let results = results_arc.lock().unwrap();
770 let (res_i, elapsed_i) = results[i];
771 for j in 1..entries_per_key {
772 let (res_j, elapsed_j) = results[i+j];
773 assert_eq!(res_i, res_j);
774 println!("key : {} i: {} j: {}", key, elapsed_i.as_millis(), elapsed_j.as_millis());
775 if cicle ==0 && key == 3 {
776 assert!(elapsed_i.as_millis() > 600);
777 assert!(elapsed_j.as_millis() > 600);
778 } else {
779 assert!(elapsed_i.as_millis() < 600);
780 assert!(elapsed_j.as_millis() < 600);
781 }
782
783 }
784 }
785 assert!(cache.len() == n_keys);
786 }
787 }
788
789 #[derive(Debug, PartialEq, Eq, Clone, Hash, Copy, Default)]
790 struct SimpleStruct {
791 value: i32,
792 }
793 #[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
794 struct ComplexKey {
795 id: i32,
796 name: String,
797 nested: SimpleStruct,
798 array: Vec<i32>,
799
800 }
801
802 #[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
803 struct ComplexData {
804 value: i32,
805 description: String,
806 nested: SimpleStruct,
807 array: Vec<i32>,
808 }
809
810 #[fixture]
811 fn complex_key_and_data_cache() -> Cache<ComplexKey, ComplexData> {
812 fn miss_handler(key: &ComplexKey, data: &mut ComplexData, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
813 std::thread::sleep(std::time::Duration::from_millis(500));
815 if key.id == -1 {
817 return false
818 }
819 data.value = key.id * 2;
820 data.description = key.name.clone();
821 data.nested = key.nested.clone();
822 data.array = key.array.clone();
823 *adhoc_code += 1; true
825 }
826 Cache::new(
827 200,
828 miss_handler,
829 Duration::from_secs(1),
830 Duration::from_secs(1),
831 )
832 }
833
834 #[rstest]
835 fn complex_key_and_data_cache_insert(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
836 let key = ComplexKey {
838 id: 1,
839 name: "name".to_string(),
840 nested: SimpleStruct { value: 1 },
841 array: vec![1, 2, 3],
842 };
843 let data = ComplexData {
844 value: 2,
845 description: "name".to_string(),
846 nested: SimpleStruct { value: 1 },
847 array: vec![1, 2, 3],
848 };
849
850 complex_key_and_data_cache.insert(&key, data);
852
853 assert_eq!(complex_key_and_data_cache.len(), 1);
855 }
856
857 #[rstest]
858 fn complex_key_data_retrieve_or_compute(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
859 let key = ComplexKey {
861 id: 1,
862 name: "name".to_string(),
863 nested: SimpleStruct { value: 1 },
864 array: vec![1, 2, 3],
865 };
866
867 let (data, adhoc_code, is_hit) = complex_key_and_data_cache.retrieve_or_compute(&key).unwrap();
869
870 assert_eq!(data.value, 2);
872 assert_eq!(data.description, "name");
873 assert_eq!(data.nested, SimpleStruct { value: 1 });
874 assert_eq!(data.array, vec![1, 2, 3]);
875 assert_eq!(adhoc_code, 1);
876 assert_eq!(is_hit, false);
877 assert_eq!(complex_key_and_data_cache.len(), 1);
878 }
879
880 #[rstest]
881 fn complex_key_data_retrieve_or_compute_change_key(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
882 let key = ComplexKey {
884 id: 1,
885 name: "name".to_string(),
886 nested: SimpleStruct { value: 1 },
887 array: vec![1, 2, 3],
888 };
889 let key_clone = key.clone();
890 let mut key_change = key.clone();
891 key_change.id = 2;
892
893 let (data, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key).unwrap();
895 let (data1, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key_clone).unwrap();
896 let (data2, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key_change).unwrap();
897
898 assert_eq!(data, data1);
900 assert_ne!(data, data2);
901 assert_eq!(complex_key_and_data_cache.len(), 2);
902 }
903
904 #[rstest]
905 fn complex_key_data_thread_safe_cache_same_key(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
906 let cache = Arc::new(complex_key_and_data_cache);
908 let n_threads: i32 = 200;
909 let start = Instant::now();
910 let key = ComplexKey {
911 id: 1,
912 name: "name".to_string(),
913 nested: SimpleStruct { value: 1 },
914 array: vec![1, 2, 3],
915 };
916
917 let handles: Vec<_> = (0..n_threads).map(|i| {
919 let cache_clone = Arc::clone(&cache);
920 thread::Builder::new().name(format!("Thread {}", i)).spawn({
921 let value = key.clone();
922 move || {
923 cache_clone.retrieve_or_compute(&value)
924 }
925 })
926 }).collect();
927
928 let results = handles.into_iter().map(|handle| handle.unwrap().join());
930 let mut i = 0;
931 for res in results {
932 assert!(res.is_ok());
934 if let Some((data, adhoc_code, is_hit)) = res.unwrap() {
935 assert_eq!(data.value, 2);
936 assert_eq!(data.description, "name");
937 assert_eq!(data.nested, SimpleStruct { value: 1 });
938 assert_eq!(data.array, vec![1, 2, 3]);
939 assert_eq!(adhoc_code, 1);
940 if i == 0 {
941 assert!(!is_hit);
942 }else {
943 assert!(is_hit);
944 }
945 }
946 i += 1;
947 }
948 let duration = start.elapsed();
949 assert!(cache.len() == 1);
950 assert!(duration.as_secs() < 1);
951
952 }
953
954 #[rstest]
955 fn complex_key_data_thread_safe_cache_different_keys(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
956 let cache = Arc::new(complex_key_and_data_cache);
958 let n_threads = 200;
959 let start = Instant::now();
960
961 let handles: Vec<_> = (0..n_threads).map(|i| {
963 let cache_clone = Arc::clone(&cache);
964 let key: ComplexKey = ComplexKey {
965 id: 1 + i,
966 name: "name".to_string(),
967 nested: SimpleStruct { value: 1 },
968 array: vec![1, 2, 3],
969 };
970 thread::spawn({ move || {
971 cache_clone.retrieve_or_compute(&key)
972 }
973 })
974 }).collect();
975
976 for handle in handles {
977 let res = handle.join();
978 assert!(res.is_ok());
980 res.unwrap();
981 }
982
983 for i in 0..n_threads {
985 let key = ComplexKey {
986 id: 1 + i,
987 name: "name".to_string(),
988 nested: SimpleStruct { value: 1 },
989 array: vec![1, 2, 3],
990 };
991 let data = cache.get(&key);
992
993 assert_eq!(data, Some(ComplexData {
994 value: (1 + i) * 2,
995 description: "name".to_string(),
996 nested: SimpleStruct { value: 1 },
997 array: vec![1, 2, 3],
998 }));
999 }
1000 assert!(cache.len() == n_threads.try_into().unwrap());
1001 let duration = start.elapsed();
1002 assert!(duration.as_secs() < 1);
1003 }
1004
1005
1006}