feox_server/
server.rs

1use crate::client_registry::ClientRegistry;
2use crate::pubsub::{handle_pubsub_operation, GlobalRegistry, ThreadLocalPubSub};
3use crate::{config::Config, error::Result, network::Connection};
4use feoxdb::FeoxStore;
5use std::net::TcpListener;
6use std::os::fd::{AsRawFd, RawFd};
7use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
8use std::sync::Arc;
9use std::thread;
10use tracing::{debug, error, info};
11
12/// High-performance Redis-compatible server
13pub struct Server {
14    config: Config,
15    store: Arc<FeoxStore>,
16    shutdown: AtomicBool,
17    active_connections: AtomicUsize,
18    pubsub_registry: Arc<GlobalRegistry>,
19    client_registry: Arc<ClientRegistry>,
20}
21
22impl Server {
23    /// Create a new server with the given configuration
24    pub fn new(config: Config) -> Result<Self> {
25        config.validate()?;
26
27        // Create a single shared FeoxStore instance
28        let store = if let Some(ref data_path) = config.data_path {
29            let mut builder = FeoxStore::builder()
30                .device_path(data_path.clone())
31                .max_memory(config.max_memory_per_shard.unwrap_or(1024 * 1024 * 1024))
32                .enable_ttl(config.enable_ttl);
33
34            // Set file size if configured
35            if let Some(file_size) = config.file_size {
36                builder = builder.file_size(file_size);
37            }
38
39            Arc::new(builder.build()?)
40        } else {
41            Arc::new(
42                FeoxStore::builder()
43                    .max_memory(config.max_memory_per_shard.unwrap_or(1024 * 1024 * 1024))
44                    .enable_ttl(config.enable_ttl)
45                    .build()?,
46            )
47        };
48
49        let (pubsub_registry, _receivers) = GlobalRegistry::new(config.threads);
50        let client_registry = Arc::new(ClientRegistry::new());
51
52        Ok(Self {
53            config,
54            store,
55            shutdown: AtomicBool::new(false),
56            active_connections: AtomicUsize::new(0),
57            pubsub_registry,
58            client_registry,
59        })
60    }
61
62    /// Run the server, spawning worker threads
63    ///
64    /// This method blocks until the server is shut down.
65    pub fn run(self: Arc<Self>) -> Result<()> {
66        // Create TCP listener
67        let listener =
68            TcpListener::bind(format!("{}:{}", self.config.bind_addr, self.config.port))?;
69
70        listener.set_nonblocking(true)?;
71        let listener_fd = listener.as_raw_fd();
72
73        info!(
74            "Server listening on {}:{}",
75            self.config.bind_addr, self.config.port
76        );
77
78        // Create pub/sub receivers for each thread
79        let (_, mut pubsub_receivers) = GlobalRegistry::new(self.config.threads);
80
81        // Spawn worker threads
82        let mut handles = Vec::new();
83
84        for thread_id in 0..self.config.threads {
85            let server = Arc::clone(&self);
86            let store = Arc::clone(&self.store);
87            let pubsub_registry = Arc::clone(&self.pubsub_registry);
88            let pubsub_receiver = pubsub_receivers.remove(0);
89            let client_registry = Arc::clone(&self.client_registry);
90
91            let handle = thread::spawn(move || {
92                if let Err(e) = server.run_worker(
93                    thread_id,
94                    listener_fd,
95                    store,
96                    pubsub_registry,
97                    pubsub_receiver,
98                    client_registry,
99                ) {
100                    error!("Worker {} failed: {}", thread_id, e);
101                }
102            });
103            handles.push(handle);
104        }
105
106        // Wait for all workers to finish
107        for handle in handles {
108            let _ = handle.join();
109        }
110
111        Ok(())
112    }
113
114    /// Signal the server to shut down gracefully
115    pub fn shutdown(&self) {
116        info!("Initiating server shutdown");
117        self.shutdown.store(true, Ordering::Release);
118    }
119
120    /// Get the number of active client connections
121    pub fn active_connections(&self) -> usize {
122        self.active_connections.load(Ordering::Acquire)
123    }
124
125    fn run_worker(
126        self: &Arc<Self>,
127        thread_id: usize,
128        listener_fd: RawFd,
129        store: Arc<FeoxStore>,
130        pubsub_registry: Arc<GlobalRegistry>,
131        pubsub_receiver: crossbeam_channel::Receiver<crate::pubsub::BroadcastMsg>,
132        client_registry: Arc<ClientRegistry>,
133    ) -> Result<()> {
134        use mio::net::{TcpListener as MioTcpListener, TcpStream as MioTcpStream};
135        use mio::{Events, Interest, Poll, Token};
136        use std::collections::HashMap;
137        use std::io::{ErrorKind, Read, Write};
138        use std::os::fd::FromRawFd;
139
140        // Create mio Poll instance
141        let mut poll = Poll::new()?;
142        let mut events = Events::with_capacity(1024);
143
144        // Convert raw fd to mio listener
145        let std_listener = unsafe { TcpListener::from_raw_fd(listener_fd) };
146        std_listener.set_nonblocking(true)?;
147        let mut listener = MioTcpListener::from_std(std_listener);
148
149        // Register listener
150        const SERVER: Token = Token(0);
151        poll.registry()
152            .register(&mut listener, SERVER, Interest::READABLE)?;
153
154        // Connection tracking
155        let mut connections: HashMap<Token, (MioTcpStream, Connection)> = HashMap::new();
156        let mut next_token = 1usize;
157
158        // Initialize thread-local pub/sub
159        let mut pubsub_manager =
160            ThreadLocalPubSub::new(thread_id, pubsub_receiver, pubsub_registry.clone());
161
162        info!("Worker {} started", thread_id);
163
164        // Event loop
165        while !self.shutdown.load(Ordering::Acquire) {
166            // Process incoming pub/sub messages
167            let pubsub_deliveries = pubsub_manager.process_inbox();
168            for (conn_id, message) in pubsub_deliveries {
169                // Find connection by ID and queue message
170                for (_token, (stream, connection)) in connections.iter_mut() {
171                    if connection.connection_id == conn_id {
172                        connection.queue_pubsub_message(message);
173                        connection.process_pubsub_messages();
174
175                        // Write any pending data immediately
176                        while let Some(data) = connection.pending_writes() {
177                            let data_len = data.len();
178                            match stream.write(data) {
179                                Ok(n) => {
180                                    connection.consume_writes(n);
181                                    if n < data_len {
182                                        break;
183                                    }
184                                }
185                                Err(e) if e.kind() == ErrorKind::WouldBlock => break,
186                                Err(_) => break,
187                            }
188                        }
189                        break;
190                    }
191                }
192            }
193
194            // Poll for events with 100ms timeout
195            poll.poll(&mut events, Some(std::time::Duration::from_millis(100)))?;
196
197            for event in events.iter() {
198                match event.token() {
199                    SERVER => {
200                        // Accept new connections
201                        loop {
202                            match listener.accept() {
203                                Ok((mut stream, addr)) => {
204                                    debug!("New connection from {:?}", addr);
205
206                                    // Configure socket
207                                    stream.set_nodelay(self.config.tcp_nodelay)?;
208
209                                    let token = Token(next_token);
210                                    next_token += 1;
211
212                                    // Register for read events
213                                    poll.registry().register(
214                                        &mut stream,
215                                        token,
216                                        Interest::READABLE,
217                                    )?;
218
219                                    let mut connection = Connection::new_with_addr(
220                                        0, // fd not used in this path
221                                        self.config.connection_buffer_size,
222                                        Arc::clone(&store),
223                                        &self.config, // Pass config here
224                                        Some(addr),
225                                    );
226
227                                    // Set client registry for CLIENT command support
228                                    connection.set_client_registry(Arc::clone(&client_registry));
229
230                                    // Register client in registry
231                                    client_registry.register(&connection, thread_id);
232
233                                    connections.insert(token, (stream, connection));
234                                    self.active_connections.fetch_add(1, Ordering::Relaxed);
235                                }
236                                Err(e) if e.kind() == ErrorKind::WouldBlock => break,
237                                Err(e) => {
238                                    error!("Error accepting connection: {}", e);
239                                    break;
240                                }
241                            }
242                        }
243                    }
244                    token => {
245                        // First, collect any deliveries that need to be made
246                        let mut deliveries_to_make = Vec::new();
247
248                        // Handle client connection
249                        let should_close =
250                            if let Some((stream, connection)) = connections.get_mut(&token) {
251                                let mut should_close = false;
252
253                                if event.is_readable() {
254                                    // Use a simple buffer (optimize with pool later if needed)
255                                    let mut buffer = vec![0u8; 8192];
256
257                                    match stream.read(&mut buffer) {
258                                        Ok(0) => {
259                                            // Connection closed
260                                            should_close = true;
261                                        }
262                                        Ok(n) => {
263                                            // Process commands inline and get pub/sub operations
264                                            match connection.process_read(&buffer[..n]) {
265                                                Ok(pubsub_ops) => {
266                                                    // Process pub/sub operations
267                                                    for op in pubsub_ops {
268                                                        let deliveries = handle_pubsub_operation(
269                                                            &mut pubsub_manager,
270                                                            &pubsub_registry,
271                                                            connection.connection_id,
272                                                            op,
273                                                            connection,
274                                                            thread_id,
275                                                        );
276                                                        deliveries_to_make.extend(deliveries);
277                                                    }
278
279                                                    // Process any queued pub/sub messages
280                                                    connection.process_pubsub_messages();
281
282                                                    // Update client info in registry if needed
283                                                    client_registry.update(connection);
284
285                                                    // Write response immediately
286                                                    while let Some(response_data) =
287                                                        connection.pending_writes()
288                                                    {
289                                                        let response_len = response_data.len();
290                                                        match stream.write(response_data) {
291                                                            Ok(n) => {
292                                                                connection.consume_writes(n);
293                                                                if n < response_len {
294                                                                    // Partial write, would block
295                                                                    break;
296                                                                }
297                                                            }
298                                                            Err(e)
299                                                                if e.kind()
300                                                                    == ErrorKind::WouldBlock =>
301                                                            {
302                                                                break;
303                                                            }
304                                                            Err(e) => {
305                                                                error!("Error writing: {}", e);
306                                                                should_close = true;
307                                                                break;
308                                                            }
309                                                        }
310                                                    }
311                                                }
312                                                Err(e) => {
313                                                    error!("Error processing read: {}", e);
314                                                    should_close = true;
315                                                }
316                                            }
317
318                                            if connection.is_closed() {
319                                                should_close = true;
320                                            }
321                                        }
322                                        Err(e) if e.kind() != ErrorKind::WouldBlock => {
323                                            if e.kind() != ErrorKind::ConnectionReset {
324                                                error!("Error reading: {}", e);
325                                            }
326                                            should_close = true;
327                                        }
328                                        Err(_) => {} // WouldBlock - ignore
329                                    }
330                                }
331
332                                should_close
333                            } else {
334                                false
335                            };
336
337                        if should_close {
338                            if let Some((mut stream, mut connection)) = connections.remove(&token) {
339                                let _ = poll.registry().deregister(&mut stream);
340
341                                // Clean up pub/sub subscriptions
342                                pubsub_manager.connection_dropped(connection.connection_id);
343
344                                // Unregister from client registry
345                                client_registry.unregister(connection.connection_id);
346
347                                connection.close();
348                                self.active_connections.fetch_sub(1, Ordering::Relaxed);
349                            }
350                        }
351
352                        // Now deliver any pub/sub messages to local connections
353                        for (delivery_conn_id, msg) in deliveries_to_make {
354                            for (_, (_, conn)) in connections.iter_mut() {
355                                if conn.connection_id == delivery_conn_id {
356                                    conn.queue_pubsub_message(msg);
357                                    conn.process_pubsub_messages();
358                                    break;
359                                }
360                            }
361                        }
362                    }
363                }
364            }
365        }
366
367        // Cleanup
368        for (_, (mut stream, mut connection)) in connections {
369            let _ = poll.registry().deregister(&mut stream);
370            pubsub_manager.connection_dropped(connection.connection_id);
371            client_registry.unregister(connection.connection_id);
372            connection.close();
373        }
374
375        info!("Worker {} shutting down", thread_id);
376        Ok(())
377    }
378}