Merge pull request #1498 from libgit2/vmg/atomic64 64 bit atomic operations and shared cache memory usage
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 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
diff --git a/include/git2/common.h b/include/git2/common.h
index ccd252f..6101e13 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -133,7 +133,8 @@ enum {
GIT_OPT_SET_SEARCH_PATH,
GIT_OPT_SET_CACHE_OBJECT_LIMIT,
GIT_OPT_SET_CACHE_MAX_SIZE,
- GIT_OPT_ENABLE_CACHING
+ GIT_OPT_ENABLE_CACHING,
+ GIT_OPT_GET_CACHED_MEMORY
};
/**
diff --git a/src/cache.c b/src/cache.c
index ca122fb..88f643b 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -18,7 +18,8 @@
GIT__USE_OIDMAP
bool git_cache__enabled = true;
-size_t git_cache__max_storage = (4 * 1024 * 1024);
+int64_t git_cache__max_storage = (256 * 1024 * 1024);
+git_atomic64 git_cache__current_storage = {0};
static size_t git_cache__max_object_size[8] = {
0, /* GIT_OBJ__EXT1 */
@@ -81,6 +82,7 @@ static void clear_cache(git_cache *cache)
});
kh_clear(oid, cache->map);
+ git_atomic64_add(&git_cache__current_storage, -cache->used_memory);
cache->used_memory = 0;
}
@@ -106,7 +108,7 @@ void git_cache_free(git_cache *cache)
static void cache_evict_entries(git_cache *cache)
{
uint32_t seed = rand();
- size_t evict_count = 8;
+ int64_t evicted_memory = 0, evict_count = 8;
/* do not infinite loop if there's not enough entries to evict */
if (evict_count > kh_size(cache->map)) {
@@ -121,12 +123,15 @@ static void cache_evict_entries(git_cache *cache)
git_cached_obj *evict = kh_val(cache->map, pos);
evict_count--;
- cache->used_memory -= evict->size;
+ evicted_memory += evict->size;
git_cached_obj_decref(evict);
kh_del(oid, cache->map, pos);
}
}
+
+ cache->used_memory -= evicted_memory;
+ git_atomic64_add(&git_cache__current_storage, -evicted_memory);
}
static bool cache_should_store(git_otype object_type, size_t object_size)
@@ -171,7 +176,8 @@ 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)
+ /* soften the load on the cache */
+ if (git_cache__current_storage.val > git_cache__max_storage)
cache_evict_entries(cache);
pos = kh_get(oid, cache->map, &entry->oid);
@@ -186,6 +192,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
kh_val(cache->map, pos) = entry;
git_cached_obj_incref(entry);
cache->used_memory += entry->size;
+ git_atomic64_add(&git_cache__current_storage, (int64_t)entry->size);
}
}
/* found */
diff --git a/src/cache.h b/src/cache.h
index 1715c72..1fb87dc 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -31,11 +31,12 @@ typedef struct {
typedef struct {
git_oidmap *map;
git_mutex lock;
- size_t used_memory;
+ int64_t used_memory;
} git_cache;
extern bool git_cache__enabled;
-extern size_t git_cache__max_storage;
+extern int64_t git_cache__max_storage;
+extern git_atomic64 git_cache__current_storage;
int git_cache_set_max_object_size(git_otype type, size_t size);
diff --git a/src/thread-utils.h b/src/thread-utils.h
index dafe70a..28ecd29 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -18,6 +18,14 @@ typedef struct {
#endif
} git_atomic;
+typedef struct {
+#if defined(GIT_WIN32)
+ __int64 val;
+#else
+ int64_t val;
+#endif
+} git_atomic64;
+
GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
{
a->val = val;
@@ -57,6 +65,17 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a)
#endif
}
+GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
+{
+#if defined(GIT_WIN32)
+ return _InterlockedExchangeAdd(&a->val, addend);
+#elif defined(__GNUC__)
+ return __sync_add_and_fetch(&a->val, addend);
+#else
+# error "Unsupported architecture for atomic operations"
+#endif
+}
+
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
{
#if defined(GIT_WIN32)
@@ -82,6 +101,17 @@ GIT_INLINE(void *) git___compare_and_swap(
return (foundval == oldval) ? oldval : newval;
}
+GIT_INLINE(int) git_atomic64_add(git_atomic64 *a, int64_t addend)
+{
+#if defined(GIT_WIN32)
+ return _InterlockedExchangeAdd64(&a->val, addend);
+#elif defined(__GNUC__)
+ return __sync_add_and_fetch(&a->val, addend);
+#else
+# error "Unsupported architecture for atomic operations"
+#endif
+}
+
#else
#define git_thread unsigned int
@@ -110,6 +140,12 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a)
return ++a->val;
}
+GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
+{
+ a->val += addend;
+ return a->val;
+}
+
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
{
return --a->val;
@@ -125,6 +161,12 @@ GIT_INLINE(void *) git___compare_and_swap(
return oldval;
}
+GIT_INLINE(int) git_atomic64_add(git_atomic64 *a, int64_t addend)
+{
+ a->val += addend;
+ return a->val;
+}
+
#endif
/* Atomically replace oldval with newval
diff --git a/src/util.c b/src/util.c
index c3fc697..ce67c7e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -39,7 +39,6 @@ int git_libgit2_capabilities()
/* Declarations for tuneable settings */
extern size_t git_mwindow__window_size;
extern size_t git_mwindow__mapped_limit;
-extern size_t git_odb__cache_size;
static int config_level_to_futils_dir(int config_level)
{
@@ -104,12 +103,17 @@ int git_libgit2_opts(int key, ...)
}
case GIT_OPT_SET_CACHE_MAX_SIZE:
- git_cache__max_storage = va_arg(ap, size_t);
+ git_cache__max_storage = va_arg(ap, int64_t);
break;
case GIT_OPT_ENABLE_CACHING:
git_cache__enabled = (va_arg(ap, int) != 0);
break;
+
+ case GIT_OPT_GET_CACHED_MEMORY:
+ *(va_arg(ap, int64_t *)) = git_cache__current_storage.val;
+ *(va_arg(ap, int64_t *)) = git_cache__max_storage;
+ break;
}
va_end(ap);