1use crate::connection::RedisConnection;
8use crate::core::{
9 config::{ConnectionConfig, PoolStrategy},
10 error::{RedisError, RedisResult},
11 value::RespValue,
12};
13use std::sync::Arc;
14use tokio::sync::{mpsc, Mutex, RwLock, Semaphore};
15use tracing::{debug, warn};
16
17struct CommandRequest {
19 command: String,
20 args: Vec<RespValue>,
21 response_tx: tokio::sync::oneshot::Sender<RedisResult<RespValue>>,
22}
23
24pub struct MultiplexedPool {
26 command_tx: mpsc::UnboundedSender<CommandRequest>,
27}
28
29impl MultiplexedPool {
30 pub async fn new(config: ConnectionConfig, host: String, port: u16) -> RedisResult<Self> {
32 let (command_tx, mut command_rx) = mpsc::unbounded_channel::<CommandRequest>();
33
34 tokio::spawn(async move {
36 let mut conn = match RedisConnection::connect(&host, port, config.clone()).await {
37 Ok(conn) => conn,
38 Err(e) => {
39 warn!("Failed to create multiplexed connection: {:?}", e);
40 return;
41 }
42 };
43
44 while let Some(req) = command_rx.recv().await {
45 let result = conn.execute_command(&req.command, &req.args).await;
46 let _ = req.response_tx.send(result);
48 }
49
50 debug!("Multiplexed connection handler stopped");
51 });
52
53 Ok(Self { command_tx })
54 }
55
56 pub async fn execute_command(
58 &self,
59 command: String,
60 args: Vec<RespValue>,
61 ) -> RedisResult<RespValue> {
62 let (response_tx, response_rx) = tokio::sync::oneshot::channel();
63
64 self.command_tx
65 .send(CommandRequest {
66 command,
67 args,
68 response_tx,
69 })
70 .map_err(|_| RedisError::Connection("Multiplexed connection closed".to_string()))?;
71
72 response_rx
73 .await
74 .map_err(|_| RedisError::Connection("Response channel closed".to_string()))?
75 }
76}
77
78pub struct ConnectionPool {
80 connections: Arc<RwLock<Vec<Arc<Mutex<RedisConnection>>>>>,
81 semaphore: Arc<Semaphore>,
82 config: ConnectionConfig,
83 host: String,
84 port: u16,
85}
86
87impl ConnectionPool {
88 pub async fn new(
90 config: ConnectionConfig,
91 host: String,
92 port: u16,
93 max_size: usize,
94 ) -> RedisResult<Self> {
95 let mut connections = Vec::new();
96
97 let initial_size = config.pool.min_idle.min(max_size).max(1);
99 for _ in 0..initial_size {
100 let conn = RedisConnection::connect(&host, port, config.clone()).await?;
101 connections.push(Arc::new(Mutex::new(conn)));
102 }
103
104 Ok(Self {
105 connections: Arc::new(RwLock::new(connections)),
106 semaphore: Arc::new(Semaphore::new(max_size)),
107 config,
108 host,
109 port,
110 })
111 }
112
113 async fn get_connection(&self) -> RedisResult<Arc<Mutex<RedisConnection>>> {
115 let _permit = self
117 .semaphore
118 .acquire()
119 .await
120 .map_err(|_| RedisError::Pool("Failed to acquire permit".to_string()))?;
121
122 {
124 let mut connections = self.connections.write().await;
125 if let Some(conn) = connections.pop() {
126 return Ok(conn);
127 }
128 }
129
130 let conn = RedisConnection::connect(&self.host, self.port, self.config.clone()).await?;
132 Ok(Arc::new(Mutex::new(conn)))
133 }
134
135 async fn return_connection(&self, conn: Arc<Mutex<RedisConnection>>) {
137 let mut connections = self.connections.write().await;
138 connections.push(conn);
139 }
140
141 pub async fn execute_command(
143 &self,
144 command: String,
145 args: Vec<RespValue>,
146 ) -> RedisResult<RespValue> {
147 let conn = self.get_connection().await?;
148 let result = {
149 let mut conn_guard = conn.lock().await;
150 conn_guard.execute_command(&command, &args).await
151 };
152
153 self.return_connection(conn).await;
155
156 result
157 }
158}
159
160pub enum Pool {
162 Multiplexed(MultiplexedPool),
164 Pool(Box<ConnectionPool>),
166}
167
168impl Pool {
169 pub async fn new(config: ConnectionConfig, host: String, port: u16) -> RedisResult<Self> {
171 match config.pool.strategy {
172 PoolStrategy::Multiplexed => {
173 let pool = MultiplexedPool::new(config, host, port).await?;
174 Ok(Self::Multiplexed(pool))
175 }
176 PoolStrategy::Pool => {
177 let pool =
178 ConnectionPool::new(config.clone(), host, port, config.pool.max_size).await?;
179 Ok(Self::Pool(Box::new(pool)))
180 }
181 }
182 }
183
184 pub async fn execute_command(
186 &self,
187 command: String,
188 args: Vec<RespValue>,
189 ) -> RedisResult<RespValue> {
190 match self {
191 Self::Multiplexed(pool) => pool.execute_command(command, args).await,
192 Self::Pool(pool) => pool.execute_command(command, args).await,
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use crate::core::config::PoolConfig;
201
202 #[test]
203 fn test_pool_config() {
204 let config = ConnectionConfig::new("redis://localhost:6379");
205 assert_eq!(config.pool.strategy, PoolStrategy::Multiplexed);
206 }
207
208 #[test]
209 fn test_custom_pool_config() {
210 let mut config = ConnectionConfig::new("redis://localhost:6379");
211 config.pool = PoolConfig {
212 strategy: PoolStrategy::Pool,
213 max_size: 20,
214 min_idle: 5,
215 ..Default::default()
216 };
217
218 assert_eq!(config.pool.strategy, PoolStrategy::Pool);
219 assert_eq!(config.pool.max_size, 20);
220 }
221}