use std::ops::Deref;
use super::inner::ConnectionPool;
use crate::netlink::{connection::Connection, protocol::ProtocolState};
#[non_exhaustive]
pub struct PooledConnection<'p, P: ProtocolState> {
pool: &'p ConnectionPool<P>,
conn: Option<Connection<P>>,
}
impl<'p, P: ProtocolState> PooledConnection<'p, P> {
pub(super) fn new(pool: &'p ConnectionPool<P>, conn: Connection<P>) -> Self {
Self {
pool,
conn: Some(conn),
}
}
}
impl<'p, P: ProtocolState + Send + Sync + 'static> PooledConnection<'p, P> {
pub fn invalidate(mut self) {
if let Some(conn) = self.conn.take() {
tracing::warn!(
ns = ?self.pool.namespace(),
"PooledConnection::invalidate: dropping pooled connection, replenishing in background"
);
drop(conn);
let inner = self.pool.inner.clone();
tokio::spawn(async move {
match inner.factory.build().await {
Ok(fresh) => match inner.available.try_send(fresh) {
Ok(()) => {
tracing::debug!(
ns = ?inner.namespace,
"PooledConnection::invalidate: replacement connection added to pool"
);
}
Err(_) => {
tracing::debug!(
"PooledConnection::invalidate: pool closed before replenish"
);
}
},
Err(e) => {
tracing::error!(
error = %e,
ns = ?inner.namespace,
"PooledConnection::invalidate: replenish failed; pool capacity reduced by one"
);
}
}
});
}
}
}
impl<P: ProtocolState> Deref for PooledConnection<'_, P> {
type Target = Connection<P>;
fn deref(&self) -> &Connection<P> {
debug_assert!(
self.conn.is_some(),
"PooledConnection::conn cleared without consuming \
the guard — would imply a use-after-move past the \
Rust borrow checker. Bug."
);
self.conn
.as_ref()
.expect("PooledConnection holds a Connection until drop (see invariant above)")
}
}
impl<P: ProtocolState> Drop for PooledConnection<'_, P> {
fn drop(&mut self) {
if let Some(conn) = self.conn.take() {
let _ = self.pool.inner.available.try_send(conn);
}
}
}