Separate Connection and Request lifetimes
This commit is contained in:
@@ -20,6 +20,40 @@
|
||||
// Forward declaration
|
||||
struct Server;
|
||||
|
||||
/**
|
||||
* Base interface for sending messages to a connection.
|
||||
* This restricted interface is safe for use by pipeline threads,
|
||||
* containing only the append_message method needed for responses.
|
||||
* Pipeline threads should use WeakRef<MessageSender> to safely
|
||||
* send responses without accessing other connection functionality
|
||||
* that should only be used by the I/O thread.
|
||||
*/
|
||||
struct MessageSender {
|
||||
/**
|
||||
* @brief Append message data to connection's outgoing message queue.
|
||||
*
|
||||
* Thread-safe method that can be called from any thread, including
|
||||
* pipeline processing threads. The arena is moved into the connection
|
||||
* to maintain data lifetime until the message is sent.
|
||||
*
|
||||
* @param data_parts Span of string_view parts to send (arena-allocated)
|
||||
* @param arena Arena containing the memory for data_parts string_views
|
||||
* @param close_after_send Whether to close connection after sending
|
||||
*
|
||||
* Example usage:
|
||||
* ```cpp
|
||||
* auto response_parts = std::span{arena.allocate<std::string_view>(2), 2};
|
||||
* response_parts[0] = "HTTP/1.1 200 OK\r\n\r\n";
|
||||
* response_parts[1] = "Hello World";
|
||||
* conn.append_message(response_parts, std::move(arena));
|
||||
* ```
|
||||
*/
|
||||
virtual void append_message(std::span<std::string_view> data_parts,
|
||||
Arena arena, bool close_after_send = false) = 0;
|
||||
|
||||
virtual ~MessageSender() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a single client connection with thread-safe concurrent access.
|
||||
*
|
||||
@@ -42,7 +76,7 @@ struct Server;
|
||||
* - No connection-owned arena for parsing/response generation
|
||||
* - Message queue stores spans + owning arenas until I/O completion
|
||||
*/
|
||||
struct Connection {
|
||||
struct Connection : MessageSender {
|
||||
// No public constructor or factory method - only Server can create
|
||||
// connections
|
||||
|
||||
@@ -91,7 +125,7 @@ struct Connection {
|
||||
* ```
|
||||
*/
|
||||
void append_message(std::span<std::string_view> data_parts, Arena arena,
|
||||
bool close_after_send = false);
|
||||
bool close_after_send = false) override;
|
||||
|
||||
/**
|
||||
* @brief Get a WeakRef to this connection for async operations.
|
||||
@@ -120,7 +154,10 @@ struct Connection {
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
WeakRef<Connection> get_weak_ref() const { return self_ref_.copy(); }
|
||||
WeakRef<MessageSender> get_weak_ref() const {
|
||||
assert(self_ref_.lock());
|
||||
return self_ref_.copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the unique identifier for this connection.
|
||||
@@ -278,23 +315,26 @@ private:
|
||||
|
||||
// Networking interface - only accessible by Server
|
||||
int readBytes(char *buf, size_t buffer_size);
|
||||
bool writeBytes();
|
||||
enum WriteBytesResult {
|
||||
Error = 1 << 0,
|
||||
Progress = 1 << 1,
|
||||
Drained = 1 << 2,
|
||||
Close = 1 << 3,
|
||||
};
|
||||
uint32_t write_bytes();
|
||||
|
||||
// Direct access methods for Server (must hold mutex)
|
||||
int getFd() const { return fd_; }
|
||||
bool has_messages() const { return !message_queue_.empty(); }
|
||||
bool should_close() const { return close_after_send_; }
|
||||
size_t getEpollIndex() const { return epoll_index_; }
|
||||
|
||||
// Server can set self-reference after creation
|
||||
void setSelfRef(WeakRef<Connection> self) { self_ref_ = std::move(self); }
|
||||
void close();
|
||||
|
||||
// Immutable connection properties
|
||||
const int fd_;
|
||||
int fd_;
|
||||
const int64_t id_;
|
||||
const size_t epoll_index_; // Index of the epoll instance this connection uses
|
||||
struct sockaddr_storage addr_; // sockaddr_storage handles IPv4/IPv6
|
||||
ConnectionHandler *handler_;
|
||||
ConnectionHandler *const handler_;
|
||||
WeakRef<Server> server_; // Weak reference to server for safe cleanup
|
||||
WeakRef<Connection> self_ref_; // WeakRef to self for get_weak_ref()
|
||||
|
||||
@@ -305,6 +345,13 @@ private:
|
||||
// mutex_, but if non-empty mutex_ can be
|
||||
// dropped while server accesses existing elements.
|
||||
int64_t outgoing_bytes_queued_{0}; // Counter of queued bytes
|
||||
bool close_after_send_{false}; // Close after sending all messages
|
||||
bool is_closed_{false}; // Connection closed state
|
||||
|
||||
#if __has_feature(thread_sanitizer)
|
||||
void tsan_acquire() { tsan_sync.load(std::memory_order_acquire); }
|
||||
void tsan_release() { tsan_sync.store(0, std::memory_order_release); }
|
||||
std::atomic<int> tsan_sync;
|
||||
#else
|
||||
void tsan_acquire() {}
|
||||
void tsan_release() {}
|
||||
#endif
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user