[Tarantool-patches] [PATCH v4 4/6] sql: use parser's region of "index" array
Roman Khabibov
roman.habibov at tarantool.org
Tue Sep 29 02:29:26 MSK 2020
Hi! Thanks for the review.
> On Sep 16, 2020, at 16:30, Nikita Pettik <korablev at tarantool.org> wrote:
>
> On 12 Sep 00:51, Roman Khabibov wrote:
>> Allocate memory for the "index" array of ephemeral space on the
>> parser's region instead of a heap as it was before. Fixed a memory
>> leak that realloc() generated.
>>
>> Needed for #3075
>
> Why it is related to 3075??
Fixed to -> 2349. Due to this patch, I avoid malloc inside sql_space_shallow_copy.
>> ---
>> src/box/sql/build.c | 42 +++++++++++++++++++++++++++++++-----------
>> 1 file changed, 31 insertions(+), 11 deletions(-)
>>
>> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
>> index 6cc76bb77..d1d240315 100644
>> --- a/src/box/sql/build.c
>> +++ b/src/box/sql/build.c
>> @@ -2226,29 +2226,49 @@ vdbe_emit_new_sec_index_id(struct Parse *parse, uint32_t space_id,
>> }
>>
>> /**
>> - * Add new index to table's indexes list.
>> + * Add new index to ephemeral @a space's "index" array. Reallocate
>> + * memory on @a region if needed.
>> + *
>> * We follow convention that PK comes first in list.
>> *
>> + * @param region Region (on parser).
>> * @param space Space to which belongs given index.
>> * @param index Index to be added to list.
>> */
>> static void
>> -table_add_index(struct space *space, struct index *index)
>> +sql_space_add_index(struct region *region, struct space *space,
>> + struct index *index)
>> {
>> uint32_t idx_count = space->index_count;
>> - size_t indexes_sz = sizeof(struct index *) * (idx_count + 1);
>> - struct index **idx = (struct index **) realloc(space->index,
>> - indexes_sz);
>> - if (idx == NULL) {
>> - diag_set(OutOfMemory, indexes_sz, "realloc", "idx");
>> - return;
>> - }
>> - space->index = idx;
>> + size_t size = 0;
>> + struct index **idx = NULL;
>> + if (idx_count == 0) {
>> + idx = region_alloc_array(region, typeof(struct index *), 1,
>> + &size);
>> + if (idx == NULL)
>> + goto alloc_error;
>> + /*
>> + * Reallocate each time the idx_count becomes equal to the
>> + * power of two.
>> + */
>> + } else if ((idx_count & (idx_count - 1)) == 0) {
>> + idx = region_alloc_array(region, typeof(struct index *),
>> + idx_count * 2, &size);
>> + if (idx == NULL)
>> + goto alloc_error;
>> + memcpy(idx, space->index, idx_count * sizeof(struct index *));
>> + }
>> + if (idx != NULL)
>> + space->index = idx;
>
> DOes it make any sense? Why not simply call ::free (in case there really
> was memleak)?
It was a memleak, really. I checked it by valgrind.
This is the main reason. So that when destroying the parser, you don't have
to check whether it was CREATE or ALTER, whether malloc or realloc was called
inside build.c, and don't call free. The parser region is well suited for
this task.
>> /* Make sure that PK always comes as first member. */
>> if (index->def->iid == 0 && idx_count != 0)
>> SWAP(space->index[0], index);
>> space->index[space->index_count++] = index;
>> space->index_id_max = MAX(space->index_id_max, index->def->iid);;
>> + return;
>> +
>> +alloc_error:
>> + diag_set(OutOfMemory, size, "region_alloc_array", "idx");
>> }
>>
>> int
>> @@ -2717,7 +2737,7 @@ sql_create_index(struct Parse *parse) {
>>
>> if (tbl_name != NULL)
>> goto exit_create_index;
>> - table_add_index(space, index);
>> + sql_space_add_index(&parse->region, space, index);
>> index = NULL;
>>
>> /* Clean up before exiting. */
>> --
>> 2.24.3 (Apple Git-128)
>>
commit 177c4389af647677afcce9fa58b12f00e398fbe9
Author: Roman Khabibov <roman.habibov at tarantool.org>
Date: Thu Sep 3 14:26:47 2020 +0300
sql: use parser's region of "index" array
Allocate memory for the "index" array of ephemeral space on the
parser's region instead of a heap as it was before. Fixed a memory
leak that realloc() generated.
Needed for #2349
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 6cc76bb77..d1d240315 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -2226,29 +2226,49 @@ vdbe_emit_new_sec_index_id(struct Parse *parse, uint32_t space_id,
}
/**
- * Add new index to table's indexes list.
+ * Add new index to ephemeral @a space's "index" array. Reallocate
+ * memory on @a region if needed.
+ *
* We follow convention that PK comes first in list.
*
+ * @param region Region (on parser).
* @param space Space to which belongs given index.
* @param index Index to be added to list.
*/
static void
-table_add_index(struct space *space, struct index *index)
+sql_space_add_index(struct region *region, struct space *space,
+ struct index *index)
{
uint32_t idx_count = space->index_count;
- size_t indexes_sz = sizeof(struct index *) * (idx_count + 1);
- struct index **idx = (struct index **) realloc(space->index,
- indexes_sz);
- if (idx == NULL) {
- diag_set(OutOfMemory, indexes_sz, "realloc", "idx");
- return;
- }
- space->index = idx;
+ size_t size = 0;
+ struct index **idx = NULL;
+ if (idx_count == 0) {
+ idx = region_alloc_array(region, typeof(struct index *), 1,
+ &size);
+ if (idx == NULL)
+ goto alloc_error;
+ /*
+ * Reallocate each time the idx_count becomes equal to the
+ * power of two.
+ */
+ } else if ((idx_count & (idx_count - 1)) == 0) {
+ idx = region_alloc_array(region, typeof(struct index *),
+ idx_count * 2, &size);
+ if (idx == NULL)
+ goto alloc_error;
+ memcpy(idx, space->index, idx_count * sizeof(struct index *));
+ }
+ if (idx != NULL)
+ space->index = idx;
/* Make sure that PK always comes as first member. */
if (index->def->iid == 0 && idx_count != 0)
SWAP(space->index[0], index);
space->index[space->index_count++] = index;
space->index_id_max = MAX(space->index_id_max, index->def->iid);;
+ return;
+
+alloc_error:
+ diag_set(OutOfMemory, size, "region_alloc_array", "idx");
}
int
@@ -2717,7 +2737,7 @@ sql_create_index(struct Parse *parse) {
if (tbl_name != NULL)
goto exit_create_index;
- table_add_index(space, index);
+ sql_space_add_index(&parse->region, space, index);
index = NULL;
/* Clean up before exiting. */
More information about the Tarantool-patches
mailing list