]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: shctx: Shared objects block by block allocation.
authorFrédéric Lécaille <flecaille@haproxy.com>
Mon, 22 Oct 2018 15:55:57 +0000 (17:55 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 24 Oct 2018 02:35:53 +0000 (04:35 +0200)
This patch makes shctx capable of storing objects in several parts,
each parts being made of several blocks. There is no more need to
walk through until reaching the end of a row to append new blocks.

A new pointer to a struct shared_block member, named last_reserved,
has been added to struct shared_block so that to memorize the last block which was
reserved by shctx_row_reserve_hot(). Same thing about "last_append" pointer which
is used to memorize the last block used by shctx_row_data_append() to store the data.

include/proto/shctx.h
include/types/shctx.h
src/cache.c
src/shctx.c
src/ssl_sock.c

index 55cb2a77260d94cececa92050b670261c867105f..13e00c753a4da55464c7cace38ef4a2a8511ae4f 100644 (file)
 #endif
 
 int shctx_init(struct shared_context **orig_shctx, int maxblocks, int blocksize, int extra, int shared);
-struct shared_block *shctx_row_reserve_hot(struct shared_context *shctx, int data_len);
+struct shared_block *shctx_row_reserve_hot(struct shared_context *shctx,
+                                           struct shared_block *last, int data_len);
 void shctx_row_inc_hot(struct shared_context *shctx, struct shared_block *first);
 void shctx_row_dec_hot(struct shared_context *shctx, struct shared_block *first);
 int shctx_row_data_append(struct shared_context *shctx,
-                          struct shared_block *first, unsigned char *data, int len);
+                          struct shared_block *first, struct shared_block *from,
+                          unsigned char *data, int len);
 int shctx_row_data_get(struct shared_context *shctx, struct shared_block *first,
                        unsigned char *dst, int offset, int len);
 
@@ -180,6 +182,19 @@ static inline void _shctx_unlock(struct shared_context *shctx)
 
 /* List Macros */
 
