use super::TransactionOwner;
use std::sync::{Mutex, PoisonError};
use tokio::sync::Notify;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum TransactionProgress {
AwaitingResponse,
SegmentedResponse { generation: u64 },
}
#[derive(Debug)]
struct ProgressState {
version: u64,
value: TransactionProgress,
}
#[derive(Debug)]
pub(super) struct TransactionShared {
state: Mutex<ProgressState>,
notify: Notify,
}
impl TransactionShared {
pub(super) fn new() -> Self {
Self {
state: Mutex::new(ProgressState {
version: 0,
value: TransactionProgress::AwaitingResponse,
}),
notify: Notify::new(),
}
}
fn snapshot(&self) -> (u64, TransactionProgress) {
let state = self.state.lock().unwrap_or_else(PoisonError::into_inner);
(state.version, state.value)
}
fn version(&self) -> u64 {
self.state
.lock()
.unwrap_or_else(PoisonError::into_inner)
.version
}
}
impl TransactionOwner {
pub(super) fn publish_progress(&self, value: TransactionProgress) {
{
let mut state = self.0.state.lock().unwrap_or_else(PoisonError::into_inner);
state.version = state.version.wrapping_add(1);
state.value = value;
}
self.0.notify.notify_one();
}
}
#[derive(Debug)]
pub(crate) struct ProgressReceiver {
owner: TransactionOwner,
seen: u64,
}
impl ProgressReceiver {
pub(super) fn new(owner: TransactionOwner) -> Self {
Self { owner, seen: 0 }
}
pub(crate) fn borrow_and_update(&mut self) -> TransactionProgress {
let (version, value) = self.owner.0.snapshot();
self.seen = version;
value
}
#[cfg(test)]
pub(crate) fn current(&self) -> TransactionProgress {
self.owner.0.snapshot().1
}
pub(crate) async fn changed(&mut self) {
loop {
if self.owner.0.version() != self.seen {
return;
}
self.owner.0.notify.notified().await;
}
}
}
#[cfg(test)]
#[path = "progress_tests.rs"]
mod tests;