]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add a static pre-allocated buffer to isc_buffer_t
authorOndřej Surý <ondrej@isc.org>
Thu, 15 Dec 2022 21:51:52 +0000 (22:51 +0100)
committerOndřej Surý <ondrej@isc.org>
Tue, 20 Dec 2022 18:13:48 +0000 (19:13 +0100)
When the buffer is allocated via isc_buffer_allocate() and the size is
smaller or equal ISC_BUFFER_STATIC_SIZE (currently 512 bytes), the
buffer will be allocated as a flexible array member in the buffer
structure itself instead of allocating it on the heap.  This should help
when the buffer is used on the hot-path with small allocations.

lib/isc/buffer.c
lib/isc/include/isc/buffer.h
tests/isc/buffer_test.c

index 8d9873adad673b426aa5c51d04b3d6c2a1ec5fd5..9e2c3bf33920657a1d0dbb8a600c269b085edced 100644 (file)
@@ -120,72 +120,80 @@ isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
 }
 
 void
-isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
+isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dbufp,
                    unsigned int length) {
-       REQUIRE(dynbuffer != NULL && *dynbuffer == NULL);
+       REQUIRE(dbufp != NULL && *dbufp == NULL);
 
-       isc_buffer_t *dbuf = isc_mem_get(mctx, sizeof(isc_buffer_t));
-       unsigned char *bdata = isc_mem_get(mctx, length);
+       isc_buffer_t *dbuf = isc_mem_get(mctx, sizeof(*dbuf) + length);
+       uint8_t *bdata = (uint8_t *)dbuf + sizeof(*dbuf);
 
        isc_buffer_init(dbuf, bdata, length);
-
+       dbuf->extra = length;
        dbuf->mctx = mctx;
 
-       *dynbuffer = dbuf;
+       *dbufp = dbuf;
 }
 
 isc_result_t
