use super::Session;
use crate::persistence::CrossProcessFileLock;
impl Session {
pub(crate) fn try_frontend_writer(&self) -> anyhow::Result<Option<CrossProcessFileLock>> {
let root = self
.path
.parent()
.ok_or_else(|| anyhow::anyhow!("missing root"))?;
super::store::prepare_session_root(root)?;
CrossProcessFileLock::try_acquire(&self.path.with_extension("writer"))
}
}
#[cfg(test)]
mod tests {
use super::super::SessionManager;
use tempfile::TempDir;
#[test]
fn writer_conflict_and_dead_owner_recovery_cross_process() {
const ROOT: &str = "MAGI_TEST_SESSION_WRITER_ROOT";
const MODE: &str = "MAGI_TEST_SESSION_WRITER_MODE";
if let Some(root) = std::env::var_os(ROOT) {
let session = SessionManager::new(root.into())
.open("writer-test")
.unwrap();
let lease = session.try_frontend_writer().unwrap();
if std::env::var(MODE).unwrap() == "conflict" {
assert!(lease.is_none());
return;
}
assert!(lease.is_some());
std::process::exit(0);
}
let temp = TempDir::new().unwrap();
let root = temp.path().join("sessions");
let session = SessionManager::new(root.clone())
.open("writer-test")
.unwrap();
let owner = session.try_frontend_writer().unwrap().unwrap();
let child = |mode: &str| {
let output = std::process::Command::new(std::env::current_exe().unwrap())
.args(["--exact", "sessions::writer::tests::writer_conflict_and_dead_owner_recovery_cross_process", "--quiet"])
.env(ROOT, &root).env(MODE, mode).output().unwrap();
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
};
child("conflict");
drop(owner);
child("abandon");
assert!(session.try_frontend_writer().unwrap().is_some());
}
}