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 fn get_entry(&self, key: &K) -> Option<Arc<Mutex<Entry<D>>>> {
149 let cache_entry = {
151 let mut cache = self.lru_cache.lock().unwrap();
152 cache.get(key).map(|entry| Arc::clone(entry))
153 };
154 match cache_entry {
156 None => return None,
157 Some(entry_arc) => {
158 let entry = entry_arc.lock().unwrap();
159 if entry.is_valid() {
160 return Some(Arc::clone(&entry_arc));
161 }
162 }
163 }
164 self.lru_cache.lock().unwrap().pop(key);
166 None
167 }
168
169 pub fn len(&self) -> usize {
170 self.lru_cache.lock().unwrap().len()
171 }
172
173 fn handle_hit(&self, key: &K) -> Option<(D, u8)> {
174 if let Some(entry_arc) = self.get_entry(key) {
176 let entry_arc_clone = Arc::clone(&entry_arc);
177 let entry = entry_arc.lock().unwrap();
178 match entry.status {
179 EntryStatus::AVAILABLE => {
180 eprintln!("Error: entry should not be available at this point");
182 return None;
183 }
184 EntryStatus::CALCULATING => {
185 println!("CALCULATING");
186 match entry.cond_var.wait_while(
187 entry_arc_clone.lock().unwrap(),
188 |entry: &mut Entry<D>| entry.status == EntryStatus::CALCULATING)
189 {
190 Ok(_) => {}
191 Err(e) => {
192 eprintln!("Error while waiting: {:?}", e);
193 return None;
194 }
195 }
196 }
197 _ => {}
198 }
199 return Some((entry.data.clone(), entry.adhoc_code));
200 }
201 return None;
202 }
203
204 pub fn retrieve_or_compute(&self, key: &K) -> Option<(D, u8, bool)> {
205 self.retrieve_or_compute_with_params(key, &[])
206 }
207
208 pub fn retrieve_or_compute_with_params(&self, key: &K, params: &[&dyn Any]) -> Option<(D, u8, bool)> {
209 let miss_handler = self.miss_handler;
210 let positive_ttl = self.positive_ttl;
211 let negative_ttl = self.negative_ttl;
212
213 if let Some((data, adhoc_code)) = self.handle_hit(&key) {
214 return Some((data, adhoc_code, true));
215 }
216
217 let entry_arc = {
219 let mut locked_cache = self.lru_cache.lock().unwrap();
220 let entry_arc = locked_cache.get_or_insert_mut(key.clone(), || Arc::new(Mutex::new(Entry::default())));
221 Arc::clone(&entry_arc)
222 };
223
224 let mut locked_entry = entry_arc.lock().unwrap();
225 let entry_arc_clone = Arc::clone(&entry_arc);
226 let locked_entry = locked_entry.deref_mut();
227
228 match locked_entry.status {
229 EntryStatus::AVAILABLE => {
230 {
231 locked_entry.status = EntryStatus::CALCULATING;
232 if miss_handler(&key, &mut locked_entry.data, &mut locked_entry.adhoc_code, params) {
233 locked_entry.expiration = Instant::now() + positive_ttl;
234 locked_entry.status = EntryStatus::READY;
235 } else {
236 locked_entry.expiration = Instant::now() + negative_ttl;
237 locked_entry.status = EntryStatus::FAILED;
238 }
239 }
240 locked_entry.cond_var.notify_all();
241 }
242 EntryStatus::CALCULATING => {
243 println!("CALCULATING");
244 match locked_entry.cond_var.wait_while(
245 entry_arc_clone.lock().unwrap(),
246 |entry: &mut Entry<D>| entry.status == EntryStatus::CALCULATING)
247 {
248 Ok(_) => {}
249 Err(e) => {
250 eprintln!("Error while waiting: {:?}", e);
251 return None;
252 }
253 }
254 }
255 EntryStatus::READY | EntryStatus::FAILED => {}
256 }
257
258
259 Some((locked_entry.data.clone(), locked_entry.adhoc_code, false))
260 }
261}
262
263#[cfg(test)]
268mod tests {
269
270 use std::thread;
271
272 use super::*;
273 use rstest::*;
274
275 #[fixture]
276 fn simple_cache() -> Cache<i32, i32> {
277 fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
278 if *key == -1 {
280 return false
281 }
282 *data = key * 2;
283 *adhoc_code += 1; true
285 }
286 Cache::new(
287 3,
288 miss_handler,
289 Duration::from_millis(200),
290 Duration::from_millis(100),
291 )
292 }
293
294 #[rstest]
295 fn insert_value(simple_cache: Cache<i32, i32>) {
296 let key = 1;
298 let value = 2;
299
300 simple_cache.insert(&key, value);
302
303 assert_eq!(simple_cache.len(), 1);
305 }
306
307 #[rstest]
308 fn insert_same_key(simple_cache: Cache<i32, i32>) {
309 let key = 1;
311 let value = 2;
312
313 simple_cache.insert(&key, value);
315 simple_cache.insert(&key, value);
316
317 assert_eq!(simple_cache.len(), 1);
319 }
320
321 #[rstest]
322 fn get_value(simple_cache: Cache<i32, i32>) {
323 let key = 1;
325 let value = 2;
326
327 simple_cache.insert(&key, value);
329
330 assert_eq!(simple_cache.get(&key), Some(value));
332 }
333
334 #[rstest]
335 fn get_value_not_found(simple_cache: Cache<i32, i32>) {
336 let key = 1;
338
339 assert_eq!(simple_cache.get(&key), None);
341 }
342
343 #[rstest]
344 fn insert_max_capacity(simple_cache: Cache<i32, i32>) {
345 let key1 = 1;
347 let key2 = 2;
348 let key3 = 3;
349 let key4 = 4;
350 let value = 2;
351
352 simple_cache.insert(&key1, value);
354 simple_cache.insert(&key2, value);
355 simple_cache.insert(&key3, value);
356 simple_cache.insert(&key4, value);
357
358 assert_eq!(simple_cache.len(), 3);
360 assert_eq!(simple_cache.get(&key1), None); }
362
363 #[rstest]
364 fn get_lru_change(simple_cache: Cache<i32, i32>) {
365 let key1 = 1;
367 let key2 = 2;
368 let key3 = 3;
369 let key4 = 4;
370 let value = 2;
371
372 simple_cache.insert(&key1, value);
374 simple_cache.insert(&key2, value);
375 simple_cache.get(&key1); simple_cache.insert(&key3, value);
377 simple_cache.insert(&key4, value);
378
379 assert_eq!(simple_cache.len(), 3);
381 assert_eq!(simple_cache.get(&key2), None); }
383
384 #[rstest]
385 fn ttl_expired(simple_cache: Cache<i32, i32>) {
386 let key = 1;
388 let value = 2;
389
390 simple_cache.insert(&key, value);
392 std::thread::sleep(std::time::Duration::from_millis(250));
393
394 assert_eq!(simple_cache.get(&key), None);
396 }
397
398 #[rstest]
399 fn retrieve_or_compute_not_in_cache(simple_cache: Cache<i32, i32>){
400 let key = 1;
402
403 let (data, adhoc_code, is_hit) = simple_cache.retrieve_or_compute(&key).unwrap();
405
406 assert_eq!(data, 2);
408 assert_eq!(adhoc_code, 1);
409 assert_eq!(is_hit, false);
410 assert_eq!(simple_cache.len(), 1);
411 }
412
413 #[rstest]
414 fn retrieve_or_compute_already_in_cache(simple_cache: Cache<i32, i32>){
415 let key = 1;
417
418 simple_cache.retrieve_or_compute(&key);
420 simple_cache.retrieve_or_compute(&key);
421 simple_cache.retrieve_or_compute(&key);
422 simple_cache.retrieve_or_compute(&key);
423 let (data, adhoc_code, is_hit) = simple_cache.retrieve_or_compute(&key).unwrap();
424
425 assert_eq!(data, 2);
427 assert_eq!(adhoc_code, 1);
428 assert_eq!(is_hit, true);
429 assert_eq!(simple_cache.len(), 1);
430 }
431
432 #[rstest]
433 fn retrieve_or_compute_ttl_expired(simple_cache: Cache<i32, i32>){
434 let key = 1;
436 simple_cache.retrieve_or_compute(&key);
438 let entry_1 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
439 std::thread::sleep(std::time::Duration::from_millis(100));
440 simple_cache.retrieve_or_compute(&key);
441 let entry_2 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
442 std::thread::sleep(std::time::Duration::from_millis(150));
443 simple_cache.retrieve_or_compute(&key);
444 let entry_3 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
445
446 assert_eq!(entry_1.status, EntryStatus::READY);
448 assert_eq!(entry_1, entry_2); assert_ne!(entry_1, entry_3); }
451
452 #[rstest]
453 fn retrieve_or_compute_negative_ttl(simple_cache: Cache<i32, i32>){
454 let key = -1;
456
457 simple_cache.retrieve_or_compute(&key);
459 let entry_1 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
460 std::thread::sleep(std::time::Duration::from_millis(105));
461 simple_cache.retrieve_or_compute(&key);
462 let entry_2 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
463
464 assert_ne!(entry_1, entry_2); assert_eq!(entry_1.status, EntryStatus::FAILED);
467 }
468
469 #[fixture]
470 fn simple_cache_with_params () -> Cache<i32, i32> {
471 fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, params: &[&dyn Any]) -> bool {
472
473 if *key == -1 {
475 return false
476 }
477 *data = key * 2;
478 for param in params {
479 if let Some(param) = param.downcast_ref::<i32>() {
480 *data += param;
481 }
482 }
483 if params[0].downcast_ref::<&str>().is_some() {
484 *adhoc_code += 1;
485 }
486 *adhoc_code += 1; true
488 }
489 Cache::new(
490 3,
491 miss_handler,
492 Duration::from_millis(200),
493 Duration::from_millis(100),
494 )
495 }
496
497 #[rstest]
498 fn retrieve_or_compute_with_params(simple_cache_with_params: Cache<i32, i32>){
499 let key = 1;
501 let param = 3;
502
503 let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[¶m]).unwrap();
505
506 assert_eq!(data, 5);
508 assert_eq!(adhoc_code, 1);
509 assert_eq!(is_hit, false);
510 assert_eq!(simple_cache_with_params.len(), 1);
511 }
512
513 #[rstest]
514 fn retrieve_or_compute_with_multiple_params(simple_cache_with_params: Cache<i32, i32>){
515 let key = 1;
517 let param1 = 3;
518 let param2 = 4;
519
520 let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[¶m1, ¶m2]).unwrap();
522
523 assert_eq!(data, 9);
525 assert_eq!(adhoc_code, 1);
526 assert_eq!(is_hit, false);
527 assert_eq!(simple_cache_with_params.len(), 1);
528 }
529
530 #[rstest]
531 fn retrieve_or_compute_with_multiple_params_different_types(simple_cache_with_params: Cache<i32, i32>){
532 let key = 1;
534 let param1 = "hola";
535 let param2 = 3;
536 let param3 = 4;
537
538 let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[¶m1, ¶m2, ¶m3]).unwrap();
540
541 assert_eq!(data, 9);
543 assert_eq!(adhoc_code, 2);
544 assert_eq!(is_hit, false);
545 assert_eq!(simple_cache_with_params.len(), 1);
546 }
547
548 #[fixture]
549 fn time_consuming_mh() -> Cache<i32, i32> {
550 fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
551
552 std::thread::sleep(std::time::Duration::from_millis(500));
553 if *key == 3 {
554 std::thread::sleep(std::time::Duration::from_millis(500));
555 }
556
557 *data = key * 2;
558 *adhoc_code += 1; true
560 }
561 Cache::new(
562 200,
563 miss_handler,
564 Duration::from_secs(60),
565 Duration::from_secs(60),
566 )
567 }
568
569 #[rstest]
570 fn test_thread_safe_cache_same_key(time_consuming_mh: Cache<i32, i32>) {
571 let cache = Arc::new(time_consuming_mh);
573 let n_threads: i32 = 200;
574 let start = Instant::now();
575
576 let handles: Vec<_> = (0..n_threads).map(|i| {
578 let cache_clone = Arc::clone(&cache);
579 thread::spawn({
580 move || {
581 let key = 456;
582 let start = Instant::now();
583 let res = cache_clone.retrieve_or_compute(&key);
584 (res, start.elapsed())
585 }
586 })
587 }).collect();
588
589 let results: Vec<_> = handles.into_iter().map(|handle| handle.join()).collect();
591 let duration = start.elapsed();
592 for res in results {
593 assert!(res.is_ok());
595 if let (Some((data, adhoc_code, _)), elapsed) = res.as_ref().unwrap() {
596 let key = 456;
597 assert_eq!(*data, key * 2);
598 assert_eq!(*adhoc_code, 1);
599 assert!(elapsed.as_millis() < 600);
600 }
601 }
602
603 assert!(cache.len() == 1);
604 assert!(duration.as_secs() < 1);
605
606 }
607
608 #[rstest]
609 fn test_thread_safe_cache_different_keys(time_consuming_mh: Cache<i32, i32>) {
610 let cache = Arc::new(time_consuming_mh);
612 let n_threads = 20;
613 let start = Instant::now();
614
615 let handles: Vec<_> = (0..n_threads).map(|i| {
617 let cache_clone = Arc::clone(&cache);
618 thread::spawn({
619 move || {
620 let key = 456 + i as i32;
621 let start = Instant::now();
622 let res = cache_clone.retrieve_or_compute(&key);
623 (res, start.elapsed())
624 }
625 })
626 }).collect();
627let results: Vec<_> = handles.into_iter().map(|handle| handle.join()).collect();
628
629 let duration = start.elapsed();
630 for i in 0..n_threads {
632 let res = &results[i];
633 assert!(res.is_ok());
635 if let (Some((data, adhoc_code, _)), elapsed) = res.as_ref().unwrap() {
636 let key = 456 + i as i32;
637 assert_eq!(*data, key * 2);
638 assert_eq!(*adhoc_code, 1);
639 assert!(elapsed.as_millis() < 600);
640 }
641 }
642 for i in 0..n_threads {
643 let key = 456 + i as i32;
644 let data = cache.get(&key);
645 assert_eq!(data, Some(key * 2));
646 }
647 assert!(cache.len() == n_threads.try_into().unwrap());
648 assert!(duration.as_secs() < 1);
649 }
650
651 #[rstest]
652 fn test_thread_safe_cache_maximum_capacity(time_consuming_mh: Cache<i32, i32>) {
653 let cache = Arc::new(time_consuming_mh);
655 let n_threads = 202;
656 let start = Instant::now();
657
658 let handles: Vec<_> = (0..n_threads).map(|i| {
660 let cache_clone = Arc::clone(&cache);
661 thread::spawn(move || {
662 let key = 456 + i;
663 cache_clone.retrieve_or_compute(&key);
664 })
665 }).collect();
666
667 for handle in handles {
668 let res = handle.join();
669 assert!(res.is_ok());
671 res.unwrap();
672 }
673
674 let mut not_in_cache_count = 0;
676 for i in 0..n_threads {
677 let key = 456 + i;
678 let data = cache.get(&key);
679 if data == None {
680 not_in_cache_count += 1;
681 } else {
682 let key = 456 + i;
683 let data = cache.get(&key);
684 assert_eq!(data, Some(key * 2));
685 }
686 }
687 let duration = start.elapsed();
688 assert!(cache.len() == 200);
689 assert!(duration.as_secs() < 1);
690 assert_eq!(not_in_cache_count, 2);
691 }
692
693 #[rstest]
694 fn test_thread_safe_heavy_threads(time_consuming_mh: Cache<i32, i32>) {
695 let cache = Arc::new(time_consuming_mh);
696 for cicle in 0..50 {
697 let n_keys = 5;
699 let entries_per_key = 20;
700 let results = vec![((0,0), Duration::default()); n_keys * entries_per_key];
701 let results_arc = Arc::new(Mutex::new(results));
702 let mut threads = Vec::<thread::JoinHandle<_>>::with_capacity(n_keys * entries_per_key);
703
704 for i in 0..n_keys {
706 for j in 0..entries_per_key {
707 let cache_clone = Arc::clone(&cache);
708 let results_clone = Arc::clone(&results_arc);
709 threads.push(thread::spawn(move || {
710 let key = (i + 1) as i32;
711 let start = Instant::now();
712 let (data, adhoc_code, _) = cache_clone.retrieve_or_compute(&key).unwrap();
713 let mut results = results_clone.lock().unwrap();
714 results[i*entries_per_key+j] = ((data, adhoc_code), start.elapsed());
715 }));
716 }
717 }
718 for handle in threads {
719 let res = handle.join();
720 assert!(res.is_ok());
722 res.unwrap();
723 }
724
725 let mut key = 0;
727 for i in (0..n_keys * entries_per_key).step_by(entries_per_key) {
728 key += 1;
729 let results = results_arc.lock().unwrap();
730 let (res_i, elapsed_i) = results[i];
731 for j in 1..entries_per_key {
732 let (res_j, elapsed_j) = results[i+j];
733 assert_eq!(res_i, res_j);
734 println!("key : {} i: {} j: {}", key, elapsed_i.as_millis(), elapsed_j.as_millis());
735 if cicle ==0 && key == 3 {
736 assert!(elapsed_i.as_millis() > 600);
737 assert!(elapsed_j.as_millis() > 600);
738 } else {
739 assert!(elapsed_i.as_millis() < 600);
740 assert!(elapsed_j.as_millis() < 600);
741 }
742
743 }
744 }
745 assert!(cache.len() == n_keys);
746 }
747 }
748
749 #[derive(Debug, PartialEq, Eq, Clone, Hash, Copy, Default)]
750 struct SimpleStruct {
751 value: i32,
752 }
753 #[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
754 struct ComplexKey {
755 id: i32,
756 name: String,
757 nested: SimpleStruct,
758 array: Vec<i32>,
759
760 }
761
762 #[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
763 struct ComplexData {
764 value: i32,
765 description: String,
766 nested: SimpleStruct,
767 array: Vec<i32>,
768 }
769
770 #[fixture]
771 fn complex_key_and_data_cache() -> Cache<ComplexKey, ComplexData> {
772 fn miss_handler(key: &ComplexKey, data: &mut ComplexData, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
773 std::thread::sleep(std::time::Duration::from_millis(500));
775 if key.id == -1 {
777 return false
778 }
779 data.value = key.id * 2;
780 data.description = key.name.clone();
781 data.nested = key.nested.clone();
782 data.array = key.array.clone();
783 *adhoc_code += 1; true
785 }
786 Cache::new(
787 200,
788 miss_handler,
789 Duration::from_secs(1),
790 Duration::from_secs(1),
791 )
792 }
793
794 #[rstest]
795 fn complex_key_and_data_cache_insert(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
796 let key = ComplexKey {
798 id: 1,
799 name: "name".to_string(),
800 nested: SimpleStruct { value: 1 },
801 array: vec![1, 2, 3],
802 };
803 let data = ComplexData {
804 value: 2,
805 description: "name".to_string(),
806 nested: SimpleStruct { value: 1 },
807 array: vec![1, 2, 3],
808 };
809
810 complex_key_and_data_cache.insert(&key, data);
812
813 assert_eq!(complex_key_and_data_cache.len(), 1);
815 }
816
817 #[rstest]
818 fn complex_key_data_retrieve_or_compute(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
819 let key = ComplexKey {
821 id: 1,
822 name: "name".to_string(),
823 nested: SimpleStruct { value: 1 },
824 array: vec![1, 2, 3],
825 };
826
827 let (data, adhoc_code, is_hit) = complex_key_and_data_cache.retrieve_or_compute(&key).unwrap();
829
830 assert_eq!(data.value, 2);
832 assert_eq!(data.description, "name");
833 assert_eq!(data.nested, SimpleStruct { value: 1 });
834 assert_eq!(data.array, vec![1, 2, 3]);
835 assert_eq!(adhoc_code, 1);
836 assert_eq!(is_hit, false);
837 assert_eq!(complex_key_and_data_cache.len(), 1);
838 }
839
840 #[rstest]
841 fn complex_key_data_retrieve_or_compute_change_key(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
842 let key = ComplexKey {
844 id: 1,
845 name: "name".to_string(),
846 nested: SimpleStruct { value: 1 },
847 array: vec![1, 2, 3],
848 };
849 let key_clone = key.clone();
850 let mut key_change = key.clone();
851 key_change.id = 2;
852
853 let (data, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key).unwrap();
855 let (data1, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key_clone).unwrap();
856 let (data2, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key_change).unwrap();
857
858 assert_eq!(data, data1);
860 assert_ne!(data, data2);
861 assert_eq!(complex_key_and_data_cache.len(), 2);
862 }
863
864 #[rstest]
865 fn complex_key_data_thread_safe_cache_same_key(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
866 let cache = Arc::new(complex_key_and_data_cache);
868 let n_threads: i32 = 200;
869 let start = Instant::now();
870 let key = ComplexKey {
871 id: 1,
872 name: "name".to_string(),
873 nested: SimpleStruct { value: 1 },
874 array: vec![1, 2, 3],
875 };
876
877 let handles: Vec<_> = (0..n_threads).map(|i| {
879 let cache_clone = Arc::clone(&cache);
880 thread::Builder::new().name(format!("Thread {}", i)).spawn({
881 let value = key.clone();
882 move || {
883 cache_clone.retrieve_or_compute(&value)
884 }
885 })
886 }).collect();
887
888 let results = handles.into_iter().map(|handle| handle.unwrap().join());
890 let mut i = 0;
891 for res in results {
892 assert!(res.is_ok());
894 if let Some((data, adhoc_code, is_hit)) = res.unwrap() {
895 assert_eq!(data.value, 2);
896 assert_eq!(data.description, "name");
897 assert_eq!(data.nested, SimpleStruct { value: 1 });
898 assert_eq!(data.array, vec![1, 2, 3]);
899 assert_eq!(adhoc_code, 1);
900 if i == 0 {
901 assert!(!is_hit);
902 }else {
903 assert!(is_hit);
904 }
905 }
906 i += 1;
907 }
908 let duration = start.elapsed();
909 assert!(cache.len() == 1);
910 assert!(duration.as_secs() < 1);
911
912 }
913
914 #[rstest]
915 fn complex_key_data_thread_safe_cache_different_keys(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
916 let cache = Arc::new(complex_key_and_data_cache);
918 let n_threads = 200;
919 let start = Instant::now();
920
921 let handles: Vec<_> = (0..n_threads).map(|i| {
923 let cache_clone = Arc::clone(&cache);
924 let key: ComplexKey = ComplexKey {
925 id: 1 + i,
926 name: "name".to_string(),
927 nested: SimpleStruct { value: 1 },
928 array: vec![1, 2, 3],
929 };
930 thread::spawn({ move || {
931 cache_clone.retrieve_or_compute(&key)
932 }
933 })
934 }).collect();
935
936 for handle in handles {
937 let res = handle.join();
938 assert!(res.is_ok());
940 res.unwrap();
941 }
942
943 for i in 0..n_threads {
945 let key = ComplexKey {
946 id: 1 + i,
947 name: "name".to_string(),
948 nested: SimpleStruct { value: 1 },
949 array: vec![1, 2, 3],
950 };
951 let data = cache.get(&key);
952
953 assert_eq!(data, Some(ComplexData {
954 value: (1 + i) * 2,
955 description: "name".to_string(),
956 nested: SimpleStruct { value: 1 },
957 array: vec![1, 2, 3],
958 }));
959 }
960 assert!(cache.len() == n_threads.try_into().unwrap());
961 let duration = start.elapsed();
962 assert!(duration.as_secs() < 1);
963 }
964
965
966}