use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, OnceLock, Weak};
use graphile_worker_runtime as runtime;
#[derive(Default)]
pub(super) struct ClaimCoordinator {
fetches: runtime::RwLock<()>,
returns: AtomicUsize,
}
impl ClaimCoordinator {
pub(super) fn for_worker(worker_id: &str) -> Arc<Self> {
static WORKERS: OnceLock<Mutex<HashMap<String, Weak<ClaimCoordinator>>>> = OnceLock::new();
let mut workers = WORKERS.get_or_init(Default::default).lock().unwrap();
workers.retain(|_, worker| worker.strong_count() != 0);
if let Some(worker) = workers.get(worker_id).and_then(Weak::upgrade) {
return worker;
}
let worker = Arc::new(Self::default());
workers.insert(worker_id.to_owned(), Arc::downgrade(&worker));
worker
}
pub(super) fn try_fetch(&self) -> Option<runtime::RwLockReadGuard<'_, ()>> {
let guard = self.fetches.try_read()?;
(self.returns.load(Ordering::Acquire) == 0).then_some(guard)
}
pub(super) async fn begin_return(self: &Arc<Self>) -> ReturnPermit {
let _fetches = self.fetches.write().await;
self.returns.fetch_add(1, Ordering::AcqRel);
ReturnPermit(self.clone())
}
}
pub(super) struct ReturnPermit(Arc<ClaimCoordinator>);
impl Drop for ReturnPermit {
fn drop(&mut self) {
self.0.returns.fetch_sub(1, Ordering::AcqRel);
}
}
#[derive(Default)]
pub(super) struct PendingReturns {
pub(super) jobs: Vec<graphile_worker_job::Job>,
pub(super) permit: Option<ReturnPermit>,
}