+/*
+ * Insert <s> block after <head> which is not necessarily the head of a list,
+ * so between <head> and the next element after <head>.
+ */
+static inline void shctx_block_append_hot(struct shared_context *shctx,
+                                          struct list *head,
+                                          struct shared_block *s)
+{
+       shctx->nbav--;
+       LIST_DEL(&s->list);
+       LIST_ADD(head, &s->list);
+}
+
 static inline void shctx_block_set_hot(struct shared_context *shctx,
                                    struct shared_block *s)
 {
index 559bebadb58e52fdf4d9dd63ec049a15fd81bb40..186f7365dcf001d08df856904a7da67f65838092 100644 (file)
@@ -24,6 +24,8 @@ struct shared_block {
        unsigned int len;          /* data length for the row */
        unsigned int block_count;  /* number of blocks */
        unsigned int refcount;
+       struct shared_block *last_reserved;
+       struct shared_block *last_append;
        unsigned char data[0];
 };
 
index 2024642f9f61ba80b63d3e2eba21754edb8bdd3d..b549537c8e2835785e990a241e7e833fcd5065b4 100644 (file)
@@ -224,7 +224,7 @@ cache_store_http_forward_data(struct stream *s, struct filter *filter,
                                /* Skip remaining headers to fill the cache */
                                c_adv(msg->chn, st->hdrs_len);
                                ret = shctx_row_data_append(shctx,
-                                                           st->first_block,
+                                                           st->first_block, NULL,
                                                            (unsigned char *)ci_head(msg->chn),
                                                            MIN(ci_contig_data(msg->chn), len - st->hdrs_len));
                                /* Rewind the buffer to forward all data */
@@ -440,7 +440,7 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
 
        shctx_lock(shctx);
 
-       first = shctx_row_reserve_hot(shctx, sizeof(struct cache_entry) + msg->sov + msg->body_len);
+       first = shctx_row_reserve_hot(shctx, NULL, sizeof(struct cache_entry) + msg->sov + msg->body_len);
        if (!first) {
                shctx_unlock(shctx);
                goto out;
@@ -465,7 +465,7 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
 
        /* does not need to be locked because it's in the "hot" list,
         * copy the headers */
-       if (shctx_row_data_append(shctx, first, (unsigned char *)ci_head(&s->res), msg->sov) < 0)
+       if (shctx_row_data_append(shctx, first, NULL, (unsigned char *)ci_head(&s->res), msg->sov) < 0)
                goto out;
 
        /* register the buffer in the filter ctx for filling it with data*/
index 59ac8b83162e9086441b4a5f23b55c2991cb4f4b..2a149a1d5972a00b28c2d049a5b627a90a7423ea 100644 (file)
@@ -25,42 +25,67 @@ int use_shared_mem = 0;
 #endif
 
 /*
- * Reserve a row, put it in the hotlist, set the refcount to 1
+ * Reserve a new row if <first> is null, put it in the hotlist, set the refcount to 1
+ * or append new blocks to the row with <first> as first block if non null.
  *
  * Reserve blocks in the avail list and put them in the hot list
  * Return the first block put in the hot list or NULL if not enough blocks available
  */
-struct shared_block *shctx_row_reserve_hot(struct shared_context *shctx, int data_len)
+struct shared_block *shctx_row_reserve_hot(struct shared_context *shctx,
+                                           struct shared_block *first, int data_len)
 {
-       struct shared_block *block, *sblock, *ret = NULL, *first;
+       struct shared_block *last = NULL, *block, *sblock, *ret = NULL, *next;
        int enough = 0;
        int freed = 0;
+       int remain;
 
        /* not enough usable blocks */
        if (data_len > shctx->nbav * shctx->block_size)
                goto out;
 
+       /* Note that <remain> is nul only if <first> is not nul. */
+       remain = 1;
+       if (first) {
+               /* Check that there is some block to reserve.
+                * In this first block of code we compute the remaining room in the
+                * current list of block already reserved for this object.
+                * We return asap if there is enough room to copy <data_len> bytes.
+                */
+               last = first->last_reserved;
+               /* Remaining room. */
+               remain = (shctx->block_size * first->block_count - first->len);
+               if (remain) {
+                       if (remain > data_len) {
+                               return last ? last : first;
+                       } else {
+                               data_len -= remain;
+                               if (!data_len)
+                                       return last ? last : first;
+                       }
+               }
+       }
+
        while (!enough && !LIST_ISEMPTY(&shctx->avail)) {
                int count = 0;
                int first_count = 0, first_len = 0;
 
-               first = block = LIST_NEXT(&shctx->avail, struct shared_block *, list);
+               next = block = LIST_NEXT(&shctx->avail, struct shared_block *, list);
                if (ret == NULL)
-                       ret = first;
+                       ret = next;
 
-               first_count = first->block_count;
-               first_len = first->len;
+               first_count = next->block_count;
+               first_len = next->len;
                /*
                Should never been set to 0.
-               if (first->block_count == 0)
-               first->block_count = 1;
+               if (next->block_count == 0)
+               next->block_count = 1;
                */
 
                list_for_each_entry_safe_from(block, sblock, &shctx->avail, list) {
 
                        /* release callback */
                        if (first_len && shctx->free_block)
-                               shctx->free_block(first, block);
+                               shctx->free_block(next, block);
 
                        block->block_count = 1;
                        block->len = 0;
@@ -68,22 +93,41 @@ struct shared_block *shctx_row_reserve_hot(struct shared_context *shctx, int dat
                        freed++;
                        data_len -= shctx->block_size;
 
-                       if (data_len > 0)
-                               shctx_block_set_hot(shctx, block);
-
-                       if (data_len <= 0 && !enough) {
-                               shctx_block_set_hot(shctx, block);
-                               ret->block_count = freed;
-                               ret->refcount = 1;
-                               enough = 1;
+                       if (data_len > 0 || !enough) {
+                               if (last) {
+                                       shctx_block_append_hot(shctx, &last->list, block);
+                                       last = block;
+                               } else {
+                                       shctx_block_set_hot(shctx, block);
+                               }
+                               if (!remain) {
+                                       first->last_append = block;
+                                       remain = 1;
+                               }
+                               if (data_len <= 0) {
+                                       ret->block_count = freed;
+                                       ret->refcount = 1;
+                                       ret->last_reserved = block;
+                                       enough = 1;
+                               }
                        }
-
                        count++;
                        if (count >= first_count)
                                break;
                }
        }
 
+       if (first) {
+               first->block_count += ret->block_count;
+               first->last_reserved = ret->last_reserved;
+               /* Reset this block. */
+               ret->last_reserved = NULL;
+               ret->block_count = 1;
+               ret->refcount = 0;
+               /* Return the first block. */
+               ret = first;
+       }
+
 out:
        return ret;
 }
@@ -147,50 +191,44 @@ void shctx_row_dec_hot(struct shared_context *shctx, struct shared_block *first)
  * Return the amount of appended data if ret >= 0
  * or how much more space it needs to contains the data if < 0.
  */
-int shctx_row_data_append(struct shared_context *shctx, struct shared_block *first, unsigned char *data, int len)
+int shctx_row_data_append(struct shared_context *shctx,
+                          struct shared_block *first, struct shared_block *from,
+                          unsigned char *data, int len)
 {
        int remain, start;
-       int count = 0;
        struct shared_block *block;
 
-
        /* return -<len> needed to work */
        if (len > first->block_count * shctx->block_size - first->len)
                return (first->block_count * shctx->block_size - first->len) - len;
 
-       /* skipping full buffers, stop at the first buffer with remaining space */
-       block = first;
+       block = from ? from : first;
        list_for_each_entry_from(block, &shctx->hot, list) {
-               count++;
-
-
-               /* break if there is not enough blocks */
-               if (count > first->block_count)
-                       break;
-
                /* end of copy */
                if (len <= 0)
                        break;
 
-               /* skip full buffers */
-               if (count * shctx->block_size <= first->len)
-                       continue;
-
-               /* remaining space in the current block which is not full */
-               remain = (shctx->block_size * count - first->len) % shctx->block_size;
-               /* if remain == 0, previous buffer are full, or first->len == 0 */
-               remain = remain ? remain : shctx->block_size;
-
-               /* start must be calculated before remain is modified */
-               start = shctx->block_size - remain;
+               /* remaining written bytes in the current block. */
+               remain = (shctx->block_size * first->block_count - first->len) % shctx->block_size;
+               /* if remain == 0, previous buffers are full, or first->len == 0 */
+               if (!remain) {
+                       remain = shctx->block_size;
+                       start = 0;
+               }
+               else {
+                       /* start must be calculated before remain is modified */
+                       start = shctx->block_size - remain;
+               }
 
                /* must not try to copy more than len */
                remain = MIN(remain, len);
 
                memcpy(block->data + start, data, remain);
+
                data += remain;
                len -= remain;
                first->len += remain; /* update len in the head of the row */
+               first->last_append = block;
        }
 
        return len;
index 41833768d81f7d012552da4772770010c145365b..ee713692bf2e3dce4dccfc7e38977d44c98751b0 100644 (file)
@@ -3871,7 +3871,7 @@ static int sh_ssl_sess_store(unsigned char *s_id, unsigned char *data, int data_
        struct shared_block *first;
        struct sh_ssl_sess_hdr *sh_ssl_sess, *oldsh_ssl_sess;
 
-       first = shctx_row_reserve_hot(ssl_shctx, data_len + sizeof(struct sh_ssl_sess_hdr));
+       first = shctx_row_reserve_hot(ssl_shctx, NULL, data_len + sizeof(struct sh_ssl_sess_hdr));
        if (!first) {
                /* Could not retrieve enough free blocks to store that session */
                return 0;
@@ -3897,7 +3897,7 @@ static int sh_ssl_sess_store(unsigned char *s_id, unsigned char *data, int data_
                first->len = sizeof(struct sh_ssl_sess_hdr);
        }
 
-       if (shctx_row_data_append(ssl_shctx, first, data, data_len) < 0) {
+       if (shctx_row_data_append(ssl_shctx, first, NULL, data, data_len) < 0) {
                shctx_row_dec_hot(ssl_shctx, first);
                return 0;
        }