1extern crate alloc;
193
194use crate::config::GdsfCacheConfig;
195use crate::entry::CacheEntry;
196use crate::list::{List, ListEntry};
197use crate::meta::GdsfMeta;
198use crate::metrics::{CacheMetrics, GdsfCacheMetrics};
199use alloc::boxed::Box;
200use alloc::collections::BTreeMap;
201use alloc::string::String;
202use core::borrow::Borrow;
203use core::hash::{BuildHasher, Hash};
204use core::mem;
205use core::num::NonZeroUsize;
206
207#[cfg(feature = "hashbrown")]
208use hashbrown::DefaultHashBuilder;
209#[cfg(feature = "hashbrown")]
210use hashbrown::HashMap;
211
212#[cfg(not(feature = "hashbrown"))]
213use std::collections::hash_map::RandomState as DefaultHashBuilder;
214#[cfg(not(feature = "hashbrown"))]
215use std::collections::HashMap;
216
217pub(crate) struct GdsfSegment<K, V, S = DefaultHashBuilder> {
223 config: GdsfCacheConfig,
224 global_age: f64,
225 min_priority: f64,
226 map: HashMap<K, *mut ListEntry<CacheEntry<K, V, GdsfMeta>>, S>,
228 priority_lists: BTreeMap<u64, List<CacheEntry<K, V, GdsfMeta>>>,
230 metrics: GdsfCacheMetrics,
231 current_size: u64,
233}
234
235unsafe impl<K: Send, V: Send, S: Send> Send for GdsfSegment<K, V, S> {}
238
239unsafe impl<K: Send, V: Send, S: Sync> Sync for GdsfSegment<K, V, S> {}
241
242impl<K: Hash + Eq, V: Clone, S: BuildHasher> GdsfSegment<K, V, S> {
243 #[allow(dead_code)] pub(crate) fn init(config: GdsfCacheConfig, hasher: S) -> Self {
254 let map_capacity = config.capacity.get().next_power_of_two();
255 GdsfSegment {
256 global_age: config.initial_age,
257 min_priority: 0.0,
258 map: HashMap::with_capacity_and_hasher(map_capacity, hasher),
259 priority_lists: BTreeMap::new(),
260 metrics: GdsfCacheMetrics::new(config.max_size),
261 current_size: 0,
262 config,
263 }
264 }
265
266 #[inline]
267 pub(crate) fn cap(&self) -> NonZeroUsize {
268 self.config.capacity
269 }
270
271 #[inline]
272 pub(crate) fn len(&self) -> usize {
273 self.map.len()
274 }
275
276 #[inline]
277 pub(crate) fn is_empty(&self) -> bool {
278 self.map.is_empty()
279 }
280
281 #[inline]
282 pub(crate) fn global_age(&self) -> f64 {
283 self.global_age
284 }
285
286 #[inline]
288 pub(crate) fn current_size(&self) -> u64 {
289 self.current_size
290 }
291
292 #[inline]
294 pub(crate) fn max_size(&self) -> u64 {
295 self.config.max_size
296 }
297
298 #[inline]
299 pub(crate) fn metrics(&self) -> &GdsfCacheMetrics {
300 &self.metrics
301 }
302
303 fn estimate_object_size(&self, _key: &K, _value: &V) -> u64 {
304 mem::size_of::<K>() as u64 + mem::size_of::<V>() as u64 + 64
305 }
306
307 #[inline]
308 pub(crate) fn record_miss(&mut self, object_size: u64) {
309 self.metrics.core.record_miss(object_size);
310 }
311
312 fn calculate_priority(&self, frequency: u64, size: u64) -> f64 {
313 if size == 0 {
314 return f64::INFINITY;
315 }
316 (frequency as f64 / size as f64) + self.global_age
317 }
318
319 unsafe fn update_priority_by_node(
320 &mut self,
321 node: *mut ListEntry<CacheEntry<K, V, GdsfMeta>>,
322 ) -> *mut ListEntry<CacheEntry<K, V, GdsfMeta>>
323 where
324 K: Clone + Hash + Eq,
325 {
326 let entry = (*node).get_value_mut();
328 let key_cloned = entry.key.clone();
329 let size = entry.size;
330 let meta = entry.metadata_mut().unwrap();
331 let old_priority = meta.priority;
332
333 meta.increment();
334
335 let global_age = self.global_age;
336 let new_priority = meta.calculate_priority(size, global_age);
337
338 let old_priority_key = (old_priority * 1000.0) as u64;
339 let new_priority_key = (new_priority * 1000.0) as u64;
340
341 if old_priority_key == new_priority_key {
342 self.priority_lists
343 .get_mut(&new_priority_key)
344 .unwrap()
345 .move_to_front(node);
346 return node;
347 }
348
349 let boxed_entry = self
350 .priority_lists
351 .get_mut(&old_priority_key)
352 .unwrap()
353 .remove(node)
354 .unwrap();
355
356 if self
357 .priority_lists
358 .get(&old_priority_key)
359 .unwrap()
360 .is_empty()
361 {
362 self.priority_lists.remove(&old_priority_key);
363 }
364
365 let entry_ptr = Box::into_raw(boxed_entry);
366
367 let capacity = self.config.capacity;
368 self.priority_lists
369 .entry(new_priority_key)
370 .or_insert_with(|| List::new(capacity));
371
372 self.priority_lists
373 .get_mut(&new_priority_key)
374 .unwrap()
375 .attach_from_other_list(entry_ptr);
376
377 self.map.insert(key_cloned, entry_ptr);
379 entry_ptr
380 }
381
382 pub(crate) fn get<Q>(&mut self, key: &Q) -> Option<V>
383 where
384 K: Borrow<Q> + Clone,
385 Q: ?Sized + Hash + Eq,
386 {
387 if let Some(&node) = self.map.get(key) {
388 unsafe {
389 let entry = (*node).get_value();
391 let object_size = self.estimate_object_size(&entry.key, &entry.value);
392 let meta = entry.metadata.as_ref().unwrap();
393 self.metrics.core.record_hit(object_size);
394 self.metrics
395 .record_item_access(meta.frequency, entry.size, meta.priority);
396
397 let new_node = self.update_priority_by_node(node);
398 let value = (*new_node).get_value().value.clone();
399 Some(value)
400 }
401 } else {
402 None
403 }
404 }
405
406 pub(crate) fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
407 where
408 K: Borrow<Q> + Clone,
409 Q: ?Sized + Hash + Eq,
410 {
411 if let Some(&node) = self.map.get(key) {
412 unsafe {
413 let entry = (*node).get_value();
415 let object_size = self.estimate_object_size(&entry.key, &entry.value);
416 let meta = entry.metadata.as_ref().unwrap();
417 self.metrics.core.record_hit(object_size);
418 self.metrics
419 .record_item_access(meta.frequency, entry.size, meta.priority);
420
421 let new_node = self.update_priority_by_node(node);
422 let entry_mut = (*new_node).get_value_mut();
423 Some(&mut entry_mut.value)
424 }
425 } else {
426 None
427 }
428 }
429
430 pub(crate) fn contains_key<Q>(&self, key: &Q) -> bool
431 where
432 K: Borrow<Q>,
433 Q: ?Sized + Hash + Eq,
434 {
435 self.map.contains_key(key)
436 }
437
438 pub(crate) fn put(&mut self, key: K, val: V, size: u64) -> Option<V>
439 where
440 K: Clone,
441 {
442 if size == 0 {
443 return None;
444 }
445
446 let object_size = self.estimate_object_size(&key, &val);
447
448 if let Some(&node) = self.map.get(&key) {
450 unsafe {
451 let entry = (*node).get_value_mut();
453 let old_size = entry.size;
454 let meta = entry.metadata_mut().unwrap();
455 let old_priority_key = (meta.priority * 1000.0) as u64;
456 let frequency = meta.frequency;
457
458 let list = self.priority_lists.get_mut(&old_priority_key).unwrap();
460 let boxed_entry = list.remove(node).unwrap();
461
462 if list.is_empty() {
463 self.priority_lists.remove(&old_priority_key);
464 }
465
466 let entry_ptr = Box::into_raw(boxed_entry);
467 let old_value = (*entry_ptr).get_value().value.clone();
468 let _ = Box::from_raw(entry_ptr);
469
470 self.current_size = self.current_size.saturating_sub(old_size);
472 self.current_size += size;
473
474 let new_priority = self.calculate_priority(frequency, size);
476 let new_priority_key = (new_priority * 1000.0) as u64;
477
478 let new_entry = CacheEntry::with_metadata(
479 key.clone(),
480 val,
481 size,
482 GdsfMeta::new(frequency, new_priority),
483 );
484
485 let capacity = self.cap();
486 let list = self
487 .priority_lists
488 .entry(new_priority_key)
489 .or_insert_with(|| List::new(capacity));
490
491 if let Some(new_node) = list.add(new_entry) {
492 self.map.insert(key, new_node);
493 self.metrics.core.record_insertion(object_size);
494 return Some(old_value);
495 } else {
496 self.map.remove(&key);
497 return None;
498 }
499 }
500 }
501
502 let capacity = self.config.capacity.get();
504 let max_size = self.config.max_size;
505
506 while self.len() >= capacity
507 || (self.current_size + size > max_size && !self.map.is_empty())
508 {
509 self.evict_one();
510 }
511
512 let priority = self.calculate_priority(1, size);
513 let priority_key = (priority * 1000.0) as u64;
514
515 let cap = self.config.capacity;
516 let list = self
517 .priority_lists
518 .entry(priority_key)
519 .or_insert_with(|| List::new(cap));
520
521 let cache_entry =
522 CacheEntry::with_metadata(key.clone(), val, size, GdsfMeta::new(1, priority));
523
524 if let Some(node) = list.add(cache_entry) {
525 self.map.insert(key, node);
526 self.current_size += size;
527
528 if self.len() == 1 || priority < self.min_priority {
529 self.min_priority = priority;
530 }
531
532 self.metrics.core.record_insertion(size);
533 self.metrics
534 .record_item_cached(size, self.metrics.average_item_size());
535 self.metrics.record_item_access(1, size, priority);
536
537 None
538 } else {
539 None
540 }
541 }
542
543 fn evict_one(&mut self) {
544 if self.is_empty() {
545 return;
546 }
547
548 let min_priority_key = *self.priority_lists.keys().next().unwrap();
549 let list = self.priority_lists.get_mut(&min_priority_key).unwrap();
550
551 if let Some(boxed_entry) = list.remove_last() {
552 unsafe {
553 let entry_ptr = Box::into_raw(boxed_entry);
555 let entry = (*entry_ptr).get_value();
556 let evicted_size = entry.size;
557 let priority_to_update = entry
558 .metadata
559 .as_ref()
560 .map(|m| m.priority)
561 .unwrap_or(self.global_age);
562
563 self.current_size = self.current_size.saturating_sub(evicted_size);
564 self.metrics.core.record_eviction(evicted_size);
565 self.metrics.record_size_based_eviction();
566 self.metrics.record_aging_event(priority_to_update);
567
568 self.global_age = priority_to_update;
569 self.map.remove(&entry.key);
570
571 let _ = Box::from_raw(entry_ptr);
572 }
573 }
574
575 if list.is_empty() {
576 self.priority_lists.remove(&min_priority_key);
577 }
578 }
579
580 pub(crate) fn pop<Q>(&mut self, key: &Q) -> Option<V>
581 where
582 K: Borrow<Q>,
583 Q: ?Sized + Hash + Eq,
584 {
585 if let Some(node) = self.map.remove(key) {
586 unsafe {
587 let entry = (*node).get_value();
589 let removed_size = entry.size;
590 let priority = entry.metadata.as_ref().map(|m| m.priority).unwrap_or(0.0);
591 let priority_key = (priority * 1000.0) as u64;
592
593 let list = self.priority_lists.get_mut(&priority_key).unwrap();
594 let boxed_entry = list.remove(node).unwrap();
595
596 if list.is_empty() {
597 self.priority_lists.remove(&priority_key);
598 }
599
600 let entry_ptr = Box::into_raw(boxed_entry);
601 let result = (*entry_ptr).get_value().value.clone();
602 self.current_size = self.current_size.saturating_sub(removed_size);
603 let _ = Box::from_raw(entry_ptr);
604
605 Some(result)
606 }
607 } else {
608 None
609 }
610 }
611
612 pub(crate) fn clear(&mut self) {
613 self.map.clear();
614 self.priority_lists.clear();
615 self.global_age = 0.0;
616 self.min_priority = 0.0;
617 self.current_size = 0;
618 }
619}
620
621impl<K, V, S> core::fmt::Debug for GdsfSegment<K, V, S> {
622 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
623 f.debug_struct("GdsfSegment")
624 .field("capacity", &self.config.capacity)
625 .field("len", &self.map.len())
626 .field("global_age", &self.global_age)
627 .finish()
628 }
629}
630
631#[derive(Debug)]
633pub struct GdsfCache<K, V, S = DefaultHashBuilder> {
634 segment: GdsfSegment<K, V, S>,
635}
636
637impl<K: Hash + Eq, V: Clone, S: BuildHasher> GdsfCache<K, V, S> {
638 #[inline]
639 pub fn cap(&self) -> NonZeroUsize {
640 self.segment.cap()
641 }
642
643 #[inline]
644 pub fn len(&self) -> usize {
645 self.segment.len()
646 }
647
648 #[inline]
649 pub fn is_empty(&self) -> bool {
650 self.segment.is_empty()
651 }
652
653 #[inline]
655 pub fn current_size(&self) -> u64 {
656 self.segment.current_size()
657 }
658
659 #[inline]
661 pub fn max_size(&self) -> u64 {
662 self.segment.max_size()
663 }
664
665 #[inline]
666 pub fn global_age(&self) -> f64 {
667 self.segment.global_age()
668 }
669
670 #[inline]
671 pub fn record_miss(&mut self, object_size: u64) {
672 self.segment.record_miss(object_size);
673 }
674
675 #[inline]
676 pub fn get<Q>(&mut self, key: &Q) -> Option<V>
677 where
678 K: Borrow<Q> + Clone,
679 Q: ?Sized + Hash + Eq,
680 {
681 self.segment.get(key)
682 }
683
684 #[inline]
685 pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
686 where
687 K: Borrow<Q> + Clone,
688 Q: ?Sized + Hash + Eq,
689 {
690 self.segment.get_mut(key)
691 }
692
693 #[inline]
694 pub fn contains_key<Q>(&self, key: &Q) -> bool
695 where
696 K: Borrow<Q>,
697 Q: ?Sized + Hash + Eq,
698 {
699 self.segment.contains_key(key)
700 }
701
702 #[inline]
703 pub fn put(&mut self, key: K, val: V, size: u64) -> Option<V>
704 where
705 K: Clone,
706 {
707 self.segment.put(key, val, size)
708 }
709
710 #[inline]
711 pub fn pop<Q>(&mut self, key: &Q) -> Option<V>
712 where
713 K: Borrow<Q>,
714 Q: ?Sized + Hash + Eq,
715 {
716 self.segment.pop(key)
717 }
718
719 #[inline]
720 pub fn clear(&mut self) {
721 self.segment.clear()
722 }
723}
724
725impl<K: Hash + Eq, V: Clone, S: BuildHasher> CacheMetrics for GdsfCache<K, V, S> {
726 fn metrics(&self) -> BTreeMap<String, f64> {
727 self.segment.metrics().metrics()
728 }
729
730 fn algorithm_name(&self) -> &'static str {
731 self.segment.metrics().algorithm_name()
732 }
733}
734
735impl<K: Hash + Eq, V: Clone> GdsfCache<K, V, DefaultHashBuilder> {
736 pub fn init(config: GdsfCacheConfig, hasher: Option<DefaultHashBuilder>) -> Self {
771 GdsfCache {
772 segment: GdsfSegment::init(config, hasher.unwrap_or_default()),
773 }
774 }
775}
776
777#[cfg(test)]
778mod tests {
779 use super::*;
780 use crate::config::GdsfCacheConfig;
781 use core::num::NonZeroUsize;
782
783 fn make_cache<K: Hash + Eq + Clone, V: Clone>(cap: usize) -> GdsfCache<K, V> {
785 let config = GdsfCacheConfig {
786 capacity: NonZeroUsize::new(cap).unwrap(),
787 initial_age: 0.0,
788 max_size: u64::MAX,
789 };
790 GdsfCache::init(config, None)
791 }
792
793 #[test]
794 fn test_gdsf_basic_operations() {
795 let mut cache = make_cache(3);
796
797 assert_eq!(cache.put("a", 1, 1), None);
798 assert_eq!(cache.put("b", 2, 2), None);
799 assert_eq!(cache.put("c", 3, 1), None);
800 assert_eq!(cache.len(), 3);
801
802 assert_eq!(cache.get(&"a"), Some(1));
803 assert_eq!(cache.get(&"b"), Some(2));
804 assert_eq!(cache.get(&"c"), Some(3));
805
806 assert!(cache.contains_key(&"a"));
807 assert!(!cache.contains_key(&"d"));
808 }
809
810 #[test]
811 fn test_gdsf_frequency_priority() {
812 let mut cache = make_cache(2);
813
814 cache.put("a", 1, 1);
815 cache.put("b", 2, 1);
816
817 cache.get(&"a");
818 cache.get(&"a");
819
820 cache.put("c", 3, 1);
821
822 assert!(cache.contains_key(&"a"));
823 assert!(!cache.contains_key(&"b"));
824 assert!(cache.contains_key(&"c"));
825 }
826
827 #[test]
828 fn test_gdsf_size_consideration() {
829 let mut cache = make_cache(2);
830
831 cache.put("small", 1, 1);
832 cache.put("large", 2, 10);
833
834 cache.put("medium", 3, 5);
835
836 assert!(cache.contains_key(&"small"));
837 assert!(!cache.contains_key(&"large"));
838 assert!(cache.contains_key(&"medium"));
839 }
840
841 #[test]
842 fn test_gdsf_update_existing() {
843 let mut cache = make_cache(2);
844
845 cache.put("key", 1, 1);
846 assert_eq!(cache.get(&"key"), Some(1));
847
848 assert_eq!(cache.put("key", 2, 2), Some(1));
849 assert_eq!(cache.get(&"key"), Some(2));
850 assert_eq!(cache.len(), 1);
851 }
852
853 #[test]
854 fn test_gdsf_zero_size_rejection() {
855 let mut cache = make_cache(2);
856
857 assert_eq!(cache.put("key", 1, 0), None);
858 assert_eq!(cache.len(), 0);
859 assert!(!cache.contains_key(&"key"));
860 }
861
862 #[test]
863 fn test_gdsf_pop() {
864 let mut cache = make_cache(2);
865
866 cache.put("a", 1, 1);
867 cache.put("b", 2, 1);
868
869 assert_eq!(cache.pop(&"a"), Some(1));
870 assert_eq!(cache.len(), 1);
871 assert!(!cache.contains_key(&"a"));
872 assert!(cache.contains_key(&"b"));
873
874 assert_eq!(cache.pop(&"nonexistent"), None);
875 }
876
877 #[test]
878 fn test_gdsf_clear() {
879 let mut cache = make_cache(2);
880
881 cache.put("a", 1, 1);
882 cache.put("b", 2, 1);
883 assert_eq!(cache.len(), 2);
884
885 cache.clear();
886 assert_eq!(cache.len(), 0);
887 assert!(cache.is_empty());
888 assert!(!cache.contains_key(&"a"));
889 assert!(!cache.contains_key(&"b"));
890 }
891
892 #[test]
893 fn test_gdsf_global_aging() {
894 let mut cache = make_cache(2);
895
896 cache.put("a", 1, 1);
897 cache.put("b", 2, 1);
898
899 let initial_age = cache.global_age();
900
901 cache.put("c", 3, 1);
902
903 assert!(cache.global_age() > initial_age);
904 }
905
906 #[test]
907 fn test_miri_stacked_borrows_fix() {
908 let mut cache = make_cache(10);
909
910 cache.put("a", 1, 10);
911 cache.put("b", 2, 20);
912 cache.put("c", 3, 15);
913
914 for _ in 0..3 {
915 assert_eq!(cache.get(&"a"), Some(1));
916 assert_eq!(cache.get(&"b"), Some(2));
917 assert_eq!(cache.get(&"c"), Some(3));
918 }
919
920 assert_eq!(cache.len(), 3);
921
922 if let Some(val) = cache.get_mut(&"a") {
923 *val += 10;
924 }
925 assert_eq!(cache.get(&"a"), Some(11));
926 }
927
928 #[test]
929 fn test_gdsf_segment_directly() {
930 let config = GdsfCacheConfig {
931 capacity: NonZeroUsize::new(2).unwrap(),
932 initial_age: 0.0,
933 max_size: u64::MAX,
934 };
935 let mut segment: GdsfSegment<&str, i32, DefaultHashBuilder> =
936 GdsfSegment::init(config, DefaultHashBuilder::default());
937 assert_eq!(segment.len(), 0);
938 assert!(segment.is_empty());
939 assert_eq!(segment.cap().get(), 2);
940 segment.put("a", 1, 1);
941 segment.put("b", 2, 2);
942 assert_eq!(segment.len(), 2);
943 assert_eq!(segment.get(&"a"), Some(1));
944 assert_eq!(segment.get(&"b"), Some(2));
945 }
946
947 #[test]
948 fn test_gdsf_concurrent_access() {
949 extern crate std;
950 use std::sync::{Arc, Mutex};
951 use std::thread;
952 use std::vec::Vec;
953
954 let cache = Arc::new(Mutex::new(make_cache::<String, i32>(100)));
955 let num_threads = 4;
956 let ops_per_thread = 100;
957
958 let mut handles: Vec<std::thread::JoinHandle<()>> = Vec::new();
959
960 for t in 0..num_threads {
961 let cache = Arc::clone(&cache);
962 handles.push(thread::spawn(move || {
963 for i in 0..ops_per_thread {
964 let key = std::format!("key_{}_{}", t, i);
965 let size = ((i % 10) + 1) as u64; let mut guard = cache.lock().unwrap();
967 guard.put(key.clone(), i, size);
968 let _ = guard.get(&key);
969 }
970 }));
971 }
972
973 for handle in handles {
974 handle.join().unwrap();
975 }
976
977 let mut guard = cache.lock().unwrap();
978 assert!(guard.len() <= 100);
979 guard.clear(); }
981
982 #[test]
983 fn test_gdsf_size_aware_tracking() {
984 let mut cache = make_cache(10);
985
986 assert_eq!(cache.current_size(), 0);
987 assert_eq!(cache.max_size(), u64::MAX);
988
989 cache.put("a", 1, 100);
991 cache.put("b", 2, 200);
992 cache.put("c", 3, 150);
993
994 assert_eq!(cache.current_size(), 450);
995 assert_eq!(cache.len(), 3);
996
997 cache.clear();
999 assert_eq!(cache.current_size(), 0);
1000 }
1001
1002 #[test]
1003 fn test_gdsf_init_constructor() {
1004 let config = GdsfCacheConfig {
1005 capacity: NonZeroUsize::new(1000).unwrap(),
1006 initial_age: 0.0,
1007 max_size: 1024 * 1024,
1008 };
1009 let cache: GdsfCache<String, i32> = GdsfCache::init(config, None);
1010
1011 assert_eq!(cache.current_size(), 0);
1012 assert_eq!(cache.max_size(), 1024 * 1024);
1013 }
1014
1015 #[test]
1016 fn test_gdsf_with_limits_constructor() {
1017 let config = GdsfCacheConfig {
1018 capacity: NonZeroUsize::new(100).unwrap(),
1019 initial_age: 0.0,
1020 max_size: 1024 * 1024,
1021 };
1022 let cache: GdsfCache<String, String> = GdsfCache::init(config, None);
1023
1024 assert_eq!(cache.current_size(), 0);
1025 assert_eq!(cache.max_size(), 1024 * 1024);
1026 assert_eq!(cache.cap().get(), 100);
1027 }
1028}