cow(minCapacity);
}
+SBuf::size_type
+SBuf::reserve(const SBufReservationRequirements &req)
+{
+ debugs(24, 8, id << " was: " << off_ << '+' << len_ << '+' << spaceSize() <<
+ '=' << store_->capacity);
+
+ const bool mustRealloc = !req.allowShared && store_->LockCount() > 1;
+
+ if (!mustRealloc && spaceSize() >= req.minSpace)
+ return spaceSize(); // the caller is content with what we have
+
+ /* only reallocation can make the caller happy */
+
+ if (!mustRealloc && len_ >= req.maxCapacity)
+ return spaceSize(); // but we cannot reallocate
+
+ const size_type newSpace = std::min(req.idealSpace, maxSize - len_);
+ reserveCapacity(std::min(len_ + newSpace, req.maxCapacity));
+ debugs(24, 7, id << " now: " << off_ << '+' << len_ << '+' << spaceSize() <<
+ '=' << store_->capacity);
+ return spaceSize(); // reallocated and probably reserved enough space
+}
+
char *
SBuf::rawSpace(size_type minSpace)
{
};
class CharacterSet;
+class SBufReservationRequirements;
/**
* A String or Buffer.
*/
void reserveCapacity(size_type minCapacity);
+ /** Accommodate caller's requirements regarding SBuf's storage if possible.
+ *
+ * \return spaceSize(), which may be zero
+ */
+ size_type reserve(const SBufReservationRequirements &requirements);
+
/** slicing method
*
* Removes SBuf prefix and suffix, leaving a sequence of 'n'
SBuf& lowAppend(const char * memArea, size_type areaSize);
};
+/// Named SBuf::reserve() parameters. Defaults ask for and restrict nothing.
+class SBufReservationRequirements
+{
+public:
+ typedef SBuf::size_type size_type;
+
+ SBufReservationRequirements() : idealSpace(0), minSpace(0), maxCapacity(SBuf::maxSize), allowShared(true) {}
+
+ /*
+ * Parameters are listed in the reverse order of importance: Satisfaction of
+ * the lower-listed requirements may violate the higher-listed requirements.
+ */
+ size_type idealSpace; ///< if allocating anyway, provide this much space
+ size_type minSpace; ///< allocate if spaceSize() is smaller
+ size_type maxCapacity; ///< do not allocate more than this
+ bool allowShared; ///< whether sharing our storage with others is OK
+};
+
/// ostream output operator
inline std::ostream &
operator <<(std::ostream& os, const SBuf& S)
return result;
}
-bool
+/// Prepare inBuf for I/O. This method balances several conflicting desires:
+/// 1. Do not read too few bytes at a time.
+/// 2. Do not waste too much buffer space.
+/// 3. Do not [re]allocate or memmove the buffer too much.
+/// 4. Obey Config.maxRequestBufferSize limit.
+void
ConnStateData::In::maybeMakeSpaceAvailable()
{
- if (buf.spaceSize() < 2) {
- const SBuf::size_type haveCapacity = buf.length() + buf.spaceSize();
- if (haveCapacity >= Config.maxRequestBufferSize) {
- debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
- return false;
- }
- if (haveCapacity == 0) {
- // haveCapacity is based on the SBuf visible window of the MemBlob buffer, which may fill up.
- // at which point bump the buffer back to default. This allocates a new MemBlob with any un-parsed bytes.
- buf.reserveCapacity(CLIENT_REQ_BUF_SZ);
- } else {
- const SBuf::size_type wantCapacity = min(static_cast<SBuf::size_type>(Config.maxRequestBufferSize), haveCapacity*2);
- buf.reserveCapacity(wantCapacity);
- }
- debugs(33, 2, "growing request buffer: available=" << buf.spaceSize() << " used=" << buf.length());
- }
- return (buf.spaceSize() >= 2);
+ // The hard-coded parameters are arbitrary but seem reasonable.
+ // A careful study of Squid I/O and parsing patterns is needed to tune them.
+ SBufReservationRequirements requirements;
+ requirements.minSpace = 1024; // smaller I/Os are not worth their overhead
+ requirements.idealSpace = CLIENT_REQ_BUF_SZ; // we expect few larger I/Os
+ requirements.maxCapacity = Config.maxRequestBufferSize;
+ requirements.allowShared = true; // allow because inBuf is used immediately
+ buf.reserve(requirements);
+ if (!buf.spaceSize())
+ debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
}
void
// Client TCP connection details from comm layer.
Comm::ConnectionPointer clientConnection;
- struct In {
+ class In {
+ public:
In();
~In();
- bool maybeMakeSpaceAvailable();
+ void maybeMakeSpaceAvailable();
ChunkedCodingParser *bodyParser; ///< parses chunked request body
SBuf buf;
void SBuf::forceSize(size_type newSize) STUB
const char* SBuf::c_str() STUB_RETVAL("")
void SBuf::reserveCapacity(size_type minCapacity) STUB
+SBuf::size_type SBuf::reserve(const SBufReservationRequirements &) STUB_RETVAL(0)
SBuf& SBuf::chop(size_type pos, size_type n) STUB_RETVAL(*this)
SBuf& SBuf::trim(const SBuf &toRemove, bool atBeginning, bool atEnd) STUB_RETVAL(*this)
SBuf SBuf::substr(size_type pos, size_type n) const STUB_RETVAL(*this)
bool ConnStateData::serveDelayedError(ClientSocketContext *context) STUB_RETVAL(false)
#endif
-bool ConnStateData::In::maybeMakeSpaceAvailable() STUB_RETVAL(false)
+void ConnStateData::In::maybeMakeSpaceAvailable() STUB
void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl) STUB
const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end) STUB_RETVAL(NULL)