diff options
| author | Carlos Martín Nieto <cmn@dwim.me> | 2012-12-21 13:46:48 +0100 |
|---|---|---|
| committer | Carlos Martín Nieto <cmn@dwim.me> | 2013-01-11 17:32:59 +0100 |
| commit | 0ed756200693aed93c4c9fb4f8776196fec5a971 (patch) | |
| tree | 4274bf1f28278fc167ea302a579df9f492c69e78 /src/pack.c | |
| parent | c8f79c2bdf9dd237d5c407526bcfc20d4eff5e64 (diff) | |
| download | libgit2-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.c | 36 |
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 */ |
