Commit b959d9d3 authored by jan.koester's avatar jan.koester
Browse files

test

parent 6f8e6048
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -375,12 +375,13 @@ static std::vector<uint8_t> h3BuildResponse(uint16_t status_code,

libhttppp::HttpEvent::HttpEvent(std::vector<netplus::socket*> serversocket, int timeout,
                                 size_t h2OffloadThreads, int idleTimeoutSeconds,
                                 size_t h1OffloadThreads, size_t h2DispatchQueueMax)
                                 size_t h1OffloadThreads, size_t h2DispatchQueueMax,
                                 size_t h1DispatchQueueMax)
    : netplus::event(serversocket, timeout, idleTimeoutSeconds) {
    if (h2OffloadThreads > 0)
        _h2DispatchPool = std::make_unique<netplus::ThreadPool>(h2OffloadThreads, h2DispatchQueueMax);
    if (h1OffloadThreads > 0)
        _h1DispatchPool = std::make_unique<netplus::ThreadPool>(h1OffloadThreads);
        _h1DispatchPool = std::make_unique<netplus::ThreadPool>(h1OffloadThreads, h1DispatchQueueMax);
    // 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
@@ -542,8 +543,27 @@ bool libhttppp::HttpEvent::_dispatchH2Stream(HttpRequest &cureq,
            // stays effectively unique since nothing else ever sees this
            // particular shared_ptr.
            auto trBox = std::make_shared<std::unique_ptr<HttpRequest>>(std::move(tempreq_ptr));

            // Marks this connection as having offloaded work in flight for the idle reaper
            // (see netplus::con::hasPendingOps()) -- the reaper's only other signal,
            // lasteventime, is never refreshed by this background task's own write below
            // (_flushSendDataNow doesn't touch it), so without this a connection that's
            // otherwise quiet while one stream is slowly rendering looks idle and gets
            // closed out from under the still-running task: proxyplus sends its FIN first
            // while the peer is still legitimately waiting on the response, and the peer
            // never sends its own FIN back (FIN_WAIT_2 buildup -- see the 08-16 netstat lead).
            connOwner->slots[0].PendingOps.fetch_add(1, std::memory_order_relaxed);
            bool accepted = _h2DispatchPool->submit(
                [this, connOwner, trBox, sid, tid, args]() mutable {
                    // Always runs, on every exit path below (including the early
                    // "torn down while blocked" return), so PendingOps can't be left
                    // incremented forever if the connection is legitimately reaped
                    // right after this task finishes.
                    struct PendingOpGuard {
                        netplus::con::ConSlot *slot;
                        ~PendingOpGuard() { slot->PendingOps.fetch_sub(1, std::memory_order_relaxed); }
                    } pendingGuard{&connOwner->slots[0]};

                    // The ONLY blocking call in this task — touches
                    // *trBox (private to this task) only, never
                    // cureq/h2state(). A backend call inside RequestEvent
@@ -577,6 +597,11 @@ bool libhttppp::HttpEvent::_dispatchH2Stream(HttpRequest &cureq,
                });
            if (accepted) return true;

            // Rejected -- the lambda above (and its PendingOpGuard) will never run, so undo
            // the increment ourselves or PendingOps would sit above zero forever and this
            // connection would never be idle-reaped again.
            connOwner->slots[0].PendingOps.fetch_sub(1, std::memory_order_relaxed);

            // Pool is already at h2DispatchQueueMax pending tasks -- every worker is presumably
            // busy with something slow (or stuck) and piling this stream up behind them too
            // would just be another request nobody notices is waiting forever (the exact
@@ -640,7 +665,7 @@ void libhttppp::HttpEvent::_dispatchH1Request(HttpRequest &cureq, size_t consume
            // _dispatchH2Stream's trBox below.
            auto sockBox = std::make_shared<std::unique_ptr<netplus::socket>>(std::move(sock));

            _h1DispatchPool->submit(
            bool accepted = _h1DispatchPool->submit(
                [this, connOwner, sockBox, consumeBodyBytes, tid, args]() mutable {
                    HttpRequest &cureq2 = static_cast<HttpRequest&>(*connOwner);
                    // Safe without event_mutex: nothing else can observe this connection while
+12 −1
Original line number Diff line number Diff line
@@ -75,9 +75,20 @@ namespace libhttppp {
        // way to notice. A positive value makes _dispatchH2Stream respond 503 immediately once
        // the pool is this full instead of queuing behind it. Has no effect if h2OffloadThreads
        // is 0 (nothing to bound).
        // h1DispatchQueueMax: H1 analogue of h2DispatchQueueMax, bounding _h1DispatchPool (see
        // netplus::ThreadPool's own max_queue_size). 0 (the default) keeps it unbounded for
        // every existing caller. Before this existed, a saturated _h1DispatchPool left every
        // subsequent offloaded request's socket detached from the event loop (invisible to the
        // idle reaper) and un-timed until a worker finally freed up -- if the peer gave up
        // first, proxyplus discovered it far too late and started its own close against a
        // peer that might already be gone, producing sockets stuck in LAST_ACK. A positive
        // value makes _dispatchH1Request answer 503 immediately (without ever calling the
        // possibly-slow RequestEvent) once the pool is this full, mirroring H2's overload
        // response. Has no effect if h1OffloadThreads is 0.
        HttpEvent(std::vector<netplus::socket*> serversocket,int timeout = 1000,
                  size_t h2OffloadThreads = 0, int idleTimeoutSeconds = 0,
                  size_t h1OffloadThreads = 0, size_t h2DispatchQueueMax = 0);
                  size_t h1OffloadThreads = 0, size_t h2DispatchQueueMax = 0,
                  size_t h1DispatchQueueMax = 0);

        // Return true to have this stream's RequestEvent run on the H2
        // offload thread pool instead of inline in the frame-processing