use std::collections::{HashMap, HashSet};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(transparent)]
pub struct KvCacheMap(HashMap<String, String>);
impl KvCacheMap {
pub fn chunk_hashes(&self) -> Vec<String> {
self.0.keys().cloned().collect()
}
pub fn diff_deleted(&self, new_hashes: &[String]) -> Vec<String> {
let new_set: HashSet<&String> = new_hashes.iter().collect();
self.0
.keys()
.filter(|h| !new_set.contains(*h))
.cloned()
.collect()
}
pub fn replace(&mut self, new_hashes: &[String], text: &str) {
self.0.clear();
for h in new_hashes {
self.0.insert(h.clone(), text.to_string());
}
}
}
pub fn spawn_prefetch(chunk_hashes: Vec<String>, lookup_id: String) {
if chunk_hashes.is_empty() {
return;
}
let count = chunk_hashes.len();
tokio::spawn(async move {
let payload = serde_json::json!({
"chunk_hashes": chunk_hashes,
"lookup_id": lookup_id,
});
match reqwest::Client::new()
.post("http://localhost:6999/memory/prefetch")
.json(&payload)
.send()
.await
{
Ok(resp) => {
let status = resp.status();
tracing::info!(
status = %status,
count = count,
"kv cache prefetch completed"
);
}
Err(e) => {
tracing::warn!(
error = %e,
count = count,
"kv cache prefetch failed"
);
}
}
});
}
pub fn spawn_evict(deleted_hashes: Vec<String>) {
if deleted_hashes.is_empty() {
return;
}
let count = deleted_hashes.len();
tokio::spawn(async move {
let payload = serde_json::json!({
"chunk_hashes": deleted_hashes,
});
match reqwest::Client::new()
.post("http://localhost:6999/memory/evict")
.json(&payload)
.send()
.await
{
Ok(resp) => {
tracing::info!(
status = %resp.status(),
count = count,
"kv cache evict completed"
);
}
Err(e) => {
tracing::warn!(
error = %e,
count = count,
"kv cache evict failed"
);
}
}
});
}