Replace VLA with thread local vectors

This commit is contained in:
2025-08-22 18:04:12 -04:00
parent f51f257df6
commit c58a00a34f
3 changed files with 27 additions and 35 deletions

View File

@@ -88,27 +88,6 @@ FetchContent_MakeAvailable(llhttp)
include_directories(src)
# Check for VLA (Variable Length Array) support
include(CheckCXXSourceCompiles)
check_cxx_source_compiles(
"
int main() {
int n = 10;
char arr[n];
return 0;
}
"
HAVE_VLA_SUPPORT)
if(NOT HAVE_VLA_SUPPORT)
message(
FATAL_ERROR
"Compiler must support Variable Length Arrays (VLA). Please use GCC or Clang."
)
endif()
message(STATUS "Compiler supports Variable Length Arrays")
find_package(weaseljson REQUIRED)
# Generate JSON token hash table using gperf

View File

@@ -1,10 +1,14 @@
#include "connection.hpp"
#include "server.hpp" // Need this for releaseBackToServer implementation
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <errno.h>
#include <limits.h>
// Static thread-local storage for iovec buffer
static thread_local std::vector<struct iovec> g_iovec_buffer{IOV_MAX};
Connection::Connection(struct sockaddr_storage addr, int fd, int64_t id,
size_t epoll_index, ConnectionHandler *handler,
Server &server)
@@ -62,8 +66,9 @@ int Connection::readBytes(char *buf, size_t buffer_size) {
bool Connection::writeBytes() {
while (!messages_.empty()) {
// Build iovec array up to IOV_MAX limit
struct iovec iov[IOV_MAX];
// Build iovec array up to IOV_MAX limit using thread-local vector
assert(g_iovec_buffer.size() == IOV_MAX);
struct iovec *iov = g_iovec_buffer.data();
int iov_count = 0;
for (auto it = messages_.begin();

View File

@@ -17,6 +17,9 @@
#include <unistd.h>
#include <vector>
// Static thread-local storage for read buffer (used across different functions)
static thread_local std::vector<char> g_read_buffer;
std::shared_ptr<Server> Server::create(const weaseldb::Config &config,
ConnectionHandler &handler,
const std::vector<int> &listen_fds) {
@@ -285,15 +288,16 @@ void Server::start_io_threads(std::vector<std::thread> &threads) {
// Each thread uses its assigned epoll instance (round-robin)
int epollfd = get_epoll_for_thread(thread_id);
struct epoll_event events[config_.server.event_batch_size];
std::unique_ptr<Connection> batch[config_.server.event_batch_size];
int batch_events[config_.server.event_batch_size];
std::vector<epoll_event> events(config_.server.event_batch_size);
std::vector<std::unique_ptr<Connection>> batch(
config_.server.event_batch_size);
std::vector<int> batch_events(config_.server.event_batch_size);
std::vector<int>
ready_listen_fds; // Reused across iterations to avoid allocation
for (;;) {
int event_count =
epoll_wait(epollfd, events, config_.server.event_batch_size, -1);
int event_count = epoll_wait(epollfd, events.data(),
config_.server.event_batch_size, -1);
if (event_count == -1) {
if (errno == EINTR) {
continue;
@@ -336,8 +340,9 @@ void Server::start_io_threads(std::vector<std::thread> &threads) {
// Process existing connections in batch
if (batch_count > 0) {
process_connection_batch(epollfd, {batch, (size_t)batch_count},
{batch_events, (size_t)batch_count});
process_connection_batch(
epollfd, std::span(batch).subspan(0, batch_count),
std::span(batch_events).subspan(0, batch_count));
}
// Only accept on listen sockets that epoll indicates are ready
@@ -393,8 +398,9 @@ void Server::start_io_threads(std::vector<std::thread> &threads) {
// Process batch if full
if (batch_count == config_.server.event_batch_size) {
process_connection_batch(epollfd, {batch, (size_t)batch_count},
{batch_events, (size_t)batch_count});
process_connection_batch(
epollfd, {batch.data(), (size_t)batch_count},
{batch_events.data(), (size_t)batch_count});
batch_count = 0;
}
} // End inner accept loop
@@ -402,8 +408,9 @@ void Server::start_io_threads(std::vector<std::thread> &threads) {
// Process remaining accepted connections
if (batch_count > 0) {
process_connection_batch(epollfd, {batch, (size_t)batch_count},
{batch_events, (size_t)batch_count});
process_connection_batch(
epollfd, std::span(batch).subspan(0, batch_count),
std::span(batch_events).subspan(0, batch_count));
batch_count = 0;
}
}
@@ -417,7 +424,8 @@ void Server::process_connection_reads(std::unique_ptr<Connection> &conn,
// Handle EPOLLIN - read data and process it
if (events & EPOLLIN) {
auto buf_size = config_.server.read_buffer_size;
char buf[buf_size];
g_read_buffer.resize(buf_size);
char *buf = g_read_buffer.data();
int r = conn->readBytes(buf, buf_size);
if (r < 0) {