use crate::vector_search;
#[derive(Debug, Clone)]
pub struct MemoryCache {
pub chunks: Vec<String>,
pub embeddings: Vec<Vec<f32>>,
pub source_channels: Vec<String>,
pub timestamps: Vec<f64>,
pub session_ids: Vec<String>,
pub tags: Vec<String>,
pub tombstones: Vec<u8>,
pub embedding_dim: usize,
pub norms: Vec<f32>,
pub activation_weights: Vec<f32>,
}
impl MemoryCache {
pub fn new(embedding_dim: usize) -> Self {
Self {
chunks: Vec::new(),
embeddings: Vec::new(),
source_channels: Vec::new(),
timestamps: Vec::new(),
session_ids: Vec::new(),
tags: Vec::new(),
tombstones: Vec::new(),
embedding_dim,
norms: Vec::new(),
activation_weights: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.chunks.len()
}
pub fn is_empty(&self) -> bool {
self.chunks.is_empty()
}
pub fn count_active(&self) -> usize {
self.tombstones.iter().filter(|&&t| t == 0).count()
}
pub fn push(
&mut self,
chunk: String,
embedding: Vec<f32>,
source_channel: String,
timestamp: f64,
session_id: String,
tags: String,
) -> usize {
let idx = self.chunks.len();
let norm = vector_search::compute_norm(&embedding);
self.chunks.push(chunk);
self.embeddings.push(embedding);
self.source_channels.push(source_channel);
self.timestamps.push(timestamp);
self.session_ids.push(session_id);
self.tags.push(tags);
self.tombstones.push(0);
self.norms.push(norm);
self.activation_weights.push(1.0);
idx
}
pub fn mark_deleted(&mut self, id: usize) -> bool {
if id < self.tombstones.len() && self.tombstones[id] == 0 {
self.tombstones[id] = 1;
true
} else {
false
}
}
pub fn tombstone_fraction(&self) -> f32 {
if self.chunks.is_empty() {
return 0.0;
}
let tombstoned = self.tombstones.iter().filter(|&&t| t == 1).count();
tombstoned as f32 / self.chunks.len() as f32
}
pub fn compact(&mut self) -> (usize, Vec<Option<usize>>) {
let old_len = self.chunks.len();
let mut index_map = vec![None; old_len];
let mut new_idx = 0usize;
let mut new_chunks = Vec::new();
let mut new_embeddings = Vec::new();
let mut new_source_channels = Vec::new();
let mut new_timestamps = Vec::new();
let mut new_session_ids = Vec::new();
let mut new_tags = Vec::new();
let mut new_tombstones = Vec::new();
let mut new_norms = Vec::new();
let mut new_activation_weights = Vec::new();
for (i, slot) in index_map.iter_mut().enumerate() {
if self.tombstones[i] == 0 {
*slot = Some(new_idx);
new_idx += 1;
let norm = vector_search::compute_norm(&self.embeddings[i]);
new_chunks.push(self.chunks[i].clone());
new_embeddings.push(self.embeddings[i].clone());
new_source_channels.push(self.source_channels[i].clone());
new_timestamps.push(self.timestamps[i]);
new_session_ids.push(self.session_ids[i].clone());
new_tags.push(self.tags[i].clone());
new_tombstones.push(0u8);
new_norms.push(norm);
new_activation_weights.push(self.activation_weights[i]);
}
}
let removed = old_len - new_chunks.len();
self.chunks = new_chunks;
self.embeddings = new_embeddings;
self.source_channels = new_source_channels;
self.timestamps = new_timestamps;
self.session_ids = new_session_ids;
self.tags = new_tags;
self.tombstones = new_tombstones;
self.norms = new_norms;
self.activation_weights = new_activation_weights;
(removed, index_map)
}
pub fn flat_embeddings(&self) -> Vec<f32> {
let mut flat = Vec::with_capacity(self.embeddings.len() * self.embedding_dim);
for emb in &self.embeddings {
flat.extend_from_slice(emb);
}
flat
}
}