From e4f34e8a0fec22a0300d6d529a5899ced3d0582a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 25 Oct 2010 22:36:23 -0400 Subject: [PATCH] Correct logic for realigning a chain in evbuffer_add The old logic was both too eager to realign (it would move a whole chain to save a byte) and too reluctant to realign (it would only realign when data would fit into the misaligned portion, without considering the space at the end of the chain). The new logic matches that from evbuffer_expand_singlechain: it only realigns a chain when not much data is to be moved, and there's a bunch of space to be regained. Spotted by Yan Lin. --- buffer.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/buffer.c b/buffer.c index eb2d84b2..0e6c7762 100644 --- a/buffer.c +++ b/buffer.c @@ -136,6 +136,8 @@ static int use_mmap = 1; #define CHAIN_PINNED_R(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_R) != 0) static void evbuffer_chain_align(struct evbuffer_chain *chain); +static int evbuffer_chain_should_realign(struct evbuffer_chain *chain, + size_t datalen); static void evbuffer_deferred_callback(struct deferred_cb *cb, void *arg); static int evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos, const char *mem, size_t len); @@ -1503,7 +1505,8 @@ evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen) buf->total_len += datlen; buf->n_add_for_cb += datlen; goto out; - } else if ((size_t)chain->misalign >= datlen && !CHAIN_PINNED(chain)) { + } else if (!CHAIN_PINNED(chain) && + evbuffer_chain_should_realign(chain, datlen)) { /* we can fit the data into the misalignment */ evbuffer_chain_align(chain); @@ -1638,6 +1641,17 @@ evbuffer_chain_align(struct evbuffer_chain *chain) #define MAX_TO_COPY_IN_EXPAND 4096 #define MAX_TO_REALIGN_IN_EXPAND 2048 +/** Helper: return true iff we should realign chain to fit datalen bytes of + data in it. */ +static int +evbuffer_chain_should_realign(struct evbuffer_chain *chain, + size_t datlen) +{ + return chain->buffer_len - chain->off >= datlen && + (chain->off < chain->buffer_len / 2) && + (chain->off <= MAX_TO_REALIGN_IN_EXPAND); +} + /* Expands the available space in the event buffer to at least datlen, all in * a single chunk. Return that chunk. */ static struct evbuffer_chain * @@ -1680,14 +1694,11 @@ evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen) /* If the misalignment plus the remaining space fulfills our data * needs, we could just force an alignment to happen. Afterwards, we - * have enough space. But only do this if we're saving at least 1/2 - * the chain size and moving no more than MAX_TO_REALIGN_IN_EXPAND - * bytes. Otherwise the space savings are probably offset by the time - * lost in copying. + * have enough space. But only do this if we're saving a lot of space + * and not moving too much data. Otherwise the space savings are + * probably offset by the time lost in copying. */ - if (chain->buffer_len - chain->off >= datlen && - (chain->off < chain->buffer_len / 2) && - (chain->off <= MAX_TO_REALIGN_IN_EXPAND)) { + if (evbuffer_chain_should_realign(chain, datlen)) { evbuffer_chain_align(chain); result = chain; goto ok; -- 2.40.0