Skip to main content

kode_bridge/
pool.rs

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