-isc_buffer_reserve(isc_buffer_t *dynbuffer, unsigned int size) {
-       size_t len;
+isc_buffer_reserve(isc_buffer_t *dbuf, unsigned int size) {
+       REQUIRE(ISC_BUFFER_VALID(dbuf));
 
-       REQUIRE(ISC_BUFFER_VALID(dynbuffer));
+       size_t len;
+       uint8_t *bdata = (uint8_t *)dbuf + sizeof(*dbuf);
 
-       len = dynbuffer->length;
-       if ((len - dynbuffer->used) >= size) {
+       len = dbuf->length;
+       if ((len - dbuf->used) >= size) {
                return (ISC_R_SUCCESS);
        }
 
-       if (dynbuffer->mctx == NULL) {
+       if (dbuf->mctx == NULL) {
                return (ISC_R_NOSPACE);
        }
 
        /* Round to nearest buffer size increment */
-       len = size + dynbuffer->used;
-       len = (len + ISC_BUFFER_INCR - 1 - ((len - 1) % ISC_BUFFER_INCR));
+       len = size + dbuf->used;
+       len = ISC_ALIGN(len, ISC_BUFFER_INCR);
 
        /* Cap at UINT_MAX */
        if (len > UINT_MAX) {
                len = UINT_MAX;
        }
 
-       if ((len - dynbuffer->used) < size) {
+       if ((len - dbuf->used) < size) {
                return (ISC_R_NOMEMORY);
        }
 
-       dynbuffer->base = isc_mem_reget(dynbuffer->mctx, dynbuffer->base,
-                                       dynbuffer->length, len);
-       dynbuffer->length = (unsigned int)len;
+       if (dbuf->base == bdata) {
+               dbuf->base = isc_mem_get(dbuf->mctx, len);
+               memmove(dbuf->base, bdata, dbuf->used);
+       } else {
+               dbuf->base = isc_mem_reget(dbuf->mctx, dbuf->base, dbuf->length,
+                                          len);
+       }
+       dbuf->length = (unsigned int)len;
 
        return (ISC_R_SUCCESS);
 }
 
 void
-isc_buffer_free(isc_buffer_t **dynbuffer) {
-       isc_buffer_t *dbuf;
-       isc_mem_t *mctx;
+isc_buffer_free(isc_buffer_t **dbufp) {
+       REQUIRE(dbufp != NULL && ISC_BUFFER_VALID(*dbufp));
+       REQUIRE((*dbufp)->mctx != NULL);
 
-       REQUIRE(dynbuffer != NULL);
-       REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
-       REQUIRE((*dynbuffer)->mctx != NULL);
+       isc_buffer_t *dbuf = *dbufp;
+       isc_mem_t *mctx = dbuf->mctx;
+       uint8_t *bdata = (uint8_t *)dbuf + sizeof(*dbuf);
+       unsigned int extra = dbuf->extra;
 
-       dbuf = *dynbuffer;
-       *dynbuffer = NULL; /* destroy external reference */
-       mctx = dbuf->mctx;
+       *dbufp = NULL; /* destroy external reference */
        dbuf->mctx = NULL;
 
-       isc_mem_put(mctx, dbuf->base, dbuf->length);
+       if (dbuf->base != bdata) {
+               isc_mem_put(mctx, dbuf->base, dbuf->length);
+       }
+
        isc_buffer_invalidate(dbuf);
-       isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
+       isc_mem_put(mctx, dbuf, sizeof(*dbuf) + extra);
 }
 
 isc_result_t
index 6ce0ba45ce5e706122553e5991d2601879f4ae66..0929e6a750179aa04fb119f61d38246fb04355bb 100644 (file)
@@ -128,7 +128,7 @@ ISC_LANG_BEGINDECLS
  * space in a buffer, we round the allocated buffer length up to the
  * nearest * multiple of this value.
  */
-#define ISC_BUFFER_INCR 2048
+#define ISC_BUFFER_INCR 512
 
 /*
  * The following macros MUST be used only on valid buffers.  It is the
@@ -177,6 +177,8 @@ struct isc_buffer {
        unsigned int used;
        unsigned int current;
        unsigned int active;
+       /*! The extra bytes allocated for dynamic buffer */
+       unsigned int extra;
        /*@}*/
        /*! linkable */
        ISC_LINK(isc_buffer_t) link;
@@ -184,6 +186,8 @@ struct isc_buffer {
        isc_mem_t *mctx;
 };
 
+#define ISC_BUFFER_STATIC_SIZE 512
+
 /***
  *** Functions
  ***/
@@ -509,10 +513,12 @@ static inline void
 isc_buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
        ISC_REQUIRE(b != NULL);
 
-       *b = (isc_buffer_t){ .base = base,
-                            .length = length,
-                            .magic = ISC_BUFFER_MAGIC };
-       ISC_LINK_INIT(b, link);
+       *b = (isc_buffer_t){
+               .base = base,
+               .length = length,
+               .link = ISC_LINK_INITIALIZER,
+               .magic = ISC_BUFFER_MAGIC,
+       };
 }
 
 /*!
@@ -521,8 +527,10 @@ isc_buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
  */
 static inline void
 isc_buffer_initnull(isc_buffer_t *b) {
-       *b = (isc_buffer_t){ .magic = ISC_BUFFER_MAGIC };
-       ISC_LINK_INIT(b, link);
+       *b = (isc_buffer_t){
+               .link = ISC_LINK_INITIALIZER,
+               .magic = ISC_BUFFER_MAGIC,
+       };
 }
 
 /*!
@@ -560,12 +568,9 @@ isc_buffer_invalidate(isc_buffer_t *b) {
        ISC_REQUIRE(!ISC_LINK_LINKED(b, link));
        ISC_REQUIRE(b->mctx == NULL);
 
-       b->magic = 0;
-       b->base = NULL;
-       b->length = 0;
-       b->used = 0;
-       b->current = 0;
-       b->active = 0;
+       *b = (isc_buffer_t){
+               .magic = 0,
+       };
 }
 
 /*!
index 94ed6f8017691eca8db17106093cddd5ae3e7dcb..09e1038e467a09663fc704a80f9884b58bbc00e4 100644 (file)
@@ -42,48 +42,44 @@ ISC_RUN_TEST_IMPL(isc_buffer_reserve) {
        UNUSED(state);
 
        b = NULL;
-       isc_buffer_allocate(mctx, &b, 1024);
-       assert_int_equal(b->length, 1024);
+       isc_buffer_allocate(mctx, &b, ISC_BUFFER_INCR);
+       assert_int_equal(b->length, ISC_BUFFER_INCR);
 
        /*
-        * 1024 bytes should already be available, so this call does
+        * 512 bytes should already be available, so this call does
         * nothing.
         */
-       result = isc_buffer_reserve(b, 1024);
+       result = isc_buffer_reserve(b, 512);
        assert_int_equal(result, ISC_R_SUCCESS);
-       assert_true(ISC_BUFFER_VALID(b));
        assert_non_null(b);
-       assert_int_equal(b->length, 1024);
+       assert_int_equal(b->length, ISC_BUFFER_INCR);
 
        /*
-        * This call should grow it to 2048 bytes as only 1024 bytes are
+        * This call should grow it to 1536 bytes as only 1024 bytes are
         * available in the buffer.
         */
        result = isc_buffer_reserve(b, 1025);
        assert_int_equal(result, ISC_R_SUCCESS);
-       assert_true(ISC_BUFFER_VALID(b));
        assert_non_null(b);
-       assert_int_equal(b->length, 2048);
+       assert_int_equal(b->length, 3 * ISC_BUFFER_INCR);
 
        /*
-        * 2048 bytes should already be available, so this call does
+        * 1536 bytes should already be available, so this call does
         * nothing.
         */
-       result = isc_buffer_reserve(b, 2000);
+       result = isc_buffer_reserve(b, 1500);
        assert_int_equal(result, ISC_R_SUCCESS);
-       assert_true(ISC_BUFFER_VALID(b));
        assert_non_null(b);
-       assert_int_equal(b->length, 2048);
+       assert_int_equal(b->length, 3 * ISC_BUFFER_INCR);
 
        /*
-        * This call should grow it to 4096 bytes as only 2048 bytes are
+        * This call should grow it to 4096 bytes as only 1536 bytes are
         * available in the buffer.
         */
-       result = isc_buffer_reserve(b, 3000);
+       result = isc_buffer_reserve(b, 3585);
        assert_int_equal(result, ISC_R_SUCCESS);
-       assert_true(ISC_BUFFER_VALID(b));
        assert_non_null(b);
-       assert_int_equal(b->length, 4096);
+       assert_int_equal(b->length, 8 * ISC_BUFFER_INCR);
 
        /* Consume some of the buffer so we can run the next test. */
        isc_buffer_add(b, 4096);
@@ -93,9 +89,8 @@ ISC_RUN_TEST_IMPL(isc_buffer_reserve) {
         */
        result = isc_buffer_reserve(b, UINT_MAX);
        assert_int_equal(result, ISC_R_NOMEMORY);
-       assert_true(ISC_BUFFER_VALID(b));
        assert_non_null(b);
-       assert_int_equal(b->length, 4096);
+       assert_int_equal(b->length, 8 * ISC_BUFFER_INCR);
 
        isc_buffer_free(&b);
 }