No lock-contention in ip-tracker

This commit is contained in:
Alexey 2026-03-05 13:52:27 +03:00
parent 0b1a8cd3f8
commit 83cadc0bf3
No known key found for this signature in database
1 changed files with 13 additions and 12 deletions

View File

@ -134,20 +134,20 @@ impl UserIpTracker {
pub async fn get_recent_counts_for_users(&self, users: &[String]) -> HashMap<String, usize> { pub async fn get_recent_counts_for_users(&self, users: &[String]) -> HashMap<String, usize> {
let window = *self.limit_window.read().await; let window = *self.limit_window.read().await;
let now = Instant::now(); let now = Instant::now();
let mut recent_ips = self.recent_ips.write().await; let recent_ips = self.recent_ips.read().await;
let mut counts = HashMap::with_capacity(users.len()); let mut counts = HashMap::with_capacity(users.len());
for user in users { for user in users {
let count = if let Some(user_recent) = recent_ips.get_mut(user) { let count = if let Some(user_recent) = recent_ips.get(user) {
Self::prune_recent(user_recent, now, window); user_recent
user_recent.len() .values()
.filter(|seen_at| now.duration_since(**seen_at) <= window)
.count()
} else { } else {
0 0
}; };
counts.insert(user.clone(), count); counts.insert(user.clone(), count);
} }
recent_ips.retain(|_, user_recent| !user_recent.is_empty());
counts counts
} }
@ -168,21 +168,22 @@ impl UserIpTracker {
pub async fn get_recent_ips_for_users(&self, users: &[String]) -> HashMap<String, Vec<IpAddr>> { pub async fn get_recent_ips_for_users(&self, users: &[String]) -> HashMap<String, Vec<IpAddr>> {
let window = *self.limit_window.read().await; let window = *self.limit_window.read().await;
let now = Instant::now(); let now = Instant::now();
let mut recent_ips = self.recent_ips.write().await; let recent_ips = self.recent_ips.read().await;
let mut out = HashMap::with_capacity(users.len()); let mut out = HashMap::with_capacity(users.len());
for user in users { for user in users {
let mut ips = if let Some(user_recent) = recent_ips.get_mut(user) { let mut ips = if let Some(user_recent) = recent_ips.get(user) {
Self::prune_recent(user_recent, now, window); user_recent
user_recent.keys().copied().collect::<Vec<_>>() .iter()
.filter(|(_, seen_at)| now.duration_since(**seen_at) <= window)
.map(|(ip, _)| *ip)
.collect::<Vec<_>>()
} else { } else {
Vec::new() Vec::new()
}; };
ips.sort(); ips.sort();
out.insert(user.clone(), ips); out.insert(user.clone(), ips);
} }
recent_ips.retain(|_, user_recent| !user_recent.is_empty());
out out
} }