Add Connection::arena
This commit is contained in:
58
src/main.cpp
58
src/main.cpp
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user