]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] buffer: make buffer_feed* support writing non-contiguous chunks
authorWilly Tarreau <w@1wt.eu>
Tue, 10 Aug 2010 13:28:21 +0000 (15:28 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 10 Aug 2010 15:48:57 +0000 (17:48 +0200)
The buffer_feed* functions that are used to send data to buffers did only
support sending contiguous chunks while they're relying on memcpy(). This
patch improves on this by making them able to write in two chunks if needed.
Thus, the buffer_almost_full() function has been improved to really consider
the remaining space and not just what can be written at once.

include/proto/buffers.h
src/buffers.c

index 870dadb614dfa6dfcc401ac5e3890673d6db07e1..dca3c889a0d152b7f2166e71206147d86cfdb89e 100644 (file)
@@ -289,6 +289,15 @@ static inline int buffer_realign(struct buffer *buf)
        return buffer_max(buf);
 }
 
+/*
+ * Return the maximum amount of bytes that can be written into the buffer in
+ * one call to buffer_feed*().
+ */
+static inline int buffer_free_space(struct buffer *buf)
+{
+       return buffer_max_len(buf) - buf->l;
+}
+
 /*
  * Return the max amount of bytes that can be stuffed into the buffer at once.
  * Note that this may be lower than the actual buffer size when the free space
@@ -314,10 +323,33 @@ static inline int buffer_contig_space(struct buffer *buf)
        return ret;
 }
 
+/*
+ * Same as above but the caller may pass the value of buffer_max_len(buf) if it
+ * knows it, thus avoiding some calculations.
+ */
+static inline int buffer_contig_space_with_len(struct buffer *buf, int maxlen)
+{
+       int ret;
+
+       if (buf->l == 0) {
+               buf->r = buf->w = buf->lr = buf->data;
+               ret = maxlen;
+       }
+       else if (buf->r > buf->w) {
+               ret = buf->data + maxlen - buf->r;
+       }
+       else {
+               ret = buf->w - buf->r;
+               if (ret > maxlen)
+                       ret = maxlen;
+       }
+       return ret;
+}
+
 /* Return 1 if the buffer has less than 1/4 of its capacity free, otherwise 0 */
 static inline int buffer_almost_full(struct buffer *buf)
 {
-       if (buffer_contig_space(buf) < buf->size / 4)
+       if (buffer_free_space(buf) < buf->size / 4)
                return 1;
        return 0;
 }
index 2557fe4a0add5037814e81b09a7ac565644d0c77..c128bb9a357d4f8149eeabc05f98f41304e35066 100644 (file)
@@ -86,19 +86,24 @@ int buffer_feed2(struct buffer *buf, const char *str, int len)
        if (len == 0)
                return -1;
 
-       if (len > buffer_max_len(buf)) {
-               /* we can't write this chunk and will never be able to, because
-                * it is larger than the buffer's current max size.
+       max = buffer_max_len(buf);
+       if (len > max - buf->l) {
+               /* we can't write this chunk right now because the buffer is
+                * almost full or because the block is too large. Return the
+                * available space or -2 if impossible.
                 */
-               return -2;
-       }
+               if (len > max)
+                       return -2;
 
-       max = buffer_contig_space(buf);
+               return max - buf->l;
+       }
 
+       /* OK so the data fits in the buffer in one or two blocks */
+       max = buffer_contig_space_with_len(buf, max);
+       memcpy(buf->r, str, MIN(len, max));
        if (len > max)
-               return max;
+               memcpy(buf->data, str + max, len - max);
 
-       memcpy(buf->r, str, len);
        buf->l += len;
        buf->r += len;
        buf->total += len;
@@ -113,8 +118,8 @@ int buffer_feed2(struct buffer *buf, const char *str, int len)
                buf->flags &= ~BF_OUT_EMPTY;
        }
 
-       if (buf->r == buf->data + buf->size)
-               buf->r = buf->data;
+       if (buf->r >= buf->data + buf->size)
+               buf->r -= buf->size;
 
        buf->flags &= ~BF_FULL;
        if (buf->l >= buffer_max_len(buf))