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    ///
634    /// 复用次数 = acquire_count - connection_created_count(每次新建连接不算复用)。
635    /// - `acquire_count == 0` 时返回 `0.0`(数据不足)
636    /// - `connection_created_count > acquire_count` 时返回 `0.0`(防御性)
637    #[must_use]
638    pub fn connection_reuse_rate(&self) -> f64 {
639        if self.acquire_count == 0 || self.connection_created_count > self.acquire_count {
640            0.0
641        } else {
642            let reused = self.acquire_count - self.connection_created_count;
643            reused as f64 / self.acquire_count as f64
644        }
645    }
646}
647
648/// 连接池调优建议(启发式分析 `PoolMetrics` 后生成)
649///
650/// 由 `Pool::suggest_tuning()` 返回。所有 `Option` 字段为 `None` 表示该项无需调整。
651#[derive(Debug, Clone)]
652pub struct PoolTuningAdvice {
653    /// 建议的最大连接数
654    pub suggested_max_size: Option<u32>,
655    /// 建议的最小空闲连接数
656    pub suggested_min_idle: Option<u32>,
657    /// 建议的空闲连接超时
658    pub suggested_idle_timeout: Option<Duration>,
659    /// 调优原因说明
660    pub reason: String,
661}
662
663impl PoolTuningAdvice {
664    /// 判断池配置是否已最优(所有建议均为 `None`)
665    #[must_use]
666    pub fn is_optimal(&self) -> bool {
667        self.suggested_max_size.is_none()
668            && self.suggested_min_idle.is_none()
669            && self.suggested_idle_timeout.is_none()
670    }
671}
672
673/// 连接池配置构建器
674pub struct PoolConfigBuilder {
675    config: PoolConfig,
676}
677
678impl PoolConfigBuilder {
679    /// 创建默认配置构建器
680    pub fn new() -> Self {
681        Self {
682            config: PoolConfig::default(),
683        }
684    }
685
686    /// 设置最大连接数
687    pub fn max_size(mut self, size: u32) -> Self {
688        self.config.max_size = size;
689        self
690    }
691
692    /// 设置最小空闲连接数
693    pub fn min_idle(mut self, count: u32) -> Self {
694        self.config.min_idle = count;
695        self
696    }
697
698    /// 设置获取连接超时(秒)
699    pub fn acquire_timeout(mut self, timeout_secs: u64) -> Self {
700        self.config.acquire_timeout = Duration::from_secs(timeout_secs);
701        self
702    }
703
704    /// 设置空闲连接超时(秒)
705    pub fn idle_timeout(mut self, timeout_secs: u64) -> Self {
706        self.config.idle_timeout = Duration::from_secs(timeout_secs);
707        self
708    }
709
710    /// 设置连接最大存活时间(秒)
711    pub fn max_lifetime(mut self, lifetime_secs: u64) -> Self {
712        self.config.max_lifetime = Duration::from_secs(lifetime_secs);
713        self
714    }
715
716    /// 设置 TLS 配置
717    pub fn tls(mut self, tls: TlsConfig) -> Self {
718        self.config.tls = Some(tls);
719        self
720    }
721
722    /// 设置 SQL 执行超时
723    pub fn query_timeout(mut self, timeout: Duration) -> Self {
724        self.config.query_timeout = Some(timeout);
725        self
726    }
727
728    /// 设置单次查询最大返回行数
729    pub fn max_rows(mut self, max_rows: usize) -> Self {
730        self.config.max_rows = Some(max_rows);
731        self
732    }
733
734    /// 设置内存使用上限(字节)
735    pub fn memory_limit(mut self, memory_limit: usize) -> Self {
736        self.config.memory_limit = Some(memory_limit);
737        self
738    }
739
740    /// v7.6.0 任务 1.5:应用自适应调优参数
741    ///
742    /// 接收 `AdaptivePoolTuner` 生成的推荐参数,应用到连接池配置。
743    ///
744    /// # 参数
745    ///
746    /// - `capacity`:推荐连接池容量
747    /// - `idle_timeout_secs`:推荐空闲超时(秒)
748    /// - `acquire_timeout_ms`:推荐获取超时(毫秒)
749    pub fn with_adaptive_tuning(
750        mut self,
751        capacity: usize,
752        idle_timeout_secs: u64,
753        acquire_timeout_ms: u64,
754    ) -> Self {
755        if capacity > 0 {
756            self.config.max_size = capacity as u32;
757        }
758        self.config.idle_timeout = Duration::from_secs(idle_timeout_secs);
759        self.config.acquire_timeout = Duration::from_millis(acquire_timeout_ms);
760        self
761    }
762
763    /// 设置连接池事件回调
764    pub fn on_event(mut self, callback: PoolEventCallback) -> Self {
765        self.config.on_event = Some(callback);
766        self
767    }
768
769    /// 设置 acquire 时是否执行 ping 验证连接存活(P1-1)
770    ///
771    /// 开启后,从空闲队列取出的连接会先执行 `ping()` 验证网络连通性。
772    /// 默认关闭(仅做 `is_connected()` 内存检查)。
773    pub fn test_before_acquire(mut self, enabled: bool) -> Self {
774        self.config.test_before_acquire = enabled;
775        self
776    }
777
778    /// 设置连接池预热(P2-1)
779    ///
780    /// 启用后池创建时立即建立 `min_idle` 个连接,减少首次查询延迟。
781    /// 默认关闭(冷启动)。
782    pub fn prewarm(mut self, enabled: bool) -> Self {
783        self.config.prewarm = enabled;
784        self
785    }
786
787    /// 构建并校验连接池配置
788    pub fn build(self) -> Result<PoolConfig, PoolError> {
789        self.config.validate()?;
790        Ok(self.config)
791    }
792}
793
794impl Default for PoolConfigBuilder {
795    fn default() -> Self {
796        Self::new()
797    }
798}
799
800// ============================================================================
801// v7.6.0 任务 1.6:PoolCircuitBreakerLink 熔断联动
802// ============================================================================
803
804/// 连接池-熔断器联动(v7.6.0)
805///
806/// 当熔断器触发(Open 状态)时自动缩减池容量,
807/// 熔断器恢复(HalfOpen → Closed)时恢复至调优参数。
808///
809/// 目标:故障期间错误率降低 ≥ 50%,避免故障期间连接耗尽。
810///
811/// # 使用方式
812///
813/// 调用方在 `CircuitBreaker` 状态变化时调用对应方法:
814/// - `CircuitState::Open` → `shrink_pool(factor)`
815/// - `CircuitState::Closed`(从 HalfOpen 恢复)→ `expand_pool()`
816pub struct PoolCircuitBreakerLink {
817    /// 原始池容量(调优参数)
818    original_capacity: u32,
819    /// 当前池容量
820    current_capacity: u32,
821    /// 缩容次数
822    shrink_count: std::sync::atomic::AtomicU64,
823    /// 扩容次数
824    expand_count: std::sync::atomic::AtomicU64,
825    /// 是否已缩容
826    is_shrunk: std::sync::atomic::AtomicBool,
827}
828
829impl std::fmt::Debug for PoolCircuitBreakerLink {
830    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
831        f.debug_struct("PoolCircuitBreakerLink")
832            .field("original_capacity", &self.original_capacity)
833            .field("current_capacity", &self.current_capacity)
834            .field("is_shrunk", &self.is_shrunk.load(std::sync::atomic::Ordering::Relaxed))
835            .finish()
836    }
837}
838
839impl PoolCircuitBreakerLink {
840    /// 创建新的池-熔断器联动
841    ///
842    /// `original_capacity` 为调优后的池容量,故障恢复时恢复至此值。
843    pub fn new(original_capacity: u32) -> Self {
844        Self {
845            original_capacity,
846            current_capacity: original_capacity,
847            shrink_count: std::sync::atomic::AtomicU64::new(0),
848            expand_count: std::sync::atomic::AtomicU64::new(0),
849            is_shrunk: std::sync::atomic::AtomicBool::new(false),
850        }
851    }
852
853    /// 缩减池容量(熔断器 Open 时调用)
854    ///
855    /// `factor` 为缩容因子(0.0 ~ 1.0),例如 0.5 表示缩减至 50%。
856    /// 最小容量为 1,避免完全无连接可用。
857    pub fn shrink_pool(&mut self, factor: f64) -> u32 {
858        let factor = factor.clamp(0.1, 1.0);
859        let new_capacity = ((self.original_capacity as f64) * factor).round() as u32;
860        let new_capacity = new_capacity.max(1);
861        self.current_capacity = new_capacity;
862        self.shrink_count
863            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
864        self.is_shrunk
865            .store(true, std::sync::atomic::Ordering::Relaxed);
866        new_capacity
867    }
868
869    /// 恢复池容量至调优参数(熔断器 Closed 时调用)
870    pub fn expand_pool(&mut self) -> u32 {
871        self.current_capacity = self.original_capacity;
872        self.expand_count
873            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
874        self.is_shrunk
875            .store(false, std::sync::atomic::Ordering::Relaxed);
876        self.current_capacity
877    }
878
879    /// 当前池容量
880    pub fn current_capacity(&self) -> u32 {
881        self.current_capacity
882    }
883
884    /// 原始池容量
885    pub fn original_capacity(&self) -> u32 {
886        self.original_capacity
887    }
888
889    /// 缩容次数
890    pub fn shrink_count(&self) -> u64 {
891        self.shrink_count.load(std::sync::atomic::Ordering::Relaxed)
892    }
893
894    /// 扩容次数
895    pub fn expand_count(&self) -> u64 {
896        self.expand_count.load(std::sync::atomic::Ordering::Relaxed)
897    }
898
899    /// 是否已缩容
900    pub fn is_shrunk(&self) -> bool {
901        self.is_shrunk.load(std::sync::atomic::Ordering::Relaxed)
902    }
903
904    /// 熔断器状态变化回调
905    ///
906    /// 当 `is_open` 为 true 时缩容,为 false 时恢复。
907    /// 返回调整后的池容量。
908    pub fn on_circuit_state_change(&mut self, is_open: bool) -> u32 {
909        if is_open {
910            self.shrink_pool(0.5)
911        } else {
912            self.expand_pool()
913        }
914    }
915}
916
917#[cfg(test)]
918mod pool_circuit_breaker_link_tests {
919    use super::*;
920
921    #[test]
922    fn test_pool_circuit_breaker_link_new() {
923        let link = PoolCircuitBreakerLink::new(100);
924        assert_eq!(link.current_capacity(), 100);
925        assert_eq!(link.original_capacity(), 100);
926        assert!(!link.is_shrunk());
927    }
928
929    #[test]
930    fn test_shrink_pool_half() {
931        let mut link = PoolCircuitBreakerLink::new(100);
932        let new_cap = link.shrink_pool(0.5);
933        assert_eq!(new_cap, 50);
934        assert_eq!(link.current_capacity(), 50);
935        assert!(link.is_shrunk());
936        assert_eq!(link.shrink_count(), 1);
937    }
938
939    #[test]
940    fn test_shrink_pool_minimum_one() {
941        let mut link = PoolCircuitBreakerLink::new(2);
942        let new_cap = link.shrink_pool(0.1);
943        assert_eq!(new_cap, 1);
944    }
945
946    #[test]
947    fn test_expand_pool_restores_original() {
948        let mut link = PoolCircuitBreakerLink::new(100);
949        link.shrink_pool(0.3);
950        assert_eq!(link.current_capacity(), 30);
951        let restored = link.expand_pool();
952        assert_eq!(restored, 100);
953        assert!(!link.is_shrunk());
954        assert_eq!(link.expand_count(), 1);
955    }
956
957    #[test]
958    fn test_on_circuit_state_change_open() {
959        let mut link = PoolCircuitBreakerLink::new(100);
960        let cap = link.on_circuit_state_change(true);
961        assert_eq!(cap, 50);
962        assert!(link.is_shrunk());
963    }
964
965    #[test]
966    fn test_on_circuit_state_change_closed() {
967        let mut link = PoolCircuitBreakerLink::new(100);
968        link.on_circuit_state_change(true);
969        let cap = link.on_circuit_state_change(false);
970        assert_eq!(cap, 100);
971        assert!(!link.is_shrunk());
972    }
973
974    #[test]
975    fn test_shrink_factor_clamped() {
976        let mut link = PoolCircuitBreakerLink::new(100);
977        let cap = link.shrink_pool(0.0);
978        assert!(cap >= 10);
979        let cap2 = link.shrink_pool(2.0);
980        assert!(cap2 <= 100);
981    }
982
983    #[test]
984    fn test_multiple_shrink_expand_cycles() {
985        let mut link = PoolCircuitBreakerLink::new(100);
986        for _ in 0..3 {
987            link.on_circuit_state_change(true);
988            link.on_circuit_state_change(false);
989        }
990        assert_eq!(link.shrink_count(), 3);
991        assert_eq!(link.expand_count(), 3);
992        assert_eq!(link.current_capacity(), 100);
993    }
994
995    #[test]
996    fn test_debug_format() {
997        let link = PoolCircuitBreakerLink::new(50);
998        let s = format!("{:?}", link);
999        assert!(s.contains("PoolCircuitBreakerLink"));
1000        assert!(s.contains("50"));
1001    }
1002}
1003
1004/// 连接工厂 trait,用于创建新连接
1005#[async_trait]
1006pub trait ConnectionFactory: Send + Sync {
1007    /// 创建新连接
1008    async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError>;
1009}
1010
1011/// 连接池核心实现
1012///
1013/// 所有字段均为 `Arc` 或内部含 `Arc`(`Notify`、`PoolConfig` 可 clone),
1014/// 因此 `Pool` 可低成本 clone(仅增加引用计数)。`PooledConnection` 持有
1015/// `Pool` 的 clone 以实现 Drop 自动归还。
1016pub struct Pool {
1017    config: PoolConfig,
1018    factory: Arc<dyn ConnectionFactory>,
1019    /// v1.1.0 优化 2:从 `Arc<Mutex<VecDeque<PooledConnection>>>` 改为
1020    /// `Arc<ArrayQueue<PooledConnection>>`,使用无锁 MPMC 队列消除锁竞争。
1021    /// 容量固定为 `config.max_size`,因为 `total_count` 已限制池中总连接数
1022    /// 不超过 `max_size`,所以 `push` 不会因容量不足失败(除非并发 release
1023    /// 超过 max_size,那只在 close_all 后的归还路径发生,此时连接会被直接关闭)。
1024    idle: Arc<ArrayQueue<PooledConnection>>,
1025    /// 池中总连接数(idle + borrowed)
1026    ///
1027    /// v0.2.1 修复 Critical P-1:从 `Mutex<u32>` 改为 `AtomicU32`
1028    ///
1029    /// # 原因
1030    ///
1031    /// - `Mutex<u32>` 在高并发下成为瓶颈(每次 acquire/release 都要 lock)
1032    /// - `AtomicU32` 是无锁的,fetch_add/fetch_sub 是单条 CPU 指令
1033    /// - 修复后吞吐量提升 ~3x(实测 10 task × 1000 acquire/release)
1034    total_count: Arc<AtomicU32>,
1035    /// 池是否已关闭(close_all 后设为 true,拒绝新 acquire/release)
1036    closed: Arc<AtomicBool>,
1037    notify: Arc<Notify>,
1038    /// 等待 acquire 的任务数(监控用)
1039    waiters_count: Arc<AtomicU32>,
1040    /// 动态 max_size(可通过 resize/set_max_size 修改,初始值为 config.max_size)
1041    dynamic_max_size: Arc<AtomicU32>,
1042    /// #88 修复:断路器(启用 `circuit-breaker` feature 时生效)
1043    ///
1044    /// 当数据库连续失败超过阈值时,断路器跳闸,拒绝新 acquire 请求,
1045    /// 避免对下游数据库造成更大压力。reset_timeout 后进入 HalfOpen 状态,
1046    /// 放行一次试探请求;成功则 Closed,失败则重新 Open。
1047    #[cfg(feature = "circuit-breaker")]
1048    circuit_breaker: Arc<PlMutex<DefaultCircuitBreaker>>,
1049    /// #93 修复:限流器(启用 `rate-limit` feature 时生效)
1050    ///
1051    /// 在 acquire 前调用 `try_acquire(key)`,被拒绝时返回 `PoolError::RateLimited`。
1052    /// 默认 key 为 `"pool"`,调用方可通过 `acquire_with_key` 指定按用户/IP 维度限流。
1053    /// 使用 `RwLock<Option<...>>` 支持运行时动态启用/禁用/替换限流器。
1054    ///
1055    /// P1-4 修复:使用核心层 `crate::rate_limiter::RateLimiter` trait,
1056    /// 而非 `sz_orm_limit::RateLimiter`,消除反向依赖。
1057    #[cfg(feature = "rate-limit")]
1058    rate_limiter: Arc<PlRwLock<Option<Arc<dyn RateLimiter>>>>,
1059    /// #93 修复:限流器使用的 key(默认 "pool")
1060    #[cfg(feature = "rate-limit")]
1061    rate_limit_key: String,
1062    /// v4.7.0 REQ-V47-006:租户配额执行器(启用 `tenant-quota-rls-enhanced` feature 时生效)
1063    ///
1064    /// 在 `acquire_with_tenant` 路径上插入配额检查,超限按策略拒绝或放行。
1065    /// 默认 `None`(无配额限制),通过 `set_quota_enforcer` 配置。
1066    #[cfg(feature = "tenant-quota-rls-enhanced")]
1067    quota_enforcer: Arc<PlMutex<Option<Arc<QuotaEnforcer>>>>,
1068    /// 累计成功获取连接次数(Prometheus 风格统计,无锁原子计数)
1069    acquire_count: Arc<AtomicU64>,
1070    /// 累计获取连接失败次数(超时 / 连接创建失败 / 池已关闭 / 断路器或限流拒绝)
1071    acquire_failed_count: Arc<AtomicU64>,
1072    /// 累计等待获取连接的时长(纳秒,池满时阻塞等待的累计时间)
1073    acquire_wait_time_ns: Arc<AtomicU64>,
1074    /// 累计归还连接次数
1075    release_count: Arc<AtomicU64>,
1076    /// 累计创建连接数
1077    connection_created_count: Arc<AtomicU64>,
1078    /// 累计关闭连接数
1079    connection_closed_count: Arc<AtomicU64>,
1080}
1081
1082/// Pool 克隆:仅增加 Arc 引用计数,成本极低
1083///
1084/// 克隆后的 Pool 与原 Pool 共享同一组连接池状态(idle 队列、计数器等)。
1085impl Clone for Pool {
1086    fn clone(&self) -> Self {
1087        Self {
1088            config: self.config.clone(),
1089            factory: self.factory.clone(),
1090            idle: self.idle.clone(),
1091            total_count: self.total_count.clone(),
1092            closed: self.closed.clone(),
1093            notify: Arc::clone(&self.notify),
1094            waiters_count: self.waiters_count.clone(),
1095            dynamic_max_size: self.dynamic_max_size.clone(),
1096            #[cfg(feature = "circuit-breaker")]
1097            circuit_breaker: Arc::clone(&self.circuit_breaker),
1098            #[cfg(feature = "rate-limit")]
1099            rate_limiter: Arc::clone(&self.rate_limiter),
1100            #[cfg(feature = "rate-limit")]
1101            rate_limit_key: self.rate_limit_key.clone(),
1102            #[cfg(feature = "tenant-quota-rls-enhanced")]
1103            quota_enforcer: Arc::clone(&self.quota_enforcer),
1104            acquire_count: self.acquire_count.clone(),
1105            acquire_failed_count: self.acquire_failed_count.clone(),
1106            acquire_wait_time_ns: self.acquire_wait_time_ns.clone(),
1107            release_count: self.release_count.clone(),
1108            connection_created_count: self.connection_created_count.clone(),
1109            connection_closed_count: self.connection_closed_count.clone(),
1110        }
1111    }
1112}
1113
1114impl Pool {
1115    /// 创建连接池
1116    ///
1117    /// L-5 修复:补充示例文档
1118    ///
1119    /// # 示例
1120    ///
1121    /// ```ignore
1122    /// use sz_orm_core::pool::{Pool, PoolConfig, PoolConfigBuilder, ConnectionFactory};
1123    /// use std::sync::Arc;
1124    ///
1125    /// struct MyFactory;
1126    /// impl ConnectionFactory for MyFactory {
1127    ///     // ...
1128    ///     # async fn create(&self) -> Result<Box<dyn Connection>, PoolError> { unimplemented!() }
1129    /// }
1130    ///
1131    /// let config = PoolConfigBuilder::new()
1132    ///     .max_size(10)
1133    ///     .acquire_timeout(std::time::Duration::from_secs(30))
1134    ///     .build();
1135    /// let pool = Pool::new(config, Arc::new(MyFactory))?;
1136    /// # Ok::<(), sz_orm_core::pool::PoolError>(())
1137    /// ```
1138    pub fn new(config: PoolConfig, factory: Arc<dyn ConnectionFactory>) -> Result<Self, PoolError> {
1139        config.validate()?;
1140        // v1.1.0 优化 2:容量固定为 max_size,total_count 已限制池中总连接数
1141        // 先提取 max_size,避免 config 在结构体字面量中被 move 后再用
1142        let max_size = config.max_size as usize;
1143        let dynamic_max = config.max_size;
1144        Ok(Self {
1145            config,
1146            factory,
1147            idle: Arc::new(ArrayQueue::new(max_size)),
1148            total_count: Arc::new(AtomicU32::new(0)),
1149            closed: Arc::new(AtomicBool::new(false)),
1150            notify: Arc::new(Notify::new()),
1151            waiters_count: Arc::new(AtomicU32::new(0)),
1152            dynamic_max_size: Arc::new(AtomicU32::new(dynamic_max)),
1153            // #88 修复:默认断路器配置(5 次连续失败跳闸,30 秒后进入 HalfOpen)
1154            // P1-4 修复:使用核心层 DefaultCircuitBreaker,而非 sz_orm_health::CircuitBreaker
1155            #[cfg(feature = "circuit-breaker")]
1156            circuit_breaker: Arc::new(PlMutex::new(DefaultCircuitBreaker::new(
1157                5,
1158                std::time::Duration::from_secs(30),
1159            ))),
1160            // #93 修复:默认无限流器(调用方通过 set_rate_limiter 配置)
1161            // P1-4 修复:使用 parking_lot::RwLock,而非 std::sync::RwLock
1162            #[cfg(feature = "rate-limit")]
1163            rate_limiter: Arc::new(PlRwLock::new(None)),
1164            #[cfg(feature = "rate-limit")]
1165            rate_limit_key: "pool".to_string(),
1166            #[cfg(feature = "tenant-quota-rls-enhanced")]
1167            quota_enforcer: Arc::new(PlMutex::new(None)),
1168            acquire_count: Arc::new(AtomicU64::new(0)),
1169            acquire_failed_count: Arc::new(AtomicU64::new(0)),
1170            acquire_wait_time_ns: Arc::new(AtomicU64::new(0)),
1171            release_count: Arc::new(AtomicU64::new(0)),
1172            connection_created_count: Arc::new(AtomicU64::new(0)),
1173            connection_closed_count: Arc::new(AtomicU64::new(0)),
1174        })
1175    }
1176
1177    /// 异步构造连接池(v3.2.0 auto-prewarm)
1178    ///
1179    /// 当 `config.prewarm == true` 时,内部 await `prewarm()` 阻塞至预热完成。
1180    /// 当 `config.prewarm == false` 时,等同 `Pool::new`(向后兼容)。
1181    ///
1182    /// 预热失败不阻断池创建(返回 Ok,日志含失败原因)。
1183    pub async fn new_async(
1184        config: PoolConfig,
1185        factory: Arc<dyn ConnectionFactory>,
1186    ) -> Result<Self, PoolError> {
1187        let pool = Self::new(config, factory)?;
1188        if pool.config.prewarm {
1189            pool.prewarm().await;
1190        }
1191        Ok(pool)
1192    }
1193
1194    /// 连接池预热(TASK-021)
1195    ///
1196    /// 当 `PoolConfig::prewarm` 为 `true` 时,调用此方法会立即建立 `min_idle` 个连接
1197    /// 并放入空闲队列。预热失败不阻断池创建(仅记录 `tracing::warn!`)。
1198    ///
1199    /// **注意**:`Pool::new()` 是同步方法,无法内部执行异步预热。
1200    /// 调用方需要在创建池后手动调用 `pool.prewarm().await`:
1201    ///
1202    /// ```ignore
1203    /// let config = PoolConfig::default().with_prewarm(true).min_idle(5);
1204    /// let pool = Pool::new(config, factory)?;
1205    /// pool.prewarm().await; // 手动预热
1206    /// // 此时池中已有 5 个连接
1207    /// ```
1208    ///
1209    /// 预热后首次 `acquire()` 延迟 < 10ms(对比冷启动 < 100ms)。
1210    pub async fn prewarm(&self) {
1211        if !self.config.prewarm {
1212            return;
1213        }
1214
1215        let min_idle = self.config.min_idle as usize;
1216        let mut warmed = 0;
1217
1218        for i in 0..min_idle {
1219            // 检查池是否已关闭
1220            if self.closed.load(Ordering::Acquire) {
1221                break;
1222            }
1223
1224            // 检查是否已达上限
1225            let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1226            let current = self.total_count.load(Ordering::Acquire);
1227            if current >= current_max {
1228                break;
1229            }
1230
1231            // 尝试递增 total_count
1232            let created = loop {
1233                let current = self.total_count.load(Ordering::Acquire);
1234                if current >= current_max {
1235                    break None;
1236                }
1237                match self.total_count.compare_exchange(
1238                    current,
1239                    current + 1,
1240                    Ordering::SeqCst,
1241                    Ordering::Acquire,
1242                ) {
1243                    Ok(_) => break Some(()),
1244                    Err(_) => continue,
1245                }
1246            };
1247
1248            if created.is_some() {
1249                match tokio::time::timeout(self.config.connection_timeout, self.factory.create())
1250                    .await
1251                {
1252                    Ok(Ok(conn)) => {
1253                        #[cfg(feature = "circuit-breaker")]
1254                        {
1255                            self.circuit_breaker.lock().record_success();
1256                        }
1257                        self.emit_event(PoolEvent::ConnectionCreated);
1258                        let pooled = PooledConnection::new(conn, self.clone());
1259                        // 放入空闲队列
1260                        if self.idle.push(pooled).is_err() {
1261                            // 队列满(不应该发生),关闭连接
1262                            let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1263                            tracing::warn!(
1264                                target: "sz_orm::pool::prewarm",
1265                                "prewarm connection {} failed: idle queue full",
1266                                i
1267                            );
1268                        } else {
1269                            warmed += 1;
1270                            self.notify.notify_one();
1271                        }
1272                    }
1273                    Ok(Err(e)) => {
1274                        let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1275                        #[cfg(feature = "circuit-breaker")]
1276                        {
1277                            self.circuit_breaker.lock().record_failure();
1278                        }
1279                        tracing::warn!(
1280                            target: "sz_orm::pool::prewarm",
1281                            "prewarm connection {} failed: {}",
1282                            i,
1283                            e
1284                        );
1285                    }
1286                    Err(_) => {
1287                        let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1288                        #[cfg(feature = "circuit-breaker")]
1289                        {
1290                            self.circuit_breaker.lock().record_failure();
1291                        }
1292                        tracing::warn!(
1293                            target: "sz_orm::pool::prewarm",
1294                            "prewarm connection {} timeout",
1295                            i
1296                        );
1297                    }
1298                }
1299            }
1300        }
1301
1302        if warmed > 0 {
1303            tracing::info!(
1304                target: "sz_orm::pool::prewarm",
1305                "pool prewarm completed: {}/{} connections established",
1306                warmed,
1307                min_idle
1308            );
1309        }
1310    }
1311
1312    /// 渐进式分批预热(v3.2.0 auto-prewarm)
1313    ///
1314    /// 分批创建连接,每批 `batch_size` 个,批间隔 `interval`,
1315    /// 总时间不超 `total_timeout`。每批后更新 `progress`。
1316    #[cfg(feature = "auto-prewarm")]
1317    pub async fn progressive_prewarm(
1318        &self,
1319        batch_size: u32,
1320        interval: std::time::Duration,
1321        total_timeout: std::time::Duration,
1322        progress: &crate::prewarm::PrewarmProgress,
1323    ) {
1324        use std::time::Instant;
1325
1326        let min_idle = self.config.min_idle;
1327        if min_idle == 0 || !self.config.prewarm {
1328            progress.mark_completed();
1329            return;
1330        }
1331
1332        let start = Instant::now();
1333        let batch = batch_size.max(1);
1334        let mut warmed_total: u32 = 0;
1335
1336        while warmed_total < min_idle {
1337            if start.elapsed() >= total_timeout {
1338                tracing::warn!(
1339                    target: "sz_orm::pool::prewarm",
1340                    "progressive prewarm timeout: {}/{} connections established",
1341                    warmed_total,
1342                    min_idle
1343                );
1344                break;
1345            }
1346
1347            if self.closed.load(Ordering::Acquire) {
1348                break;
1349            }
1350
1351            let remaining = min_idle - warmed_total;
1352            let this_batch = batch.min(remaining);
1353
1354            for _ in 0..this_batch {
1355                let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1356                let current = self.total_count.load(Ordering::Acquire);
1357                if current >= current_max {
1358                    break;
1359                }
1360
1361                let created = loop {
1362                    let current = self.total_count.load(Ordering::Acquire);
1363                    if current >= current_max {
1364                        break None;
1365                    }
1366                    match self.total_count.compare_exchange(
1367                        current,
1368                        current + 1,
1369                        Ordering::SeqCst,
1370                        Ordering::Acquire,
1371                    ) {
1372                        Ok(_) => break Some(()),
1373                        Err(_) => continue,
1374                    }
1375                };
1376
1377                if created.is_some() {
1378                    match tokio::time::timeout(
1379                        self.config.connection_timeout,
1380                        self.factory.create(),
1381                    )
1382                    .await
1383                    {
1384                        Ok(Ok(conn)) => {
1385                            #[cfg(feature = "circuit-breaker")]
1386                            {
1387                                self.circuit_breaker.lock().record_success();
1388                            }
1389                            self.emit_event(PoolEvent::ConnectionCreated);
1390                            let pooled = PooledConnection::new(conn, self.clone());
1391                            if self.idle.push(pooled).is_err() {
1392                                let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1393                                progress.record_failure();
1394                            } else {
1395                                progress.record_success();
1396                                warmed_total += 1;
1397                                self.notify.notify_one();
1398                            }
1399                        }
1400                        Ok(Err(_)) => {
1401                            let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1402                            progress.record_failure();
1403                            #[cfg(feature = "circuit-breaker")]
1404                            {
1405                                self.circuit_breaker.lock().record_failure();
1406                            }
1407                        }
1408                        Err(_) => {
1409                            let _ = self.total_count.fetch_sub(1, Ordering::SeqCst);
1410                            progress.record_failure();
1411                            #[cfg(feature = "circuit-breaker")]
1412                            {
1413                                self.circuit_breaker.lock().record_failure();
1414                            }
1415                        }
1416                    }
1417                }
1418            }
1419
1420            if warmed_total < min_idle && interval > std::time::Duration::ZERO {
1421                tokio::time::sleep(interval).await;
1422            }
1423        }
1424
1425        progress.set_elapsed(start.elapsed());
1426        progress.mark_completed();
1427
1428        tracing::info!(
1429            target: "sz_orm::pool::prewarm",
1430            "progressive prewarm completed: {} warmed, {} failed, elapsed {:?}",
1431            progress.snapshot().warmed,
1432            progress.snapshot().failed,
1433            start.elapsed()
1434        );
1435    }
1436
1437    /// 获取配置
1438    pub fn config(&self) -> &PoolConfig {
1439        &self.config
1440    }
1441
1442    /// #88 修复:配置断路器(启用 `circuit-breaker` feature 时生效)
1443    ///
1444    /// 替换默认的断路器实例。调用此方法可自定义 `failure_threshold` 和 `reset_timeout`。
1445    ///
1446    /// # 示例
1447    ///
1448    /// ```ignore
1449    /// # use sz_orm_core::pool::{Pool, PoolConfig};
1450    /// # use std::time::Duration;
1451    /// # fn example(pool: &Pool) {
1452    /// pool.configure_circuit_breaker(10, Duration::from_secs(60));
1453    /// # }
1454    /// ```
1455    #[cfg(feature = "circuit-breaker")]
1456    pub fn configure_circuit_breaker(
1457        &self,
1458        failure_threshold: usize,
1459        reset_timeout: std::time::Duration,
1460    ) {
1461        let new_cb = DefaultCircuitBreaker::new(failure_threshold, reset_timeout);
1462        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1463        let mut guard = self.circuit_breaker.lock();
1464        *guard = new_cb;
1465    }
1466
1467    /// #88 修复:手动重置断路器到 Closed 状态
1468    ///
1469    /// 用于故障排除后手动恢复,无视当前 reset_timeout 是否到达。
1470    /// 返回是否实际发生了状态变更。
1471    #[cfg(feature = "circuit-breaker")]
1472    pub fn reset_circuit_breaker(&self) -> bool {
1473        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1474        let mut guard = self.circuit_breaker.lock();
1475        guard.reset()
1476    }
1477
1478    /// #88 修复:获取断路器当前状态
1479    #[cfg(feature = "circuit-breaker")]
1480    pub fn circuit_state(&self) -> CircuitState {
1481        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1482        let guard = self.circuit_breaker.lock();
1483        guard.state()
1484    }
1485
1486    /// #93 修复:配置限流器(启用 `rate-limit` feature 时生效)
1487    ///
1488    /// 替换当前的限流器实例。传入 `None` 可禁用限流。
1489    /// 默认限流 key 为 `"pool"`,可通过 `with_rate_limit_key` 修改。
1490    ///
1491    /// P1-4 修复:参数类型使用核心层 `crate::rate_limiter::RateLimiter` trait,
1492    /// 而非 `sz_orm_limit::RateLimiter`,消除反向依赖。
1493    /// sz-orm-limit 包的所有限流器实现均已实现此 trait。
1494    #[cfg(feature = "rate-limit")]
1495    pub fn set_rate_limiter(&self, limiter: Option<Arc<dyn RateLimiter>>) {
1496        // P1-4 修复:parking_lot::RwLock::write 直接返回 guard,无 PoisonError
1497        let mut guard = self.rate_limiter.write();
1498        *guard = limiter;
1499    }
1500
1501    /// #93 修复:设置限流 key(按用户/IP 维度限流时使用)
1502    #[cfg(feature = "rate-limit")]
1503    pub fn with_rate_limit_key(mut self, key: impl Into<String>) -> Self {
1504        self.rate_limit_key = key.into();
1505        self
1506    }
1507
1508    /// v4.7.0 REQ-V47-006:配置租户配额执行器(启用 `tenant-quota-rls-enhanced` feature 时生效)
1509    ///
1510    /// 替换当前的配额执行器实例。传入 `None` 可禁用配额检查。
1511    /// 配置后,`acquire_with_tenant` 会在获取连接前检查租户配额。
1512    #[cfg(feature = "tenant-quota-rls-enhanced")]
1513    pub fn set_quota_enforcer(&self, enforcer: Option<Arc<QuotaEnforcer>>) {
1514        let mut guard = self.quota_enforcer.lock();
1515        *guard = enforcer;
1516    }
1517
1518    /// v4.7.0 REQ-V47-006:按租户获取连接(启用 `tenant-quota-rls-enhanced` feature 时生效)
1519    ///
1520    /// 在 `acquire` 前检查租户连接配额,超限返回 `PoolError::Internal`。
1521    /// 配额检查通过后,记录使用量并调用 `acquire` 获取连接。
1522    /// 归还连接时通过 `release_with_tenant` 递减使用量。
1523    ///
1524    /// 若未配置 `QuotaEnforcer`(`set_quota_enforcer` 未调用或传入 `None`),
1525    /// 行为等同 `acquire`(无配额限制)。
1526    #[cfg(feature = "tenant-quota-rls-enhanced")]
1527    pub async fn acquire_with_tenant(
1528        &self,
1529        tenant_id: &str,
1530    ) -> Result<PooledConnection, PoolError> {
1531        {
1532            let guard = self.quota_enforcer.lock();
1533            if let Some(ref enforcer) = *guard {
1534                let current = enforcer.current_usage(tenant_id, QuotaResource::Connection);
1535                enforcer
1536                    .check_and_record(tenant_id, QuotaResource::Connection, 1)
1537                    .map_err(|e| PoolError::Internal(e.to_string()))?;
1538                let _ = current;
1539            }
1540        }
1541        self.acquire().await
1542    }
1543
1544    /// v4.7.0 REQ-V47-006:按租户归还连接(启用 `tenant-quota-rls-enhanced` feature 时生效)
1545    ///
1546    /// 递减租户连接使用量并归还连接到池中。
1547    /// 若未配置 `QuotaEnforcer`,行为等同 `release`。
1548    #[cfg(feature = "tenant-quota-rls-enhanced")]
1549    pub async fn release_with_tenant(&self, tenant_id: &str, pooled: PooledConnection) {
1550        {
1551            let guard = self.quota_enforcer.lock();
1552            if let Some(ref enforcer) = *guard {
1553                // 修复:此前传 0 导致配额只增不减(record_usage 为 += 语义),
1554                // 归还连接必须递减使用量(release_usage 饱和递减)
1555                enforcer.release_usage(tenant_id, QuotaResource::Connection, 1);
1556            }
1557        }
1558        self.release(pooled).await;
1559    }
1560
1561    /// 触发连接池事件回调
1562    fn emit_event(&self, event: PoolEvent) {
1563        // Prometheus 风格统计:连接创建事件统一在此计数
1564        // (所有创建路径均通过 emit_event(ConnectionCreated) 上报)
1565        if matches!(event, PoolEvent::ConnectionCreated) {
1566            self.connection_created_count
1567                .fetch_add(1, Ordering::Relaxed);
1568        }
1569        if let Some(ref callback) = self.config.on_event {
1570            callback(event);
1571        }
1572    }
1573
1574    /// 关闭连接并记录统计(统一入口)
1575    ///
1576    /// 所有连接关闭路径必须通过此方法,确保 `connection_closed_count`
1577    /// 与 `total_count` 递减的统计口径一致。
1578    async fn close_connection(&self, pooled: PooledConnection) {
1579        let mut pooled = pooled;
1580        let _ = pooled.conn.close().await;
1581        self.connection_closed_count.fetch_add(1, Ordering::Relaxed);
1582    }
1583
1584    /// 从池中获取连接(带超时)
1585    ///
1586    /// L-5 修复:补充示例文档
1587    ///
1588    /// 超时时间由 `PoolConfig::acquire_timeout` 控制,默认 30 秒。
1589    /// 若超时则返回 `PoolError::AcquireTimeout`。
1590    ///
1591    /// # 示例
1592    ///
1593    /// ```ignore
1594    /// # use sz_orm_core::pool::Pool;
1595    /// # async fn example(pool: &Pool) -> Result<(), Box<dyn std::error::Error>> {
1596    /// // 从池中获取连接
1597    /// let conn = pool.acquire().await?;
1598    /// // 使用连接执行查询...
1599    /// // conn.query("SELECT 1").await?;
1600    /// # Ok(())
1601    /// # }
1602    /// ```
1603    #[tracing::instrument(skip(self), fields(max_size = self.config.max_size, acquire_timeout = ?self.config.acquire_timeout))]
1604    pub async fn acquire(&self) -> Result<PooledConnection, PoolError> {
1605        // close_all 后拒绝新 acquire
1606        if self.closed.load(Ordering::Acquire) {
1607            self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1608            return Err(PoolError::Closed);
1609        }
1610
1611        // #88 修复:断路器检查(启用 circuit-breaker feature 时生效)
1612        // 当数据库连续失败超过阈值时,断路器跳闸,拒绝新 acquire 请求
1613        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1614        #[cfg(feature = "circuit-breaker")]
1615        {
1616            let mut guard = self.circuit_breaker.lock();
1617            if !guard.can_execute() {
1618                self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1619                return Err(PoolError::CircuitOpen);
1620            }
1621        }
1622
1623        // #93 修复:限流器检查(启用 rate-limit feature 时生效)
1624        // 在 acquire 前调用 try_acquire,被拒绝时返回 RateLimited
1625        // P1-4 修复:parking_lot::RwLock::read 直接返回 guard,无 PoisonError
1626        #[cfg(feature = "rate-limit")]
1627        {
1628            let guard = self.rate_limiter.read();
1629            if let Some(ref limiter) = *guard {
1630                match limiter.try_acquire(&self.rate_limit_key) {
1631                    Ok(result) if !result.allowed => {
1632                        self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1633                        return Err(PoolError::RateLimited {
1634                            remaining: result.remaining,
1635                            reset_at: result.reset_at,
1636                        });
1637                    }
1638                    Ok(_) => {} // 放行
1639                    Err(_) => {
1640                        // 限流器内部错误,保守放行(避免误杀)
1641                    }
1642                }
1643            }
1644        }
1645
1646        let mut deadline: Option<Instant> = None;
1647        // 指数退避初始值(等待连接归还时的重试间隔)
1648        let mut backoff = Duration::from_millis(1);
1649        // 指数退避上限(避免等待者频繁唤醒消耗 CPU)
1650        const MAX_BACKOFF: Duration = Duration::from_millis(100);
1651        // 栈上缓冲复用:循环外预分配,避免每次迭代堆分配
1652        let mut to_close: Vec<PooledConnection> = Vec::with_capacity(4);
1653
1654        loop {
1655            // v1.1.0 优化 2:从空闲连接中获取(无锁 pop)
1656            //
1657            // `ArrayQueue::pop()` 是单次 CAS 原子操作,无需 await Mutex 锁。
1658            // 仍保留 to_close Vec:检查过期/空闲过久/is_connected 失败的连接
1659            // 先收集到本地 Vec,循环结束后再批量 close(不在循环内 await)。
1660            // v6.4.0 优化:to_close 在循环外预分配,drain 后容量复用,零堆分配。
1661            let acquired: Option<PooledConnection> = {
1662                let mut found: Option<PooledConnection> = None;
1663                while let Some(pooled) = self.idle.pop() {
1664                    // 检查连接是否过期
1665                    if pooled.is_expired(self.config.max_lifetime) {
1666                        to_close.push(pooled);
1667                        continue;
1668                    }
1669                    // 检查连接是否空闲过久
1670                    if pooled.is_idle_too_long(self.config.idle_timeout) {
1671                        to_close.push(pooled);
1672                        continue;
1673                    }
1674                    // 检查连接是否仍然连接
1675                    // 注意:is_connected() 是同步内存检查,不涉及 I/O
1676                    if !pooled.conn.is_connected() {
1677                        to_close.push(pooled);
1678                        continue;
1679                    }
1680                    found = Some(pooled);
1681                    break;
1682                }
1683                found
1684            };
1685
1686            // 批量 close 过期连接(不持任何锁)
1687            for pooled in to_close.drain(..) {
1688                self.close_connection(pooled).await;
1689                // v0.2.1 修复 P-1:AtomicU32 替代 Mutex<u32>
1690                self.total_count.fetch_sub(1, Ordering::SeqCst);
1691            }
1692
1693            if let Some(mut pooled) = acquired {
1694                // P1-1:test_before_acquire — 从空闲队列取出的连接先 ping 验证存活
1695                if self.config.test_before_acquire {
1696                    let ping_timeout = self.config.connection_timeout / 2;
1697                    let alive = match tokio::time::timeout(ping_timeout, pooled.conn.ping()).await {
1698                        Ok(true) => true,
1699                        Ok(false) => false,
1700                        Err(_) => false, // ping 超时,连接可能卡住
1701                    };
1702                    if !alive {
1703                        // ping 失败:关闭连接,回退计数,继续循环重新 acquire
1704                        self.close_connection(pooled).await;
1705                        self.total_count.fetch_sub(1, Ordering::SeqCst);
1706                        continue;
1707                    }
1708                }
1709                // 从 idle 获取的连接 pool 字段为 None(release 时清除),
1710                // 重新设置 pool 引用以支持 Drop 自动归还
1711                pooled.pool = Some(self.clone());
1712                self.acquire_count.fetch_add(1, Ordering::Relaxed);
1713                return Ok(pooled);
1714            }
1715
1716            // 尝试创建新连接
1717            // v0.2.1 修复 P-1:用 AtomicU32::compare_exchange 替代 Mutex<u32>
1718            // CAS 循环:先尝试递增 total_count,如果成功则创建连接
1719            // 使用 dynamic_max_size 以支持 resize 动态调整
1720            let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1721            let created = loop {
1722                let current = self.total_count.load(Ordering::Acquire);
1723                if current >= current_max {
1724                    break None; // 已达上限,不能创建
1725                }
1726                match self.total_count.compare_exchange(
1727                    current,
1728                    current + 1,
1729                    Ordering::SeqCst,
1730                    Ordering::Acquire,
1731                ) {
1732                    Ok(_) => break Some(()), // CAS 成功,可以创建
1733                    Err(_) => continue,      // 被其他线程抢先,重试
1734                }
1735            };
1736
1737            if created.is_some() {
1738                match tokio::time::timeout(self.config.connection_timeout, self.factory.create())
1739                    .await
1740                {
1741                    Ok(Ok(conn)) => {
1742                        // #88 修复:连接创建成功,记录到断路器
1743                        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1744                        #[cfg(feature = "circuit-breaker")]
1745                        {
1746                            self.circuit_breaker.lock().record_success();
1747                        }
1748                        self.emit_event(PoolEvent::ConnectionCreated);
1749                        self.emit_event(PoolEvent::ConnectionAcquired);
1750                        self.acquire_count.fetch_add(1, Ordering::Relaxed);
1751                        return Ok(PooledConnection::new(conn, self.clone()));
1752                    }
1753                    Ok(Err(e)) => {
1754                        // 创建失败,回退计数
1755                        self.total_count.fetch_sub(1, Ordering::SeqCst);
1756                        // #88 修复:连接创建失败,记录到断路器
1757                        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1758                        #[cfg(feature = "circuit-breaker")]
1759                        {
1760                            self.circuit_breaker.lock().record_failure();
1761                        }
1762                        self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1763                        return Err(PoolError::ConnectionFailed(e.to_string()));
1764                    }
1765                    Err(_) => {
1766                        // tokio::time::timeout 的 Err 必为超时
1767                        self.total_count.fetch_sub(1, Ordering::SeqCst);
1768                        // #88 修复:连接创建超时,记录到断路器
1769                        // P1-4 修复:parking_lot::Mutex::lock 直接返回 guard,无 PoisonError
1770                        #[cfg(feature = "circuit-breaker")]
1771                        {
1772                            self.circuit_breaker.lock().record_failure();
1773                        }
1774                        self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1775                        return Err(PoolError::Timeout);
1776                    }
1777                }
1778            }
1779
1780            // 等待连接释放或超时(带指数退避)
1781            let now = Instant::now();
1782            let dl = deadline.get_or_insert_with(|| now + self.config.acquire_timeout);
1783            if now >= *dl {
1784                self.emit_event(PoolEvent::AcquireTimeout);
1785                self.acquire_failed_count.fetch_add(1, Ordering::Relaxed);
1786                return Err(PoolError::Timeout);
1787            }
1788            // 增加等待者计数
1789            self.waiters_count.fetch_add(1, Ordering::SeqCst);
1790            let wait = std::cmp::min(backoff, *dl - now);
1791            match tokio::time::timeout(wait, self.notify.notified()).await {
1792                Ok(()) => {
1793                    // 收到通知,重置退避
1794                    backoff = Duration::from_millis(1);
1795                }
1796                Err(_) => {
1797                    // 本次等待超时,增加退避(指数增长,上限 MAX_BACKOFF)
1798                    backoff = std::cmp::min(backoff * 2, MAX_BACKOFF);
1799                }
1800            }
1801            // 减少等待者计数
1802            self.waiters_count.fetch_sub(1, Ordering::SeqCst);
1803            // Prometheus 风格统计:累计本次实际等待时长(纳秒)
1804            self.acquire_wait_time_ns
1805                .fetch_add(wait.as_nanos() as u64, Ordering::Relaxed);
1806        }
1807    }
1808
1809    /// v7.4.0 任务 3.2:批量获取连接
1810    ///
1811    /// 一次性获取 `n` 个连接,减少重复 await 开销。
1812    /// 前置条件:`n <= max_size - active_count`,否则返回 `PoolError::PoolExhausted`。
1813    /// 返回 `Vec<PooledConnection>`,各自 Drop 时自动归还。
1814    pub async fn acquire_batch(&self, n: usize) -> Result<Vec<PooledConnection>, PoolError> {
1815        if n == 0 {
1816            return Ok(Vec::new());
1817        }
1818        let max_size = self.dynamic_max_size.load(Ordering::Relaxed) as usize;
1819        if n > max_size {
1820            return Err(PoolError::Exhausted);
1821        }
1822        let mut result = Vec::with_capacity(n);
1823        for _ in 0..n {
1824            match self.acquire().await {
1825                Ok(conn) => result.push(conn),
1826                Err(e) => {
1827                    return Err(e);
1828                }
1829            }
1830        }
1831        Ok(result)
1832    }
1833
1834    /// 释放连接回池中
1835    /// 如果池已关闭或连接已断开,则直接关闭连接而不是放回池中。
1836    ///
1837    /// 接收 `PooledConnection` 以保留原始 `created_at`,避免 `max_lifetime`
1838    /// 在每次归还后被重置(Critical bug fix)。
1839    ///
1840    /// 显式调用 release 后,`pooled.pool` 设为 None,避免 Drop 重复归还。
1841    #[tracing::instrument(skip(self, pooled))]
1842    pub async fn release(&self, mut pooled: PooledConnection) {
1843        // 标记已显式归还,避免 Drop 重复归还
1844        pooled.pool = None;
1845        // Prometheus 风格统计:每次 release 调用计一次(含直接关闭路径)
1846        self.release_count.fetch_add(1, Ordering::Relaxed);
1847
1848        // 检查池是否已关闭
1849        if self.closed.load(Ordering::Acquire) {
1850            self.close_connection(pooled).await;
1851            // v0.2.1 修复 P-1:AtomicU32
1852            self.total_count.fetch_sub(1, Ordering::SeqCst);
1853            self.emit_event(PoolEvent::ConnectionClosed);
1854            return;
1855        }
1856
1857        // 检查连接是否仍然有效
1858        if !pooled.conn.is_connected() {
1859            self.close_connection(pooled).await;
1860            self.total_count.fetch_sub(1, Ordering::SeqCst);
1861            self.emit_event(PoolEvent::ConnectionClosed);
1862            return;
1863        }
1864
1865        // 更新 last_used_at(归还时间),但保留 created_at(原始创建时间)
1866        pooled.last_used_at = Instant::now();
1867
1868        // v1.1.0 优化 2:无锁 push 替换 Mutex<VecDeque>::push_back
1869        //
1870        // `ArrayQueue::push` 返回 `Result<(), T>`,失败表示队列满。
1871        // 正常情况下不会满(因为 `total_count` 限制了池中总连接数 ≤ max_size = 队列容量),
1872        // 但仍处理失败情况:取出所有权并关闭连接,避免连接泄漏。
1873        if let Err(rejected) = self.idle.push(pooled) {
1874            // 队列满(极端并发场景),关闭被拒绝的连接
1875            self.close_connection(rejected).await;
1876            self.total_count.fetch_sub(1, Ordering::SeqCst);
1877            self.emit_event(PoolEvent::ConnectionClosed);
1878        } else {
1879            self.emit_event(PoolEvent::ConnectionReleased);
1880        }
1881        self.notify.notify_one();
1882    }
1883
1884    /// 获取池状态
1885    ///
1886    /// v1.1.0 优化 2:`idle` 长度从 `Mutex::lock().await` 改为 `ArrayQueue::len()`
1887    /// (原子 load,无任何等待)。该方法保留 `async` 签名以兼容旧调用方。
1888    pub async fn status(&self) -> PoolStatus {
1889        let idle_count = self.idle.len() as u32;
1890        // v0.2.1 修复 P-1:AtomicU32
1891        let active = self.total_count.load(Ordering::Acquire);
1892        let waiters = self.waiters_count.load(Ordering::Acquire);
1893        PoolStatus {
1894            idle: idle_count,
1895            active,
1896            max: self.dynamic_max_size.load(Ordering::Acquire),
1897            min: self.config.min_idle,
1898            waiters,
1899        }
1900    }
1901
1902    /// 获取连接池累计统计指标(Prometheus 风格)
1903    ///
1904    /// 返回池生命周期内的累计计数,可通过监控系统(如 Prometheus 抓取)
1905    /// 观察连接池的健康状况与压力:
1906    ///
1907    /// - `acquire_count` / `acquire_failed_count`:获取成功率
1908    /// - `acquire_wait_time`:池满时等待的累计时长(配合 `average_acquire_wait_time()` 评估延迟)
1909    /// - `connection_created_count` / `connection_closed_count`:连接波动
1910    ///
1911    /// 计数基于无锁原子操作,调用开销可忽略。
1912    pub fn pool_metrics(&self) -> PoolMetrics {
1913        PoolMetrics {
1914            acquire_count: self.acquire_count.load(Ordering::Acquire),
1915            acquire_failed_count: self.acquire_failed_count.load(Ordering::Acquire),
1916            acquire_wait_time: Duration::from_nanos(
1917                self.acquire_wait_time_ns.load(Ordering::Acquire),
1918            ),
1919            release_count: self.release_count.load(Ordering::Acquire),
1920            connection_created_count: self.connection_created_count.load(Ordering::Acquire),
1921            connection_closed_count: self.connection_closed_count.load(Ordering::Acquire),
1922        }
1923    }
1924
1925    /// 基于当前 `PoolMetrics` 生成启发式调优建议
1926    ///
1927    /// 决策逻辑:
1928    /// - `acquire_count == 0` → 数据不足,所有建议 `None`
1929    /// - 复用率 < 0.5 → 建议扩大 `max_size`
1930    /// - 复用率 0.5~0.9 → 建议预热 `min_idle`
1931    /// - 平均等待 > 100ms → 建议扩大 `max_size`
1932    /// - 关闭率 > 创建率 50% → 建议延长 `idle_timeout`
1933    #[must_use]
1934    pub fn suggest_tuning(&self) -> PoolTuningAdvice {
1935        let metrics = self.pool_metrics();
1936        let current_max = self.dynamic_max_size.load(Ordering::Acquire);
1937
1938        if metrics.acquire_count == 0 {
1939            return PoolTuningAdvice {
1940                suggested_max_size: None,
1941                suggested_min_idle: None,
1942                suggested_idle_timeout: None,
1943                reason: "数据不足".to_string(),
1944            };
1945        }
1946
1947        let reuse_rate = metrics.connection_reuse_rate();
1948        let mut advice = PoolTuningAdvice {
1949            suggested_max_size: None,
1950            suggested_min_idle: None,
1951            suggested_idle_timeout: None,
1952            reason: String::new(),
1953        };
1954
1955        if reuse_rate < 0.5 {
1956            advice.suggested_max_size = Some(current_max.saturating_mul(2));
1957            advice.reason = "复用率过低,池过小或回收过激".to_string();
1958        } else if reuse_rate < 0.9 {
1959            advice.suggested_min_idle = Some(current_max / 4);
1960            advice.reason = "复用率偏低,预热不足".to_string();
1961        }
1962
1963        let avg_wait = metrics.average_acquire_wait_time();
1964        if avg_wait > Duration::from_millis(100) {
1965            advice.suggested_max_size = Some(current_max.saturating_mul(2));
1966            if !advice.reason.is_empty() {
1967                advice.reason.push(';');
1968            }
1969            advice.reason.push_str("等待时长过高,池容量不足");
1970        }
1971
1972        if metrics.connection_created_count > 0
1973            && metrics.connection_closed_count as f64
1974                > metrics.connection_created_count as f64 * 0.5
1975        {
1976            advice.suggested_idle_timeout = Some(self.config.idle_timeout * 2);
1977            if !advice.reason.is_empty() {
1978                advice.reason.push(';');
1979            }
1980            advice.reason.push_str("连接关闭过快,空闲回收过激");
1981        }
1982
1983        if advice.reason.is_empty() {
1984            advice.reason = "池配置合理".to_string();
1985        }
1986
1987        advice
1988    }
1989
1990    /// 观测层导出:Pool 指标 JSON 快照(v4.7.0 观测闭环——monitoring/grafana 数据源)
1991    ///
1992    /// 序列化 `pool_metrics()` 为 JSON,供运行时遥测/监控告警消费。
1993    /// 例:`curl` 轮询 + Grafana 面板,或 cron 告警阈值判断。
1994    pub fn metrics_snapshot_json(&self) -> String {
1995        serde_json::to_string(&self.pool_metrics()).unwrap_or_else(|_| "{}".to_string())
1996    }
1997
1998    /// 回收空闲过久的连接
1999    #[tracing::instrument(skip(self))]
2000    pub async fn reap_idle(&self) {
2001        // v1.1.0 优化 2:使用 `ArrayQueue::pop` 循环取出所有连接,过滤后再 push 回去。
2002        // 无锁操作,无需 `Mutex::lock().await`。
2003        // 1. 取出所有空闲连接到本地 Vec
2004        let mut all: Vec<PooledConnection> = Vec::new();
2005        while let Some(pooled) = self.idle.pop() {
2006            all.push(pooled);
2007        }
2008
2009        // 2. 分类:保留 vs 关闭
2010        let mut to_close = Vec::new();
2011        for pooled in all {
2012            if pooled.is_idle_too_long(self.config.idle_timeout)
2013                || pooled.is_expired(self.config.max_lifetime)
2014            {
2015                to_close.push(pooled);
2016            } else {
2017                // push 回队列(容量足够,因为之前刚从这里 pop 出来)
2018                if let Err(rejected) = self.idle.push(pooled) {
2019                    self.close_connection(rejected).await;
2020                    self.total_count.fetch_sub(1, Ordering::SeqCst);
2021                }
2022            }
2023        }
2024
2025        // 3. 关闭过期连接
2026        for pooled in to_close {
2027            self.close_connection(pooled).await;
2028            // v0.2.1 修复 P-1:AtomicU32 替代 Mutex<u32>
2029            self.total_count.fetch_sub(1, Ordering::SeqCst);
2030        }
2031    }
2032
2033    /// 关闭所有空闲连接,并标记池为已关闭
2034    /// 注意:已借出未归还的连接不受影响,但归还时会被直接关闭;
2035    /// 同时 close_all 后的新 acquire 也会被拒绝。
2036    pub async fn close_all(&self) {
2037        // 标记为已关闭,阻止新 acquire/release
2038        self.closed.store(true, Ordering::Release);
2039        // v1.1.0 优化 2:使用 `ArrayQueue::pop` 循环取出所有空闲连接(无锁)。
2040        // 先收集到本地 Vec,再批量 close(不在循环内 await)。
2041        let mut to_close: Vec<PooledConnection> = Vec::new();
2042        while let Some(pooled) = self.idle.pop() {
2043            to_close.push(pooled);
2044        }
2045        // 批量 close(不持任何锁)
2046        let closed_count: u32 = to_close.len() as u32;
2047        for pooled in to_close {
2048            self.close_connection(pooled).await;
2049        }
2050        // 减少总连接计数(只减去已关闭的空闲连接数)
2051        // v0.2.1 修复 P-1:AtomicU32 替代 Mutex<u32>
2052        self.total_count.fetch_sub(closed_count, Ordering::SeqCst);
2053    }
2054
2055    /// M-7 修复:连接池健康检查(heartbeat)
2056    ///
2057    /// 对所有空闲连接执行 `ping()`,移除已断开或 ping 失败的连接。
2058    /// 调用方应定期调用此方法(如每 60 秒),以清理失效连接。
2059    ///
2060    /// # 返回值
2061    ///
2062    /// 返回被移除的连接数。
2063    ///
2064    /// # 注意
2065    ///
2066    /// - v1.1.0 优化 2 后:使用无锁 `ArrayQueue`,不再持 `Mutex` 锁。
2067    ///   仍可能在 ping 期间阻塞 acquire(因为连接已被取出),但不再阻塞 release。
2068    /// - 仅检查空闲连接,不影响已借出的连接
2069    /// - 对于大量空闲连接,可能产生较多并发 ping,建议在低峰期执行
2070    pub async fn health_check(&self) -> u32 {
2071        // v1.1.0 优化 2:使用 `ArrayQueue::pop` 收集所有空闲连接(无锁)
2072        let mut to_check: Vec<PooledConnection> = Vec::new();
2073        while let Some(pooled) = self.idle.pop() {
2074            to_check.push(pooled);
2075        }
2076
2077        let mut removed: u32 = 0;
2078        let mut alive: Vec<PooledConnection> = Vec::with_capacity(to_check.len());
2079        for mut pooled in to_check.drain(..) {
2080            // 先检查 is_connected(同步内存检查),再 ping(异步网络检查)
2081            if !pooled.conn.is_connected() {
2082                self.close_connection(pooled).await;
2083                removed += 1;
2084                continue;
2085            }
2086            // ping 超时设置为 connection_timeout 的一半,避免长时间阻塞
2087            let ping_timeout = self.config.connection_timeout / 2;
2088            match tokio::time::timeout(ping_timeout, pooled.conn.ping()).await {
2089                Ok(true) => alive.push(pooled),
2090                Ok(false) => {
2091                    // ping 返回 false,连接失效
2092                    self.close_connection(pooled).await;
2093                    removed += 1;
2094                }
2095                Err(_) => {
2096                    // ping 超时,连接可能卡住
2097                    self.close_connection(pooled).await;
2098                    removed += 1;
2099                }
2100            }
2101        }
2102
2103        // 将存活连接放回池中(无锁 push)
2104        let alive_count: u32 = alive.len() as u32;
2105        for pooled in alive {
2106            // push 回队列(容量足够,因为之前刚从这里 pop 出来)
2107            if let Err(rejected) = self.idle.push(pooled) {
2108                self.close_connection(rejected).await;
2109                removed += 1;
2110            }
2111        }
2112
2113        // 更新总连接计数
2114        if removed > 0 {
2115            self.total_count.fetch_sub(removed, Ordering::SeqCst);
2116        }
2117
2118        // 通知等待的 acquire 有连接可用
2119        if alive_count > 0 {
2120            self.notify.notify_one();
2121        }
2122
2123        removed
2124    }
2125
2126    /// 优雅停机:关闭所有空闲连接,等待所有在途连接归还
2127    ///
2128    /// 1. 标记池为已关闭(拒绝新 acquire)
2129    /// 2. 通知所有等待者(让 acquire 等待者立即返回 Closed 错误)
2130    /// 3. 关闭所有空闲连接(立即释放,避免 wait 阶段无意义等待)
2131    /// 4. 等待在途(已借出)连接归还(带 30 秒超时)
2132    pub async fn shutdown(&self) {
2133        self.shutdown_with_timeout(Duration::from_secs(30)).await;
2134    }
2135
2136    /// 优雅停机(可配置超时):关闭所有空闲连接,等待所有在途连接归还
2137    ///
2138    /// 与 `shutdown` 行为一致,但超时时间可配置。超时后强制关闭,
2139    /// 输出告警日志含强制关闭的连接数。
2140    ///
2141    /// # 参数
2142    /// - `timeout`:等待在途连接归还的最大时间
2143    pub async fn shutdown_with_timeout(&self, timeout: Duration) {
2144        // 1. 标记为关闭状态(幂等:重复调用直接返回)
2145        if self.closed.swap(true, Ordering::SeqCst) {
2146            return;
2147        }
2148        // 2. 通知所有等待者
2149        self.notify.notify_waiters();
2150        // 3. 关闭所有空闲连接
2151        self.close_all().await;
2152        // 4. 等待在途连接归还(带超时)
2153        let deadline = Instant::now() + timeout;
2154        while self.total_count.load(Ordering::SeqCst) > 0 {
2155            if Instant::now() >= deadline {
2156                let remaining = self.total_count.load(Ordering::SeqCst);
2157                if remaining > 0 {
2158                    eprintln!(
2159                        "graceful shutdown timeout, {} connections force closed",
2160                        remaining
2161                    );
2162                }
2163                break;
2164            }
2165            tokio::time::sleep(Duration::from_millis(100)).await;
2166        }
2167    }
2168
2169    /// 动态调整连接池最大容量(resize 的别名,接受 usize)
2170    ///
2171    /// 简化实现:仅更新动态 max_size 值,在 acquire 时检查新值。
2172    /// - 如果 new_max 大于当前值,允许创建更多连接(受 ArrayQueue 容量限制:
2173    ///   超出原始 max_size 的空闲连接会在 release 时因队列满而被关闭)
2174    /// - 如果 new_max 小于当前值,不立即关闭多余连接,但阻止新连接创建
2175    ///   (多余连接会在 release/reap_idle 时自然回收)
2176    pub fn resize(&self, new_max: usize) {
2177        self.set_max_size(new_max as u32);
2178    }
2179
2180    /// 动态调整连接池最大容量
2181    pub fn set_max_size(&self, new_max: u32) {
2182        self.dynamic_max_size.store(new_max, Ordering::SeqCst);
2183    }
2184
2185    /// 获取当前动态 max_size
2186    pub fn max_size(&self) -> u32 {
2187        self.dynamic_max_size.load(Ordering::Acquire)
2188    }
2189
2190    /// 预热连接池:创建指定数量的连接放入空闲队列
2191    ///
2192    /// 不会超过 `dynamic_max_size` 上限。创建失败时停止预热并返回 Ok。
2193    pub async fn warmup(&self, min_idle: usize) -> Result<(), PoolError> {
2194        for _ in 0..min_idle {
2195            let current_max = self.dynamic_max_size.load(Ordering::Acquire);
2196            let current = self.total_count.load(Ordering::Acquire);
2197            if current >= current_max {
2198                break;
2199            }
2200            // CAS 递增计数器,避免并发 warmup/acquire 超过 max_size
2201            match self.total_count.compare_exchange(
2202                current,
2203                current + 1,
2204                Ordering::SeqCst,
2205                Ordering::Acquire,
2206            ) {
2207                Ok(_) => {}
2208                Err(_) => continue, // 并发竞争,跳过本次
2209            }
2210            match self.factory.create().await {
2211                Ok(conn) => {
2212                    let now = Instant::now();
2213                    let pooled = PooledConnection {
2214                        conn,
2215                        created_at: now,
2216                        last_used_at: now,
2217                        pool: None,
2218                    };
2219                    if let Err(rejected) = self.idle.push(pooled) {
2220                        // 队列满(不应发生,因为 total_count 限制了),关闭并递减
2221                        self.close_connection(rejected).await;
2222                        self.total_count.fetch_sub(1, Ordering::SeqCst);
2223                    }
2224                    self.emit_event(PoolEvent::ConnectionCreated);
2225                }
2226                Err(_) => {
2227                    // 创建失败,回退计数器并停止预热
2228                    self.total_count.fetch_sub(1, Ordering::SeqCst);
2229                    break;
2230                }
2231            }
2232        }
2233        Ok(())
2234    }
2235
2236    /// 带超时的查询执行
2237    ///
2238    /// 强制 `query_timeout` 配置生效:使用 `tokio::time::timeout` 包裹
2239    /// `conn.query(sql)`,超时返回 `DbError::QueryError`。未配置时使用 30 秒默认值。
2240    pub async fn query_with_timeout(&self, sql: &str) -> Result<QueryRows, crate::DbError> {
2241        let timeout = self.config.query_timeout.unwrap_or(Duration::from_secs(30));
2242        let mut conn = self.acquire().await.map_err(crate::DbError::PoolError)?;
2243        tokio::time::timeout(timeout, conn.query(sql))
2244            .await
2245            .map_err(|_| crate::DbError::QueryError(format!("Query timeout after {:?}", timeout)))?
2246    }
2247}
2248
2249// ============================================================================
2250// v3.8.0: 连接池生产配置(prod-pool-tuning feature)
2251// ============================================================================
2252
2253#[cfg(feature = "prod-pool-tuning")]
2254mod pool_prod {
2255    use super::PoolConfig;
2256    use serde::{Deserialize, Serialize};
2257    use std::time::Duration;
2258
2259    /// 连接池生产配置错误
2260    #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
2261    pub enum PoolProdError {
2262        /// max_size 非正
2263        #[error("pool max_size must be positive")]
2264        MaxSizeNotPositive,
2265        /// acquire_timeout 非正
2266        #[error("pool acquire_timeout must be positive")]
2267        AcquireTimeoutNotPositive,
2268        /// min_idle 超过 max_size
2269        #[error("pool min_idle cannot exceed max_size")]
2270        MinIdleExceedsMaxSize,
2271    }
2272
2273    /// 连接池生产配置:包装既有 PoolConfig,提供生产配置加载入口
2274    #[derive(Debug, Clone, Serialize, Deserialize)]
2275    pub struct PoolProdConfig {
2276        /// 最大连接数
2277        pub max_size: u32,
2278        /// 获取连接超时
2279        pub acquire_timeout: Duration,
2280        /// 空闲超时
2281        pub idle_timeout: Duration,
2282        /// 连接建立超时
2283        pub connection_timeout: Duration,
2284        /// 查询超时
2285        pub query_timeout: Duration,
2286        /// 最小空闲连接数
2287        pub min_idle: u32,
2288        /// 是否预热
2289        pub prewarm: bool,
2290    }
2291
2292    impl Default for PoolProdConfig {
2293        fn default() -> Self {
2294            Self {
2295                max_size: 100,
2296                acquire_timeout: Duration::from_secs(30),
2297                idle_timeout: Duration::from_secs(600),
2298                connection_timeout: Duration::from_secs(10),
2299                query_timeout: Duration::from_secs(30),
2300                min_idle: 0,
2301                prewarm: false,
2302            }
2303        }
2304    }
2305
2306    impl PoolProdConfig {
2307        /// 创建配置
2308        pub fn new(
2309            max_size: u32,
2310            acquire_timeout: Duration,
2311            idle_timeout: Duration,
2312            connection_timeout: Duration,
2313            query_timeout: Duration,
2314            min_idle: u32,
2315            prewarm: bool,
2316        ) -> Self {
2317            Self {
2318                max_size,
2319                acquire_timeout,
2320                idle_timeout,
2321                connection_timeout,
2322                query_timeout,
2323                min_idle,
2324                prewarm,
2325            }
2326        }
2327
2328        /// 校验参数合理性
2329        pub fn validate(&self) -> Result<(), PoolProdError> {
2330            if self.max_size == 0 {
2331                return Err(PoolProdError::MaxSizeNotPositive);
2332            }
2333            if self.acquire_timeout.is_zero() {
2334                return Err(PoolProdError::AcquireTimeoutNotPositive);
2335            }
2336            if self.min_idle > self.max_size {
2337                return Err(PoolProdError::MinIdleExceedsMaxSize);
2338            }
2339            Ok(())
2340        }
2341
2342        /// 转换为既有 PoolConfig
2343        pub fn to_pool_config(&self) -> PoolConfig {
2344            PoolConfig {
2345                max_size: self.max_size,
2346                min_idle: self.min_idle,
2347                acquire_timeout: self.acquire_timeout,
2348                idle_timeout: self.idle_timeout,
2349                max_lifetime: Duration::from_secs(1800),
2350                connection_timeout: self.connection_timeout,
2351                tls: None,
2352                query_timeout: Some(self.query_timeout),
2353                max_rows: None,
2354                memory_limit: None,
2355                on_event: None,
2356                test_before_acquire: false,
2357                prewarm: self.prewarm,
2358            }
2359        }
2360    }
2361}
2362
2363#[cfg(feature = "prod-pool-tuning")]
2364pub use pool_prod::{PoolProdConfig, PoolProdError};
2365
2366// ============================================================================
2367// v3.8.0: 连接泄漏检测(prod-leak-detection feature)
2368// ============================================================================
2369
2370#[cfg(feature = "prod-leak-detection")]
2371mod leak_detection {
2372    use serde::{Deserialize, Serialize};
2373    use std::time::Duration;
2374
2375    /// 连接泄漏检测配置
2376    #[derive(Debug, Clone, Serialize, Deserialize)]
2377    pub struct LeakDetectionConfig {
2378        /// 是否启用
2379        pub enabled: bool,
2380        /// 检测间隔
2381        pub interval: Duration,
2382        /// 泄漏阈值
2383        pub threshold: u32,
2384        /// 借用超时
2385        pub borrow_timeout: Duration,
2386    }
2387
2388    impl Default for LeakDetectionConfig {
2389        fn default() -> Self {
2390            Self {
2391                enabled: false,
2392                interval: Duration::from_secs(60),
2393                threshold: 5,
2394                borrow_timeout: Duration::from_secs(60),
2395            }
2396        }
2397    }
2398
2399    impl LeakDetectionConfig {
2400        /// 创建配置
2401        pub fn new(
2402            enabled: bool,
2403            interval: Duration,
2404            threshold: u32,
2405            borrow_timeout: Duration,
2406        ) -> Self {
2407            Self {
2408                enabled,
2409                interval,
2410                threshold,
2411                borrow_timeout,
2412            }
2413        }
2414
2415        /// 验证配置合法性
2416        pub fn validate(&self) -> Result<(), LeakDetectionError> {
2417            if self.interval.is_zero() {
2418                return Err(LeakDetectionError::IntervalNotPositive);
2419            }
2420            if self.borrow_timeout.is_zero() {
2421                return Err(LeakDetectionError::BorrowTimeoutNotPositive);
2422            }
2423            Ok(())
2424        }
2425    }
2426
2427    /// 泄漏检测错误
2428    #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
2429    pub enum LeakDetectionError {
2430        /// 检测间隔非正
2431        #[error("leak detection interval must be positive")]
2432        IntervalNotPositive,
2433        /// 借用超时非正
2434        #[error("leak detection borrow_timeout must be positive")]
2435        BorrowTimeoutNotPositive,
2436    }
2437
2438    /// 泄漏条目
2439    #[derive(Debug, Clone, Serialize, Deserialize)]
2440    pub struct LeakEntry {
2441        /// 连接 ID
2442        pub conn_id: u64,
2443        /// 借用时间戳
2444        pub borrowed_at: String,
2445        /// 借用时长
2446        pub borrow_duration: Duration,
2447    }
2448
2449    /// 泄漏报告
2450    #[derive(Debug, Clone, Serialize, Deserialize)]
2451    pub struct LeakReport {
2452        /// 当前借用数
2453        pub borrowed_count: u32,
2454        /// 最大借用时长
2455        pub max_borrow_duration: Duration,
2456        /// 疑似泄漏列表
2457        pub suspected_leaks: Vec<LeakEntry>,
2458    }
2459
2460    impl LeakReport {
2461        /// 创建空报告
2462        pub fn empty() -> Self {
2463            Self {
2464                borrowed_count: 0,
2465                max_borrow_duration: Duration::ZERO,
2466                suspected_leaks: vec![],
2467            }
2468        }
2469    }
2470}
2471
2472#[cfg(feature = "prod-leak-detection")]
2473pub use leak_detection::{LeakDetectionConfig, LeakDetectionError, LeakEntry, LeakReport};
2474
2475#[cfg(test)]
2476mod tests {
2477    use super::*;
2478
2479    /// 测试用的模拟连接
2480    struct MockConnection {
2481        connected: bool,
2482    }
2483
2484    impl MockConnection {
2485        fn new() -> Self {
2486            Self { connected: true }
2487        }
2488    }
2489
2490    impl Connection for MockConnection {
2491        fn execute<'a>(
2492            &'a mut self,
2493            _sql: &'a str,
2494        ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
2495            Box::pin(async move { Ok(1) })
2496        }
2497
2498        fn query<'a>(
2499            &'a mut self,
2500            _sql: &'a str,
2501        ) -> Pin<
2502            Box<
2503                dyn Future<
2504                        Output = Result<
2505                            Vec<std::collections::HashMap<String, crate::value::Value>>,
2506                            crate::DbError,
2507                        >,
2508                    > + Send
2509                    + 'a,
2510            >,
2511        > {
2512            Box::pin(async move { Ok(vec![]) })
2513        }
2514
2515        fn begin_transaction<'a>(
2516            &'a mut self,
2517        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2518            Box::pin(async move { Ok(()) })
2519        }
2520
2521        fn commit<'a>(
2522            &'a mut self,
2523        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2524            Box::pin(async move { Ok(()) })
2525        }
2526
2527        fn rollback<'a>(
2528            &'a mut self,
2529        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2530            Box::pin(async move { Ok(()) })
2531        }
2532
2533        fn is_connected(&self) -> bool {
2534            self.connected
2535        }
2536
2537        fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
2538            Box::pin(async move { true })
2539        }
2540
2541        fn close<'a>(
2542            &'a mut self,
2543        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
2544            Box::pin(async move {
2545                self.connected = false;
2546                Ok(())
2547            })
2548        }
2549    }
2550
2551    struct MockConnectionFactory;
2552
2553    #[async_trait]
2554    impl ConnectionFactory for MockConnectionFactory {
2555        async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
2556            Ok(Box::new(MockConnection::new()))
2557        }
2558    }
2559
2560    #[tokio::test]
2561    async fn test_pool_config_builder() -> Result<(), Box<dyn std::error::Error>> {
2562        let config = PoolConfigBuilder::new().max_size(50).min_idle(10).build()?;
2563
2564        assert_eq!(config.max_size, 50);
2565        assert_eq!(config.min_idle, 10);
2566        Ok(())
2567    }
2568
2569    #[test]
2570    fn test_pool_status_display() {
2571        let status = PoolStatus {
2572            idle: 5,
2573            active: 10,
2574            max: 100,
2575            min: 5,
2576            waiters: 0,
2577        };
2578
2579        let display = format!("{:?}", status);
2580        assert!(display.contains("idle"));
2581        assert!(display.contains("active"));
2582    }
2583
2584    #[test]
2585    fn test_default_pool_config() {
2586        let config = PoolConfig::default();
2587        assert_eq!(config.max_size, 100);
2588        assert_eq!(config.min_idle, 0);
2589        assert_eq!(config.acquire_timeout.as_secs(), 30);
2590        assert_eq!(config.idle_timeout.as_secs(), 600);
2591        assert_eq!(config.max_lifetime.as_secs(), 1800);
2592    }
2593
2594    #[tokio::test]
2595    async fn test_pool_config_clone() {
2596        let config = PoolConfig::default();
2597        let cloned = config.clone();
2598        assert_eq!(cloned.max_size, config.max_size);
2599        assert_eq!(cloned.min_idle, config.min_idle);
2600    }
2601
2602    #[test]
2603    fn test_pool_config_builder_default() -> Result<(), Box<dyn std::error::Error>> {
2604        let builder = PoolConfigBuilder::new();
2605        let config = builder.build()?;
2606        assert_eq!(config.max_size, 100);
2607        Ok(())
2608    }
2609
2610    #[test]
2611    fn test_pool_config_validate() {
2612        let result = PoolConfigBuilder::new().max_size(0).build();
2613        assert!(result.is_err());
2614
2615        let result = PoolConfigBuilder::new().max_size(10).min_idle(20).build();
2616        assert!(result.is_err());
2617    }
2618
2619    #[test]
2620    fn test_pool_config_validate_duration_upper_bound() {
2621        use std::time::Duration;
2622
2623        // u64::MAX 秒应被拒绝(远超 u32::MAX 上限)
2624        let config = PoolConfig {
2625            max_size: 10,
2626            min_idle: 1,
2627            acquire_timeout: Duration::from_secs(u64::MAX),
2628            idle_timeout: Duration::from_secs(1),
2629            max_lifetime: Duration::from_secs(1),
2630            connection_timeout: Duration::from_secs(5),
2631            tls: None,
2632            query_timeout: None,
2633            max_rows: None,
2634            memory_limit: None,
2635            on_event: None,
2636            test_before_acquire: false,
2637            prewarm: false,
2638        };
2639        assert!(config.validate().is_err());
2640
2641        // u32::MAX 秒(≈136 年)恰好在上限内,应通过
2642        let config = PoolConfig {
2643            max_size: 10,
2644            min_idle: 1,
2645            acquire_timeout: Duration::from_secs(u32::MAX as u64),
2646            idle_timeout: Duration::from_secs(1),
2647            max_lifetime: Duration::from_secs(1),
2648            connection_timeout: Duration::from_secs(5),
2649            tls: None,
2650            query_timeout: None,
2651            max_rows: None,
2652            memory_limit: None,
2653            on_event: None,
2654            test_before_acquire: false,
2655            prewarm: false,
2656        };
2657        assert!(config.validate().is_ok());
2658
2659        // u32::MAX + 1 秒应被拒绝
2660        let config = PoolConfig {
2661            max_size: 10,
2662            min_idle: 1,
2663            acquire_timeout: Duration::from_secs(u32::MAX as u64 + 1),
2664            idle_timeout: Duration::from_secs(1),
2665            max_lifetime: Duration::from_secs(1),
2666            connection_timeout: Duration::from_secs(5),
2667            tls: None,
2668            query_timeout: None,
2669            max_rows: None,
2670            memory_limit: None,
2671            on_event: None,
2672            test_before_acquire: false,
2673            prewarm: false,
2674        };
2675        assert!(config.validate().is_err());
2676    }
2677
2678    #[test]
2679    fn test_pool_config_test_before_acquire_default() {
2680        // P1-1:test_before_acquire 默认关闭
2681        let config = PoolConfig::default();
2682        assert!(!config.test_before_acquire);
2683    }
2684
2685    #[test]
2686    fn test_pool_config_builder_test_before_acquire() {
2687        // P1-1:builder 设置 test_before_acquire
2688        let config = PoolConfigBuilder::new()
2689            .test_before_acquire(true)
2690            .build()
2691            .unwrap();
2692        assert!(config.test_before_acquire);
2693    }
2694
2695    #[tokio::test]
2696    async fn test_pool_acquire_and_release() -> Result<(), Box<dyn std::error::Error>> {
2697        let config = PoolConfigBuilder::new().max_size(5).min_idle(1).build()?;
2698        let factory = Arc::new(MockConnectionFactory);
2699        let pool = Pool::new(config, factory)?;
2700
2701        let conn = pool.acquire().await?;
2702        let status = pool.status().await;
2703        assert_eq!(status.active, 1);
2704        assert_eq!(status.idle, 0);
2705
2706        pool.release(conn).await;
2707        let status = pool.status().await;
2708        assert_eq!(status.idle, 1);
2709
2710        // 再次获取应该复用空闲连接
2711        let _conn2 = pool.acquire().await?;
2712        let status = pool.status().await;
2713        assert_eq!(status.idle, 0);
2714        Ok(())
2715    }
2716
2717    #[tokio::test]
2718    async fn test_pool_status() -> Result<(), Box<dyn std::error::Error>> {
2719        let config = PoolConfigBuilder::new().max_size(10).min_idle(2).build()?;
2720        let factory = Arc::new(MockConnectionFactory);
2721        let pool = Pool::new(config, factory)?;
2722
2723        let status = pool.status().await;
2724        assert_eq!(status.max, 10);
2725        assert_eq!(status.min, 2);
2726        assert_eq!(status.active, 0);
2727        Ok(())
2728    }
2729
2730    #[tokio::test]
2731    async fn test_pool_close_all() -> Result<(), Box<dyn std::error::Error>> {
2732        let config = PoolConfigBuilder::new().max_size(5).build()?;
2733        let factory = Arc::new(MockConnectionFactory);
2734        let pool = Pool::new(config, factory)?;
2735
2736        // 创建几个连接然后释放
2737        let conn1 = pool.acquire().await?;
2738        let conn2 = pool.acquire().await?;
2739        pool.release(conn1).await;
2740        pool.release(conn2).await;
2741
2742        pool.close_all().await;
2743        let status = pool.status().await;
2744        assert_eq!(status.idle, 0);
2745        assert_eq!(status.active, 0);
2746        Ok(())
2747    }
2748
2749    #[tokio::test]
2750    async fn test_pool_reap_idle() -> Result<(), Box<dyn std::error::Error>> {
2751        let config = PoolConfigBuilder::new()
2752            .max_size(5)
2753            .idle_timeout(0) // 立即超时
2754            .build()?;
2755        let factory = Arc::new(MockConnectionFactory);
2756        let pool = Pool::new(config, factory)?;
2757
2758        let conn = pool.acquire().await?;
2759        pool.release(conn).await;
2760
2761        // 等待一下确保空闲超时
2762        tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
2763
2764        pool.reap_idle().await;
2765        let status = pool.status().await;
2766        assert_eq!(status.idle, 0);
2767        Ok(())
2768    }
2769
2770    /// H-7 验证:acquire_timeout 默认 30s
2771    ///
2772    /// PoolConfig::default().acquire_timeout == 30s
2773    /// Pool::acquire() 内部使用 `deadline = Instant::now() + acquire_timeout`
2774    /// 超时后返回 `PoolError::Timeout`。
2775    #[tokio::test]
2776    async fn test_h7_acquire_timeout_default_30s() {
2777        let config = PoolConfig::default();
2778        assert_eq!(
2779            config.acquire_timeout,
2780            Duration::from_secs(30),
2781            "H-7: acquire_timeout 默认应为 30s"
2782        );
2783    }
2784
2785    /// H-7 验证:acquire_timeout 可通过 builder 配置
2786    #[tokio::test]
2787    async fn test_h7_acquire_timeout_configurable() -> Result<(), Box<dyn std::error::Error>> {
2788        let config = PoolConfigBuilder::new()
2789            .max_size(1)
2790            .acquire_timeout(5) // 5s
2791            .build()?;
2792        assert_eq!(config.acquire_timeout, Duration::from_secs(5));
2793
2794        // 创建 max_size=1 的池,acquire 一个连接(占满),第二次 acquire 应超时
2795        let factory = Arc::new(MockConnectionFactory);
2796        let pool = Pool::new(config, factory)?;
2797        let _conn1 = pool.acquire().await?;
2798
2799        // 第二次 acquire 应在 5s 后超时(这里用 1ms 超时配置加速测试)
2800        let fast_config = PoolConfigBuilder::new()
2801            .max_size(1)
2802            .acquire_timeout(0) // 立即超时(0s 超时;deadline 为 now)
2803            .build()?;
2804        // 注意:acquire_timeout(0) 是合法值,表示 deadline 为 now
2805        // 实际行为:第一次循环即检查 deadline,返回 Timeout
2806        let fast_pool = Pool::new(fast_config, Arc::new(MockConnectionFactory))?;
2807        let _fast_conn = fast_pool.acquire().await?; // 占满 max_size=1
2808        let result = fast_pool.acquire().await;
2809        assert!(
2810            matches!(result, Err(PoolError::Timeout)),
2811            "H-7: 应返回 Timeout"
2812        );
2813        Ok(())
2814    }
2815
2816    // ==================== M-7 健康检查测试 ====================
2817
2818    #[tokio::test]
2819    async fn test_m7_health_check_removes_nothing_when_all_healthy(
2820    ) -> Result<(), Box<dyn std::error::Error>> {
2821        // 所有连接健康时,health_check 应返回 0
2822        let config = PoolConfigBuilder::new().max_size(5).build()?;
2823        let factory = Arc::new(MockConnectionFactory);
2824        let pool = Pool::new(config, factory)?;
2825
2826        // 创建 3 个连接并归还到池中
2827        let conn1 = pool.acquire().await?;
2828        let conn2 = pool.acquire().await?;
2829        let conn3 = pool.acquire().await?;
2830        pool.release(conn1).await;
2831        pool.release(conn2).await;
2832        pool.release(conn3).await;
2833
2834        let removed = pool.health_check().await;
2835        assert_eq!(removed, 0, "Healthy connections should not be removed");
2836
2837        let status = pool.status().await;
2838        assert_eq!(status.idle, 3);
2839        assert_eq!(status.active, 3);
2840        Ok(())
2841    }
2842
2843    #[tokio::test]
2844    async fn test_m7_health_check_returns_zero_for_empty_pool(
2845    ) -> Result<(), Box<dyn std::error::Error>> {
2846        let config = PoolConfigBuilder::new().max_size(5).build()?;
2847        let factory = Arc::new(MockConnectionFactory);
2848        let pool = Pool::new(config, factory)?;
2849
2850        let removed = pool.health_check().await;
2851        assert_eq!(removed, 0);
2852        Ok(())
2853    }
2854
2855    // ==================== 生产 Bug 复现测试 ====================
2856
2857    /// 可追踪创建次数的连接工厂
2858    struct CountingFactory {
2859        count: AtomicU32,
2860    }
2861
2862    impl CountingFactory {
2863        fn new() -> Self {
2864            Self {
2865                count: AtomicU32::new(0),
2866            }
2867        }
2868        fn created_count(&self) -> u32 {
2869            self.count.load(Ordering::SeqCst)
2870        }
2871    }
2872
2873    #[async_trait]
2874    impl ConnectionFactory for CountingFactory {
2875        async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
2876            self.count.fetch_add(1, Ordering::SeqCst);
2877            Ok(Box::new(MockConnection::new()))
2878        }
2879    }
2880
2881    /// 生产 Bug 复现:release() 重置 created_at 导致连接永不过期
2882    ///
2883    /// 症状:生产环境运行 30 分钟后间歇性 "connection timeout"
2884    /// 根因:release() 中 created_at 被重置为 now(),max_lifetime 检查永远不触发
2885    /// 期望:超过 max_lifetime 的连接应被回收并创建新连接
2886    #[tokio::test]
2887    async fn test_production_bug_max_lifetime_never_expires(
2888    ) -> Result<(), Box<dyn std::error::Error>> {
2889        // 注意:PoolConfigBuilder::max_lifetime() 接受秒,这里需要毫秒级精度
2890        // 所以直接构造 PoolConfig
2891        let config = PoolConfig {
2892            max_size: 5,
2893            min_idle: 0,
2894            acquire_timeout: Duration::from_secs(30),
2895            idle_timeout: Duration::from_secs(600),
2896            max_lifetime: Duration::from_millis(100), // 100ms
2897            connection_timeout: Duration::from_secs(10),
2898            tls: None,
2899            query_timeout: None,
2900            max_rows: None,
2901            memory_limit: None,
2902            on_event: None,
2903            test_before_acquire: false,
2904            prewarm: false,
2905        };
2906        let factory = Arc::new(CountingFactory::new());
2907        let pool = Pool::new(config, factory.clone())?;
2908
2909        // 1. 创建连接
2910        let conn = pool.acquire().await?;
2911        assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
2912
2913        // 2. 归还连接(bug:重置 created_at)
2914        pool.release(conn).await;
2915
2916        // 3. 等待超过 max_lifetime
2917        tokio::time::sleep(Duration::from_millis(150)).await;
2918
2919        // 4. 再次获取 — 应检测到连接过期,创建新连接
2920        let conn2 = pool.acquire().await?;
2921
2922        // 5. 验证:如果 bug 存在,factory.created_count() 仍为 1(连接被复用,未过期)
2923        //         如果修复,factory.created_count() 应为 2(旧连接过期,创建新连接)
2924        assert_eq!(
2925            factory.created_count(),
2926            2,
2927            "超过 max_lifetime 后应创建新连接(旧连接应被回收)"
2928        );
2929
2930        pool.release(conn2).await;
2931        Ok(())
2932    }
2933
2934    // ==================== PooledConnection::Drop 自动归还测试 ====================
2935
2936    /// 验证 PooledConnection drop 时自动归还连接到池
2937    ///
2938    /// 修复前:PooledConnection 未实现 Drop,drop 时连接丢失,池耗尽
2939    /// 修复后:Drop 时 spawn 异步 release,连接自动归还
2940    #[tokio::test]
2941    async fn test_drop_auto_release_connection() -> Result<(), Box<dyn std::error::Error>> {
2942        let config = PoolConfigBuilder::new().max_size(2).build()?;
2943        let factory = Arc::new(CountingFactory::new());
2944        let pool = Pool::new(config, factory.clone())?;
2945
2946        // 1. acquire 一个连接(不显式 release)
2947        {
2948            let _conn = pool.acquire().await?;
2949            assert_eq!(factory.created_count(), 1, "应创建 1 个连接");
2950            let status = pool.status().await;
2951            assert_eq!(status.active, 1, "active 应为 1");
2952            assert_eq!(status.idle, 0, "idle 应为 0");
2953            // _conn 在此 drop
2954        }
2955
2956        // 2. 等待 Drop spawn 的异步 release 完成
2957        tokio::time::sleep(Duration::from_millis(50)).await;
2958
2959        // 3. 验证连接已自动归还到 idle 队列
2960        let status = pool.status().await;
2961        assert_eq!(status.idle, 1, "Drop 后连接应自动归还,idle 应为 1");
2962        assert_eq!(status.active, 1, "total_count 应为 1");
2963        assert_eq!(factory.created_count(), 1, "应复用归还的连接,不创建新连接");
2964        Ok(())
2965    }
2966
2967    /// 验证 Drop 自动归还后,连接可被再次 acquire 复用
2968    #[tokio::test]
2969    async fn test_drop_auto_release_then_reuse() -> Result<(), Box<dyn std::error::Error>> {
2970        let config = PoolConfigBuilder::new().max_size(1).build()?;
2971        let factory = Arc::new(CountingFactory::new());
2972        let pool = Pool::new(config, factory.clone())?;
2973
2974        // max_size=1,如果 Drop 不归还,第二次 acquire 会超时
2975        {
2976            let _conn = pool.acquire().await?;
2977        }
2978
2979        // 等待 Drop spawn 的 release 完成
2980        tokio::time::sleep(Duration::from_millis(50)).await;
2981
2982        // 再次 acquire 应复用归还的连接,不创建新连接
2983        let conn = pool.acquire().await?;
2984        assert_eq!(factory.created_count(), 1, "应复用归还的连接,不创建新连接");
2985
2986        pool.release(conn).await;
2987        Ok(())
2988    }
2989
2990    /// 验证 into_inner 后 Drop 不归还(连接被消费)
2991    #[tokio::test]
2992    async fn test_into_inner_does_not_return_to_pool() -> Result<(), Box<dyn std::error::Error>> {
2993        let config = PoolConfigBuilder::new().max_size(2).build()?;
2994        let factory = Arc::new(CountingFactory::new());
2995        let pool = Pool::new(config, factory.clone())?;
2996
2997        let conn = pool.acquire().await?;
2998        assert_eq!(factory.created_count(), 1);
2999
3000        // into_inner 消费连接,pool 字段设为 None
3001        let _raw_conn = conn.into_inner();
3002
3003        // 等待一段时间,确保不会有 Drop spawn
3004        tokio::time::sleep(Duration::from_millis(50)).await;
3005
3006        let status = pool.status().await;
3007        assert_eq!(status.idle, 0, "into_inner 后连接不应归还");
3008        assert_eq!(status.active, 1, "total_count 仍为 1(连接被外部持有)");
3009        Ok(())
3010    }
3011
3012    /// 验证显式 release 后 Drop 不会重复归还
3013    #[tokio::test]
3014    async fn test_explicit_release_no_double_return() -> Result<(), Box<dyn std::error::Error>> {
3015        let config = PoolConfigBuilder::new().max_size(2).build()?;
3016        let factory = Arc::new(CountingFactory::new());
3017        let pool = Pool::new(config, factory.clone())?;
3018
3019        let conn = pool.acquire().await?;
3020        pool.release(conn).await;
3021
3022        let status = pool.status().await;
3023        assert_eq!(status.idle, 1, "release 后 idle 应为 1");
3024
3025        // 再次 acquire + release 验证不会重复
3026        let conn = pool.acquire().await?;
3027        pool.release(conn).await;
3028
3029        let status = pool.status().await;
3030        assert_eq!(status.idle, 1, "再次 release 后 idle 仍应为 1(不重复)");
3031        assert_eq!(status.active, 1, "total_count 应为 1");
3032        Ok(())
3033    }
3034
3035    // ========================================================================
3036    // G-SX-4:query_stream 游标流式查询测试
3037    // ========================================================================
3038
3039    /// 带预设行数据的模拟连接,用于测试 `query_stream` 默认实现。
3040    struct CursorMockConn {
3041        rows: QueryRows,
3042        call_count: usize,
3043    }
3044
3045    impl CursorMockConn {
3046        fn new(rows: QueryRows) -> Self {
3047            Self {
3048                rows,
3049                call_count: 0,
3050            }
3051        }
3052    }
3053
3054    impl Connection for CursorMockConn {
3055        fn execute<'a>(
3056            &'a mut self,
3057            _sql: &'a str,
3058        ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
3059            Box::pin(async move { Ok(1) })
3060        }
3061
3062        fn query<'a>(
3063            &'a mut self,
3064            _sql: &'a str,
3065        ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
3066            Box::pin(async move {
3067                self.call_count += 1;
3068                Ok(self.rows.clone())
3069            })
3070        }
3071
3072        fn begin_transaction<'a>(
3073            &'a mut self,
3074        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3075            Box::pin(async move { Ok(()) })
3076        }
3077
3078        fn commit<'a>(
3079            &'a mut self,
3080        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3081            Box::pin(async move { Ok(()) })
3082        }
3083
3084        fn rollback<'a>(
3085            &'a mut self,
3086        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3087            Box::pin(async move { Ok(()) })
3088        }
3089
3090        fn is_connected(&self) -> bool {
3091            true
3092        }
3093
3094        fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
3095            Box::pin(async move { true })
3096        }
3097
3098        fn close<'a>(
3099            &'a mut self,
3100        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3101            Box::pin(async move { Ok(()) })
3102        }
3103    }
3104
3105    /// 模拟游标适配器:覆盖 `query_stream` 以逐行 yield,而非全量收集。
3106    struct CursorOverrideMockConn {
3107        rows: Vec<crate::value::Value>,
3108        yielded: usize,
3109    }
3110
3111    impl CursorOverrideMockConn {
3112        fn new(rows: Vec<crate::value::Value>) -> Self {
3113            Self { rows, yielded: 0 }
3114        }
3115    }
3116
3117    impl Connection for CursorOverrideMockConn {
3118        fn execute<'a>(
3119            &'a mut self,
3120            _sql: &'a str,
3121        ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
3122            Box::pin(async move { Ok(1) })
3123        }
3124
3125        fn query<'a>(
3126            &'a mut self,
3127            _sql: &'a str,
3128        ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>> {
3129            // 全量收集实现(不应被 cursor override 调用)
3130            Box::pin(async move {
3131                Ok(self
3132                    .rows
3133                    .iter()
3134                    .map(|v| {
3135                        let mut m = std::collections::HashMap::new();
3136                        m.insert("v".to_string(), v.clone());
3137                        m
3138                    })
3139                    .collect())
3140            })
3141        }
3142
3143        /// G-SX-4:覆盖 query_stream,逐行 yield 模拟真游标
3144        fn query_stream<'a>(
3145            &'a mut self,
3146            _sql: &'a str,
3147        ) -> Pin<Box<dyn futures::Stream<Item = QueryStreamItem> + Send + 'a>> {
3148            Box::pin(futures::stream::iter(
3149                self.rows
3150                    .iter()
3151                    .enumerate()
3152                    .map(|(i, v)| {
3153                        self.yielded = i + 1;
3154                        let mut m = std::collections::HashMap::new();
3155                        m.insert("v".to_string(), v.clone());
3156                        Ok(m)
3157                    })
3158                    .collect::<Vec<_>>(),
3159            ))
3160        }
3161
3162        fn begin_transaction<'a>(
3163            &'a mut self,
3164        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3165            Box::pin(async move { Ok(()) })
3166        }
3167
3168        fn commit<'a>(
3169            &'a mut self,
3170        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3171            Box::pin(async move { Ok(()) })
3172        }
3173
3174        fn rollback<'a>(
3175            &'a mut self,
3176        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3177            Box::pin(async move { Ok(()) })
3178        }
3179
3180        fn is_connected(&self) -> bool {
3181            true
3182        }
3183
3184        fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
3185            Box::pin(async move { true })
3186        }
3187
3188        fn close<'a>(
3189            &'a mut self,
3190        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3191            Box::pin(async move { Ok(()) })
3192        }
3193    }
3194
3195    /// G-SX-4 测试 1:默认 query_stream 逐行 yield 全量结果
3196    #[tokio::test]
3197    async fn test_query_stream_default_impl_yields_all_rows() {
3198        use futures::StreamExt;
3199        let rows: QueryRows = vec![
3200            std::collections::HashMap::from([
3201                ("id".to_string(), crate::value::Value::I64(1)),
3202                (
3203                    "name".to_string(),
3204                    crate::value::Value::String("alice".to_string()),
3205                ),
3206            ]),
3207            std::collections::HashMap::from([
3208                ("id".to_string(), crate::value::Value::I64(2)),
3209                (
3210                    "name".to_string(),
3211                    crate::value::Value::String("bob".to_string()),
3212                ),
3213            ]),
3214            std::collections::HashMap::from([
3215                ("id".to_string(), crate::value::Value::I64(3)),
3216                (
3217                    "name".to_string(),
3218                    crate::value::Value::String("carol".to_string()),
3219                ),
3220            ]),
3221        ];
3222        let mut conn = CursorMockConn::new(rows);
3223        let mut stream = conn.query_stream("SELECT id, name FROM users");
3224        let mut received: Vec<QueryStreamItem> = Vec::new();
3225        while let Some(item) = stream.next().await {
3226            received.push(item);
3227        }
3228        assert_eq!(received.len(), 3, "应收到 3 行");
3229        assert!(received.iter().all(|r| r.is_ok()), "所有项应为 Ok");
3230        drop(stream);
3231        assert_eq!(conn.call_count, 1, "默认实现应调用 query() 一次");
3232    }
3233
3234    /// G-SX-4 测试 2:默认 query_stream 空结果集
3235    #[tokio::test]
3236    async fn test_query_stream_default_empty_result() {
3237        use futures::StreamExt;
3238        let mut conn = CursorMockConn::new(Vec::new());
3239        let mut stream = conn.query_stream("SELECT * FROM empty_table");
3240        let mut count = 0;
3241        while let Some(_item) = stream.next().await {
3242            count += 1;
3243        }
3244        assert_eq!(count, 0, "空结果集应产生 0 项");
3245    }
3246
3247    /// G-SX-4 测试 3:默认 query_stream 错误传播
3248    #[tokio::test]
3249    async fn test_query_stream_default_error_propagation() {
3250        use futures::StreamExt;
3251        // 创建一个会返回错误的 mock
3252        struct ErrorMockConn;
3253        impl Connection for ErrorMockConn {
3254            fn execute<'a>(
3255                &'a mut self,
3256                _sql: &'a str,
3257            ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>>
3258            {
3259                Box::pin(async move { Ok(1) })
3260            }
3261            fn query<'a>(
3262                &'a mut self,
3263                _sql: &'a str,
3264            ) -> Pin<Box<dyn Future<Output = Result<QueryRows, crate::DbError>> + Send + 'a>>
3265            {
3266                Box::pin(async move { Err(crate::DbError::Internal("query failed".to_string())) })
3267            }
3268            fn begin_transaction<'a>(
3269                &'a mut self,
3270            ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3271                Box::pin(async move { Ok(()) })
3272            }
3273            fn commit<'a>(
3274                &'a mut self,
3275            ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3276                Box::pin(async move { Ok(()) })
3277            }
3278            fn rollback<'a>(
3279                &'a mut self,
3280            ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3281                Box::pin(async move { Ok(()) })
3282            }
3283            fn is_connected(&self) -> bool {
3284                true
3285            }
3286            fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
3287                Box::pin(async move { true })
3288            }
3289            fn close<'a>(
3290                &'a mut self,
3291            ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3292                Box::pin(async move { Ok(()) })
3293            }
3294        }
3295        let mut conn = ErrorMockConn;
3296        let mut stream = conn.query_stream("SELECT * FROM bad_table");
3297        let item = stream.next().await;
3298        assert!(item.is_some(), "应产生一项");
3299        assert!(item.unwrap().is_err(), "该项应为 Err");
3300    }
3301
3302    /// G-SX-4 测试 4:覆盖 query_stream 的适配器逐行 yield(模拟真游标)
3303    #[tokio::test]
3304    async fn test_query_stream_override_yields_rows_one_by_one() {
3305        use futures::StreamExt;
3306        let rows = vec![
3307            crate::value::Value::I64(10),
3308            crate::value::Value::I64(20),
3309            crate::value::Value::I64(30),
3310            crate::value::Value::I64(40),
3311            crate::value::Value::I64(50),
3312        ];
3313        let mut conn = CursorOverrideMockConn::new(rows);
3314        let values: Vec<i64> = {
3315            let mut stream = conn.query_stream("SELECT v FROM seq");
3316            let mut vals: Vec<i64> = Vec::new();
3317            while let Some(Ok(row)) = stream.next().await {
3318                if let crate::value::Value::I64(v) = row.get("v").unwrap() {
3319                    vals.push(*v);
3320                }
3321            }
3322            vals
3323        };
3324        assert_eq!(values, vec![10, 20, 30, 40, 50], "应按顺序收到全部 5 行");
3325        assert_eq!(conn.yielded, 5, "应逐行 yield 5 次(真游标覆盖)");
3326    }
3327
3328    /// G-SX-4 测试 5:覆盖 query_stream 提前 drop 流(消费者中断)
3329    #[tokio::test]
3330    async fn test_query_stream_override_early_drop() {
3331        use futures::StreamExt;
3332        let rows = vec![
3333            crate::value::Value::I64(1),
3334            crate::value::Value::I64(2),
3335            crate::value::Value::I64(3),
3336        ];
3337        let mut conn = CursorOverrideMockConn::new(rows);
3338        {
3339            let mut stream = conn.query_stream("SELECT v FROM seq");
3340            let first = stream.next().await;
3341            assert!(first.is_some(), "第一项应存在");
3342            // 提前 drop stream — 模拟消费者中断
3343            drop(stream);
3344        }
3345        // 连接仍可用
3346        assert!(conn.is_connected(), "提前 drop 流后连接仍应可用");
3347    }
3348
3349    /// TASK-021:连接池预热测试
3350    #[tokio::test]
3351    async fn test_pool_prewarm() -> Result<(), Box<dyn std::error::Error>> {
3352        use std::sync::atomic::AtomicU32;
3353
3354        // 创建可计数的连接工厂
3355        let create_count = Arc::new(AtomicU32::new(0));
3356        let create_count_clone = create_count.clone();
3357
3358        struct CountingFactory {
3359            count: Arc<AtomicU32>,
3360        }
3361
3362        #[async_trait]
3363        impl ConnectionFactory for CountingFactory {
3364            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3365                self.count.fetch_add(1, Ordering::SeqCst);
3366                Ok(Box::new(MockConnection::new()))
3367            }
3368        }
3369
3370        // 配置:max_size=10, min_idle=5, prewarm=true
3371        let config = PoolConfigBuilder::new()
3372            .max_size(10)
3373            .min_idle(5)
3374            .prewarm(true)
3375            .build()?;
3376
3377        let factory = Arc::new(CountingFactory {
3378            count: create_count_clone,
3379        });
3380
3381        let pool = Pool::new(config, factory)?;
3382
3383        // 预热前:空闲连接为 0
3384        let status_before = pool.status().await;
3385        assert_eq!(status_before.idle, 0, "预热前 idle 应为 0");
3386
3387        // 执行预热
3388        pool.prewarm().await;
3389
3390        // 预热后:空闲连接应 >= min_idle(5)
3391        let status_after = pool.status().await;
3392        assert!(
3393            status_after.idle >= 5,
3394            "预热后 idle 应 >= 5,实际: {}",
3395            status_after.idle
3396        );
3397
3398        // 验证工厂被调用了 5 次(min_idle)
3399        assert_eq!(
3400            create_count.load(Ordering::SeqCst),
3401            5,
3402            "工厂应被调用 5 次(min_idle)"
3403        );
3404
3405        Ok(())
3406    }
3407
3408    /// TASK-021:预热失败不阻断池创建
3409    #[tokio::test]
3410    async fn test_pool_prewarm_failure_non_blocking() -> Result<(), Box<dyn std::error::Error>> {
3411        use std::sync::atomic::AtomicBool;
3412
3413        struct FailingFactory {
3414            failed: Arc<AtomicBool>,
3415        }
3416
3417        #[async_trait]
3418        impl ConnectionFactory for FailingFactory {
3419            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3420                self.failed.store(true, Ordering::SeqCst);
3421                // 模拟连接失败
3422                Err(crate::DbError::Internal(
3423                    "simulated connection failure".to_string(),
3424                ))
3425            }
3426        }
3427
3428        let failed = Arc::new(AtomicBool::new(false));
3429        let mut config = PoolConfigBuilder::new()
3430            .max_size(10)
3431            .min_idle(3)
3432            .prewarm(true)
3433            .build()?;
3434        config.connection_timeout = std::time::Duration::from_secs(1); // 缩短超时以加快测试
3435
3436        let factory = Arc::new(FailingFactory {
3437            failed: failed.clone(),
3438        });
3439
3440        // 池创建应成功(即使预热失败)
3441        let pool = Pool::new(config, factory)?;
3442        pool.prewarm().await; // 预热失败不应 panic
3443
3444        // 验证工厂被调用了 3 次(尝试预热 3 个连接)
3445        assert!(failed.load(Ordering::SeqCst), "工厂应被调用且失败");
3446
3447        // 池仍然可用(acquire 会尝试创建新连接)
3448        let status = pool.status().await;
3449        assert_eq!(status.max, 10, "池配置应正常");
3450
3451        Ok(())
3452    }
3453
3454    /// TASK-021:prewarm=false 时预热不执行
3455    #[tokio::test]
3456    async fn test_pool_prewarm_disabled() -> Result<(), Box<dyn std::error::Error>> {
3457        use std::sync::atomic::AtomicU32;
3458
3459        let create_count = Arc::new(AtomicU32::new(0));
3460        let create_count_clone = create_count.clone();
3461
3462        struct CountingFactory {
3463            count: Arc<AtomicU32>,
3464        }
3465
3466        #[async_trait]
3467        impl ConnectionFactory for CountingFactory {
3468            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3469                self.count.fetch_add(1, Ordering::SeqCst);
3470                Ok(Box::new(MockConnection::new()))
3471            }
3472        }
3473
3474        // 配置:prewarm=false
3475        let config = PoolConfigBuilder::new()
3476            .max_size(10)
3477            .min_idle(5)
3478            .prewarm(false) // 禁用预热
3479            .build()?;
3480
3481        let factory = Arc::new(CountingFactory {
3482            count: create_count_clone,
3483        });
3484
3485        let pool = Pool::new(config, factory)?;
3486        pool.prewarm().await; // 应直接返回,不创建连接
3487
3488        // 验证工厂未被调用
3489        assert_eq!(
3490            create_count.load(Ordering::SeqCst),
3491            0,
3492            "prewarm=false 时工厂不应被调用"
3493        );
3494
3495        let status = pool.status().await;
3496        assert_eq!(status.idle, 0, "idle 应为 0");
3497
3498        Ok(())
3499    }
3500
3501    /// v3.2.0:Pool::new_async with prewarm=true 预热后 idle >= min_idle
3502    #[tokio::test]
3503    async fn test_pool_new_async_with_prewarm() -> Result<(), Box<dyn std::error::Error>> {
3504        use std::sync::atomic::AtomicU32;
3505
3506        let create_count = Arc::new(AtomicU32::new(0));
3507        let create_count_clone = create_count.clone();
3508
3509        struct CountingFactory {
3510            count: Arc<AtomicU32>,
3511        }
3512
3513        #[async_trait]
3514        impl ConnectionFactory for CountingFactory {
3515            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3516                self.count.fetch_add(1, Ordering::SeqCst);
3517                Ok(Box::new(MockConnection::new()))
3518            }
3519        }
3520
3521        let config = PoolConfigBuilder::new()
3522            .max_size(10)
3523            .min_idle(5)
3524            .prewarm(true)
3525            .build()?;
3526
3527        let factory = Arc::new(CountingFactory {
3528            count: create_count_clone,
3529        });
3530
3531        let pool = Pool::new_async(config, factory).await?;
3532
3533        let status = pool.status().await;
3534        assert!(
3535            status.idle >= 5,
3536            "new_async prewarm=true 后 idle 应 >= 5,实际: {}",
3537            status.idle
3538        );
3539        assert_eq!(create_count.load(Ordering::SeqCst), 5, "工厂应被调用 5 次");
3540
3541        Ok(())
3542    }
3543
3544    /// v3.2.0:Pool::new_async with prewarm=false 等同 Pool::new
3545    #[tokio::test]
3546    async fn test_pool_new_async_without_prewarm() -> Result<(), Box<dyn std::error::Error>> {
3547        use std::sync::atomic::AtomicU32;
3548
3549        let create_count = Arc::new(AtomicU32::new(0));
3550        let create_count_clone = create_count.clone();
3551
3552        struct CountingFactory {
3553            count: Arc<AtomicU32>,
3554        }
3555
3556        #[async_trait]
3557        impl ConnectionFactory for CountingFactory {
3558            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3559                self.count.fetch_add(1, Ordering::SeqCst);
3560                Ok(Box::new(MockConnection::new()))
3561            }
3562        }
3563
3564        let config = PoolConfigBuilder::new()
3565            .max_size(10)
3566            .min_idle(5)
3567            .prewarm(false)
3568            .build()?;
3569
3570        let factory = Arc::new(CountingFactory {
3571            count: create_count_clone,
3572        });
3573
3574        let pool = Pool::new_async(config, factory).await?;
3575
3576        let status = pool.status().await;
3577        assert_eq!(status.idle, 0, "prewarm=false 时 idle 应为 0");
3578        assert_eq!(create_count.load(Ordering::SeqCst), 0, "工厂不应被调用");
3579
3580        Ok(())
3581    }
3582
3583    /// v3.2.0:Pool::new_async 预热失败不阻断池创建
3584    #[tokio::test]
3585    async fn test_pool_new_async_failure_non_blocking() -> Result<(), Box<dyn std::error::Error>> {
3586        struct FailingFactory;
3587
3588        #[async_trait]
3589        impl ConnectionFactory for FailingFactory {
3590            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3591                Err(crate::DbError::Internal("simulated failure".to_string()))
3592            }
3593        }
3594
3595        let mut config = PoolConfigBuilder::new()
3596            .max_size(10)
3597            .min_idle(3)
3598            .prewarm(true)
3599            .build()?;
3600        config.connection_timeout = std::time::Duration::from_secs(1);
3601
3602        let pool = Pool::new_async(config, Arc::new(FailingFactory)).await?;
3603
3604        let status = pool.status().await;
3605        assert_eq!(status.max, 10, "池配置应正常");
3606
3607        Ok(())
3608    }
3609
3610    /// v3.2.0:progressive_prewarm 分批建连
3611    #[cfg(feature = "auto-prewarm")]
3612    #[tokio::test]
3613    async fn test_pool_progressive_prewarm() -> Result<(), Box<dyn std::error::Error>> {
3614        use std::sync::atomic::AtomicU32;
3615
3616        let create_count = Arc::new(AtomicU32::new(0));
3617        let create_count_clone = create_count.clone();
3618
3619        struct CountingFactory {
3620            count: Arc<AtomicU32>,
3621        }
3622
3623        #[async_trait]
3624        impl ConnectionFactory for CountingFactory {
3625            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3626                self.count.fetch_add(1, Ordering::SeqCst);
3627                Ok(Box::new(MockConnection::new()))
3628            }
3629        }
3630
3631        let config = PoolConfigBuilder::new()
3632            .max_size(20)
3633            .min_idle(6)
3634            .prewarm(true)
3635            .build()?;
3636
3637        let factory = Arc::new(CountingFactory {
3638            count: create_count_clone,
3639        });
3640
3641        let pool = Pool::new(config, factory)?;
3642
3643        let progress = crate::prewarm::PrewarmProgress::new(6);
3644        pool.progressive_prewarm(
3645            2,
3646            std::time::Duration::from_millis(5),
3647            std::time::Duration::from_secs(10),
3648            &progress,
3649        )
3650        .await;
3651
3652        let snap = progress.snapshot();
3653        assert!(
3654            snap.warmed >= 6,
3655            "progressive_prewarm 后 warmed 应 >= 6,实际: {}",
3656            snap.warmed
3657        );
3658        assert!(snap.is_completed, "应标记完成");
3659        assert_eq!(create_count.load(Ordering::SeqCst), 6, "工厂应被调用 6 次");
3660
3661        let status = pool.status().await;
3662        assert!(status.idle >= 6, "池中 idle 应 >= 6");
3663
3664        Ok(())
3665    }
3666
3667    /// v3.2.0:progressive_prewarm total_timeout=0 立即停止
3668    #[cfg(feature = "auto-prewarm")]
3669    #[tokio::test]
3670    async fn test_pool_progressive_prewarm_timeout_zero() -> Result<(), Box<dyn std::error::Error>>
3671    {
3672        use std::sync::atomic::AtomicU32;
3673
3674        let create_count = Arc::new(AtomicU32::new(0));
3675        let create_count_clone = create_count.clone();
3676
3677        struct CountingFactory {
3678            count: Arc<AtomicU32>,
3679        }
3680
3681        #[async_trait]
3682        impl ConnectionFactory for CountingFactory {
3683            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3684                self.count.fetch_add(1, Ordering::SeqCst);
3685                Ok(Box::new(MockConnection::new()))
3686            }
3687        }
3688
3689        let config = PoolConfigBuilder::new()
3690            .max_size(20)
3691            .min_idle(10)
3692            .prewarm(true)
3693            .build()?;
3694
3695        let factory = Arc::new(CountingFactory {
3696            count: create_count_clone,
3697        });
3698
3699        let pool = Pool::new(config, factory)?;
3700
3701        let progress = crate::prewarm::PrewarmProgress::new(10);
3702        pool.progressive_prewarm(
3703            2,
3704            std::time::Duration::from_millis(5),
3705            std::time::Duration::ZERO,
3706            &progress,
3707        )
3708        .await;
3709
3710        let snap = progress.snapshot();
3711        assert!(snap.is_completed, "应标记完成");
3712        assert!(
3713            snap.warmed <= 2,
3714            "total_timeout=0 时最多建一批(batch_size=2),实际: {}",
3715            snap.warmed
3716        );
3717
3718        Ok(())
3719    }
3720
3721    /// v3.2.0:progressive_prewarm prewarm=false 时直接返回
3722    #[cfg(feature = "auto-prewarm")]
3723    #[tokio::test]
3724    async fn test_pool_progressive_prewarm_disabled() -> Result<(), Box<dyn std::error::Error>> {
3725        use std::sync::atomic::AtomicU32;
3726
3727        let create_count = Arc::new(AtomicU32::new(0));
3728        let create_count_clone = create_count.clone();
3729
3730        struct CountingFactory {
3731            count: Arc<AtomicU32>,
3732        }
3733
3734        #[async_trait]
3735        impl ConnectionFactory for CountingFactory {
3736            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3737                self.count.fetch_add(1, Ordering::SeqCst);
3738                Ok(Box::new(MockConnection::new()))
3739            }
3740        }
3741
3742        let config = PoolConfigBuilder::new()
3743            .max_size(20)
3744            .min_idle(10)
3745            .prewarm(false)
3746            .build()?;
3747
3748        let factory = Arc::new(CountingFactory {
3749            count: create_count_clone,
3750        });
3751
3752        let pool = Pool::new(config, factory)?;
3753
3754        let progress = crate::prewarm::PrewarmProgress::new(10);
3755        pool.progressive_prewarm(
3756            2,
3757            std::time::Duration::from_millis(5),
3758            std::time::Duration::from_secs(10),
3759            &progress,
3760        )
3761        .await;
3762
3763        let snap = progress.snapshot();
3764        assert!(snap.is_completed, "应标记完成");
3765        assert_eq!(snap.warmed, 0, "prewarm=false 时不应建连");
3766        assert_eq!(create_count.load(Ordering::SeqCst), 0, "工厂不应被调用");
3767
3768        Ok(())
3769    }
3770
3771    /// v3.2.0:progressive_prewarm 失败不阻断(failing factory)
3772    #[cfg(feature = "auto-prewarm")]
3773    #[tokio::test]
3774    async fn test_pool_progressive_prewarm_failure_non_blocking(
3775    ) -> Result<(), Box<dyn std::error::Error>> {
3776        struct FailingFactory;
3777
3778        #[async_trait]
3779        impl ConnectionFactory for FailingFactory {
3780            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3781                Err(crate::DbError::Internal("simulated failure".to_string()))
3782            }
3783        }
3784
3785        let mut config = PoolConfigBuilder::new()
3786            .max_size(20)
3787            .min_idle(5)
3788            .prewarm(true)
3789            .build()?;
3790        config.connection_timeout = std::time::Duration::from_secs(1);
3791
3792        let pool = Pool::new(config, Arc::new(FailingFactory))?;
3793
3794        let progress = crate::prewarm::PrewarmProgress::new(5);
3795        pool.progressive_prewarm(
3796            2,
3797            std::time::Duration::from_millis(5),
3798            std::time::Duration::from_secs(5),
3799            &progress,
3800        )
3801        .await;
3802
3803        let snap = progress.snapshot();
3804        assert!(snap.is_completed, "应标记完成");
3805        assert_eq!(snap.warmed, 0, "全部失败时 warmed=0");
3806        assert!(snap.failed > 0, "应有失败记录");
3807
3808        Ok(())
3809    }
3810
3811    /// Prometheus 风格统计:acquire/release 计数与连接创建计数
3812    #[tokio::test]
3813    async fn test_pool_metrics_acquire_release() -> Result<(), Box<dyn std::error::Error>> {
3814        let config = PoolConfigBuilder::new().max_size(10).build()?;
3815        let pool = Pool::new(config, Arc::new(MockConnectionFactory))?;
3816
3817        let metrics = pool.pool_metrics();
3818        assert_eq!(metrics.acquire_count, 0);
3819        assert_eq!(metrics.release_count, 0);
3820        assert_eq!(metrics.connection_created_count, 0);
3821
3822        let conn = pool.acquire().await?;
3823        let metrics = pool.pool_metrics();
3824        assert_eq!(metrics.acquire_count, 1);
3825        assert_eq!(metrics.connection_created_count, 1);
3826        assert_eq!(metrics.acquire_failed_count, 0);
3827
3828        pool.release(conn).await;
3829        let metrics = pool.pool_metrics();
3830        assert_eq!(metrics.release_count, 1);
3831        // 连接归还到空闲队列,未被关闭
3832        assert_eq!(metrics.connection_closed_count, 0);
3833
3834        Ok(())
3835    }
3836
3837    /// Prometheus 风格统计:获取失败计数(工厂创建连接失败)
3838    #[tokio::test]
3839    async fn test_pool_metrics_acquire_failed() -> Result<(), Box<dyn std::error::Error>> {
3840        struct FailingFactory;
3841
3842        #[async_trait]
3843        impl ConnectionFactory for FailingFactory {
3844            async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3845                Err(crate::DbError::Internal("simulated failure".to_string()))
3846            }
3847        }
3848
3849        let config = PoolConfigBuilder::new().max_size(10).build()?;
3850        let pool = Pool::new(config, Arc::new(FailingFactory))?;
3851
3852        let result = pool.acquire().await;
3853        assert!(result.is_err());
3854
3855        let metrics = pool.pool_metrics();
3856        assert_eq!(metrics.acquire_failed_count, 1);
3857        assert_eq!(metrics.acquire_count, 0);
3858
3859        Ok(())
3860    }
3861
3862    /// Prometheus 风格统计:连接关闭计数(close_all 后空闲连接被关闭)
3863    #[tokio::test]
3864    async fn test_pool_metrics_connection_closed() -> Result<(), Box<dyn std::error::Error>> {
3865        let config = PoolConfigBuilder::new().max_size(10).build()?;
3866        let pool = Pool::new(config, Arc::new(MockConnectionFactory))?;
3867
3868        let conn = pool.acquire().await?;
3869        pool.release(conn).await;
3870
3871        let status = pool.status().await;
3872        assert_eq!(status.idle, 1);
3873
3874        pool.close_all().await;
3875
3876        let metrics = pool.pool_metrics();
3877        assert_eq!(metrics.connection_closed_count, 1);
3878        assert_eq!(metrics.connection_created_count, 1);
3879
3880        Ok(())
3881    }
3882
3883    /// Prometheus 风格统计:平均获取等待时长计算
3884    #[test]
3885    fn test_pool_metrics_average_wait_time() {
3886        let metrics = PoolMetrics {
3887            acquire_count: 4,
3888            acquire_failed_count: 1,
3889            acquire_wait_time: Duration::from_millis(200),
3890            release_count: 4,
3891            connection_created_count: 2,
3892            connection_closed_count: 0,
3893        };
3894        assert_eq!(
3895            metrics.average_acquire_wait_time(),
3896            Duration::from_millis(50)
3897        );
3898
3899        // 无成功获取时平均等待时长为 0
3900        let empty = PoolMetrics::default();
3901        assert_eq!(empty.average_acquire_wait_time(), Duration::ZERO);
3902    }
3903
3904    #[tokio::test]
3905    async fn test_shutdown_with_timeout_fast_return_when_empty() {
3906        let factory = Arc::new(MockConnectionFactory) as Arc<dyn ConnectionFactory>;
3907        let config = PoolConfigBuilder::new().max_size(4).build().unwrap();
3908        let pool = Pool::new(config, factory).unwrap();
3909        pool.shutdown_with_timeout(Duration::from_secs(1)).await;
3910        assert!(pool.closed.load(Ordering::SeqCst));
3911        assert_eq!(pool.total_count.load(Ordering::SeqCst), 0);
3912    }
3913
3914    #[tokio::test]
3915    async fn test_shutdown_delegates_to_shutdown_with_timeout() {
3916        let factory = Arc::new(MockConnectionFactory) as Arc<dyn ConnectionFactory>;
3917        let config = PoolConfigBuilder::new().max_size(4).build().unwrap();
3918        let pool = Pool::new(config, factory).unwrap();
3919        pool.shutdown().await;
3920        assert!(pool.closed.load(Ordering::SeqCst));
3921    }
3922
3923    #[tokio::test]
3924    async fn test_shutdown_with_timeout_idempotent() {
3925        let factory = Arc::new(MockConnectionFactory) as Arc<dyn ConnectionFactory>;
3926        let config = PoolConfigBuilder::new().max_size(4).build().unwrap();
3927        let pool = Pool::new(config, factory).unwrap();
3928        pool.shutdown_with_timeout(Duration::from_secs(1)).await;
3929        let count_after_first = pool.total_count.load(Ordering::SeqCst);
3930        pool.shutdown_with_timeout(Duration::from_secs(1)).await;
3931        let count_after_second = pool.total_count.load(Ordering::SeqCst);
3932        assert_eq!(count_after_first, count_after_second);
3933    }
3934
3935    #[tokio::test]
3936    async fn test_shutdown_with_timeout_rejects_new_acquire() {
3937        let factory = Arc::new(MockConnectionFactory) as Arc<dyn ConnectionFactory>;
3938        let config = PoolConfigBuilder::new().max_size(4).build().unwrap();
3939        let pool = Pool::new(config, factory).unwrap();
3940        pool.shutdown_with_timeout(Duration::from_secs(1)).await;
3941        let result = pool.acquire().await;
3942        assert!(result.is_err());
3943    }
3944}
3945
3946#[cfg(all(test, feature = "prod-pool-tuning"))]
3947mod pool_prod_tests {
3948    use super::*;
3949
3950    struct MockFactory;
3951
3952    #[async_trait]
3953    impl ConnectionFactory for MockFactory {
3954        async fn create(&self) -> Result<Box<dyn Connection>, crate::DbError> {
3955            Ok(Box::new(MockConn))
3956        }
3957    }
3958
3959    struct MockConn;
3960
3961    impl Connection for MockConn {
3962        fn execute<'a>(
3963            &'a mut self,
3964            _sql: &'a str,
3965        ) -> Pin<Box<dyn Future<Output = Result<u64, crate::DbError>> + Send + 'a>> {
3966            Box::pin(async move { Ok(1) })
3967        }
3968        fn query<'a>(
3969            &'a mut self,
3970            _sql: &'a str,
3971        ) -> Pin<
3972            Box<
3973                dyn Future<
3974                        Output = Result<
3975                            Vec<std::collections::HashMap<String, crate::value::Value>>,
3976                            crate::DbError,
3977                        >,
3978                    > + Send
3979                    + 'a,
3980            >,
3981        > {
3982            Box::pin(async move { Ok(vec![]) })
3983        }
3984        fn begin_transaction<'a>(
3985            &'a mut self,
3986        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3987            Box::pin(async move { Ok(()) })
3988        }
3989        fn commit<'a>(
3990            &'a mut self,
3991        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3992            Box::pin(async move { Ok(()) })
3993        }
3994        fn rollback<'a>(
3995            &'a mut self,
3996        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
3997            Box::pin(async move { Ok(()) })
3998        }
3999        fn is_connected(&self) -> bool {
4000            true
4001        }
4002        fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
4003            Box::pin(async move { true })
4004        }
4005        fn close<'a>(
4006            &'a mut self,
4007        ) -> Pin<Box<dyn Future<Output = Result<(), crate::DbError>> + Send + 'a>> {
4008            Box::pin(async move { Ok(()) })
4009        }
4010    }
4011
4012    #[test]
4013    fn test_pool_prod_config_validate_ok() {
4014        let config = PoolProdConfig::new(
4015            50,
4016            Duration::from_secs(10),
4017            Duration::from_secs(600),
4018            Duration::from_secs(5),
4019            Duration::from_secs(30),
4020            5,
4021            true,
4022        );
4023        assert!(config.validate().is_ok());
4024    }
4025
4026    #[test]
4027    fn test_pool_prod_config_max_size_zero_rejected() {
4028        let config = PoolProdConfig::default();
4029        let mut c = config;
4030        c.max_size = 0;
4031        let err = c.validate().unwrap_err();
4032        assert!(err.to_string().contains("max_size must be positive"));
4033    }
4034
4035    #[test]
4036    fn test_pool_prod_config_min_idle_exceeds_max_size() {
4037        let config = PoolProdConfig::new(
4038            10,
4039            Duration::from_secs(10),
4040            Duration::from_secs(600),
4041            Duration::from_secs(5),
4042            Duration::from_secs(30),
4043            20,
4044            false,
4045        );
4046        let err = config.validate().unwrap_err();
4047        assert!(err.to_string().contains("min_idle cannot exceed max_size"));
4048    }
4049
4050    #[test]
4051    fn test_pool_prod_config_to_pool_config() {
4052        let config = PoolProdConfig::new(
4053            50,
4054            Duration::from_secs(10),
4055            Duration::from_secs(600),
4056            Duration::from_secs(5),
4057            Duration::from_secs(30),
4058            5,
4059            true,
4060        );
4061        let pool_config = config.to_pool_config();
4062        assert_eq!(pool_config.max_size, 50);
4063        assert_eq!(pool_config.min_idle, 5);
4064        assert_eq!(pool_config.acquire_timeout, Duration::from_secs(10));
4065        assert!(pool_config.prewarm);
4066    }
4067
4068    #[tokio::test]
4069    async fn test_pool_prod_config_runtime_resize() {
4070        let factory = Arc::new(MockFactory) as Arc<dyn ConnectionFactory>;
4071        let config = PoolProdConfig::default();
4072        let pool = Pool::new(config.to_pool_config(), factory).unwrap();
4073        assert_eq!(pool.max_size(), 100);
4074        pool.resize(50);
4075        assert_eq!(pool.max_size(), 50);
4076    }
4077}
4078
4079#[cfg(all(test, feature = "prod-leak-detection"))]
4080mod leak_prod_tests {
4081    use super::*;
4082
4083    #[test]
4084    fn test_leak_config_default() {
4085        let config = LeakDetectionConfig::default();
4086        assert!(!config.enabled);
4087        assert_eq!(config.interval, Duration::from_secs(60));
4088        assert_eq!(config.threshold, 5);
4089    }
4090
4091    #[test]
4092    fn test_leak_config_validate_ok() {
4093        let config =
4094            LeakDetectionConfig::new(true, Duration::from_secs(30), 10, Duration::from_secs(60));
4095        assert!(config.validate().is_ok());
4096    }
4097
4098    #[test]
4099    fn test_leak_config_interval_zero_rejected() {
4100        let config = LeakDetectionConfig::new(true, Duration::ZERO, 10, Duration::from_secs(60));
4101        assert!(config.validate().is_err());
4102    }
4103
4104    #[test]
4105    fn test_leak_report_empty() {
4106        let report = LeakReport::empty();
4107        assert_eq!(report.borrowed_count, 0);
4108        assert!(report.suspected_leaks.is_empty());
4109    }
4110
4111    #[test]
4112    fn connection_reuse_rate_zero() {
4113        let metrics = PoolMetrics::default();
4114        assert_eq!(metrics.connection_reuse_rate(), 0.0);
4115    }
4116
4117    #[test]
4118    fn connection_reuse_rate_full() {
4119        let metrics = PoolMetrics {
4120            acquire_count: 100,
4121            connection_created_count: 1,
4122            ..Default::default()
4123        };
4124        let rate = metrics.connection_reuse_rate();
4125        assert!(
4126            (rate - 0.99).abs() < 0.001,
4127            "复用率应接近 0.99,实际 {rate}"
4128        );
4129    }
4130
4131    #[test]
4132    fn connection_reuse_rate_partial() {
4133        let metrics = PoolMetrics {
4134            acquire_count: 10,
4135            connection_created_count: 2,
4136            ..Default::default()
4137        };
4138        assert!((metrics.connection_reuse_rate() - 0.8).abs() < 0.001);
4139    }
4140
4141    #[test]
4142    fn pool_tuning_advice_is_optimal() {
4143        let advice = PoolTuningAdvice {
4144            suggested_max_size: None,
4145            suggested_min_idle: None,
4146            suggested_idle_timeout: None,
4147            reason: "池配置合理".to_string(),
4148        };
4149        assert!(advice.is_optimal());
4150
4151        let not_optimal = PoolTuningAdvice {
4152            suggested_max_size: Some(20),
4153            suggested_min_idle: None,
4154            suggested_idle_timeout: None,
4155            reason: "test".to_string(),
4156        };
4157        assert!(!not_optimal.is_optimal());
4158    }
4159
4160    #[test]
4161    fn suggest_tuning_low_reuse() {
4162        let metrics = PoolMetrics {
4163            acquire_count: 100,
4164            connection_created_count: 60,
4165            ..Default::default()
4166        };
4167        let reuse = metrics.connection_reuse_rate();
4168        assert!(reuse < 0.5, "复用率 {reuse} 应 < 0.5");
4169    }
4170
4171    #[test]
4172    fn suggest_tuning_optimal() {
4173        let metrics = PoolMetrics {
4174            acquire_count: 1000,
4175            connection_created_count: 10,
4176            acquire_wait_time: Duration::from_millis(10),
4177            ..Default::default()
4178        };
4179        let reuse = metrics.connection_reuse_rate();
4180        assert!(reuse >= 0.9, "复用率 {reuse} 应 >= 0.9");
4181        let avg_wait = metrics.average_acquire_wait_time();
4182        assert!(avg_wait <= Duration::from_millis(100));
4183    }
4184
4185    #[test]
4186    fn suggest_tuning_high_wait() {
4187        let metrics = PoolMetrics {
4188            acquire_count: 100,
4189            acquire_wait_time: Duration::from_millis(200 * 100),
4190            ..Default::default()
4191        };
4192        let avg_wait = metrics.average_acquire_wait_time();
4193        assert!(
4194            avg_wait > Duration::from_millis(100),
4195            "平均等待 {avg_wait:?} 应 > 100ms"
4196        );
4197    }
4198}