Skip to main content

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