From 6843cebe17b7ce15eb9a6d1a88ac2e7e9c00d5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 10 Jul 2014 14:10:39 +0200 Subject: [PATCH] index: fill the tree cache when reading from a tree When reading from a tree, we know what every tree is going to look like, so we can fill in the tree cache completely, making use of the index for modification of trees a lot quicker. --- src/index.c | 8 ++++++ src/tree-cache.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ src/tree-cache.h | 4 +++ 3 files changed, 83 insertions(+) diff --git a/src/index.c b/src/index.c index 8ea1fd49e..be043a9bf 100644 --- a/src/index.c +++ b/src/index.c @@ -2277,6 +2277,7 @@ typedef struct read_tree_data { git_vector *old_entries; git_vector *new_entries; git_vector_cmp entry_cmp; + git_tree_cache *tree; } read_tree_data; static int read_tree_cb( @@ -2338,6 +2339,9 @@ int git_index_read_tree(git_index *index, const git_tree *tree) data.new_entries = &entries; data.entry_cmp = index->entries_search; + index->tree = NULL; + git_pool_clear(&index->tree_pool); + if (index_sort_if_needed(index, true) < 0) return -1; @@ -2358,6 +2362,10 @@ int git_index_read_tree(git_index *index, const git_tree *tree) } git_vector_free(&entries); + if (error < 0) + return error; + + error = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool); return error; } diff --git a/src/tree-cache.c b/src/tree-cache.c index d76d9281b..86521ce4d 100644 --- a/src/tree-cache.c +++ b/src/tree-cache.c @@ -7,6 +7,7 @@ #include "tree-cache.h" #include "pool.h" +#include "tree.h" static git_tree_cache *find_child( const git_tree_cache *tree, const char *path, const char *end) @@ -155,6 +156,76 @@ int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer return 0; } +static int read_tree_recursive(git_tree_cache *cache, const git_tree *tree, git_pool *pool) +{ + git_repository *repo; + size_t i, j, nentries, ntrees; + int error; + + repo = git_tree_owner(tree); + + git_oid_cpy(&cache->oid, git_tree_id(tree)); + nentries = git_tree_entrycount(tree); + + /* + * We make sure we know how many trees we need to allocate for + * so we don't have to realloc and change the pointers for the + * parents. + */ + ntrees = 0; + for (i = 0; i < nentries; i++) { + const git_tree_entry *entry; + + entry = git_tree_entry_byindex(tree, i); + if (git_tree_entry_filemode(entry) == GIT_FILEMODE_TREE) + ntrees++; + } + + cache->children_count = ntrees; + cache->children = git_pool_mallocz(pool, ntrees * sizeof(git_tree_cache *)); + GITERR_CHECK_ALLOC(cache->children); + + j = 0; + for (i = 0; i < nentries; i++) { + const git_tree_entry *entry; + git_tree *subtree; + + entry = git_tree_entry_byindex(tree, i); + if (git_tree_entry_filemode(entry) != GIT_FILEMODE_TREE) + continue; + + if ((error = git_tree_cache_new(&cache->children[j], git_tree_entry_name(entry), cache, pool)) < 0) + return error; + + if ((error = git_tree_lookup(&subtree, repo, git_tree_entry_id(entry))) < 0) + return error; + + error = read_tree_recursive(cache->children[j], subtree, pool); + git_tree_free(subtree); + j++; + + if (error < 0) + return error; + } + + return 0; +} + +int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_pool *pool) +{ + int error; + git_tree_cache *cache; + + if ((error = git_tree_cache_new(&cache, "", NULL, pool)) < 0) + return error; + + if ((error = read_tree_recursive(cache, tree, pool)) < 0) + return error; + + *out = cache; + return 0; +} + int git_tree_cache_new(git_tree_cache **out, const char *name, git_tree_cache *parent, git_pool *pool) { size_t name_len; diff --git a/src/tree-cache.h b/src/tree-cache.h index d41a51f84..d75049d8b 100644 --- a/src/tree-cache.h +++ b/src/tree-cache.h @@ -27,6 +27,10 @@ int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path); const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char *path); int git_tree_cache_new(git_tree_cache **out, const char *name, git_tree_cache *parent, git_pool *pool); +/** + * Read a tree as the root of the tree cache (like for `git read-tree`) + */ +int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_pool *pool); void git_tree_cache_free(git_tree_cache *tree); #endif