Skip to main content

kode_bridge/
pool.rs

1use crate::errors::{KodeBridgeError, Result};
2#[cfg(windows)]
3use crate::transport::WindowsServerVerification;
4use crate::transport::{Endpoint, IpcStream};
5use parking_lot::Mutex;
6use std::collections::VecDeque;
7use std::sync::Arc;
8use std::time::{Duration, Instant};
9use tokio::sync::{OwnedSemaphorePermit, Semaphore};
10use tracing::{debug, trace, warn};
11
12/// Configuration for connection pool
13#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
14pub struct PoolConfig {
15    /// Maximum number of connections in the pool
16    pub max_size: usize,
17    /// Minimum number of idle connections to maintain
18    pub min_idle: usize,
19    /// Maximum time a connection can be idle before being closed (in milliseconds)
20    pub max_idle_time_ms: u64,
21    /// Maximum time to wait for a connection from the pool (in milliseconds)
22    pub connection_timeout_ms: u64,
23    /// Time to wait between connection attempts (in milliseconds)
24    pub retry_delay_ms: u64,
25    /// Maximum number of retry attempts
26    pub max_retries: usize,
27    /// Concurrent request limit
28    pub max_concurrent_requests: usize,
29    /// Rate limiting: max requests per second
30    pub max_requests_per_second: Option<f64>,
31}
32
33impl Default for PoolConfig {
34    fn default() -> Self {
35        Self {
36            max_size: 64,                 // 增加到2的幂次,更好的内存对齐
37            min_idle: 8,                  // 减少最小空闲连接
38            max_idle_time_ms: 120_000,    // 2分钟 - 进一步减少空闲时间
39            connection_timeout_ms: 3_000, // 减少连接超时到3秒
40            retry_delay_ms: 10,           // 减少重试延迟到10ms
41            max_retries: 2,               // 减少重试次数到2次
42            max_concurrent_requests: 32,
43            max_requests_per_second: None,
44        }
45    }
46}
47
48impl PoolConfig {
49    /// Get max idle time as Duration
50    pub const fn max_idle_time(&self) -> Duration {
51        Duration::from_millis(self.max_idle_time_ms)
52    }
53
54    /// Get connection timeout as Duration
55    pub const fn connection_timeout(&self) -> Duration {
56        Duration::from_millis(self.connection_timeout_ms)
57    }
58
59    /// Get retry delay as Duration
60    pub const fn retry_delay(&self) -> Duration {
61        Duration::from_millis(self.retry_delay_ms)
62    }
63}
64
65/// A pooled connection wrapper
66pub struct PooledConnection {
67    inner: Option<IpcStream>,
68    permit: Option<OwnedSemaphorePermit>,
69    created_at: Instant,
70    last_used: Instant,
71    reusable: bool,
72    pool: Arc<ConnectionPoolInner>,
73}
74
75impl PooledConnection {
76    fn new(stream: IpcStream, permit: OwnedSemaphorePermit, pool: Arc<ConnectionPoolInner>) -> Self {
77        let now = Instant::now();
78        Self {
79            inner: Some(stream),
80            permit: Some(permit),
81            created_at: now,
82            last_used: now,
83            reusable: true,
84            pool,
85        }
86    }
87
88    /// Get the underlying stream
89    pub fn stream(&mut self) -> Option<&mut IpcStream> {
90        self.last_used = Instant::now();
91        self.inner.as_mut()
92    }
93
94    /// Take ownership of the underlying stream
95    pub fn into_stream(mut self) -> Option<IpcStream> {
96        self.reusable = false;
97        if let Some(permit) = self.permit.take() {
98            self.pool
99                .active_connections
100                .fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
101            drop(permit);
102        }
103        self.inner.take()
104    }
105
106    /// Mark the connection as broken so it is not returned to the pool.
107    pub const fn invalidate(&mut self) {
108        self.reusable = false;
109    }
110
111    /// Check if connection is still valid
112    pub fn is_valid(&self) -> bool {
113        self.inner.is_some() && self.last_used.elapsed() < self.pool.config.max_idle_time()
114    }
115
116    /// Get connection age
117    pub fn age(&self) -> Duration {
118        self.created_at.elapsed()
119    }
120
121    /// Get idle time
122    pub fn idle_time(&self) -> Duration {
123        self.last_used.elapsed()
124    }
125}
126
127impl Drop for PooledConnection {
128    fn drop(&mut self) {
129        if let Some(stream) = self.inner.take() {
130            if let Some(permit) = self.permit.take() {
131                self.pool.return_connection(stream, permit, self.reusable);
132            }
133        }
134    }
135}
136
137struct IdleConnection {
138    stream: IpcStream,
139    last_used: Instant,
140    permit: OwnedSemaphorePermit,
141}
142
143/// Internal pool state with PUT request optimization
144struct ConnectionPoolInner {
145    endpoint: Endpoint,
146    config: PoolConfig,
147    connections: Mutex<VecDeque<IdleConnection>>,
148    semaphore: Arc<Semaphore>,
149    /// Number of checked-out connections currently in use.
150    active_connections: std::sync::atomic::AtomicUsize,
151    #[cfg(windows)]
152    windows_server_verification: WindowsServerVerification,
153}
154
155impl ConnectionPoolInner {
156    fn new(endpoint: Endpoint, config: PoolConfig) -> Self {
157        Self {
158            endpoint,
159            semaphore: Arc::new(Semaphore::new(config.max_size)),
160            connections: Mutex::new(VecDeque::new()),
161            active_connections: std::sync::atomic::AtomicUsize::new(0),
162            #[cfg(windows)]
163            windows_server_verification: WindowsServerVerification::default(),
164            config,
165        }
166    }
167
168    #[cfg(windows)]
169    fn new_with_windows_server_verification(
170        endpoint: Endpoint,
171        config: PoolConfig,
172        verification: WindowsServerVerification,
173    ) -> Self {
174        let mut inner = Self::new(endpoint, config);
175        inner.windows_server_verification = verification;
176        inner
177    }
178
179    async fn connect(&self) -> std::io::Result<IpcStream> {
180        #[cfg(windows)]
181        {
182            IpcStream::connect_with_windows_server_verification(&self.endpoint, self.windows_server_verification).await
183        }
184        #[cfg(not(windows))]
185        {
186            IpcStream::connect(&self.endpoint).await
187        }
188    }
189
190    /// Get a fresh connection for PUT requests, bypassing normal pool
191    async fn get_fresh_connection(&self) -> Result<IpcStream> {
192        let mut last_error = None;
193        for attempt in 0..2 {
194            if attempt > 0 {
195                tokio::time::sleep(Duration::from_millis(10)).await;
196            }
197
198            match self.connect().await {
199                Ok(stream) => {
200                    debug!("Created fresh connection for PUT request");
201                    return Ok(stream);
202                }
203                Err(e) => {
204                    warn!("Fresh connection attempt {} failed: {}", attempt + 1, e);
205                    last_error = Some(e);
206                }
207            }
208        }
209
210        Err(KodeBridgeError::connection(format!(
211            "Failed to create fresh connection: {}",
212            last_error
213                .map(|e| e.to_string())
214                .unwrap_or_else(|| "Unknown error".to_string())
215        )))
216    }
217
218    /// 预热新连接池,为PUT请求做准备
219    async fn preheat_fresh_connections(&self, count: usize) {
220        let mut successful = 0;
221        for _ in 0..count {
222            let Ok(permit) = Arc::clone(&self.semaphore).try_acquire_owned() else {
223                break;
224            };
225
226            match self.connect().await {
227                Ok(stream) => {
228                    self.connections.lock().push_back(IdleConnection {
229                        stream,
230                        last_used: Instant::now(),
231                        permit,
232                    });
233                    successful += 1;
234                }
235                Err(_) => {
236                    drop(permit);
237                    break;
238                }
239            }
240        }
241        if successful > 0 {
242            debug!("Preheated {} fresh connections", successful);
243        }
244    }
245
246    async fn create_connection(&self) -> Result<IpcStream> {
247        let mut last_error = None;
248        let mut delay = self.config.retry_delay();
249        let max_delay = Duration::from_millis(200); // 限制最大延迟为200ms
250
251        for attempt in 0..self.config.max_retries {
252            if attempt > 0 {
253                // 优化的指数退避,避免过长的延迟
254                tokio::time::sleep(delay).await;
255                delay = std::cmp::min(delay * 2, max_delay);
256            }
257
258            match self.connect().await {
259                Ok(stream) => {
260                    debug!("Created new connection on attempt {}", attempt + 1);
261                    return Ok(stream);
262                }
263                Err(e) => {
264                    warn!("Connection attempt {} failed: {}", attempt + 1, e);
265                    last_error = Some(e);
266                }
267            }
268        }
269
270        Err(KodeBridgeError::connection(format!(
271            "Failed to get fresh connection and no pooled connections available: {}",
272            last_error
273                .map(|e| e.to_string())
274                .unwrap_or_else(|| "Unknown error".to_string())
275        )))
276    }
277
278    fn get_pooled_connection(&self) -> Option<(IpcStream, OwnedSemaphorePermit)> {
279        let mut connections = self.connections.lock();
280
281        let now = Instant::now();
282        while let Some(idle) = connections.front() {
283            if now.duration_since(idle.last_used) > self.config.max_idle_time() {
284                connections.pop_front();
285            } else {
286                break;
287            }
288        }
289
290        connections.pop_front().map(|idle| {
291            trace!("Reusing pooled connection, {} remaining", connections.len());
292            (idle.stream, idle.permit)
293        })
294    }
295
296    fn return_connection(&self, stream: IpcStream, permit: OwnedSemaphorePermit, reusable: bool) {
297        self.active_connections
298            .fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
299
300        if !reusable {
301            trace!("Dropping broken pooled connection");
302            return;
303        }
304
305        let (kept, pool_size) = {
306            let mut connections = self.connections.lock();
307
308            if connections.len() < self.config.max_size {
309                connections.push_back(IdleConnection {
310                    stream,
311                    last_used: Instant::now(),
312                    permit,
313                });
314                (true, connections.len())
315            } else {
316                (false, connections.len())
317            }
318        };
319
320        if kept {
321            trace!("Returned connection to pool, {} total", pool_size);
322        } else {
323            trace!("Pool full, dropping connection");
324        }
325    }
326}
327
328/// High-performance connection pool for IPC connections
329#[derive(Clone)]
330pub struct ConnectionPool {
331    inner: Arc<ConnectionPoolInner>,
332}
333
334impl ConnectionPool {
335    /// Create a new connection pool
336    pub fn new(endpoint: Endpoint, config: PoolConfig) -> Self {
337        Self {
338            inner: Arc::new(ConnectionPoolInner::new(endpoint, config)),
339        }
340    }
341
342    #[cfg(windows)]
343    pub(crate) fn new_with_windows_server_verification(
344        endpoint: Endpoint,
345        config: PoolConfig,
346        verification: WindowsServerVerification,
347    ) -> Self {
348        Self {
349            inner: Arc::new(ConnectionPoolInner::new_with_windows_server_verification(
350                endpoint,
351                config,
352                verification,
353            )),
354        }
355    }
356
357    /// Create a connection pool with default configuration
358    pub fn with_default_config(endpoint: Endpoint) -> Self {
359        Self::new(endpoint, PoolConfig::default())
360    }
361
362    /// Get a connection from the pool
363    pub async fn get_connection(&self) -> Result<PooledConnection> {
364        if let Some((stream, permit)) = self.inner.get_pooled_connection() {
365            self.inner
366                .active_connections
367                .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
368            return Ok(PooledConnection::new(stream, permit, Arc::clone(&self.inner)));
369        }
370
371        let timeout = self.inner.config.connection_timeout();
372        let permit = tokio::time::timeout(timeout, Arc::clone(&self.inner.semaphore).acquire_owned())
373            .await
374            .map_err(|_| KodeBridgeError::timeout(timeout.as_millis() as u64))?
375            .map_err(|_| KodeBridgeError::custom("Semaphore closed"))?;
376
377        if let Some((stream, pooled_permit)) = self.inner.get_pooled_connection() {
378            drop(permit);
379            self.inner
380                .active_connections
381                .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
382            return Ok(PooledConnection::new(stream, pooled_permit, Arc::clone(&self.inner)));
383        }
384
385        match self.inner.create_connection().await {
386            Ok(stream) => {
387                self.inner
388                    .active_connections
389                    .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
390                Ok(PooledConnection::new(stream, permit, Arc::clone(&self.inner)))
391            }
392            Err(e) => Err(e),
393        }
394    }
395
396    /// Get a fresh connection optimized for PUT requests
397    pub async fn get_fresh_connection(&self) -> Result<PooledConnection> {
398        let permit = tokio::time::timeout(
399            Duration::from_millis(100),
400            Arc::clone(&self.inner.semaphore).acquire_owned(),
401        )
402        .await
403        .map_err(|_| KodeBridgeError::timeout(100))?
404        .map_err(|_| KodeBridgeError::custom("Semaphore closed"))?;
405
406        match self.inner.get_fresh_connection().await {
407            Ok(stream) => {
408                self.inner
409                    .active_connections
410                    .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
411                Ok(PooledConnection::new(stream, permit, Arc::clone(&self.inner)))
412            }
413            Err(e) => Err(e),
414        }
415    }
416
417    /// Preheat fresh connections for better PUT performance
418    pub async fn preheat_for_puts(&self, count: usize) {
419        self.inner.preheat_fresh_connections(count).await;
420    }
421
422    /// Get multiple connections for concurrent operations
423    pub async fn get_connections(&self, count: usize) -> Result<Vec<PooledConnection>> {
424        let mut connections = Vec::with_capacity(count);
425
426        // Use semaphore to control concurrent acquisition
427        let mut tasks = Vec::new();
428        for _ in 0..count {
429            let pool = self.clone();
430            tasks.push(tokio::spawn(async move { pool.get_connection().await }));
431        }
432
433        // Wait for all connection acquisitions to complete
434        for task in tasks {
435            match task.await {
436                Ok(Ok(conn)) => connections.push(conn),
437                Ok(Err(e)) => return Err(e),
438                Err(e) => return Err(KodeBridgeError::custom(format!("Task failed: {}", e))),
439            }
440        }
441
442        Ok(connections)
443    }
444
445    /// Get pool statistics
446    pub fn stats(&self) -> PoolStats {
447        let connections = self.inner.connections.lock();
448        let active_count = self
449            .inner
450            .active_connections
451            .load(std::sync::atomic::Ordering::Relaxed);
452        PoolStats {
453            total_connections: connections.len() + active_count,
454            available_permits: self.inner.semaphore.available_permits(),
455            max_size: self.inner.config.max_size,
456            active_connections: active_count,
457        }
458    }
459
460    /// Close all pooled connections
461    pub fn close(&self) {
462        self.inner.connections.lock().clear();
463        debug!("Closed all pooled connections");
464    }
465}
466
467/// Pool statistics
468#[derive(Debug, Clone)]
469pub struct PoolStats {
470    pub total_connections: usize,
471    pub available_permits: usize,
472    pub max_size: usize,
473    pub active_connections: usize,
474}
475
476impl std::fmt::Display for PoolStats {
477    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
478        write!(
479            f,
480            "Pool(connections: {}, active: {}, permits: {}, max: {})",
481            self.total_connections, self.active_connections, self.available_permits, self.max_size
482        )
483    }
484}