]> git.kaiwu.me - haproxy.git/commitdiff
MEDIUM: htx: Skip UNUSED blocs when getting previous,next and first blocks
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 8 Jul 2026 08:38:12 +0000 (10:38 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 24 Jul 2026 09:58:25 +0000 (11:58 +0200)
htx_get_prev_blk(), htx_get_next_blk() and htx_get_first_blk() functions
were modified to automatically skip UNUSED blocks. So now, a valid block or
NULL is returned.  In addition, htx_remove_blk() was adapted accordingly to
also skip UNUSED blocks.

Thanks to this change, the loops on HTX messages could be simplified by
removing test on UNUSED blocks, while it remains harmless.

include/haproxy/htx.h
src/htx.c

index 4b7b9834fd52dec8e5e82e2954f2055d743aa8ec..b48d87df64e6b04ddcc0a28a74e9693e51141e02 100644 (file)
@@ -272,16 +272,22 @@ static inline int32_t htx_get_prev(const struct htx *htx, uint32_t pos)
        return (pos - 1);
 }
 
-/* Returns the HTX block before <blk> in the HTX message <htx>. If <blk> is the
- * head, NULL returned.
+/* Returns the HTX block before <blk> in the HTX message <htx>, skipping all
+ * UNUSED blocks. If <blk> is the head, NULL returned.
  */
 static inline struct htx_blk *htx_get_prev_blk(const struct htx *htx,
                                               const struct htx_blk *blk)
 {
-       int32_t pos;
+       struct htx_blk *pblk = NULL;
+       int32_t pos = htx_get_blk_pos(htx, blk);
 
-       pos = htx_get_prev(htx, htx_get_blk_pos(htx, blk));
-       return ((pos == -1) ? NULL : htx_get_blk(htx, pos));
+       for (pos = htx_get_prev(htx, pos); pos != -1; pos = htx_get_prev(htx, pos)) {
+               pblk = htx_get_blk(htx, pos);
+               if (htx_get_blk_type(pblk) != HTX_BLK_UNUSED)
+                       break;
+               pblk = NULL;
+       }
+       return pblk;
 }
 
 /* Returns the position of block immediately after the one pointed by <pos>. If
@@ -295,18 +301,25 @@ static inline int32_t htx_get_next(const struct htx *htx, uint32_t pos)
 
 }
 
-/* Returns the HTX block after <blk> in the HTX message <htx>. If <blk> is the
- * tail, NULL returned.
+/* Returns the HTX block after <blk> in the HTX message <htx>, skipping UNUSED
+ * blocks. If <blk> is the tail, NULL returned.
  */
 static inline struct htx_blk *htx_get_next_blk(const struct htx *htx,
                                               const struct htx_blk *blk)
 {
-       int32_t pos;
+       struct htx_blk *nblk = NULL;
+       int32_t pos = htx_get_blk_pos(htx, blk);
 
-       pos = htx_get_next(htx, htx_get_blk_pos(htx, blk));
-       return ((pos == -1) ? NULL : htx_get_blk(htx, pos));
+       for (pos = htx_get_next(htx, pos); pos != -1; pos = htx_get_next(htx, pos)) {
+               nblk = htx_get_blk(htx, pos);
+               if (htx_get_blk_type(nblk) != HTX_BLK_UNUSED)
+                       break;
+               nblk = NULL;
+       }
+       return nblk;
 }
 
+
 /* Returns the position of the first block in the HTX message <htx>. -1 means
  * the first block is unset or the HTS is empty.
  */
@@ -315,15 +328,21 @@ static inline int32_t htx_get_first(const struct htx *htx)
        return htx->first;
 }
 
-/* Returns the first HTX block in the HTX message <htx>. If unset or if <htx> is
- * empty, NULL returned.
+/* Returns the first HTX block in the HTX message <htx>, skipping UNUSED
+ * blocks. If unset or if <htx> is empty, NULL returned.
  */
 static inline struct htx_blk *htx_get_first_blk(const struct htx *htx)
 {
+       struct htx_blk *fblk = NULL;
        int32_t pos;
 
-       pos = htx_get_first(htx);
-       return ((pos == -1) ? NULL : htx_get_blk(htx, pos));
+       for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
+               fblk = htx_get_blk(htx, pos);
+               if (htx_get_blk_type(fblk) != HTX_BLK_UNUSED)
+                       break;
+               fblk = NULL;
+       }
+       return fblk;
 }
 
 /* Returns the type of the first block in the HTX message <htx>. If unset or if
index 3a05dc42fcac5944bb74df41add6cdbb2b774e5c..fff8289321c3a201c8bc353510f911f6d4672cc1 100644 (file)
--- a/src/htx.c
+++ b/src/htx.c
@@ -368,6 +368,7 @@ struct htx_blk *htx_add_blk(struct htx *htx, enum htx_blk_type type, uint32_t bl
  */
 struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk)
 {
+       struct htx_blk *prevblk, *nextblk;
        enum htx_blk_type type;
        uint32_t pos, addr, sz;
 
@@ -382,6 +383,15 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk)
                return NULL;
        }
 
+       /* Get prev and next blocks, skipping all UNUSED blocks.
+        *   <prevblk> may NULL if the head is removed otherwise it must exists
+        *   <nextblk> may NULL if the tail is removed otherwise it must exists
+        */
+       prevblk = htx_get_prev_blk(htx, blk);
+       nextblk = htx_get_next_blk(htx, blk);
+
+       /* There is at least 2 used blocks, so (head != tail and tail > 0) */
+
        type = htx_get_blk_type(blk);
        pos  = htx_get_blk_pos(htx, blk);
        sz   = htx_get_blksz(blk);
@@ -394,26 +404,24 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk)
                blk->info = ((uint32_t)HTX_BLK_UNUSED << 28);
        }
 
-       /* There is at least 2 blocks, so tail is always > 0 */
+
        if (pos == htx->head) {
                /* move the head forward */
-               htx->head++;
+               BUG_ON_HOT(prevblk != NULL || nextblk == NULL);
+               htx->head = htx_get_blk_pos(htx, nextblk);
        }
        else if (pos == htx->tail) {
-               /* remove the tail. this was the last inserted block so
-                * return NULL. */
-               htx->tail--;
-               blk = NULL;
+               /* remove the tail */
+               BUG_ON_HOT(prevblk == NULL || nextblk != NULL);
+               htx->tail = htx_get_blk_pos(htx, prevblk);
                goto end;
        }
        else
                htx->flags |= HTX_FL_FRAGMENTED;
 
-       blk = htx_get_blk(htx, pos+1);
-
   end:
        if (pos == htx->first)
-               htx->first = (blk ? htx_get_blk_pos(htx, blk) : -1);
+               htx->first = (nextblk ? htx_get_blk_pos(htx, nextblk) : -1);
 
        if (htx->head == htx->tail) {
                /* If there is just one block in the HTX message, free space can
@@ -443,7 +451,7 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk)
        BUG_ON((int32_t)htx->head_addr < 0);
        BUG_ON(htx->end_addr > htx->tail_addr);
        BUG_ON(htx->head_addr > htx->end_addr);
-       return blk;
+       return nextblk;
 }
 
 /* Looks for the HTX block containing the offset <offset>, starting at the HTX