Commit 5e37874d by Carlos Martín Nieto

Merge remote-tracking branch 'upstream/cmn/treebuilder-perf'

parents 130cb548 fcc60066
...@@ -301,8 +301,10 @@ GIT_EXTERN(const git_tree_entry *) git_treebuilder_get( ...@@ -301,8 +301,10 @@ GIT_EXTERN(const git_tree_entry *) git_treebuilder_get(
* If an entry named `filename` already exists, its attributes * If an entry named `filename` already exists, its attributes
* will be updated with the given ones. * will be updated with the given ones.
* *
* The optional pointer `out` can be used to retrieve a pointer to * The optional pointer `out` can be used to retrieve a pointer to the
* the newly created/updated entry. Pass NULL if you do not need it. * newly created/updated entry. Pass NULL if you do not need it. The
* pointer may not be valid past the next operation in this
* builder. Duplicate the entry if you want to keep it.
* *
* No attempt is being made to ensure that the provided oid points * No attempt is being made to ensure that the provided oid points
* to an existing git object in the object database, nor that the * to an existing git object in the object database, nor that the
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#define DEFAULT_TREE_SIZE 16 #define DEFAULT_TREE_SIZE 16
#define MAX_FILEMODE_BYTES 6 #define MAX_FILEMODE_BYTES 6
GIT__USE_STRMAP;
static bool valid_filemode(const int filemode) static bool valid_filemode(const int filemode)
{ {
return (filemode == GIT_FILEMODE_TREE return (filemode == GIT_FILEMODE_TREE
...@@ -365,7 +367,8 @@ size_t git_tree_entrycount(const git_tree *tree) ...@@ -365,7 +367,8 @@ size_t git_tree_entrycount(const git_tree *tree)
unsigned int git_treebuilder_entrycount(git_treebuilder *bld) unsigned int git_treebuilder_entrycount(git_treebuilder *bld)
{ {
assert(bld); assert(bld);
return (unsigned int)bld->entrycount;
return git_strmap_num_entries(bld->map);
} }
static int tree_error(const char *str, const char *path) static int tree_error(const char *str, const char *path)
...@@ -450,6 +453,7 @@ static int append_entry( ...@@ -450,6 +453,7 @@ static int append_entry(
git_filemode_t filemode) git_filemode_t filemode)
{ {
git_tree_entry *entry; git_tree_entry *entry;
int error = 0;
if (!valid_entry_name(filename)) if (!valid_entry_name(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);
...@@ -460,12 +464,12 @@ static int append_entry( ...@@ -460,12 +464,12 @@ static int append_entry(
git_oid_cpy(&entry->oid, id); git_oid_cpy(&entry->oid, id);
entry->attr = (uint16_t)filemode; entry->attr = (uint16_t)filemode;
if (git_vector_insert_sorted(&bld->entries, entry, NULL) < 0) { git_strmap_insert(bld->map, entry->filename, entry, error);
git__free(entry); if (error < 0) {
giterr_set(GITERR_TREE, "failed to append entry %s to the tree builder", filename);
return -1; return -1;
} }
bld->entrycount++;
return 0; return 0;
} }
...@@ -610,18 +614,16 @@ int git_tree__write_index( ...@@ -610,18 +614,16 @@ int git_tree__write_index(
int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source) int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source)
{ {
git_treebuilder *bld; git_treebuilder *bld;
size_t i, source_entries = DEFAULT_TREE_SIZE; size_t i;
assert(builder_p); assert(builder_p);
bld = git__calloc(1, sizeof(git_treebuilder)); bld = git__calloc(1, sizeof(git_treebuilder));
GITERR_CHECK_ALLOC(bld); GITERR_CHECK_ALLOC(bld);
if (source != NULL) if (git_strmap_alloc(&bld->map) < 0) {
source_entries = source->entries.length; return -1;
}
if (git_vector_init(&bld->entries, source_entries, entry_sort_cmp) < 0)
goto on_error;
if (source != NULL) { if (source != NULL) {
git_tree_entry *entry_src; git_tree_entry *entry_src;
...@@ -651,7 +653,8 @@ int git_treebuilder_insert( ...@@ -651,7 +653,8 @@ int git_treebuilder_insert(
git_filemode_t filemode) git_filemode_t filemode)
{ {
git_tree_entry *entry; git_tree_entry *entry;
size_t pos; int error;
git_strmap_iter pos;
assert(bld && id && filename); assert(bld && id && filename);
...@@ -661,22 +664,20 @@ int git_treebuilder_insert( ...@@ -661,22 +664,20 @@ int git_treebuilder_insert(
if (!valid_entry_name(filename)) if (!valid_entry_name(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);
if (!tree_key_search(&pos, &bld->entries, filename, strlen(filename))) { pos = git_strmap_lookup_index(bld->map, filename);
entry = git_vector_get(&bld->entries, pos); if (git_strmap_valid_index(bld->map, pos)) {
if (entry->removed) { entry = git_strmap_value_at(bld->map, pos);
entry->removed = 0;
bld->entrycount++;
}
} else { } else {
entry = alloc_entry(filename); entry = alloc_entry(filename);
GITERR_CHECK_ALLOC(entry); GITERR_CHECK_ALLOC(entry);
if (git_vector_insert_sorted(&bld->entries, entry, NULL) < 0) { git_strmap_insert(bld->map, entry->filename, entry, error);
git__free(entry);
if (error < 0) {
git_tree_entry_free(entry);
giterr_set(GITERR_TREE, "failed to insert %s", filename);
return -1; return -1;
} }
bld->entrycount++;
} }
git_oid_cpy(&entry->oid, id); git_oid_cpy(&entry->oid, id);
...@@ -690,17 +691,14 @@ int git_treebuilder_insert( ...@@ -690,17 +691,14 @@ int git_treebuilder_insert(
static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename) static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename)
{ {
size_t idx; git_tree_entry *entry = NULL;
git_tree_entry *entry; git_strmap_iter pos;
assert(bld && filename); assert(bld && filename);
if (tree_key_search(&idx, &bld->entries, filename, strlen(filename)) < 0) pos = git_strmap_lookup_index(bld->map, filename);
return NULL; if (git_strmap_valid_index(bld->map, pos))
entry = git_strmap_value_at(bld->map, pos);
entry = git_vector_get(&bld->entries, idx);
if (entry->removed)
return NULL;
return entry; return entry;
} }
...@@ -712,35 +710,44 @@ const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *file ...@@ -712,35 +710,44 @@ const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *file
int git_treebuilder_remove(git_treebuilder *bld, const char *filename) int git_treebuilder_remove(git_treebuilder *bld, const char *filename)
{ {
git_tree_entry *remove_ptr = treebuilder_get(bld, filename); git_tree_entry *entry = treebuilder_get(bld, filename);
if (remove_ptr == NULL || remove_ptr->removed) if (entry == NULL)
return tree_error("Failed to remove entry. File isn't in the tree", filename); return tree_error("Failed to remove entry. File isn't in the tree", filename);
remove_ptr->removed = 1; git_strmap_delete(bld->map, filename);
bld->entrycount--; git_tree_entry_free(entry);
return 0; return 0;
} }
int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld) int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld)
{ {
int error = 0; int error = 0;
size_t i; size_t i, entrycount;
git_buf tree = GIT_BUF_INIT; git_buf tree = GIT_BUF_INIT;
git_odb *odb; git_odb *odb;
git_tree_entry *entry;
git_vector entries;
assert(bld); assert(bld);
git_vector_sort(&bld->entries); entrycount = git_strmap_num_entries(bld->map);
if (git_vector_init(&entries, entrycount, entry_sort_cmp) < 0)
return -1;
/* Grow the buffer beforehand to an estimated size */ git_strmap_foreach_value(bld->map, entry, {
error = git_buf_grow(&tree, bld->entries.length * 72); if (git_vector_insert(&entries, entry) < 0)
return -1;
});
for (i = 0; i < bld->entries.length && !error; ++i) { git_vector_sort(&entries);
git_tree_entry *entry = git_vector_get(&bld->entries, i);
/* Grow the buffer beforehand to an estimated size */
error = git_buf_grow(&tree, entrycount * 72);
if (entry->removed) for (i = 0; i < entries.length && !error; ++i) {
continue; git_tree_entry *entry = git_vector_get(&entries, i);
git_buf_printf(&tree, "%o ", entry->attr); git_buf_printf(&tree, "%o ", entry->attr);
git_buf_put(&tree, entry->filename, entry->filename_len + 1); git_buf_put(&tree, entry->filename, entry->filename_len + 1);
...@@ -750,6 +757,8 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b ...@@ -750,6 +757,8 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b
error = -1; error = -1;
} }
git_vector_free(&entries);
if (!error && if (!error &&
!(error = git_repository_odb__weakptr(&odb, repo))) !(error = git_repository_odb__weakptr(&odb, repo)))
error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE); error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE);
...@@ -763,31 +772,27 @@ void git_treebuilder_filter( ...@@ -763,31 +772,27 @@ void git_treebuilder_filter(
git_treebuilder_filter_cb filter, git_treebuilder_filter_cb filter,
void *payload) void *payload)
{ {
size_t i; const char *filename;
git_tree_entry *entry; git_tree_entry *entry;
assert(bld && filter); assert(bld && filter);
git_vector_foreach(&bld->entries, i, entry) { git_strmap_foreach(bld->map, filename, entry, {
if (!entry->removed && filter(entry, payload)) { if (filter(entry, payload)) {
entry->removed = 1; git_strmap_delete(bld->map, filename);
bld->entrycount--; git_tree_entry_free(entry);
} }
} });
} }
void git_treebuilder_clear(git_treebuilder *bld) void git_treebuilder_clear(git_treebuilder *bld)
{ {
size_t i;
git_tree_entry *e; git_tree_entry *e;
assert(bld); assert(bld);
git_vector_foreach(&bld->entries, i, e) git_strmap_foreach_value(bld->map, e, git_tree_entry_free(e));
git_tree_entry_free(e); git_strmap_clear(bld->map);
git_vector_clear(&bld->entries);
bld->entrycount = 0;
} }
void git_treebuilder_free(git_treebuilder *bld) void git_treebuilder_free(git_treebuilder *bld)
...@@ -796,7 +801,7 @@ void git_treebuilder_free(git_treebuilder *bld) ...@@ -796,7 +801,7 @@ void git_treebuilder_free(git_treebuilder *bld)
return; return;
git_treebuilder_clear(bld); git_treebuilder_clear(bld);
git_vector_free(&bld->entries); git_strmap_free(bld->map);
git__free(bld); git__free(bld);
} }
......
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
#include "repository.h" #include "repository.h"
#include "odb.h" #include "odb.h"
#include "vector.h" #include "vector.h"
#include "strmap.h"
struct git_tree_entry { struct git_tree_entry {
uint16_t removed;
uint16_t attr; uint16_t attr;
git_oid oid; git_oid oid;
size_t filename_len; size_t filename_len;
...@@ -26,8 +26,7 @@ struct git_tree { ...@@ -26,8 +26,7 @@ struct git_tree {
}; };
struct git_treebuilder { struct git_treebuilder {
git_vector entries; git_strmap *map;
size_t entrycount; /* vector may contain "removed" entries */
}; };
GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e)
......
...@@ -104,6 +104,7 @@ void test_object_tree_write__subtree(void) ...@@ -104,6 +104,7 @@ void test_object_tree_write__subtree(void)
void test_object_tree_write__sorted_subtrees(void) void test_object_tree_write__sorted_subtrees(void)
{ {
git_treebuilder *builder; git_treebuilder *builder;
git_tree *tree;
unsigned int i; unsigned int i;
int position_c = -1, position_cake = -1, position_config = -1; int position_c = -1, position_cake = -1, position_config = -1;
...@@ -143,8 +144,9 @@ void test_object_tree_write__sorted_subtrees(void) ...@@ -143,8 +144,9 @@ void test_object_tree_write__sorted_subtrees(void)
cl_git_pass(git_treebuilder_write(&tree_oid, g_repo, builder)); cl_git_pass(git_treebuilder_write(&tree_oid, g_repo, builder));
for (i = 0; i < builder->entries.length; ++i) { cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid));
git_tree_entry *entry = git_vector_get(&builder->entries, i); for (i = 0; i < git_tree_entrycount(tree); i++) {
const git_tree_entry *entry = git_tree_entry_byindex(tree, i);
if (strcmp(entry->filename, "c") == 0) if (strcmp(entry->filename, "c") == 0)
position_c = i; position_c = i;
...@@ -156,6 +158,8 @@ void test_object_tree_write__sorted_subtrees(void) ...@@ -156,6 +158,8 @@ void test_object_tree_write__sorted_subtrees(void)
position_config = i; position_config = i;
} }
git_tree_free(tree);
cl_assert(position_c != -1); cl_assert(position_c != -1);
cl_assert(position_cake != -1); cl_assert(position_cake != -1);
cl_assert(position_config != -1); cl_assert(position_config != -1);
......
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