Replace VLA with thread local vectors
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user