diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2014-06-18 17:13:12 +0200 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2014-06-23 21:50:36 +0200 |
commit | b3b66c57930358467395fc3a5bca87edefd25cf4 (patch) | |
tree | 1ca1c8fd8bf8fd69156c566a83ac12375b427a5e /src/mwindow.c | |
parent | 1589aa0c4d48fb130d8a5db28c45cd3d173cde6d (diff) | |
download | libgit2-b3b66c57930358467395fc3a5bca87edefd25cf4.tar.gz |
Share packs across repository instancescmn/global-mwf
Opening the same repository multiple times will currently open the same
file multiple times, as well as map the same region of the file multiple
times. This is not necessary, as the packfile data is immutable.
Instead of opening and closing packfiles directly, introduce an
indirection and allocate packfiles globally. This does mean locking on
each packfile open, but we already use this lock for the global mwindow
list so it doesn't introduce a new contention point.
Diffstat (limited to 'src/mwindow.c')
-rw-r--r-- | src/mwindow.c | 124 |
1 files changed, 116 insertions, 8 deletions
diff --git a/src/mwindow.c b/src/mwindow.c index 7e5fcdfbc..0d6535056 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -11,6 +11,10 @@ #include "fileops.h" #include "map.h" #include "global.h" +#include "strmap.h" +#include "pack.h" + +GIT__USE_STRMAP; #define DEFAULT_WINDOW_SIZE \ (sizeof(void*) >= 8 \ @@ -26,20 +30,126 @@ size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT; /* Whenever you want to read or modify this, grab git__mwindow_mutex */ static git_mwindow_ctl mem_ctl; -/* - * Free all the windows in a sequence, typically because we're done - * with the file +/* Global list of mwindow files, to open packs once across repos */ +git_strmap *git__pack_cache = NULL; + +/** + * Run under mwindow lock */ -void git_mwindow_free_all(git_mwindow_file *mwf) +int git_mwindow_files_init(void) { - git_mwindow_ctl *ctl = &mem_ctl; - size_t i; + if (git__pack_cache) + return 0; + + return git_strmap_alloc(&git__pack_cache); +} + +void git_mwindow_files_free(void) +{ + git_strmap *tmp = git__pack_cache; + + git__pack_cache = NULL; + git_strmap_free(tmp); +} + +int git_mwindow_get_pack(struct git_pack_file **out, const char *path) +{ + int error; + char *packname; + git_strmap_iter pos; + struct git_pack_file *pack; + + if ((error = git_packfile__name(&packname, path)) < 0) + return error; + + if (git_mutex_lock(&git__mwindow_mutex) < 0) + return -1; + + if (git_mwindow_files_init() < 0) { + git_mutex_unlock(&git__mwindow_mutex); + return -1; + } + + pos = git_strmap_lookup_index(git__pack_cache, packname); + git__free(packname); + + if (git_strmap_valid_index(git__pack_cache, pos)) { + pack = git_strmap_value_at(git__pack_cache, pos); + git_atomic_inc(&pack->refcount); + + git_mutex_unlock(&git__mwindow_mutex); + *out = pack; + return 0; + } + + /* If we didn't find it, we need to create it */ + if ((error = git_packfile_alloc(&pack, path)) < 0) { + git_mutex_unlock(&git__mwindow_mutex); + return error; + } + + git_atomic_inc(&pack->refcount); + + git_strmap_insert(git__pack_cache, pack->pack_name, pack, error); + git_mutex_unlock(&git__mwindow_mutex); + + if (error < 0) + return -1; + *out = pack; + return 0; +} + +int git_mwindow_put_pack(struct git_pack_file *pack) +{ + int count; + git_strmap_iter pos; + + if (git_mutex_lock(&git__mwindow_mutex) < 0) + return -1; + + if (git_mwindow_files_init() < 0) { + git_mutex_unlock(&git__mwindow_mutex); + return -1; + } + + pos = git_strmap_lookup_index(git__pack_cache, pack->pack_name); + if (!git_strmap_valid_index(git__pack_cache, pos)) { + git_mutex_unlock(&git__mwindow_mutex); + return GIT_ENOTFOUND; + } + + count = git_atomic_dec(&pack->refcount); + if (count == 0) { + git_strmap_delete_at(git__pack_cache, pos); + git_packfile_free(pack); + } + + git_mutex_unlock(&git__mwindow_mutex); + return 0; +} + +void git_mwindow_free_all(git_mwindow_file *mwf) +{ if (git_mutex_lock(&git__mwindow_mutex)) { giterr_set(GITERR_THREAD, "unable to lock mwindow mutex"); return; } + git_mwindow_free_all_locked(mwf); + + git_mutex_unlock(&git__mwindow_mutex); +} + +/* + * Free all the windows in a sequence, typically because we're done + * with the file + */ +void git_mwindow_free_all_locked(git_mwindow_file *mwf) +{ + git_mwindow_ctl *ctl = &mem_ctl; + size_t i; + /* * Remove these windows from the global list */ @@ -67,8 +177,6 @@ void git_mwindow_free_all(git_mwindow_file *mwf) mwf->windows = w->next; git__free(w); } - - git_mutex_unlock(&git__mwindow_mutex); } /* |