summaryrefslogtreecommitdiff
path: root/src/submodule.c
diff options
context:
space:
mode:
authorBrock Peabody <bpeabody@twosigma.com>2016-11-23 18:32:48 -0500
committerDavid Turner <dturner@twosigma.com>2017-01-20 17:33:56 -0500
commit4d99c4cfc604bb141fd4e1423e934ebd3fb7e2a7 (patch)
tree7fa6287b0ecfb6873dfd74eaf819cff1cf396bc2 /src/submodule.c
parentca05857e71f8d11582b1ad82f63c6a61e96fe20e (diff)
downloadlibgit2-4d99c4cfc604bb141fd4e1423e934ebd3fb7e2a7.tar.gz
Allow for caching of submodules.
Added `git_repository_submodule_cache_all` to initialze a cache of submodules on the repository so that operations looking up N submodules are O(N) and not O(N^2). Added a `git_repository_submodule_cache_clear` function to remove the cache. Also optimized the function that loads all submodules as it was itself O(N^2) w.r.t the number of submodules, having to loop through the `.gitmodules` file once per submodule. I changed it to process the `.gitmodules` file once, into a map. Signed-off-by: David Turner <dturner@twosigma.com>
Diffstat (limited to 'src/submodule.c')
-rw-r--r--src/submodule.c119
1 files changed, 80 insertions, 39 deletions
diff --git a/src/submodule.c b/src/submodule.c
index 46462f165..6996006dc 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -149,40 +149,53 @@ static int find_by_path(const git_config_entry *entry, void *payload)
}
/**
- * Find out the name of a submodule from its path
+ * Release the name map returned by 'load_submodule_names'.
*/
-static int name_from_path(git_buf *out, git_config *cfg, const char *path)
+static void free_submodule_names(git_strmap *names)
+{
+ git_buf *name = 0;
+ if (names == NULL)
+ return;
+ git_strmap_foreach_value(names, name, {
+ git__free(name);
+ });
+ git_strmap_free(names);
+ return;
+}
+
+/**
+ * Map submodule paths to names.
+ * TODO: for some use-cases, this might need case-folding on a
+ * case-insensitive filesystem
+ */
+static int load_submodule_names(git_strmap *out, git_config *cfg)
{
const char *key = "submodule\\..*\\.path";
git_config_iterator *iter;
git_config_entry *entry;
- int error;
+ git_buf buf = GIT_BUF_INIT;
+ int rval;
+ int error = 0;
if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
return error;
- while ((error = git_config_next(&entry, iter)) == 0) {
+ while (git_config_next(&entry, iter) == 0) {
const char *fdot, *ldot;
- /* TODO: this should maybe be strcasecmp on a case-insensitive fs */
- if (strcmp(path, entry->value) != 0)
- continue;
-
fdot = strchr(entry->name, '.');
ldot = strrchr(entry->name, '.');
- git_buf_clear(out);
- git_buf_put(out, fdot + 1, ldot - fdot - 1);
- goto cleanup;
- }
-
- if (error == GIT_ITEROVER) {
- giterr_set(GITERR_SUBMODULE, "could not find a submodule name for '%s'", path);
- error = GIT_ENOTFOUND;
+ git_buf_put(&buf, fdot + 1, ldot - fdot - 1);
+ git_strmap_insert(out, entry->value, git_buf_detach(&buf), rval);
+ if (rval < 0) {
+ giterr_set(GITERR_NOMEMORY, "Error inserting submodule into hash table");
+ free_submodule_names(out);
+ return -1;
+ }
}
-cleanup:
git_config_iterator_free(iter);
- return error;
+ return 0;
}
int git_submodule_lookup(
@@ -196,6 +209,17 @@ int git_submodule_lookup(
assert(repo && name);
+ if (repo->submodule_cache != NULL) {
+ khiter_t pos = git_strmap_lookup_index(repo->submodule_cache, name);
+ if (git_strmap_valid_index(repo->submodule_cache, pos)) {
+ if (out) {
+ *out = git_strmap_value_at(repo->submodule_cache, pos);
+ GIT_REFCOUNT_INC(*out);
+ }
+ return 0;
+ }
+ }
+
if ((error = submodule_alloc(&sm, repo, name)) < 0)
return error;
@@ -327,20 +351,18 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf
int error;
git_iterator *i;
const git_index_entry *entry;
- git_buf name = GIT_BUF_INIT;
+ git_strmap *names = 0;
+ git_strmap_alloc(&names);
+ if ((error = load_submodule_names(names, cfg)))
+ goto done;
if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
- return error;
+ goto done;
while (!(error = git_iterator_advance(&entry, i))) {
khiter_t pos = git_strmap_lookup_index(map, entry->path);
git_submodule *sm;
- git_buf_clear(&name);
- if (!name_from_path(&name, cfg, entry->path)) {
- git_strmap_lookup_index(map, name.ptr);
- }
-
if (git_strmap_valid_index(map, pos)) {
sm = git_strmap_value_at(map, pos);
@@ -349,7 +371,17 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf
else
sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
} else if (S_ISGITLINK(entry->mode)) {
- if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name.ptr ? name.ptr : entry->path)) {
+ khiter_t name_pos;
+ const char *name;
+
+ name_pos = git_strmap_lookup_index(names, entry->path);
+ if (git_strmap_valid_index(names, name_pos)) {
+ name = git_strmap_value_at(names, name_pos);
+ } else {
+ name = entry->path;
+ }
+
+ if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) {
submodule_update_from_index_entry(sm, entry);
git_submodule_free(sm);
}
@@ -359,8 +391,9 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf
if (error == GIT_ITEROVER)
error = 0;
- git_buf_free(&name);
+done:
git_iterator_free(i);
+ free_submodule_names(names);
return error;
}
@@ -370,20 +403,18 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg
int error;
git_iterator *i;
const git_index_entry *entry;
- git_buf name = GIT_BUF_INIT;
+ git_strmap *names = 0;
+ git_strmap_alloc(&names);
+ if ((error = load_submodule_names(names, cfg)))
+ goto done;
if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
- return error;
+ goto done;
while (!(error = git_iterator_advance(&entry, i))) {
khiter_t pos = git_strmap_lookup_index(map, entry->path);
git_submodule *sm;
- git_buf_clear(&name);
- if (!name_from_path(&name, cfg, entry->path)) {
- git_strmap_lookup_index(map, name.ptr);
- }
-
if (git_strmap_valid_index(map, pos)) {
sm = git_strmap_value_at(map, pos);
@@ -392,7 +423,17 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg
else
sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
} else if (S_ISGITLINK(entry->mode)) {
- if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name.ptr ? name.ptr : entry->path)) {
+ khiter_t name_pos;
+ const char *name;
+
+ name_pos = git_strmap_lookup_index(names, entry->path);
+ if (git_strmap_valid_index(names, name_pos)) {
+ name = git_strmap_value_at(names, name_pos);
+ } else {
+ name = entry->path;
+ }
+
+ if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) {
submodule_update_from_head_data(
sm, entry->mode, &entry->id);
git_submodule_free(sm);
@@ -403,8 +444,9 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg
if (error == GIT_ITEROVER)
error = 0;
- git_buf_free(&name);
+done:
git_iterator_free(i);
+ free_submodule_names(names);
return error;
}
@@ -416,7 +458,7 @@ typedef struct {
git_repository *repo;
} lfc_data;
-static int all_submodules(git_repository *repo, git_strmap *map)
+int git_submodule__map(git_repository *repo, git_strmap *map)
{
int error = 0;
git_index *idx = NULL;
@@ -509,7 +551,7 @@ int git_submodule_foreach(
if ((error = git_strmap_alloc(&submodules)) < 0)
return error;
- if ((error = all_submodules(repo, submodules)) < 0)
+ if ((error = git_submodule__map(repo, submodules)) < 0)
goto done;
if (!(error = git_vector_init(
@@ -1566,7 +1608,6 @@ int git_submodule_location(unsigned int *location, git_submodule *sm)
location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
}
-
/*
* INTERNAL FUNCTIONS
*/