1use crate::cache;
4
5#[cfg(feature = "object-cache-dynamic")]
6mod memory {
7 use std::num::NonZeroUsize;
8
9 use clru::WeightScale;
10
11 use crate::{cache, cache::set_vec_to_slice};
12
13 struct Entry {
14 data: Vec<u8>,
15 kind: gix_object::Kind,
16 }
17
18 type Key = gix_hash::ObjectId;
19
20 struct CustomScale;
21
22 impl WeightScale<Key, Entry> for CustomScale {
23 fn weight(&self, key: &Key, value: &Entry) -> usize {
24 value.data.len() + std::mem::size_of::<Entry>() + key.as_bytes().len()
25 }
26 }
27
28 pub struct MemoryCappedHashmap {
30 inner: clru::CLruCache<Key, Entry, gix_hashtable::hash::Builder, CustomScale>,
31 free_list: Vec<Vec<u8>>,
32 debug: gix_features::cache::Debug,
33 }
34
35 impl MemoryCappedHashmap {
36 pub fn capacity(&self) -> usize {
38 self.inner.capacity()
39 }
40 pub fn new(memory_cap_in_bytes: usize) -> MemoryCappedHashmap {
43 MemoryCappedHashmap {
44 inner: clru::CLruCache::with_config(
45 clru::CLruCacheConfig::new(NonZeroUsize::new(memory_cap_in_bytes).expect("non zero"))
46 .with_hasher(gix_hashtable::hash::Builder)
47 .with_scale(CustomScale),
48 ),
49 free_list: Vec::new(),
50 debug: gix_features::cache::Debug::new(format!("MemoryCappedObjectHashmap({memory_cap_in_bytes}B)")),
51 }
52 }
53 }
54
55 impl cache::Object for MemoryCappedHashmap {
56 fn put(&mut self, id: gix_hash::ObjectId, kind: gix_object::Kind, data: &[u8]) {
58 self.debug.put();
59 let Some(data) = set_vec_to_slice(self.free_list.pop().unwrap_or_default(), data) else {
60 return;
61 };
62 let res = self.inner.put_with_weight(id, Entry { data, kind });
63 match res {
64 Ok(Some(previous_entry)) => self.free_list.push(previous_entry.data),
65 Ok(None) => {}
66 Err((_key, value)) => self.free_list.push(value.data),
67 }
68 }
69
70 fn get(&mut self, id: &gix_hash::ObjectId, out: &mut Vec<u8>) -> Option<gix_object::Kind> {
72 let res = self.inner.get(id).and_then(|e| {
73 set_vec_to_slice(out, &e.data)?;
74 Some(e.kind)
75 });
76 if res.is_some() {
77 self.debug.hit();
78 } else {
79 self.debug.miss();
80 }
81 res
82 }
83 }
84}
85#[cfg(feature = "object-cache-dynamic")]
86pub use memory::MemoryCappedHashmap;
87
88pub struct Never;
90
91impl cache::Object for Never {
92 fn put(&mut self, _id: gix_hash::ObjectId, _kind: gix_object::Kind, _data: &[u8]) {}
94
95 fn get(&mut self, _id: &gix_hash::ObjectId, _out: &mut Vec<u8>) -> Option<gix_object::Kind> {
97 None
98 }
99}
100
101impl<T: cache::Object + ?Sized> cache::Object for Box<T> {
102 fn put(&mut self, id: gix_hash::ObjectId, kind: gix_object::Kind, data: &[u8]) {
103 use std::ops::DerefMut;
104 self.deref_mut().put(id, kind, data);
105 }
106
107 fn get(&mut self, id: &gix_hash::ObjectId, out: &mut Vec<u8>) -> Option<gix_object::Kind> {
108 use std::ops::DerefMut;
109 self.deref_mut().get(id, out)
110 }
111}