do_memory_storage_turso/pool/
config.rs1use do_memory_core::{Error, Result};
6use libsql::Connection;
7use parking_lot::RwLock;
8use std::sync::Arc;
9use std::sync::atomic::{AtomicU64, AtomicUsize};
10use std::time::Duration;
11use tokio::sync::OwnedSemaphorePermit;
12
13#[derive(Debug, Clone)]
15pub struct PoolConfig {
16 pub min_connections: usize,
18 pub max_connections: usize,
20 pub connection_timeout: Duration,
22 pub enable_health_check: bool,
24 pub health_check_timeout: Duration,
26 pub acquire_timeout_ms: u64,
29 pub idle_timeout_ms: u64,
32}
33
34impl Default for PoolConfig {
35 fn default() -> Self {
36 Self {
37 min_connections: 1,
38 max_connections: 10,
39 connection_timeout: Duration::from_secs(5),
40 enable_health_check: true,
41 health_check_timeout: Duration::from_secs(2),
42 acquire_timeout_ms: 5000,
43 idle_timeout_ms: 0,
44 }
45 }
46}
47
48#[derive(Debug)]
53pub struct PoolMetrics {
54 pub active_connections: AtomicUsize,
56 pub total_acquired: AtomicU64,
58 pub total_wait_ms: AtomicU64,
60 pub reconnect_count: AtomicU64,
62}
63
64impl Default for PoolMetrics {
65 fn default() -> Self {
66 Self {
67 active_connections: AtomicUsize::new(0),
68 total_acquired: AtomicU64::new(0),
69 total_wait_ms: AtomicU64::new(0),
70 reconnect_count: AtomicU64::new(0),
71 }
72 }
73}
74
75impl PoolMetrics {
76 pub fn record_acquire(&self, wait_ms: u64) {
78 self.active_connections
79 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
80 self.total_acquired
81 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
82 self.total_wait_ms
83 .fetch_add(wait_ms, std::sync::atomic::Ordering::Relaxed);
84 }
85
86 pub fn record_release(&self) {
88 self.active_connections
89 .fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
90 }
91
92 pub fn record_reconnect(&self) {
94 self.reconnect_count
95 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
96 }
97
98 pub fn snapshot(&self) -> PoolMetricsSnapshot {
100 PoolMetricsSnapshot {
101 active_connections: self
102 .active_connections
103 .load(std::sync::atomic::Ordering::Relaxed),
104 total_acquired: self
105 .total_acquired
106 .load(std::sync::atomic::Ordering::Relaxed),
107 total_wait_ms: self
108 .total_wait_ms
109 .load(std::sync::atomic::Ordering::Relaxed),
110 reconnect_count: self
111 .reconnect_count
112 .load(std::sync::atomic::Ordering::Relaxed),
113 }
114 }
115}
116
117#[derive(Debug, Clone, Default)]
119pub struct PoolMetricsSnapshot {
120 pub active_connections: usize,
122 pub total_acquired: u64,
124 pub total_wait_ms: u64,
126 pub reconnect_count: u64,
128}
129
130#[derive(Debug, Clone, Default)]
132pub struct PoolStatistics {
133 pub total_created: usize,
135 pub total_health_checks_passed: usize,
137 pub total_health_checks_failed: usize,
139 pub active_connections: usize,
141 pub total_wait_time_ms: u64,
143 pub total_checkouts: usize,
145 pub avg_wait_time_ms: u64,
147}
148
149impl PoolStatistics {
150 pub fn update_averages(&mut self) {
151 if self.total_checkouts > 0 {
152 self.avg_wait_time_ms = self.total_wait_time_ms / self.total_checkouts as u64;
153 }
154 }
155}
156
157#[derive(Debug)]
159pub struct PooledConnection {
160 pub(super) connection: Option<Connection>,
161 pub(super) _permit: OwnedSemaphorePermit,
162 pub(super) stats: Arc<RwLock<PoolStatistics>>,
163 pub(super) metrics: Option<Arc<PoolMetrics>>,
164}
165
166impl PooledConnection {
167 pub fn connection(&self) -> Option<&Connection> {
169 self.connection.as_ref()
170 }
171
172 pub fn into_inner(mut self) -> Result<Connection> {
174 self.connection
175 .take()
176 .ok_or_else(|| Error::Storage("Connection already taken".to_string()))
177 }
178}
179
180impl Drop for PooledConnection {
181 fn drop(&mut self) {
182 let mut stats = self.stats.write();
185 if stats.active_connections > 0 {
186 stats.active_connections -= 1;
187 }
188 if let Some(ref metrics) = self.metrics {
190 metrics.record_release();
191 }
192 }
193}