cache: Max cache size, and evict when the cache fills up
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
diff --git a/include/git2/common.h b/include/git2/common.h
index 80d83d3..ccd252f 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -131,7 +131,8 @@ enum {
GIT_OPT_SET_MWINDOW_MAPPED_LIMIT,
GIT_OPT_GET_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
};
diff --git a/src/cache.c b/src/cache.c
index c51be89..ca122fb 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -18,6 +18,7 @@
GIT__USE_OIDMAP
bool git_cache__enabled = true;
+size_t git_cache__max_storage = (4 * 1024 * 1024);
static size_t git_cache__max_object_size[8] = {
0, /* GIT_OBJ__EXT1 */
@@ -70,19 +71,25 @@ int git_cache_init(git_cache *cache)
return 0;
}
-void git_cache_clear(git_cache *cache)
+/* called with lock */
+static void clear_cache(git_cache *cache)
{
git_cached_obj *evict = NULL;
- if (git_mutex_lock(&cache->lock) < 0)
- return;
-
kh_foreach_value(cache->map, evict, {
git_cached_obj_decref(evict);
});
kh_clear(oid, cache->map);
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);
}
@@ -95,14 +102,15 @@ void git_cache_free(git_cache *cache)
git_mutex_free(&cache->lock);
}
-/* Call with lock, yo */
-static void cache_evict_entries(git_cache *cache, size_t evict_count)
+/* Called with lock */
+static void cache_evict_entries(git_cache *cache)
{
uint32_t seed = rand();
+ size_t evict_count = 8;
/* do not infinite loop if there's not enough entries to evict */
if (evict_count > kh_size(cache->map)) {
- git_cache_clear(cache);
+ clear_cache(cache);
return;
}
@@ -163,6 +171,9 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
if (git_mutex_lock(&cache->lock) < 0)
return entry;
+ if (cache->used_memory > git_cache__max_storage)
+ cache_evict_entries(cache);
+
pos = kh_get(oid, cache->map, &entry->oid);
/* not found */
diff --git a/src/cache.h b/src/cache.h
index e95d521..1715c72 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -35,6 +35,7 @@ typedef struct {
} git_cache;
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);
diff --git a/src/util.c b/src/util.c
index 1ed5d5d..c3fc697 100644
--- a/src/util.c
+++ b/src/util.c
@@ -95,7 +95,7 @@ int git_libgit2_opts(int key, ...)
error = git_futils_dirs_set(error, va_arg(ap, const char *));
break;
- case GIT_OPT_SET_CACHE_LIMIT:
+ case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
{
git_otype type = (git_otype)va_arg(ap, int);
size_t size = va_arg(ap, size_t);
@@ -103,6 +103,10 @@ int git_libgit2_opts(int key, ...)
break;
}
+ case GIT_OPT_SET_CACHE_MAX_SIZE:
+ git_cache__max_storage = va_arg(ap, size_t);
+ break;
+
case GIT_OPT_ENABLE_CACHING:
git_cache__enabled = (va_arg(ap, int) != 0);
break;
diff --git a/tests-clar/object/cache.c b/tests-clar/object/cache.c
index b36bf27..a3eba87 100644
--- a/tests-clar/object/cache.c
+++ b/tests-clar/object/cache.c
@@ -13,7 +13,7 @@ void test_object_cache__cleanup(void)
git_repository_free(g_repo);
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 {
@@ -54,7 +54,7 @@ void test_object_cache__cache_everything(void)
git_odb *odb;
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));
@@ -103,7 +103,7 @@ void test_object_cache__cache_no_blobs(void)
git_object *obj;
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));