perf(server): offload sync disk/db IO to tokio blocking thread pool
Makes apply_sync_write, write_to_local_delta, and store modify truly async, preventing the mcp-memory-server from locking the tokio executor during disk IO
This commit is contained in:
1 parent
1fd1d119e6
commit
248799ca5d
5 files changed
+105
-40
No files matched your search
+41
-28
@@ -110,61 +110,74 @@ impl MemoryState {
|
||||
Self::merge_graphs(&mut master, &session_graph);
|
||||
master
|
||||
}
|
||||
pub fn write_to_local_delta<F: FnOnce(&mut KnowledgeGraph)>(&self, update_fn: F) {
|
||||
let mut session_graph = self.session_graph.write().unwrap();
|
||||
update_fn(&mut session_graph);
|
||||
let wal_path = self.base_dir.join("wal.jsonl");
|
||||
if let Ok(payload) = serde_json::to_string(&*session_graph)
|
||||
&& let Ok(mut file) = std::fs::OpenOptions::new()
|
||||
pub async fn write_to_local_delta<F: FnOnce(&mut KnowledgeGraph)>(&self, update_fn: F) {
|
||||
let payload = {
|
||||
let mut session_graph = self.session_graph.write().unwrap();
|
||||
update_fn(&mut session_graph);
|
||||
serde_json::to_string(&*session_graph).ok()
|
||||
};
|
||||
if let Some(payload) = payload {
|
||||
let wal_path = self.base_dir.join("wal.jsonl");
|
||||
if let Ok(mut file) = tokio::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(&wal_path)
|
||||
.await
|
||||
{
|
||||
use std::io::Write;
|
||||
let _ = writeln!(file, "{}", payload);
|
||||
use tokio::io::AsyncWriteExt;
|
||||
let _ = file.write_all(payload.as_bytes()).await;
|
||||
let _ = file.write_all(b"\n").await;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn apply_sync_write<F: FnOnce(&mut KnowledgeGraph)>(&self, update_fn: F) {
|
||||
pub async fn apply_sync_write<F: FnOnce(&mut KnowledgeGraph)>(&self, update_fn: F) {
|
||||
let lock_path = self.base_dir.join("master.lock");
|
||||
let mut attempts = 0;
|
||||
loop {
|
||||
if fs::OpenOptions::new()
|
||||
if tokio::fs::OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(&lock_path)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
break;
|
||||
}
|
||||
if attempts > 100 {
|
||||
let _ = fs::remove_file(&lock_path);
|
||||
let _ = tokio::fs::remove_file(&lock_path).await;
|
||||
}
|
||||
attempts += 1;
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
let mut master = self.get_full_graph();
|
||||
let wal_path = self.base_dir.join("wal.jsonl");
|
||||
let _ = fs::remove_file(&wal_path);
|
||||
let _ = tokio::fs::remove_file(&wal_path).await;
|
||||
*self.session_graph.write().unwrap() = KnowledgeGraph::default();
|
||||
update_fn(&mut master);
|
||||
|
||||
let write_json = |path: &std::path::Path, data: &KnowledgeGraph| -> std::io::Result<()> {
|
||||
if path.exists() {
|
||||
let bak_path = path.with_extension("json.bak");
|
||||
let _ = fs::copy(path, &bak_path);
|
||||
}
|
||||
let tmp_path = path.with_extension("json.tmp");
|
||||
let json_data = serde_json::to_string_pretty(data)?;
|
||||
fs::write(&tmp_path, json_data)?;
|
||||
fs::rename(&tmp_path, path)
|
||||
};
|
||||
let _ = write_json(&self.master_path, &master);
|
||||
let master_path = self.master_path.clone();
|
||||
let master_clone = master.clone();
|
||||
let _ = tokio::task::spawn_blocking(move || {
|
||||
let write_json = |path: &std::path::Path, data: &KnowledgeGraph| -> std::io::Result<()> {
|
||||
if path.exists() {
|
||||
let bak_path = path.with_extension("json.bak");
|
||||
let _ = std::fs::copy(path, &bak_path);
|
||||
}
|
||||
let tmp_path = path.with_extension("json.tmp");
|
||||
let json_data = serde_json::to_string_pretty(data)?;
|
||||
std::fs::write(&tmp_path, json_data)?;
|
||||
std::fs::rename(&tmp_path, path)
|
||||
};
|
||||
let _ = write_json(&master_path, &master_clone);
|
||||
}).await;
|
||||
|
||||
let mut cache_lock = self.master_cache.write().unwrap();
|
||||
cache_lock.0 = master;
|
||||
cache_lock.1 = self.master_mtime();
|
||||
{
|
||||
let mut cache_lock = self.master_cache.write().unwrap();
|
||||
cache_lock.0 = master;
|
||||
cache_lock.1 = self.master_mtime();
|
||||
}
|
||||
|
||||
let _ = fs::remove_file(&lock_path);
|
||||
let _ = tokio::fs::remove_file(&lock_path).await;
|
||||
}
|
||||
|
||||
pub fn rebuild_index(&self) {
|
||||
|
||||
Reference in new issue
Block a user