]> 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, 18 Sep 2026 15:05:18 +0000 (17:05 +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 1fe851cf7a5816a81fad4f08c254bd68f790f0e9..885b5115df30b17cbde03217c4ea3cd7f687120e 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 bac133a7c5eff3b2d1a90c5661ccb32ae5e9b31a..3e5681357ac219f4f324e483aec6dbf86b2e2561 100644 (file)
--- a/src/htx.c
+++ b/src/htx.c
@@ -372,6 +372,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;
 
@@ -386,6 +387,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);
@@ -398,26 +408,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
@@ -447,7 +455,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