Document per-connection locking strategy

This commit is contained in:
2025-09-15 22:33:52 -04:00
parent 0d76c73077
commit ba59a992dd
3 changed files with 9 additions and 74 deletions

View File

@@ -201,57 +201,6 @@ struct Connection : MessageSender {
*/
int64_t get_id() const { return id_; }
/**
* @brief Get the number of bytes queued for transmission.
*
* Returns the total number of bytes in all messages currently
* queued for transmission to the client. This includes all data added via
* append_message() that has not yet been sent over the network.
*
* @return Total bytes queued for transmission
*
* @warning Thread Safety: Only call from the thread that currently owns this
* connection. Concurrent access to the message queue is not thread-safe.
*
* @note Performance: This method uses an O(1) counter for fast retrieval
* in release builds. In debug builds, validates counter accuracy.
*
* @note The count decreases as the server sends data via writeBytes() and
* removes completed messages from the queue.
*
* Use cases:
* ```cpp
* // Check if all data has been sent
* if (conn->outgoing_bytes_queued() == 0) {
* conn->reset(); // Safe to reset arena
* }
*
* // Implement backpressure
* if (conn->outgoing_bytes_queued() > MAX_BUFFER_SIZE) {
* // Stop adding more data until queue drains
* }
*
* // Logging/monitoring
* metrics.recordQueueDepth(conn->get_id(), conn->outgoing_bytes_queued());
* ```
*/
int64_t outgoing_bytes_queued() const {
std::lock_guard lock(mutex_);
#ifndef NDEBUG
// Debug build: validate counter accuracy
int64_t computed_total = 0;
for (const auto &message : message_queue_) {
for (const auto &part : message.data_parts) {
computed_total += part.size();
}
}
assert(
outgoing_bytes_queued_ == computed_total &&
"outgoing_bytes_queued_ counter is out of sync with actual queue size");
#endif
return outgoing_bytes_queued_;
}
/**
* @brief Protocol-specific data pointer for handler use.
*
@@ -347,19 +296,14 @@ private:
WeakRef<Server> server_; // Weak reference to server for safe epoll_ctl calls
WeakRef<Connection> self_ref_; // WeakRef to self for get_weak_ref()
// state shared with pipeline threads (protected by mutex_)
mutable std::mutex mutex_; // Protects all mutable state
std::deque<Message>
message_queue_; // Queue of messages to send. Protected by
// mutex_, but if non-empty mutex_ can be
// dropped while server accesses existing elements.
int64_t outgoing_bytes_queued_{0}; // Counter of queued bytes
std::deque<PendingResponse>
pending_response_queue_; // Responses awaiting protocol processing
// Only accessed from io thread
std::deque<Message> message_queue_;
mutable std::mutex mutex_;
ConnectionShutdown shutdown_requested_{
ConnectionShutdown::None}; // Shutdown mode requested
// Set to a negative number in `close`
int fd_;
ConnectionShutdown::None}; // Protected by mutex_
std::deque<PendingResponse> pending_response_queue_; // Protected by mutex_
int fd_; // Protected by mutex_
#if __has_feature(thread_sanitizer)
void tsan_acquire() { tsan_sync.load(std::memory_order_acquire); }