use super::*;
const SESSIONS_RETENTION_NS: u64 = 90 * 24 * 60 * 60 * 1_000_000_000u64;
pub(super) fn lock_error_hint(err: anyhow::Error, db_path: &std::path::Path) -> anyhow::Error {
let msg = format!("{err}");
if msg.contains("already locked") || msg.contains("WouldBlock") {
let lock_file = db_path.join("LOCK");
let pid_hint = std::fs::read_to_string(&lock_file)
.ok()
.and_then(|s| s.trim().parse::<u32>().ok())
.map(|pid| format!(" (holder PID: {pid})"))
.unwrap_or_default();
anyhow::anyhow!(
"cannot open {} — another mati process holds the lock{pid_hint}.\n\
This is usually the MCP server (mati serve) or a background daemon.\n\
To stop the daemon: `mati daemon stop`\n\
To check: `lsof {}/LOCK`",
db_path.display(),
db_path.display()
)
} else {
err
}
}
pub(super) fn open_knowledge_tree(path: PathBuf) -> Result<Tree> {
let opts = Options::new()
.with_path(path)
.with_versioning(true, 0) .with_enable_vlog(true)
.with_vlog_value_threshold(0)
.with_vlog_checksum_verification(VLogChecksumLevel::Full);
TreeBuilder::with_options(opts)
.build()
.context("failed to open knowledge.db")
}
pub(super) fn open_sessions_tree(path: PathBuf) -> Result<Tree> {
let opts = Options::new()
.with_path(path)
.with_versioning(true, SESSIONS_RETENTION_NS)
.with_enable_vlog(true)
.with_vlog_value_threshold(0);
TreeBuilder::with_options(opts)
.build()
.context("failed to open sessions.db")
}