-
-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds new statistics for tracking connections created and closed #202
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
use std::cmp::{max, min}; | ||
use std::fmt; | ||
use std::future::Future; | ||
use std::sync::atomic::Ordering; | ||
use std::sync::{Arc, Weak}; | ||
use std::time::{Duration, Instant}; | ||
|
||
|
@@ -86,6 +87,7 @@ where | |
|
||
pub(crate) async fn get(&self) -> Result<PooledConnection<'_, M>, RunError<M::Error>> { | ||
let mut kind = StatsKind::Direct; | ||
let mut wait_time_start = None; | ||
|
||
let future = async { | ||
loop { | ||
|
@@ -98,6 +100,7 @@ where | |
let mut conn = match conn { | ||
Some(conn) => PooledConnection::new(self, conn), | ||
None => { | ||
wait_time_start = Some(Instant::now()); | ||
kind = StatsKind::Waited; | ||
self.inner.notify.notified().await; | ||
continue; | ||
|
@@ -111,6 +114,10 @@ where | |
match self.inner.manager.is_valid(&mut conn).await { | ||
Ok(()) => return Ok(conn), | ||
Err(e) => { | ||
self.inner | ||
.statistics | ||
.connections_invalid_closed | ||
.fetch_add(1, Ordering::SeqCst); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can just make this another There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. jaja, good point. Ill try to do that! |
||
self.inner.forward_error(e); | ||
conn.state = ConnectionState::Invalid; | ||
continue; | ||
|
@@ -127,7 +134,16 @@ where | |
} | ||
}; | ||
|
||
self.inner.statistics.record(kind); | ||
self.inner.statistics.record_get(kind); | ||
|
||
if let Some(wait_time_start) = wait_time_start { | ||
let wait_time = Instant::now() - wait_time_start; | ||
self.inner | ||
.statistics | ||
.get_waited_time_micro | ||
.fetch_add(wait_time.as_micros() as u64, Ordering::SeqCst); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why micros vs millis or nanos? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess that micros would provide enough detail (nanos might be just noise) while we would keep the also the u64 large enough for storing many many many micros. In any case since we move this to a Duration we will be storing behind the scenes IIRC micros using u128. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oks now I remembered, everything I wanted to use an Atomic Type. I guess that we can try to use an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Finally I went for using micros with u64 for converting later to Duration. If you want to use nanos, i can do that. But got the feeling that nanosecond resolution for this specific use case would not provide a lot of value (indeed micro most likely will not neither) Ive just kept the type to If you want to to go for nanos and/or |
||
} | ||
|
||
result | ||
} | ||
|
||
|
@@ -147,7 +163,13 @@ where | |
let mut locked = self.inner.internals.lock(); | ||
match (state, self.inner.manager.has_broken(&mut conn.conn)) { | ||
(ConnectionState::Present, false) => locked.put(conn, None, self.inner.clone()), | ||
(_, _) => { | ||
(_, is_broken) => { | ||
if is_broken { | ||
self.inner | ||
.statistics | ||
.connections_broken_closed | ||
.fetch_add(1, Ordering::SeqCst); | ||
} | ||
let approvals = locked.dropped(1, &self.inner.statics); | ||
self.spawn_replenishing_approvals(approvals); | ||
self.inner.notify.notify_waiters(); | ||
|
@@ -190,6 +212,10 @@ where | |
.internals | ||
.lock() | ||
.put(conn, Some(approval), self.inner.clone()); | ||
self.inner | ||
.statistics | ||
.connections_created | ||
.fetch_add(1, Ordering::SeqCst); | ||
return Ok(()); | ||
} | ||
Err(e) => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,7 +49,15 @@ where | |
|
||
pub(crate) fn reap(&self) -> ApprovalIter { | ||
let mut locked = self.internals.lock(); | ||
locked.reap(&self.statics) | ||
let (iter, max_idle_timeout_closed, max_lifetime_closed) = locked.reap(&self.statics); | ||
drop(locked); | ||
self.statistics | ||
.connections_max_idle_timeout_closed | ||
.fetch_add(max_idle_timeout_closed, Ordering::SeqCst); | ||
self.statistics | ||
.connections_max_lifetime_closed | ||
.fetch_add(max_lifetime_closed, Ordering::SeqCst); | ||
iter | ||
} | ||
|
||
pub(crate) fn forward_error(&self, err: M::Error) { | ||
|
@@ -139,22 +147,34 @@ where | |
ApprovalIter { num: num as usize } | ||
} | ||
|
||
pub(crate) fn reap(&mut self, config: &Builder<M>) -> ApprovalIter { | ||
pub(crate) fn reap(&mut self, config: &Builder<M>) -> (ApprovalIter, u64, u64) { | ||
let mut max_lifetime_closed: u64 = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please avoid type annotations where possible. |
||
let mut max_idle_timeout_closed: u64 = 0; | ||
let now = Instant::now(); | ||
let before = self.conns.len(); | ||
|
||
self.conns.retain(|conn| { | ||
let mut keep = true; | ||
if let Some(timeout) = config.idle_timeout { | ||
keep &= now - conn.idle_start < timeout; | ||
if now - conn.idle_start >= timeout { | ||
max_idle_timeout_closed += 1; | ||
keep &= false; | ||
} | ||
} | ||
if let Some(lifetime) = config.max_lifetime { | ||
keep &= now - conn.conn.birth < lifetime; | ||
if now - conn.conn.birth >= lifetime { | ||
max_lifetime_closed += 1; | ||
keep &= false; | ||
} | ||
} | ||
keep | ||
}); | ||
|
||
self.dropped((before - self.conns.len()) as u32, config) | ||
( | ||
self.dropped((before - self.conns.len()) as u32, config), | ||
max_idle_timeout_closed, | ||
max_lifetime_closed, | ||
) | ||
} | ||
|
||
pub(crate) fn state(&self, statistics: Statistics) -> State { | ||
|
@@ -255,10 +275,16 @@ pub(crate) struct AtomicStatistics { | |
pub(crate) get_direct: AtomicU64, | ||
pub(crate) get_waited: AtomicU64, | ||
pub(crate) get_timed_out: AtomicU64, | ||
pub(crate) get_waited_time_micro: AtomicU64, | ||
pub(crate) connections_created: AtomicU64, | ||
pub(crate) connections_broken_closed: AtomicU64, | ||
pub(crate) connections_invalid_closed: AtomicU64, | ||
pub(crate) connections_max_lifetime_closed: AtomicU64, | ||
pub(crate) connections_max_idle_timeout_closed: AtomicU64, | ||
Comment on lines
+281
to
+285
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's skip the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For all of them? at least at first sight the Also it follows the same practice for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, let's keep |
||
} | ||
|
||
impl AtomicStatistics { | ||
pub(crate) fn record(&self, kind: StatsKind) { | ||
pub(crate) fn record_get(&self, kind: StatsKind) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that we can use it for incrementing other (non- |
||
match kind { | ||
StatsKind::Direct => self.get_direct.fetch_add(1, Ordering::SeqCst), | ||
StatsKind::Waited => self.get_waited.fetch_add(1, Ordering::SeqCst), | ||
|
@@ -273,6 +299,16 @@ impl From<&AtomicStatistics> for Statistics { | |
get_direct: item.get_direct.load(Ordering::SeqCst), | ||
get_waited: item.get_waited.load(Ordering::SeqCst), | ||
get_timed_out: item.get_timed_out.load(Ordering::SeqCst), | ||
get_waited_time_micro: item.get_waited_time_micro.load(Ordering::SeqCst), | ||
connections_created: item.connections_created.load(Ordering::SeqCst), | ||
connections_broken_closed: item.connections_broken_closed.load(Ordering::SeqCst), | ||
connections_invalid_closed: item.connections_invalid_closed.load(Ordering::SeqCst), | ||
connections_max_lifetime_closed: item | ||
.connections_max_lifetime_closed | ||
.load(Ordering::SeqCst), | ||
connections_max_idle_timeout_closed: item | ||
.connections_max_idle_timeout_closed | ||
.load(Ordering::SeqCst), | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this a
std::time::Duration
, and lose the_micro
suffix.