first commit: echo server
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* 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
|
||||
Reference in New Issue
Block a user