Skip to main content

pg_proto/
cleanliness.rs

1//! Extensible evidence for application-owned connection reuse policy.
2
3use bytes::Bytes;
4
5use crate::codec::TransactionStatus;
6
7/// Observable facts which may affect whether an upstream connection is reusable.
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub enum CleanlinessEvent {
10    /// The backend reported its current transaction state.
11    TransactionStatus(TransactionStatus),
12    /// A reportable run-time parameter changed.
13    ParameterChanged {
14        /// Parameter name.
15        name: Bytes,
16        /// New parameter value.
17        value: Bytes,
18    },
19    /// The session began listening on a notification channel.
20    Listen {
21        /// Channel name.
22        channel: Bytes,
23    },
24    /// The session stopped listening on one or all channels.
25    Unlisten {
26        /// Channel name, or `None` for every channel.
27        channel: Option<Bytes>,
28    },
29    /// The session acquired an advisory lock.
30    AdvisoryLockAcquired,
31    /// The session released its advisory locks.
32    AdvisoryLocksReleased,
33    /// A portal became live.
34    PortalOpened {
35        /// Portal name.
36        name: Bytes,
37    },
38    /// A portal was closed.
39    PortalClosed {
40        /// Portal name.
41        name: Bytes,
42    },
43    /// A prepared statement became live.
44    StatementPrepared {
45        /// Prepared-statement name.
46        name: Bytes,
47    },
48    /// A prepared statement was closed.
49    StatementClosed {
50        /// Prepared-statement name.
51        name: Bytes,
52    },
53    /// A reset operation restored the application's clean baseline.
54    ResetComplete,
55    /// Evidence from application-specific SQL inspection.
56    Application {
57        /// Application-defined category.
58        kind: Bytes,
59        /// Application-defined supporting detail.
60        detail: Bytes,
61    },
62}
63
64/// Downstream policy which consumes cleanliness evidence.
65///
66/// The protocol library reports facts; the application decides whether they
67/// prohibit pooling and what reset operation, if any, restores reusability.
68pub trait CleanlinessPolicy {
69    /// Incorporates one observed fact into the policy's state.
70    fn observe(&mut self, event: &CleanlinessEvent);
71
72    /// Reports whether the accumulated evidence permits connection reuse.
73    fn reusable(&self) -> bool;
74}
75
76/// A no-op policy for applications which do not pool upstream connections.
77#[derive(Clone, Copy, Debug, Default)]
78pub struct IgnoreCleanliness;
79
80impl CleanlinessPolicy for IgnoreCleanliness {
81    fn observe(&mut self, _event: &CleanlinessEvent) {}
82
83    fn reusable(&self) -> bool {
84        true
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[derive(Default)]
93    struct RejectLocks(bool);
94
95    impl CleanlinessPolicy for RejectLocks {
96        fn observe(&mut self, event: &CleanlinessEvent) {
97            match event {
98                CleanlinessEvent::AdvisoryLockAcquired => self.0 = true,
99                CleanlinessEvent::AdvisoryLocksReleased | CleanlinessEvent::ResetComplete => {
100                    self.0 = false;
101                }
102                _ => {}
103            }
104        }
105
106        fn reusable(&self) -> bool {
107            !self.0
108        }
109    }
110
111    #[test]
112    fn application_policy_interprets_protocol_evidence() {
113        let mut policy = RejectLocks::default();
114        policy.observe(&CleanlinessEvent::AdvisoryLockAcquired);
115        assert!(!policy.reusable());
116        policy.observe(&CleanlinessEvent::AdvisoryLocksReleased);
117        assert!(policy.reusable());
118    }
119}