105 lines
4.4 KiB
C++
105 lines
4.4 KiB
C++
/* ************************************************************************** */
|
|
/* */
|
|
/* ::: :::::::: */
|
|
/* SlotPool.hpp :+: :+: :+: */
|
|
/* +:+ +:+ +:+ */
|
|
/* By: acossari <acossari@student.codam.nl> +#+ +:+ +#+ */
|
|
/* +#+#+#+#+#+ +#+ */
|
|
/* Created: 2026/08/28 21:51:32 by acossari #+# #+# */
|
|
/* Updated: 2026/08/29 20:33:13 by acossari ### ########.fr */
|
|
/* */
|
|
/* ************************************************************************** */
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <vector>
|
|
|
|
#include "event/EventToken.hpp"
|
|
#include "net/Connection.hpp"
|
|
#include "net/FileDescriptor.hpp"
|
|
|
|
namespace webserv {
|
|
|
|
// SlotPool uses fixed storage instead of growing a container for every new
|
|
// connection. This representation provides three guarantees:
|
|
//
|
|
// 1. Every slot keeps a permanent index and stable storage. EventToken pairs
|
|
// that index with an endpoint generation so stale events can be rejected.
|
|
//
|
|
// 2. The slot array is allocated once. Connections are constructed and
|
|
// destroyed in place, so their slots are never relocated.
|
|
//
|
|
// 3. The free list limits the pool to CAPACITY connections. acquire() returns
|
|
// no index when it is exhausted, and drain() makes retired slots reusable.
|
|
class SlotPool final {
|
|
public:
|
|
// Slot indices use uint32_t to match their field in the 64-bit EventToken.
|
|
// 256 is a calculated tradeoff, not an optimal value. It doubles the
|
|
// target of 128 concurrent clients exercised by the provided tester. It
|
|
// assumes a conservative limit of 1024 fds per process, common on Linux.
|
|
//
|
|
// fd budget = 4 base fds (standard streams and epoll)
|
|
// + L listener fds
|
|
// + 2 * 256 connection fds (socket + possible temporary file)
|
|
// + 2 * 24 CGI pipe fds (the tester reaches 20, leaving 4 spare)
|
|
// + 8 spare fds (temporary setup and general working margin)
|
|
// = 572 + L
|
|
//
|
|
// This leaves space for up to 452 listeners, giving substantial headroom.
|
|
// A capacity of 512 would require 1084 + L fds, already exceeding 1024.
|
|
static constexpr std::uint32_t CAPACITY = 256;
|
|
// Each slot tracks the client socket and the CGI stdin and stdout pipes.
|
|
static constexpr std::size_t ENDPOINTS_PER_SLOT = 3;
|
|
|
|
struct Endpoint {
|
|
std::uint32_t generation = 0;
|
|
std::uint32_t registeredEvents = 0;
|
|
bool registered = false;
|
|
};
|
|
|
|
SlotPool();
|
|
|
|
bool full() const noexcept { return freeHead_ == CAPACITY; }
|
|
|
|
// Constructs a Connection for the socket in a free slot and returns its
|
|
// index. Returns std::nullopt when the pool is full.
|
|
std::optional<std::uint32_t> acquire(FileDescriptor socket);
|
|
|
|
// Returns true only if the token still identifies a registered endpoint
|
|
// in an active slot with the same generation.
|
|
bool isCurrent(const EventToken& token) const noexcept;
|
|
|
|
// Accesses the connection or endpoint metadata already stored in a slot.
|
|
Connection& connection(std::uint32_t index);
|
|
Endpoint& endpoint(std::uint32_t index, EndpointKind kind);
|
|
|
|
// Quarantines an active slot until the current event batch is complete.
|
|
void retire(std::uint32_t index) noexcept;
|
|
|
|
// Recycles all quarantined slots and returns how many became available.
|
|
std::size_t drain();
|
|
|
|
private:
|
|
enum class SlotState { Free, InUse, Retired };
|
|
|
|
struct Slot {
|
|
std::array<Endpoint, ENDPOINTS_PER_SLOT> endpoints;
|
|
std::optional<Connection> connection;
|
|
SlotState state = SlotState::Free;
|
|
std::uint32_t nextFree = 0;
|
|
};
|
|
|
|
std::array<Slot, CAPACITY> slots_;
|
|
// Holds retired slot indices until they can return to the free list.
|
|
// With storage reserved for CAPACITY entries, it acts as if it were a fixed
|
|
// array while tracking how many entries are active without another counter.
|
|
std::vector<std::uint32_t> pendingFree_;
|
|
std::uint32_t freeHead_ = 0;
|
|
};
|
|
|
|
} // namespace webserv
|