From: Eduard Bagdasaryan Date: Wed, 23 Apr 2025 12:59:03 +0000 (+0000) Subject: Do not treat tiny virgin response buffer space specially (#2056) X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=76a642b613ddb0d4450930945703c68343f8d133;p=thirdparty%2Fsquid.git Do not treat tiny virgin response buffer space specially (#2056) A long series of commits sprinkled Squid code with special treatment of virgin response buffer space equal to one or two bytes: * 2005 commit 2afaba07 adds a 2-byte hack to HttpStateData. The hack avoids stalling transactions by never asking StoreEntry::delayAwareRead() to read 1 byte. * 2006 commit 253cacc adds the same 2-byte hack to Ftp::Client. * 2007 commit 478cfe99 adds a 2-byte hack to Icap::ModXact::virginConsume() so that ICAP transactions do not stall when HttpStateData hack prevents new virgin bytes from being read into a BodyPipe buffer that has just one or two space bytes left. The ICAP hack was probably one-byte more aggressive than necessary... * 2011 commit 0ad2b63b adds +1 byte hacks to ServerStateData and ClientHttpRequest to work around the same StoreEntry::delayAwareRead() problem leading to excessive buffering with slow clients. * A followup 2012 commit 4dc2b072 adjusts StoreEntry::delayAwareRead() to allow 1-byte reads, making _all_ of the above hacks unnecessary. However, that commit only removed +1 byte hacks added in 2011, missing HttpStateData and ICAP hacks added in 2005, 2006 and 2007, probably because that 2012 work focused on fixing the bug introduced by 2011 commit (that was triggered by slow client-Squid communication). We now remove the remaining known hacks that worked around StoreEntry::delayAwareRead() inability to read 1 byte (i.e. the first three hacks on the above list). These changes also happen to fix transaction stalls with read_ahead_gap set to 1 and probably some other rare use cases: Transactions could stall because inBuf.spaceSize() may be 1 for an emptied inBuf, leading to maybeMakeSpaceAvailable() returning zero due to `read_size < 2` being true. That zero result prevents HttpStateData from making progress by reading new virgin response bytes. Mistreatment of "emptied inBuf" cases was exposed by 2023 commit 50c5af88 changes. More work is needed to address other, more prominent "emptied inBuf" cases. --- diff --git a/src/adaptation/icap/ModXact.cc b/src/adaptation/icap/ModXact.cc index e03c9c21df..f7201fb8b3 100644 --- a/src/adaptation/icap/ModXact.cc +++ b/src/adaptation/icap/ModXact.cc @@ -435,10 +435,7 @@ void Adaptation::Icap::ModXact::virginConsume() BodyPipe &bp = *virgin.body_pipe; const bool wantToPostpone = isRepeatable || canStartBypass || protectGroupBypass; - // Why > 2? HttpState does not use the last bytes in the buffer - // because Client::delayRead() is arguably broken. See - // HttpStateData::maybeReadVirginBody for more details. - if (wantToPostpone && bp.buf().spaceSize() > 2) { + if (wantToPostpone && bp.buf().spaceSize() > 0) { // Postponing may increase memory footprint and slow the HTTP side // down. Not postponing may increase the number of ICAP errors // if the ICAP service fails. We may also use "potential" space to diff --git a/src/clients/FtpClient.cc b/src/clients/FtpClient.cc index 3cd38db070..a667cd5df8 100644 --- a/src/clients/FtpClient.cc +++ b/src/clients/FtpClient.cc @@ -929,7 +929,7 @@ Ftp::Client::maybeReadVirginBody() debugs(9, 9, "FTP may read up to " << read_sz << " bytes"); - if (read_sz < 2) // see http.cc + if (!read_sz) return; data.read_pending = true; diff --git a/src/http.cc b/src/http.cc index 6411c29203..f15cf5b5ef 100644 --- a/src/http.cc +++ b/src/http.cc @@ -1699,7 +1699,7 @@ HttpStateData::maybeMakeSpaceAvailable(const size_t maxReadSize) // how much we want to read const size_t read_size = calcBufferSpaceToReserve(inBuf.spaceSize(), maxReadSize); - if (read_size < 2) { + if (!read_size) { debugs(11, 7, "will not read up to " << read_size << " into buffer (" << inBuf.length() << "/" << inBuf.spaceSize() << ") from " << serverConnection); return 0; }