use dashmap::DashMap;
use crate::{hash::ObjectHash, internal::pack::cache_object::CacheObject};
#[derive(Default, Debug)]
pub struct Waitlist {
pub map_offset: DashMap<usize, Vec<CacheObject>>,
pub map_ref: DashMap<ObjectHash, Vec<CacheObject>>,
}
impl Waitlist {
pub fn new() -> Self {
Self::default()
}
pub fn insert_offset(&self, offset: usize, obj: CacheObject) {
self.map_offset.entry(offset).or_default().push(obj);
}
pub fn insert_ref(&self, hash: ObjectHash, obj: CacheObject) {
self.map_ref.entry(hash).or_default().push(obj);
}
pub fn take(&self, offset: usize, hash: ObjectHash) -> Vec<CacheObject> {
let mut res = Vec::new();
if let Some((_, vec)) = self.map_offset.remove(&offset) {
res.extend(vec);
}
if let Some((_, vec)) = self.map_ref.remove(&hash) {
res.extend(vec);
}
res
}
pub fn has_waiters(&self, offset: usize, hash: ObjectHash) -> bool {
self.map_offset.contains_key(&offset) || self.map_ref.contains_key(&hash)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::internal::{object::types::ObjectType, pack::cache_object::CacheObjectInfo};
fn make_test_obj(offset: usize) -> CacheObject {
CacheObject {
info: CacheObjectInfo::BaseObject(ObjectType::Blob, ObjectHash::default()),
offset,
crc32: 0,
data_decompressed: vec![],
mem_recorder: None,
is_delta_in_pack: false,
known_hash: None,
}
}
#[test]
fn test_waitlist_offset() {
let waitlist = Waitlist::new();
let obj1 = make_test_obj(10);
let obj2 = make_test_obj(20);
waitlist.insert_offset(100, obj1);
waitlist.insert_offset(100, obj2);
let res = waitlist.take(100, ObjectHash::default());
assert_eq!(res.len(), 2);
assert_eq!(res[0].offset, 10);
assert_eq!(res[1].offset, 20);
let res_empty = waitlist.take(100, ObjectHash::default());
assert!(res_empty.is_empty());
}
#[test]
fn test_waitlist_ref() {
let waitlist = Waitlist::new();
let hash = ObjectHash::new(b"test_hash");
let obj = make_test_obj(30);
waitlist.insert_ref(hash, obj);
let res = waitlist.take(0, hash);
assert_eq!(res.len(), 1);
assert_eq!(res[0].offset, 30);
let res_empty = waitlist.take(0, hash);
assert!(res_empty.is_empty());
}
#[test]
fn test_waitlist_mixed() {
let waitlist = Waitlist::new();
let hash = ObjectHash::new(b"test_hash");
let offset = 200;
let obj1 = make_test_obj(1);
let obj2 = make_test_obj(2);
waitlist.insert_offset(offset, obj1);
waitlist.insert_ref(hash, obj2);
let res = waitlist.take(offset, hash);
assert_eq!(res.len(), 2);
assert!(res.iter().any(|o| o.offset == 1));
assert!(res.iter().any(|o| o.offset == 2));
assert!(waitlist.map_offset.is_empty());
assert!(waitlist.map_ref.is_empty());
}
}