From 5cad0759dc2a624af7a9465823628775dc390456 Mon Sep 17 00:00:00 2001 From: Georgiy Lebedev <g.lebedev@tarantool.org> Date: Tue, 18 Oct 2022 11:24:23 +0300 Subject: [PATCH] uri: optimize allocation of parameters and their values dynamic arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allocation of URI parameters and their values dynamic arrays is done inefficiently: they are reallocated each time a new parameter or parameter value is added — grow them exponentially instead. `struct uri_param` and `struct uri` are exposed in Lua via FFI (see src/lua/uri.lua): add warnings about the necessity of reflecting changes to them in `ffi.cdecl`. Closes #7155 NO_DOC=optimization NO_TEST=optimization --- ...-optimize-add-param-and-add-param-value.md | 3 ++ src/lib/uri/uri.c | 40 ++++++++++++++----- src/lib/uri/uri.h | 9 +++++ src/lua/uri.lua | 2 + 4 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 changelogs/unreleased/gh-7155-uri-optimize-add-param-and-add-param-value.md diff --git a/changelogs/unreleased/gh-7155-uri-optimize-add-param-and-add-param-value.md b/changelogs/unreleased/gh-7155-uri-optimize-add-param-and-add-param-value.md new file mode 100644 index 0000000000..e35a324d1b --- /dev/null +++ b/changelogs/unreleased/gh-7155-uri-optimize-add-param-and-add-param-value.md @@ -0,0 +1,3 @@ +## bugfix/uri + +* Optimized addition of parameters and parameter values (gh-7155). diff --git a/src/lib/uri/uri.c b/src/lib/uri/uri.c index edf9f8b707..eab70b34b8 100644 --- a/src/lib/uri/uri.c +++ b/src/lib/uri/uri.c @@ -10,9 +10,18 @@ #define XSTRDUP(s) (s != NULL ? xstrdup(s) : NULL) #define XSTRNDUP(s, n) (s != NULL ? xstrndup(s, n) : NULL) +/** + * WARNING: this structure is exposed in Lua via FFI (see src/lua/uri.lua): any + * change must be reflected in `ffi.cdef`. + */ struct uri_param { /** Name of URI parameter. */ char *name; + /** + * Capacity of URI parameter values dynamic array (used for exponential + * reallocation). + */ + int values_capacity; /** Count of values for this parameter. */ int value_count; /** Array of values for this parameter. */ @@ -38,8 +47,13 @@ uri_find_param(const struct uri *uri, const char *name) static void uri_param_add_value(struct uri_param *param, const char *value) { - size_t size = (param->value_count + 1) * sizeof(char *); - param->values = xrealloc(param->values, size); + assert(param->value_count <= param->values_capacity); + if (param->value_count == param->values_capacity) { + param->values_capacity = param->values_capacity == 0 ? 16 : + param->values_capacity * 2; + size_t size = param->values_capacity * sizeof(char *); + param->values = xrealloc(param->values, size); + } param->values[param->value_count++] = xstrdup(value); } @@ -65,6 +79,7 @@ uri_param_create(struct uri_param *param, const char *name) param->name = xstrdup(name); param->values = NULL; param->value_count = 0; + param->values_capacity = 0; } /** @@ -74,9 +89,10 @@ static void uri_param_copy(struct uri_param *dst, const struct uri_param *src) { dst->name = xstrdup(src->name); + dst->values_capacity = src->values_capacity; dst->value_count = src->value_count; - dst->values = (src->value_count == 0 ? NULL : - xmalloc(src->value_count * sizeof(*dst->values))); + dst->values = (src->values_capacity == 0 ? NULL : + xmalloc(src->values_capacity * sizeof(*dst->values))); for (int i = 0; i < src->value_count; i++) dst->values[i] = xstrdup(src->values[i]); } @@ -99,9 +115,14 @@ uri_add_param(struct uri *uri, const char *name, const char *value) { struct uri_param *param = uri_find_param(uri, name); if (param == NULL) { - size_t size = (uri->param_count + 1) * - sizeof(struct uri_param); - uri->params = xrealloc(uri->params, size); + assert(uri->param_count <= uri->params_capacity); + if (uri->param_count == uri->params_capacity) { + uri->params_capacity = uri->params_capacity == 0 ? 16 : + uri->params_capacity * 2; + size_t size = + uri->params_capacity * sizeof(struct uri_param); + uri->params = xrealloc(uri->params, size); + } param = &uri->params[uri->param_count++]; uri_param_create(param, name); } @@ -161,9 +182,10 @@ uri_copy(struct uri *dst, const struct uri *src) dst->query = XSTRDUP(src->query); dst->fragment = XSTRDUP(src->fragment); dst->host_hint = src->host_hint; + dst->params_capacity = src->params_capacity; dst->param_count = src->param_count; - dst->params = (src->param_count == 0 ? NULL : - xmalloc(src->param_count * sizeof(*dst->params))); + dst->params = (src->params_capacity == 0 ? NULL : + xmalloc(src->params_capacity * sizeof(*dst->params))); for (int i = 0; i < src->param_count; i++) uri_param_copy(&dst->params[i], &src->params[i]); } diff --git a/src/lib/uri/uri.h b/src/lib/uri/uri.h index bfbeb923b4..a0a97e90ef 100644 --- a/src/lib/uri/uri.h +++ b/src/lib/uri/uri.h @@ -15,6 +15,10 @@ extern "C" { struct uri_param; +/** + * WARNING: this structure is exposed in Lua via FFI (see src/lua/uri.lua): any + * change must be reflected in `ffi.cdef`. + */ struct uri { char *scheme; char *login; @@ -25,6 +29,11 @@ struct uri { char *query; char *fragment; int host_hint; + /** + * Capacity of URI parameters dynamic array (used for exponential + * reallocation). + */ + int params_capacity; /** Count of URI parameters */ int param_count; /** Different URI parameters */ diff --git a/src/lua/uri.lua b/src/lua/uri.lua index a263064286..ed1b272a7b 100644 --- a/src/lua/uri.lua +++ b/src/lua/uri.lua @@ -7,6 +7,7 @@ local uri = require('uri') local uri_cdef = [[ struct uri_param { const char *name; + int values_capacity; int value_count; const char **values; }; @@ -28,6 +29,7 @@ struct uri { const char *query; const char *fragment; int host_hint; + int params_capacity; int param_count; struct uri_param *params; }; -- GitLab