Skip to main content

pgwire_replication/client/
feedback.rs

1//! Observing standby status feedback: how long an acknowledged position
2//! waited before the server was told about it.
3
4use std::fmt;
5use std::sync::Arc;
6use std::time::Duration;
7
8/// A standby status update that told the server about a newer applied
9/// position, reported to a [`FeedbackObserver`] after the write succeeded.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[non_exhaustive]
12pub struct FeedbackSent {
13    /// From the oldest raise of the applied position that this update is the
14    /// first to report, until the update was written. Raises coalesced into
15    /// one update keep the oldest, so this is how long an acknowledged
16    /// position was withheld from the server, including across a failed
17    /// write or a new session that carried it over
18    /// ([`ReplicationClient::carry_feedback_pending`](crate::ReplicationClient::carry_feedback_pending)).
19    pub pending_for: Duration,
20}
21
22/// Called after each successful standby status update that advanced the
23/// position reported to the server; never for one that repeated it. Runs on
24/// the replication worker, so it must be cheap and must not block.
25#[derive(Clone)]
26pub struct FeedbackObserver(Arc<dyn Fn(FeedbackSent) + Send + Sync>);
27
28impl FeedbackObserver {
29    pub fn new(observer: impl Fn(FeedbackSent) + Send + Sync + 'static) -> Self {
30        Self(Arc::new(observer))
31    }
32
33    pub(crate) fn observe(&self, sent: FeedbackSent) {
34        (self.0)(sent)
35    }
36}
37
38impl fmt::Debug for FeedbackObserver {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.write_str("FeedbackObserver(..)")
41    }
42}
43
44/// Two observers are equal when they are the same callback.
45impl PartialEq for FeedbackObserver {
46    fn eq(&self, other: &Self) -> bool {
47        Arc::ptr_eq(&self.0, &other.0)
48    }
49}
50
51impl Eq for FeedbackObserver {}
52
53// The callback is only ever called by the replication worker
54// (`observe` is crate-private), so a reference held across a
55// `catch_unwind` boundary cannot observe state that a panic left broken.
56// This keeps `ReplicationConfig` unwind safe, as it was before observers.
57impl std::panic::UnwindSafe for FeedbackObserver {}
58impl std::panic::RefUnwindSafe for FeedbackObserver {}