summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Almesberger <werner@almesberger.net>2016-10-29 20:08:02 (GMT)
committerWerner Almesberger <werner@almesberger.net>2016-10-29 20:16:19 (GMT)
commit7bea1c432cbc60844eca08c044f559b4411f8887 (patch)
treefd77371f087ec0e9f22cd2325cb571c38528d4c8
parentda077cfcc19b21ebc994e6d1fb5ab85c99f9cc72 (diff)
downloadeeshow-7bea1c432cbc60844eca08c044f559b4411f8887.zip
eeshow-7bea1c432cbc60844eca08c044f559b4411f8887.tar.gz
eeshow-7bea1c432cbc60844eca08c044f559b4411f8887.tar.bz2
file/: implement caching version of git_repository_open_ext for libgit2 < 0.22
In version 0.22, this was added: Share open packfiles across repositories to share descriptors and mmaps Unfortunately, some people are unable to upgrade to modern libraries. Without FD sharing, eeshow may run out of file descriptors when loading large repositories. This commit adds a cache to reduce the number of times a repository is opened, which may in turn reduce the number of open files.
-rw-r--r--file/git-file.c2
-rw-r--r--file/git-hist.c4
-rw-r--r--file/git-util.c35
-rw-r--r--file/git-util.h3
4 files changed, 41 insertions, 3 deletions
diff --git a/file/git-file.c b/file/git-file.c
index 24c90fb..10e70a4 100644
--- a/file/git-file.c
+++ b/file/git-file.c
@@ -79,7 +79,7 @@ static git_repository *select_repo(const char *path)
*/
while (1) {
progress(3, "trying \"%s\"", tmp);
- if (!git_repository_open_ext(&repo, *tmp ? tmp : "/",
+ if (!git_repository_open_ext_caching(&repo, *tmp ? tmp : "/",
GIT_REPOSITORY_OPEN_CROSS_FS, NULL))
break;
slash = strrchr(tmp, '/');
diff --git a/file/git-hist.c b/file/git-hist.c
index 0359673..24d0252 100644
--- a/file/git-hist.c
+++ b/file/git-hist.c
@@ -210,7 +210,7 @@ bool vcs_git_try(const char *path)
* exists, but then it would complain about the file not existing,
* which would be at best confusing.
*/
- if (git_repository_open_ext(&repo, path,
+ if (git_repository_open_ext_caching(&repo, path,
GIT_REPOSITORY_OPEN_CROSS_FS, NULL))
return 0;
if (git_repository_is_empty(repo))
@@ -267,7 +267,7 @@ struct vcs_history *vcs_git_history(const char *path, unsigned depth)
git_init_once();
- if (git_repository_open_ext(&history->repo, path,
+ if (git_repository_open_ext_caching(&history->repo, path,
GIT_REPOSITORY_OPEN_CROSS_FS, NULL))
pfatal_git(path);
diff --git a/file/git-util.c b/file/git-util.c
index 5d604f5..aeeb65f 100644
--- a/file/git-util.c
+++ b/file/git-util.c
@@ -10,11 +10,13 @@
* (at your option) any later version.
*/
+#include <stddef.h>
#include <stdbool.h>
#include <assert.h>
#include <git2.h>
+#include "misc/util.h"
#include "file/git-util.h"
@@ -65,6 +67,39 @@ bool git_repo_is_dirty(git_repository *repo)
}
+int git_repository_open_ext_caching(git_repository **out, const char *path,
+ unsigned int flags, const char *ceiling_dirs)
+{
+#if LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR < 22
+ static struct repo_cache {
+ const char *path;
+ git_repository *repo;
+ struct repo_cache *next;
+ } *repo_cache = NULL;
+ struct repo_cache *c;
+ int res;
+
+ assert(flags == GIT_REPOSITORY_OPEN_CROSS_FS);
+ assert(ceiling_dirs == NULL);
+ for (c = repo_cache; c; c = c->next)
+ if (!strcmp(c->path, path)) {
+ *out = c->repo;
+ return 0;
+ }
+ res = git_repository_open_ext(out, path, flags, ceiling_dirs);
+ if (res)
+ return res;
+ c = alloc_type(struct repo_cache);
+ c->path = stralloc(path);
+ c->repo = *out;
+ c->next = repo_cache;
+ repo_cache = c;
+ return 0;
+#else
+ return git_repository_open_ext(out, path, flags, ceiling_dirs);
+#endif
+}
+
/*
* Git documentation says that git_libgit2_init can be called more then once
* but doesn't quite what happens then, e.g., whether references obtained
diff --git a/file/git-util.h b/file/git-util.h
index 4c7e329..6f11573 100644
--- a/file/git-util.h
+++ b/file/git-util.h
@@ -18,6 +18,9 @@
#include <git2.h>
+int git_repository_open_ext_caching(git_repository **out, const char *path,
+ unsigned int flags, const char *ceiling_dirs);
+
bool git_repo_is_dirty(git_repository *repo);
void git_init_once(void);