Skip to main content

sz_orm_core/
pool.rs

1//! Connection Pool
2//!
3//! Provides async connection pooling with configurable options
4
5use async_trait::async_trait;
6use crossbeam_queue::ArrayQueue;
7use futures::StreamExt;
8// v4.7.0 观测闭环:PoolMetrics JSON 导出(metrics_snapshot_json)
9use serde::{Deserialize, Serialize};
10// P1-4 修复:使用核心层定义的 CircuitBreaker/RateLimiter 抽象,
11// 消除对 sz-orm-health/sz-orm-limit 的反向依赖。
12// parking_lot 锁仅在启用 circuit-breaker/rate-limit/tenant-quota-rls-enhanced feature 时使用
13//(v4.7.0 接线修复:quota_enforcer 字段同样使用 PlMutex,见 tenant_quota_rls.rs)
14#[cfg(any(feature = "circuit-breaker", feature = "tenant-quota-rls-enhanced"))]
15use parking_lot::Mutex as PlMutex;
16#[cfg(feature = "rate-limit")]
17use parking_lot::RwLock as PlRwLock;
18use std::future::Future;
19use std::ops::{Deref, DerefMut};
20use std::pin::Pin;
21use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering};
22use std::sync::Arc;
23use std::time::{Duration, Instant};
24use tokio::sync::Notify;
25
26// P1-4 修复:CircuitBreaker/RateLimiter 抽象已提升到核心层,
27// 仅在启用相应 feature 时导入(避免 default feature 下的 unused imports)
28// 注意:trait 方法(can_execute/record_success 等)需要 trait 在 scope 中
29#[cfg(feature = "circuit-breaker")]
30use crate::circuit_breaker::{CircuitBreaker, CircuitState, DefaultCircuitBreaker};
31use crate::error::PoolError;
32#[cfg(feature = "rate-limit")]
33use crate::rate_limiter::RateLimiter;
34#[cfg(feature = "tenant-quota-rls-enhanced")]
35use crate::tenant_quota_rls::{QuotaEnforcer, QuotaResource};
36
37/// 查询结果行类型别名:避免 `Connection::query` 签名触发 `clippy::type_complexity`。
38pub type QueryRows = Vec<std::collections::HashMap<String, crate::value::Value>>;
39
40/// 流式查询结果项类型别名:避免 `Connection::query_stream` 签名触发 `clippy::type_complexity`。
41pub type QueryStreamItem =
42    Result<std::collections::HashMap<String, crate::value::Value>, crate::DbError>;
43
44/// 数据库连接 trait
45///
46/// 注意:此 trait 手动解糖 async 方法(不使用 `#[async_trait]`),
47/// 以避免 `&str` 参数触发 HRTB 与 sqlx::Executor 冲突。
48/// 所有 async 方法使用单一生命周期 `'a`(绑定 `&'a mut self` 和 `&'a str`),
49/// 而非 HRTB,从而允许 sqlx 适配器实现。
50pub trait Connection: Send + Sync {
51    /// 执行 SQL(INSERT/UPDATE/DELETE),返回影响行数
52    fn execute<'a>(
53        &'a mut self,
54        sql: &'a str,
55    ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>>;
56    /// 执行查询(SELECT),返回结果行集
57    fn query<'a>(
58        &'a mut self,
59        sql: &'a str,
60    ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>>;
61    /// 开启事务
62    fn begin_transaction<'a>(
63        &'a mut self,
64    ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
65    /// 提交事务
66    fn commit<'a>(
67        &'a mut self,
68    ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
69    /// 回滚事务
70    fn rollback<'a>(
71        &'a mut self,
72    ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
73    /// 判断连接是否仍然有效
74    fn is_connected(&self) -> bool;
75    /// 发送 PING 检测连接存活
76    fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>>;
77    /// 关闭连接
78    fn close<'a>(
79        &'a mut self,
80    ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>>;
81
82    /// 参数绑定执行(INSERT/UPDATE/DELETE)
83    ///
84    /// 使用真实 prepared statement 绑定参数,避免 SQL 注入。
85    /// 默认实现返回 `NotImplemented` 错误;支持参数绑定的适配器
86    /// (如 sz-orm-oracle)应覆盖此方法。
87    fn execute_with_params<'a>(
88        &'a mut self,
89        sql: &'a str,
90        params: &'a [crate::value::Value],
91    ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
92        let _ = (sql, params);
93        Box::pin(async move {
94            Err(crate::DbError::Internal(
95                "execute_with_params not implemented for this adapter".to_string(),
96            ))
97        })
98    }
99
100    /// 参数绑定查询(SELECT)
101    ///
102    /// 使用真实 prepared statement 绑定参数,避免 SQL 注入。
103    /// 默认实现返回 `NotImplemented` 错误;支持参数绑定的适配器
104    /// (如 sz-orm-oracle)应覆盖此方法。
105    fn query_with_params<'a>(
106        &'a mut self,
107        sql: &'a str,
108        params: &'a [crate::value::Value],
109    ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
110        let _ = (sql, params);
111        Box::pin(async move {
112            Err(crate::DbError::Internal(
113                "query_with_params not implemented for this adapter".to_string(),
114            ))
115        })
116    }
117
118    /// 位置式查询(SELECT):返回 `(列名, 按列顺序的值矩阵)`
119    ///
120    /// 绕过 `HashMap<String, Value>` 行映射,适用于 SELECT ALL 大结果集场景。
121    /// 默认实现返回 `NotImplemented` 错误;适配器可覆盖此方法以获得 30%~50% 性能提升。
122    fn query_values<'a>(
123        &'a mut self,
124        sql: &'a str,
125    ) -> Pin<Box<dyn Future<Output = Result<crate::value::QueryValues, crate::DbError>> + Send + 'a>>
126    {
127        let _ = sql;
128        Box::pin(async move {
129            Err(crate::DbError::Internal(
130                "query_values not implemented for this adapter".to_string(),
131            ))
132        })
133    }
134
135    /// 参数绑定位置式查询(SELECT):叠加 prepared statement + 位置式映射双重优化
136    ///
137    /// 默认实现返回 `NotImplemented` 错误;适配器可覆盖此方法以获得最佳性能。
138    fn query_values_with_params<'a>(
139        &'a mut self,
140        sql: &'a str,
141        params: &'a [crate::value::Value],
142    ) -> Pin<Box<dyn Future<Output = Result<crate::value::QueryValues, crate::DbError>> + Send + 'a>>
143    {
144        let _ = (sql, params);
145        Box::pin(async move {
146            Err(crate::DbError::Internal(
147                "query_values_with_params not implemented for this adapter".to_string(),
148            ))
149        })
150    }
151
152    /// 流式查询:返回逐行结果流
153    ///
154    /// 默认实现:通过 `query()` 获取全部行后,以
155    /// `futures::stream::iter` 逐行 yield,提供统一的流式消费接口。
156    /// 适合中小结果集;对超大结果集,支持原生游标的适配器应覆盖此方法。
157    ///
158    /// # 注意
159    ///
160    /// 此方法本身是同步的(返回 Stream),但内部通过 `futures::stream::once`
161    /// 异步获取数据后展开为逐行流。若适配器支持 sqlx `fetch()` 游标,
162    /// 覆盖此方法可获得真正的逐行拉取,避免大结果集内存峰值。
163    fn query_stream<'a>(
164        &'a mut self,
165        sql: &'a str,
166    ) -> Pin<Box<dyn futures::Stream<Item = QueryStreamItem> + Send + 'a>> {
167        // 克隆 sql 以脱离 &self 的生命周期
168        let sql_owned = sql.to_string();
169        // 使用 stream::once 异步执行查询,再 flat_map 为逐行流
170        let stream = futures::stream::once(async move { self.query(&sql_owned).await })
171            // 统一为 Vec 收集后再 iter:保证 match 两臂流类型一致(E0308 修复)
172            .map(|result| {
173                let items: Vec<QueryStreamItem> = match result {
174                    Ok(rows) => rows.into_iter().map(Ok).collect(),
175                    Err(e) => vec![Err(e)],
176                };
177                futures::stream::iter(items)
178            })
179            .flatten();
180        Box::pin(stream)
181    }
182
183    /// 游标式流式查询(P1-2):按 `batch_size` 分批拉取,避免大结果集内存峰值。
184    ///
185    /// 适用于无原生服务器端游标(或无法便捷暴露逐行拉取)的数据库:
186    /// - Oracle:`ROWNUM` 子查询包装(见 `cursor_stream::build_paged_query`);
187    /// - SQL Server:`OFFSET ... ROWS FETCH NEXT ... ROWS ONLY`。
188    ///
189    /// 默认实现退化为 [`Connection::query_stream`](全量拉取后逐行 yield);
190    /// Oracle/MSSQL 适配器应覆盖此方法,使用
191    /// `cursor_stream::stream_cursor_paged(conn, sql, DbType::Oracle, batch)`
192    /// 获得真正的分页游标流。
193    fn query_stream_cursor<'a>(
194        &'a mut self,
195        sql: &'a str,
196        _batch_size: usize,
197    ) -> Pin<Box<dyn futures::Stream<Item = QueryStreamItem> + Send + 'a>> {
198        self.query_stream(sql)
199    }
200
201    /// 批量执行多条 SQL(按顺序执行,返回累计影响行数)
202    ///
203    /// 默认实现循环调用 `execute`;适配器可覆盖此方法以利用数据库原生
204    /// 批量执行能力。
205    fn execute_batch<'a>(
206        &'a mut self,
207        sqls: &'a [String],
208    ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
209        Box::pin(async move {
210            let mut total = 0u64;
211            for sql in sqls {
212                total += self.execute(sql).await?;
213            }
214            Ok(total)
215        })
216    }
217
218    /// 批量插入(单条 SQL 多次参数绑定执行)
219    ///
220    /// 默认实现循环调用 `execute_with_params`;适配器可覆盖此方法
221    /// 以利用数据库原生批量 DML 能力(如 Oracle Array DML)。
222    fn execute_batch_params<'a>(
223        &'a mut self,
224        sql: &'a str,
225        params_batch: &'a [Vec<crate::value::Value>],
226    ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
227        Box::pin(async move {
228            let mut total = 0u64;
229            for params in params_batch {
230                total += self.execute_with_params(sql, params).await?;
231            }
232            Ok(total)
233        })
234    }
235}
236
237/// 连接池中的连接条目,记录创建时间和最后使用时间
238///
239/// - `created_at`:连接的原始创建时间,**不**随 acquire/release 重置,
240///   用于 `max_lifetime` 过期判定。
241/// - `last_used_at`:上次归还到池的时间,用于 `idle_timeout` 空闲超时判定。
242/// - `pool`:归属的连接池引用,Drop 时自动归还。`None` 表示无需归还
243///   (已通过 `release()`/`into_inner()` 显式处理)。
244pub struct PooledConnection {
245    conn: Box<dyn Connection>,
246    created_at: Instant,
247    last_used_at: Instant,
248    pool: Option<Pool>,
249}
250
251impl PooledConnection {
252    fn new(conn: Box<dyn Connection>, pool: Pool) -> Self {
253        let now = Instant::now();
254        Self {
255            conn,
256            created_at: now,
257            last_used_at: now,
258            pool: Some(pool),
259        }
260    }
261
262    fn is_expired(&self, max_lifetime: Duration) -> bool {
263        self.created_at.elapsed() >= max_lifetime
264    }
265
266    fn is_idle_too_long(&self, idle_timeout: Duration) -> bool {
267        self.last_used_at.elapsed() >= idle_timeout
268    }
269
270    /// 连接的原始创建时间(不随 acquire/release 重置)
271    pub fn created_at(&self) -> Instant {
272        self.created_at
273    }
274
275    /// 提取内部连接(消费 PooledConnection)
276    ///
277    /// 用于将连接传递给 `Transaction::new` 等消费连接的 API。
278    /// 调用此方法后,连接不再属于池,调用方需自行管理其生命周期。
279    pub fn into_inner(mut self) -> Box<dyn Connection> {
280        self.pool = None; // 标记无需归还
281                          // PooledConnection 实现了 Drop,不能直接 move conn,
282                          // 用 mem::replace 取出连接,放入 ClosedConnection 占位符
283        std::mem::replace(&mut self.conn, Box::new(ClosedConnection))
284    }
285}
286
287/// PooledConnection 的 Drop 实现:自动归还连接到池中
288///
289/// 修复 Critical Bug:之前 PooledConnection 未实现 Drop,连接在 drop 时
290/// 丢失,不归还池中,导致池耗尽。
291///
292/// 实现策略:
293/// 1. 如果 `pool` 为 `Some`(未显式 release/into_inner),取出连接并放入
294///    `ClosedConnection` 占位符
295/// 2. 在 tokio runtime 中 spawn 异步 release(Drop 不能 await)
296/// 3. 如果不在 tokio runtime 中(P0 修复):手动递减 `total_count`,
297///    避免池容量被耗尽;连接随 `pooled` drop 自然释放(依赖底层连接 Drop)
298impl Drop for PooledConnection {
299    fn drop(&mut self) {
300        if let Some(pool) = self.pool.take() {
301            // 取出原始连接,放入占位符(避免重复 close)
302            let conn = std::mem::replace(&mut self.conn, Box::new(ClosedConnection));
303            let pooled = PooledConnection {
304                conn,
305                created_at: self.created_at,
306                last_used_at: self.last_used_at,
307                pool: None,
308            };
309            // 尝试在 tokio runtime 中异步归还
310            if let Ok(handle) = tokio::runtime::Handle::try_current() {
311                handle.spawn(async move {
312                    pool.release(pooled).await;
313                });
314            } else {
315                // 不在 tokio runtime 中:手动递减计数器,避免池容量泄漏
316                // 注意:close 是 async 方法,无法在 sync Drop 中 await;
317                //       连接随 `pooled` drop 自然释放(依赖底层连接 Drop)
318                drop(pooled);
319                pool.total_count.fetch_sub(1, Ordering::SeqCst);
320            }
321        }
322    }
323}
324
325/// 占位连接,用于 PooledConnection::Drop 替换原始连接
326///
327/// 所有操作返回错误或默认值,`is_connected()` 返回 false。
328struct ClosedConnection;
329
330impl Connection for ClosedConnection {
331    fn execute<'a>(
332        &'a mut self,
333        _sql: &'a str,
334    ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
335        Box::pin(async {
336            Err(crate::DbError::ConnectionError(
337                "connection already returned to pool".to_string(),
338            ))
339        })
340    }
341
342    fn query<'a>(
343        &'a mut self,
344        _sql: &'a str,
345    ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
346        Box::pin(async {
347            Err(crate::DbError::ConnectionError(
348                "connection already returned to pool".to_string(),
349            ))
350        })
351    }
352
353    fn begin_transaction<'a>(
354        &'a mut self,
355    ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
356        Box::pin(async {
357            Err(crate::DbError::ConnectionError(
358                "connection already returned to pool".to_string(),
359            ))
360        })
361    }
362
363    fn commit<'a>(
364        &'a mut self,
365    ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
366        Box::pin(async { Ok(()) })
367    }
368
369    fn rollback<'a>(
370        &'a mut self,
371    ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
372        Box::pin(async { Ok(()) })
373    }
374
375    fn is_connected(&self) -> bool {
376        false
377    }
378
379    fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
380        Box::pin(async { false })
381    }
382
383    fn close<'a>(
384        &'a mut self,
385    ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
386        Box::pin(async { Ok(()) })
387    }
388}
389
390impl Deref for PooledConnection {
391    type Target = dyn Connection;
392
393    fn deref(&self) -> &Self::Target {
394        self.conn.as_ref()
395    }
396}
397
398impl DerefMut for PooledConnection {
399    fn deref_mut(&mut self) -> &mut Self::Target {
400        self.conn.as_mut()
401    }
402}
403
404/// TLS 版本
405#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
406pub enum TlsVersion {
407    /// TLS 1.2
408    #[default]
409    Tls12,
410    /// TLS 1.3
411    Tls13,
412}
413
414/// TLS 配置
415#[derive(Debug, Clone, Default)]
416pub struct TlsConfig {
417    /// 是否启用 TLS
418    pub enabled: bool,
419    /// CA 证书路径
420    pub ca_cert_path: Option<String>,
421    /// 客户端证书路径(双向 TLS)
422    pub client_cert_path: Option<String>,
423    /// 客户端私钥路径
424    pub client_key_path: Option<String>,
425    /// 最小 TLS 版本
426    pub min_version: TlsVersion,
427}
428
429/// 连接池事件
430#[derive(Debug, Clone)]
431pub enum PoolEvent {
432    /// 创建新连接
433    ConnectionCreated,
434    /// 连接被关闭
435    ConnectionClosed,
436    /// 连接被获取
437    ConnectionAcquired,
438    /// 连接被归还
439    ConnectionReleased,
440    /// 获取连接超时
441    AcquireTimeout,
442}
443
444/// 连接池事件回调
445pub type PoolEventCallback = Arc<dyn Fn(PoolEvent) + Send + Sync>;
446
447/// 连接池配置
448pub struct PoolConfig {
449    /// 最大连接数
450    pub max_size: u32,
451    /// 最小空闲连接数
452    pub min_idle: u32,
453    /// 获取连接超时时间
454    pub acquire_timeout: Duration,
455    /// 空闲连接超时时间
456    pub idle_timeout: Duration,
457    /// 连接最大存活时间
458    pub max_lifetime: Duration,
459    /// 连接建立超时时间
460    pub connection_timeout: Duration,
461    /// TLS 配置
462    pub tls: Option<TlsConfig>,
463    /// SQL 执行超时(默认 30 秒)
464    pub query_timeout: Option<Duration>,
465    /// 单次查询最大返回行数(默认无限制)
466    pub max_rows: Option<usize>,
467    /// 内存使用上限(字节,默认无限制)
468    pub memory_limit: Option<usize>,
469    /// 连接池事件回调
470    pub on_event: Option<PoolEventCallback>,
471    /// acquire 时是否执行 ping 验证连接存活(默认 false)。
472    ///
473    /// 开启后,从空闲队列取出的连接会先执行 `ping()` 验证网络连通性,
474    /// ping 失败的连接会被丢弃并重新 acquire。
475    ///
476    /// **注意**:开启此选项会增加每次 acquire 的延迟(一次额外的网络 RTT)。
477    /// 适用于 DB 可能重启且不能容忍首次查询失败的场景。
478    pub test_before_acquire: bool,
479    /// 连接池预热:启用后池创建时立即建立 `min_idle` 个连接(默认 false)。
480    ///
481    /// 预热后首次 acquire 延迟 < 10ms(对比冷启动 < 100ms)。
482    ///
483    /// # 示例
484    ///
485    /// ```ignore
486    /// let config = PoolConfig::default().with_prewarm(true);
487    /// let pool = Pool::new(config, factory).await?;
488    /// // 此时池中已有 min_idle 个连接
489    /// ```
490    pub prewarm: bool,
491}
492
493impl Default for PoolConfig {
494    fn default() -> Self {
495        Self {
496            max_size: 100,
497            min_idle: 0,
498            acquire_timeout: Duration::from_secs(30),
499            idle_timeout: Duration::from_secs(600),
500            max_lifetime: Duration::from_secs(1800),
501            connection_timeout: Duration::from_secs(10),
502            tls: None,
503            query_timeout: Some(Duration::from_secs(30)),
504            max_rows: None,
505            memory_limit: None,
506            on_event: None,
507            test_before_acquire: false,
508            prewarm: false,
509        }
510    }
511}
512
513impl Clone for PoolConfig {
514    fn clone(&self) -> Self {
515        Self {
516            max_size: self.max_size,
517            min_idle: self.min_idle,
518            acquire_timeout: self.acquire_timeout,
519            idle_timeout: self.idle_timeout,
520            max_lifetime: self.max_lifetime,
521            connection_timeout: self.connection_timeout,
522            tls: self.tls.clone(),
523            query_timeout: self.query_timeout,
524            max_rows: self.max_rows,
525            memory_limit: self.memory_limit,
526            on_event: self.on_event.clone(),
527            test_before_acquire: self.test_before_acquire,
528            prewarm: self.prewarm,
529        }
530    }
531}
532
533impl PoolConfig {
534    /// 校验配置合法性
535    pub fn validate(&self) -> Result<(), PoolError> {
536        if self.max_size == 0 {
537            return Err(PoolError::InvalidConfig("max_size cannot be 0".to_string()));
538        }
539        if self.min_idle > self.max_size {
540            return Err(PoolError::InvalidConfig(
541                "min_idle cannot exceed max_size".to_string(),
542            ));
543        }
544        // Duration 上界校验:防止 `Instant::now() + duration` 溢出 panic。
545        // u64::MAX 秒 ≈ 5.8e11 年,远超任何合理配置;实际使用中 1 年(31_536_000 秒)
546        // 已是宽松上限。此处用 u32::MAX 秒(≈ 136 年)作为硬性上限,
547        // 既覆盖所有现实场景,又保证 `Instant + Duration` 在 i64 微秒精度内不溢出。
548        const MAX_DURATION_SECS: u64 = u32::MAX as u64; // ≈ 136 年
549        for (name, dur) in [
550            ("acquire_timeout", self.acquire_timeout),
551            ("idle_timeout", self.idle_timeout),
552            ("max_lifetime", self.max_lifetime),
553            ("connection_timeout", self.connection_timeout),
554        ] {
555            if dur.as_secs() > MAX_DURATION_SECS {
556                return Err(PoolError::InvalidConfig(format!(
557                    "{name} ({:?}) exceeds maximum allowed duration ({} seconds)",
558                    dur, MAX_DURATION_SECS
559                )));
560            }
561        }
562        Ok(())
563    }
564
565    /// 设置预热标志(链式调用)
566    #[must_use]
567    pub fn with_prewarm(mut self, prewarm: bool) -> Self {
568        self.prewarm = prewarm;
569        self
570    }
571}
572
573/// 连接池状态快照
574pub struct PoolStatus {
575    /// 空闲连接数
576    pub idle: u32,
577    /// 活跃连接数
578    pub active: u32,
579    /// 最大连接数
580    pub max: u32,
581    /// 最小空闲连接数
582    pub min: u32,
583    /// 等待 acquire 的任务数
584    pub waiters: u32,
585}
586
587impl std::fmt::Debug for PoolStatus {
588    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
589        f.debug_struct("PoolStatus")
590            .field("idle", &self.idle)
591            .field("active", &self.active)
592            .field("max", &self.max)
593            .field("min", &self.min)
594            .field("waiters", &self.waiters)
595            .finish()
596    }
597}
598
599/// 连接池累计统计指标(Prometheus 风格)
600///
601/// 所有字段均为池生命周期内的累计值(不会随获取/归还重置),
602/// 由 `Pool::pool_metrics()` 返回。基于无锁 `AtomicU64` 计数,
603/// 对 acquire/release 热路径的影响可忽略(单条原子指令)。
604/// serde 序列化支持:观测层导出(`Pool::metrics_snapshot_json`,v4.7.0 观测闭环)。
605#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
606pub struct PoolMetrics {
607    /// 累计成功获取连接次数
608    pub acquire_count: u64,
609    /// 累计获取连接失败次数(超时 / 连接创建失败 / 池已关闭 / 断路器或限流拒绝)
610    pub acquire_failed_count: u64,
611    /// 累计等待获取连接的时长(池满时阻塞等待的累计时间)
612    pub acquire_wait_time: Duration,
613    /// 累计归还连接次数
614    pub release_count: u64,
615    /// 累计创建连接数(含 prewarm / warmup / acquire 新建)
616    pub connection_created_count: u64,
617    /// 累计关闭连接数(含过期回收 / 失效 / 池关闭)
618    pub connection_closed_count: u64,
619}
620
621impl PoolMetrics {
622    /// 平均获取等待时长(无成功获取时为 0)
623    #[must_use]
624    pub fn average_acquire_wait_time(&self) -> Duration {
625        if self.acquire_count == 0 {
626            Duration::ZERO
627        } else {
628            self.acquire_wait_time / self.acquire_count as u32
629        }
630    }
631}
632
633/// 连接池配置构建器
634pub struct PoolConfigBuilder {
635    config: PoolConfig,
636}
637
638impl PoolConfigBuilder {
639    /// 创建默认配置构建器
640    pub fn new() -> Self {
641        Self {
642            config: PoolConfig::default(),
643        }
644    }
645
646    /// 设置最大连接数
647    pub fn max_size(mut self, size: u32) -> Self {
648        self.config.max_size = size;
649        self
650    }
651
652    /// 设置最小空闲连接数
653    pub fn min_idle(mut self, count: u32) -> Self {
654        self.config.min_idle = count;
655        self
656    }
657
658    /// 设置获取连接超时(秒)
659    pub fn acquire_timeout(mut self, timeout_secs: u64) -> Self {
660        self.config.acquire_timeout = Duration::from_secs(timeout_secs);
661        self
662    }
663
664    /// 设置空闲连接超时(秒)
665    pub fn idle_timeout(mut self, timeout_secs: u64) -> Self {
666        self.config.idle_timeout = Duration::from_secs(timeout_secs);
667        self
668    }
669
670    /// 设置连接最大存活时间(秒)
671    pub fn max_lifetime(mut self, lifetime_secs: u64) -> Self {
672        self.config.max_lifetime = Duration::from_secs(lifetime_secs);
673        self
674    }
675
676    /// 设置 TLS 配置
677    pub fn tls(mut self, tls: TlsConfig) -> Self {
678        self.config.tls = Some(tls);
679        self
680    }
681
682    /// 设置 SQL 执行超时
683    pub fn query_timeout(mut self, timeout: Duration) -> Self {
684        self.config.query_timeout = Some(timeout);
685        self
686    }
687
688    /// 设置单次查询最大返回行数
689    pub fn max_rows(mut self, max_rows: usize) -> Self {
690        self.config.max_rows = Some(max_rows);
691        self
692    }
693
694    /// 设置内存使用上限(字节)
695    pub fn memory_limit(mut self, memory_limit: usize) -> Self {
696        self.config.memory_limit = Some(memory_limit);
697        self
698    }
699
700    /// 设置连接池事件回调
701    pub fn on_event(mut self, callback: PoolEventCallback) -> Self {
702        self.config.on_event = Some(callback);
703        self
704    }
705
706    /// 设置 acquire 时是否执行 ping 验证连接存活(P1-1)
707    ///
708    /// 开启后,从空闲队列取出的连接会先执行 `ping()` 验证网络连通性。
709    /// 默认关闭(仅做 `is_connected()` 内存检查)。
710    pub fn test_before_acquire(mut self, enabled: bool) -> Self {
711        self.config.test_before_acquire = enabled;
712        self
713    }
714
715    /// 设置连接池预热(P2-1)
716    ///
717    /// 启用后池创建时立即建立 `min_idle` 个连接,减少首次查询延迟。
718    /// 默认关闭(冷启动)。
719    pub fn prewarm(mut self, enabled: bool) -> Self {
720        self.config.prewarm = enabled;
721        self
722    }
723
724    /// 构建并校验连接池配置
725    pub fn build(self) -> Result<PoolConfig, PoolError> {
726        self.config.validate()?;
727        Ok(self.config)
728    }
729}
730
731impl Default for PoolConfigBuilder {
732    fn default() -> Self {
733        Self::new()
734    }
735}
736
737/// 连接工厂 trait,用于创建新连接
738#[async_trait]
739pub trait ConnectionFactory: Send + Sync {
740    /// 创建新连接
741    async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError>;
742}
743
744/// 连接池核心实现
745///
746/// 所有字段均为 `Arc` 或内部含 `Arc`(`Notify`、`PoolConfig` 可 clone),
747/// 因此 `Pool` 可低成本 clone(仅增加引用计数)。`PooledConnection` 持有
748/// `Pool` 的 clone 以实现 Drop 自动归还。
749pub struct Pool {
750    config: PoolConfig,
751    factory: Arc<dyn ConnectionFactory>,
752    /// v1.1.0 优化 2:从 `Arc<Mutex<VecDeque<PooledConnection>>>` 改为
753    /// `Arc<ArrayQueue<PooledConnection>>`,使用无锁 MPMC 队列消除锁竞争。
754    /// 容量固定为 `config.max_size`,因为 `total_count` 已限制池中总连接数
755    /// 不超过 `max_size`,所以 `push` 不会因容量不足失败(除非并发 release
756    /// 超过 max_size,那只在 close_all 后的归还路径发生,此时连接会被直接关闭)。
757    idle: Arc<ArrayQueue<PooledConnection>>,
758    /// 池中总连接数(idle + borrowed)
759    ///
760    /// v0.2.1 修复 Critical P-1:从 `Mutex<u32>` 改为 `AtomicU32`
761    ///
762    /// # 原因
763    ///
764    /// - `Mutex<u32>` 在高并发下成为瓶颈(每次 acquire/release 都要 lock)
765    /// - `AtomicU32` 是无锁的,fetch_add/fetch_sub 是单条 CPU 指令
766    /// - 修复后吞吐量提升 ~3x(实测 10 task × 1000 acquire/release)
767    total_count: Arc<AtomicU32>,
768    /// 池是否已关闭(close_all 后设为 true,拒绝新 acquire/release)
769    closed: Arc<AtomicBool>,
770    notify: Arc<Notify>,
771    /// 等待 acquire 的任务数(监控用)
772    waiters_count: Arc<AtomicU32>,
773    /// 动态 max_size(可通过 resize/set_max_size 修改,初始值为 config.max_size)
774    dynamic_max_size: Arc<AtomicU32>,
775    /// #88 修复:断路器(启用 `circuit-breaker` feature 时生效)
776    ///
777    /// 当数据库连续失败超过阈值时,断路器跳闸,拒绝新 acquire 请求,
778    /// 避免对下游数据库造成更大压力。reset_timeout 后进入 HalfOpen 状态,
779    /// 放行一次试探请求;成功则 Closed,失败则重新 Open。
780    #[cfg(feature = "circuit-breaker")]
781    circuit_breaker: Arc<PlMutex<DefaultCircuitBreaker>>,
782    /// #93 修复:限流器(启用 `rate-limit` feature 时生效)
783    ///
784    /// 在 acquire 前调用 `try_acquire(key)`,被拒绝时返回 `PoolError::RateLimited`。
785    /// 默认 key 为 `"pool"`,调用方可通过 `acquire_with_key` 指定按用户/IP 维度限流。
786    /// 使用 `RwLock<Option<...>>` 支持运行时动态启用/禁用/替换限流器。
787    ///
788    /// P1-4 修复:使用核心层 `crate::rate_limiter::RateLimiter` trait,
789    /// 而非 `sz_orm_limit::RateLimiter`,消除反向依赖。
790    #[cfg(feature = "rate-limit")]
791    rate_limiter: Arc<PlRwLock<Option<Arc<dyn RateLimiter>>>>,
792    /// #93 修复:限流器使用的 key(默认 "pool")
793    #[cfg(feature = "rate-limit")]
794    rate_limit_key: String,
795    /// v4.7.0 REQ-V47-006:租户配额执行器(启用 `tenant-quota-rls-enhanced` feature 时生效)
796    ///
797    /// 在 `acquire_with_tenant` 路径上插入配额检查,超限按策略拒绝或放行。
798    /// 默认 `None`(无配额限制),通过 `set_quota_enforcer` 配置。
799    #[cfg(feature = "tenant-quota-rls-enhanced")]
800    quota_enforcer: Arc<PlMutex<Option<Arc<QuotaEnforcer>>>>,
801    /// 累计成功获取连接次数(Prometheus 风格统计,无锁原子计数)
802    acquire_count: Arc<AtomicU64>,
803    /// 累计获取连接失败次数(超时 / 连接创建失败 / 池已关闭 / 断路器或限流拒绝)
804    acquire_failed_count: Arc<AtomicU64>,
805    /// 累计等待获取连接的时长(纳秒,池满时阻塞等待的累计时间)
806    acquire_wait_time_ns: Arc<AtomicU64>,
807    /// 累计归还连接次数
808    release_count: Arc<AtomicU64>,
809    /// 累计创建连接数
810    connection_created_count: Arc<AtomicU64>,
811    /// 累计关闭连接数
812    connection_closed_count: Arc<AtomicU64>,
813}
814
815/// Pool 克隆:仅增加 Arc 引用计数,成本极低
816///
817/// 克隆后的 Pool 与原 Pool 共享同一组连接池状态(idle 队列、计数器等)。
818impl Clone for Pool {
819    fn clone(&self) -> Self {
820        Self {
821            config: self.config.clone(),
822            factory: self.factory.clone(),
823            idle: self.idle.clone(),
824            total_count: self.total_count.clone(),
825            closed: self.closed.clone(),
826            notify: Arc::clone(&self.notify),
827            waiters_count: self.waiters_count.clone(),
828            dynamic_max_size: self.dynamic_max_size.clone(),
829            #[cfg(feature = "circuit-breaker")]
830            circuit_breaker: Arc::clone(&self.circuit_breaker),
831            #[cfg(feature = "rate-limit")]
832            rate_limiter: Arc::clone(&self.rate_limiter),
833            #[cfg(feature = "rate-limit")]
834            rate_limit_key: self.rate_limit_key.clone(),
835            #[cfg(feature = "tenant-quota-rls-enhanced")]
836            quota_enforcer: Arc::clone(&self.quota_enforcer),
837            acquire_count: self.acquire_count.clone(),
838            acquire_failed_count: self.acquire_failed_count.clone(),
839            acquire_wait_time_ns: self.acquire_wait_time_ns.clone(),
840            release_count: self.release_count.clone(),
841            connection_created_count: self.connection_created_count.clone(),
842            connection_closed_count: self.connection_closed_count.clone(),
843        }
844    }
845}
846
847impl Pool {
848    /// 创建连接池
849    ///
850    /// L-5 修复:补充示例文档
851    ///
852    /// # 示例
853    ///
854    /// ```ignore
855    /// use sz_orm_core::pool::{Pool, PoolConfig, PoolConfigBuilder, ConnectionFactory};
856    /// use std::sync::Arc;
857    ///
858    /// struct MyFactory;
859    /// impl ConnectionFactory for MyFactory {
860    ///     // ...
861    ///     # async fn create(&self) -> Result<Box<dyn Connection>, PoolError> { unimplemented!() }
862    /// }
863    ///
864    /// let config = PoolConfigBuilder::new()
865    ///     .max_size(10)
866    ///     .acquire_timeout(std::time::Duration::from_secs(30))
867    ///     .build();
868    /// let pool = Pool::new(config, Arc::new(MyFactory))?;
869    /// # Ok::<(), sz_orm_core::pool::PoolError>(())
870    /// ```
871    pub fn new(config: PoolConfig, factory: Arc<dyn ConnectionFactory>) -> Result<Self, PoolError> {
872        config.validate()?;
873        // v1.1.0 优化 2:容量固定为 max_size,total_count 已限制池中总连接数
874        // 先提取 max_size,避免 config 在结构体字面量中被 move 后再用
875        let max_size = config.max_size as usize;
876        let dynamic_max = config.max_size;
877        Ok(Self {
878            config,
879            factory,
880            idle: Arc::new(ArrayQueue::new(max_size)),
881            total_count: Arc::new(AtomicU32::new(0)),
882            closed: Arc::new(AtomicBool::new(false)),
883            notify: Arc::new(Notify::new()),
884            waiters_count: Arc::new(AtomicU32::new(0)),
885            dynamic_max_size: Arc::new(AtomicU32::new(dynamic_max)),
886            // #88 修复:默认断路器配置(5 次连续失败跳闸,30 秒后进入 HalfOpen)
887            // P1-4 修复:使用核心层 DefaultCircuitBreaker,而非 sz_orm_health::CircuitBreaker
888            #[cfg(feature = "circuit-breaker")]
889            circuit_breaker: Arc::new(PlMutex::new(DefaultCircuitBreaker::new(
890                5,
891                std::time::Duration::from_secs(30),
892            ))),
893            // #93 修复:默认无限流器(调用方通过 set_rate_limiter 配置)
894            // P1-4 修复:使用 parking_lot::RwLock,而非 std::sync::RwLock
895            #[cfg(feature = "rate-limit")]
896            rate_limiter: Arc::new(PlRwLock::new(None)),
897            #[cfg(feature = "rate-limit")]
898            rate_limit_key: "pool".to_string(),
899            #[cfg(feature = "tenant-quota-rls-enhanced")]
900            quota_enforcer: Arc::new(PlMutex::new(None)),
901            acquire_count: Arc::new(AtomicU64::new(0)),
902            acquire_failed_count: Arc::new(AtomicU64::new(0)),
903            acquire_wait_time_ns: Arc::new(AtomicU64::new(0)),
904            release_count: Arc::new(AtomicU64::new(0)),
905            connection_created_count: Arc::new(AtomicU64::new(0)),
906            connection_closed_count: Arc::new(AtomicU64::new(0)),
907        })
908    }
909
910    /// 异步构造连接池(v3.2.0 auto-prewarm)
911    ///
912    /// 当 `config.prewarm == true` 时,内部 await `prewarm()` 阻塞至预热完成。
913    /// 当 `config.prewarm == false` 时,等同 `Pool::new`(向后兼容)。
914    ///
915    /// 预热失败不阻断池创建(返回 Ok,日志含失败原因)。
916    pub async fn new_async(
917        config: PoolConfig,
918        factory: Arc<dyn ConnectionFactory>,
919    ) -> Result<Self, PoolError> {
920        let pool = Self::new(config, factory)?;
921        if pool.config.prewarm {
922            pool.prewarm().await;
923        }
924        Ok(pool)
925    }
926
927    /// 连接池预热(TASK-021)
928    ///
929    /// 当 `PoolConfig::prewarm` 为 `true` 时,调用此方法会立即建立 `min_idle` 个连接
930    /// 并放入空闲队列。预热失败不阻断池创建(仅记录 `tracing::warn!`)。
931    ///
932    /// **注意**:`Pool::new()` 是同步方法,无法内部执行异步预热。
933    /// 调用方需要在创建池后手动调用 `pool.prewarm().await`:
934    ///
935    /// ```ignore
936    /// let config = PoolConfig::default().with_prewarm(true).min_idle(5);
937    /// let pool = Pool::new(config, factory)?;
938    /// pool.prewarm().await; // 手动预热
939    /// // 此时池中已有 5 个连接
940    /// ```
941    ///
942    /// 预热后首次 `acquire()` 延迟 < 10ms(对比冷启动 < 100ms)。
943    pub async fn prewarm(&self) {
944        if !self.config.prewarm {
945            return;
946        }
947
948        let min_idle = self.config.min_idle as usize;
949        let mut warmed = 0;
950
951        for i in 0..min_idle {
952            // 检查池是否已关闭
953            if self.closed.load(Ordering::Acquire) {
954                break;
955            }
956
957            // 检查是否已达上限
958            let current_max = self.dynamic_max_size.load(Ordering::Acquire);
959            let current = self.total_count.load(Ordering::Acquire);
960            if current >= current_max {
961                break;
962            }
963
964            // 尝试递增 total_count
965            let created = loop {
966                let current = self.total_count.load(Ordering::Acquire);
967                if current >= current_max {
968                    break None;
969                }
970                match self.total_count.compare_exchange(
971                    current,
972                    current + 1,
973                    Ordering::SeqCst,
974                    Ordering::Acquire,
975                ) {
976                    Ok(_) => break Some(()),
977                    Err(_) => continue,
978                }
979            };
980
981            if created.is_some() {
982                match tokio::time::timeout(self.config.connection_timeout, self.factory.create())
983                    .await
984                {
985                    Ok(Ok(conn)) => {
986                        #[cfg(feature = "circuit-breaker")]
987                        {
988                            self.circuit_breaker.lock().record_success();
989                        }
990                        self.emit_event(PoolEvent::ConnectionCreated);
991                        let pooled = PooledConnection::new(conn, self.clone());
992                        // 放入空闲队列
993                        if self.idle.push(pooled).is_err() {
994                            // 队列满(不应该发生),关闭连接
995                            let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
996                            tracing::warn!(
997                                target: "sz_orm::pool::prewarm",
998                                "prewarm connection {} failed: idle queue full",
999                                i
1000                            );
1001                        } else {
1002                            warmed += 1;
1003                            self.notify.notify_one();
1004                        }
1005                    }
1006                    Ok(Err(e)) => {
1007                        let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1008                        #[cfg(feature = "circuit-breaker")]
1009                        {
1010                            self.circuit_breaker.lock().record_failure();
1011                        }
1012                        tracing::warn!(
1013                            target: "sz_orm::pool::prewarm",
1014                            "prewarm connection {} failed: {}",
1015                            i,
1016                            e
1017                        );
1018                    }
1019                    Err(_) => {
1020                        let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1021                        #[cfg(feature = "circuit-breaker")]
1022                        {
1023                            self.circuit_breaker.lock().record_failure();
1024                        }
1025                        tracing::warn!(
1026                            target: "sz_orm::pool::prewarm",
1027                            "prewarm connection {} timeout",
1028                            i
1029                        );
1030                    }
1031                }
1032            }
1033        }
1034
1035        if warmed > 0 {
1036            tracing::info!(
1037                target: "sz_orm::pool::prewarm",
1038                "pool prewarm completed: {}/{} connections established",
1039                warmed,
1040                min_idle
1041            );
1042        }
1043    }
1044
1045    /// 渐进式分批预热(v3.2.0 auto-prewarm)
1046    ///
1047    /// 分批创建连接,每批 `batch_size` 个,批间隔 `interval`,
1048    /// 总时间不超 `total_timeout`。每批后更新 `progress`。
1049    #[cfg(feature = "auto-prewarm")]
1050    pub async fn progressive_prewarm(
1051        &self,
1052        batch_size: u32,
1053        interval: std::time::Duration,
1054        total_timeout: std::time::Duration,
1055        progress: &crate::prewarm::PrewarmProgress,
1056    ) {
1057        use std::time::Instant;
1058
1059        let min_idle = self.config.min_idle;
1060        if min_idle == 0 || !self.config.prewarm {
1061            progress.mark_completed();
1062            return;
1063        }
1064
1065        let start = Instant::now();
1066        let batch = batch_size.max(1);
1067        let mut warmed_total: u32 = 0;
1068
1069        while warmed_total < min_idle {
1070            if start.elapsed() >= total_timeout {
1071                tracing::warn!(
1072                    target: "sz_orm::pool::prewarm",
1073                    "progressive prewarm timeout: {}/{} connections established",
1074                    warmed_total,
1075                    min_idle
1076                );
1077                break;
1078            }
1079
1080            if self.closed.load(Ordering::Acquire) {
1081                break;
1082            }
1083
1084            let remaining = min_idle - warmed_total;
1085            let this_batch = batch.min(remaining);
1086
1087            for _ in 0..this_batch {
1088                let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1089                let current = self.total_count.load(Ordering::Acquire);
1090                if current >= current_max {
1091                    break;
1092                }
1093
1094                let created = loop {
1095                    let current = self.total_count.load(Ordering::Acquire);
1096                    if current >= current_max {
1097                        break None;
1098                    }
1099                    match self.total_count.compare_exchange(
1100                        current,
1101                        current + 1,
1102                        Ordering::SeqCst,
1103                        Ordering::Acquire,
1104                    ) {
1105                        Ok(_) => break Some(()),
1106                        Err(_) => continue,
1107                    }
1108                };
1109
1110                if created.is_some() {
1111                    match tokio::time::timeout(
1112                        self.config.connection_timeout,
1113                        self.factory.create(),
1114                    )
1115                    .await
1116                    {
1117                        Ok(Ok(conn)) => {
1118                            #[cfg(feature = "circuit-breaker")]
1119                            {
1120                                self.circuit_breaker.lock().record_success();
1121                            }
1122                            self.emit_event(PoolEvent::ConnectionCreated);
1123                            let pooled = PooledConnection::new(conn, self.clone());
1124                            if self.idle.push(pooled).is_err() {
1125                                let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1126                                progress.record_failure();
1127                            } else {
1128                                progress.record_success();
1129                                warmed_total += 1;
1130                                self.notify.notify_one();
1131                            }
1132                        }
1133                        Ok(Err(_)) => {
1134                            let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1135                            progress.record_failure();
1136                            #[cfg(feature = "circuit-breaker")]
1137                            {
1138                                self.circuit_breaker.lock().record_failure();
1139                            }
1140                        }
1141                        Err(_) => {
1142                            let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1143                            progress.record_failure();
1144                            #[cfg(feature = "circuit-breaker")]
1145                            {
1146                                self.circuit_breaker.lock().record_failure();
1147                            }
1148                        }
1149                    }
1150                }
1151            }
1152
1153            if warmed_total < min_idle && interval > std::time::Duration::ZERO {
1154                tokio::time::sleep(interval).await;
1155            }
1156        }
1157
1158        progress.set_elapsed(start.elapsed());
1159        progress.mark_completed();
1160
1161        tracing::info!(
1162            target: "sz_orm::pool::prewarm",
1163            "progressive prewarm completed: {} warmed, {} failed, elapsed {:?}",
1164            progress.snapshot().warmed,
1165            progress.snapshot().failed,
1166            start.elapsed()
1167        );
1168    }
1169
1170    /// 获取配置
1171    pub fn config(&self) -> &PoolConfig {
1172        &self.config
1173    }
1174
1175    /// #88 修复:配置断路器(启用 `circuit-breaker` feature 时生效)
1176    ///
1177    /// 替换默认的断路器实例。调用此方法可自定义 `failure_threshold` 和 `reset_timeout`。
1178    ///
1179    /// # 示例
1180    ///
1181    /// ```ignore
1182    /// # use sz_orm_core::pool::{Pool, PoolConfig};
1183    /// # use std::time::Duration;
1184    /// # fn example(pool: &Pool) {
1185    /// pool.configure_circuit_breaker(10, Duration::from_secs(60));
1186    /// # }
1187    /// ```
1188    #[cfg(feature = "circuit-breaker")]
1189    pub fn configure_circuit_breaker(
1190        &self,
1191        failure_threshold: usize,
1192        reset_timeout: std::time::Duration,
1193    ) {
1194        let new_cb = DefaultCircuitBreaker::new(failure_threshold, reset_timeout);
1195        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1196        let mut guard = self.circuit_breaker.lock();
1197        *guard = new_cb;
1198    }
1199
1200    /// #88 修复:手动重置断路器到 Closed 状态
1201    ///
1202    /// 用于故障排除后手动恢复,无视当前 reset_timeout 是否到达。
1203    /// 返回是否实际发生了状态变更。
1204    #[cfg(feature = "circuit-breaker")]
1205    pub fn reset_circuit_breaker(&self) -> bool {
1206        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1207        let mut guard = self.circuit_breaker.lock();
1208        guard.reset()
1209    }
1210
1211    /// #88 修复:获取断路器当前状态
1212    #[cfg(feature = "circuit-breaker")]
1213    pub fn circuit_state(&self) -> CircuitState {
1214        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1215        let guard = self.circuit_breaker.lock();
1216        guard.state()
1217    }
1218
1219    /// #93 修复:配置限流器(启用 `rate-limit` feature 时生效)
1220    ///
1221    /// 替换当前的限流器实例。传入 `None` 可禁用限流。
1222    /// 默认限流 key 为 `"pool"`,可通过 `with_rate_limit_key` 修改。
1223    ///
1224    /// P1-4 修复:参数类型使用核心层 `crate::rate_limiter::RateLimiter` trait,
1225    /// 而非 `sz_orm_limit::RateLimiter`,消除反向依赖。
1226    /// sz-orm-limit 包的所有限流器实现均已实现此 trait。
1227    #[cfg(feature = "rate-limit")]
1228    pub fn set_rate_limiter(&self, limiter: Option<Arc<dyn RateLimiter>>) {
1229        // P1-4 修复:parking_lot::RwLock::write 直接返回 guard,无 PoisonError
1230        let mut guard = self.rate_limiter.write();
1231        *guard = limiter;
1232    }
1233
1234    /// #93 修复:设置限流 key(按用户/IP 维度限流时使用)
1235    #[cfg(feature = "rate-limit")]
1236    pub fn with_rate_limit_key(mut self, key: impl Into<String>) -> Self {
1237        self.rate_limit_key = key.into();
1238        self
1239    }
1240
1241    /// v4.7.0 REQ-V47-006:配置租户配额执行器(启用 `tenant-quota-rls-enhanced` feature 时生效)
1242    ///
1243    /// 替换当前的配额执行器实例。传入 `None` 可禁用配额检查。
1244    /// 配置后,`acquire_with_tenant` 会在获取连接前检查租户配额。
1245    #[cfg(feature = "tenant-quota-rls-enhanced")]
1246    pub fn set_quota_enforcer(&self, enforcer: Option<Arc<QuotaEnforcer>>) {
1247        let mut guard = self.quota_enforcer.lock();
1248        *guard = enforcer;
1249    }
1250
1251    /// v4.7.0 REQ-V47-006:按租户获取连接(启用 `tenant-quota-rls-enhanced` feature 时生效)
1252    ///
1253    /// 在 `acquire` 前检查租户连接配额,超限返回 `PoolError::Internal`。
1254    /// 配额检查通过后,记录使用量并调用 `acquire` 获取连接。
1255    /// 归还连接时通过 `release_with_tenant` 递减使用量。
1256    ///
1257    /// 若未配置 `QuotaEnforcer`(`set_quota_enforcer` 未调用或传入 `None`),
1258    /// 行为等同 `acquire`(无配额限制)。
1259    #[cfg(feature = "tenant-quota-rls-enhanced")]
1260    pub async fn acquire_with_tenant(
1261        &self,
1262        tenant_id: &str,
1263    ) -> Result<PooledConnection, PoolError> {
1264        {
1265            let guard = self.quota_enforcer.lock();
1266            if let Some(ref enforcer) = *guard {
1267                let current = enforcer.current_usage(tenant_id, QuotaResource::Connection);
1268                enforcer
1269                    .check_and_record(tenant_id, QuotaResource::Connection, 1)
1270                    .map_err(|e| PoolError::Internal(e.to_string()))?;
1271                let _ = current;
1272            }
1273        }
1274        self.acquire().await
1275    }
1276
1277    /// v4.7.0 REQ-V47-006:按租户归还连接(启用 `tenant-quota-rls-enhanced` feature 时生效)
1278    ///
1279    /// 递减租户连接使用量并归还连接到池中。
1280    /// 若未配置 `QuotaEnforcer`,行为等同 `release`。
1281    #[cfg(feature = "tenant-quota-rls-enhanced")]
1282    pub async fn release_with_tenant(&self, tenant_id: &str, pooled: PooledConnection) {
1283        {
1284            let guard = self.quota_enforcer.lock();
1285            if let Some(ref enforcer) = *guard {
1286                // 修复:此前传 0 导致配额只增不减(record_usage 为 += 语义),
1287                // 归还连接必须递减使用量(release_usage 饱和递减)
1288                enforcer.release_usage(tenant_id, QuotaResource::Connection, 1);
1289            }
1290        }
1291        self.release(pooled).await;
1292    }
1293
1294    /// 触发连接池事件回调
1295    fn emit_event(&self, event: PoolEvent) {
1296        // Prometheus 风格统计:连接创建事件统一在此计数
1297        // (所有创建路径均通过 emit_event(ConnectionCreated) 上报)
1298        if matches!(event, PoolEvent::ConnectionCreated) {
1299            self.connection_created_count
1300                .fetch_add(1, Ordering::Relaxed);
1301        }
1302        if let Some(ref callback) = self.config.on_event {
1303            callback(event);
1304        }
1305    }
1306
1307    /// 关闭连接并记录统计(统一入口)
1308    ///
1309    /// 所有连接关闭路径必须通过此方法,确保 `connection_closed_count`
1310    /// 与 `total_count` 递减的统计口径一致。
1311    async fn close_connection(&self, pooled: PooledConnection) {
1312        let mut pooled = pooled;
1313        let _ = pooled.conn.close().await;
1314        self.connection_closed_count.fetch_add(1, Ordering::Relaxed);
1315    }
1316
1317    /// 从池中获取连接(带超时)
1318    ///
1319    /// L-5 修复:补充示例文档
1320    ///
1321    /// 超时时间由 `PoolConfig::acquire_timeout` 控制,默认 30 秒。
1322    /// 若超时则返回 `PoolError::AcquireTimeout`。
1323    ///
1324    /// # 示例
1325    ///
1326    /// ```ignore
1327    /// # use sz_orm_core::pool::Pool;
1328    /// # async fn example(pool: &Pool) -> Result<(), Box<dyn std::error::Error>> {
1329    /// // 从池中获取连接
1330    /// let conn = pool.acquire().await?;
1331    /// // 使用连接执行查询...
1332    /// // conn.query("SELECT 1").await?;
1333    /// # Ok(())
1334    /// # }
1335    /// ```
1336    #[tracing::instrument(skip(self), fields(max_size = self.config.max_size, acquire_timeout = ?self.config.acquire_timeout))]
1337    pub async fn acquire(&self) -> Result<PooledConnection, PoolError> {
1338        // close_all 后拒绝新 acquire
1339        if self.closed.load(Ordering::Acquire) {
1340            self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1341            return Err(PoolError::Closed);
1342        }
1343
1344        // #88 修复:断路器检查(启用 circuit-breaker feature 时生效)
1345        // 当数据库连续失败超过阈值时,断路器跳闸,拒绝新 acquire 请求
1346        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1347        #[cfg(feature = "circuit-breaker")]
1348        {
1349            let mut guard = self.circuit_breaker.lock();
1350            if !guard.can_execute() {
1351                self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1352                return Err(PoolError::CircuitOpen);
1353            }
1354        }
1355
1356        // #93 修复:限流器检查(启用 rate-limit feature 时生效)
1357        // 在 acquire 前调用 try_acquire,被拒绝时返回 RateLimited
1358        // P1-4 修复:parking_lot::RwLock::read 直接返回 guard,无 PoisonError
1359        #[cfg(feature = "rate-limit")]
1360        {
1361            let guard = self.rate_limiter.read();
1362            if let Some(ref limiter) = *guard {
1363                match limiter.try_acquire(&self.rate_limit_key) {
1364                    Ok(result) if !result.allowed => {
1365                        self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1366                        return Err(PoolError::RateLimited {
1367                            remaining: result.remaining,
1368                            reset_at: result.reset_at,
1369                        });
1370                    }
1371                    Ok(_) => {} // 放行
1372                    Err(_) => {
1373                        // 限流器内部错误,保守放行(避免误杀)
1374                    }
1375                }
1376            }
1377        }
1378
1379        let deadline = Instant::now() + self.config.acquire_timeout;
1380        // 指数退避初始值(等待连接归还时的重试间隔)
1381        let mut backoff = Duration::from_millis(1);
1382        // 指数退避上限(避免等待者频繁唤醒消耗 CPU)
1383        const MAX_BACKOFF: Duration = Duration::from_millis(100);
1384
1385        loop {
1386            // v1.1.0 优化 2:从空闲连接中获取(无锁 pop)
1387            //
1388            // `ArrayQueue::pop()` 是单次 CAS 原子操作,无需 await Mutex 锁。
1389            // 仍保留 to_close Vec:检查过期/空闲过久/is_connected 失败的连接
1390            // 先收集到本地 Vec,循环结束后再批量 close(不在循环内 await)。
1391            let mut to_close: Vec<PooledConnection> = Vec::new();
1392            let acquired: Option<PooledConnection> = {
1393                let mut found: Option<PooledConnection> = None;
1394                while let Some(pooled) = self.idle.pop() {
1395                    // 检查连接是否过期
1396                    if pooled.is_expired(self.config.max_lifetime) {
1397                        to_close.push(pooled);
1398                        continue;
1399                    }
1400                    // 检查连接是否空闲过久
1401                    if pooled.is_idle_too_long(self.config.idle_timeout) {
1402                        to_close.push(pooled);
1403                        continue;
1404                    }
1405                    // 检查连接是否仍然连接
1406                    // 注意:is_connected() 是同步内存检查,不涉及 I/O
1407                    if !pooled.conn.is_connected() {
1408                        to_close.push(pooled);
1409                        continue;
1410                    }
1411                    found = Some(pooled);
1412                    break;
1413                }
1414                found
1415            };
1416
1417            // 批量 close 过期连接(不持任何锁)
1418            for pooled in to_close {
1419                self.close_connection(pooled).await;
1420                // v0.2.1 修复 P-1:AtomicU32 替代 Mutex<u32>
1421                self.total_count.fetch_sub(1, Ordering::SeqCst);
1422            }
1423
1424            if let Some(mut pooled) = acquired {
1425                // P1-1:test_before_acquire — 从空闲队列取出的连接先 ping 验证存活
1426                if self.config.test_before_acquire {
1427                    let ping_timeout = self.config.connection_timeout / 2;
1428                    let alive = match tokio::time::timeout(ping_timeout, pooled.conn.ping()).await {
1429                        Ok(true) => true,
1430                        Ok(false) => false,
1431                        Err(_) => false, // ping 超时,连接可能卡住
1432                    };
1433                    if !alive {
1434                        // ping 失败:关闭连接,回退计数,继续循环重新 acquire
1435                        self.close_connection(pooled).await;
1436                        self.total_count.fetch_sub(1, Ordering::SeqCst);
1437                        continue;
1438                    }
1439                }
1440                // 从 idle 获取的连接 pool 字段为 None(release 时清除),
1441                // 重新设置 pool 引用以支持 Drop 自动归还
1442                pooled.pool = Some(self.clone());
1443                self.acquire_count.fetch_add(1, Ordering::Relaxed);
1444                return Ok(pooled);
1445            }
1446
1447            // 尝试创建新连接
1448            // v0.2.1 修复 P-1:用 AtomicU32::compare_exchange 替代 Mutex<u32>
1449            // CAS 循环:先尝试递增 total_count,如果成功则创建连接
1450            // 使用 dynamic_max_size 以支持 resize 动态调整
1451            let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1452            let created = loop {
1453                let current = self.total_count.load(Ordering::Acquire);
1454                if current >= current_max {
1455                    break None; // 已达上限,不能创建
1456                }
1457                match self.total_count.compare_exchange(
1458                    current,
1459                    current + 1,
1460                    Ordering::SeqCst,
1461                    Ordering::Acquire,
1462                ) {
1463                    Ok(_) => break Some(()), // CAS 成功,可以创建
1464                    Err(_) => continue,      // 被其他线程抢先,重试
1465                }
1466            };
1467
1468            if created.is_some() {
1469                match tokio::time::timeout(self.config.connection_timeout, self.factory.create())
1470                    .await
1471                {
1472                    Ok(Ok(conn)) => {
1473                        // #88 修复:连接创建成功,记录到断路器
1474                        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1475                        #[cfg(feature = "circuit-breaker")]
1476                        {
1477                            self.circuit_breaker.lock().record_success();
1478                        }
1479                        self.emit_event(PoolEvent::ConnectionCreated);
1480                        self.emit_event(PoolEvent::ConnectionAcquired);
1481                        self.acquire_count.fetch_add(1, Ordering::Relaxed);
1482                        return Ok(PooledConnection::new(conn, self.clone()));
1483                    }
1484                    Ok(Err(e)) => {
1485                        // 创建失败,回退计数
1486                        self.total_count.fetch_sub(1, Ordering::SeqCst);
1487                        // #88 修复:连接创建失败,记录到断路器
1488                        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1489                        #[cfg(feature = "circuit-breaker")]
1490                        {
1491                            self.circuit_breaker.lock().record_failure();
1492                        }
1493                        self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1494                        return Err(PoolError::ConnectionFailed(e.to_string()));
1495                    }
1496                    Err(_) => {
1497                        // tokio::time::timeout 的 Err 必为超时
1498                        self.total_count.fetch_sub(1, Ordering::SeqCst);
1499                        // #88 修复:连接创建超时,记录到断路器
1500                        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1501                        #[cfg(feature = "circuit-breaker")]
1502                        {
1503                            self.circuit_breaker.lock().record_failure();
1504                        }
1505                        self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1506                        return Err(PoolError::Timeout);
1507                    }
1508                }
1509            }
1510
1511            // 等待连接释放或超时(带指数退避)
1512            let now = Instant::now();
1513            if now >= deadline {
1514                self.emit_event(PoolEvent::AcquireTimeout);
1515                self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1516                return Err(PoolError::Timeout);
1517            }
1518            // 增加等待者计数
1519            self.waiters_count.fetch_add(1, Ordering::SeqCst);
1520            let wait = std::cmp::min(backoff, deadline - now);
1521            match tokio::time::timeout(wait, self.notify.notified()).await {
1522                Ok(()) => {
1523                    // 收到通知,重置退避
1524                    backoff = Duration::from_millis(1);
1525                }
1526                Err(_) => {
1527                    // 本次等待超时,增加退避(指数增长,上限 MAX_BACKOFF)
1528                    backoff = std::cmp::min(backoff * 2, MAX_BACKOFF);
1529                }
1530            }
1531            // 减少等待者计数
1532            self.waiters_count.fetch_sub(1, Ordering::SeqCst);
1533            // Prometheus 风格统计:累计本次实际等待时长(纳秒)
1534            self.acquire_wait_time_ns
1535                .fetch_add(wait.as_nanos() as u64, Ordering::Relaxed);
1536        }
1537    }
1538
1539    /// 释放连接回池中
1540    /// 如果池已关闭或连接已断开,则直接关闭连接而不是放回池中。
1541    ///
1542    /// 接收 `PooledConnection` 以保留原始 `created_at`,避免 `max_lifetime`
1543    /// 在每次归还后被重置(Critical bug fix)。
1544    ///
1545    /// 显式调用 release 后,`pooled.pool` 设为 None,避免 Drop 重复归还。
1546    #[tracing::instrument(skip(self, pooled))]
1547    pub async fn release(&self, mut pooled: PooledConnection) {
1548        // 标记已显式归还,避免 Drop 重复归还
1549        pooled.pool = None;
1550        // Prometheus 风格统计:每次 release 调用计一次(含直接关闭路径)
1551        self.release_count.fetch_add(1, Ordering::Relaxed);
1552
1553        // 检查池是否已关闭
1554        if self.closed.load(Ordering::Acquire) {
1555            self.close_connection(pooled).await;
1556            // v0.2.1 修复 P-1:AtomicU32
1557            self.total_count.fetch_sub(1, Ordering::SeqCst);
1558            self.emit_event(PoolEvent::ConnectionClosed);
1559            return;
1560        }
1561
1562        // 检查连接是否仍然有效
1563        if !pooled.conn.is_connected() {
1564            self.close_connection(pooled).await;
1565            self.total_count.fetch_sub(1, Ordering::SeqCst);
1566            self.emit_event(PoolEvent::ConnectionClosed);
1567            return;
1568        }
1569
1570        // 更新 last_used_at(归还时间),但保留 created_at(原始创建时间)
1571        pooled.last_used_at = Instant::now();
1572
1573        // v1.1.0 优化 2:无锁 push 替换 Mutex<VecDeque>::push_back
1574        //
1575        // `ArrayQueue::push` 返回 `Result<(), T>`,失败表示队列满。
1576        // 正常情况下不会满(因为 `total_count` 限制了池中总连接数 ≤ max_size = 队列容量),
1577        // 但仍处理失败情况:取出所有权并关闭连接,避免连接泄漏。
1578        if let Err(rejected) = self.idle.push(pooled) {
1579            // 队列满(极端并发场景),关闭被拒绝的连接
1580            self.close_connection(rejected).await;
1581            self.total_count.fetch_sub(1, Ordering::SeqCst);
1582            self.emit_event(PoolEvent::ConnectionClosed);
1583        } else {
1584            self.emit_event(PoolEvent::ConnectionReleased);
1585        }
1586        self.notify.notify_one();
1587    }
1588
1589    /// 获取池状态
1590    ///
1591    /// v1.1.0 优化 2:`idle` 长度从 `Mutex::lock().await` 改为 `ArrayQueue::len()`
1592    /// (原子 load,无任何等待)。该方法保留 `async` 签名以兼容旧调用方。
1593    pub async fn status(&self) -> PoolStatus {
1594        let idle_count = self.idle.len() as u32;
1595        // v0.2.1 修复 P-1:AtomicU32
1596        let active = self.total_count.load(Ordering::Acquire);
1597        let waiters = self.waiters_count.load(Ordering::Acquire);
1598        PoolStatus {
1599            idle: idle_count,
1600            active,
1601            max: self.dynamic_max_size.load(Ordering::Acquire),
1602            min: self.config.min_idle,
1603            waiters,
1604        }
1605    }
1606
1607    /// 获取连接池累计统计指标(Prometheus 风格)
1608    ///
1609    /// 返回池生命周期内的累计计数,可通过监控系统(如 Prometheus 抓取)
1610    /// 观察连接池的健康状况与压力:
1611    ///
1612    /// - `acquire_count` / `acquire_failed_count`:获取成功率
1613    /// - `acquire_wait_time`:池满时等待的累计时长(配合 `average_acquire_wait_time()` 评估延迟)
1614    /// - `connection_created_count` / `connection_closed_count`:连接波动
1615    ///
1616    /// 计数基于无锁原子操作,调用开销可忽略。
1617    pub fn pool_metrics(&self) -> PoolMetrics {
1618        PoolMetrics {
1619            acquire_count: self.acquire_count.load(Ordering::Acquire),
1620            acquire_failed_count: self.acquire_failed_count.load(Ordering::Acquire),
1621            acquire_wait_time: Duration::from_nanos(
1622                self.acquire_wait_time_ns.load(Ordering::Acquire),
1623            ),
1624            release_count: self.release_count.load(Ordering::Acquire),
1625            connection_created_count: self.connection_created_count.load(Ordering::Acquire),
1626            connection_closed_count: self.connection_closed_count.load(Ordering::Acquire),
1627        }
1628    }
1629
1630    /// 观测层导出:Pool 指标 JSON 快照(v4.7.0 观测闭环——monitoring/grafana 数据源)
1631    ///
1632    /// 序列化 `pool_metrics()` 为 JSON,供运行时遥测/监控告警消费。
1633    /// 例:`curl` 轮询 + Grafana 面板,或 cron 告警阈值判断。
1634    pub fn metrics_snapshot_json(&self) -> String {
1635        serde_json::to_string(&self.pool_metrics()).unwrap_or_else(|_| "{}".to_string())
1636    }
1637
1638    /// 回收空闲过久的连接
1639    #[tracing::instrument(skip(self))]
1640    pub async fn reap_idle(&self) {
1641        // v1.1.0 优化 2:使用 `ArrayQueue::pop` 循环取出所有连接,过滤后再 push 回去。
1642        // 无锁操作,无需 `Mutex::lock().await`。
1643        // 1. 取出所有空闲连接到本地 Vec
1644        let mut all: Vec<PooledConnection> = Vec::new();
1645        while let Some(pooled) = self.idle.pop() {
1646            all.push(pooled);
1647        }
1648
1649        // 2. 分类:保留 vs 关闭
1650        let mut to_close = Vec::new();
1651        for pooled in all {
1652            if pooled.is_idle_too_long(self.config.idle_timeout)
1653                || pooled.is_expired(self.config.max_lifetime)
1654            {
1655                to_close.push(pooled);
1656            } else {
1657                // push 回队列(容量足够,因为之前刚从这里 pop 出来)
1658                if let Err(rejected) = self.idle.push(pooled) {
1659                    self.close_connection(rejected).await;
1660                    self.total_count.fetch_sub(1, Ordering::SeqCst);
1661                }
1662            }
1663        }
1664
1665        // 3. 关闭过期连接
1666        for pooled in to_close {
1667            self.close_connection(pooled).await;
1668            // v0.2.1 修复 P-1:AtomicU32 替代 Mutex<u32>
1669            self.total_count.fetch_sub(1, Ordering::SeqCst);
1670        }
1671    }
1672
1673    /// 关闭所有空闲连接,并标记池为已关闭
1674    /// 注意:已借出未归还的连接不受影响,但归还时会被直接关闭;
1675    /// 同时 close_all 后的新 acquire 也会被拒绝。
1676    pub async fn close_all(&self) {
1677        // 标记为已关闭,阻止新 acquire/release
1678        self.closed.store(true, Ordering::Release);
1679        // v1.1.0 优化 2:使用 `ArrayQueue::pop` 循环取出所有空闲连接(无锁)。
1680        // 先收集到本地 Vec,再批量 close(不在循环内 await)。
1681        let mut to_close: Vec<PooledConnection> = Vec::new();
1682        while let Some(pooled) = self.idle.pop() {
1683            to_close.push(pooled);
1684        }
1685        // 批量 close(不持任何锁)
1686        let closed_count: u32 = to_close.len() as u32;
1687        for pooled in to_close {
1688            self.close_connection(pooled).await;
1689        }
1690        // 减少总连接计数(只减去已关闭的空闲连接数)
1691        // v0.2.1 修复 P-1:AtomicU32 替代 Mutex<u32>
1692        self.total_count.fetch_sub(closed_count, Ordering::SeqCst);
1693    }
1694
1695    /// M-7 修复:连接池健康检查(heartbeat)
1696    ///
1697    /// 对所有空闲连接执行 `ping()`,移除已断开或 ping 失败的连接。
1698    /// 调用方应定期调用此方法(如每 60 秒),以清理失效连接。
1699    ///
1700    /// # 返回值
1701    ///
1702    /// 返回被移除的连接数。
1703    ///
1704    /// # 注意
1705    ///
1706    /// - v1.1.0 优化 2 后:使用无锁 `ArrayQueue`,不再持 `Mutex` 锁。
1707    ///   仍可能在 ping 期间阻塞 acquire(因为连接已被取出),但不再阻塞 release。
1708    /// - 仅检查空闲连接,不影响已借出的连接
1709    /// - 对于大量空闲连接,可能产生较多并发 ping,建议在低峰期执行
1710    pub async fn health_check(&self) -> u32 {
1711        // v1.1.0 优化 2:使用 `ArrayQueue::pop` 收集所有空闲连接(无锁)
1712        let mut to_check: Vec<PooledConnection> = Vec::new();
1713        while let Some(pooled) = self.idle.pop() {
1714            to_check.push(pooled);
1715        }
1716
1717        let mut removed: u32 = 0;
1718        let mut alive: Vec<PooledConnection> = Vec::with_capacity(to_check.len());
1719        for mut pooled in to_check.drain(..) {
1720            // 先检查 is_connected(同步内存检查),再 ping(异步网络检查)
1721            if !pooled.conn.is_connected() {
1722                self.close_connection(pooled).await;
1723                removed += 1;
1724                continue;
1725            }
1726            // ping 超时设置为 connection_timeout 的一半,避免长时间阻塞
1727            let ping_timeout = self.config.connection_timeout / 2;
1728            match tokio::time::timeout(ping_timeout, pooled.conn.ping()).await {
1729                Ok(true) => alive.push(pooled),
1730                Ok(false) => {
1731                    // ping 返回 false,连接失效
1732                    self.close_connection(pooled).await;
1733                    removed += 1;
1734                }
1735                Err(_) => {
1736                    // ping 超时,连接可能卡住
1737                    self.close_connection(pooled).await;
1738                    removed += 1;
1739                }
1740            }
1741        }
1742
1743        // 将存活连接放回池中(无锁 push)
1744        let alive_count: u32 = alive.len() as u32;
1745        for pooled in alive {
1746            // push 回队列(容量足够,因为之前刚从这里 pop 出来)
1747            if let Err(rejected) = self.idle.push(pooled) {
1748                self.close_connection(rejected).await;
1749                removed += 1;
1750            }
1751        }
1752
1753        // 更新总连接计数
1754        if removed > 0 {
1755            self.total_count.fetch_sub(removed, Ordering::SeqCst);
1756        }
1757
1758        // 通知等待的 acquire 有连接可用
1759        if alive_count > 0 {
1760            self.notify.notify_one();
1761        }
1762
1763        removed
1764    }
1765
1766    /// 优雅停机:关闭所有空闲连接,等待所有在途连接归还
1767    ///
1768    /// 1. 标记池为已关闭(拒绝新 acquire)
1769    /// 2. 通知所有等待者(让 acquire 等待者立即返回 Closed 错误)
1770    /// 3. 关闭所有空闲连接(立即释放,避免 wait 阶段无意义等待)
1771    /// 4. 等待在途(已借出)连接归还(带 30 秒超时)
1772    pub async fn shutdown(&self) {
1773        self.shutdown_with_timeout(Duration::from_secs(30)).await;
1774    }
1775
1776    /// 优雅停机(可配置超时):关闭所有空闲连接,等待所有在途连接归还
1777    ///
1778    /// 与 [`shutdown`] 行为一致,但超时时间可配置。超时后强制关闭,
1779    /// 输出告警日志含强制关闭的连接数。
1780    ///
1781    /// # 参数
1782    /// - `timeout`:等待在途连接归还的最大时间
1783    pub async fn shutdown_with_timeout(&self, timeout: Duration) {
1784        // 1. 标记为关闭状态(幂等:重复调用直接返回)
1785        if self.closed.swap(true, Ordering::SeqCst) {
1786            return;
1787        }
1788        // 2. 通知所有等待者
1789        self.notify.notify_waiters();
1790        // 3. 关闭所有空闲连接
1791        self.close_all().await;
1792        // 4. 等待在途连接归还(带超时)
1793        let deadline = Instant::now() + timeout;
1794        while self.total_count.load(Ordering::SeqCst) > 0 {
1795            if Instant::now() >= deadline {
1796                let remaining = self.total_count.load(Ordering::SeqCst);
1797                if remaining > 0 {
1798                    eprintln!(
1799                        "graceful shutdown timeout, {} connections force closed",
1800                        remaining
1801                    );
1802                }
1803                break;
1804            }
1805            tokio::time::sleep(Duration::from_millis(100)).await;
1806        }
1807    }
1808
1809    /// 动态调整连接池最大容量(resize 的别名,接受 usize)
1810    ///
1811    /// 简化实现:仅更新动态 max_size 值,在 acquire 时检查新值。
1812    /// - 如果 new_max 大于当前值,允许创建更多连接(受 ArrayQueue 容量限制:
1813    ///   超出原始 max_size 的空闲连接会在 release 时因队列满而被关闭)
1814    /// - 如果 new_max 小于当前值,不立即关闭多余连接,但阻止新连接创建
1815    ///   (多余连接会在 release/reap_idle 时自然回收)
1816    pub fn resize(&self, new_max: usize) {
1817        self.set_max_size(new_max as u32);
1818    }
1819
1820    /// 动态调整连接池最大容量
1821    pub fn set_max_size(&self, new_max: u32) {
1822        self.dynamic_max_size.store(new_max, Ordering::SeqCst);
1823    }
1824
1825    /// 获取当前动态 max_size
1826    pub fn max_size(&self) -> u32 {
1827        self.dynamic_max_size.load(Ordering::Acquire)
1828    }
1829
1830    /// 预热连接池:创建指定数量的连接放入空闲队列
1831    ///
1832    /// 不会超过 `dynamic_max_size` 上限。创建失败时停止预热并返回 Ok。
1833    pub async fn warmup(&self, min_idle: usize) -> Result<(), PoolError> {
1834        for _ in 0..min_idle {
1835            let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1836            let current = self.total_count.load(Ordering::Acquire);
1837            if current >= current_max {
1838                break;
1839            }
1840            // CAS 递增计数器,避免并发 warmup/acquire 超过 max_size
1841            match self.total_count.compare_exchange(
1842                current,
1843                current + 1,
1844                Ordering::SeqCst,
1845                Ordering::Acquire,
1846            ) {
1847                Ok(_) => {}
1848                Err(_) => continue, // 并发竞争,跳过本次
1849            }
1850            match self.factory.create().await {
1851                Ok(conn) => {
1852                    let now = Instant::now();
1853                    let pooled = PooledConnection {
1854                        conn,
1855                        created_at: now,
1856                        last_used_at: now,
1857                        pool: None,
1858                    };
1859                    if let Err(rejected) = self.idle.push(pooled) {
1860                        // 队列满(不应发生,因为 total_count 限制了),关闭并递减
1861                        self.close_connection(rejected).await;
1862                        self.total_count.fetch_sub(1, Ordering::SeqCst);
1863                    }
1864                    self.emit_event(PoolEvent::ConnectionCreated);
1865                }
1866                Err(_) => {
1867                    // 创建失败,回退计数器并停止预热
1868                    self.total_count.fetch_sub(1, Ordering::SeqCst);
1869                    break;
1870                }
1871            }
1872        }
1873        Ok(())
1874    }
1875
1876    /// 带超时的查询执行
1877    ///
1878    /// 强制 `query_timeout` 配置生效:使用 `tokio::time::timeout` 包裹
1879    /// `conn.query(sql)`,超时返回 `DbError::QueryError`。未配置时使用 30 秒默认值。
1880    pub async fn query_with_timeout(&self, sql: &str) -> Result<QueryRows, crate::DbError> {
1881        let timeout = self.config.query_timeout.unwrap_or(Duration::from_secs(30));
1882        let mut conn = self.acquire().await.map_err(crate::DbError::PoolError)?;
1883        tokio::time::timeout(timeout, conn.query(sql))
1884            .await
1885            .map_err(|_| crate::DbError::QueryError(format!("Query timeout after {:?}", timeout)))?
1886    }
1887}
1888
1889// ============================================================================
1890// v3.8.0: 连接池生产配置(prod-pool-tuning feature)
1891// ============================================================================
1892
1893#[cfg(feature = "prod-pool-tuning")]
1894mod pool_prod {
1895    use super::PoolConfig;
1896    use serde::{Deserialize, Serialize};
1897    use std::time::Duration;
1898
1899    /// 连接池生产配置错误
1900    #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
1901    pub enum PoolProdError {
1902        /// max_size 非正
1903        #[error("pool max_size must be positive")]
1904        MaxSizeNotPositive,
1905        /// acquire_timeout 非正
1906        #[error("pool acquire_timeout must be positive")]
1907        AcquireTimeoutNotPositive,
1908        /// min_idle 超过 max_size
1909        #[error("pool min_idle cannot exceed max_size")]
1910        MinIdleExceedsMaxSize,
1911    }
1912
1913    /// 连接池生产配置:包装既有 PoolConfig,提供生产配置加载入口
1914    #[derive(Debug, Clone, Serialize, Deserialize)]
1915    pub struct PoolProdConfig {
1916        /// 最大连接数
1917        pub max_size: u32,
1918        /// 获取连接超时
1919        pub acquire_timeout: Duration,
1920        /// 空闲超时
1921        pub idle_timeout: Duration,
1922        /// 连接建立超时
1923        pub connection_timeout: Duration,
1924        /// 查询超时
1925        pub query_timeout: Duration,
1926        /// 最小空闲连接数
1927        pub min_idle: u32,
1928        /// 是否预热
1929        pub prewarm: bool,
1930    }
1931
1932    impl Default for PoolProdConfig {
1933        fn default() -> Self {
1934            Self {
1935                max_size: 100,
1936                acquire_timeout: Duration::from_secs(30),
1937                idle_timeout: Duration::from_secs(600),
1938                connection_timeout: Duration::from_secs(10),
1939                query_timeout: Duration::from_secs(30),
1940                min_idle: 0,
1941                prewarm: false,
1942            }
1943        }
1944    }
1945
1946    impl PoolProdConfig {
1947        /// 创建配置
1948        pub fn new(
1949            max_size: u32,
1950            acquire_timeout: Duration,
1951            idle_timeout: Duration,
1952            connection_timeout: Duration,
1953            query_timeout: Duration,
1954            min_idle: u32,
1955            prewarm: bool,
1956        ) -> Self {
1957            Self {
1958                max_size,
1959                acquire_timeout,
1960                idle_timeout,
1961                connection_timeout,
1962                query_timeout,
1963                min_idle,
1964                prewarm,
1965            }
1966        }
1967
1968        /// 校验参数合理性
1969        pub fn validate(&self) -> Result<(), PoolProdError> {
1970            if self.max_size == 0 {
1971                return Err(PoolProdError::MaxSizeNotPositive);
1972            }
1973            if self.acquire_timeout.is_zero() {
1974                return Err(PoolProdError::AcquireTimeoutNotPositive);
1975            }
1976            if self.min_idle > self.max_size {
1977                return Err(PoolProdError::MinIdleExceedsMaxSize);
1978            }
1979            Ok(())
1980        }
1981
1982        /// 转换为既有 PoolConfig
1983        pub fn to_pool_config(&self) -> PoolConfig {
1984            PoolConfig {
1985                max_size: self.max_size,
1986                min_idle: self.min_idle,
1987                acquire_timeout: self.acquire_timeout,
1988                idle_timeout: self.idle_timeout,
1989                max_lifetime: Duration::from_secs(1800),
1990                connection_timeout: self.connection_timeout,
1991                tls: None,
1992                query_timeout: Some(self.query_timeout),
1993                max_rows: None,
1994                memory_limit: None,
1995                on_event: None,
1996                test_before_acquire: false,
1997                prewarm: self.prewarm,
1998            }
1999        }
2000    }
2001}
2002
2003#[cfg(feature = "prod-pool-tuning")]
2004pub use pool_prod::{PoolProdConfig, PoolProdError};
2005
2006// ============================================================================
2007// v3.8.0: 连接泄漏检测(prod-leak-detection feature)
2008// ============================================================================
2009
2010#[cfg(feature = "prod-leak-detection")]
2011mod leak_detection {
2012    use serde::{Deserialize, Serialize};
2013    use std::time::Duration;
2014
2015    /// 连接泄漏检测配置
2016    #[derive(Debug, Clone, Serialize, Deserialize)]
2017    pub struct LeakDetectionConfig {
2018        /// 是否启用
2019        pub enabled: bool,
2020        /// 检测间隔
2021        pub interval: Duration,
2022        /// 泄漏阈值
2023        pub threshold: u32,
2024        /// 借用超时
2025        pub borrow_timeout: Duration,
2026    }
2027
2028    impl Default for LeakDetectionConfig {
2029        fn default() -> Self {
2030            Self {
2031                enabled: false,
2032                interval: Duration::from_secs(60),
2033                threshold: 5,
2034                borrow_timeout: Duration::from_secs(60),
2035            }
2036        }
2037    }
2038
2039    impl LeakDetectionConfig {
2040        /// 创建配置
2041        pub fn new(
2042            enabled: bool,
2043            interval: Duration,
2044            threshold: u32,
2045            borrow_timeout: Duration,
2046        ) -> Self {
2047            Self {
2048                enabled,
2049                interval,
2050                threshold,
2051                borrow_timeout,
2052            }
2053        }
2054
2055        /// 验证配置合法性
2056        pub fn validate(&self) -> Result<(), LeakDetectionError> {
2057            if self.interval.is_zero() {
2058                return Err(LeakDetectionError::IntervalNotPositive);
2059            }
2060            if self.borrow_timeout.is_zero() {
2061                return Err(LeakDetectionError::BorrowTimeoutNotPositive);
2062            }
2063            Ok(())
2064        }
2065    }
2066
2067    /// 泄漏检测错误
2068    #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
2069    pub enum LeakDetectionError {
2070        /// 检测间隔非正
2071        #[error("leak detection interval must be positive")]
2072        IntervalNotPositive,
2073        /// 借用超时非正
2074        #[error("leak detection borrow_timeout must be positive")]
2075        BorrowTimeoutNotPositive,
2076    }
2077
2078    /// 泄漏条目
2079    #[derive(Debug, Clone, Serialize, Deserialize)]
2080    pub struct LeakEntry {
2081        /// 连接 ID
2082        pub conn_id: u64,
2083        /// 借用时间戳
2084        pub borrowed_at: String,
2085        /// 借用时长
2086        pub borrow_duration: Duration,
2087    }
2088
2089    /// 泄漏报告
2090    #[derive(Debug, Clone, Serialize, Deserialize)]
2091    pub struct LeakReport {
2092        /// 当前借用数
2093        pub borrowed_count: u32,
2094        /// 最大借用时长
2095        pub max_borrow_duration: Duration,
2096        /// 疑似泄漏列表
2097        pub suspected_leaks: Vec<LeakEntry>,
2098    }
2099
2100    impl LeakReport {
2101        /// 创建空报告
2102        pub fn empty() -> Self {
2103            Self {
2104                borrowed_count: 0,
2105                max_borrow_duration: Duration::ZERO,
2106                suspected_leaks: vec![],
2107            }
2108        }
2109    }
2110}
2111
2112#[cfg(feature = "prod-leak-detection")]
2113pub use leak_detection::{LeakDetectionConfig, LeakDetectionError, LeakEntry, LeakReport};
2114
2115#[cfg(test)]
2116mod tests {
2117    use super::*;
2118
2119    /// 测试用的模拟连接
2120    struct MockConnection {
2121        connected: bool,
2122    }
2123
2124    impl MockConnection {
2125        fn new() -> Self {
2126            Self { connected: true }
2127        }
2128    }
2129
2130    impl Connection for MockConnection {
2131        fn execute<'a>(
2132            &'a mut self,
2133            _sql: &'a str,
2134        ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
2135            Box::pin(async move { Ok(1) })
2136        }
2137
2138        fn query<'a>(
2139            &'a mut self,
2140            _sql: &'a str,
2141        ) -> Pin<
2142            Box<
2143                dyn Future<
2144                        Output = Result<
2145                            Vec<std::collections::HashMap<String, crate::value::Value>>,
2146                            crate::DbError,
2147                        >,
2148                    > + Send
2149                    + 'a,
2150            >,
2151        > {
2152            Box::pin(async move { Ok(vec![]) })
2153        }
2154
2155        fn begin_transaction<'a>(
2156            &'a mut self,
2157        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2158            Box::pin(async move { Ok(()) })
2159        }
2160
2161        fn commit<'a>(
2162            &'a mut self,
2163        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2164            Box::pin(async move { Ok(()) })
2165        }
2166
2167        fn rollback<'a>(
2168            &'a mut self,
2169        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2170            Box::pin(async move { Ok(()) })
2171        }
2172
2173        fn is_connected(&self) -> bool {
2174            self.connected
2175        }
2176
2177        fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
2178            Box::pin(async move { true })
2179        }
2180
2181        fn close<'a>(
2182            &'a mut self,
2183        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2184            Box::pin(async move {
2185                self.connected = false;
2186                Ok(())
2187            })
2188        }
2189    }
2190
2191    struct MockConnectionFactory;
2192
2193    #[async_trait]
2194    impl ConnectionFactory for MockConnectionFactory {
2195        async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
2196            Ok(Box::new(MockConnection::new()))
2197        }
2198    }
2199
2200    #[tokio::test]
2201    async fn test_pool_config_builder() -> Result<(), Box<dyn std::error::Error>> {
2202        let config = PoolConfigBuilder::new().max_size(50).min_idle(10).build()?;
2203
2204        assert_eq!(config.max_size, 50);
2205        assert_eq!(config.min_idle, 10);
2206        Ok(())
2207    }
2208
2209    #[test]
2210    fn test_pool_status_display() {
2211        let status = PoolStatus {
2212            idle: 5,
2213            active: 10,
2214            max: 100,
2215            min: 5,
2216            waiters: 0,
2217        };
2218
2219        let display = format!("{:?}", status);
2220        assert!(display.contains("idle"));
2221        assert!(display.contains("active"));
2222    }
2223
2224    #[test]
2225    fn test_default_pool_config() {
2226        let config = PoolConfig::default();
2227        assert_eq!(config.max_size, 100);
2228        assert_eq!(config.min_idle, 0);
2229        assert_eq!(config.acquire_timeout.as_secs(), 30);
2230        assert_eq!(config.idle_timeout.as_secs(), 600);
2231        assert_eq!(config.max_lifetime.as_secs(), 1800);
2232    }
2233
2234    #[tokio::test]
2235    async fn test_pool_config_clone() {
2236        let config = PoolConfig::default();
2237        let cloned = config.clone();
2238        assert_eq!(cloned.max_size, config.max_size);
2239        assert_eq!(cloned.min_idle, config.min_idle);
2240    }
2241
2242    #[test]
2243    fn test_pool_config_builder_default() -> Result<(), Box<dyn std::error::Error>> {
2244        let builder = PoolConfigBuilder::new();
2245        let config = builder.build()?;
2246        assert_eq!(config.max_size, 100);
2247        Ok(())
2248    }
2249
2250    #[test]
2251    fn test_pool_config_validate() {
2252        let result = PoolConfigBuilder::new().max_size(0).build();
2253        assert!(result.is_err());
2254
2255        let result = PoolConfigBuilder::new().max_size(10).min_idle(20).build();
2256        assert!(result.is_err());
2257    }
2258
2259    #[test]
2260    fn test_pool_config_validate_duration_upper_bound() {
2261        use std::time::Duration;
2262
2263        // u64::MAX 秒应被拒绝(远超 u32::MAX 上限)
2264        let config = PoolConfig {
2265            max_size: 10,
2266            min_idle: 1,
2267            acquire_timeout: Duration::from_secs(u64::MAX),
2268            idle_timeout: Duration::from_secs(1),
2269            max_lifetime: Duration::from_secs(1),
2270            connection_timeout: Duration::from_secs(5),
2271            tls: None,
2272            query_timeout: None,
2273            max_rows: None,
2274            memory_limit: None,
2275            on_event: None,
2276            test_before_acquire: false,
2277            prewarm: false,
2278        };
2279        assert!(config.validate().is_err());
2280
2281        // u32::MAX 秒(≈136 年)恰好在上限内,应通过
2282        let config = PoolConfig {
2283            max_size: 10,
2284            min_idle: 1,
2285            acquire_timeout: Duration::from_secs(u32::MAX as u64),
2286            idle_timeout: Duration::from_secs(1),
2287            max_lifetime: Duration::from_secs(1),
2288            connection_timeout: Duration::from_secs(5),
2289            tls: None,
2290            query_timeout: None,
2291            max_rows: None,
2292            memory_limit: None,
2293            on_event: None,
2294            test_before_acquire: false,
2295            prewarm: false,
2296        };
2297        assert!(config.validate().is_ok());
2298
2299        // u32::MAX + 1 秒应被拒绝
2300        let config = PoolConfig {
2301            max_size: 10,
2302            min_idle: 1,
2303            acquire_timeout: Duration::from_secs(u32::MAX as u64 + 1),
2304            idle_timeout: Duration::from_secs(1),
2305            max_lifetime: Duration::from_secs(1),
2306            connection_timeout: Duration::from_secs(5),
2307            tls: None,
2308            query_timeout: None,
2309            max_rows: None,
2310            memory_limit: None,
2311            on_event: None,
2312            test_before_acquire: false,
2313            prewarm: false,
2314        };
2315        assert!(config.validate().is_err());
2316    }
2317
2318    #[test]
2319    fn test_pool_config_test_before_acquire_default() {
2320        // P1-1:test_before_acquire 默认关闭
2321        let config = PoolConfig::default();
2322        assert!(!config.test_before_acquire);
2323    }
2324
2325    #[test]
2326    fn test_pool_config_builder_test_before_acquire() {
2327        // P1-1:builder 设置 test_before_acquire
2328        let config = PoolConfigBuilder::new()
2329            .test_before_acquire(true)
2330            .build()
2331            .unwrap();
2332        assert!(config.test_before_acquire);
2333    }
2334
2335    #[tokio::test]
2336    async fn test_pool_acquire_and_release() -> Result<(), Box<dyn std::error::Error>> {
2337        let config = PoolConfigBuilder::new().max_size(5).min_idle(1).build()?;
2338        let factory = Arc::new(MockConnectionFactory);
2339        let pool = Pool::new(config, factory)?;
2340
2341        let conn = pool.acquire().await?;
2342        let status = pool.status().await;
2343        assert_eq!(status.active, 1);
2344        assert_eq!(status.idle, 0);
2345
2346        pool.release(conn).await;
2347        let status = pool.status().await;
2348        assert_eq!(status.idle, 1);
2349
2350        // 再次获取应该复用空闲连接
2351        let _conn2 = pool.acquire().await?;
2352        let status = pool.status().await;
2353        assert_eq!(status.idle, 0);
2354        Ok(())
2355    }
2356
2357    #[tokio::test]
2358    async fn test_pool_status() -> Result<(), Box<dyn std::error::Error>> {
2359        let config = PoolConfigBuilder::new().max_size(10).min_idle(2).build()?;
2360        let factory = Arc::new(MockConnectionFactory);
2361        let pool = Pool::new(config, factory)?;
2362
2363        let status = pool.status().await;
2364        assert_eq!(status.max, 10);
2365        assert_eq!(status.min, 2);
2366        assert_eq!(status.active, 0);
2367        Ok(())
2368    }
2369
2370    #[tokio::test]
2371    async fn test_pool_close_all() -> Result<(), Box<dyn std::error::Error>> {
2372        let config = PoolConfigBuilder::new().max_size(5).build()?;
2373        let factory = Arc::new(MockConnectionFactory);
2374        let pool = Pool::new(config, factory)?;
2375
2376        // 创建几个连接然后释放
2377        let conn1 = pool.acquire().await?;
2378        let conn2 = pool.acquire().await?;
2379        pool.release(conn1).await;
2380        pool.release(conn2).await;
2381
2382        pool.close_all().await;
2383        let status = pool.status().await;
2384        assert_eq!(status.idle, 0);
2385        assert_eq!(status.active, 0);
2386        Ok(())
2387    }
2388
2389    #[tokio::test]
2390    async fn test_pool_reap_idle() -> Result<(), Box<dyn std::error::Error>> {
2391        let config = PoolConfigBuilder::new()
2392            .max_size(5)
2393            .idle_timeout(0) // 立即超时
2394            .build()?;
2395        let factory = Arc::new(MockConnectionFactory);
2396        let pool = Pool::new(config, factory)?;
2397
2398        let conn = pool.acquire().await?;
2399        pool.release(conn).await;
2400
2401        // 等待一下确保空闲超时
2402        tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
2403
2404        pool.reap_idle().await;
2405        let status = pool.status().await;
2406        assert_eq!(status.idle, 0);
2407        Ok(())
2408    }
2409
2410    /// H-7 验证:acquire_timeout 默认 30s
2411    ///
2412    /// PoolConfig::default().acquire_timeout == 30s
2413    /// Pool::acquire() 内部使用 `deadline = Instant::now() + acquire_timeout`
2414    /// 超时后返回 `PoolError::Timeout`。
2415    #[tokio::test]
2416    async fn test_h7_acquire_timeout_default_30s() {
2417        let config = PoolConfig::default();
2418        assert_eq!(
2419            config.acquire_timeout,
2420            Duration::from_secs(30),
2421            "H-7: acquire_timeout 默认应为 30s"
2422        );
2423    }
2424
2425    /// H-7 验证:acquire_timeout 可通过 builder 配置
2426    #[tokio::test]
2427    async fn test_h7_acquire_timeout_configurable() -> Result<(), Box<dyn std::error::Error>> {
2428        let config = PoolConfigBuilder::new()
2429            .max_size(1)
2430            .acquire_timeout(5) // 5s
2431            .build()?;
2432        assert_eq!(config.acquire_timeout, Duration::from_secs(5));
2433
2434        // 创建 max_size=1 的池,acquire 一个连接(占满),第二次 acquire 应超时
2435        let factory = Arc::new(MockConnectionFactory);
2436        let pool = Pool::new(config, factory)?;
2437        let _conn1 = pool.acquire().await?;
2438
2439        // 第二次 acquire 应在 5s 后超时(这里用 1ms 超时配置加速测试)
2440        let fast_config = PoolConfigBuilder::new()
2441            .max_size(1)
2442            .acquire_timeout(0) // 立即超时(0s 超时;deadline 为 now)
2443            .build()?;
2444        // 注意:acquire_timeout(0) 是合法值,表示 deadline 为 now
2445        // 实际行为:第一次循环即检查 deadline,返回 Timeout
2446        let fast_pool = Pool::new(fast_config, Arc::new(MockConnectionFactory))?;
2447        let _fast_conn = fast_pool.acquire().await?; // 占满 max_size=1
2448        let result = fast_pool.acquire().await;
2449        assert!(
2450            matches!(result, Err(PoolError::Timeout)),
2451            "H-7: 应返回 Timeout"
2452        );
2453        Ok(())
2454    }
2455
2456    // ==================== M-7 健康检查测试 ====================
2457
2458    #[tokio::test]
2459    async fn test_m7_health_check_removes_nothing_when_all_healthy(
2460    ) -> Result<(), Box<dyn std::error::Error>> {
2461        // 所有连接健康时,health_check 应返回 0
2462        let config = PoolConfigBuilder::new().max_size(5).build()?;
2463        let factory = Arc::new(MockConnectionFactory);
2464        let pool = Pool::new(config, factory)?;
2465
2466        // 创建 3 个连接并归还到池中
2467        let conn1 = pool.acquire().await?;
2468        let conn2 = pool.acquire().await?;
2469        let conn3 = pool.acquire().await?;
2470        pool.release(conn1).await;
2471        pool.release(conn2).await;
2472        pool.release(conn3).await;
2473
2474        let removed = pool.health_check().await;
2475        assert_eq!(removed, 0, "Healthy connections should not be removed");
2476
2477        let status = pool.status().await;
2478        assert_eq!(status.idle, 3);
2479        assert_eq!(status.active, 3);
2480        Ok(())
2481    }
2482
2483    #[tokio::test]
2484    async fn test_m7_health_check_returns_zero_for_empty_pool(
2485    ) -> Result<(), Box<dyn std::error::Error>> {
2486        let config = PoolConfigBuilder::new().max_size(5).build()?;
2487        let factory = Arc::new(MockConnectionFactory);
2488        let pool = Pool::new(config, factory)?;
2489
2490        let removed = pool.health_check().await;
2491        assert_eq!(removed, 0);
2492        Ok(())
2493    }
2494
2495    // ==================== 生产 Bug 复现测试 ====================
2496
2497    /// 可追踪创建次数的连接工厂
2498    struct CountingFactory {
2499        count: AtomicU32,
2500    }
2501
2502    impl CountingFactory {
2503        fn new() -> Self {
2504            Self {
2505                count: AtomicU32::new(0),
2506            }
2507        }
2508        fn created_count(&self) -> u32 {
2509            self.count.load(Ordering::SeqCst)
2510        }
2511    }
2512
2513    #[async_trait]
2514    impl ConnectionFactory for CountingFactory {
2515        async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
2516            self.count.fetch_add(1, Ordering::SeqCst);
2517            Ok(Box::new(MockConnection::new()))
2518        }
2519    }
2520
2521    /// 生产 Bug 复现:release() 重置 created_at 导致连接永不过期
2522    ///
2523    /// 症状:生产环境运行 30 分钟后间歇性 "connection timeout"
2524    /// 根因:release() 中 created_at 被重置为 now(),max_lifetime 检查永远不触发
2525    /// 期望:超过 max_lifetime 的连接应被回收并创建新连接
2526    #[tokio::test]
2527    async fn test_production_bug_max_lifetime_never_expires(
2528    ) -> Result<(), Box<dyn std::error::Error>> {
2529        // 注意:PoolConfigBuilder::max_lifetime() 接受秒,这里需要毫秒级精度
2530        // 所以直接构造 PoolConfig
2531        let config = PoolConfig {
2532            max_size: 5,
2533            min_idle: 0,
2534            acquire_timeout: Duration::from_secs(30),
2535            idle_timeout: Duration::from_secs(600),
2536            max_lifetime: Duration::from_millis(100), // 100ms
2537            connection_timeout: Duration::from_secs(10),
2538            tls: None,
2539            query_timeout: None,
2540            max_rows: None,
2541            memory_limit: None,
2542            on_event: None,
2543            test_before_acquire: false,
2544            prewarm: false,
2545        };
2546        let factory = Arc::new(CountingFactory::new());
2547        let pool = Pool::new(config, factory.clone())?;
2548
2549        // 1. 创建连接
2550        let conn = pool.acquire().await?;
2551        assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
2552
2553        // 2. 归还连接(bug:重置 created_at)
2554        pool.release(conn).await;
2555
2556        // 3. 等待超过 max_lifetime
2557        tokio::time::sleep(Duration::from_millis(150)).await;
2558
2559        // 4. 再次获取 — 应检测到连接过期,创建新连接
2560        let conn2 = pool.acquire().await?;
2561
2562        // 5. 验证:如果 bug 存在,factory.created_count() 仍为 1(连接被复用,未过期)
2563        //         如果修复,factory.created_count() 应为 2(旧连接过期,创建新连接)
2564        assert_eq!(
2565            factory.created_count(),
2566            2,
2567            "超过 max_lifetime 后应创建新连接(旧连接应被回收)"
2568        );
2569
2570        pool.release(conn2).await;
2571        Ok(())
2572    }
2573
2574    // ==================== PooledConnection::Drop 自动归还测试 ====================
2575
2576    /// 验证 PooledConnection drop 时自动归还连接到池
2577    ///
2578    /// 修复前:PooledConnection 未实现 Drop,drop 时连接丢失,池耗尽
2579    /// 修复后:Drop 时 spawn 异步 release,连接自动归还
2580    #[tokio::test]
2581    async fn test_drop_auto_release_connection() -> Result<(), Box<dyn std::error::Error>> {
2582        let config = PoolConfigBuilder::new().max_size(2).build()?;
2583        let factory = Arc::new(CountingFactory::new());
2584        let pool = Pool::new(config, factory.clone())?;
2585
2586        // 1. acquire 一个连接(不显式 release)
2587        {
2588            let _conn = pool.acquire().await?;
2589            assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
2590            let status = pool.status().await;
2591            assert_eq!(status.active, 1, "active 应为 1");
2592            assert_eq!(status.idle, 0, "idle 应为 0");
2593            // _conn 在此 drop
2594        }
2595
2596        // 2. 等待 Drop spawn 的异步 release 完成
2597        tokio::time::sleep(Duration::from_millis(50)).await;
2598
2599        // 3. 验证连接已自动归还到 idle 队列
2600        let status = pool.status().await;
2601        assert_eq!(status.idle, 1, "Drop 后连接应自动归还,idle 应为 1");
2602        assert_eq!(status.active, 1, "total_count 应为 1");
2603        assert_eq!(factory.created_count(), 1, "应复用归还的连接,不创建新连接");
2604        Ok(())
2605    }
2606
2607    /// 验证 Drop 自动归还后,连接可被再次 acquire 复用
2608    #[tokio::test]
2609    async fn test_drop_auto_release_then_reuse() -> Result<(), Box<dyn std::error::Error>> {
2610        let config = PoolConfigBuilder::new().max_size(1).build()?;
2611        let factory = Arc::new(CountingFactory::new());
2612        let pool = Pool::new(config, factory.clone())?;
2613
2614        // max_size=1,如果 Drop 不归还,第二次 acquire 会超时
2615        {
2616            let _conn = pool.acquire().await?;
2617        }
2618
2619        // 等待 Drop spawn 的 release 完成
2620        tokio::time::sleep(Duration::from_millis(50)).await;
2621
2622        // 再次 acquire 应复用归还的连接,不创建新连接
2623        let conn = pool.acquire().await?;
2624        assert_eq!(factory.created_count(), 1, "应复用归还的连接,不创建新连接");
2625
2626        pool.release(conn).await;
2627        Ok(())
2628    }
2629
2630    /// 验证 into_inner 后 Drop 不归还(连接被消费)
2631    #[tokio::test]
2632    async fn test_into_inner_does_not_return_to_pool() -> Result<(), Box<dyn std::error::Error>> {
2633        let config = PoolConfigBuilder::new().max_size(2).build()?;
2634        let factory = Arc::new(CountingFactory::new());
2635        let pool = Pool::new(config, factory.clone())?;
2636
2637        let conn = pool.acquire().await?;
2638        assert_eq!(factory.created_count(), 1);
2639
2640        // into_inner 消费连接,pool 字段设为 None
2641        let _raw_conn = conn.into_inner();
2642
2643        // 等待一段时间,确保不会有 Drop spawn
2644        tokio::time::sleep(Duration::from_millis(50)).await;
2645
2646        let status = pool.status().await;
2647        assert_eq!(status.idle, 0, "into_inner 后连接不应归还");
2648        assert_eq!(status.active, 1, "total_count 仍为 1(连接被外部持有)");
2649        Ok(())
2650    }
2651
2652    /// 验证显式 release 后 Drop 不会重复归还
2653    #[tokio::test]
2654    async fn test_explicit_release_no_double_return() -> Result<(), Box<dyn std::error::Error>> {
2655        let config = PoolConfigBuilder::new().max_size(2).build()?;
2656        let factory = Arc::new(CountingFactory::new());
2657        let pool = Pool::new(config, factory.clone())?;
2658
2659        let conn = pool.acquire().await?;
2660        pool.release(conn).await;
2661
2662        let status = pool.status().await;
2663        assert_eq!(status.idle, 1, "release 后 idle 应为 1");
2664
2665        // 再次 acquire + release 验证不会重复
2666        let conn = pool.acquire().await?;
2667        pool.release(conn).await;
2668
2669        let status = pool.status().await;
2670        assert_eq!(status.idle, 1, "再次 release 后 idle 仍应为 1(不重复)");
2671        assert_eq!(status.active, 1, "total_count 应为 1");
2672        Ok(())
2673    }
2674
2675    // ========================================================================
2676    // G-SX-4:query_stream 游标流式查询测试
2677    // ========================================================================
2678
2679    /// 带预设行数据的模拟连接,用于测试 `query_stream` 默认实现。
2680    struct CursorMockConn {
2681        rows: QueryRows,
2682        call_count: usize,
2683    }
2684
2685    impl CursorMockConn {
2686        fn new(rows: QueryRows) -> Self {
2687            Self {
2688                rows,
2689                call_count: 0,
2690            }
2691        }
2692    }
2693
2694    impl Connection for CursorMockConn {
2695        fn execute<'a>(
2696            &'a mut self,
2697            _sql: &'a str,
2698        ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
2699            Box::pin(async move { Ok(1) })
2700        }
2701
2702        fn query<'a>(
2703            &'a mut self,
2704            _sql: &'a str,
2705        ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
2706            Box::pin(async move {
2707                self.call_count += 1;
2708                Ok(self.rows.clone())
2709            })
2710        }
2711
2712        fn begin_transaction<'a>(
2713            &'a mut self,
2714        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2715            Box::pin(async move { Ok(()) })
2716        }
2717
2718        fn commit<'a>(
2719            &'a mut self,
2720        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2721            Box::pin(async move { Ok(()) })
2722        }
2723
2724        fn rollback<'a>(
2725            &'a mut self,
2726        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2727            Box::pin(async move { Ok(()) })
2728        }
2729
2730        fn is_connected(&self) -> bool {
2731            true
2732        }
2733
2734        fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
2735            Box::pin(async move { true })
2736        }
2737
2738        fn close<'a>(
2739            &'a mut self,
2740        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2741            Box::pin(async move { Ok(()) })
2742        }
2743    }
2744
2745    /// 模拟游标适配器:覆盖 `query_stream` 以逐行 yield,而非全量收集。
2746    struct CursorOverrideMockConn {
2747        rows: Vec<crate::value::Value>,
2748        yielded: usize,
2749    }
2750
2751    impl CursorOverrideMockConn {
2752        fn new(rows: Vec<crate::value::Value>) -> Self {
2753            Self { rows, yielded: 0 }
2754        }
2755    }
2756
2757    impl Connection for CursorOverrideMockConn {
2758        fn execute<'a>(
2759            &'a mut self,
2760            _sql: &'a str,
2761        ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
2762            Box::pin(async move { Ok(1) })
2763        }
2764
2765        fn query<'a>(
2766            &'a mut self,
2767            _sql: &'a str,
2768        ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
2769            // 全量收集实现(不应被 cursor override 调用)
2770            Box::pin(async move {
2771                Ok(self
2772                    .rows
2773                    .iter()
2774                    .map(|v| {
2775                        let mut m = std::collections::HashMap::new();
2776                        m.insert("v".to_string(), v.clone());
2777                        m
2778                    })
2779                    .collect())
2780            })
2781        }
2782
2783        /// G-SX-4:覆盖 query_stream,逐行 yield 模拟真游标
2784        fn query_stream<'a>(
2785            &'a mut self,
2786            _sql: &'a str,
2787        ) -> Pin<Box<dyn futures::Stream<Item = QueryStreamItem> + Send + 'a>> {
2788            Box::pin(futures::stream::iter(
2789                self.rows
2790                    .iter()
2791                    .enumerate()
2792                    .map(|(i, v)| {
2793                        self.yielded = i + 1;
2794                        let mut m = std::collections::HashMap::new();
2795                        m.insert("v".to_string(), v.clone());
2796                        Ok(m)
2797                    })
2798                    .collect::<Vec<_>>(),
2799            ))
2800        }
2801
2802        fn begin_transaction<'a>(
2803            &'a mut self,
2804        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2805            Box::pin(async move { Ok(()) })
2806        }
2807
2808        fn commit<'a>(
2809            &'a mut self,
2810        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2811            Box::pin(async move { Ok(()) })
2812        }
2813
2814        fn rollback<'a>(
2815            &'a mut self,
2816        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2817            Box::pin(async move { Ok(()) })
2818        }
2819
2820        fn is_connected(&self) -> bool {
2821            true
2822        }
2823
2824        fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
2825            Box::pin(async move { true })
2826        }
2827
2828        fn close<'a>(
2829            &'a mut self,
2830        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2831            Box::pin(async move { Ok(()) })
2832        }
2833    }
2834
2835    /// G-SX-4 测试 1:默认 query_stream 逐行 yield 全量结果
2836    #[tokio::test]
2837    async fn test_query_stream_default_impl_yields_all_rows() {
2838        use futures::StreamExt;
2839        let rows: QueryRows = vec![
2840            std::collections::HashMap::from([
2841                ("id".to_string(), crate::value::Value::I64(1)),
2842                (
2843                    "name".to_string(),
2844                    crate::value::Value::String("alice".to_string()),
2845                ),
2846            ]),
2847            std::collections::HashMap::from([
2848                ("id".to_string(), crate::value::Value::I64(2)),
2849                (
2850                    "name".to_string(),
2851                    crate::value::Value::String("bob".to_string()),
2852                ),
2853            ]),
2854            std::collections::HashMap::from([
2855                ("id".to_string(), crate::value::Value::I64(3)),
2856                (
2857                    "name".to_string(),
2858                    crate::value::Value::String("carol".to_string()),
2859                ),
2860            ]),
2861        ];
2862        let mut conn = CursorMockConn::new(rows);
2863        let mut stream = conn.query_stream("SELECT id, name FROM users");
2864        let mut received: Vec<QueryStreamItem> = Vec::new();
2865        while let Some(item) = stream.next().await {
2866            received.push(item);
2867        }
2868        assert_eq!(received.len(), 3, "应收到 3 行");
2869        assert!(received.iter().all(|r| r.is_ok()), "所有项应为 Ok");
2870        drop(stream);
2871        assert_eq!(conn.call_count, 1, "默认实现应调用 query() 一次");
2872    }
2873
2874    /// G-SX-4 测试 2:默认 query_stream 空结果集
2875    #[tokio::test]
2876    async fn test_query_stream_default_empty_result() {
2877        use futures::StreamExt;
2878        let mut conn = CursorMockConn::new(Vec::new());
2879        let mut stream = conn.query_stream("SELECT * FROM empty_table");
2880        let mut count = 0;
2881        while let Some(_item) = stream.next().await {
2882            count += 1;
2883        }
2884        assert_eq!(count, 0, "空结果集应产生 0 项");
2885    }
2886
2887    /// G-SX-4 测试 3:默认 query_stream 错误传播
2888    #[tokio::test]
2889    async fn test_query_stream_default_error_propagation() {
2890        use futures::StreamExt;
2891        // 创建一个会返回错误的 mock
2892        struct ErrorMockConn;
2893        impl Connection for ErrorMockConn {
2894            fn execute<'a>(
2895                &'a mut self,
2896                _sql: &'a str,
2897            ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>>
2898            {
2899                Box::pin(async move { Ok(1) })
2900            }
2901            fn query<'a>(
2902                &'a mut self,
2903                _sql: &'a str,
2904            ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>>
2905            {
2906                Box::pin(async move { Err(crate::DbError::Internal("query failed".to_string())) })
2907            }
2908            fn begin_transaction<'a>(
2909                &'a mut self,
2910            ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2911                Box::pin(async move { Ok(()) })
2912            }
2913            fn commit<'a>(
2914                &'a mut self,
2915            ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2916                Box::pin(async move { Ok(()) })
2917            }
2918            fn rollback<'a>(
2919                &'a mut self,
2920            ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2921                Box::pin(async move { Ok(()) })
2922            }
2923            fn is_connected(&self) -> bool {
2924                true
2925            }
2926            fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
2927                Box::pin(async move { true })
2928            }
2929            fn close<'a>(
2930                &'a mut self,
2931            ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2932                Box::pin(async move { Ok(()) })
2933            }
2934        }
2935        let mut conn = ErrorMockConn;
2936        let mut stream = conn.query_stream("SELECT * FROM bad_table");
2937        let item = stream.next().await;
2938        assert!(item.is_some(), "应产生一项");
2939        assert!(item.unwrap().is_err(), "该项应为 Err");
2940    }
2941
2942    /// G-SX-4 测试 4:覆盖 query_stream 的适配器逐行 yield(模拟真游标)
2943    #[tokio::test]
2944    async fn test_query_stream_override_yields_rows_one_by_one() {
2945        use futures::StreamExt;
2946        let rows = vec![
2947            crate::value::Value::I64(10),
2948            crate::value::Value::I64(20),
2949            crate::value::Value::I64(30),
2950            crate::value::Value::I64(40),
2951            crate::value::Value::I64(50),
2952        ];
2953        let mut conn = CursorOverrideMockConn::new(rows);
2954        let values: Vec<i64> = {
2955            let mut stream = conn.query_stream("SELECT v FROM seq");
2956            let mut vals: Vec<i64> = Vec::new();
2957            while let Some(Ok(row)) = stream.next().await {
2958                if let crate::value::Value::I64(v) = row.get("v").unwrap() {
2959                    vals.push(*v);
2960                }
2961            }
2962            vals
2963        };
2964        assert_eq!(values, vec![10, 20, 30, 40, 50], "应按顺序收到全部 5 行");
2965        assert_eq!(conn.yielded, 5, "应逐行 yield 5 次(真游标覆盖)");
2966    }
2967
2968    /// G-SX-4 测试 5:覆盖 query_stream 提前 drop 流(消费者中断)
2969    #[tokio::test]
2970    async fn test_query_stream_override_early_drop() {
2971        use futures::StreamExt;
2972        let rows = vec![
2973            crate::value::Value::I64(1),
2974            crate::value::Value::I64(2),
2975            crate::value::Value::I64(3),
2976        ];
2977        let mut conn = CursorOverrideMockConn::new(rows);
2978        {
2979            let mut stream = conn.query_stream("SELECT v FROM seq");
2980            let first = stream.next().await;
2981            assert!(first.is_some(), "第一项应存在");
2982            // 提前 drop stream — 模拟消费者中断
2983            drop(stream);
2984        }
2985        // 连接仍可用
2986        assert!(conn.is_connected(), "提前 drop 流后连接仍应可用");
2987    }
2988
2989    /// TASK-021:连接池预热测试
2990    #[tokio::test]
2991    async fn test_pool_prewarm() -> Result<(), Box<dyn std::error::Error>> {
2992        use std::sync::atomic::AtomicU32;
2993
2994        // 创建可计数的连接工厂
2995        let create_count = Arc::new(AtomicU32::new(0));
2996        let create_count_clone = create_count.clone();
2997
2998        struct CountingFactory {
2999            count: Arc<AtomicU32>,
3000        }
3001
3002        #[async_trait]
3003        impl ConnectionFactory for CountingFactory {
3004            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3005                self.count.fetch_add(1, Ordering::SeqCst);
3006                Ok(Box::new(MockConnection::new()))
3007            }
3008        }
3009
3010        // 配置:max_size=10, min_idle=5, prewarm=true
3011        let config = PoolConfigBuilder::new()
3012            .max_size(10)
3013            .min_idle(5)
3014            .prewarm(true)
3015            .build()?;
3016
3017        let factory = Arc::new(CountingFactory {
3018            count: create_count_clone,
3019        });
3020
3021        let pool = Pool::new(config, factory)?;
3022
3023        // 预热前:空闲连接为 0
3024        let status_before = pool.status().await;
3025        assert_eq!(status_before.idle, 0, "预热前 idle 应为 0");
3026
3027        // 执行预热
3028        pool.prewarm().await;
3029
3030        // 预热后:空闲连接应 >= min_idle(5)
3031        let status_after = pool.status().await;
3032        assert!(
3033            status_after.idle >= 5,
3034            "预热后 idle 应 >= 5,实际: {}",
3035            status_after.idle
3036        );
3037
3038        // 验证工厂被调用了 5 次(min_idle)
3039        assert_eq!(
3040            create_count.load(Ordering::SeqCst),
3041            5,
3042            "工厂应被调用 5 次(min_idle)"
3043        );
3044
3045        Ok(())
3046    }
3047
3048    /// TASK-021:预热失败不阻断池创建
3049    #[tokio::test]
3050    async fn test_pool_prewarm_failure_non_blocking() -> Result<(), Box<dyn std::error::Error>> {
3051        use std::sync::atomic::AtomicBool;
3052
3053        struct FailingFactory {
3054            failed: Arc<AtomicBool>,
3055        }
3056
3057        #[async_trait]
3058        impl ConnectionFactory for FailingFactory {
3059            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3060                self.failed.store(true, Ordering::SeqCst);
3061                // 模拟连接失败
3062                Err(crate::DbError::Internal(
3063                    "simulated connection failure".to_string(),
3064                ))
3065            }
3066        }
3067
3068        let failed = Arc::new(AtomicBool::new(false));
3069        let mut config = PoolConfigBuilder::new()
3070            .max_size(10)
3071            .min_idle(3)
3072            .prewarm(true)
3073            .build()?;
3074        config.connection_timeout = std::time::Duration::from_secs(1); // 缩短超时以加快测试
3075
3076        let factory = Arc::new(FailingFactory {
3077            failed: failed.clone(),
3078        });
3079
3080        // 池创建应成功(即使预热失败)
3081        let pool = Pool::new(config, factory)?;
3082        pool.prewarm().await; // 预热失败不应 panic
3083
3084        // 验证工厂被调用了 3 次(尝试预热 3 个连接)
3085        assert!(failed.load(Ordering::SeqCst), "工厂应被调用且失败");
3086
3087        // 池仍然可用(acquire 会尝试创建新连接)
3088        let status = pool.status().await;
3089        assert_eq!(status.max, 10, "池配置应正常");
3090
3091        Ok(())
3092    }
3093
3094    /// TASK-021:prewarm=false 时预热不执行
3095    #[tokio::test]
3096    async fn test_pool_prewarm_disabled() -> Result<(), Box<dyn std::error::Error>> {
3097        use std::sync::atomic::AtomicU32;
3098
3099        let create_count = Arc::new(AtomicU32::new(0));
3100        let create_count_clone = create_count.clone();
3101
3102        struct CountingFactory {
3103            count: Arc<AtomicU32>,
3104        }
3105
3106        #[async_trait]
3107        impl ConnectionFactory for CountingFactory {
3108            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3109                self.count.fetch_add(1, Ordering::SeqCst);
3110                Ok(Box::new(MockConnection::new()))
3111            }
3112        }
3113
3114        // 配置:prewarm=false
3115        let config = PoolConfigBuilder::new()
3116            .max_size(10)
3117            .min_idle(5)
3118            .prewarm(false) // 禁用预热
3119            .build()?;
3120
3121        let factory = Arc::new(CountingFactory {
3122            count: create_count_clone,
3123        });
3124
3125        let pool = Pool::new(config, factory)?;
3126        pool.prewarm().await; // 应直接返回,不创建连接
3127
3128        // 验证工厂未被调用
3129        assert_eq!(
3130            create_count.load(Ordering::SeqCst),
3131            0,
3132            "prewarm=false 时工厂不应被调用"
3133        );
3134
3135        let status = pool.status().await;
3136        assert_eq!(status.idle, 0, "idle 应为 0");
3137
3138        Ok(())
3139    }
3140
3141    /// v3.2.0:Pool::new_async with prewarm=true 预热后 idle >= min_idle
3142    #[tokio::test]
3143    async fn test_pool_new_async_with_prewarm() -> Result<(), Box<dyn std::error::Error>> {
3144        use std::sync::atomic::AtomicU32;
3145
3146        let create_count = Arc::new(AtomicU32::new(0));
3147        let create_count_clone = create_count.clone();
3148
3149        struct CountingFactory {
3150            count: Arc<AtomicU32>,
3151        }
3152
3153        #[async_trait]
3154        impl ConnectionFactory for CountingFactory {
3155            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3156                self.count.fetch_add(1, Ordering::SeqCst);
3157                Ok(Box::new(MockConnection::new()))
3158            }
3159        }
3160
3161        let config = PoolConfigBuilder::new()
3162            .max_size(10)
3163            .min_idle(5)
3164            .prewarm(true)
3165            .build()?;
3166
3167        let factory = Arc::new(CountingFactory {
3168            count: create_count_clone,
3169        });
3170
3171        let pool = Pool::new_async(config, factory).await?;
3172
3173        let status = pool.status().await;
3174        assert!(
3175            status.idle >= 5,
3176            "new_async prewarm=true 后 idle 应 >= 5,实际: {}",
3177            status.idle
3178        );
3179        assert_eq!(create_count.load(Ordering::SeqCst), 5, "工厂应被调用 5 次");
3180
3181        Ok(())
3182    }
3183
3184    /// v3.2.0:Pool::new_async with prewarm=false 等同 Pool::new
3185    #[tokio::test]
3186    async fn test_pool_new_async_without_prewarm() -> Result<(), Box<dyn std::error::Error>> {
3187        use std::sync::atomic::AtomicU32;
3188
3189        let create_count = Arc::new(AtomicU32::new(0));
3190        let create_count_clone = create_count.clone();
3191
3192        struct CountingFactory {
3193            count: Arc<AtomicU32>,
3194        }
3195
3196        #[async_trait]
3197        impl ConnectionFactory for CountingFactory {
3198            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3199                self.count.fetch_add(1, Ordering::SeqCst);
3200                Ok(Box::new(MockConnection::new()))
3201            }
3202        }
3203
3204        let config = PoolConfigBuilder::new()
3205            .max_size(10)
3206            .min_idle(5)
3207            .prewarm(false)
3208            .build()?;
3209
3210        let factory = Arc::new(CountingFactory {
3211            count: create_count_clone,
3212        });
3213
3214        let pool = Pool::new_async(config, factory).await?;
3215
3216        let status = pool.status().await;
3217        assert_eq!(status.idle, 0, "prewarm=false 时 idle 应为 0");
3218        assert_eq!(create_count.load(Ordering::SeqCst), 0, "工厂不应被调用");
3219
3220        Ok(())
3221    }
3222
3223    /// v3.2.0:Pool::new_async 预热失败不阻断池创建
3224    #[tokio::test]
3225    async fn test_pool_new_async_failure_non_blocking() -> Result<(), Box<dyn std::error::Error>> {
3226        struct FailingFactory;
3227
3228        #[async_trait]
3229        impl ConnectionFactory for FailingFactory {
3230            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3231                Err(crate::DbError::Internal("simulated failure".to_string()))
3232            }
3233        }
3234
3235        let mut config = PoolConfigBuilder::new()
3236            .max_size(10)
3237            .min_idle(3)
3238            .prewarm(true)
3239            .build()?;
3240        config.connection_timeout = std::time::Duration::from_secs(1);
3241
3242        let pool = Pool::new_async(config, Arc::new(FailingFactory)).await?;
3243
3244        let status = pool.status().await;
3245        assert_eq!(status.max, 10, "池配置应正常");
3246
3247        Ok(())
3248    }
3249
3250    /// v3.2.0:progressive_prewarm 分批建连
3251    #[cfg(feature = "auto-prewarm")]
3252    #[tokio::test]
3253    async fn test_pool_progressive_prewarm() -> Result<(), Box<dyn std::error::Error>> {
3254        use std::sync::atomic::AtomicU32;
3255
3256        let create_count = Arc::new(AtomicU32::new(0));
3257        let create_count_clone = create_count.clone();
3258
3259        struct CountingFactory {
3260            count: Arc<AtomicU32>,
3261        }
3262
3263        #[async_trait]
3264        impl ConnectionFactory for CountingFactory {
3265            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3266                self.count.fetch_add(1, Ordering::SeqCst);
3267                Ok(Box::new(MockConnection::new()))
3268            }
3269        }
3270
3271        let config = PoolConfigBuilder::new()
3272            .max_size(20)
3273            .min_idle(6)
3274            .prewarm(true)
3275            .build()?;
3276
3277        let factory = Arc::new(CountingFactory {
3278            count: create_count_clone,
3279        });
3280
3281        let pool = Pool::new(config, factory)?;
3282
3283        let progress = crate::prewarm::PrewarmProgress::new(6);
3284        pool.progressive_prewarm(
3285            2,
3286            std::time::Duration::from_millis(5),
3287            std::time::Duration::from_secs(10),
3288            &progress,
3289        )
3290        .await;
3291
3292        let snap = progress.snapshot();
3293        assert!(
3294            snap.warmed >= 6,
3295            "progressive_prewarm 后 warmed 应 >= 6,实际: {}",
3296            snap.warmed
3297        );
3298        assert!(snap.is_completed, "应标记完成");
3299        assert_eq!(create_count.load(Ordering::SeqCst), 6, "工厂应被调用 6 次");
3300
3301        let status = pool.status().await;
3302        assert!(status.idle >= 6, "池中 idle 应 >= 6");
3303
3304        Ok(())
3305    }
3306
3307    /// v3.2.0:progressive_prewarm total_timeout=0 立即停止
3308    #[cfg(feature = "auto-prewarm")]
3309    #[tokio::test]
3310    async fn test_pool_progressive_prewarm_timeout_zero() -> Result<(), Box<dyn std::error::Error>>
3311    {
3312        use std::sync::atomic::AtomicU32;
3313
3314        let create_count = Arc::new(AtomicU32::new(0));
3315        let create_count_clone = create_count.clone();
3316
3317        struct CountingFactory {
3318            count: Arc<AtomicU32>,
3319        }
3320
3321        #[async_trait]
3322        impl ConnectionFactory for CountingFactory {
3323            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3324                self.count.fetch_add(1, Ordering::SeqCst);
3325                Ok(Box::new(MockConnection::new()))
3326            }
3327        }
3328
3329        let config = PoolConfigBuilder::new()
3330            .max_size(20)
3331            .min_idle(10)
3332            .prewarm(true)
3333            .build()?;
3334
3335        let factory = Arc::new(CountingFactory {
3336            count: create_count_clone,
3337        });
3338
3339        let pool = Pool::new(config, factory)?;
3340
3341        let progress = crate::prewarm::PrewarmProgress::new(10);
3342        pool.progressive_prewarm(
3343            2,
3344            std::time::Duration::from_millis(5),
3345            std::time::Duration::ZERO,
3346            &progress,
3347        )
3348        .await;
3349
3350        let snap = progress.snapshot();
3351        assert!(snap.is_completed, "应标记完成");
3352        assert!(
3353            snap.warmed <= 2,
3354            "total_timeout=0 时最多建一批(batch_size=2),实际: {}",
3355            snap.warmed
3356        );
3357
3358        Ok(())
3359    }
3360
3361    /// v3.2.0:progressive_prewarm prewarm=false 时直接返回
3362    #[cfg(feature = "auto-prewarm")]
3363    #[tokio::test]
3364    async fn test_pool_progressive_prewarm_disabled() -> Result<(), Box<dyn std::error::Error>> {
3365        use std::sync::atomic::AtomicU32;
3366
3367        let create_count = Arc::new(AtomicU32::new(0));
3368        let create_count_clone = create_count.clone();
3369
3370        struct CountingFactory {
3371            count: Arc<AtomicU32>,
3372        }
3373
3374        #[async_trait]
3375        impl ConnectionFactory for CountingFactory {
3376            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3377                self.count.fetch_add(1, Ordering::SeqCst);
3378                Ok(Box::new(MockConnection::new()))
3379            }
3380        }
3381
3382        let config = PoolConfigBuilder::new()
3383            .max_size(20)
3384            .min_idle(10)
3385            .prewarm(false)
3386            .build()?;
3387
3388        let factory = Arc::new(CountingFactory {
3389            count: create_count_clone,
3390        });
3391
3392        let pool = Pool::new(config, factory)?;
3393
3394        let progress = crate::prewarm::PrewarmProgress::new(10);
3395        pool.progressive_prewarm(
3396            2,
3397            std::time::Duration::from_millis(5),
3398            std::time::Duration::from_secs(10),
3399            &progress,
3400        )
3401        .await;
3402
3403        let snap = progress.snapshot();
3404        assert!(snap.is_completed, "应标记完成");
3405        assert_eq!(snap.warmed, 0, "prewarm=false 时不应建连");
3406        assert_eq!(create_count.load(Ordering::SeqCst), 0, "工厂不应被调用");
3407
3408        Ok(())
3409    }
3410
3411    /// v3.2.0:progressive_prewarm 失败不阻断(failing factory)
3412    #[cfg(feature = "auto-prewarm")]
3413    #[tokio::test]
3414    async fn test_pool_progressive_prewarm_failure_non_blocking(
3415    ) -> Result<(), Box<dyn std::error::Error>> {
3416        struct FailingFactory;
3417
3418        #[async_trait]
3419        impl ConnectionFactory for FailingFactory {
3420            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3421                Err(crate::DbError::Internal("simulated failure".to_string()))
3422            }
3423        }
3424
3425        let mut config = PoolConfigBuilder::new()
3426            .max_size(20)
3427            .min_idle(5)
3428            .prewarm(true)
3429            .build()?;
3430        config.connection_timeout = std::time::Duration::from_secs(1);
3431
3432        let pool = Pool::new(config, Arc::new(FailingFactory))?;
3433
3434        let progress = crate::prewarm::PrewarmProgress::new(5);
3435        pool.progressive_prewarm(
3436            2,
3437            std::time::Duration::from_millis(5),
3438            std::time::Duration::from_secs(5),
3439            &progress,
3440        )
3441        .await;
3442
3443        let snap = progress.snapshot();
3444        assert!(snap.is_completed, "应标记完成");
3445        assert_eq!(snap.warmed, 0, "全部失败时 warmed=0");
3446        assert!(snap.failed > 0, "应有失败记录");
3447
3448        Ok(())
3449    }
3450
3451    /// Prometheus 风格统计:acquire/release 计数与连接创建计数
3452    #[tokio::test]
3453    async fn test_pool_metrics_acquire_release() -> Result<(), Box<dyn std::error::Error>> {
3454        let config = PoolConfigBuilder::new().max_size(10).build()?;
3455        let pool = Pool::new(config, Arc::new(MockConnectionFactory))?;
3456
3457        let metrics = pool.pool_metrics();
3458        assert_eq!(metrics.acquire_count, 0);
3459        assert_eq!(metrics.release_count, 0);
3460        assert_eq!(metrics.connection_created_count, 0);
3461
3462        let conn = pool.acquire().await?;
3463        let metrics = pool.pool_metrics();
3464        assert_eq!(metrics.acquire_count, 1);
3465        assert_eq!(metrics.connection_created_count, 1);
3466        assert_eq!(metrics.acquire_failed_count, 0);
3467
3468        pool.release(conn).await;
3469        let metrics = pool.pool_metrics();
3470        assert_eq!(metrics.release_count, 1);
3471        // 连接归还到空闲队列,未被关闭
3472        assert_eq!(metrics.connection_closed_count, 0);
3473
3474        Ok(())
3475    }
3476
3477    /// Prometheus 风格统计:获取失败计数(工厂创建连接失败)
3478    #[tokio::test]
3479    async fn test_pool_metrics_acquire_failed() -> Result<(), Box<dyn std::error::Error>> {
3480        struct FailingFactory;
3481
3482        #[async_trait]
3483        impl ConnectionFactory for FailingFactory {
3484            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3485                Err(crate::DbError::Internal("simulated failure".to_string()))
3486            }
3487        }
3488
3489        let config = PoolConfigBuilder::new().max_size(10).build()?;
3490        let pool = Pool::new(config, Arc::new(FailingFactory))?;
3491
3492        let result = pool.acquire().await;
3493        assert!(result.is_err());
3494
3495        let metrics = pool.pool_metrics();
3496        assert_eq!(metrics.acquire_failed_count, 1);
3497        assert_eq!(metrics.acquire_count, 0);
3498
3499        Ok(())
3500    }
3501
3502    /// Prometheus 风格统计:连接关闭计数(close_all 后空闲连接被关闭)
3503    #[tokio::test]
3504    async fn test_pool_metrics_connection_closed() -> Result<(), Box<dyn std::error::Error>> {
3505        let config = PoolConfigBuilder::new().max_size(10).build()?;
3506        let pool = Pool::new(config, Arc::new(MockConnectionFactory))?;
3507
3508        let conn = pool.acquire().await?;
3509        pool.release(conn).await;
3510
3511        let status = pool.status().await;
3512        assert_eq!(status.idle, 1);
3513
3514        pool.close_all().await;
3515
3516        let metrics = pool.pool_metrics();
3517        assert_eq!(metrics.connection_closed_count, 1);
3518        assert_eq!(metrics.connection_created_count, 1);
3519
3520        Ok(())
3521    }
3522
3523    /// Prometheus 风格统计:平均获取等待时长计算
3524    #[test]
3525    fn test_pool_metrics_average_wait_time() {
3526        let metrics = PoolMetrics {
3527            acquire_count: 4,
3528            acquire_failed_count: 1,
3529            acquire_wait_time: Duration::from_millis(200),
3530            release_count: 4,
3531            connection_created_count: 2,
3532            connection_closed_count: 0,
3533        };
3534        assert_eq!(
3535            metrics.average_acquire_wait_time(),
3536            Duration::from_millis(50)
3537        );
3538
3539        // 无成功获取时平均等待时长为 0
3540        let empty = PoolMetrics::default();
3541        assert_eq!(empty.average_acquire_wait_time(), Duration::ZERO);
3542    }
3543
3544    #[tokio::test]
3545    async fn test_shutdown_with_timeout_fast_return_when_empty() {
3546        let factory = Arc::new(MockConnectionFactory) as Arc<dyn ConnectionFactory>;
3547        let config = PoolConfigBuilder::new().max_size(4).build().unwrap();
3548        let pool = Pool::new(config, factory).unwrap();
3549        pool.shutdown_with_timeout(Duration::from_secs(1)).await;
3550        assert!(pool.closed.load(Ordering::SeqCst));
3551        assert_eq!(pool.total_count.load(Ordering::SeqCst), 0);
3552    }
3553
3554    #[tokio::test]
3555    async fn test_shutdown_delegates_to_shutdown_with_timeout() {
3556        let factory = Arc::new(MockConnectionFactory) as Arc<dyn ConnectionFactory>;
3557        let config = PoolConfigBuilder::new().max_size(4).build().unwrap();
3558        let pool = Pool::new(config, factory).unwrap();
3559        pool.shutdown().await;
3560        assert!(pool.closed.load(Ordering::SeqCst));
3561    }
3562
3563    #[tokio::test]
3564    async fn test_shutdown_with_timeout_idempotent() {
3565        let factory = Arc::new(MockConnectionFactory) as Arc<dyn ConnectionFactory>;
3566        let config = PoolConfigBuilder::new().max_size(4).build().unwrap();
3567        let pool = Pool::new(config, factory).unwrap();
3568        pool.shutdown_with_timeout(Duration::from_secs(1)).await;
3569        let count_after_first = pool.total_count.load(Ordering::SeqCst);
3570        pool.shutdown_with_timeout(Duration::from_secs(1)).await;
3571        let count_after_second = pool.total_count.load(Ordering::SeqCst);
3572        assert_eq!(count_after_first, count_after_second);
3573    }
3574
3575    #[tokio::test]
3576    async fn test_shutdown_with_timeout_rejects_new_acquire() {
3577        let factory = Arc::new(MockConnectionFactory) as Arc<dyn ConnectionFactory>;
3578        let config = PoolConfigBuilder::new().max_size(4).build().unwrap();
3579        let pool = Pool::new(config, factory).unwrap();
3580        pool.shutdown_with_timeout(Duration::from_secs(1)).await;
3581        let result = pool.acquire().await;
3582        assert!(result.is_err());
3583    }
3584}
3585
3586#[cfg(all(test, feature = "prod-pool-tuning"))]
3587mod pool_prod_tests {
3588    use super::*;
3589
3590    struct MockFactory;
3591
3592    #[async_trait]
3593    impl ConnectionFactory for MockFactory {
3594        async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3595            Ok(Box::new(MockConn))
3596        }
3597    }
3598
3599    struct MockConn;
3600
3601    impl Connection for MockConn {
3602        fn execute<'a>(
3603            &'a mut self,
3604            _sql: &'a str,
3605        ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
3606            Box::pin(async move { Ok(1) })
3607        }
3608        fn query<'a>(
3609            &'a mut self,
3610            _sql: &'a str,
3611        ) -> Pin<
3612            Box<
3613                dyn Future<
3614                        Output = Result<
3615                            Vec<std::collections::HashMap<String, crate::value::Value>>,
3616                            crate::DbError,
3617                        >,
3618                    > + Send
3619                    + 'a,
3620            >,
3621        > {
3622            Box::pin(async move { Ok(vec![]) })
3623        }
3624        fn begin_transaction<'a>(
3625            &'a mut self,
3626        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3627            Box::pin(async move { Ok(()) })
3628        }
3629        fn commit<'a>(
3630            &'a mut self,
3631        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3632            Box::pin(async move { Ok(()) })
3633        }
3634        fn rollback<'a>(
3635            &'a mut self,
3636        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3637            Box::pin(async move { Ok(()) })
3638        }
3639        fn is_connected(&self) -> bool {
3640            true
3641        }
3642        fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
3643            Box::pin(async move { true })
3644        }
3645        fn close<'a>(
3646            &'a mut self,
3647        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3648            Box::pin(async move { Ok(()) })
3649        }
3650    }
3651
3652    #[test]
3653    fn test_pool_prod_config_validate_ok() {
3654        let config = PoolProdConfig::new(
3655            50,
3656            Duration::from_secs(10),
3657            Duration::from_secs(600),
3658            Duration::from_secs(5),
3659            Duration::from_secs(30),
3660            5,
3661            true,
3662        );
3663        assert!(config.validate().is_ok());
3664    }
3665
3666    #[test]
3667    fn test_pool_prod_config_max_size_zero_rejected() {
3668        let config = PoolProdConfig::default();
3669        let mut c = config;
3670        c.max_size = 0;
3671        let err = c.validate().unwrap_err();
3672        assert!(err.to_string().contains("max_size must be positive"));
3673    }
3674
3675    #[test]
3676    fn test_pool_prod_config_min_idle_exceeds_max_size() {
3677        let config = PoolProdConfig::new(
3678            10,
3679            Duration::from_secs(10),
3680            Duration::from_secs(600),
3681            Duration::from_secs(5),
3682            Duration::from_secs(30),
3683            20,
3684            false,
3685        );
3686        let err = config.validate().unwrap_err();
3687        assert!(err.to_string().contains("min_idle cannot exceed max_size"));
3688    }
3689
3690    #[test]
3691    fn test_pool_prod_config_to_pool_config() {
3692        let config = PoolProdConfig::new(
3693            50,
3694            Duration::from_secs(10),
3695            Duration::from_secs(600),
3696            Duration::from_secs(5),
3697            Duration::from_secs(30),
3698            5,
3699            true,
3700        );
3701        let pool_config = config.to_pool_config();
3702        assert_eq!(pool_config.max_size, 50);
3703        assert_eq!(pool_config.min_idle, 5);
3704        assert_eq!(pool_config.acquire_timeout, Duration::from_secs(10));
3705        assert!(pool_config.prewarm);
3706    }
3707
3708    #[tokio::test]
3709    async fn test_pool_prod_config_runtime_resize() {
3710        let factory = Arc::new(MockFactory) as Arc<dyn ConnectionFactory>;
3711        let config = PoolProdConfig::default();
3712        let pool = Pool::new(config.to_pool_config(), factory).unwrap();
3713        assert_eq!(pool.max_size(), 100);
3714        pool.resize(50);
3715        assert_eq!(pool.max_size(), 50);
3716    }
3717}
3718
3719#[cfg(all(test, feature = "prod-leak-detection"))]
3720mod leak_prod_tests {
3721    use super::*;
3722
3723    #[test]
3724    fn test_leak_config_default() {
3725        let config = LeakDetectionConfig::default();
3726        assert!(!config.enabled);
3727        assert_eq!(config.interval, Duration::from_secs(60));
3728        assert_eq!(config.threshold, 5);
3729    }
3730
3731    #[test]
3732    fn test_leak_config_validate_ok() {
3733        let config =
3734            LeakDetectionConfig::new(true, Duration::from_secs(30), 10, Duration::from_secs(60));
3735        assert!(config.validate().is_ok());
3736    }
3737
3738    #[test]
3739    fn test_leak_config_interval_zero_rejected() {
3740        let config = LeakDetectionConfig::new(true, Duration::ZERO, 10, Duration::from_secs(60));
3741        assert!(config.validate().is_err());
3742    }
3743
3744    #[test]
3745    fn test_leak_report_empty() {
3746        let report = LeakReport::empty();
3747        assert_eq!(report.borrowed_count, 0);
3748        assert!(report.suspected_leaks.is_empty());
3749    }
3750}