summaryrefslogtreecommitdiff
path: root/src/pack.c
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2012-12-21 13:46:48 +0100
committerCarlos Martín Nieto <cmn@dwim.me>2013-01-11 17:32:59 +0100
commit0ed756200693aed93c4c9fb4f8776196fec5a971 (patch)
tree4274bf1f28278fc167ea302a579df9f492c69e78 /src/pack.c
parentc8f79c2bdf9dd237d5c407526bcfc20d4eff5e64 (diff)
downloadlibgit2-0ed756200693aed93c4c9fb4f8776196fec5a971.tar.gz
pack: limit the amount of memory the base delta cache can use
Currently limited to 16MB (like git) and to objects up to 1MB in size.
Diffstat (limited to 'src/pack.c')
-rw-r--r--src/pack.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/src/pack.c b/src/pack.c
index a4c3ebdc2..cc9d07983 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -65,8 +65,8 @@ static void free_cache_object(void *o)
{
git_pack_cache_entry *e = (git_pack_cache_entry *)o;
- assert(e->refcount.val == 0);
if (e != NULL) {
+ assert(e->refcount.val == 0);
git__free(e->raw.data);
git__free(e);
}
@@ -107,28 +107,60 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, size_t offset)
if (k != kh_end(cache->entries)) { /* found it */
entry = kh_value(cache->entries, k);
git_atomic_inc(&entry->refcount);
- entry->uses++;
+ entry->last_usage = cache->use_ctr++;
}
git_mutex_unlock(&cache->lock);
return entry;
}
+/* Run with the cache lock held */
+static void free_lowest_entry(git_pack_cache *cache)
+{
+ git_pack_cache_entry *lowest = NULL, *entry;
+ khiter_t k, lowest_k;
+
+ for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) {
+ if (!kh_exist(cache->entries, k))
+ continue;
+
+ entry = kh_value(cache->entries, k);
+ if (lowest == NULL || entry->last_usage < lowest->last_usage) {
+ lowest_k = k;
+ lowest = entry;
+ }
+ }
+
+ if (!lowest) /* there's nothing to free */
+ return;
+
+ cache->memory_used -= lowest->raw.len;
+ kh_del(off, cache->entries, lowest_k);
+ free_cache_object(lowest);
+}
+
static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)
{
git_pack_cache_entry *entry;
int error, exists = 0;
khiter_t k;
+ if (base->len > GIT_PACK_CACHE_SIZE_LIMIT)
+ return -1;
+
entry = new_cache_object(base);
if (entry) {
git_mutex_lock(&cache->lock);
/* Add it to the cache if nobody else has */
exists = kh_get(off, cache->entries, offset) != kh_end(cache->entries);
if (!exists) {
+ while (cache->memory_used + base->len > cache->memory_limit)
+ free_lowest_entry(cache);
+
k = kh_put(off, cache->entries, offset, &error);
assert(error != 0);
kh_value(cache->entries, k) = entry;
+ cache->memory_used += entry->raw.len;
}
git_mutex_unlock(&cache->lock);
/* Somebody beat us to adding it into the cache */