Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/common/ttl_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ where
Self {
buckets,
data: stage_targets,
time: Arc::new(AtomicU64::new(0)),
// Explicitly initialize `time` to 1 to avoid underflow issues with circular buffer.
time: Arc::new(AtomicU64::new(1)),
Comment on lines -187 to +188
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 nice. Any chance to reproduce this in a test that fails in main and succeeds in this branch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's a good q let me think on that for a minute

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! PTAL

gc_scheduler_task: None,
config,
#[cfg(test)]
Expand Down Expand Up @@ -446,6 +447,34 @@ mod tests {
assert!(final_time < 100);
}

#[tokio::test]
async fn test_initial_time() {
// Create a map with 7 buckets. 7 is chosen specifically as it
// has the property that (2^64 - 1) % 7 = 1, whereas (0 - 1) % 7 = 6.
let ttl_map = TTLMap::<String, i32>::_new(TTLMapConfig {
ttl: Duration::from_millis(70),
tick: Duration::from_millis(10),
});

ttl_map.get_or_init("test_key".to_string(), || 999);

// Advance GC 3 times, which shouldn't free the first key.
for _ in 0..3 {
TTLMap::<String, i32>::gc(ttl_map.time.clone(), &ttl_map.buckets);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think we can just truncate everything after this.


tokio::time::sleep(Duration::from_millis(10)).await;
// Check that we still have our key. Have to wait before asserting to avoid the assertion
// being spuriously true.
assert_eq!(ttl_map.data.len(), 1);

// Run GC for 4 more steps, at which point the first key should be removed.
for _ in 0..4 {
TTLMap::<String, i32>::gc(ttl_map.time.clone(), &ttl_map.buckets);
}
assert_eventually(|| ttl_map.data.is_empty(), Duration::from_millis(100)).await;
}

// Run with `cargo test bench_lock_contention --release -- --nocapture` to see output.
#[tokio::test(flavor = "multi_thread", worker_threads = 16)]
async fn bench_lock_contention() {
Expand Down