1use async_trait::async_trait;
6use std::collections::VecDeque;
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::{Mutex, Notify};
14
15use crate::error::PoolError;
16
17pub type QueryRows = Vec<std::collections::HashMap<String, crate::value::Value>>;
19
20pub trait Connection: Send + Sync {
27 fn execute<'a>(
28 &'a mut self,
29 sql: &'a str,
30 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>>;
31 fn query<'a>(
32 &'a mut self,
33 sql: &'a str,
34 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>>;
35 fn begin_transaction<'a>(
36 &'a mut self,
37 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
38 fn commit<'a>(
39 &'a mut self,
40 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
41 fn rollback<'a>(
42 &'a mut self,
43 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
44 fn is_connected(&self) -> bool;
45 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>>;
46 fn close<'a>(
47 &'a mut self,
48 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
49}
50
51pub struct PooledConnection {
57 conn: Box<dyn Connection>,
58 created_at: Instant,
59 last_used_at: Instant,
60}
61
62impl PooledConnection {
63 fn new(conn: Box<dyn Connection>) -> Self {
64 let now = Instant::now();
65 Self {
66 conn,
67 created_at: now,
68 last_used_at: now,
69 }
70 }
71
72 fn is_expired(&self, max_lifetime: Duration) -> bool {
73 self.created_at.elapsed() >= max_lifetime
74 }
75
76 fn is_idle_too_long(&self, idle_timeout: Duration) -> bool {
77 self.last_used_at.elapsed() >= idle_timeout
78 }
79
80 pub fn created_at(&self) -> Instant {
82 self.created_at
83 }
84
85 pub fn into_inner(self) -> Box<dyn Connection> {
90 self.conn
91 }
92}
93
94impl Deref for PooledConnection {
95 type Target = dyn Connection;
96
97 fn deref(&self) -> &Self::Target {
98 self.conn.as_ref()
99 }
100}
101
102impl DerefMut for PooledConnection {
103 fn deref_mut(&mut self) -> &mut Self::Target {
104 self.conn.as_mut()
105 }
106}
107
108pub struct PoolConfig {
109 pub max_size: u32,
110 pub min_idle: u32,
111 pub acquire_timeout: Duration,
112 pub idle_timeout: Duration,
113 pub max_lifetime: Duration,
114 pub connection_timeout: Duration,
115}
116
117impl Default for PoolConfig {
118 fn default() -> Self {
119 Self {
120 max_size: 100,
121 min_idle: 0,
122 acquire_timeout: Duration::from_secs(30),
123 idle_timeout: Duration::from_secs(600),
124 max_lifetime: Duration::from_secs(1800),
125 connection_timeout: Duration::from_secs(10),
126 }
127 }
128}
129
130impl Clone for PoolConfig {
131 fn clone(&self) -> Self {
132 Self {
133 max_size: self.max_size,
134 min_idle: self.min_idle,
135 acquire_timeout: self.acquire_timeout,
136 idle_timeout: self.idle_timeout,
137 max_lifetime: self.max_lifetime,
138 connection_timeout: self.connection_timeout,
139 }
140 }
141}
142
143impl PoolConfig {
144 pub fn validate(&self) -> Result<(), PoolError> {
146 if self.max_size == 0 {
147 return Err(PoolError::InvalidConfig("max_size cannot be 0".to_string()));
148 }
149 if self.min_idle > self.max_size {
150 return Err(PoolError::InvalidConfig(
151 "min_idle cannot exceed max_size".to_string(),
152 ));
153 }
154 Ok(())
155 }
156}
157
158pub struct PoolStatus {
159 pub idle: u32,
160 pub active: u32,
161 pub max: u32,
162 pub min: u32,
163}
164
165impl std::fmt::Debug for PoolStatus {
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 f.debug_struct("PoolStatus")
168 .field("idle", &self.idle)
169 .field("active", &self.active)
170 .field("max", &self.max)
171 .field("min", &self.min)
172 .finish()
173 }
174}
175
176pub struct PoolConfigBuilder {
177 config: PoolConfig,
178}
179
180impl PoolConfigBuilder {
181 pub fn new() -> Self {
182 Self {
183 config: PoolConfig::default(),
184 }
185 }
186
187 pub fn max_size(mut self, size: u32) -> Self {
188 self.config.max_size = size;
189 self
190 }
191
192 pub fn min_idle(mut self, count: u32) -> Self {
193 self.config.min_idle = count;
194 self
195 }
196
197 pub fn acquire_timeout(mut self, timeout_secs: u64) -> Self {
198 self.config.acquire_timeout = Duration::from_secs(timeout_secs);
199 self
200 }
201
202 pub fn idle_timeout(mut self, timeout_secs: u64) -> Self {
203 self.config.idle_timeout = Duration::from_secs(timeout_secs);
204 self
205 }
206
207 pub fn max_lifetime(mut self, lifetime_secs: u64) -> Self {
208 self.config.max_lifetime = Duration::from_secs(lifetime_secs);
209 self
210 }
211
212 pub fn build(self) -> Result<PoolConfig, PoolError> {
213 self.config.validate()?;
214 Ok(self.config)
215 }
216}
217
218impl Default for PoolConfigBuilder {
219 fn default() -> Self {
220 Self::new()
221 }
222}
223
224#[async_trait]
226pub trait ConnectionFactory: Send + Sync {
227 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError>;
228}
229
230pub struct Pool {
232 config: PoolConfig,
233 factory: Arc<dyn ConnectionFactory>,
234 idle: Arc<Mutex<VecDeque<PooledConnection>>>,
235 total_count: Arc<AtomicU32>,
245 closed: Arc<AtomicBool>,
247 notify: Notify,
248}
249
250impl Pool {
251 pub fn new(config: PoolConfig, factory: Arc<dyn ConnectionFactory>) -> Result<Self, PoolError> {
275 config.validate()?;
276 Ok(Self {
277 config,
278 factory,
279 idle: Arc::new(Mutex::new(VecDeque::new())),
280 total_count: Arc::new(AtomicU32::new(0)),
281 closed: Arc::new(AtomicBool::new(false)),
282 notify: Notify::new(),
283 })
284 }
285
286 pub fn config(&self) -> &PoolConfig {
288 &self.config
289 }
290
291 #[tracing::instrument(skip(self), fields(max_size = self.config.max_size, acquire_timeout = ?self.config.acquire_timeout))]
311 pub async fn acquire(&self) -> Result<PooledConnection, PoolError> {
312 if self.closed.load(Ordering::Acquire) {
314 return Err(PoolError::Closed);
315 }
316
317 let deadline = Instant::now() + self.config.acquire_timeout;
318
319 loop {
320 let mut to_close: Vec<PooledConnection> = Vec::new();
326 let acquired: Option<PooledConnection> = {
327 let mut idle = self.idle.lock().await;
328 let mut found: Option<PooledConnection> = None;
329 while let Some(pooled) = idle.pop_front() {
330 if pooled.is_expired(self.config.max_lifetime) {
332 to_close.push(pooled);
333 continue;
334 }
335 if pooled.is_idle_too_long(self.config.idle_timeout) {
337 to_close.push(pooled);
338 continue;
339 }
340 if !pooled.conn.is_connected() {
343 to_close.push(pooled);
344 continue;
345 }
346 found = Some(pooled);
347 break;
348 }
349 found
350 };
352
353 for mut pooled in to_close {
355 let _ = pooled.conn.close().await;
356 self.total_count.fetch_sub(1, Ordering::SeqCst);
358 }
359
360 if let Some(pooled) = acquired {
361 return Ok(pooled);
362 }
363
364 let created = loop {
368 let current = self.total_count.load(Ordering::Acquire);
369 if current >= self.config.max_size {
370 break None; }
372 match self.total_count.compare_exchange(
373 current,
374 current + 1,
375 Ordering::SeqCst,
376 Ordering::Acquire,
377 ) {
378 Ok(_) => break Some(()), Err(_) => continue, }
381 };
382
383 if created.is_some() {
384 match tokio::time::timeout(self.config.connection_timeout, self.factory.create())
385 .await
386 {
387 Ok(Ok(conn)) => return Ok(PooledConnection::new(conn)),
388 Ok(Err(e)) => {
389 self.total_count.fetch_sub(1, Ordering::SeqCst);
391 return Err(PoolError::ConnectionFailed(e.to_string()));
392 }
393 Err(_) => {
394 self.total_count.fetch_sub(1, Ordering::SeqCst);
396 return Err(PoolError::Timeout);
397 }
398 }
399 }
400
401 let now = Instant::now();
403 if now >= deadline {
404 return Err(PoolError::Timeout);
405 }
406 let _ = tokio::time::timeout(deadline - now, self.notify.notified()).await;
407 }
408 }
409
410 #[tracing::instrument(skip(self, pooled))]
416 pub async fn release(&self, mut pooled: PooledConnection) {
417 if self.closed.load(Ordering::Acquire) {
419 let _ = pooled.conn.close().await;
420 self.total_count.fetch_sub(1, Ordering::SeqCst);
422 return;
423 }
424
425 if !pooled.conn.is_connected() {
427 let _ = pooled.conn.close().await;
428 self.total_count.fetch_sub(1, Ordering::SeqCst);
429 return;
430 }
431
432 pooled.last_used_at = Instant::now();
434
435 {
436 let mut idle = self.idle.lock().await;
437 idle.push_back(pooled);
438 }
439 self.notify.notify_one();
440 }
441
442 pub async fn status(&self) -> PoolStatus {
444 let idle_count = self.idle.lock().await.len() as u32;
445 let active = self.total_count.load(Ordering::Acquire);
447 PoolStatus {
448 idle: idle_count,
449 active,
450 max: self.config.max_size,
451 min: self.config.min_idle,
452 }
453 }
454
455 #[tracing::instrument(skip(self))]
457 pub async fn reap_idle(&self) {
458 let mut idle = self.idle.lock().await;
459 let mut to_close = Vec::new();
460 let mut remaining = VecDeque::new();
461 while let Some(pooled) = idle.pop_front() {
462 if pooled.is_idle_too_long(self.config.idle_timeout)
463 || pooled.is_expired(self.config.max_lifetime)
464 {
465 to_close.push(pooled);
466 } else {
467 remaining.push_back(pooled);
468 }
469 }
470 *idle = remaining;
471 drop(idle);
472 for mut pooled in to_close {
473 let _ = pooled.conn.close().await;
474 self.total_count.fetch_sub(1, Ordering::SeqCst);
476 }
477 }
478
479 pub async fn close_all(&self) {
483 self.closed.store(true, Ordering::Release);
485 let to_close: Vec<PooledConnection> = {
488 let mut idle = self.idle.lock().await;
489 let mut collected = Vec::with_capacity(idle.len());
490 while let Some(pooled) = idle.pop_front() {
491 collected.push(pooled);
492 }
493 collected
494 };
495 let closed_count: u32 = to_close.len() as u32;
497 for mut pooled in to_close {
498 let _ = pooled.conn.close().await;
499 }
500 self.total_count.fetch_sub(closed_count, Ordering::SeqCst);
503 }
504
505 pub async fn health_check(&self) -> u32 {
520 let mut to_check: Vec<PooledConnection> = {
522 let mut idle = self.idle.lock().await;
523 let mut collected = Vec::with_capacity(idle.len());
524 while let Some(pooled) = idle.pop_front() {
525 collected.push(pooled);
526 }
527 collected
528 };
529
530 let mut removed: u32 = 0;
531 let mut alive: Vec<PooledConnection> = Vec::with_capacity(to_check.len());
532 for mut pooled in to_check.drain(..) {
533 if !pooled.conn.is_connected() {
535 let _ = pooled.conn.close().await;
536 removed += 1;
537 continue;
538 }
539 let ping_timeout = self.config.connection_timeout / 2;
541 match tokio::time::timeout(ping_timeout, pooled.conn.ping()).await {
542 Ok(true) => alive.push(pooled),
543 Ok(false) => {
544 let _ = pooled.conn.close().await;
546 removed += 1;
547 }
548 Err(_) => {
549 let _ = pooled.conn.close().await;
551 removed += 1;
552 }
553 }
554 }
555
556 let alive_count: u32 = alive.len() as u32;
558 {
559 let mut idle = self.idle.lock().await;
560 for pooled in alive {
561 idle.push_back(pooled);
562 }
563 }
564
565 if removed > 0 {
567 self.total_count.fetch_sub(removed, Ordering::SeqCst);
568 }
569
570 if alive_count > 0 {
572 self.notify.notify_one();
573 }
574
575 removed
576 }
577}
578
579#[cfg(test)]
580mod tests {
581 use super::*;
582
583 struct MockConnection {
585 connected: bool,
586 }
587
588 impl MockConnection {
589 fn new() -> Self {
590 Self { connected: true }
591 }
592 }
593
594 impl Connection for MockConnection {
595 fn execute<'a>(
596 &'a mut self,
597 _sql: &'a str,
598 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
599 Box::pin(async move { Ok(1) })
600 }
601
602 fn query<'a>(
603 &'a mut self,
604 _sql: &'a str,
605 ) -> Pin<
606 Box<
607 dyn Future<
608 Output = Result<
609 Vec<std::collections::HashMap<String, crate::value::Value>>,
610 crate::DbError,
611 >,
612 > + Send
613 + 'a,
614 >,
615 > {
616 Box::pin(async move { Ok(vec![]) })
617 }
618
619 fn begin_transaction<'a>(
620 &'a mut self,
621 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
622 Box::pin(async move { Ok(()) })
623 }
624
625 fn commit<'a>(
626 &'a mut self,
627 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
628 Box::pin(async move { Ok(()) })
629 }
630
631 fn rollback<'a>(
632 &'a mut self,
633 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
634 Box::pin(async move { Ok(()) })
635 }
636
637 fn is_connected(&self) -> bool {
638 self.connected
639 }
640
641 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
642 Box::pin(async move { true })
643 }
644
645 fn close<'a>(
646 &'a mut self,
647 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
648 Box::pin(async move {
649 self.connected = false;
650 Ok(())
651 })
652 }
653 }
654
655 struct MockConnectionFactory;
656
657 #[async_trait]
658 impl ConnectionFactory for MockConnectionFactory {
659 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
660 Ok(Box::new(MockConnection::new()))
661 }
662 }
663
664 #[tokio::test]
665 async fn test_pool_config_builder() {
666 let config = PoolConfigBuilder::new()
667 .max_size(50)
668 .min_idle(10)
669 .build()
670 .unwrap();
671
672 assert_eq!(config.max_size, 50);
673 assert_eq!(config.min_idle, 10);
674 }
675
676 #[test]
677 fn test_pool_status_display() {
678 let status = PoolStatus {
679 idle: 5,
680 active: 10,
681 max: 100,
682 min: 5,
683 };
684
685 let display = format!("{:?}", status);
686 assert!(display.contains("idle"));
687 assert!(display.contains("active"));
688 }
689
690 #[test]
691 fn test_default_pool_config() {
692 let config = PoolConfig::default();
693 assert_eq!(config.max_size, 100);
694 assert_eq!(config.min_idle, 0);
695 assert_eq!(config.acquire_timeout.as_secs(), 30);
696 assert_eq!(config.idle_timeout.as_secs(), 600);
697 assert_eq!(config.max_lifetime.as_secs(), 1800);
698 }
699
700 #[tokio::test]
701 async fn test_pool_config_clone() {
702 let config = PoolConfig::default();
703 let cloned = config.clone();
704 assert_eq!(cloned.max_size, config.max_size);
705 assert_eq!(cloned.min_idle, config.min_idle);
706 }
707
708 #[test]
709 fn test_pool_config_builder_default() {
710 let builder = PoolConfigBuilder::new();
711 let config = builder.build().unwrap();
712 assert_eq!(config.max_size, 100);
713 }
714
715 #[test]
716 fn test_pool_config_validate() {
717 let result = PoolConfigBuilder::new().max_size(0).build();
718 assert!(result.is_err());
719
720 let result = PoolConfigBuilder::new().max_size(10).min_idle(20).build();
721 assert!(result.is_err());
722 }
723
724 #[tokio::test]
725 async fn test_pool_acquire_and_release() {
726 let config = PoolConfigBuilder::new()
727 .max_size(5)
728 .min_idle(1)
729 .build()
730 .unwrap();
731 let factory = Arc::new(MockConnectionFactory);
732 let pool = Pool::new(config, factory).unwrap();
733
734 let conn = pool.acquire().await.unwrap();
735 let status = pool.status().await;
736 assert_eq!(status.active, 1);
737 assert_eq!(status.idle, 0);
738
739 pool.release(conn).await;
740 let status = pool.status().await;
741 assert_eq!(status.idle, 1);
742
743 let _conn2 = pool.acquire().await.unwrap();
745 let status = pool.status().await;
746 assert_eq!(status.idle, 0);
747 }
748
749 #[tokio::test]
750 async fn test_pool_status() {
751 let config = PoolConfigBuilder::new()
752 .max_size(10)
753 .min_idle(2)
754 .build()
755 .unwrap();
756 let factory = Arc::new(MockConnectionFactory);
757 let pool = Pool::new(config, factory).unwrap();
758
759 let status = pool.status().await;
760 assert_eq!(status.max, 10);
761 assert_eq!(status.min, 2);
762 assert_eq!(status.active, 0);
763 }
764
765 #[tokio::test]
766 async fn test_pool_close_all() {
767 let config = PoolConfigBuilder::new().max_size(5).build().unwrap();
768 let factory = Arc::new(MockConnectionFactory);
769 let pool = Pool::new(config, factory).unwrap();
770
771 let conn1 = pool.acquire().await.unwrap();
773 let conn2 = pool.acquire().await.unwrap();
774 pool.release(conn1).await;
775 pool.release(conn2).await;
776
777 pool.close_all().await;
778 let status = pool.status().await;
779 assert_eq!(status.idle, 0);
780 assert_eq!(status.active, 0);
781 }
782
783 #[tokio::test]
784 async fn test_pool_reap_idle() {
785 let config = PoolConfigBuilder::new()
786 .max_size(5)
787 .idle_timeout(0) .build()
789 .unwrap();
790 let factory = Arc::new(MockConnectionFactory);
791 let pool = Pool::new(config, factory).unwrap();
792
793 let conn = pool.acquire().await.unwrap();
794 pool.release(conn).await;
795
796 tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
798
799 pool.reap_idle().await;
800 let status = pool.status().await;
801 assert_eq!(status.idle, 0);
802 }
803
804 #[tokio::test]
810 async fn test_h7_acquire_timeout_default_30s() {
811 let config = PoolConfig::default();
812 assert_eq!(
813 config.acquire_timeout,
814 Duration::from_secs(30),
815 "H-7: acquire_timeout 默认应为 30s"
816 );
817 }
818
819 #[tokio::test]
821 async fn test_h7_acquire_timeout_configurable() {
822 let config = PoolConfigBuilder::new()
823 .max_size(1)
824 .acquire_timeout(5) .build()
826 .unwrap();
827 assert_eq!(config.acquire_timeout, Duration::from_secs(5));
828
829 let factory = Arc::new(MockConnectionFactory);
831 let pool = Pool::new(config, factory).unwrap();
832 let _conn1 = pool.acquire().await.unwrap();
833
834 let fast_config = PoolConfigBuilder::new()
836 .max_size(1)
837 .acquire_timeout(0) .build()
839 .unwrap();
840 let fast_pool = Pool::new(fast_config, Arc::new(MockConnectionFactory)).unwrap();
843 let _fast_conn = fast_pool.acquire().await.unwrap(); let result = fast_pool.acquire().await;
845 assert!(
846 matches!(result, Err(PoolError::Timeout)),
847 "H-7: 应返回 Timeout"
848 );
849 }
850
851 #[tokio::test]
854 async fn test_m7_health_check_removes_nothing_when_all_healthy() {
855 let config = PoolConfigBuilder::new().max_size(5).build().unwrap();
857 let factory = Arc::new(MockConnectionFactory);
858 let pool = Pool::new(config, factory).unwrap();
859
860 let conn1 = pool.acquire().await.unwrap();
862 let conn2 = pool.acquire().await.unwrap();
863 let conn3 = pool.acquire().await.unwrap();
864 pool.release(conn1).await;
865 pool.release(conn2).await;
866 pool.release(conn3).await;
867
868 let removed = pool.health_check().await;
869 assert_eq!(removed, 0, "Healthy connections should not be removed");
870
871 let status = pool.status().await;
872 assert_eq!(status.idle, 3);
873 assert_eq!(status.active, 3);
874 }
875
876 #[tokio::test]
877 async fn test_m7_health_check_returns_zero_for_empty_pool() {
878 let config = PoolConfigBuilder::new().max_size(5).build().unwrap();
879 let factory = Arc::new(MockConnectionFactory);
880 let pool = Pool::new(config, factory).unwrap();
881
882 let removed = pool.health_check().await;
883 assert_eq!(removed, 0);
884 }
885
886 struct CountingFactory {
890 count: AtomicU32,
891 }
892
893 impl CountingFactory {
894 fn new() -> Self {
895 Self {
896 count: AtomicU32::new(0),
897 }
898 }
899 fn created_count(&self) -> u32 {
900 self.count.load(Ordering::SeqCst)
901 }
902 }
903
904 #[async_trait]
905 impl ConnectionFactory for CountingFactory {
906 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
907 self.count.fetch_add(1, Ordering::SeqCst);
908 Ok(Box::new(MockConnection::new()))
909 }
910 }
911
912 #[tokio::test]
918 async fn test_production_bug_max_lifetime_never_expires() {
919 let config = PoolConfig {
922 max_size: 5,
923 min_idle: 0,
924 acquire_timeout: Duration::from_secs(30),
925 idle_timeout: Duration::from_secs(600),
926 max_lifetime: Duration::from_millis(100), connection_timeout: Duration::from_secs(10),
928 };
929 let factory = Arc::new(CountingFactory::new());
930 let pool = Pool::new(config, factory.clone()).unwrap();
931
932 let conn = pool.acquire().await.unwrap();
934 assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
935
936 pool.release(conn).await;
938
939 tokio::time::sleep(Duration::from_millis(150)).await;
941
942 let conn2 = pool.acquire().await.unwrap();
944
945 assert_eq!(
948 factory.created_count(),
949 2,
950 "超过 max_lifetime 后应创建新连接(旧连接应被回收)"
951 );
952
953 pool.release(conn2).await;
954 }
955}