sausage core: modules per topic, journal writer thread with WAL and batches, hash cache by metadata, 49 tests per rule
Blank stdout lines give no warning. core.exit requests the exit in its own handler.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
//! Advisory FIFO locks and cleanup of ended processes.
|
||||
use crate::error;
|
||||
use crate::{Host, RpcResult, host::State};
|
||||
use serde_json::json;
|
||||
use std::collections::VecDeque;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
pub(crate) struct Lock {
|
||||
pub(crate) owner: String,
|
||||
pub(crate) queue: VecDeque<(String, oneshot::Sender<RpcResult>)>,
|
||||
}
|
||||
|
||||
impl Host {
|
||||
/// Acquire a FIFO queue position, or report whether the lock is free.
|
||||
pub(crate) async fn lock(&self, caller: &str, path: &str, wait: bool) -> RpcResult {
|
||||
let rx = {
|
||||
let mut state = self.0.state.lock().unwrap();
|
||||
if let Some(lock) = state.locks.get_mut(path) {
|
||||
if !wait {
|
||||
return Ok(json!({"held":false}));
|
||||
}
|
||||
let (tx, rx) = oneshot::channel();
|
||||
lock.queue.push_back((caller.into(), tx));
|
||||
Some(rx)
|
||||
} else {
|
||||
state.locks.insert(
|
||||
path.into(),
|
||||
Lock {
|
||||
owner: caller.into(),
|
||||
queue: VecDeque::new(),
|
||||
},
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
match rx {
|
||||
Some(rx) => rx
|
||||
.await
|
||||
.unwrap_or_else(|_| Err(error(-32603, "lock canceled"))),
|
||||
None => Ok(json!({"held":true})),
|
||||
}
|
||||
}
|
||||
/// Release a held lock only when this process owns it.
|
||||
pub(crate) fn unlock(&self, caller: &str, path: &str) {
|
||||
let mut state = self.0.state.lock().unwrap();
|
||||
if state
|
||||
.locks
|
||||
.get(path)
|
||||
.is_some_and(|lock| lock.owner == caller)
|
||||
{
|
||||
grant(&mut state, path);
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove queued acquisitions and grant the next owner of each held lock.
|
||||
pub(crate) fn release_locks(state: &mut State, pid: &str) {
|
||||
for lock in state.locks.values_mut() {
|
||||
lock.queue.retain(|(p, _)| p != pid);
|
||||
}
|
||||
let paths: Vec<_> = state
|
||||
.locks
|
||||
.iter()
|
||||
.filter(|(_, l)| l.owner == pid)
|
||||
.map(|(p, _)| p.clone())
|
||||
.collect();
|
||||
for path in paths {
|
||||
grant(state, &path);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn grant(state: &mut State, path: &str) {
|
||||
if let Some(mut lock) = state.locks.remove(path) {
|
||||
while let Some((owner, tx)) = lock.queue.pop_front() {
|
||||
if tx.send(Ok(json!({"held":true}))).is_ok() {
|
||||
lock.owner = owner;
|
||||
state.locks.insert(path.into(), lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user