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)
{
#include "Debug.h"
#include "globals.h"
#include "sbuf/Exceptions.h"
+#include "sbuf/forward.h"
#include "sbuf/MemBlob.h"
#include "sbuf/Stats.h"
} SBufCaseSensitive;
class CharacterSet;
-class SBuf;
/** Forward input const_iterator for SBufs
*
*/
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;
+
+ /*
+ * Parameters are listed in the reverse order of importance: Satisfaction of
+ * the lower-listed requirements may violate the higher-listed requirements.
+ */
+ size_type idealSpace = 0; ///< if allocating anyway, provide this much space
+ size_type minSpace = 0; ///< allocate if spaceSize() is smaller
+ size_type maxCapacity = SBuf::maxSize; ///< do not allocate more than this
+ bool allowShared = true; ///< whether sharing our storage with others is OK
+};
+
/// ostream output operator
inline std::ostream &
operator <<(std::ostream& os, const SBuf& S)
class SBuf;
class SBufIterator;
class SBufReverseIterator;
+class SBufReservationRequirements;
class OutOfBoundsException;
class InvalidParamException;
}
}
-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
Server::maybeMakeSpaceAvailable()
{
- if (inBuf.spaceSize() < 2) {
- const SBuf::size_type haveCapacity = inBuf.length() + inBuf.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.
- inBuf.reserveCapacity(CLIENT_REQ_BUF_SZ);
- } else {
- const SBuf::size_type wantCapacity = min(static_cast<SBuf::size_type>(Config.maxRequestBufferSize), haveCapacity*2);
- inBuf.reserveCapacity(wantCapacity);
- }
- debugs(33, 2, "growing request buffer: available=" << inBuf.spaceSize() << " used=" << inBuf.length());
- }
- return (inBuf.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
+ inBuf.reserve(requirements);
+ if (!inBuf.spaceSize())
+ debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
}
void
public:
/// grows the available read buffer space (if possible)
- bool maybeMakeSpaceAvailable();
+ void maybeMakeSpaceAvailable();
// Client TCP connection details from comm layer.
Comm::ConnectionPointer clientConnection;
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)