Implement eviction in neighbor cache for fixed storage size.

This commit is contained in:
whitequark 2017-11-21 11:53:26 +00:00
parent 29a338228d
commit 52a6e27206
1 changed files with 55 additions and 2 deletions

View File

@ -85,9 +85,40 @@ impl<'a> Cache<'a> {
}
}
Ok(None) => {
net_trace!("filled {} => {}", protocol_addr, hardware_addr);
net_trace!("filled {} => {} (was empty)", protocol_addr, hardware_addr);
}
Err((protocol_addr, neighbor)) => {
// If we're going down this branch, it means that a fixed-size cache storage
// is full, and we need to evict an entry.
let old_protocol_addr = match self.storage {
ManagedMap::Borrowed(ref mut pairs) => {
pairs
.iter()
.min_by_key(|pair_opt| {
let (_protocol_addr, neighbor) = pair_opt.unwrap();
neighbor.expires_at
})
.expect("empty neighbor cache storage") // unwraps min_by_key
.unwrap() // unwraps pair
.0
}
// Owned maps can extend themselves.
ManagedMap::Owned(_) => unreachable!()
};
let _old_neighbor =
self.storage.remove(&old_protocol_addr).unwrap();
match self.storage.insert(protocol_addr, neighbor) {
Ok(None) => {
net_trace!("filled {} => {} (evicted {} => {})",
protocol_addr, hardware_addr,
old_protocol_addr, _old_neighbor.hardware_addr);
}
// We've covered everything else above.
_ => unreachable!()
}
}
Err(_) => unreachable!()
}
}
@ -130,9 +161,13 @@ mod test {
const HADDR_A: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 1]);
const HADDR_B: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 2]);
const HADDR_C: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 3]);
const HADDR_D: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 4]);
const PADDR_A: IpAddress = IpAddress::Ipv4(Ipv4Address([1, 0, 0, 1]));
const PADDR_B: IpAddress = IpAddress::Ipv4(Ipv4Address([1, 0, 0, 2]));
const PADDR_C: IpAddress = IpAddress::Ipv4(Ipv4Address([1, 0, 0, 3]));
const PADDR_D: IpAddress = IpAddress::Ipv4(Ipv4Address([1, 0, 0, 4]));
#[test]
fn test_fill() {
@ -172,6 +207,24 @@ mod test {
assert_eq!(cache.lookup_pure(&PADDR_A, 0), Some(HADDR_B));
}
#[test]
fn test_evict() {
let mut cache_storage = [Default::default(); 3];
let mut cache = Cache::new(&mut cache_storage[..]);
cache.fill(PADDR_A, HADDR_A, 100);
cache.fill(PADDR_B, HADDR_B, 50);
cache.fill(PADDR_C, HADDR_C, 200);
assert_eq!(cache.lookup_pure(&PADDR_B, 1000), Some(HADDR_B));
assert_eq!(cache.lookup_pure(&PADDR_D, 1000), None);
println!("{:?}", cache);
cache.fill(PADDR_D, HADDR_D, 300);
println!("{:?}", cache);
assert_eq!(cache.lookup_pure(&PADDR_B, 1000), None);
assert_eq!(cache.lookup_pure(&PADDR_D, 1000), Some(HADDR_D));
}
#[test]
fn test_hush() {
let mut cache_storage = [Default::default(); 3];