mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-11 17:41:55 +00:00
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.
This commit is contained in:
parent
c8f79c2bdf
commit
0ed7562006
36
src/pack.c
36
src/pack.c
@ -65,8 +65,8 @@ static void free_cache_object(void *o)
|
|||||||
{
|
{
|
||||||
git_pack_cache_entry *e = (git_pack_cache_entry *)o;
|
git_pack_cache_entry *e = (git_pack_cache_entry *)o;
|
||||||
|
|
||||||
assert(e->refcount.val == 0);
|
|
||||||
if (e != NULL) {
|
if (e != NULL) {
|
||||||
|
assert(e->refcount.val == 0);
|
||||||
git__free(e->raw.data);
|
git__free(e->raw.data);
|
||||||
git__free(e);
|
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 */
|
if (k != kh_end(cache->entries)) { /* found it */
|
||||||
entry = kh_value(cache->entries, k);
|
entry = kh_value(cache->entries, k);
|
||||||
git_atomic_inc(&entry->refcount);
|
git_atomic_inc(&entry->refcount);
|
||||||
entry->uses++;
|
entry->last_usage = cache->use_ctr++;
|
||||||
}
|
}
|
||||||
git_mutex_unlock(&cache->lock);
|
git_mutex_unlock(&cache->lock);
|
||||||
|
|
||||||
return entry;
|
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)
|
static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)
|
||||||
{
|
{
|
||||||
git_pack_cache_entry *entry;
|
git_pack_cache_entry *entry;
|
||||||
int error, exists = 0;
|
int error, exists = 0;
|
||||||
khiter_t k;
|
khiter_t k;
|
||||||
|
|
||||||
|
if (base->len > GIT_PACK_CACHE_SIZE_LIMIT)
|
||||||
|
return -1;
|
||||||
|
|
||||||
entry = new_cache_object(base);
|
entry = new_cache_object(base);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
git_mutex_lock(&cache->lock);
|
git_mutex_lock(&cache->lock);
|
||||||
/* Add it to the cache if nobody else has */
|
/* Add it to the cache if nobody else has */
|
||||||
exists = kh_get(off, cache->entries, offset) != kh_end(cache->entries);
|
exists = kh_get(off, cache->entries, offset) != kh_end(cache->entries);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
|
while (cache->memory_used + base->len > cache->memory_limit)
|
||||||
|
free_lowest_entry(cache);
|
||||||
|
|
||||||
k = kh_put(off, cache->entries, offset, &error);
|
k = kh_put(off, cache->entries, offset, &error);
|
||||||
assert(error != 0);
|
assert(error != 0);
|
||||||
kh_value(cache->entries, k) = entry;
|
kh_value(cache->entries, k) = entry;
|
||||||
|
cache->memory_used += entry->raw.len;
|
||||||
}
|
}
|
||||||
git_mutex_unlock(&cache->lock);
|
git_mutex_unlock(&cache->lock);
|
||||||
/* Somebody beat us to adding it into the cache */
|
/* Somebody beat us to adding it into the cache */
|
||||||
|
@ -54,7 +54,7 @@ struct git_pack_idx_header {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef struct git_pack_cache_entry {
|
typedef struct git_pack_cache_entry {
|
||||||
int uses; /* enough? */
|
size_t last_usage; /* enough? */
|
||||||
git_atomic refcount;
|
git_atomic refcount;
|
||||||
git_rawobj raw;
|
git_rawobj raw;
|
||||||
} git_pack_cache_entry;
|
} git_pack_cache_entry;
|
||||||
@ -63,11 +63,13 @@ typedef struct git_pack_cache_entry {
|
|||||||
|
|
||||||
GIT__USE_OFFMAP;
|
GIT__USE_OFFMAP;
|
||||||
|
|
||||||
#define GIT_PACK_CACHE_MEMORY_LIMIT 2 * 1024 * 1024;
|
#define GIT_PACK_CACHE_MEMORY_LIMIT 16 * 1024 * 1024
|
||||||
|
#define GIT_PACK_CACHE_SIZE_LIMIT 1024 * 1024 /* don't bother caching anything over 1MB */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t memory_used;
|
size_t memory_used;
|
||||||
size_t memory_limit;
|
size_t memory_limit;
|
||||||
|
size_t use_ctr;
|
||||||
git_mutex lock;
|
git_mutex lock;
|
||||||
git_offmap *entries;
|
git_offmap *entries;
|
||||||
} git_pack_cache;
|
} git_pack_cache;
|
||||||
|
Loading…
Reference in New Issue
Block a user