Add Connection::arena

This commit is contained in:
2025-08-19 11:51:44 -04:00
parent 1141251002
commit 5dc800a088

View File

@@ -1,3 +1,4 @@
#include "arena_allocator.hpp"
#include "config.hpp" #include "config.hpp"
#include <atomic> #include <atomic>
#include <cassert> #include <cassert>
@@ -130,6 +131,7 @@ struct Connection {
const int fd; const int fd;
const int64_t id; const int64_t id;
struct sockaddr_storage addr; // sockaddr_storage handles IPv4/IPv6 struct sockaddr_storage addr; // sockaddr_storage handles IPv4/IPv6
ArenaAllocator arena;
Connection(struct sockaddr_storage addr, int fd, int64_t id) Connection(struct sockaddr_storage addr, int fd, int64_t id)
: fd(fd), id(id), addr(addr) { : fd(fd), id(id), addr(addr) {
@@ -145,15 +147,24 @@ struct Connection {
} }
} }
struct Task { struct Message {
std::string s; // Owned by Connection::arena
bool closeConnection{false}; std::string_view s;
int written = 0; int written = 0;
}; };
std::deque<Message, ArenaStlAllocator<Message>> messages{
ArenaStlAllocator<Message>{&arena}};
// Copies s into arena, and appends to messages
void appendMessage(std::string_view s) {
char *arena_str = arena.allocate<char>(s.size());
std::memcpy(arena_str, s.data(), s.size());
messages.emplace_back(std::string_view(arena_str, s.size()), 0);
}
// Whether or not to close the connection after completing writing the
// response
bool closeConnection{false};
std::deque<Task> tasks; bool readBytes(size_t max_request_size) {
void readBytes(size_t max_request_size) {
// Use smaller buffer size but respect max request size // Use smaller buffer size but respect max request size
// TODO revisit // TODO revisit
size_t buf_size = std::min(size_t(4096), max_request_size); size_t buf_size = std::min(size_t(4096), max_request_size);
@@ -165,28 +176,23 @@ struct Connection {
continue; continue;
} }
if (errno == EAGAIN) { if (errno == EAGAIN) {
return; return false;
} }
perror("read"); perror("read");
goto close_connection; return true;
} }
if (r == 0) { if (r == 0) {
goto close_connection; return true;
} }
// "pump parser" // "pump parser"
// TODO revisit // TODO revisit
tasks.emplace_back(std::string{buf.data(), size_t(r)}); appendMessage({buf.data(), size_t(r)});
} }
close_connection:
tasks.emplace_back(std::string{}, true);
} }
bool writeBytes() { bool writeBytes() {
while (!tasks.empty()) { while (!messages.empty()) {
auto &front = tasks.front(); auto &front = messages.front();
if (front.closeConnection) {
return true;
}
int w; int w;
for (;;) { for (;;) {
w = write(fd, front.s.data() + front.written, w = write(fd, front.s.data() + front.written,
@@ -206,10 +212,12 @@ struct Connection {
assert(w != 0); assert(w != 0);
front.written += w; front.written += w;
if (front.written == int(front.s.size())) { if (front.written == int(front.s.size())) {
tasks.pop_front(); messages.pop_front();
} }
} }
return false; assert(messages.empty());
arena.reset();
return closeConnection;
} }
// This is necessary because tsan doesn't (yet?) understand that there's a // This is necessary because tsan doesn't (yet?) understand that there's a
@@ -346,8 +354,16 @@ int main(int argc, char *argv[]) {
continue; continue;
} }
// When we register our epoll interest, if we have something to
// write, we write. Otherwise we read.
assert(!((events[i].events & EPOLLIN) &&
(events[i].events & EPOLLOUT)));
if (events[i].events & EPOLLIN) { if (events[i].events & EPOLLIN) {
conn->readBytes(max_request_size); bool done = conn->readBytes(max_request_size);
if (done) {
continue;
}
} }
if (events[i].events & EPOLLOUT) { if (events[i].events & EPOLLOUT) {
@@ -357,7 +373,7 @@ int main(int argc, char *argv[]) {
} }
} }
if (conn->tasks.empty()) { if (conn->messages.empty()) {
events[i].events = EPOLLIN | EPOLLONESHOT | EPOLLRDHUP; events[i].events = EPOLLIN | EPOLLONESHOT | EPOLLRDHUP;
} else { } else {
events[i].events = EPOLLOUT | EPOLLONESHOT | EPOLLRDHUP; events[i].events = EPOLLOUT | EPOLLONESHOT | EPOLLRDHUP;