1use async_trait::async_trait;
6use crossbeam_queue::ArrayQueue;
7use std::future::Future;
8use std::ops::{Deref, DerefMut};
9use std::pin::Pin;
10use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
11use std::sync::Arc;
12use std::time::{Duration, Instant};
13use tokio::sync::Notify;
14
15use crate::error::PoolError;
16
17pub type QueryRows = Vec<std::collections::HashMap<String, crate::value::Value>>;
19
20pub type QueryStreamItem =
22 Result<std::collections::HashMap<String, crate::value::Value>, crate::DbError>;
23
24pub trait Connection: Send + Sync {
31 fn execute<'a>(
32 &'a mut self,
33 sql: &'a str,
34 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>>;
35 fn query<'a>(
36 &'a mut self,
37 sql: &'a str,
38 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>>;
39 fn begin_transaction<'a>(
40 &'a mut self,
41 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
42 fn commit<'a>(
43 &'a mut self,
44 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
45 fn rollback<'a>(
46 &'a mut self,
47 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
48 fn is_connected(&self) -> bool;
49 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>>;
50 fn close<'a>(
51 &'a mut self,
52 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
53
54 fn execute_with_params<'a>(
60 &'a mut self,
61 sql: &'a str,
62 params: &'a [crate::value::Value],
63 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
64 let _ = (sql, params);
65 Box::pin(async move {
66 Err(crate::DbError::Internal(
67 "execute_with_params not implemented for this adapter".to_string(),
68 ))
69 })
70 }
71
72 fn query_with_params<'a>(
78 &'a mut self,
79 sql: &'a str,
80 params: &'a [crate::value::Value],
81 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
82 let _ = (sql, params);
83 Box::pin(async move {
84 Err(crate::DbError::Internal(
85 "query_with_params not implemented for this adapter".to_string(),
86 ))
87 })
88 }
89
90 fn query_values<'a>(
95 &'a mut self,
96 sql: &'a str,
97 ) -> Pin<Box<dyn Future<Output = Result<crate::value::QueryValues, crate::DbError>> + Send + 'a>>
98 {
99 let _ = sql;
100 Box::pin(async move {
101 Err(crate::DbError::Internal(
102 "query_values not implemented for this adapter".to_string(),
103 ))
104 })
105 }
106
107 fn query_values_with_params<'a>(
111 &'a mut self,
112 sql: &'a str,
113 params: &'a [crate::value::Value],
114 ) -> Pin<Box<dyn Future<Output = Result<crate::value::QueryValues, crate::DbError>> + Send + 'a>>
115 {
116 let _ = (sql, params);
117 Box::pin(async move {
118 Err(crate::DbError::Internal(
119 "query_values_with_params not implemented for this adapter".to_string(),
120 ))
121 })
122 }
123
124 fn query_stream<'a>(
129 &'a mut self,
130 sql: &'a str,
131 ) -> Pin<Box<dyn futures::Stream<Item = QueryStreamItem> + Send + 'a>> {
132 let _ = sql;
133 Box::pin(futures::stream::empty())
134 }
135
136 fn execute_batch<'a>(
141 &'a mut self,
142 sqls: &'a [String],
143 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
144 Box::pin(async move {
145 let mut total = 0u64;
146 for sql in sqls {
147 total += self.execute(sql).await?;
148 }
149 Ok(total)
150 })
151 }
152
153 fn execute_batch_params<'a>(
158 &'a mut self,
159 sql: &'a str,
160 params_batch: &'a [Vec<crate::value::Value>],
161 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
162 Box::pin(async move {
163 let mut total = 0u64;
164 for params in params_batch {
165 total += self.execute_with_params(sql, params).await?;
166 }
167 Ok(total)
168 })
169 }
170}
171
172pub struct PooledConnection {
180 conn: Box<dyn Connection>,
181 created_at: Instant,
182 last_used_at: Instant,
183 pool: Option<Pool>,
184}
185
186impl PooledConnection {
187 fn new(conn: Box<dyn Connection>, pool: Pool) -> Self {
188 let now = Instant::now();
189 Self {
190 conn,
191 created_at: now,
192 last_used_at: now,
193 pool: Some(pool),
194 }
195 }
196
197 fn is_expired(&self, max_lifetime: Duration) -> bool {
198 self.created_at.elapsed() >= max_lifetime
199 }
200
201 fn is_idle_too_long(&self, idle_timeout: Duration) -> bool {
202 self.last_used_at.elapsed() >= idle_timeout
203 }
204
205 pub fn created_at(&self) -> Instant {
207 self.created_at
208 }
209
210 pub fn into_inner(mut self) -> Box<dyn Connection> {
215 self.pool = None; std::mem::replace(&mut self.conn, Box::new(ClosedConnection))
219 }
220}
221
222impl Drop for PooledConnection {
234 fn drop(&mut self) {
235 if let Some(pool) = self.pool.take() {
236 let conn = std::mem::replace(&mut self.conn, Box::new(ClosedConnection));
238 let pooled = PooledConnection {
239 conn,
240 created_at: self.created_at,
241 last_used_at: self.last_used_at,
242 pool: None,
243 };
244 if let Ok(handle) = tokio::runtime::Handle::try_current() {
246 handle.spawn(async move {
247 pool.release(pooled).await;
248 });
249 } else {
250 drop(pooled);
254 pool.total_count.fetch_sub(1, Ordering::SeqCst);
255 }
256 }
257 }
258}
259
260struct ClosedConnection;
264
265impl Connection for ClosedConnection {
266 fn execute<'a>(
267 &'a mut self,
268 _sql: &'a str,
269 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
270 Box::pin(async {
271 Err(crate::DbError::ConnectionError(
272 "connection already returned to pool".to_string(),
273 ))
274 })
275 }
276
277 fn query<'a>(
278 &'a mut self,
279 _sql: &'a str,
280 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
281 Box::pin(async {
282 Err(crate::DbError::ConnectionError(
283 "connection already returned to pool".to_string(),
284 ))
285 })
286 }
287
288 fn begin_transaction<'a>(
289 &'a mut self,
290 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
291 Box::pin(async {
292 Err(crate::DbError::ConnectionError(
293 "connection already returned to pool".to_string(),
294 ))
295 })
296 }
297
298 fn commit<'a>(
299 &'a mut self,
300 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
301 Box::pin(async { Ok(()) })
302 }
303
304 fn rollback<'a>(
305 &'a mut self,
306 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
307 Box::pin(async { Ok(()) })
308 }
309
310 fn is_connected(&self) -> bool {
311 false
312 }
313
314 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
315 Box::pin(async { false })
316 }
317
318 fn close<'a>(
319 &'a mut self,
320 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
321 Box::pin(async { Ok(()) })
322 }
323}
324
325impl Deref for PooledConnection {
326 type Target = dyn Connection;
327
328 fn deref(&self) -> &Self::Target {
329 self.conn.as_ref()
330 }
331}
332
333impl DerefMut for PooledConnection {
334 fn deref_mut(&mut self) -> &mut Self::Target {
335 self.conn.as_mut()
336 }
337}
338
339#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
341pub enum TlsVersion {
342 #[default]
343 Tls12,
344 Tls13,
345}
346
347#[derive(Debug, Clone, Default)]
349pub struct TlsConfig {
350 pub enabled: bool,
352 pub ca_cert_path: Option<String>,
354 pub client_cert_path: Option<String>,
356 pub client_key_path: Option<String>,
358 pub min_version: TlsVersion,
360}
361
362#[derive(Debug, Clone)]
364pub enum PoolEvent {
365 ConnectionCreated,
367 ConnectionClosed,
369 ConnectionAcquired,
371 ConnectionReleased,
373 AcquireTimeout,
375}
376
377pub type PoolEventCallback = Arc<dyn Fn(PoolEvent) + Send + Sync>;
379
380pub struct PoolConfig {
381 pub max_size: u32,
382 pub min_idle: u32,
383 pub acquire_timeout: Duration,
384 pub idle_timeout: Duration,
385 pub max_lifetime: Duration,
386 pub connection_timeout: Duration,
387 pub tls: Option<TlsConfig>,
389 pub query_timeout: Option<Duration>,
391 pub max_rows: Option<usize>,
393 pub memory_limit: Option<usize>,
395 pub on_event: Option<PoolEventCallback>,
397}
398
399impl Default for PoolConfig {
400 fn default() -> Self {
401 Self {
402 max_size: 100,
403 min_idle: 0,
404 acquire_timeout: Duration::from_secs(30),
405 idle_timeout: Duration::from_secs(600),
406 max_lifetime: Duration::from_secs(1800),
407 connection_timeout: Duration::from_secs(10),
408 tls: None,
409 query_timeout: Some(Duration::from_secs(30)),
410 max_rows: None,
411 memory_limit: None,
412 on_event: None,
413 }
414 }
415}
416
417impl Clone for PoolConfig {
418 fn clone(&self) -> Self {
419 Self {
420 max_size: self.max_size,
421 min_idle: self.min_idle,
422 acquire_timeout: self.acquire_timeout,
423 idle_timeout: self.idle_timeout,
424 max_lifetime: self.max_lifetime,
425 connection_timeout: self.connection_timeout,
426 tls: self.tls.clone(),
427 query_timeout: self.query_timeout,
428 max_rows: self.max_rows,
429 memory_limit: self.memory_limit,
430 on_event: self.on_event.clone(),
431 }
432 }
433}
434
435impl PoolConfig {
436 pub fn validate(&self) -> Result<(), PoolError> {
438 if self.max_size == 0 {
439 return Err(PoolError::InvalidConfig("max_size cannot be 0".to_string()));
440 }
441 if self.min_idle > self.max_size {
442 return Err(PoolError::InvalidConfig(
443 "min_idle cannot exceed max_size".to_string(),
444 ));
445 }
446 Ok(())
447 }
448}
449
450pub struct PoolStatus {
451 pub idle: u32,
452 pub active: u32,
453 pub max: u32,
454 pub min: u32,
455 pub waiters: u32,
457}
458
459impl std::fmt::Debug for PoolStatus {
460 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
461 f.debug_struct("PoolStatus")
462 .field("idle", &self.idle)
463 .field("active", &self.active)
464 .field("max", &self.max)
465 .field("min", &self.min)
466 .field("waiters", &self.waiters)
467 .finish()
468 }
469}
470
471pub struct PoolConfigBuilder {
472 config: PoolConfig,
473}
474
475impl PoolConfigBuilder {
476 pub fn new() -> Self {
477 Self {
478 config: PoolConfig::default(),
479 }
480 }
481
482 pub fn max_size(mut self, size: u32) -> Self {
483 self.config.max_size = size;
484 self
485 }
486
487 pub fn min_idle(mut self, count: u32) -> Self {
488 self.config.min_idle = count;
489 self
490 }
491
492 pub fn acquire_timeout(mut self, timeout_secs: u64) -> Self {
493 self.config.acquire_timeout = Duration::from_secs(timeout_secs);
494 self
495 }
496
497 pub fn idle_timeout(mut self, timeout_secs: u64) -> Self {
498 self.config.idle_timeout = Duration::from_secs(timeout_secs);
499 self
500 }
501
502 pub fn max_lifetime(mut self, lifetime_secs: u64) -> Self {
503 self.config.max_lifetime = Duration::from_secs(lifetime_secs);
504 self
505 }
506
507 pub fn tls(mut self, tls: TlsConfig) -> Self {
509 self.config.tls = Some(tls);
510 self
511 }
512
513 pub fn query_timeout(mut self, timeout: Duration) -> Self {
515 self.config.query_timeout = Some(timeout);
516 self
517 }
518
519 pub fn max_rows(mut self, max_rows: usize) -> Self {
521 self.config.max_rows = Some(max_rows);
522 self
523 }
524
525 pub fn memory_limit(mut self, memory_limit: usize) -> Self {
527 self.config.memory_limit = Some(memory_limit);
528 self
529 }
530
531 pub fn on_event(mut self, callback: PoolEventCallback) -> Self {
533 self.config.on_event = Some(callback);
534 self
535 }
536
537 pub fn build(self) -> Result<PoolConfig, PoolError> {
538 self.config.validate()?;
539 Ok(self.config)
540 }
541}
542
543impl Default for PoolConfigBuilder {
544 fn default() -> Self {
545 Self::new()
546 }
547}
548
549#[async_trait]
551pub trait ConnectionFactory: Send + Sync {
552 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError>;
553}
554
555pub struct Pool {
561 config: PoolConfig,
562 factory: Arc<dyn ConnectionFactory>,
563 idle: Arc<ArrayQueue<PooledConnection>>,
569 total_count: Arc<AtomicU32>,
579 closed: Arc<AtomicBool>,
581 notify: Arc<Notify>,
582 waiters_count: Arc<AtomicU32>,
584 dynamic_max_size: Arc<AtomicU32>,
586 #[cfg(feature = "circuit-breaker")]
592 circuit_breaker: Arc<std::sync::Mutex<sz_orm_health::CircuitBreaker>>,
593 #[cfg(feature = "rate-limit")]
599 rate_limiter: Arc<std::sync::RwLock<Option<Arc<dyn sz_orm_limit::RateLimiter>>>>,
600 #[cfg(feature = "rate-limit")]
602 rate_limit_key: String,
603}
604
605impl Clone for Pool {
609 fn clone(&self) -> Self {
610 Self {
611 config: self.config.clone(),
612 factory: self.factory.clone(),
613 idle: self.idle.clone(),
614 total_count: self.total_count.clone(),
615 closed: self.closed.clone(),
616 notify: Arc::clone(&self.notify),
617 waiters_count: self.waiters_count.clone(),
618 dynamic_max_size: self.dynamic_max_size.clone(),
619 #[cfg(feature = "circuit-breaker")]
620 circuit_breaker: Arc::clone(&self.circuit_breaker),
621 #[cfg(feature = "rate-limit")]
622 rate_limiter: Arc::clone(&self.rate_limiter),
623 #[cfg(feature = "rate-limit")]
624 rate_limit_key: self.rate_limit_key.clone(),
625 }
626 }
627}
628
629impl Pool {
630 pub fn new(config: PoolConfig, factory: Arc<dyn ConnectionFactory>) -> Result<Self, PoolError> {
654 config.validate()?;
655 let max_size = config.max_size as usize;
658 let dynamic_max = config.max_size;
659 Ok(Self {
660 config,
661 factory,
662 idle: Arc::new(ArrayQueue::new(max_size)),
663 total_count: Arc::new(AtomicU32::new(0)),
664 closed: Arc::new(AtomicBool::new(false)),
665 notify: Arc::new(Notify::new()),
666 waiters_count: Arc::new(AtomicU32::new(0)),
667 dynamic_max_size: Arc::new(AtomicU32::new(dynamic_max)),
668 #[cfg(feature = "circuit-breaker")]
670 circuit_breaker: Arc::new(std::sync::Mutex::new(sz_orm_health::CircuitBreaker::new(
671 5,
672 std::time::Duration::from_secs(30),
673 ))),
674 #[cfg(feature = "rate-limit")]
676 rate_limiter: Arc::new(std::sync::RwLock::new(None)),
677 #[cfg(feature = "rate-limit")]
678 rate_limit_key: "pool".to_string(),
679 })
680 }
681
682 pub fn config(&self) -> &PoolConfig {
684 &self.config
685 }
686
687 #[cfg(feature = "circuit-breaker")]
701 pub fn configure_circuit_breaker(
702 &self,
703 failure_threshold: usize,
704 reset_timeout: std::time::Duration,
705 ) {
706 let new_cb = sz_orm_health::CircuitBreaker::new(failure_threshold, reset_timeout);
707 if let Ok(mut guard) = self.circuit_breaker.lock() {
708 *guard = new_cb;
709 }
710 }
711
712 #[cfg(feature = "circuit-breaker")]
717 pub fn reset_circuit_breaker(&self) -> bool {
718 if let Ok(mut guard) = self.circuit_breaker.lock() {
719 return guard.reset();
720 }
721 false
722 }
723
724 #[cfg(feature = "circuit-breaker")]
726 pub fn circuit_state(&self) -> sz_orm_health::CircuitState {
727 if let Ok(guard) = self.circuit_breaker.lock() {
728 guard.state()
729 } else {
730 sz_orm_health::CircuitState::Closed
732 }
733 }
734
735 #[cfg(feature = "rate-limit")]
740 pub fn set_rate_limiter(&self, limiter: Option<Arc<dyn sz_orm_limit::RateLimiter>>) {
741 if let Ok(mut guard) = self.rate_limiter.write() {
742 *guard = limiter;
743 }
744 }
745
746 #[cfg(feature = "rate-limit")]
748 pub fn with_rate_limit_key(mut self, key: impl Into<String>) -> Self {
749 self.rate_limit_key = key.into();
750 self
751 }
752
753 fn emit_event(&self, event: PoolEvent) {
755 if let Some(ref callback) = self.config.on_event {
756 callback(event);
757 }
758 }
759
760 #[tracing::instrument(skip(self), fields(max_size = self.config.max_size, acquire_timeout = ?self.config.acquire_timeout))]
780 pub async fn acquire(&self) -> Result<PooledConnection, PoolError> {
781 if self.closed.load(Ordering::Acquire) {
783 return Err(PoolError::Closed);
784 }
785
786 #[cfg(feature = "circuit-breaker")]
789 {
790 let can_execute = if let Ok(mut guard) = self.circuit_breaker.lock() {
791 guard.can_execute()
792 } else {
793 true
795 };
796 if !can_execute {
797 return Err(PoolError::CircuitOpen);
798 }
799 }
800
801 #[cfg(feature = "rate-limit")]
804 {
805 if let Ok(guard) = self.rate_limiter.read() {
806 if let Some(ref limiter) = *guard {
807 match limiter.try_acquire(&self.rate_limit_key) {
808 Ok(result) if !result.allowed => {
809 return Err(PoolError::RateLimited {
810 remaining: result.remaining,
811 reset_at: result.reset_at,
812 });
813 }
814 Ok(_) => {} Err(_) => {
816 }
818 }
819 }
820 }
821 }
822
823 let deadline = Instant::now() + self.config.acquire_timeout;
824 let mut backoff = Duration::from_millis(1);
826 const MAX_BACKOFF: Duration = Duration::from_millis(100);
828
829 loop {
830 let mut to_close: Vec<PooledConnection> = Vec::new();
836 let acquired: Option<PooledConnection> = {
837 let mut found: Option<PooledConnection> = None;
838 while let Some(pooled) = self.idle.pop() {
839 if pooled.is_expired(self.config.max_lifetime) {
841 to_close.push(pooled);
842 continue;
843 }
844 if pooled.is_idle_too_long(self.config.idle_timeout) {
846 to_close.push(pooled);
847 continue;
848 }
849 if !pooled.conn.is_connected() {
852 to_close.push(pooled);
853 continue;
854 }
855 found = Some(pooled);
856 break;
857 }
858 found
859 };
860
861 for mut pooled in to_close {
863 let _ = pooled.conn.close().await;
864 self.total_count.fetch_sub(1, Ordering::SeqCst);
866 }
867
868 if let Some(mut pooled) = acquired {
869 pooled.pool = Some(self.clone());
872 return Ok(pooled);
873 }
874
875 let current_max = self.dynamic_max_size.load(Ordering::Acquire);
880 let created = loop {
881 let current = self.total_count.load(Ordering::Acquire);
882 if current >= current_max {
883 break None; }
885 match self.total_count.compare_exchange(
886 current,
887 current + 1,
888 Ordering::SeqCst,
889 Ordering::Acquire,
890 ) {
891 Ok(_) => break Some(()), Err(_) => continue, }
894 };
895
896 if created.is_some() {
897 match tokio::time::timeout(self.config.connection_timeout, self.factory.create())
898 .await
899 {
900 Ok(Ok(conn)) => {
901 #[cfg(feature = "circuit-breaker")]
903 {
904 if let Ok(mut guard) = self.circuit_breaker.lock() {
905 guard.record_success();
906 }
907 }
908 self.emit_event(PoolEvent::ConnectionCreated);
909 self.emit_event(PoolEvent::ConnectionAcquired);
910 return Ok(PooledConnection::new(conn, self.clone()));
911 }
912 Ok(Err(e)) => {
913 self.total_count.fetch_sub(1, Ordering::SeqCst);
915 #[cfg(feature = "circuit-breaker")]
917 {
918 if let Ok(mut guard) = self.circuit_breaker.lock() {
919 guard.record_failure();
920 }
921 }
922 return Err(PoolError::ConnectionFailed(e.to_string()));
923 }
924 Err(_) => {
925 self.total_count.fetch_sub(1, Ordering::SeqCst);
927 #[cfg(feature = "circuit-breaker")]
929 {
930 if let Ok(mut guard) = self.circuit_breaker.lock() {
931 guard.record_failure();
932 }
933 }
934 return Err(PoolError::Timeout);
935 }
936 }
937 }
938
939 let now = Instant::now();
941 if now >= deadline {
942 self.emit_event(PoolEvent::AcquireTimeout);
943 return Err(PoolError::Timeout);
944 }
945 self.waiters_count.fetch_add(1, Ordering::SeqCst);
947 let wait = std::cmp::min(backoff, deadline - now);
948 match tokio::time::timeout(wait, self.notify.notified()).await {
949 Ok(()) => {
950 backoff = Duration::from_millis(1);
952 }
953 Err(_) => {
954 backoff = std::cmp::min(backoff * 2, MAX_BACKOFF);
956 }
957 }
958 self.waiters_count.fetch_sub(1, Ordering::SeqCst);
960 }
961 }
962
963 #[tracing::instrument(skip(self, pooled))]
971 pub async fn release(&self, mut pooled: PooledConnection) {
972 pooled.pool = None;
974
975 if self.closed.load(Ordering::Acquire) {
977 let _ = pooled.conn.close().await;
978 self.total_count.fetch_sub(1, Ordering::SeqCst);
980 self.emit_event(PoolEvent::ConnectionClosed);
981 return;
982 }
983
984 if !pooled.conn.is_connected() {
986 let _ = pooled.conn.close().await;
987 self.total_count.fetch_sub(1, Ordering::SeqCst);
988 self.emit_event(PoolEvent::ConnectionClosed);
989 return;
990 }
991
992 pooled.last_used_at = Instant::now();
994
995 if let Err(mut rejected) = self.idle.push(pooled) {
1001 let _ = rejected.conn.close().await;
1003 self.total_count.fetch_sub(1, Ordering::SeqCst);
1004 self.emit_event(PoolEvent::ConnectionClosed);
1005 } else {
1006 self.emit_event(PoolEvent::ConnectionReleased);
1007 }
1008 self.notify.notify_one();
1009 }
1010
1011 pub async fn status(&self) -> PoolStatus {
1016 let idle_count = self.idle.len() as u32;
1017 let active = self.total_count.load(Ordering::Acquire);
1019 let waiters = self.waiters_count.load(Ordering::Acquire);
1020 PoolStatus {
1021 idle: idle_count,
1022 active,
1023 max: self.dynamic_max_size.load(Ordering::Acquire),
1024 min: self.config.min_idle,
1025 waiters,
1026 }
1027 }
1028
1029 #[tracing::instrument(skip(self))]
1031 pub async fn reap_idle(&self) {
1032 let mut all: Vec<PooledConnection> = Vec::new();
1036 while let Some(pooled) = self.idle.pop() {
1037 all.push(pooled);
1038 }
1039
1040 let mut to_close = Vec::new();
1042 for pooled in all {
1043 if pooled.is_idle_too_long(self.config.idle_timeout)
1044 || pooled.is_expired(self.config.max_lifetime)
1045 {
1046 to_close.push(pooled);
1047 } else {
1048 if let Err(mut rejected) = self.idle.push(pooled) {
1050 let _ = rejected.conn.close().await;
1051 self.total_count.fetch_sub(1, Ordering::SeqCst);
1052 }
1053 }
1054 }
1055
1056 for mut pooled in to_close {
1058 let _ = pooled.conn.close().await;
1059 self.total_count.fetch_sub(1, Ordering::SeqCst);
1061 }
1062 }
1063
1064 pub async fn close_all(&self) {
1068 self.closed.store(true, Ordering::Release);
1070 let mut to_close: Vec<PooledConnection> = Vec::new();
1073 while let Some(pooled) = self.idle.pop() {
1074 to_close.push(pooled);
1075 }
1076 let closed_count: u32 = to_close.len() as u32;
1078 for mut pooled in to_close {
1079 let _ = pooled.conn.close().await;
1080 }
1081 self.total_count.fetch_sub(closed_count, Ordering::SeqCst);
1084 }
1085
1086 pub async fn health_check(&self) -> u32 {
1102 let mut to_check: Vec<PooledConnection> = Vec::new();
1104 while let Some(pooled) = self.idle.pop() {
1105 to_check.push(pooled);
1106 }
1107
1108 let mut removed: u32 = 0;
1109 let mut alive: Vec<PooledConnection> = Vec::with_capacity(to_check.len());
1110 for mut pooled in to_check.drain(..) {
1111 if !pooled.conn.is_connected() {
1113 let _ = pooled.conn.close().await;
1114 removed += 1;
1115 continue;
1116 }
1117 let ping_timeout = self.config.connection_timeout / 2;
1119 match tokio::time::timeout(ping_timeout, pooled.conn.ping()).await {
1120 Ok(true) => alive.push(pooled),
1121 Ok(false) => {
1122 let _ = pooled.conn.close().await;
1124 removed += 1;
1125 }
1126 Err(_) => {
1127 let _ = pooled.conn.close().await;
1129 removed += 1;
1130 }
1131 }
1132 }
1133
1134 let alive_count: u32 = alive.len() as u32;
1136 for pooled in alive {
1137 if let Err(mut rejected) = self.idle.push(pooled) {
1139 let _ = rejected.conn.close().await;
1140 removed += 1;
1141 }
1142 }
1143
1144 if removed > 0 {
1146 self.total_count.fetch_sub(removed, Ordering::SeqCst);
1147 }
1148
1149 if alive_count > 0 {
1151 self.notify.notify_one();
1152 }
1153
1154 removed
1155 }
1156
1157 pub async fn shutdown(&self) {
1164 self.closed.store(true, Ordering::SeqCst);
1166 self.notify.notify_waiters();
1168 self.close_all().await;
1170 let deadline = Instant::now() + Duration::from_secs(30);
1172 while self.total_count.load(Ordering::SeqCst) > 0 {
1173 if Instant::now() >= deadline {
1174 break;
1175 }
1176 tokio::time::sleep(Duration::from_millis(100)).await;
1177 }
1178 }
1179
1180 pub fn resize(&self, new_max: usize) {
1188 self.set_max_size(new_max as u32);
1189 }
1190
1191 pub fn set_max_size(&self, new_max: u32) {
1193 self.dynamic_max_size.store(new_max, Ordering::SeqCst);
1194 }
1195
1196 pub fn max_size(&self) -> u32 {
1198 self.dynamic_max_size.load(Ordering::Acquire)
1199 }
1200
1201 pub async fn warmup(&self, min_idle: usize) -> Result<(), PoolError> {
1205 for _ in 0..min_idle {
1206 let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1207 let current = self.total_count.load(Ordering::Acquire);
1208 if current >= current_max {
1209 break;
1210 }
1211 match self.total_count.compare_exchange(
1213 current,
1214 current + 1,
1215 Ordering::SeqCst,
1216 Ordering::Acquire,
1217 ) {
1218 Ok(_) => {}
1219 Err(_) => continue, }
1221 match self.factory.create().await {
1222 Ok(conn) => {
1223 let now = Instant::now();
1224 let pooled = PooledConnection {
1225 conn,
1226 created_at: now,
1227 last_used_at: now,
1228 pool: None,
1229 };
1230 if let Err(mut rejected) = self.idle.push(pooled) {
1231 let _ = rejected.conn.close().await;
1233 self.total_count.fetch_sub(1, Ordering::SeqCst);
1234 }
1235 self.emit_event(PoolEvent::ConnectionCreated);
1236 }
1237 Err(_) => {
1238 self.total_count.fetch_sub(1, Ordering::SeqCst);
1240 break;
1241 }
1242 }
1243 }
1244 Ok(())
1245 }
1246
1247 pub async fn query_with_timeout(&self, sql: &str) -> Result<QueryRows, crate::DbError> {
1252 let timeout = self.config.query_timeout.unwrap_or(Duration::from_secs(30));
1253 let mut conn = self.acquire().await.map_err(crate::DbError::PoolError)?;
1254 tokio::time::timeout(timeout, conn.query(sql))
1255 .await
1256 .map_err(|_| crate::DbError::QueryError(format!("Query timeout after {:?}", timeout)))?
1257 }
1258}
1259
1260#[cfg(test)]
1261mod tests {
1262 use super::*;
1263
1264 struct MockConnection {
1266 connected: bool,
1267 }
1268
1269 impl MockConnection {
1270 fn new() -> Self {
1271 Self { connected: true }
1272 }
1273 }
1274
1275 impl Connection for MockConnection {
1276 fn execute<'a>(
1277 &'a mut self,
1278 _sql: &'a str,
1279 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
1280 Box::pin(async move { Ok(1) })
1281 }
1282
1283 fn query<'a>(
1284 &'a mut self,
1285 _sql: &'a str,
1286 ) -> Pin<
1287 Box<
1288 dyn Future<
1289 Output = Result<
1290 Vec<std::collections::HashMap<String, crate::value::Value>>,
1291 crate::DbError,
1292 >,
1293 > + Send
1294 + 'a,
1295 >,
1296 > {
1297 Box::pin(async move { Ok(vec![]) })
1298 }
1299
1300 fn begin_transaction<'a>(
1301 &'a mut self,
1302 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1303 Box::pin(async move { Ok(()) })
1304 }
1305
1306 fn commit<'a>(
1307 &'a mut self,
1308 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1309 Box::pin(async move { Ok(()) })
1310 }
1311
1312 fn rollback<'a>(
1313 &'a mut self,
1314 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1315 Box::pin(async move { Ok(()) })
1316 }
1317
1318 fn is_connected(&self) -> bool {
1319 self.connected
1320 }
1321
1322 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
1323 Box::pin(async move { true })
1324 }
1325
1326 fn close<'a>(
1327 &'a mut self,
1328 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1329 Box::pin(async move {
1330 self.connected = false;
1331 Ok(())
1332 })
1333 }
1334 }
1335
1336 struct MockConnectionFactory;
1337
1338 #[async_trait]
1339 impl ConnectionFactory for MockConnectionFactory {
1340 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
1341 Ok(Box::new(MockConnection::new()))
1342 }
1343 }
1344
1345 #[tokio::test]
1346 async fn test_pool_config_builder() {
1347 let config = PoolConfigBuilder::new()
1348 .max_size(50)
1349 .min_idle(10)
1350 .build()
1351 .unwrap();
1352
1353 assert_eq!(config.max_size, 50);
1354 assert_eq!(config.min_idle, 10);
1355 }
1356
1357 #[test]
1358 fn test_pool_status_display() {
1359 let status = PoolStatus {
1360 idle: 5,
1361 active: 10,
1362 max: 100,
1363 min: 5,
1364 waiters: 0,
1365 };
1366
1367 let display = format!("{:?}", status);
1368 assert!(display.contains("idle"));
1369 assert!(display.contains("active"));
1370 }
1371
1372 #[test]
1373 fn test_default_pool_config() {
1374 let config = PoolConfig::default();
1375 assert_eq!(config.max_size, 100);
1376 assert_eq!(config.min_idle, 0);
1377 assert_eq!(config.acquire_timeout.as_secs(), 30);
1378 assert_eq!(config.idle_timeout.as_secs(), 600);
1379 assert_eq!(config.max_lifetime.as_secs(), 1800);
1380 }
1381
1382 #[tokio::test]
1383 async fn test_pool_config_clone() {
1384 let config = PoolConfig::default();
1385 let cloned = config.clone();
1386 assert_eq!(cloned.max_size, config.max_size);
1387 assert_eq!(cloned.min_idle, config.min_idle);
1388 }
1389
1390 #[test]
1391 fn test_pool_config_builder_default() {
1392 let builder = PoolConfigBuilder::new();
1393 let config = builder.build().unwrap();
1394 assert_eq!(config.max_size, 100);
1395 }
1396
1397 #[test]
1398 fn test_pool_config_validate() {
1399 let result = PoolConfigBuilder::new().max_size(0).build();
1400 assert!(result.is_err());
1401
1402 let result = PoolConfigBuilder::new().max_size(10).min_idle(20).build();
1403 assert!(result.is_err());
1404 }
1405
1406 #[tokio::test]
1407 async fn test_pool_acquire_and_release() {
1408 let config = PoolConfigBuilder::new()
1409 .max_size(5)
1410 .min_idle(1)
1411 .build()
1412 .unwrap();
1413 let factory = Arc::new(MockConnectionFactory);
1414 let pool = Pool::new(config, factory).unwrap();
1415
1416 let conn = pool.acquire().await.unwrap();
1417 let status = pool.status().await;
1418 assert_eq!(status.active, 1);
1419 assert_eq!(status.idle, 0);
1420
1421 pool.release(conn).await;
1422 let status = pool.status().await;
1423 assert_eq!(status.idle, 1);
1424
1425 let _conn2 = pool.acquire().await.unwrap();
1427 let status = pool.status().await;
1428 assert_eq!(status.idle, 0);
1429 }
1430
1431 #[tokio::test]
1432 async fn test_pool_status() {
1433 let config = PoolConfigBuilder::new()
1434 .max_size(10)
1435 .min_idle(2)
1436 .build()
1437 .unwrap();
1438 let factory = Arc::new(MockConnectionFactory);
1439 let pool = Pool::new(config, factory).unwrap();
1440
1441 let status = pool.status().await;
1442 assert_eq!(status.max, 10);
1443 assert_eq!(status.min, 2);
1444 assert_eq!(status.active, 0);
1445 }
1446
1447 #[tokio::test]
1448 async fn test_pool_close_all() {
1449 let config = PoolConfigBuilder::new().max_size(5).build().unwrap();
1450 let factory = Arc::new(MockConnectionFactory);
1451 let pool = Pool::new(config, factory).unwrap();
1452
1453 let conn1 = pool.acquire().await.unwrap();
1455 let conn2 = pool.acquire().await.unwrap();
1456 pool.release(conn1).await;
1457 pool.release(conn2).await;
1458
1459 pool.close_all().await;
1460 let status = pool.status().await;
1461 assert_eq!(status.idle, 0);
1462 assert_eq!(status.active, 0);
1463 }
1464
1465 #[tokio::test]
1466 async fn test_pool_reap_idle() {
1467 let config = PoolConfigBuilder::new()
1468 .max_size(5)
1469 .idle_timeout(0) .build()
1471 .unwrap();
1472 let factory = Arc::new(MockConnectionFactory);
1473 let pool = Pool::new(config, factory).unwrap();
1474
1475 let conn = pool.acquire().await.unwrap();
1476 pool.release(conn).await;
1477
1478 tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
1480
1481 pool.reap_idle().await;
1482 let status = pool.status().await;
1483 assert_eq!(status.idle, 0);
1484 }
1485
1486 #[tokio::test]
1492 async fn test_h7_acquire_timeout_default_30s() {
1493 let config = PoolConfig::default();
1494 assert_eq!(
1495 config.acquire_timeout,
1496 Duration::from_secs(30),
1497 "H-7: acquire_timeout 默认应为 30s"
1498 );
1499 }
1500
1501 #[tokio::test]
1503 async fn test_h7_acquire_timeout_configurable() {
1504 let config = PoolConfigBuilder::new()
1505 .max_size(1)
1506 .acquire_timeout(5) .build()
1508 .unwrap();
1509 assert_eq!(config.acquire_timeout, Duration::from_secs(5));
1510
1511 let factory = Arc::new(MockConnectionFactory);
1513 let pool = Pool::new(config, factory).unwrap();
1514 let _conn1 = pool.acquire().await.unwrap();
1515
1516 let fast_config = PoolConfigBuilder::new()
1518 .max_size(1)
1519 .acquire_timeout(0) .build()
1521 .unwrap();
1522 let fast_pool = Pool::new(fast_config, Arc::new(MockConnectionFactory)).unwrap();
1525 let _fast_conn = fast_pool.acquire().await.unwrap(); let result = fast_pool.acquire().await;
1527 assert!(
1528 matches!(result, Err(PoolError::Timeout)),
1529 "H-7: 应返回 Timeout"
1530 );
1531 }
1532
1533 #[tokio::test]
1536 async fn test_m7_health_check_removes_nothing_when_all_healthy() {
1537 let config = PoolConfigBuilder::new().max_size(5).build().unwrap();
1539 let factory = Arc::new(MockConnectionFactory);
1540 let pool = Pool::new(config, factory).unwrap();
1541
1542 let conn1 = pool.acquire().await.unwrap();
1544 let conn2 = pool.acquire().await.unwrap();
1545 let conn3 = pool.acquire().await.unwrap();
1546 pool.release(conn1).await;
1547 pool.release(conn2).await;
1548 pool.release(conn3).await;
1549
1550 let removed = pool.health_check().await;
1551 assert_eq!(removed, 0, "Healthy connections should not be removed");
1552
1553 let status = pool.status().await;
1554 assert_eq!(status.idle, 3);
1555 assert_eq!(status.active, 3);
1556 }
1557
1558 #[tokio::test]
1559 async fn test_m7_health_check_returns_zero_for_empty_pool() {
1560 let config = PoolConfigBuilder::new().max_size(5).build().unwrap();
1561 let factory = Arc::new(MockConnectionFactory);
1562 let pool = Pool::new(config, factory).unwrap();
1563
1564 let removed = pool.health_check().await;
1565 assert_eq!(removed, 0);
1566 }
1567
1568 struct CountingFactory {
1572 count: AtomicU32,
1573 }
1574
1575 impl CountingFactory {
1576 fn new() -> Self {
1577 Self {
1578 count: AtomicU32::new(0),
1579 }
1580 }
1581 fn created_count(&self) -> u32 {
1582 self.count.load(Ordering::SeqCst)
1583 }
1584 }
1585
1586 #[async_trait]
1587 impl ConnectionFactory for CountingFactory {
1588 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
1589 self.count.fetch_add(1, Ordering::SeqCst);
1590 Ok(Box::new(MockConnection::new()))
1591 }
1592 }
1593
1594 #[tokio::test]
1600 async fn test_production_bug_max_lifetime_never_expires() {
1601 let config = PoolConfig {
1604 max_size: 5,
1605 min_idle: 0,
1606 acquire_timeout: Duration::from_secs(30),
1607 idle_timeout: Duration::from_secs(600),
1608 max_lifetime: Duration::from_millis(100), connection_timeout: Duration::from_secs(10),
1610 tls: None,
1611 query_timeout: None,
1612 max_rows: None,
1613 memory_limit: None,
1614 on_event: None,
1615 };
1616 let factory = Arc::new(CountingFactory::new());
1617 let pool = Pool::new(config, factory.clone()).unwrap();
1618
1619 let conn = pool.acquire().await.unwrap();
1621 assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
1622
1623 pool.release(conn).await;
1625
1626 tokio::time::sleep(Duration::from_millis(150)).await;
1628
1629 let conn2 = pool.acquire().await.unwrap();
1631
1632 assert_eq!(
1635 factory.created_count(),
1636 2,
1637 "超过 max_lifetime 后应创建新连接(旧连接应被回收)"
1638 );
1639
1640 pool.release(conn2).await;
1641 }
1642
1643 #[tokio::test]
1650 async fn test_drop_auto_release_connection() {
1651 let config = PoolConfigBuilder::new().max_size(2).build().unwrap();
1652 let factory = Arc::new(CountingFactory::new());
1653 let pool = Pool::new(config, factory.clone()).unwrap();
1654
1655 {
1657 let _conn = pool.acquire().await.unwrap();
1658 assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
1659 let status = pool.status().await;
1660 assert_eq!(status.active, 1, "active 应为 1");
1661 assert_eq!(status.idle, 0, "idle 应为 0");
1662 }
1664
1665 tokio::time::sleep(Duration::from_millis(50)).await;
1667
1668 let status = pool.status().await;
1670 assert_eq!(status.idle, 1, "Drop 后连接应自动归还,idle 应为 1");
1671 assert_eq!(status.active, 1, "total_count 应为 1");
1672 assert_eq!(factory.created_count(), 1, "应复用归还的连接,不创建新连接");
1673 }
1674
1675 #[tokio::test]
1677 async fn test_drop_auto_release_then_reuse() {
1678 let config = PoolConfigBuilder::new().max_size(1).build().unwrap();
1679 let factory = Arc::new(CountingFactory::new());
1680 let pool = Pool::new(config, factory.clone()).unwrap();
1681
1682 {
1684 let _conn = pool.acquire().await.unwrap();
1685 }
1686
1687 tokio::time::sleep(Duration::from_millis(50)).await;
1689
1690 let conn = pool.acquire().await.expect("应能复用 Drop 归还的连接");
1692 assert_eq!(factory.created_count(), 1, "应复用归还的连接,不创建新连接");
1693
1694 pool.release(conn).await;
1695 }
1696
1697 #[tokio::test]
1699 async fn test_into_inner_does_not_return_to_pool() {
1700 let config = PoolConfigBuilder::new().max_size(2).build().unwrap();
1701 let factory = Arc::new(CountingFactory::new());
1702 let pool = Pool::new(config, factory.clone()).unwrap();
1703
1704 let conn = pool.acquire().await.unwrap();
1705 assert_eq!(factory.created_count(), 1);
1706
1707 let _raw_conn = conn.into_inner();
1709
1710 tokio::time::sleep(Duration::from_millis(50)).await;
1712
1713 let status = pool.status().await;
1714 assert_eq!(status.idle, 0, "into_inner 后连接不应归还");
1715 assert_eq!(status.active, 1, "total_count 仍为 1(连接被外部持有)");
1716 }
1717
1718 #[tokio::test]
1720 async fn test_explicit_release_no_double_return() {
1721 let config = PoolConfigBuilder::new().max_size(2).build().unwrap();
1722 let factory = Arc::new(CountingFactory::new());
1723 let pool = Pool::new(config, factory.clone()).unwrap();
1724
1725 let conn = pool.acquire().await.unwrap();
1726 pool.release(conn).await;
1727
1728 let status = pool.status().await;
1729 assert_eq!(status.idle, 1, "release 后 idle 应为 1");
1730
1731 let conn = pool.acquire().await.unwrap();
1733 pool.release(conn).await;
1734
1735 let status = pool.status().await;
1736 assert_eq!(status.idle, 1, "再次 release 后 idle 仍应为 1(不重复)");
1737 assert_eq!(status.active, 1, "total_count 应为 1");
1738 }
1739}