use std::sync::Arc;
use crate::topology::Topology;
#[derive(Debug, Default)]
pub(crate) struct Pool {
slots: Vec<Option<Arc<pgpool::Pool>>>,
topology: Topology,
}
impl Pool {
pub(crate) fn new() -> Self {
Self::default()
}
pub(crate) fn get(&self, idx: usize) -> Option<&Arc<pgpool::Pool>> {
self.slots.get(idx)?.as_ref()
}
pub(crate) fn active_pools(&self) -> impl Iterator<Item = &Arc<pgpool::Pool>> {
self.slots.iter().filter_map(|s| s.as_ref())
}
pub(crate) fn active_count(&self) -> usize {
self.slots.iter().filter(|s| s.is_some()).count()
}
pub(crate) fn pick(&self, strategy_idx: usize) -> Option<Arc<pgpool::Pool>> {
let count = self.active_count();
if count == 0 {
return None;
}
let target = strategy_idx % count;
self.slots
.iter()
.filter_map(|s| s.as_ref())
.nth(target)
.cloned()
}
pub(crate) fn resolve(
&self,
tier: &str,
bucket_id: u64,
on_master: bool,
) -> Option<Arc<pgpool::Pool>> {
let idx = self.topology.resolve(tier, bucket_id, on_master)?;
self.get(idx).cloned()
}
pub(crate) fn topology(&self) -> &Topology {
&self.topology
}
pub(crate) fn bucket_count(&self, tier: &str) -> Option<u64> {
self.topology.bucket_count(tier)
}
pub(crate) fn apply_topology(&mut self, incoming: Topology) {
self.topology.merge(incoming);
}
pub(crate) fn synchronize(
&mut self,
create_pool: impl Fn(&crate::instance::Instance) -> Arc<pgpool::Pool>,
) {
let mut alive: std::collections::HashSet<usize> = std::collections::HashSet::new();
for inst in self.topology.instances.values() {
let idx = inst.idx();
if inst.is_online() {
alive.insert(idx);
if idx >= self.slots.len() {
self.slots.resize(idx + 1, None);
self.slots[idx] = Some(create_pool(inst));
} else if self.slots[idx].is_none() {
self.slots[idx] = Some(create_pool(inst));
}
} else if idx < self.slots.len()
&& let Some(pool) = self.slots[idx].take()
{
pool.close();
}
}
for (idx, slot) in self.slots.iter_mut().enumerate() {
if !alive.contains(&idx)
&& let Some(pool) = slot.take()
{
pool.close();
}
}
}
pub(crate) fn close(&mut self) {
for slot in &mut self.slots {
if let Some(pool) = slot.take() {
pool.close();
}
}
self.topology = Topology::new();
}
}