summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-07-10 14:10:39 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-10-10 19:35:19 +0200
commit6843cebe17b7ce15eb9a6d1a88ac2e7e9c00d5b9 (patch)
tree70d5887084b1ba6e471f9f5723414cd7748575e9
parent19c88310cb79153e19b93c59020b2f7c34794f6e (diff)
downloadlibgit2-6843cebe17b7ce15eb9a6d1a88ac2e7e9c00d5b9.tar.gz
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.
-rw-r--r--src/index.c8
-rw-r--r--src/tree-cache.c71
-rw-r--r--src/tree-cache.h4
3 files changed, 83 insertions, 0 deletions
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