git_internal/internal/pack/
waitlist.rs1use dashmap::DashMap;
5
6use crate::{hash::ObjectHash, internal::pack::cache_object::CacheObject};
7
8#[derive(Default, Debug)]
11pub struct Waitlist {
12 pub map_offset: DashMap<usize, Vec<CacheObject>>,
14 pub map_ref: DashMap<ObjectHash, Vec<CacheObject>>,
15}
16
17impl Waitlist {
18 pub fn new() -> Self {
20 Self::default()
21 }
22
23 pub fn insert_offset(&self, offset: usize, obj: CacheObject) {
25 self.map_offset.entry(offset).or_default().push(obj);
26 }
27
28 pub fn insert_ref(&self, hash: ObjectHash, obj: CacheObject) {
30 self.map_ref.entry(hash).or_default().push(obj);
31 }
32
33 pub fn take(&self, offset: usize, hash: ObjectHash) -> Vec<CacheObject> {
36 let mut res = Vec::new();
37 if let Some((_, vec)) = self.map_offset.remove(&offset) {
38 res.extend(vec);
39 }
40 if let Some((_, vec)) = self.map_ref.remove(&hash) {
41 res.extend(vec);
42 }
43 res
44 }
45
46 pub fn has_waiters(&self, offset: usize, hash: ObjectHash) -> bool {
47 self.map_offset.contains_key(&offset) || self.map_ref.contains_key(&hash)
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use crate::internal::{object::types::ObjectType, pack::cache_object::CacheObjectInfo};
55
56 fn make_test_obj(offset: usize) -> CacheObject {
58 CacheObject {
59 info: CacheObjectInfo::BaseObject(ObjectType::Blob, ObjectHash::default()),
60 offset,
61 crc32: 0,
62 data_decompressed: vec![],
63 mem_recorder: None,
64 is_delta_in_pack: false,
65 known_hash: None,
66 }
67 }
68
69 #[test]
71 fn test_waitlist_offset() {
72 let waitlist = Waitlist::new();
73 let obj1 = make_test_obj(10);
74 let obj2 = make_test_obj(20);
75
76 waitlist.insert_offset(100, obj1);
77 waitlist.insert_offset(100, obj2);
78
79 let res = waitlist.take(100, ObjectHash::default());
80 assert_eq!(res.len(), 2);
81 assert_eq!(res[0].offset, 10);
82 assert_eq!(res[1].offset, 20);
83
84 let res_empty = waitlist.take(100, ObjectHash::default());
85 assert!(res_empty.is_empty());
86 }
87
88 #[test]
90 fn test_waitlist_ref() {
91 let waitlist = Waitlist::new();
92 let hash = ObjectHash::new(b"test_hash");
93 let obj = make_test_obj(30);
94
95 waitlist.insert_ref(hash, obj);
96
97 let res = waitlist.take(0, hash);
98 assert_eq!(res.len(), 1);
99 assert_eq!(res[0].offset, 30);
100
101 let res_empty = waitlist.take(0, hash);
102 assert!(res_empty.is_empty());
103 }
104
105 #[test]
107 fn test_waitlist_mixed() {
108 let waitlist = Waitlist::new();
109 let hash = ObjectHash::new(b"test_hash");
110 let offset = 200;
111
112 let obj1 = make_test_obj(1);
113 let obj2 = make_test_obj(2);
114
115 waitlist.insert_offset(offset, obj1);
116 waitlist.insert_ref(hash, obj2);
117
118 let res = waitlist.take(offset, hash);
120 assert_eq!(res.len(), 2);
121
122 assert!(res.iter().any(|o| o.offset == 1));
124 assert!(res.iter().any(|o| o.offset == 2));
125
126 assert!(waitlist.map_offset.is_empty());
128 assert!(waitlist.map_ref.is_empty());
129 }
130}