use std::collections::VecDeque;
use std::sync::mpsc;
use crate::config::PoolConfig;
use crate::connection::ConnImpl;
use crate::connection::ConnImplStatus;
use crate::error::Error;
use crate::pool::PoolManagerRequest;
pub(crate) struct PoolContents {
config: PoolConfig,
free_connections: VecDeque<ConnImpl>,
connections_requiring_ping: VecDeque<ConnImpl>,
connections_requiring_drop: Vec<ConnImpl>,
last_create_error: Option<Error>,
num_busy: usize,
num_being_created: usize,
num_being_pinged: usize,
pending_requests: VecDeque<mpsc::Sender<Result<ConnImpl, Error>>>,
pool_manager_request_channel: mpsc::Sender<PoolManagerRequest>,
}
pub(crate) enum PoolAcquireResponse {
Connection(Result<ConnImpl, Error>),
Wait(mpsc::Receiver<Result<ConnImpl, Error>>),
}
pub(crate) type PoolContentsRef =
std::sync::Arc<std::sync::Mutex<PoolContents>>;
impl PoolContents {
fn can_pool_grow(&mut self) -> bool {
let num_in_pool = self.open_count();
let min_connections = self.config.min_connections();
self.num_being_created = if num_in_pool < min_connections {
min_connections - num_in_pool
} else {
let max_connections = self.config.max_connections();
let increment = self.config.connection_increment();
(max_connections - num_in_pool).min(increment)
};
self.num_being_created > 0
}
fn get_connection(&mut self) -> Option<ConnImpl> {
while let Some(conn_impl) = self.free_connections.pop_front() {
match conn_impl.get_status(self.config.ping_interval()) {
ConnImplStatus::RequiresClose => {
self.connections_requiring_drop.push(conn_impl);
}
ConnImplStatus::RequiresPing => {
self.connections_requiring_ping.push_back(conn_impl);
}
ConnImplStatus::Healthy => {
return Some(conn_impl);
}
}
}
None
}
fn notify_manager(&mut self) {
if let Some(conn_impl) = self.connections_requiring_ping.pop_front() {
self.num_being_pinged += 1;
self.send_manager_request(PoolManagerRequest::PingConnection(
conn_impl,
));
} else if self.num_being_created == 0 && self.can_pool_grow() {
self.send_manager_request(PoolManagerRequest::GrowPool);
} else if let Some(conn_impl) = self.connections_requiring_drop.pop() {
self.send_manager_request(PoolManagerRequest::DropConnection(
conn_impl,
));
}
}
fn satisfy_request(&mut self, conn_impl_result: Result<ConnImpl, Error>) {
if let Some(sender) = self.pending_requests.pop_front() {
match sender.send(conn_impl_result) {
Ok(_) => {
self.num_busy += 1;
}
Err(e) => {
self.satisfy_request(e.0);
}
}
} else {
match conn_impl_result {
Ok(conn_impl) => {
self.free_connections.push_back(conn_impl);
}
Err(err) => {
self.last_create_error = Some(err);
}
}
}
}
fn satisfy_requests(&mut self) {
while !self.free_connections.is_empty()
&& !self.pending_requests.is_empty()
{
if let Some(conn_impl) = self.get_connection() {
self.satisfy_request(Ok(conn_impl));
}
}
}
fn send_manager_request(&self, request: PoolManagerRequest) {
self.pool_manager_request_channel.send(request).unwrap();
}
pub(super) fn acquire(&mut self) -> PoolAcquireResponse {
if let Some(conn_impl) = self.get_connection() {
self.num_busy += 1;
return PoolAcquireResponse::Connection(Ok(conn_impl));
}
let (tx, rx) = mpsc::channel();
self.pending_requests.push_back(tx);
self.notify_manager();
PoolAcquireResponse::Wait(rx)
}
pub(super) fn add_new_connection(
&mut self,
conn_impl_result: Result<ConnImpl, Error>,
) {
self.num_being_created -= 1;
self.satisfy_request(conn_impl_result);
self.notify_manager();
}
pub(super) fn add_pinged_connection(
&mut self,
conn_impl_opt: Option<ConnImpl>,
) {
self.num_being_pinged -= 1;
if let Some(conn_impl) = conn_impl_opt {
self.satisfy_request(Ok(conn_impl));
}
self.notify_manager();
}
pub(super) fn busy_count(&self) -> usize {
self.num_busy
}
pub(super) fn close(&mut self) -> Result<(), Error> {
if self.num_busy > 0 {
return Err(Error::pool_has_busy_connections());
}
self.pool_manager_request_channel
.send(PoolManagerRequest::ClosePool)
.unwrap();
self.free_connections.clear();
self.connections_requiring_ping.clear();
self.connections_requiring_drop.clear();
Ok(())
}
pub(super) fn new(
config: PoolConfig,
request_channel: mpsc::Sender<PoolManagerRequest>,
) -> Self {
let min_connections = config.min_connections();
let max_connections = config.max_connections();
if min_connections > 0 {
request_channel.send(PoolManagerRequest::GrowPool).unwrap();
}
Self {
config,
free_connections: VecDeque::with_capacity(max_connections),
connections_requiring_ping: VecDeque::new(),
connections_requiring_drop: Vec::new(),
last_create_error: None,
num_busy: 0,
num_being_created: min_connections,
num_being_pinged: 0,
pending_requests: VecDeque::new(),
pool_manager_request_channel: request_channel,
}
}
pub(super) fn open_count(&self) -> usize {
self.free_connections.len() + self.num_being_pinged + self.num_busy
}
pub(crate) fn return_connection(&mut self, conn_impl: ConnImpl) {
self.num_busy -= 1;
self.free_connections.push_front(conn_impl);
self.satisfy_requests();
}
}