Commit d8771592 by Vicent Marti

cache: Max cache size, and evict when the cache fills up

parent cf9709b6
...@@ -131,7 +131,8 @@ enum { ...@@ -131,7 +131,8 @@ enum {
GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, GIT_OPT_SET_MWINDOW_MAPPED_LIMIT,
GIT_OPT_GET_SEARCH_PATH, GIT_OPT_GET_SEARCH_PATH,
GIT_OPT_SET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH,
GIT_OPT_SET_CACHE_LIMIT, GIT_OPT_SET_CACHE_OBJECT_LIMIT,
GIT_OPT_SET_CACHE_MAX_SIZE,
GIT_OPT_ENABLE_CACHING GIT_OPT_ENABLE_CACHING
}; };
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
GIT__USE_OIDMAP GIT__USE_OIDMAP
bool git_cache__enabled = true; bool git_cache__enabled = true;
size_t git_cache__max_storage = (4 * 1024 * 1024);
static size_t git_cache__max_object_size[8] = { static size_t git_cache__max_object_size[8] = {
0, /* GIT_OBJ__EXT1 */ 0, /* GIT_OBJ__EXT1 */
...@@ -70,19 +71,25 @@ int git_cache_init(git_cache *cache) ...@@ -70,19 +71,25 @@ int git_cache_init(git_cache *cache)
return 0; return 0;
} }
void git_cache_clear(git_cache *cache) /* called with lock */
static void clear_cache(git_cache *cache)
{ {
git_cached_obj *evict = NULL; git_cached_obj *evict = NULL;
if (git_mutex_lock(&cache->lock) < 0)
return;
kh_foreach_value(cache->map, evict, { kh_foreach_value(cache->map, evict, {
git_cached_obj_decref(evict); git_cached_obj_decref(evict);
}); });
kh_clear(oid, cache->map); kh_clear(oid, cache->map);
cache->used_memory = 0; cache->used_memory = 0;
}
void git_cache_clear(git_cache *cache)
{
if (git_mutex_lock(&cache->lock) < 0)
return;
clear_cache(cache);
git_mutex_unlock(&cache->lock); git_mutex_unlock(&cache->lock);
} }
...@@ -95,14 +102,15 @@ void git_cache_free(git_cache *cache) ...@@ -95,14 +102,15 @@ void git_cache_free(git_cache *cache)
git_mutex_free(&cache->lock); git_mutex_free(&cache->lock);
} }
/* Call with lock, yo */ /* Called with lock */
static void cache_evict_entries(git_cache *cache, size_t evict_count) static void cache_evict_entries(git_cache *cache)
{ {
uint32_t seed = rand(); uint32_t seed = rand();
size_t evict_count = 8;
/* do not infinite loop if there's not enough entries to evict */ /* do not infinite loop if there's not enough entries to evict */
if (evict_count > kh_size(cache->map)) { if (evict_count > kh_size(cache->map)) {
git_cache_clear(cache); clear_cache(cache);
return; return;
} }
...@@ -163,6 +171,9 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) ...@@ -163,6 +171,9 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
if (git_mutex_lock(&cache->lock) < 0) if (git_mutex_lock(&cache->lock) < 0)
return entry; return entry;
if (cache->used_memory > git_cache__max_storage)
cache_evict_entries(cache);
pos = kh_get(oid, cache->map, &entry->oid); pos = kh_get(oid, cache->map, &entry->oid);
/* not found */ /* not found */
......
...@@ -35,6 +35,7 @@ typedef struct { ...@@ -35,6 +35,7 @@ typedef struct {
} git_cache; } git_cache;
extern bool git_cache__enabled; extern bool git_cache__enabled;
extern size_t git_cache__max_storage;
int git_cache_set_max_object_size(git_otype type, size_t size); int git_cache_set_max_object_size(git_otype type, size_t size);
......
...@@ -95,7 +95,7 @@ int git_libgit2_opts(int key, ...) ...@@ -95,7 +95,7 @@ int git_libgit2_opts(int key, ...)
error = git_futils_dirs_set(error, va_arg(ap, const char *)); error = git_futils_dirs_set(error, va_arg(ap, const char *));
break; break;
case GIT_OPT_SET_CACHE_LIMIT: case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
{ {
git_otype type = (git_otype)va_arg(ap, int); git_otype type = (git_otype)va_arg(ap, int);
size_t size = va_arg(ap, size_t); size_t size = va_arg(ap, size_t);
...@@ -103,6 +103,10 @@ int git_libgit2_opts(int key, ...) ...@@ -103,6 +103,10 @@ int git_libgit2_opts(int key, ...)
break; break;
} }
case GIT_OPT_SET_CACHE_MAX_SIZE:
git_cache__max_storage = va_arg(ap, size_t);
break;
case GIT_OPT_ENABLE_CACHING: case GIT_OPT_ENABLE_CACHING:
git_cache__enabled = (va_arg(ap, int) != 0); git_cache__enabled = (va_arg(ap, int) != 0);
break; break;
......
...@@ -13,7 +13,7 @@ void test_object_cache__cleanup(void) ...@@ -13,7 +13,7 @@ void test_object_cache__cleanup(void)
git_repository_free(g_repo); git_repository_free(g_repo);
g_repo = NULL; g_repo = NULL;
git_libgit2_opts(GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0);
} }
static struct { static struct {
...@@ -54,7 +54,7 @@ void test_object_cache__cache_everything(void) ...@@ -54,7 +54,7 @@ void test_object_cache__cache_everything(void)
git_odb *odb; git_odb *odb;
git_libgit2_opts( git_libgit2_opts(
GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)32767); GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)32767);
cl_git_pass(git_repository_odb(&odb, g_repo)); cl_git_pass(git_repository_odb(&odb, g_repo));
...@@ -103,7 +103,7 @@ void test_object_cache__cache_no_blobs(void) ...@@ -103,7 +103,7 @@ void test_object_cache__cache_no_blobs(void)
git_object *obj; git_object *obj;
git_odb *odb; git_odb *odb;
git_libgit2_opts(GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0);
cl_git_pass(git_repository_odb(&odb, g_repo)); cl_git_pass(git_repository_odb(&odb, g_repo));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment