1use crate::cache;
6
7#[cfg(feature = "object-cache-dynamic")]
8mod memory {
9 use std::num::NonZeroUsize;
10
11 use clru::WeightScale;
12
13 use crate::cache;
14
15 struct Entry {
16 data: Vec<u8>,
17 kind: git_object::Kind,
18 }
19
20 type Key = git_hash::ObjectId;
21
22 struct CustomScale;
23
24 impl WeightScale<Key, Entry> for CustomScale {
25 fn weight(&self, key: &Key, value: &Entry) -> usize {
26 value.data.len() + std::mem::size_of::<Entry>() + key.as_bytes().len()
27 }
28 }
29
30 pub struct MemoryCappedHashmap {
32 inner: clru::CLruCache<Key, Entry, git_hashtable::hash::Builder, CustomScale>,
33 free_list: Vec<Vec<u8>>,
34 debug: git_features::cache::Debug,
35 }
36
37 impl MemoryCappedHashmap {
38 pub fn capacity(&self) -> usize {
40 self.inner.capacity()
41 }
42 pub fn new(memory_cap_in_bytes: usize) -> MemoryCappedHashmap {
45 MemoryCappedHashmap {
46 inner: clru::CLruCache::with_config(
47 clru::CLruCacheConfig::new(NonZeroUsize::new(memory_cap_in_bytes).expect("non zero"))
48 .with_hasher(git_hashtable::hash::Builder::default())
49 .with_scale(CustomScale),
50 ),
51 free_list: Vec::new(),
52 debug: git_features::cache::Debug::new(format!("MemoryCappedObjectHashmap({memory_cap_in_bytes}B)")),
53 }
54 }
55 }
56
57 impl cache::Object for MemoryCappedHashmap {
58 fn put(&mut self, id: git_hash::ObjectId, kind: git_object::Kind, data: &[u8]) {
60 self.debug.put();
61 if let Ok(Some(previous_entry)) = self.inner.put_with_weight(
62 id,
63 Entry {
64 data: self
65 .free_list
66 .pop()
67 .map(|mut v| {
68 v.clear();
69 v.resize(data.len(), 0);
70 v.copy_from_slice(data);
71 v
72 })
73 .unwrap_or_else(|| Vec::from(data)),
74 kind,
75 },
76 ) {
77 self.free_list.push(previous_entry.data)
78 }
79 }
80
81 fn get(&mut self, id: &git_hash::ObjectId, out: &mut Vec<u8>) -> Option<git_object::Kind> {
83 let res = self.inner.get(id).map(|e| {
84 out.resize(e.data.len(), 0);
85 out.copy_from_slice(&e.data);
86 e.kind
87 });
88 if res.is_some() {
89 self.debug.hit()
90 } else {
91 self.debug.miss()
92 }
93 res
94 }
95 }
96}
97#[cfg(feature = "object-cache-dynamic")]
98pub use memory::MemoryCappedHashmap;
99
100pub struct Never;
102
103impl cache::Object for Never {
104 fn put(&mut self, _id: git_hash::ObjectId, _kind: git_object::Kind, _data: &[u8]) {}
106
107 fn get(&mut self, _id: &git_hash::ObjectId, _out: &mut Vec<u8>) -> Option<git_object::Kind> {
109 None
110 }
111}
112
113impl<T: cache::Object + ?Sized> cache::Object for Box<T> {
114 fn put(&mut self, id: git_hash::ObjectId, kind: git_object::Kind, data: &[u8]) {
115 use std::ops::DerefMut;
116 self.deref_mut().put(id, kind, data)
117 }
118
119 fn get(&mut self, id: &git_hash::ObjectId, out: &mut Vec<u8>) -> Option<git_object::Kind> {
120 use std::ops::DerefMut;
121 self.deref_mut().get(id, out)
122 }
123}