use crate::keyspace::Keyspace;
const SAMPLE_SIZE: usize = 20;
const EXPIRED_THRESHOLD: f64 = 0.25;
const MAX_ROUNDS: usize = 3;
pub fn run_expiration_cycle(ks: &mut Keyspace) -> usize {
let mut total_removed = 0;
for _ in 0..MAX_ROUNDS {
let removed = ks.expire_sample(SAMPLE_SIZE);
total_removed += removed;
if (removed as f64) < (SAMPLE_SIZE as f64) * EXPIRED_THRESHOLD {
break;
}
}
total_removed
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::Bytes;
use std::thread;
use std::time::Duration;
#[test]
fn no_expired_keys_removes_nothing() {
let mut ks = Keyspace::new();
for i in 0..10 {
ks.set(format!("key:{i}"), Bytes::from("val"), None, false, false);
}
let removed = run_expiration_cycle(&mut ks);
assert_eq!(removed, 0);
assert_eq!(ks.len(), 10);
}
#[test]
fn removes_expired_keys() {
let mut ks = Keyspace::new();
for i in 0..10 {
ks.set(
format!("temp:{i}"),
Bytes::from("gone"),
Some(Duration::from_millis(5)),
false,
false,
);
}
for i in 0..5 {
ks.set(format!("keep:{i}"), Bytes::from("stay"), None, false, false);
}
thread::sleep(Duration::from_millis(20));
let removed = run_expiration_cycle(&mut ks);
assert_eq!(removed, 10);
assert_eq!(ks.len(), 5);
}
#[test]
fn leaves_unexpired_keys_alone() {
let mut ks = Keyspace::new();
for i in 0..10 {
ks.set(
format!("key:{i}"),
Bytes::from("val"),
Some(Duration::from_secs(3600)),
false,
false,
);
}
let removed = run_expiration_cycle(&mut ks);
assert_eq!(removed, 0);
assert_eq!(ks.len(), 10);
}
#[test]
fn empty_keyspace_is_fine() {
let mut ks = Keyspace::new();
let removed = run_expiration_cycle(&mut ks);
assert_eq!(removed, 0);
}
}