From: Amaury Denoyelle Date: Wed, 4 May 2022 14:47:09 +0000 (+0200) Subject: MINOR: ncbuf: implement advance X-Git-Tag: v2.6-dev10~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=df25acf47fc0858656b285a42f5e2f37145dab2f;p=thirdparty%2Fhaproxy.git MINOR: ncbuf: implement advance A new function ncb_advance() is implemented. This is used to advance the buffer head pointer. This will consume the front data while forming a new gap at the end for future data. On success NCB_RET_OK is returned. The operation can be rejected if a too small new gap is formed in front of the buffer. --- diff --git a/include/haproxy/ncbuf.h b/include/haproxy/ncbuf.h index a13dd508de..68bdb95497 100644 --- a/include/haproxy/ncbuf.h +++ b/include/haproxy/ncbuf.h @@ -20,5 +20,6 @@ ncb_sz_t ncb_data(const struct ncbuf *buf, ncb_sz_t offset); enum ncb_ret ncb_add(struct ncbuf *buf, ncb_sz_t off, const char *data, ncb_sz_t len, enum ncb_add_mode mode); +enum ncb_ret ncb_advance(struct ncbuf *buf, ncb_sz_t off); #endif /* _HAPROXY_NCBUF_H */ diff --git a/src/ncbuf.c b/src/ncbuf.c index db0864984c..cec18bb73a 100644 --- a/src/ncbuf.c +++ b/src/ncbuf.c @@ -554,3 +554,104 @@ enum ncb_ret ncb_add(struct ncbuf *buf, ncb_sz_t off, return NCB_RET_OK; } + +/* Advance the head of to the offset . Data at the start of buffer + * will be lost while some space will be formed at the end to be able to insert + * new data. + * + * Returns NCB_RET_OK on success. + */ +enum ncb_ret ncb_advance(struct ncbuf *buf, ncb_sz_t off) +{ + struct ncb_blk blk, last; + ncb_sz_t off_blk; + ncb_sz_t first_data_sz; + + BUG_ON_HOT(off > ncb_size(buf)); + if (!off) + return NCB_RET_OK; + + /* Special case if off is full size. This is equivalent to a reset. */ + if (off == ncb_size(buf)) { + ncb_init(buf, buf->head); + return NCB_RET_OK; + } + + last = blk = ncb_blk_find(buf, off); + while (!ncb_blk_is_last(buf, last)) + last = ncb_blk_next(buf, last); + + off_blk = ncb_blk_off(blk, off); + + /* If new head points in a GAP, the GAP size must be big enough. */ + if (blk.flag & NCB_BK_F_GAP) { + if (blk.sz == off_blk) { + /* GAP si completely removed. */ + first_data_sz = blk.sz_data; + } + else if (!ncb_blk_is_last(buf, blk) && + blk.sz - off_blk < NCB_GAP_MIN_SZ) { + return NCB_RET_GAP_SIZE; + } + else { + /* A GAP will be present at the front. */ + first_data_sz = 0; + } + } + else { + /* If off_blk less than blk.sz, the data block will becomes the + * first block. If equal, the data block is completely removed + * and thus the following GAP will be the first block. + */ + first_data_sz = blk.sz - off_blk; + } + + /* Insert a new GAP if : + * - last block is DATA + * - last block is GAP and but is not the same as blk + * + * In the the of last block is a GAP and is the same as blk, it means + * that a GAP will be formed to recover the whole buffer content. + */ + if (last.flag & NCB_BK_F_GAP && !ncb_blk_is_last(buf, blk)) { + /* last block is a GAP : extends it unless this is a reduced + * gap and the new gap size is still not big enough. + */ + if (!(last.flag & NCB_BK_F_FIN) || last.sz + off >= NCB_GAP_MIN_SZ) { + /* use .st instead of .sz_ptr which can be NULL if reduced gap */ + ncb_write_off(buf, last.st, last.sz + off); + ncb_write_off(buf, ncb_peek(buf, last.off + NCB_GAP_SZ_DATA_OFF), 0); + } + } + else if (!(last.flag & NCB_BK_F_GAP)) { + /* last block DATA : insert a new gap after the deleted data. + * If the gap is not big enough, it will be a reduced gap. + */ + if (off >= NCB_GAP_MIN_SZ) { + ncb_write_off(buf, ncb_peek(buf, last.off + last.sz + NCB_GAP_SZ_OFF), off); + ncb_write_off(buf, ncb_peek(buf, last.off + last.sz + NCB_GAP_SZ_DATA_OFF), 0); + } + } + + /* Advance head and update the buffer reserved header which contains + * the first data block size. + */ + buf->head += off; + if (buf->head >= buf->size) + buf->head -= buf->size; + ncb_write_off(buf, ncb_reserved(buf), first_data_sz); + + /* Update the first block GAP size if needed. */ + if (blk.flag & NCB_BK_F_GAP && !first_data_sz) { + /* If first block GAP is also last one, cover whole buf. */ + if (ncb_blk_is_last(buf, blk)) + ncb_write_off(buf, ncb_head(buf), ncb_size(buf)); + else + ncb_write_off(buf, ncb_head(buf), blk.sz - off_blk); + + /* Recopy the block sz_data at the new position. */ + ncb_write_off(buf, ncb_peek(buf, NCB_GAP_SZ_DATA_OFF), blk.sz_data); + } + + return NCB_RET_OK; +}