diff --git a/CMakeLists.txt b/CMakeLists.txt index 3565214..4b74d5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/connection.cpp b/src/connection.cpp index 2b96f33..e1568f0 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -1,10 +1,14 @@ #include "connection.hpp" #include "server.hpp" // Need this for releaseBackToServer implementation +#include #include #include #include #include +// Static thread-local storage for iovec buffer +static thread_local std::vector 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(); diff --git a/src/server.cpp b/src/server.cpp index 6ae6637..5c6e0c7 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -17,6 +17,9 @@ #include #include +// Static thread-local storage for read buffer (used across different functions) +static thread_local std::vector g_read_buffer; + std::shared_ptr Server::create(const weaseldb::Config &config, ConnectionHandler &handler, const std::vector &listen_fds) { @@ -285,15 +288,16 @@ void Server::start_io_threads(std::vector &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 batch[config_.server.event_batch_size]; - int batch_events[config_.server.event_batch_size]; + std::vector events(config_.server.event_batch_size); + std::vector> batch( + config_.server.event_batch_size); + std::vector batch_events(config_.server.event_batch_size); std::vector 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 &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 &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 &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 &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) {