Connection registry
Now we can use leak sanitizer. Yay!
This commit is contained in:
93
src/connection_registry.hpp
Normal file
93
src/connection_registry.hpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
class Connection;
|
||||
|
||||
/**
|
||||
* mmap-based Connection Registry for tracking active connections.
|
||||
*
|
||||
* This registry provides a lock-free mechanism for tracking all connections
|
||||
* owned by the server, indexed by file descriptor. The design uses mmap to
|
||||
* allocate a large virtual address space efficiently, with physical memory
|
||||
* allocated on-demand as connections are created.
|
||||
*
|
||||
* CRITICAL ORDERING REQUIREMENT:
|
||||
* All connection cleanup MUST follow this exact sequence:
|
||||
* 1. Remove from registry: auto conn = registry.remove(fd)
|
||||
* 2. Delete the connection: unique_ptr destructor handles it automatically
|
||||
*
|
||||
* This ordering prevents race conditions between cleanup and fd reuse.
|
||||
* The unique_ptr interface ensures ownership is always clear and prevents
|
||||
* double-delete bugs.
|
||||
*/
|
||||
class ConnectionRegistry {
|
||||
public:
|
||||
/**
|
||||
* Initialize the connection registry.
|
||||
* Allocates virtual address space based on RLIMIT_NOFILE.
|
||||
*
|
||||
* @throws std::runtime_error if mmap fails or RLIMIT_NOFILE cannot be read
|
||||
*/
|
||||
ConnectionRegistry();
|
||||
|
||||
/**
|
||||
* Destructor ensures proper cleanup of mmap'd memory.
|
||||
*/
|
||||
~ConnectionRegistry();
|
||||
|
||||
/**
|
||||
* Store a connection in the registry, indexed by its file descriptor.
|
||||
* Takes ownership of the connection via unique_ptr.
|
||||
*
|
||||
* @param fd File descriptor (must be valid and < max_fds_)
|
||||
* @param connection unique_ptr to the connection (ownership transferred)
|
||||
*/
|
||||
void store(int fd, std::unique_ptr<Connection> connection);
|
||||
|
||||
/**
|
||||
* Check if a connection exists in the registry by file descriptor.
|
||||
*
|
||||
* @param fd File descriptor
|
||||
* @return true if connection exists, false otherwise
|
||||
*/
|
||||
bool has(int fd) const;
|
||||
|
||||
/**
|
||||
* Remove a connection from the registry and transfer ownership to caller.
|
||||
* This transfers ownership via unique_ptr move semantics.
|
||||
*
|
||||
* @param fd File descriptor
|
||||
* @return unique_ptr to the connection, or nullptr if not found
|
||||
*/
|
||||
std::unique_ptr<Connection> remove(int fd);
|
||||
|
||||
/**
|
||||
* Get the maximum number of file descriptors supported.
|
||||
*
|
||||
* @return Maximum file descriptor limit
|
||||
*/
|
||||
size_t max_fds() const { return max_fds_; }
|
||||
|
||||
/**
|
||||
* Perform graceful shutdown cleanup.
|
||||
* Iterates through all registry entries and cleans up any remaining
|
||||
* connections using the critical ordering: remove -> close -> delete.
|
||||
*
|
||||
* This method is called during server shutdown to ensure no connections leak.
|
||||
*/
|
||||
virtual void shutdown_cleanup();
|
||||
|
||||
// Non-copyable and non-movable
|
||||
ConnectionRegistry(const ConnectionRegistry &) = delete;
|
||||
ConnectionRegistry &operator=(const ConnectionRegistry &) = delete;
|
||||
ConnectionRegistry(ConnectionRegistry &&) = delete;
|
||||
ConnectionRegistry &operator=(ConnectionRegistry &&) = delete;
|
||||
|
||||
private:
|
||||
Connection **connections_; ///< mmap'd array of raw connection pointers
|
||||
size_t max_fds_; ///< Maximum file descriptor limit
|
||||
};
|
||||
Reference in New Issue
Block a user