MINOR: htx: Deduce the number of used blocks from tail and head values

<head> and <tail> fields are now signed 32-bits integers. For an empty HTX
message, these fields are set to -1. So the field <used> is now useless and can
safely be removed. To know if an HTX message is empty or not, we just compare
<head> against -1 (it also works with <tail>). The function htx_nbblks() has
been added to get the number of used blocks.
This commit is contained in:
Christopher Faulet 2019-06-11 16:32:24 +02:00
parent 5a916f7326
commit 192c6a23d4
6 changed files with 55 additions and 70 deletions

View File

@ -202,21 +202,21 @@ struct htx {
* blocks (blocks and their contents), you need to add size used by blocks, * blocks (blocks and their contents), you need to add size used by blocks,
* i.e. [ used * sizeof(struct htx_blk *) ] */ * i.e. [ used * sizeof(struct htx_blk *) ] */
uint32_t used; /* number of blocks in use */ int32_t tail; /* newest inserted block. -1 if the HTX message is empty */
uint32_t tail; /* newest inserted block. -1 if the HTX message is empty */ int32_t head; /* oldest inserted block. -1 if the HTX message is empty */
uint32_t head; /* oldest inserted block. -1 if the HTX message is empty */ int32_t first; /* position of the first block to (re)start the analyse. -1 if unset. */
uint32_t tail_addr; /* start address of the free space in front of the the blocks table */ uint32_t tail_addr; /* start address of the free space in front of the the blocks table */
uint32_t head_addr; /* start address of the free space at the beginning */ uint32_t head_addr; /* start address of the free space at the beginning */
uint32_t end_addr; /* end address of the free space at the beginning */ uint32_t end_addr; /* end address of the free space at the beginning */
uint64_t extra; /* known bytes amount remaining to receive */ uint64_t extra; /* known bytes amount remaining to receive */
uint32_t flags; /* HTX_FL_* */ uint32_t flags; /* HTX_FL_* */
int32_t first; /* position of the first block to (re)start the analyse. -1 if unset. */ /* XXX 4 bytes unused */
struct htx_blk blocks[0]; /* Blocks representing the HTTP message itself */ /* Blocks representing the HTTP message itself */
struct htx_blk blocks[0] __attribute__((aligned(8)));
}; };
@ -370,15 +370,12 @@ static inline uint32_t htx_get_blksz(const struct htx_blk *blk)
} }
} }
/* Returns the position of the oldest entry (head). /* Returns the position of the oldest entry (head). It returns a signed 32-bits
* * integer, -1 means the HTX message is empty.
* An signed 32-bits integer is returned to handle -1 case. Blocks position are
* store on unsigned 32-bits integer, but it is impossible to have so much
* blocks to overflow a 32-bits signed integer !
*/ */
static inline int32_t htx_get_head(const struct htx *htx) static inline int32_t htx_get_head(const struct htx *htx)
{ {
return (htx->used ? htx->head : -1); return htx->head;
} }
/* Returns the oldest HTX block (head) if the HTX message is not /* Returns the oldest HTX block (head) if the HTX message is not
@ -401,15 +398,12 @@ static inline enum htx_blk_type htx_get_head_type(const struct htx *htx)
return (blk ? htx_get_blk_type(blk) : HTX_BLK_UNUSED); return (blk ? htx_get_blk_type(blk) : HTX_BLK_UNUSED);
} }
/* Returns the position of the newest entry (tail). /* Returns the position of the newest entry (tail). It returns a signed 32-bits
* * integer, -1 means the HTX message is empty.
* An signed 32-bits integer is returned to handle -1 case. Blocks position are
* store on unsigned 32-bits integer, but it is impossible to have so much
* blocks to overflow a 32-bits signed integer !
*/ */
static inline int32_t htx_get_tail(const struct htx *htx) static inline int32_t htx_get_tail(const struct htx *htx)
{ {
return (htx->used ? htx->tail : -1); return htx->tail;
} }
/* Returns the newest HTX block (tail) if the HTX message is not /* Returns the newest HTX block (tail) if the HTX message is not
@ -432,17 +426,11 @@ static inline enum htx_blk_type htx_get_tail_type(const struct htx *htx)
return (blk ? htx_get_blk_type(blk) : HTX_BLK_UNUSED); return (blk ? htx_get_blk_type(blk) : HTX_BLK_UNUSED);
} }
/* Returns the position of the first block in the HTX message <htx>. If unset, /* Returns the position of the first block in the HTX message <htx>. -1 means
* or if <htx> is empty, -1 is returned. * the first block is unset or the HTS is empty.
*
* An signed 32-bits integer is returned to handle -1 case. Blocks position are
* store on unsigned 32-bits integer, but it is impossible to have so much
* blocks to overflow a 32-bits signed integer !
*/ */
static inline int32_t htx_get_first(const struct htx *htx) static inline int32_t htx_get_first(const struct htx *htx)
{ {
if (!htx->used)
return -1;
return htx->first; return htx->first;
} }
@ -469,17 +457,10 @@ static inline enum htx_blk_type htx_get_first_type(const struct htx *htx)
/* Returns the position of block immediately before the one pointed by <pos>. If /* Returns the position of block immediately before the one pointed by <pos>. If
* the message is empty or if <pos> is the position of the head, -1 returned. * the message is empty or if <pos> is the position of the head, -1 returned.
*
* An signed 32-bits integer is returned to handle -1 case. Blocks position are
* store on unsigned 32-bits integer, but it is impossible to have so much
* blocks to overflow a 32-bits signed integer !
*/ */
static inline int32_t htx_get_prev(const struct htx *htx, uint32_t pos) static inline int32_t htx_get_prev(const struct htx *htx, uint32_t pos)
{ {
int32_t head; if (htx->head == -1 || pos == htx->head)
head = htx_get_head(htx);
if (head == -1 || pos == head)
return -1; return -1;
return (pos - 1); return (pos - 1);
} }
@ -498,14 +479,10 @@ static inline struct htx_blk *htx_get_prev_blk(const struct htx *htx,
/* Returns the position of block immediately after the one pointed by <pos>. If /* Returns the position of block immediately after the one pointed by <pos>. If
* the message is empty or if <pos> is the position of the tail, -1 returned. * the message is empty or if <pos> is the position of the tail, -1 returned.
*
* An signed 32-bits integer is returned to handle -1 case. Blocks position are
* store on unsigned 32-bits integer, but it is impossible to have so much
* blocks to overflow a 32-bits signed integer !
*/ */
static inline int32_t htx_get_next(const struct htx *htx, uint32_t pos) static inline int32_t htx_get_next(const struct htx *htx, uint32_t pos)
{ {
if (!htx->used || pos == htx->tail) if (htx->tail == -1 || pos == htx->tail)
return -1; return -1;
return (pos + 1); return (pos + 1);
@ -655,7 +632,10 @@ static inline void htx_cut_data_blk(struct htx *htx, struct htx_blk *blk, uint32
/* Returns the space used by metadata in <htx>. */ /* Returns the space used by metadata in <htx>. */
static inline uint32_t htx_meta_space(const struct htx *htx) static inline uint32_t htx_meta_space(const struct htx *htx)
{ {
return (htx->used * sizeof(htx->blocks[0])); if (htx->tail == -1)
return 0;
return ((htx->tail + 1 - htx->head) * sizeof(htx->blocks[0]));
} }
/* Returns the space used (payload + metadata) in <htx> */ /* Returns the space used (payload + metadata) in <htx> */
@ -707,11 +687,11 @@ static inline int htx_almost_full(const struct htx *htx)
/* Resets an HTX message */ /* Resets an HTX message */
static inline void htx_reset(struct htx *htx) static inline void htx_reset(struct htx *htx)
{ {
htx->data = htx->used = htx->tail = htx->head = 0; htx->tail = htx->head = htx->first = -1;
htx->data = 0;
htx->tail_addr = htx->head_addr = htx->end_addr = 0; htx->tail_addr = htx->head_addr = htx->end_addr = 0;
htx->extra = 0; htx->extra = 0;
htx->flags = HTX_FL_NONE; htx->flags = HTX_FL_NONE;
htx->first = -1;
} }
/* Returns the available room for raw data in buffer <buf> once HTX overhead is /* Returns the available room for raw data in buffer <buf> once HTX overhead is
@ -773,7 +753,7 @@ static inline struct htx *htx_from_buf(struct buffer *buf)
/* Update <buf> accordingly to the HTX message <htx> */ /* Update <buf> accordingly to the HTX message <htx> */
static inline void htx_to_buf(struct htx *htx, struct buffer *buf) static inline void htx_to_buf(struct htx *htx, struct buffer *buf)
{ {
if (!htx->used && !(htx->flags & (HTX_FL_PARSING_ERROR|HTX_FL_UPGRADE))) { if ((htx->head == -1) && !(htx->flags & (HTX_FL_PARSING_ERROR|HTX_FL_UPGRADE))) {
htx_reset(htx); htx_reset(htx);
b_set_data(buf, 0); b_set_data(buf, 0);
} }
@ -786,7 +766,7 @@ static inline void htx_to_buf(struct htx *htx, struct buffer *buf)
*/ */
static inline int htx_is_empty(const struct htx *htx) static inline int htx_is_empty(const struct htx *htx)
{ {
return !htx->used; return (htx->head == -1);
} }
/* Returns 1 if the message is not empty, otherwise it returns 0. Note that it /* Returns 1 if the message is not empty, otherwise it returns 0. Note that it
@ -794,9 +774,17 @@ static inline int htx_is_empty(const struct htx *htx)
*/ */
static inline int htx_is_not_empty(const struct htx *htx) static inline int htx_is_not_empty(const struct htx *htx)
{ {
return htx->used; return (htx->head != -1);
} }
/* Returns the number of used blocks in the HTX message <htx>. Note that it is
* illegal to call this function with htx == NULL. Note also blocks of type
* HTX_BLK_UNUSED are part of used blocks.
*/
static inline int htx_nbblks(const struct htx *htx)
{
return ((htx->head != -1) ? (htx->tail + 1 - htx->head) : 0);
}
/* For debugging purpose */ /* For debugging purpose */
static inline const char *htx_blk_type_str(enum htx_blk_type type) static inline const char *htx_blk_type_str(enum htx_blk_type type)
{ {
@ -820,7 +808,8 @@ static inline void htx_dump(struct htx *htx)
int32_t pos; int32_t pos;
fprintf(stderr, "htx:%p [ size=%u - data=%u - used=%u - wrap=%s - extra=%llu]\n", fprintf(stderr, "htx:%p [ size=%u - data=%u - used=%u - wrap=%s - extra=%llu]\n",
htx, htx->size, htx->data, htx->used, (!htx->head_addr) ? "NO" : "YES", htx, htx->size, htx->data, htx_nbblks(htx),
(!htx->head_addr) ? "NO" : "YES",
(unsigned long long)htx->extra); (unsigned long long)htx->extra);
fprintf(stderr, "\tfirst=%d - head=%u, tail=%u\n", fprintf(stderr, "\tfirst=%d - head=%u, tail=%u\n",
htx->first, htx->head, htx->tail); htx->first, htx->head, htx->tail);

View File

@ -77,7 +77,7 @@ int http_find_header(const struct htx *htx, const struct ist name,
goto return_hdr; goto return_hdr;
} }
if (!htx->used) if (htx_is_empty(htx))
return 0; return 0;
for (blk = htx_get_first_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) { for (blk = htx_get_first_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) {
@ -431,7 +431,7 @@ int http_remove_header(struct htx *htx, struct http_hdr_ctx *ctx)
v = htx_get_blk_value(htx, blk); v = htx_get_blk_value(htx, blk);
if (len == v.len) { if (len == v.len) {
blk = htx_remove_blk(htx, blk); blk = htx_remove_blk(htx, blk);
if (blk || !htx->used) { if (blk || htx_is_empty(htx)) {
ctx->blk = blk; ctx->blk = blk;
ctx->value = ist2(NULL, 0); ctx->value = ist2(NULL, 0);
ctx->lws_before = ctx->lws_after = 0; ctx->lws_before = ctx->lws_after = 0;

View File

@ -13,7 +13,7 @@
#include <common/chunk.h> #include <common/chunk.h>
#include <common/htx.h> #include <common/htx.h>
struct htx htx_empty = { .size = 0, .data = 0, .used = 0 }; struct htx htx_empty = { .size = 0, .data = 0, .head = -1, .tail = -1, .first = -1 };
/* Defragments an HTX message. It removes unused blocks and unwraps the payloads /* Defragments an HTX message. It removes unused blocks and unwraps the payloads
* part. A temporary buffer is used to do so. This function never fails. if * part. A temporary buffer is used to do so. This function never fails. if
@ -30,7 +30,7 @@ struct htx_blk *htx_defrag(struct htx *htx, struct htx_blk *blk)
uint32_t addr, blksz; uint32_t addr, blksz;
int32_t first = -1; int32_t first = -1;
if (!htx->used) if (htx->head == -1)
return NULL; return NULL;
blkpos = -1; blkpos = -1;
@ -64,7 +64,6 @@ struct htx_blk *htx_defrag(struct htx *htx, struct htx_blk *blk)
} }
htx->used = new;
htx->first = first; htx->first = first;
htx->head = 0; htx->head = 0;
htx->tail = new - 1; htx->tail = new - 1;
@ -116,16 +115,14 @@ static void htx_defrag_blks(struct htx *htx)
static struct htx_blk *htx_reserve_nxblk(struct htx *htx, uint32_t blksz) static struct htx_blk *htx_reserve_nxblk(struct htx *htx, uint32_t blksz)
{ {
struct htx_blk *blk; struct htx_blk *blk;
uint32_t used, tail; uint32_t tail, headroom, tailroom;
uint32_t headroom, tailroom;
if (blksz > htx_free_data_space(htx)) if (blksz > htx_free_data_space(htx))
return NULL; /* full */ return NULL; /* full */
if (!htx->used) { if (htx->head == -1) {
/* Empty message */ /* Empty message */
htx->head = htx->tail = htx->first = 0; htx->head = htx->tail = htx->first = 0;
htx->used = 1;
blk = htx_get_blk(htx, htx->tail); blk = htx_get_blk(htx, htx->tail);
blk->addr = 0; blk->addr = 0;
htx->data = blksz; htx->data = blksz;
@ -141,11 +138,10 @@ static struct htx_blk *htx_reserve_nxblk(struct htx *htx, uint32_t blksz)
*/ */
tail = htx->tail + 1; tail = htx->tail + 1;
if (sizeof(htx->blocks[0]) * htx_pos_to_idx(htx, tail) >= htx->tail_addr) if (sizeof(htx->blocks[0]) * htx_pos_to_idx(htx, tail) >= htx->tail_addr)
used = htx->used + 1; ;
else if (tail > htx->used) { else if (htx->head > 0) {
htx_defrag_blks(htx); htx_defrag_blks(htx);
tail = htx->tail + 1; tail = htx->tail + 1;
used = htx->used + 1;
BUG_ON(sizeof(htx->blocks[0]) * htx_pos_to_idx(htx, tail) < htx->tail_addr); BUG_ON(sizeof(htx->blocks[0]) * htx_pos_to_idx(htx, tail) < htx->tail_addr);
} }
else else
@ -182,14 +178,12 @@ static struct htx_blk *htx_reserve_nxblk(struct htx *htx, uint32_t blksz)
/* need to defragment the message before inserting upfront */ /* need to defragment the message before inserting upfront */
htx_defrag(htx, NULL); htx_defrag(htx, NULL);
tail = htx->tail + 1; tail = htx->tail + 1;
used = htx->used + 1;
blk = htx_get_blk(htx, tail); blk = htx_get_blk(htx, tail);
blk->addr = htx->tail_addr; blk->addr = htx->tail_addr;
htx->tail_addr += blksz; htx->tail_addr += blksz;
} }
htx->tail = tail; htx->tail = tail;
htx->used = used;
htx->data += blksz; htx->data += blksz;
/* Set first position if not already set */ /* Set first position if not already set */
if (htx->first == -1) if (htx->first == -1)
@ -226,6 +220,8 @@ static int htx_prepare_blk_expansion(struct htx *htx, struct htx_blk *blk, int32
uint32_t sz, tailroom, headroom; uint32_t sz, tailroom, headroom;
int ret = 3; int ret = 3;
BUG_ON(htx->head == -1);
headroom = (htx->end_addr - htx->head_addr); headroom = (htx->end_addr - htx->head_addr);
tailroom = sizeof(htx->blocks[0]) * htx_pos_to_idx(htx, htx->tail) - htx->tail_addr; tailroom = sizeof(htx->blocks[0]) * htx_pos_to_idx(htx, htx->tail) - htx->tail_addr;
BUG_ON((int32_t)headroom < 0); BUG_ON((int32_t)headroom < 0);
@ -328,8 +324,10 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk)
enum htx_blk_type type; enum htx_blk_type type;
uint32_t pos, addr, sz; uint32_t pos, addr, sz;
BUG_ON(htx->head == -1);
/* This is the last block in use */ /* This is the last block in use */
if (htx->used == 1) { if (htx->head == htx->tail) {
htx_reset(htx); htx_reset(htx);
return NULL; return NULL;
} }
@ -347,14 +345,12 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk)
/* There is at least 2 blocks, so tail is always > 0 */ /* There is at least 2 blocks, so tail is always > 0 */
if (pos == htx->head) { if (pos == htx->head) {
/* move the head forward */ /* move the head forward */
htx->used--;
htx->head++; htx->head++;
} }
else if (pos == htx->tail) { else if (pos == htx->tail) {
/* remove the tail. this was the last inserted block so /* remove the tail. this was the last inserted block so
* return NULL. */ * return NULL. */
htx->tail--; htx->tail--;
htx->used--;
blk = NULL; blk = NULL;
goto end; goto end;
} }
@ -364,7 +360,7 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk)
if (pos == htx->first) if (pos == htx->first)
htx->first = (blk ? htx_get_blk_pos(htx, blk) : -1); htx->first = (blk ? htx_get_blk_pos(htx, blk) : -1);
if (htx->used == 1) { if (htx->head == htx->tail) {
/* If there is just one block in the HTX message, free space can /* If there is just one block in the HTX message, free space can
* be ajusted. This operation could save some defrags. */ * be ajusted. This operation could save some defrags. */
struct htx_blk *lastblk = htx_get_blk(htx, htx->tail); struct htx_blk *lastblk = htx_get_blk(htx, htx->tail);
@ -474,7 +470,7 @@ struct htx_blk *htx_add_data_atonce(struct htx *htx, struct ist data)
void *ptr; void *ptr;
uint32_t len, sz, tailroom, headroom; uint32_t len, sz, tailroom, headroom;
if (!htx->used) if (htx->head == -1)
goto add_new_block; goto add_new_block;
/* Not enough space to store data */ /* Not enough space to store data */
@ -929,7 +925,7 @@ size_t htx_add_data(struct htx *htx, const struct ist data)
uint32_t sz, room; uint32_t sz, room;
int32_t len = data.len; int32_t len = data.len;
if (!htx->used) if (htx->head == -1)
goto add_new_block; goto add_new_block;
/* Not enough space to store data */ /* Not enough space to store data */

View File

@ -1543,7 +1543,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
* the HTX blocks. * the HTX blocks.
*/ */
if (!b_data(&h1c->obuf)) { if (!b_data(&h1c->obuf)) {
if (chn_htx->used == 1 && if (htx_nbblks(chn_htx) == 1 &&
htx_get_blk_type(blk) == HTX_BLK_DATA && htx_get_blk_type(blk) == HTX_BLK_DATA &&
htx_get_blk_value(chn_htx, blk).len == count) { htx_get_blk_value(chn_htx, blk).len == count) {
void *old_area = h1c->obuf.area; void *old_area = h1c->obuf.area;

View File

@ -4936,7 +4936,7 @@ static size_t h2s_htx_frt_make_resp_data(struct h2s *h2s, struct buffer *buf, si
* from the HTX blocks. * from the HTX blocks.
*/ */
if (unlikely(fsize == count && if (unlikely(fsize == count &&
htx->used == 1 && type == HTX_BLK_DATA && htx_nbblks(htx) == 1 && type == HTX_BLK_DATA &&
fsize <= h2s->mws && fsize <= h2c->mws && fsize <= h2c->mfs)) { fsize <= h2s->mws && fsize <= h2c->mws && fsize <= h2c->mfs)) {
void *old_area = mbuf->area; void *old_area = mbuf->area;

View File

@ -3344,7 +3344,7 @@ static int stats_dump_full_strm_to_buffer(struct stream_interface *si, struct st
chunk_appendf(&trash, chunk_appendf(&trash,
" htx=%p flags=0x%x size=%u data=%u used=%u wrap=%s extra=%llu\n", " htx=%p flags=0x%x size=%u data=%u used=%u wrap=%s extra=%llu\n",
htx, htx->flags, htx->size, htx->data, htx->used, htx, htx->flags, htx->size, htx->data, htx_nbblks(htx),
(htx->tail >= htx->head) ? "NO" : "YES", (htx->tail >= htx->head) ? "NO" : "YES",
(unsigned long long)htx->extra); (unsigned long long)htx->extra);
} }
@ -3383,7 +3383,7 @@ static int stats_dump_full_strm_to_buffer(struct stream_interface *si, struct st
chunk_appendf(&trash, chunk_appendf(&trash,
" htx=%p flags=0x%x size=%u data=%u used=%u wrap=%s extra=%llu\n", " htx=%p flags=0x%x size=%u data=%u used=%u wrap=%s extra=%llu\n",
htx, htx->flags, htx->size, htx->data, htx->used, htx, htx->flags, htx->size, htx->data, htx_nbblks(htx),
(htx->tail >= htx->head) ? "NO" : "YES", (htx->tail >= htx->head) ? "NO" : "YES",
(unsigned long long)htx->extra); (unsigned long long)htx->extra);
} }