Commit 4ed9e939 by Carlos Martín Nieto

tree: store the entries in a growable array

Take advantage of the constant size of tree-owned arrays and store them
in an array instead of a pool. This still lets us free them all at once
but lets the system allocator do the work of fitting them in.
parent 60a194aa
...@@ -85,30 +85,26 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2) ...@@ -85,30 +85,26 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2)
} }
/** /**
* Allocate either from the pool or from the system allocator * Allocate a new self-contained entry, with enough space after it to
* store the filename and the id.
*/ */
static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, size_t filename_len, const git_oid *id) static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, const git_oid *id)
{ {
git_tree_entry *entry = NULL; git_tree_entry *entry = NULL;
size_t tree_len; size_t tree_len;
TREE_ENTRY_CHECK_NAMELEN(filename_len); TREE_ENTRY_CHECK_NAMELEN(filename_len);
tree_len = sizeof(git_tree_entry);
if (!pool && (GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, filename_len) || if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) ||
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) || GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) ||
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_RAWSZ))) GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_RAWSZ))
return NULL; return NULL;
entry = pool ? git_pool_mallocz(pool, tree_len) : entry = git__calloc(1, tree_len);
git__calloc(1, tree_len);
if (!entry) if (!entry)
return NULL; return NULL;
if (pool) { {
entry->filename = filename;
entry->oid = (git_oid *) id;
} else {
char *filename_ptr; char *filename_ptr;
void *id_ptr; void *id_ptr;
...@@ -126,29 +122,6 @@ static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, si ...@@ -126,29 +122,6 @@ static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, si
return entry; return entry;
} }
/**
* Allocate a tree entry, using the poolin the tree which owns
* it. This is useful when reading trees, so we don't allocate a ton
* of small strings but can use the pool.
*/
static git_tree_entry *alloc_entry_pooled(git_pool *pool, const char *filename, size_t filename_len, const git_oid *id)
{
git_tree_entry *entry = NULL;
if (!(entry = alloc_entry_base(pool, filename, filename_len, id)))
return NULL;
entry->pooled = true;
return entry;
}
static git_tree_entry *alloc_entry(const char *filename)
{
git_oid dummy_id = { 0 };
return alloc_entry_base(NULL, filename, strlen(filename), &dummy_id);
}
struct tree_key_search { struct tree_key_search {
const char *filename; const char *filename;
uint16_t filename_len; uint16_t filename_len;
...@@ -250,7 +223,7 @@ static int tree_key_search( ...@@ -250,7 +223,7 @@ static int tree_key_search(
void git_tree_entry_free(git_tree_entry *entry) void git_tree_entry_free(git_tree_entry *entry)
{ {
if (entry == NULL || entry->pooled) if (entry == NULL)
return; return;
git__free(entry); git__free(entry);
...@@ -258,27 +231,27 @@ void git_tree_entry_free(git_tree_entry *entry) ...@@ -258,27 +231,27 @@ void git_tree_entry_free(git_tree_entry *entry)
int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source) int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source)
{ {
git_tree_entry *cpy;
assert(source); assert(source);
*dest = alloc_entry_base(NULL, source->filename, source->filename_len, source->oid); cpy = alloc_entry(source->filename, source->filename_len, source->oid);
if (*dest == NULL) if (cpy == NULL)
return -1; return -1;
cpy->attr = source->attr;
*dest = cpy;
return 0; return 0;
} }
void git_tree__free(void *_tree) void git_tree__free(void *_tree)
{ {
git_tree *tree = _tree; git_tree *tree = _tree;
size_t i;
git_tree_entry *e;
git_vector_foreach(&tree->entries, i, e)
git_tree_entry_free(e);
git_odb_object_free(tree->odb_obj); git_odb_object_free(tree->odb_obj);
git_vector_free(&tree->entries); git_vector_free(&tree->entries);
git_pool_clear(&tree->pool); git_array_clear(tree->entries_arr);
git__free(tree); git__free(tree);
} }
...@@ -450,6 +423,7 @@ static int parse_mode(unsigned int *modep, const char *buffer, const char **buff ...@@ -450,6 +423,7 @@ static int parse_mode(unsigned int *modep, const char *buffer, const char **buff
int git_tree__parse(void *_tree, git_odb_object *odb_obj) int git_tree__parse(void *_tree, git_odb_object *odb_obj)
{ {
size_t i;
git_tree *tree = _tree; git_tree *tree = _tree;
const char *buffer; const char *buffer;
const char *buffer_end; const char *buffer_end;
...@@ -460,9 +434,8 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj) ...@@ -460,9 +434,8 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
buffer = git_odb_object_data(tree->odb_obj); buffer = git_odb_object_data(tree->odb_obj);
buffer_end = buffer + git_odb_object_size(tree->odb_obj); buffer_end = buffer + git_odb_object_size(tree->odb_obj);
git_pool_init(&tree->pool, 1); git_array_init_to_size(tree->entries_arr, DEFAULT_TREE_SIZE);
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) GITERR_CHECK_ARRAY(tree->entries_arr);
return -1;
while (buffer < buffer_end) { while (buffer < buffer_end) {
git_tree_entry *entry; git_tree_entry *entry;
...@@ -479,21 +452,28 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj) ...@@ -479,21 +452,28 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
filename_len = nul - buffer; filename_len = nul - buffer;
/** Allocate the entry and store it in the entries vector */ /** Allocate the entry and store it in the entries vector */
{ {
/* Jump to the ID just after the path */ entry = git_array_alloc(tree->entries_arr);
const void *oid_ptr = buffer + filename_len + 1;
entry = alloc_entry_pooled(&tree->pool, buffer, filename_len, oid_ptr);
GITERR_CHECK_ALLOC(entry); GITERR_CHECK_ALLOC(entry);
if (git_vector_insert(&tree->entries, entry) < 0)
return -1;
entry->attr = attr; entry->attr = attr;
entry->filename_len = filename_len;
entry->filename = buffer;
entry->oid = (git_oid *) ((char *) buffer + filename_len + 1);
} }
buffer += filename_len + 1; buffer += filename_len + 1;
buffer += GIT_OID_RAWSZ; buffer += GIT_OID_RAWSZ;
} }
/* Add the entries to the vector here, as we may reallocate during the loop */
if (git_vector_init(&tree->entries, tree->entries_arr.size, entry_sort_cmp) < 0)
return -1;
for (i = 0; i < tree->entries_arr.size; i++) {
if (git_vector_insert(&tree->entries, git_array_get(tree->entries_arr, i)) < 0)
return -1;
}
/* The tree is sorted by definition. Bad inputs give bad outputs */ /* The tree is sorted by definition. Bad inputs give bad outputs */
tree->entries.flags |= GIT_VECTOR_SORTED; tree->entries.flags |= GIT_VECTOR_SORTED;
...@@ -529,10 +509,9 @@ static int append_entry( ...@@ -529,10 +509,9 @@ static int append_entry(
if (!valid_entry_name(bld->repo, filename)) if (!valid_entry_name(bld->repo, filename))
return tree_error("Failed to insert entry. Invalid name for a tree entry", filename); return tree_error("Failed to insert entry. Invalid name for a tree entry", filename);
entry = alloc_entry(filename); entry = alloc_entry(filename, strlen(filename), id);
GITERR_CHECK_ALLOC(entry); GITERR_CHECK_ALLOC(entry);
git_oid_cpy(entry->oid, id);
entry->attr = (uint16_t)filemode; entry->attr = (uint16_t)filemode;
git_strmap_insert(bld->map, entry->filename, entry, error); git_strmap_insert(bld->map, entry->filename, entry, error);
...@@ -776,8 +755,9 @@ int git_treebuilder_insert( ...@@ -776,8 +755,9 @@ int git_treebuilder_insert(
pos = git_strmap_lookup_index(bld->map, filename); pos = git_strmap_lookup_index(bld->map, filename);
if (git_strmap_valid_index(bld->map, pos)) { if (git_strmap_valid_index(bld->map, pos)) {
entry = git_strmap_value_at(bld->map, pos); entry = git_strmap_value_at(bld->map, pos);
git_oid_cpy((git_oid *) entry->oid, id);
} else { } else {
entry = alloc_entry(filename); entry = alloc_entry(filename, strlen(filename), id);
GITERR_CHECK_ALLOC(entry); GITERR_CHECK_ALLOC(entry);
git_strmap_insert(bld->map, entry->filename, entry, error); git_strmap_insert(bld->map, entry->filename, entry, error);
...@@ -789,7 +769,6 @@ int git_treebuilder_insert( ...@@ -789,7 +769,6 @@ int git_treebuilder_insert(
} }
} }
git_oid_cpy(entry->oid, id);
entry->attr = filemode; entry->attr = filemode;
if (entry_out) if (entry_out)
......
...@@ -17,16 +17,15 @@ ...@@ -17,16 +17,15 @@
struct git_tree_entry { struct git_tree_entry {
uint16_t attr; uint16_t attr;
uint16_t filename_len; uint16_t filename_len;
git_oid *oid; const git_oid *oid;
bool pooled;
const char *filename; const char *filename;
}; };
struct git_tree { struct git_tree {
git_object object; git_object object;
git_odb_object *odb_obj; git_odb_object *odb_obj;
git_array_t(git_tree_entry) entries_arr;
git_vector entries; git_vector entries;
git_pool pool;
}; };
struct git_treebuilder { struct git_treebuilder {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment