odbc_iter/
stats.rs

1#[cfg(feature = "statistics")]
2mod inner {
3    use std::sync::atomic::{AtomicU64, Ordering};
4    use std::fmt;
5
6    // Note: possible race where EXECUTING and FETCHING at the same time... but it is OK for the use case
7    static OPEN_CONNECTIONS: AtomicU64 = AtomicU64::new(0);
8    static QUERIES_PREPARING: AtomicU64 = AtomicU64::new(0);
9    static QUERIES_EXECUTING: AtomicU64 = AtomicU64::new(0);
10    static QUERIES_FETCHING: AtomicU64 = AtomicU64::new(0);
11    static QUERIES_DONE: AtomicU64 = AtomicU64::new(0);
12    static QUERIES_FAILED: AtomicU64 = AtomicU64::new(0);
13
14    pub(super) fn open_connections_inc () {
15        OPEN_CONNECTIONS.fetch_add(1, Ordering::Relaxed);
16    }
17
18    pub(super) fn open_connections_dec() {
19        assert!(OPEN_CONNECTIONS.fetch_sub(1, Ordering::Relaxed) > 0);
20    }
21
22    pub(super) fn queries_preparing_inc() {
23        QUERIES_PREPARING.fetch_add(1, Ordering::Relaxed);
24    }
25
26    pub(super) fn queries_preparing_dec() {
27        assert!(QUERIES_PREPARING.fetch_sub(1, Ordering::Relaxed) > 0);
28    }
29
30    pub(super) fn queries_executing_inc() {
31        QUERIES_EXECUTING.fetch_add(1, Ordering::Relaxed);
32    }
33
34    pub(super) fn queries_executing_dec() {
35        assert!(QUERIES_EXECUTING.fetch_sub(1, Ordering::Relaxed) > 0);
36    }
37
38    pub(super) fn queries_fetching_inc() {
39        QUERIES_FETCHING.fetch_add(1, Ordering::Relaxed);
40    }
41
42    pub(super) fn queries_fetching_dec() {
43        assert!(QUERIES_FETCHING.fetch_sub(1, Ordering::Relaxed) > 0);
44    }
45
46    pub(super) fn queries_done_inc() {
47        QUERIES_DONE.fetch_add(1, Ordering::Relaxed);
48    }
49
50    pub(super) fn queries_failed_inc() {
51        QUERIES_FAILED.fetch_add(1, Ordering::Relaxed);
52    }
53
54    #[derive(Debug)]
55    pub struct Statistics {
56        pub open_connections: u64,
57        pub queries_preparing: u64,
58        pub queries_executing: u64,
59        pub queries_fetching: u64,
60        pub queries_done: u64,
61        pub queries_failed: u64,
62    }
63
64    impl fmt::Display for Statistics {
65        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66            write!(f, "ODBC statistics: connections: open: {open_connections}, queries: preparing: {queries_preparing}, executing: {queries_executing}, fetching: {queries_fetching}, done: {queries_done}, failed: {queries_failed}",
67                open_connections = self.open_connections,
68                queries_preparing = self.queries_preparing,
69                queries_executing = self.queries_executing,
70                queries_fetching = self.queries_fetching,
71                queries_done = self.queries_done,
72                queries_failed = self.queries_failed,
73            )
74        }
75    }
76
77    pub fn statistics() -> Statistics {
78        Statistics {
79            open_connections: OPEN_CONNECTIONS.load(Ordering::Relaxed),
80            queries_preparing: QUERIES_PREPARING.load(Ordering::Relaxed),
81            queries_executing: QUERIES_EXECUTING.load(Ordering::Relaxed),
82            queries_fetching: QUERIES_FETCHING.load(Ordering::Relaxed),
83            queries_done: QUERIES_DONE.load(Ordering::Relaxed),
84            queries_failed: QUERIES_FAILED.load(Ordering::Relaxed),
85        }
86    }
87}
88
89#[cfg(feature = "statistics")]
90pub use inner::statistics;
91
92pub(crate) struct ConnectionOpenGuard;
93
94impl ConnectionOpenGuard {
95    pub(crate) fn new() -> ConnectionOpenGuard {
96        #[cfg(feature = "statistics")]
97        inner::open_connections_inc();
98        ConnectionOpenGuard
99    }
100}
101
102impl Drop for ConnectionOpenGuard {
103    fn drop(&mut self) {
104        #[cfg(feature = "statistics")]
105        inner::open_connections_dec();
106    }
107}
108
109pub(crate) struct QueryPreparingGuard;
110
111impl QueryPreparingGuard {
112    pub(crate) fn new() -> QueryPreparingGuard {
113        #[cfg(feature = "statistics")]
114        inner::queries_preparing_inc();
115        QueryPreparingGuard
116    }
117}
118
119impl Drop for QueryPreparingGuard {
120    fn drop(&mut self) {
121        #[cfg(feature = "statistics")]
122        inner::queries_preparing_dec();
123    }
124}
125
126
127struct QueryExecutingGuard;
128
129impl QueryExecutingGuard {
130    fn new() -> QueryExecutingGuard {
131        #[cfg(feature = "statistics")]
132        inner::queries_executing_inc();
133        QueryExecutingGuard
134    }
135
136    fn failed(self) {
137        #[cfg(feature = "statistics")]
138        inner::queries_failed_inc();
139    }
140
141    fn fetching(self) -> QueryFetchingGuard {
142        QueryFetchingGuard::new()
143    }
144}
145
146#[cfg(feature = "statistics")]
147impl Drop for QueryExecutingGuard {
148    fn drop(&mut self) {
149        #[cfg(feature = "statistics")]
150        inner::queries_executing_dec();
151    }
152}
153
154pub(crate) struct QueryFetchingGuard;
155
156impl QueryFetchingGuard {
157    fn new() -> QueryFetchingGuard {
158        #[cfg(feature = "statistics")]
159        inner::queries_fetching_inc();
160        QueryFetchingGuard
161    }
162}
163
164#[cfg(feature = "statistics")]
165impl Drop for QueryFetchingGuard {
166    fn drop(&mut self) {
167        inner::queries_fetching_dec();
168        inner::queries_done_inc();
169    }
170}
171
172pub(crate) fn query_preparing<O, F>(f: F) -> O where F: FnOnce() -> O {
173    let bind = QueryPreparingGuard::new();
174    let ret = f();
175    drop(bind);
176    ret
177}
178
179pub(crate) fn query_execution<O, E, F>(f: F) -> Result<(O, QueryFetchingGuard), E> where F: FnOnce() -> Result<O, E> {
180    let exec = QueryExecutingGuard::new();
181    match f() {
182        Ok(o) => {
183
184            Ok((o, exec.fetching()))
185        }
186        Err(e) => {
187            exec.failed();
188            Err(e)
189        }
190    }
191}