Commit 6aaf9605 authored by jan.koester's avatar jan.koester
Browse files

test

parent 18d1a7fb
Loading
Loading
Loading
Loading
+26 −8
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <string>
#include <thread>
#include <chrono>
#include <algorithm>

#include <netplus/socket.h>
#include <netplus/exception.h>
@@ -356,6 +357,12 @@ libhttppp::HttpEvent::HttpEvent(std::vector<netplus::socket*> serversocket, int
    : netplus::event(serversocket, timeout) {
    if (h2OffloadThreads > 0)
        _h2DispatchPool = std::make_unique<netplus::ThreadPool>(h2OffloadThreads);
    // Bounded like quicDispatchPool() in libnetplus (same rationale: this
    // work is dominated by waiting on upstream/network, not CPU, so a
    // generous multiple of core count is cheap) -- caps how many OS
    // threads a burst of concurrent streaming H3 responses can spawn.
    _h3StreamPool = std::make_unique<netplus::ThreadPool>(
        (std::max<unsigned>)(4, std::thread::hardware_concurrency() * 2));
    // Set the HTTP/3 stream callback on QUIC server sockets so that
    // child connections created by accept() inherit it.  The event loop
    // never creates a con / calls ConnectEvent for QUIC children,
@@ -1687,15 +1694,26 @@ void libhttppp::HttpEvent::Http3StreamEvent(netplus::socket *sock,
                return;
            }

            // Event-driven streaming: move tempreq to a background
            // thread (like H2's _resumeH2Streams) so we don't block
            // the QUIC callback.  The thread calls ResponseEvent in
            // a loop, sending DATA frames as upstream produces data,
            // with proper sleeps between empty iterations.
            // Event-driven streaming: move tempreq onto the bounded H3
            // stream pool (like H2's _resumeH2Streams / _h2DispatchPool)
            // so we don't block the QUIC callback -- and, critically,
            // so a burst of concurrent streaming responses can't spawn
            // an unbounded pile of raw OS threads all hammering the
            // shared QUIC listener socket via pumpIncoming() below (that
            // starved the socket's own drain thread in production). The
            // task calls ResponseEvent in a loop, sending DATA frames as
            // upstream produces data, with proper sleeps between empty
            // iterations.
            tempreq.SendData.pos = 0;
            std::thread([this, q, stream_id, h3tid,
                         tr = std::move(tempreq_ptr),
            // std::function (what ThreadPool::submit takes) requires its
            // target to be copy-constructible even though it's only ever
            // moved/invoked here -- see _dispatchH2Stream's identical
            // trBox workaround for a move-only unique_ptr capture.
            auto trBox = std::make_shared<std::unique_ptr<HttpRequest>>(std::move(tempreq_ptr));
            _h3StreamPool->submit([this, q, stream_id, h3tid,
                         trBox,
                         content_length, total_sent]() mutable {
                HttpRequest *tr = trBox->get();
                size_t sent = total_sent;
                size_t empty_streak = 0;
                static constexpr size_t max_empty = 500;
@@ -1768,7 +1786,7 @@ void libhttppp::HttpEvent::Http3StreamEvent(netplus::socket *sock,
                    // handling above.
                    q->resetStream(stream_id, 0x0102); // H3_INTERNAL_ERROR
                }
            }).detach();
            });

            return;
        }
+7 −0
Original line number Diff line number Diff line
@@ -139,6 +139,13 @@ namespace libhttppp {
        // constructor. See shouldOffloadH2Dispatch / _dispatchH2Stream.
        std::unique_ptr<netplus::ThreadPool>  _h2DispatchPool;

        // Always constructed (unlike _h2DispatchPool, which is opt-in):
        // every streaming H3 response needs somewhere to run its
        // continuation loop (see Http3StreamEvent). Bounded so a burst of
        // concurrent large/slow responses spawns at most this many OS
        // threads instead of one raw detached thread per response.
        std::unique_ptr<netplus::ThreadPool>  _h3StreamPool;

        // Returns true if the stream was handed off to the background
        // offload pool instead of being finished synchronously — callers
        // must treat that as "progress" for reprocess-loop purposes even