mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-02 15:45:25 +00:00
Add a static pre-allocated buffer to isc_buffer_t
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.
This commit is contained in:
@@ -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) {
|
||||
isc_buffer_reserve(isc_buffer_t *dbuf, unsigned int size) {
|
||||
REQUIRE(ISC_BUFFER_VALID(dbuf));
|
||||
|
||||
size_t len;
|
||||
uint8_t *bdata = (uint8_t *)dbuf + sizeof(*dbuf);
|
||||
|
||||
REQUIRE(ISC_BUFFER_VALID(dynbuffer));
|
||||
|
||||
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
|
||||
|
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user