1use async_trait::async_trait;
6use crossbeam_queue::ArrayQueue;
7use futures::StreamExt;
8#[cfg(feature = "circuit-breaker")]
12use parking_lot::Mutex as PlMutex;
13#[cfg(feature = "rate-limit")]
14use parking_lot::RwLock as PlRwLock;
15use std::future::Future;
16use std::ops::{Deref, DerefMut};
17use std::pin::Pin;
18use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
19use std::sync::Arc;
20use std::time::{Duration, Instant};
21use tokio::sync::Notify;
22
23#[cfg(feature = "circuit-breaker")]
27use crate::circuit_breaker::{CircuitBreaker, CircuitState, DefaultCircuitBreaker};
28use crate::error::PoolError;
29#[cfg(feature = "rate-limit")]
30use crate::rate_limiter::RateLimiter;
31
32pub type QueryRows = Vec<std::collections::HashMap<String, crate::value::Value>>;
34
35pub type QueryStreamItem =
37 Result<std::collections::HashMap<String, crate::value::Value>, crate::DbError>;
38
39pub trait Connection: Send + Sync {
46 fn execute<'a>(
47 &'a mut self,
48 sql: &'a str,
49 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>>;
50 fn query<'a>(
51 &'a mut self,
52 sql: &'a str,
53 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>>;
54 fn begin_transaction<'a>(
55 &'a mut self,
56 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
57 fn commit<'a>(
58 &'a mut self,
59 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
60 fn rollback<'a>(
61 &'a mut self,
62 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
63 fn is_connected(&self) -> bool;
64 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>>;
65 fn close<'a>(
66 &'a mut self,
67 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
68
69 fn execute_with_params<'a>(
75 &'a mut self,
76 sql: &'a str,
77 params: &'a [crate::value::Value],
78 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
79 let _ = (sql, params);
80 Box::pin(async move {
81 Err(crate::DbError::Internal(
82 "execute_with_params not implemented for this adapter".to_string(),
83 ))
84 })
85 }
86
87 fn query_with_params<'a>(
93 &'a mut self,
94 sql: &'a str,
95 params: &'a [crate::value::Value],
96 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
97 let _ = (sql, params);
98 Box::pin(async move {
99 Err(crate::DbError::Internal(
100 "query_with_params not implemented for this adapter".to_string(),
101 ))
102 })
103 }
104
105 fn query_values<'a>(
110 &'a mut self,
111 sql: &'a str,
112 ) -> Pin<Box<dyn Future<Output = Result<crate::value::QueryValues, crate::DbError>> + Send + 'a>>
113 {
114 let _ = sql;
115 Box::pin(async move {
116 Err(crate::DbError::Internal(
117 "query_values not implemented for this adapter".to_string(),
118 ))
119 })
120 }
121
122 fn query_values_with_params<'a>(
126 &'a mut self,
127 sql: &'a str,
128 params: &'a [crate::value::Value],
129 ) -> Pin<Box<dyn Future<Output = Result<crate::value::QueryValues, crate::DbError>> + Send + 'a>>
130 {
131 let _ = (sql, params);
132 Box::pin(async move {
133 Err(crate::DbError::Internal(
134 "query_values_with_params not implemented for this adapter".to_string(),
135 ))
136 })
137 }
138
139 fn query_stream<'a>(
151 &'a mut self,
152 sql: &'a str,
153 ) -> Pin<Box<dyn futures::Stream<Item = QueryStreamItem> + Send + 'a>> {
154 let sql_owned = sql.to_string();
156 let stream = futures::stream::once(async move { self.query(&sql_owned).await })
158 .map(|result| {
160 let items: Vec<QueryStreamItem> = match result {
161 Ok(rows) => rows.into_iter().map(Ok).collect(),
162 Err(e) => vec![Err(e)],
163 };
164 futures::stream::iter(items)
165 })
166 .flatten();
167 Box::pin(stream)
168 }
169
170 fn query_stream_cursor<'a>(
181 &'a mut self,
182 sql: &'a str,
183 _batch_size: usize,
184 ) -> Pin<Box<dyn futures::Stream<Item = QueryStreamItem> + Send + 'a>> {
185 self.query_stream(sql)
186 }
187
188 fn execute_batch<'a>(
193 &'a mut self,
194 sqls: &'a [String],
195 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
196 Box::pin(async move {
197 let mut total = 0u64;
198 for sql in sqls {
199 total += self.execute(sql).await?;
200 }
201 Ok(total)
202 })
203 }
204
205 fn execute_batch_params<'a>(
210 &'a mut self,
211 sql: &'a str,
212 params_batch: &'a [Vec<crate::value::Value>],
213 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
214 Box::pin(async move {
215 let mut total = 0u64;
216 for params in params_batch {
217 total += self.execute_with_params(sql, params).await?;
218 }
219 Ok(total)
220 })
221 }
222}
223
224pub struct PooledConnection {
232 conn: Box<dyn Connection>,
233 created_at: Instant,
234 last_used_at: Instant,
235 pool: Option<Pool>,
236}
237
238impl PooledConnection {
239 fn new(conn: Box<dyn Connection>, pool: Pool) -> Self {
240 let now = Instant::now();
241 Self {
242 conn,
243 created_at: now,
244 last_used_at: now,
245 pool: Some(pool),
246 }
247 }
248
249 fn is_expired(&self, max_lifetime: Duration) -> bool {
250 self.created_at.elapsed() >= max_lifetime
251 }
252
253 fn is_idle_too_long(&self, idle_timeout: Duration) -> bool {
254 self.last_used_at.elapsed() >= idle_timeout
255 }
256
257 pub fn created_at(&self) -> Instant {
259 self.created_at
260 }
261
262 pub fn into_inner(mut self) -> Box<dyn Connection> {
267 self.pool = None; std::mem::replace(&mut self.conn, Box::new(ClosedConnection))
271 }
272}
273
274impl Drop for PooledConnection {
286 fn drop(&mut self) {
287 if let Some(pool) = self.pool.take() {
288 let conn = std::mem::replace(&mut self.conn, Box::new(ClosedConnection));
290 let pooled = PooledConnection {
291 conn,
292 created_at: self.created_at,
293 last_used_at: self.last_used_at,
294 pool: None,
295 };
296 if let Ok(handle) = tokio::runtime::Handle::try_current() {
298 handle.spawn(async move {
299 pool.release(pooled).await;
300 });
301 } else {
302 drop(pooled);
306 pool.total_count.fetch_sub(1, Ordering::SeqCst);
307 }
308 }
309 }
310}
311
312struct ClosedConnection;
316
317impl Connection for ClosedConnection {
318 fn execute<'a>(
319 &'a mut self,
320 _sql: &'a str,
321 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
322 Box::pin(async {
323 Err(crate::DbError::ConnectionError(
324 "connection already returned to pool".to_string(),
325 ))
326 })
327 }
328
329 fn query<'a>(
330 &'a mut self,
331 _sql: &'a str,
332 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
333 Box::pin(async {
334 Err(crate::DbError::ConnectionError(
335 "connection already returned to pool".to_string(),
336 ))
337 })
338 }
339
340 fn begin_transaction<'a>(
341 &'a mut self,
342 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
343 Box::pin(async {
344 Err(crate::DbError::ConnectionError(
345 "connection already returned to pool".to_string(),
346 ))
347 })
348 }
349
350 fn commit<'a>(
351 &'a mut self,
352 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
353 Box::pin(async { Ok(()) })
354 }
355
356 fn rollback<'a>(
357 &'a mut self,
358 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
359 Box::pin(async { Ok(()) })
360 }
361
362 fn is_connected(&self) -> bool {
363 false
364 }
365
366 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
367 Box::pin(async { false })
368 }
369
370 fn close<'a>(
371 &'a mut self,
372 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
373 Box::pin(async { Ok(()) })
374 }
375}
376
377impl Deref for PooledConnection {
378 type Target = dyn Connection;
379
380 fn deref(&self) -> &Self::Target {
381 self.conn.as_ref()
382 }
383}
384
385impl DerefMut for PooledConnection {
386 fn deref_mut(&mut self) -> &mut Self::Target {
387 self.conn.as_mut()
388 }
389}
390
391#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
393pub enum TlsVersion {
394 #[default]
395 Tls12,
396 Tls13,
397}
398
399#[derive(Debug, Clone, Default)]
401pub struct TlsConfig {
402 pub enabled: bool,
404 pub ca_cert_path: Option<String>,
406 pub client_cert_path: Option<String>,
408 pub client_key_path: Option<String>,
410 pub min_version: TlsVersion,
412}
413
414#[derive(Debug, Clone)]
416pub enum PoolEvent {
417 ConnectionCreated,
419 ConnectionClosed,
421 ConnectionAcquired,
423 ConnectionReleased,
425 AcquireTimeout,
427}
428
429pub type PoolEventCallback = Arc<dyn Fn(PoolEvent) + Send + Sync>;
431
432pub struct PoolConfig {
433 pub max_size: u32,
434 pub min_idle: u32,
435 pub acquire_timeout: Duration,
436 pub idle_timeout: Duration,
437 pub max_lifetime: Duration,
438 pub connection_timeout: Duration,
439 pub tls: Option<TlsConfig>,
441 pub query_timeout: Option<Duration>,
443 pub max_rows: Option<usize>,
445 pub memory_limit: Option<usize>,
447 pub on_event: Option<PoolEventCallback>,
449 pub test_before_acquire: bool,
457}
458
459impl Default for PoolConfig {
460 fn default() -> Self {
461 Self {
462 max_size: 100,
463 min_idle: 0,
464 acquire_timeout: Duration::from_secs(30),
465 idle_timeout: Duration::from_secs(600),
466 max_lifetime: Duration::from_secs(1800),
467 connection_timeout: Duration::from_secs(10),
468 tls: None,
469 query_timeout: Some(Duration::from_secs(30)),
470 max_rows: None,
471 memory_limit: None,
472 on_event: None,
473 test_before_acquire: false,
474 }
475 }
476}
477
478impl Clone for PoolConfig {
479 fn clone(&self) -> Self {
480 Self {
481 max_size: self.max_size,
482 min_idle: self.min_idle,
483 acquire_timeout: self.acquire_timeout,
484 idle_timeout: self.idle_timeout,
485 max_lifetime: self.max_lifetime,
486 connection_timeout: self.connection_timeout,
487 tls: self.tls.clone(),
488 query_timeout: self.query_timeout,
489 max_rows: self.max_rows,
490 memory_limit: self.memory_limit,
491 on_event: self.on_event.clone(),
492 test_before_acquire: self.test_before_acquire,
493 }
494 }
495}
496
497impl PoolConfig {
498 pub fn validate(&self) -> Result<(), PoolError> {
500 if self.max_size == 0 {
501 return Err(PoolError::InvalidConfig("max_size cannot be 0".to_string()));
502 }
503 if self.min_idle > self.max_size {
504 return Err(PoolError::InvalidConfig(
505 "min_idle cannot exceed max_size".to_string(),
506 ));
507 }
508 const MAX_DURATION_SECS: u64 = u32::MAX as u64; for (name, dur) in [
514 ("acquire_timeout", self.acquire_timeout),
515 ("idle_timeout", self.idle_timeout),
516 ("max_lifetime", self.max_lifetime),
517 ("connection_timeout", self.connection_timeout),
518 ] {
519 if dur.as_secs() > MAX_DURATION_SECS {
520 return Err(PoolError::InvalidConfig(format!(
521 "{name} ({:?}) exceeds maximum allowed duration ({} seconds)",
522 dur, MAX_DURATION_SECS
523 )));
524 }
525 }
526 Ok(())
527 }
528}
529
530pub struct PoolStatus {
531 pub idle: u32,
532 pub active: u32,
533 pub max: u32,
534 pub min: u32,
535 pub waiters: u32,
537}
538
539impl std::fmt::Debug for PoolStatus {
540 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
541 f.debug_struct("PoolStatus")
542 .field("idle", &self.idle)
543 .field("active", &self.active)
544 .field("max", &self.max)
545 .field("min", &self.min)
546 .field("waiters", &self.waiters)
547 .finish()
548 }
549}
550
551pub struct PoolConfigBuilder {
552 config: PoolConfig,
553}
554
555impl PoolConfigBuilder {
556 pub fn new() -> Self {
557 Self {
558 config: PoolConfig::default(),
559 }
560 }
561
562 pub fn max_size(mut self, size: u32) -> Self {
563 self.config.max_size = size;
564 self
565 }
566
567 pub fn min_idle(mut self, count: u32) -> Self {
568 self.config.min_idle = count;
569 self
570 }
571
572 pub fn acquire_timeout(mut self, timeout_secs: u64) -> Self {
573 self.config.acquire_timeout = Duration::from_secs(timeout_secs);
574 self
575 }
576
577 pub fn idle_timeout(mut self, timeout_secs: u64) -> Self {
578 self.config.idle_timeout = Duration::from_secs(timeout_secs);
579 self
580 }
581
582 pub fn max_lifetime(mut self, lifetime_secs: u64) -> Self {
583 self.config.max_lifetime = Duration::from_secs(lifetime_secs);
584 self
585 }
586
587 pub fn tls(mut self, tls: TlsConfig) -> Self {
589 self.config.tls = Some(tls);
590 self
591 }
592
593 pub fn query_timeout(mut self, timeout: Duration) -> Self {
595 self.config.query_timeout = Some(timeout);
596 self
597 }
598
599 pub fn max_rows(mut self, max_rows: usize) -> Self {
601 self.config.max_rows = Some(max_rows);
602 self
603 }
604
605 pub fn memory_limit(mut self, memory_limit: usize) -> Self {
607 self.config.memory_limit = Some(memory_limit);
608 self
609 }
610
611 pub fn on_event(mut self, callback: PoolEventCallback) -> Self {
613 self.config.on_event = Some(callback);
614 self
615 }
616
617 pub fn test_before_acquire(mut self, enabled: bool) -> Self {
622 self.config.test_before_acquire = enabled;
623 self
624 }
625
626 pub fn build(self) -> Result<PoolConfig, PoolError> {
627 self.config.validate()?;
628 Ok(self.config)
629 }
630}
631
632impl Default for PoolConfigBuilder {
633 fn default() -> Self {
634 Self::new()
635 }
636}
637
638#[async_trait]
640pub trait ConnectionFactory: Send + Sync {
641 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError>;
642}
643
644pub struct Pool {
650 config: PoolConfig,
651 factory: Arc<dyn ConnectionFactory>,
652 idle: Arc<ArrayQueue<PooledConnection>>,
658 total_count: Arc<AtomicU32>,
668 closed: Arc<AtomicBool>,
670 notify: Arc<Notify>,
671 waiters_count: Arc<AtomicU32>,
673 dynamic_max_size: Arc<AtomicU32>,
675 #[cfg(feature = "circuit-breaker")]
681 circuit_breaker: Arc<PlMutex<DefaultCircuitBreaker>>,
682 #[cfg(feature = "rate-limit")]
691 rate_limiter: Arc<PlRwLock<Option<Arc<dyn RateLimiter>>>>,
692 #[cfg(feature = "rate-limit")]
694 rate_limit_key: String,
695}
696
697impl Clone for Pool {
701 fn clone(&self) -> Self {
702 Self {
703 config: self.config.clone(),
704 factory: self.factory.clone(),
705 idle: self.idle.clone(),
706 total_count: self.total_count.clone(),
707 closed: self.closed.clone(),
708 notify: Arc::clone(&self.notify),
709 waiters_count: self.waiters_count.clone(),
710 dynamic_max_size: self.dynamic_max_size.clone(),
711 #[cfg(feature = "circuit-breaker")]
712 circuit_breaker: Arc::clone(&self.circuit_breaker),
713 #[cfg(feature = "rate-limit")]
714 rate_limiter: Arc::clone(&self.rate_limiter),
715 #[cfg(feature = "rate-limit")]
716 rate_limit_key: self.rate_limit_key.clone(),
717 }
718 }
719}
720
721impl Pool {
722 pub fn new(config: PoolConfig, factory: Arc<dyn ConnectionFactory>) -> Result<Self, PoolError> {
746 config.validate()?;
747 let max_size = config.max_size as usize;
750 let dynamic_max = config.max_size;
751 Ok(Self {
752 config,
753 factory,
754 idle: Arc::new(ArrayQueue::new(max_size)),
755 total_count: Arc::new(AtomicU32::new(0)),
756 closed: Arc::new(AtomicBool::new(false)),
757 notify: Arc::new(Notify::new()),
758 waiters_count: Arc::new(AtomicU32::new(0)),
759 dynamic_max_size: Arc::new(AtomicU32::new(dynamic_max)),
760 #[cfg(feature = "circuit-breaker")]
763 circuit_breaker: Arc::new(PlMutex::new(DefaultCircuitBreaker::new(
764 5,
765 std::time::Duration::from_secs(30),
766 ))),
767 #[cfg(feature = "rate-limit")]
770 rate_limiter: Arc::new(PlRwLock::new(None)),
771 #[cfg(feature = "rate-limit")]
772 rate_limit_key: "pool".to_string(),
773 })
774 }
775
776 pub fn config(&self) -> &PoolConfig {
778 &self.config
779 }
780
781 #[cfg(feature = "circuit-breaker")]
795 pub fn configure_circuit_breaker(
796 &self,
797 failure_threshold: usize,
798 reset_timeout: std::time::Duration,
799 ) {
800 let new_cb = DefaultCircuitBreaker::new(failure_threshold, reset_timeout);
801 let mut guard = self.circuit_breaker.lock();
803 *guard = new_cb;
804 }
805
806 #[cfg(feature = "circuit-breaker")]
811 pub fn reset_circuit_breaker(&self) -> bool {
812 let mut guard = self.circuit_breaker.lock();
814 guard.reset()
815 }
816
817 #[cfg(feature = "circuit-breaker")]
819 pub fn circuit_state(&self) -> CircuitState {
820 let guard = self.circuit_breaker.lock();
822 guard.state()
823 }
824
825 #[cfg(feature = "rate-limit")]
834 pub fn set_rate_limiter(&self, limiter: Option<Arc<dyn RateLimiter>>) {
835 let mut guard = self.rate_limiter.write();
837 *guard = limiter;
838 }
839
840 #[cfg(feature = "rate-limit")]
842 pub fn with_rate_limit_key(mut self, key: impl Into<String>) -> Self {
843 self.rate_limit_key = key.into();
844 self
845 }
846
847 fn emit_event(&self, event: PoolEvent) {
849 if let Some(ref callback) = self.config.on_event {
850 callback(event);
851 }
852 }
853
854 #[tracing::instrument(skip(self), fields(max_size = self.config.max_size, acquire_timeout = ?self.config.acquire_timeout))]
874 pub async fn acquire(&self) -> Result<PooledConnection, PoolError> {
875 if self.closed.load(Ordering::Acquire) {
877 return Err(PoolError::Closed);
878 }
879
880 #[cfg(feature = "circuit-breaker")]
884 {
885 let mut guard = self.circuit_breaker.lock();
886 if !guard.can_execute() {
887 return Err(PoolError::CircuitOpen);
888 }
889 }
890
891 #[cfg(feature = "rate-limit")]
895 {
896 let guard = self.rate_limiter.read();
897 if let Some(ref limiter) = *guard {
898 match limiter.try_acquire(&self.rate_limit_key) {
899 Ok(result) if !result.allowed => {
900 return Err(PoolError::RateLimited {
901 remaining: result.remaining,
902 reset_at: result.reset_at,
903 });
904 }
905 Ok(_) => {} Err(_) => {
907 }
909 }
910 }
911 }
912
913 let deadline = Instant::now() + self.config.acquire_timeout;
914 let mut backoff = Duration::from_millis(1);
916 const MAX_BACKOFF: Duration = Duration::from_millis(100);
918
919 loop {
920 let mut to_close: Vec<PooledConnection> = Vec::new();
926 let acquired: Option<PooledConnection> = {
927 let mut found: Option<PooledConnection> = None;
928 while let Some(pooled) = self.idle.pop() {
929 if pooled.is_expired(self.config.max_lifetime) {
931 to_close.push(pooled);
932 continue;
933 }
934 if pooled.is_idle_too_long(self.config.idle_timeout) {
936 to_close.push(pooled);
937 continue;
938 }
939 if !pooled.conn.is_connected() {
942 to_close.push(pooled);
943 continue;
944 }
945 found = Some(pooled);
946 break;
947 }
948 found
949 };
950
951 for mut pooled in to_close {
953 let _ = pooled.conn.close().await;
954 self.total_count.fetch_sub(1, Ordering::SeqCst);
956 }
957
958 if let Some(mut pooled) = acquired {
959 if self.config.test_before_acquire {
961 let ping_timeout = self.config.connection_timeout / 2;
962 let alive = match tokio::time::timeout(ping_timeout, pooled.conn.ping()).await {
963 Ok(true) => true,
964 Ok(false) => false,
965 Err(_) => false, };
967 if !alive {
968 let _ = pooled.conn.close().await;
970 self.total_count.fetch_sub(1, Ordering::SeqCst);
971 continue;
972 }
973 }
974 pooled.pool = Some(self.clone());
977 return Ok(pooled);
978 }
979
980 let current_max = self.dynamic_max_size.load(Ordering::Acquire);
985 let created = loop {
986 let current = self.total_count.load(Ordering::Acquire);
987 if current >= current_max {
988 break None; }
990 match self.total_count.compare_exchange(
991 current,
992 current + 1,
993 Ordering::SeqCst,
994 Ordering::Acquire,
995 ) {
996 Ok(_) => break Some(()), Err(_) => continue, }
999 };
1000
1001 if created.is_some() {
1002 match tokio::time::timeout(self.config.connection_timeout, self.factory.create())
1003 .await
1004 {
1005 Ok(Ok(conn)) => {
1006 #[cfg(feature = "circuit-breaker")]
1009 {
1010 self.circuit_breaker.lock().record_success();
1011 }
1012 self.emit_event(PoolEvent::ConnectionCreated);
1013 self.emit_event(PoolEvent::ConnectionAcquired);
1014 return Ok(PooledConnection::new(conn, self.clone()));
1015 }
1016 Ok(Err(e)) => {
1017 self.total_count.fetch_sub(1, Ordering::SeqCst);
1019 #[cfg(feature = "circuit-breaker")]
1022 {
1023 self.circuit_breaker.lock().record_failure();
1024 }
1025 return Err(PoolError::ConnectionFailed(e.to_string()));
1026 }
1027 Err(_) => {
1028 self.total_count.fetch_sub(1, Ordering::SeqCst);
1030 #[cfg(feature = "circuit-breaker")]
1033 {
1034 self.circuit_breaker.lock().record_failure();
1035 }
1036 return Err(PoolError::Timeout);
1037 }
1038 }
1039 }
1040
1041 let now = Instant::now();
1043 if now >= deadline {
1044 self.emit_event(PoolEvent::AcquireTimeout);
1045 return Err(PoolError::Timeout);
1046 }
1047 self.waiters_count.fetch_add(1, Ordering::SeqCst);
1049 let wait = std::cmp::min(backoff, deadline - now);
1050 match tokio::time::timeout(wait, self.notify.notified()).await {
1051 Ok(()) => {
1052 backoff = Duration::from_millis(1);
1054 }
1055 Err(_) => {
1056 backoff = std::cmp::min(backoff * 2, MAX_BACKOFF);
1058 }
1059 }
1060 self.waiters_count.fetch_sub(1, Ordering::SeqCst);
1062 }
1063 }
1064
1065 #[tracing::instrument(skip(self, pooled))]
1073 pub async fn release(&self, mut pooled: PooledConnection) {
1074 pooled.pool = None;
1076
1077 if self.closed.load(Ordering::Acquire) {
1079 let _ = pooled.conn.close().await;
1080 self.total_count.fetch_sub(1, Ordering::SeqCst);
1082 self.emit_event(PoolEvent::ConnectionClosed);
1083 return;
1084 }
1085
1086 if !pooled.conn.is_connected() {
1088 let _ = pooled.conn.close().await;
1089 self.total_count.fetch_sub(1, Ordering::SeqCst);
1090 self.emit_event(PoolEvent::ConnectionClosed);
1091 return;
1092 }
1093
1094 pooled.last_used_at = Instant::now();
1096
1097 if let Err(mut rejected) = self.idle.push(pooled) {
1103 let _ = rejected.conn.close().await;
1105 self.total_count.fetch_sub(1, Ordering::SeqCst);
1106 self.emit_event(PoolEvent::ConnectionClosed);
1107 } else {
1108 self.emit_event(PoolEvent::ConnectionReleased);
1109 }
1110 self.notify.notify_one();
1111 }
1112
1113 pub async fn status(&self) -> PoolStatus {
1118 let idle_count = self.idle.len() as u32;
1119 let active = self.total_count.load(Ordering::Acquire);
1121 let waiters = self.waiters_count.load(Ordering::Acquire);
1122 PoolStatus {
1123 idle: idle_count,
1124 active,
1125 max: self.dynamic_max_size.load(Ordering::Acquire),
1126 min: self.config.min_idle,
1127 waiters,
1128 }
1129 }
1130
1131 #[tracing::instrument(skip(self))]
1133 pub async fn reap_idle(&self) {
1134 let mut all: Vec<PooledConnection> = Vec::new();
1138 while let Some(pooled) = self.idle.pop() {
1139 all.push(pooled);
1140 }
1141
1142 let mut to_close = Vec::new();
1144 for pooled in all {
1145 if pooled.is_idle_too_long(self.config.idle_timeout)
1146 || pooled.is_expired(self.config.max_lifetime)
1147 {
1148 to_close.push(pooled);
1149 } else {
1150 if let Err(mut rejected) = self.idle.push(pooled) {
1152 let _ = rejected.conn.close().await;
1153 self.total_count.fetch_sub(1, Ordering::SeqCst);
1154 }
1155 }
1156 }
1157
1158 for mut pooled in to_close {
1160 let _ = pooled.conn.close().await;
1161 self.total_count.fetch_sub(1, Ordering::SeqCst);
1163 }
1164 }
1165
1166 pub async fn close_all(&self) {
1170 self.closed.store(true, Ordering::Release);
1172 let mut to_close: Vec<PooledConnection> = Vec::new();
1175 while let Some(pooled) = self.idle.pop() {
1176 to_close.push(pooled);
1177 }
1178 let closed_count: u32 = to_close.len() as u32;
1180 for mut pooled in to_close {
1181 let _ = pooled.conn.close().await;
1182 }
1183 self.total_count.fetch_sub(closed_count, Ordering::SeqCst);
1186 }
1187
1188 pub async fn health_check(&self) -> u32 {
1204 let mut to_check: Vec<PooledConnection> = Vec::new();
1206 while let Some(pooled) = self.idle.pop() {
1207 to_check.push(pooled);
1208 }
1209
1210 let mut removed: u32 = 0;
1211 let mut alive: Vec<PooledConnection> = Vec::with_capacity(to_check.len());
1212 for mut pooled in to_check.drain(..) {
1213 if !pooled.conn.is_connected() {
1215 let _ = pooled.conn.close().await;
1216 removed += 1;
1217 continue;
1218 }
1219 let ping_timeout = self.config.connection_timeout / 2;
1221 match tokio::time::timeout(ping_timeout, pooled.conn.ping()).await {
1222 Ok(true) => alive.push(pooled),
1223 Ok(false) => {
1224 let _ = pooled.conn.close().await;
1226 removed += 1;
1227 }
1228 Err(_) => {
1229 let _ = pooled.conn.close().await;
1231 removed += 1;
1232 }
1233 }
1234 }
1235
1236 let alive_count: u32 = alive.len() as u32;
1238 for pooled in alive {
1239 if let Err(mut rejected) = self.idle.push(pooled) {
1241 let _ = rejected.conn.close().await;
1242 removed += 1;
1243 }
1244 }
1245
1246 if removed > 0 {
1248 self.total_count.fetch_sub(removed, Ordering::SeqCst);
1249 }
1250
1251 if alive_count > 0 {
1253 self.notify.notify_one();
1254 }
1255
1256 removed
1257 }
1258
1259 pub async fn shutdown(&self) {
1266 self.closed.store(true, Ordering::SeqCst);
1268 self.notify.notify_waiters();
1270 self.close_all().await;
1272 let deadline = Instant::now() + Duration::from_secs(30);
1274 while self.total_count.load(Ordering::SeqCst) > 0 {
1275 if Instant::now() >= deadline {
1276 break;
1277 }
1278 tokio::time::sleep(Duration::from_millis(100)).await;
1279 }
1280 }
1281
1282 pub fn resize(&self, new_max: usize) {
1290 self.set_max_size(new_max as u32);
1291 }
1292
1293 pub fn set_max_size(&self, new_max: u32) {
1295 self.dynamic_max_size.store(new_max, Ordering::SeqCst);
1296 }
1297
1298 pub fn max_size(&self) -> u32 {
1300 self.dynamic_max_size.load(Ordering::Acquire)
1301 }
1302
1303 pub async fn warmup(&self, min_idle: usize) -> Result<(), PoolError> {
1307 for _ in 0..min_idle {
1308 let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1309 let current = self.total_count.load(Ordering::Acquire);
1310 if current >= current_max {
1311 break;
1312 }
1313 match self.total_count.compare_exchange(
1315 current,
1316 current + 1,
1317 Ordering::SeqCst,
1318 Ordering::Acquire,
1319 ) {
1320 Ok(_) => {}
1321 Err(_) => continue, }
1323 match self.factory.create().await {
1324 Ok(conn) => {
1325 let now = Instant::now();
1326 let pooled = PooledConnection {
1327 conn,
1328 created_at: now,
1329 last_used_at: now,
1330 pool: None,
1331 };
1332 if let Err(mut rejected) = self.idle.push(pooled) {
1333 let _ = rejected.conn.close().await;
1335 self.total_count.fetch_sub(1, Ordering::SeqCst);
1336 }
1337 self.emit_event(PoolEvent::ConnectionCreated);
1338 }
1339 Err(_) => {
1340 self.total_count.fetch_sub(1, Ordering::SeqCst);
1342 break;
1343 }
1344 }
1345 }
1346 Ok(())
1347 }
1348
1349 pub async fn query_with_timeout(&self, sql: &str) -> Result<QueryRows, crate::DbError> {
1354 let timeout = self.config.query_timeout.unwrap_or(Duration::from_secs(30));
1355 let mut conn = self.acquire().await.map_err(crate::DbError::PoolError)?;
1356 tokio::time::timeout(timeout, conn.query(sql))
1357 .await
1358 .map_err(|_| crate::DbError::QueryError(format!("Query timeout after {:?}", timeout)))?
1359 }
1360}
1361
1362#[cfg(test)]
1363mod tests {
1364 use super::*;
1365
1366 struct MockConnection {
1368 connected: bool,
1369 }
1370
1371 impl MockConnection {
1372 fn new() -> Self {
1373 Self { connected: true }
1374 }
1375 }
1376
1377 impl Connection for MockConnection {
1378 fn execute<'a>(
1379 &'a mut self,
1380 _sql: &'a str,
1381 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
1382 Box::pin(async move { Ok(1) })
1383 }
1384
1385 fn query<'a>(
1386 &'a mut self,
1387 _sql: &'a str,
1388 ) -> Pin<
1389 Box<
1390 dyn Future<
1391 Output = Result<
1392 Vec<std::collections::HashMap<String, crate::value::Value>>,
1393 crate::DbError,
1394 >,
1395 > + Send
1396 + 'a,
1397 >,
1398 > {
1399 Box::pin(async move { Ok(vec![]) })
1400 }
1401
1402 fn begin_transaction<'a>(
1403 &'a mut self,
1404 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1405 Box::pin(async move { Ok(()) })
1406 }
1407
1408 fn commit<'a>(
1409 &'a mut self,
1410 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1411 Box::pin(async move { Ok(()) })
1412 }
1413
1414 fn rollback<'a>(
1415 &'a mut self,
1416 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1417 Box::pin(async move { Ok(()) })
1418 }
1419
1420 fn is_connected(&self) -> bool {
1421 self.connected
1422 }
1423
1424 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
1425 Box::pin(async move { true })
1426 }
1427
1428 fn close<'a>(
1429 &'a mut self,
1430 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1431 Box::pin(async move {
1432 self.connected = false;
1433 Ok(())
1434 })
1435 }
1436 }
1437
1438 struct MockConnectionFactory;
1439
1440 #[async_trait]
1441 impl ConnectionFactory for MockConnectionFactory {
1442 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
1443 Ok(Box::new(MockConnection::new()))
1444 }
1445 }
1446
1447 #[tokio::test]
1448 async fn test_pool_config_builder() -> Result<(), Box<dyn std::error::Error>> {
1449 let config = PoolConfigBuilder::new().max_size(50).min_idle(10).build()?;
1450
1451 assert_eq!(config.max_size, 50);
1452 assert_eq!(config.min_idle, 10);
1453 Ok(())
1454 }
1455
1456 #[test]
1457 fn test_pool_status_display() {
1458 let status = PoolStatus {
1459 idle: 5,
1460 active: 10,
1461 max: 100,
1462 min: 5,
1463 waiters: 0,
1464 };
1465
1466 let display = format!("{:?}", status);
1467 assert!(display.contains("idle"));
1468 assert!(display.contains("active"));
1469 }
1470
1471 #[test]
1472 fn test_default_pool_config() {
1473 let config = PoolConfig::default();
1474 assert_eq!(config.max_size, 100);
1475 assert_eq!(config.min_idle, 0);
1476 assert_eq!(config.acquire_timeout.as_secs(), 30);
1477 assert_eq!(config.idle_timeout.as_secs(), 600);
1478 assert_eq!(config.max_lifetime.as_secs(), 1800);
1479 }
1480
1481 #[tokio::test]
1482 async fn test_pool_config_clone() {
1483 let config = PoolConfig::default();
1484 let cloned = config.clone();
1485 assert_eq!(cloned.max_size, config.max_size);
1486 assert_eq!(cloned.min_idle, config.min_idle);
1487 }
1488
1489 #[test]
1490 fn test_pool_config_builder_default() -> Result<(), Box<dyn std::error::Error>> {
1491 let builder = PoolConfigBuilder::new();
1492 let config = builder.build()?;
1493 assert_eq!(config.max_size, 100);
1494 Ok(())
1495 }
1496
1497 #[test]
1498 fn test_pool_config_validate() {
1499 let result = PoolConfigBuilder::new().max_size(0).build();
1500 assert!(result.is_err());
1501
1502 let result = PoolConfigBuilder::new().max_size(10).min_idle(20).build();
1503 assert!(result.is_err());
1504 }
1505
1506 #[test]
1507 fn test_pool_config_validate_duration_upper_bound() {
1508 use std::time::Duration;
1509
1510 let config = PoolConfig {
1512 max_size: 10,
1513 min_idle: 1,
1514 acquire_timeout: Duration::from_secs(u64::MAX),
1515 idle_timeout: Duration::from_secs(1),
1516 max_lifetime: Duration::from_secs(1),
1517 connection_timeout: Duration::from_secs(5),
1518 tls: None,
1519 query_timeout: None,
1520 max_rows: None,
1521 memory_limit: None,
1522 on_event: None,
1523 test_before_acquire: false,
1524 };
1525 assert!(config.validate().is_err());
1526
1527 let config = PoolConfig {
1529 max_size: 10,
1530 min_idle: 1,
1531 acquire_timeout: Duration::from_secs(u32::MAX as u64),
1532 idle_timeout: Duration::from_secs(1),
1533 max_lifetime: Duration::from_secs(1),
1534 connection_timeout: Duration::from_secs(5),
1535 tls: None,
1536 query_timeout: None,
1537 max_rows: None,
1538 memory_limit: None,
1539 on_event: None,
1540 test_before_acquire: false,
1541 };
1542 assert!(config.validate().is_ok());
1543
1544 let config = PoolConfig {
1546 max_size: 10,
1547 min_idle: 1,
1548 acquire_timeout: Duration::from_secs(u32::MAX as u64 + 1),
1549 idle_timeout: Duration::from_secs(1),
1550 max_lifetime: Duration::from_secs(1),
1551 connection_timeout: Duration::from_secs(5),
1552 tls: None,
1553 query_timeout: None,
1554 max_rows: None,
1555 memory_limit: None,
1556 on_event: None,
1557 test_before_acquire: false,
1558 };
1559 assert!(config.validate().is_err());
1560 }
1561
1562 #[test]
1563 fn test_pool_config_test_before_acquire_default() {
1564 let config = PoolConfig::default();
1566 assert!(!config.test_before_acquire);
1567 }
1568
1569 #[test]
1570 fn test_pool_config_builder_test_before_acquire() {
1571 let config = PoolConfigBuilder::new()
1573 .test_before_acquire(true)
1574 .build()
1575 .unwrap();
1576 assert!(config.test_before_acquire);
1577 }
1578
1579 #[tokio::test]
1580 async fn test_pool_acquire_and_release() -> Result<(), Box<dyn std::error::Error>> {
1581 let config = PoolConfigBuilder::new().max_size(5).min_idle(1).build()?;
1582 let factory = Arc::new(MockConnectionFactory);
1583 let pool = Pool::new(config, factory)?;
1584
1585 let conn = pool.acquire().await?;
1586 let status = pool.status().await;
1587 assert_eq!(status.active, 1);
1588 assert_eq!(status.idle, 0);
1589
1590 pool.release(conn).await;
1591 let status = pool.status().await;
1592 assert_eq!(status.idle, 1);
1593
1594 let _conn2 = pool.acquire().await?;
1596 let status = pool.status().await;
1597 assert_eq!(status.idle, 0);
1598 Ok(())
1599 }
1600
1601 #[tokio::test]
1602 async fn test_pool_status() -> Result<(), Box<dyn std::error::Error>> {
1603 let config = PoolConfigBuilder::new().max_size(10).min_idle(2).build()?;
1604 let factory = Arc::new(MockConnectionFactory);
1605 let pool = Pool::new(config, factory)?;
1606
1607 let status = pool.status().await;
1608 assert_eq!(status.max, 10);
1609 assert_eq!(status.min, 2);
1610 assert_eq!(status.active, 0);
1611 Ok(())
1612 }
1613
1614 #[tokio::test]
1615 async fn test_pool_close_all() -> Result<(), Box<dyn std::error::Error>> {
1616 let config = PoolConfigBuilder::new().max_size(5).build()?;
1617 let factory = Arc::new(MockConnectionFactory);
1618 let pool = Pool::new(config, factory)?;
1619
1620 let conn1 = pool.acquire().await?;
1622 let conn2 = pool.acquire().await?;
1623 pool.release(conn1).await;
1624 pool.release(conn2).await;
1625
1626 pool.close_all().await;
1627 let status = pool.status().await;
1628 assert_eq!(status.idle, 0);
1629 assert_eq!(status.active, 0);
1630 Ok(())
1631 }
1632
1633 #[tokio::test]
1634 async fn test_pool_reap_idle() -> Result<(), Box<dyn std::error::Error>> {
1635 let config = PoolConfigBuilder::new()
1636 .max_size(5)
1637 .idle_timeout(0) .build()?;
1639 let factory = Arc::new(MockConnectionFactory);
1640 let pool = Pool::new(config, factory)?;
1641
1642 let conn = pool.acquire().await?;
1643 pool.release(conn).await;
1644
1645 tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
1647
1648 pool.reap_idle().await;
1649 let status = pool.status().await;
1650 assert_eq!(status.idle, 0);
1651 Ok(())
1652 }
1653
1654 #[tokio::test]
1660 async fn test_h7_acquire_timeout_default_30s() {
1661 let config = PoolConfig::default();
1662 assert_eq!(
1663 config.acquire_timeout,
1664 Duration::from_secs(30),
1665 "H-7: acquire_timeout 默认应为 30s"
1666 );
1667 }
1668
1669 #[tokio::test]
1671 async fn test_h7_acquire_timeout_configurable() -> Result<(), Box<dyn std::error::Error>> {
1672 let config = PoolConfigBuilder::new()
1673 .max_size(1)
1674 .acquire_timeout(5) .build()?;
1676 assert_eq!(config.acquire_timeout, Duration::from_secs(5));
1677
1678 let factory = Arc::new(MockConnectionFactory);
1680 let pool = Pool::new(config, factory)?;
1681 let _conn1 = pool.acquire().await?;
1682
1683 let fast_config = PoolConfigBuilder::new()
1685 .max_size(1)
1686 .acquire_timeout(0) .build()?;
1688 let fast_pool = Pool::new(fast_config, Arc::new(MockConnectionFactory))?;
1691 let _fast_conn = fast_pool.acquire().await?; let result = fast_pool.acquire().await;
1693 assert!(
1694 matches!(result, Err(PoolError::Timeout)),
1695 "H-7: 应返回 Timeout"
1696 );
1697 Ok(())
1698 }
1699
1700 #[tokio::test]
1703 async fn test_m7_health_check_removes_nothing_when_all_healthy(
1704 ) -> Result<(), Box<dyn std::error::Error>> {
1705 let config = PoolConfigBuilder::new().max_size(5).build()?;
1707 let factory = Arc::new(MockConnectionFactory);
1708 let pool = Pool::new(config, factory)?;
1709
1710 let conn1 = pool.acquire().await?;
1712 let conn2 = pool.acquire().await?;
1713 let conn3 = pool.acquire().await?;
1714 pool.release(conn1).await;
1715 pool.release(conn2).await;
1716 pool.release(conn3).await;
1717
1718 let removed = pool.health_check().await;
1719 assert_eq!(removed, 0, "Healthy connections should not be removed");
1720
1721 let status = pool.status().await;
1722 assert_eq!(status.idle, 3);
1723 assert_eq!(status.active, 3);
1724 Ok(())
1725 }
1726
1727 #[tokio::test]
1728 async fn test_m7_health_check_returns_zero_for_empty_pool(
1729 ) -> Result<(), Box<dyn std::error::Error>> {
1730 let config = PoolConfigBuilder::new().max_size(5).build()?;
1731 let factory = Arc::new(MockConnectionFactory);
1732 let pool = Pool::new(config, factory)?;
1733
1734 let removed = pool.health_check().await;
1735 assert_eq!(removed, 0);
1736 Ok(())
1737 }
1738
1739 struct CountingFactory {
1743 count: AtomicU32,
1744 }
1745
1746 impl CountingFactory {
1747 fn new() -> Self {
1748 Self {
1749 count: AtomicU32::new(0),
1750 }
1751 }
1752 fn created_count(&self) -> u32 {
1753 self.count.load(Ordering::SeqCst)
1754 }
1755 }
1756
1757 #[async_trait]
1758 impl ConnectionFactory for CountingFactory {
1759 async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
1760 self.count.fetch_add(1, Ordering::SeqCst);
1761 Ok(Box::new(MockConnection::new()))
1762 }
1763 }
1764
1765 #[tokio::test]
1771 async fn test_production_bug_max_lifetime_never_expires(
1772 ) -> Result<(), Box<dyn std::error::Error>> {
1773 let config = PoolConfig {
1776 max_size: 5,
1777 min_idle: 0,
1778 acquire_timeout: Duration::from_secs(30),
1779 idle_timeout: Duration::from_secs(600),
1780 max_lifetime: Duration::from_millis(100), connection_timeout: Duration::from_secs(10),
1782 tls: None,
1783 query_timeout: None,
1784 max_rows: None,
1785 memory_limit: None,
1786 on_event: None,
1787 test_before_acquire: false,
1788 };
1789 let factory = Arc::new(CountingFactory::new());
1790 let pool = Pool::new(config, factory.clone())?;
1791
1792 let conn = pool.acquire().await?;
1794 assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
1795
1796 pool.release(conn).await;
1798
1799 tokio::time::sleep(Duration::from_millis(150)).await;
1801
1802 let conn2 = pool.acquire().await?;
1804
1805 assert_eq!(
1808 factory.created_count(),
1809 2,
1810 "超过 max_lifetime 后应创建新连接(旧连接应被回收)"
1811 );
1812
1813 pool.release(conn2).await;
1814 Ok(())
1815 }
1816
1817 #[tokio::test]
1824 async fn test_drop_auto_release_connection() -> Result<(), Box<dyn std::error::Error>> {
1825 let config = PoolConfigBuilder::new().max_size(2).build()?;
1826 let factory = Arc::new(CountingFactory::new());
1827 let pool = Pool::new(config, factory.clone())?;
1828
1829 {
1831 let _conn = pool.acquire().await?;
1832 assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
1833 let status = pool.status().await;
1834 assert_eq!(status.active, 1, "active 应为 1");
1835 assert_eq!(status.idle, 0, "idle 应为 0");
1836 }
1838
1839 tokio::time::sleep(Duration::from_millis(50)).await;
1841
1842 let status = pool.status().await;
1844 assert_eq!(status.idle, 1, "Drop 后连接应自动归还,idle 应为 1");
1845 assert_eq!(status.active, 1, "total_count 应为 1");
1846 assert_eq!(factory.created_count(), 1, "应复用归还的连接,不创建新连接");
1847 Ok(())
1848 }
1849
1850 #[tokio::test]
1852 async fn test_drop_auto_release_then_reuse() -> Result<(), Box<dyn std::error::Error>> {
1853 let config = PoolConfigBuilder::new().max_size(1).build()?;
1854 let factory = Arc::new(CountingFactory::new());
1855 let pool = Pool::new(config, factory.clone())?;
1856
1857 {
1859 let _conn = pool.acquire().await?;
1860 }
1861
1862 tokio::time::sleep(Duration::from_millis(50)).await;
1864
1865 let conn = pool.acquire().await?;
1867 assert_eq!(factory.created_count(), 1, "应复用归还的连接,不创建新连接");
1868
1869 pool.release(conn).await;
1870 Ok(())
1871 }
1872
1873 #[tokio::test]
1875 async fn test_into_inner_does_not_return_to_pool() -> Result<(), Box<dyn std::error::Error>> {
1876 let config = PoolConfigBuilder::new().max_size(2).build()?;
1877 let factory = Arc::new(CountingFactory::new());
1878 let pool = Pool::new(config, factory.clone())?;
1879
1880 let conn = pool.acquire().await?;
1881 assert_eq!(factory.created_count(), 1);
1882
1883 let _raw_conn = conn.into_inner();
1885
1886 tokio::time::sleep(Duration::from_millis(50)).await;
1888
1889 let status = pool.status().await;
1890 assert_eq!(status.idle, 0, "into_inner 后连接不应归还");
1891 assert_eq!(status.active, 1, "total_count 仍为 1(连接被外部持有)");
1892 Ok(())
1893 }
1894
1895 #[tokio::test]
1897 async fn test_explicit_release_no_double_return() -> Result<(), Box<dyn std::error::Error>> {
1898 let config = PoolConfigBuilder::new().max_size(2).build()?;
1899 let factory = Arc::new(CountingFactory::new());
1900 let pool = Pool::new(config, factory.clone())?;
1901
1902 let conn = pool.acquire().await?;
1903 pool.release(conn).await;
1904
1905 let status = pool.status().await;
1906 assert_eq!(status.idle, 1, "release 后 idle 应为 1");
1907
1908 let conn = pool.acquire().await?;
1910 pool.release(conn).await;
1911
1912 let status = pool.status().await;
1913 assert_eq!(status.idle, 1, "再次 release 后 idle 仍应为 1(不重复)");
1914 assert_eq!(status.active, 1, "total_count 应为 1");
1915 Ok(())
1916 }
1917
1918 struct CursorMockConn {
1924 rows: QueryRows,
1925 call_count: usize,
1926 }
1927
1928 impl CursorMockConn {
1929 fn new(rows: QueryRows) -> Self {
1930 Self {
1931 rows,
1932 call_count: 0,
1933 }
1934 }
1935 }
1936
1937 impl Connection for CursorMockConn {
1938 fn execute<'a>(
1939 &'a mut self,
1940 _sql: &'a str,
1941 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
1942 Box::pin(async move { Ok(1) })
1943 }
1944
1945 fn query<'a>(
1946 &'a mut self,
1947 _sql: &'a str,
1948 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
1949 Box::pin(async move {
1950 self.call_count += 1;
1951 Ok(self.rows.clone())
1952 })
1953 }
1954
1955 fn begin_transaction<'a>(
1956 &'a mut self,
1957 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1958 Box::pin(async move { Ok(()) })
1959 }
1960
1961 fn commit<'a>(
1962 &'a mut self,
1963 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1964 Box::pin(async move { Ok(()) })
1965 }
1966
1967 fn rollback<'a>(
1968 &'a mut self,
1969 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1970 Box::pin(async move { Ok(()) })
1971 }
1972
1973 fn is_connected(&self) -> bool {
1974 true
1975 }
1976
1977 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
1978 Box::pin(async move { true })
1979 }
1980
1981 fn close<'a>(
1982 &'a mut self,
1983 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
1984 Box::pin(async move { Ok(()) })
1985 }
1986 }
1987
1988 struct CursorOverrideMockConn {
1990 rows: Vec<crate::value::Value>,
1991 yielded: usize,
1992 }
1993
1994 impl CursorOverrideMockConn {
1995 fn new(rows: Vec<crate::value::Value>) -> Self {
1996 Self { rows, yielded: 0 }
1997 }
1998 }
1999
2000 impl Connection for CursorOverrideMockConn {
2001 fn execute<'a>(
2002 &'a mut self,
2003 _sql: &'a str,
2004 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
2005 Box::pin(async move { Ok(1) })
2006 }
2007
2008 fn query<'a>(
2009 &'a mut self,
2010 _sql: &'a str,
2011 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
2012 Box::pin(async move {
2014 Ok(self
2015 .rows
2016 .iter()
2017 .map(|v| {
2018 let mut m = std::collections::HashMap::new();
2019 m.insert("v".to_string(), v.clone());
2020 m
2021 })
2022 .collect())
2023 })
2024 }
2025
2026 fn query_stream<'a>(
2028 &'a mut self,
2029 _sql: &'a str,
2030 ) -> Pin<Box<dyn futures::Stream<Item = QueryStreamItem> + Send + 'a>> {
2031 Box::pin(futures::stream::iter(
2032 self.rows
2033 .iter()
2034 .enumerate()
2035 .map(|(i, v)| {
2036 self.yielded = i + 1;
2037 let mut m = std::collections::HashMap::new();
2038 m.insert("v".to_string(), v.clone());
2039 Ok(m)
2040 })
2041 .collect::<Vec<_>>(),
2042 ))
2043 }
2044
2045 fn begin_transaction<'a>(
2046 &'a mut self,
2047 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2048 Box::pin(async move { Ok(()) })
2049 }
2050
2051 fn commit<'a>(
2052 &'a mut self,
2053 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2054 Box::pin(async move { Ok(()) })
2055 }
2056
2057 fn rollback<'a>(
2058 &'a mut self,
2059 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2060 Box::pin(async move { Ok(()) })
2061 }
2062
2063 fn is_connected(&self) -> bool {
2064 true
2065 }
2066
2067 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
2068 Box::pin(async move { true })
2069 }
2070
2071 fn close<'a>(
2072 &'a mut self,
2073 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2074 Box::pin(async move { Ok(()) })
2075 }
2076 }
2077
2078 #[tokio::test]
2080 async fn test_query_stream_default_impl_yields_all_rows() {
2081 use futures::StreamExt;
2082 let rows: QueryRows = vec![
2083 std::collections::HashMap::from([
2084 ("id".to_string(), crate::value::Value::I64(1)),
2085 (
2086 "name".to_string(),
2087 crate::value::Value::String("alice".to_string()),
2088 ),
2089 ]),
2090 std::collections::HashMap::from([
2091 ("id".to_string(), crate::value::Value::I64(2)),
2092 (
2093 "name".to_string(),
2094 crate::value::Value::String("bob".to_string()),
2095 ),
2096 ]),
2097 std::collections::HashMap::from([
2098 ("id".to_string(), crate::value::Value::I64(3)),
2099 (
2100 "name".to_string(),
2101 crate::value::Value::String("carol".to_string()),
2102 ),
2103 ]),
2104 ];
2105 let mut conn = CursorMockConn::new(rows);
2106 let mut stream = conn.query_stream("SELECT id, name FROM users");
2107 let mut received: Vec<QueryStreamItem> = Vec::new();
2108 while let Some(item) = stream.next().await {
2109 received.push(item);
2110 }
2111 assert_eq!(received.len(), 3, "应收到 3 行");
2112 assert!(received.iter().all(|r| r.is_ok()), "所有项应为 Ok");
2113 drop(stream);
2114 assert_eq!(conn.call_count, 1, "默认实现应调用 query() 一次");
2115 }
2116
2117 #[tokio::test]
2119 async fn test_query_stream_default_empty_result() {
2120 use futures::StreamExt;
2121 let mut conn = CursorMockConn::new(Vec::new());
2122 let mut stream = conn.query_stream("SELECT * FROM empty_table");
2123 let mut count = 0;
2124 while let Some(_item) = stream.next().await {
2125 count += 1;
2126 }
2127 assert_eq!(count, 0, "空结果集应产生 0 项");
2128 }
2129
2130 #[tokio::test]
2132 async fn test_query_stream_default_error_propagation() {
2133 use futures::StreamExt;
2134 struct ErrorMockConn;
2136 impl Connection for ErrorMockConn {
2137 fn execute<'a>(
2138 &'a mut self,
2139 _sql: &'a str,
2140 ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>>
2141 {
2142 Box::pin(async move { Ok(1) })
2143 }
2144 fn query<'a>(
2145 &'a mut self,
2146 _sql: &'a str,
2147 ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>>
2148 {
2149 Box::pin(async move { Err(crate::DbError::Internal("query failed".to_string())) })
2150 }
2151 fn begin_transaction<'a>(
2152 &'a mut self,
2153 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2154 Box::pin(async move { Ok(()) })
2155 }
2156 fn commit<'a>(
2157 &'a mut self,
2158 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2159 Box::pin(async move { Ok(()) })
2160 }
2161 fn rollback<'a>(
2162 &'a mut self,
2163 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2164 Box::pin(async move { Ok(()) })
2165 }
2166 fn is_connected(&self) -> bool {
2167 true
2168 }
2169 fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
2170 Box::pin(async move { true })
2171 }
2172 fn close<'a>(
2173 &'a mut self,
2174 ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2175 Box::pin(async move { Ok(()) })
2176 }
2177 }
2178 let mut conn = ErrorMockConn;
2179 let mut stream = conn.query_stream("SELECT * FROM bad_table");
2180 let item = stream.next().await;
2181 assert!(item.is_some(), "应产生一项");
2182 assert!(item.unwrap().is_err(), "该项应为 Err");
2183 }
2184
2185 #[tokio::test]
2187 async fn test_query_stream_override_yields_rows_one_by_one() {
2188 use futures::StreamExt;
2189 let rows = vec![
2190 crate::value::Value::I64(10),
2191 crate::value::Value::I64(20),
2192 crate::value::Value::I64(30),
2193 crate::value::Value::I64(40),
2194 crate::value::Value::I64(50),
2195 ];
2196 let mut conn = CursorOverrideMockConn::new(rows);
2197 let values: Vec<i64> = {
2198 let mut stream = conn.query_stream("SELECT v FROM seq");
2199 let mut vals: Vec<i64> = Vec::new();
2200 while let Some(Ok(row)) = stream.next().await {
2201 if let crate::value::Value::I64(v) = row.get("v").unwrap() {
2202 vals.push(*v);
2203 }
2204 }
2205 vals
2206 };
2207 assert_eq!(values, vec![10, 20, 30, 40, 50], "应按顺序收到全部 5 行");
2208 assert_eq!(conn.yielded, 5, "应逐行 yield 5 次(真游标覆盖)");
2209 }
2210
2211 #[tokio::test]
2213 async fn test_query_stream_override_early_drop() {
2214 use futures::StreamExt;
2215 let rows = vec![
2216 crate::value::Value::I64(1),
2217 crate::value::Value::I64(2),
2218 crate::value::Value::I64(3),
2219 ];
2220 let mut conn = CursorOverrideMockConn::new(rows);
2221 {
2222 let mut stream = conn.query_stream("SELECT v FROM seq");
2223 let first = stream.next().await;
2224 assert!(first.is_some(), "第一项应存在");
2225 drop(stream);
2227 }
2228 assert!(conn.is_connected(), "提前 drop 流后连接仍应可用");
2230 }
2231}