]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/sbuf/SBuf.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / sbuf / SBuf.cc
index d72fa02216d5aacff7478a105305245a7366c50c..2b5d5a92e475fbda4ae89ce23221b1091c593629 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
 #include <iostream>
 #include <sstream>
 
-#ifdef VA_COPY
-#undef VA_COPY
-#endif
-#if defined HAVE_VA_COPY
-#define VA_COPY va_copy
-#elif defined HAVE___VA_COPY
-#define VA_COPY __va_copy
-#endif
-
 InstanceIdDefinitions(SBuf, "SBuf");
 
 SBufStats SBuf::stats;
@@ -157,7 +148,7 @@ SBuf::rawAppendFinish(const char *start, size_type actualSize)
     debugs(24, 8, id << " finish appending " << actualSize << " bytes");
 
     size_type newSize = length() + actualSize;
-    Must2(newSize <= min(maxSize,store_->capacity-off_), "raw append overflow");
+    Must3(newSize <= min(maxSize, store_->capacity-off_), "raw append fits", Here());
     len_ = newSize;
     store_->size = off_ + newSize;
 }
@@ -176,9 +167,6 @@ SBuf::rawSpace(size_type minSpace)
         debugs(24, 7, id << " not growing");
         return bufEnd();
     }
-    // TODO: we may try to memmove before realloc'ing in order to avoid
-    //   one allocation operation, if we're the sole owners of a MemBlob.
-    //   Maybe some heuristic on off_ and length()?
     cow(minSpace+length());
     return bufEnd();
 }
@@ -233,7 +221,7 @@ SBuf&
 SBuf::Printf(const char *fmt, ...)
 {
     // with printf() the fmt or an arg might be a dangerous char*
-    // NP: cant rely on vappendf() Locker because of clear()
+    // NP: can't rely on vappendf() Locker because of clear()
     const Locker blobKeeper(this, buf());
 
     va_list args;
@@ -266,15 +254,11 @@ SBuf::vappendf(const char *fmt, va_list vargs)
     size_type requiredSpaceEstimate = strlen(fmt)*2;
 
     char *space = rawSpace(requiredSpaceEstimate);
-#ifdef VA_COPY
     va_list ap;
-    VA_COPY(ap, vargs);
+    va_copy(ap, vargs);
     sz = vsnprintf(space, spaceSize(), fmt, ap);
     va_end(ap);
-#else
-    sz = vsnprintf(space, spaceSize(), fmt, vargs);
-#endif
-    Must2(sz >= 0, "vsnprintf() output error");
+    Must3(sz >= 0, "vsnprintf() succeeds", Here());
 
     /* check for possible overflow */
     /* snprintf on Linux returns -1 on output errors, or the size
@@ -286,7 +270,7 @@ SBuf::vappendf(const char *fmt, va_list vargs)
         requiredSpaceEstimate = sz*2; // TODO: tune heuristics
         space = rawSpace(requiredSpaceEstimate);
         sz = vsnprintf(space, spaceSize(), fmt, vargs);
-        Must2(sz >= 0, "vsnprintf() output error despite increased buffer space");
+        Must3(sz >= 0, "vsnprintf() succeeds (with increased buffer space)", Here());
     }
 
     // data was appended, update internal state
@@ -541,7 +525,7 @@ SBuf::c_str()
     ++stats.rawAccess;
     /* null-terminate the current buffer, by hand-appending a \0 at its tail but
      * without increasing its length. May COW, the side-effect is to guarantee that
-     * the MemBlob's tail is availabe for us to use */
+     * the MemBlob's tail is available for us to use */
     *rawSpace(1) = '\0';
     ++store_->size;
     ++stats.setChar;
@@ -664,7 +648,7 @@ SBuf::find(const SBuf &needle, size_type startPos) const
             debugs(24, 8, "First byte not found");
             return npos;
         }
-        // lastPossible guarrantees no out-of-bounds with memcmp()
+        // lastPossible guarantees no out-of-bounds with memcmp()
         if (0 == memcmp(needle.buf(), tmp, needle.length())) {
             debugs(24, 8, "Found at " << (tmp-buf()));
             return (tmp-buf());
@@ -862,19 +846,23 @@ SBuf::toUpper()
  * NO verifications are made on the size parameters, it's up to the caller to
  * make sure that the new size is big enough to hold the copied contents.
  * The re-allocated storage MAY be bigger than the requested size due to size-chunking
- * algorithms in MemBlock, it is guarranteed NOT to be smaller.
+ * algorithms in MemBlock, it is guaranteed NOT to be smaller.
  */
 void
 SBuf::reAlloc(size_type newsize)
 {
     debugs(24, 8, id << " new size: " << newsize);
     Must(newsize <= maxSize);
+    // TODO: Consider realloc(3)ing in some cases instead.
     MemBlob::Pointer newbuf = new MemBlob(newsize);
-    if (length() > 0)
+    if (length() > 0) {
         newbuf->append(buf(), length());
+        ++stats.cowAllocCopy;
+    } else {
+        ++stats.cowJustAlloc;
+    }
     store_ = newbuf;
     off_ = 0;
-    ++stats.cowSlow;
     debugs(24, 7, id << " new store capacity: " << store_->capacity);
 }
 
@@ -900,10 +888,27 @@ SBuf::cow(SBuf::size_type newsize)
     if (newsize == npos || newsize < length())
         newsize = length();
 
-    if (store_->LockCount() == 1 && newsize == length()) {
-        debugs(24, 8, id << " no cow needed");
-        ++stats.cowFast;
-        return;
+    if (store_->LockCount() == 1) {
+        // MemBlob::size reflects past owners. Refresh to maximize spaceSize().
+        store_->syncSize(off_ + length());
+
+        const auto availableSpace = spaceSize();
+        const auto neededSpace = newsize - length();
+        if (neededSpace <= availableSpace) {
+            debugs(24, 8, id << " no cow needed; have " << availableSpace);
+            ++stats.cowAvoided;
+            return;
+        }
+        // consume idle leading space if doing so avoids reallocation
+        // this case is typical for fill-consume-fill-consume-... I/O buffers
+        if (neededSpace <= availableSpace + off_) {
+            debugs(24, 8, id << " no cow after shifting " << off_ << " to get " << (availableSpace + off_));
+            store_->consume(off_);
+            off_ = 0;
+            ++stats.cowShift;
+            assert(neededSpace <= spaceSize());
+            return;
+        }
     }
     reAlloc(newsize);
 }