From: Christopher Faulet Date: Thu, 15 Oct 2026 09:30:59 +0000 (+0200) Subject: OPTIMIZE: stream: Stop holding a reference on the frontend during stream_free() X-Git-Tag: v3.5-dev10~162 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=c2eef4f4b31f8b6fed4c44980b0c4ec4b936e803;p=haproxy.git OPTIMIZE: stream: Stop holding a reference on the frontend during stream_free() Holding a reference on the frontend during the whole stream teardown has a performance impact: all the streams of a frontend atomically increment and decrement the same counter. Instead, the frontend capture pools are flushed before the stream connectors teardown and the remaining pools after it, depending on a flush_pools flag. That way the frontend is no longer dereferenced after sc_destroy(). Must be backported with the SPOE fix b5db88d9c ("spoe: Let an agent outlive its applets during a backend deletion"), as far as 3.3. --- diff --git a/src/stream.c b/src/stream.c index 4c425230f..dfa731623 100644 --- a/src/stream.c +++ b/src/stream.c @@ -624,6 +624,7 @@ void stream_free(struct stream *s) struct proxy *fe = sess->fe; struct bref *bref, *back; int i; + int flush_pools = 0; DBG_TRACE_POINT(STRM_EV_STRM_FREE, s); @@ -739,14 +740,14 @@ void stream_free(struct stream *s) pool_free(fe->rsp_cap_pool, s->res_cap); } - /* Hold a reference on the frontend for the rest of the stream - * teardown. The stream connectors are destroyed below. An - * client applet attached to the stream will be released there, - * and it may free an internal frontend (created and owned by an - * applet), leaving the end of the function with a dangling - * frontend. The reference is dropped at the very end. + /* Flush frontend capture pools if it is stopping. Global pools + * will be too flushed at the end. */ - proxy_take(fe); + if (unlikely(fe->flags & (PR_FL_DISABLED|PR_FL_STOPPED))) { + flush_pools = 1; + pool_flush(fe->req_cap_pool); + pool_flush(fe->rsp_cap_pool); + } } /* Cleanup all variable contexts. */ @@ -794,7 +795,7 @@ void stream_free(struct stream *s) pool_free(pool_head_stream, s); /* We may want to free the maximum amount of pools if the proxy is stopping */ - if (fe && unlikely(fe->flags & (PR_FL_DISABLED|PR_FL_STOPPED))) { + if (flush_pools) { pool_flush(pool_head_buffer); pool_flush(pool_head_large_buffer); pool_flush(pool_head_http_txn); @@ -805,11 +806,8 @@ void stream_free(struct stream *s) pool_flush(pool_head_session); pool_flush(pool_head_connection); pool_flush(pool_head_pendconn); - pool_flush(fe->req_cap_pool); - pool_flush(fe->rsp_cap_pool); } - proxy_drop(fe); }