Commit c8f79c2b by Carlos Martín Nieto

pack: abstract out the cache into its own functions

parent 525d961c
...@@ -46,14 +46,16 @@ static int packfile_error(const char *message) ...@@ -46,14 +46,16 @@ static int packfile_error(const char *message)
return -1; return -1;
} }
/********************
* Delta base cache
********************/
static git_pack_cache_entry *new_cache_object(git_rawobj *source) static git_pack_cache_entry *new_cache_object(git_rawobj *source)
{ {
git_pack_cache_entry *e = git__malloc(sizeof(git_pack_cache_entry)); git_pack_cache_entry *e = git__calloc(1, sizeof(git_pack_cache_entry));
if (!e) if (!e)
return NULL; return NULL;
e->refcount.val = 0;
memcpy(&e->raw, source, sizeof(git_rawobj)); memcpy(&e->raw, source, sizeof(git_rawobj));
return e; return e;
...@@ -70,6 +72,75 @@ static void free_cache_object(void *o) ...@@ -70,6 +72,75 @@ static void free_cache_object(void *o)
} }
} }
static void cache_free(git_pack_cache *cache)
{
khiter_t k;
if (cache->entries) {
for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) {
if (kh_exist(cache->entries, k))
free_cache_object(kh_value(cache->entries, k));
}
git_offmap_free(cache->entries);
}
}
static int cache_init(git_pack_cache *cache)
{
memset(cache, 0, sizeof(git_pack_cache));
cache->entries = git_offmap_alloc();
GITERR_CHECK_ALLOC(cache->entries);
cache->memory_limit = GIT_PACK_CACHE_MEMORY_LIMIT;
git_mutex_init(&cache->lock);
return 0;
}
static git_pack_cache_entry *cache_get(git_pack_cache *cache, size_t offset)
{
khiter_t k;
git_pack_cache_entry *entry = NULL;
git_mutex_lock(&cache->lock);
k = kh_get(off, cache->entries, offset);
if (k != kh_end(cache->entries)) { /* found it */
entry = kh_value(cache->entries, k);
git_atomic_inc(&entry->refcount);
entry->uses++;
}
git_mutex_unlock(&cache->lock);
return entry;
}
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;
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) {
k = kh_put(off, cache->entries, offset, &error);
assert(error != 0);
kh_value(cache->entries, k) = entry;
}
git_mutex_unlock(&cache->lock);
/* Somebody beat us to adding it into the cache */
if (exists) {
git__free(entry);
return -1;
}
}
return 0;
}
/*********************************************************** /***********************************************************
* *
* PACK INDEX METHODS * PACK INDEX METHODS
...@@ -364,7 +435,6 @@ static int packfile_unpack_delta( ...@@ -364,7 +435,6 @@ static int packfile_unpack_delta(
git_rawobj base, delta; git_rawobj base, delta;
git_pack_cache_entry *cached = NULL; git_pack_cache_entry *cached = NULL;
int error, found_base = 0; int error, found_base = 0;
khiter_t k;
base_offset = get_delta_base(p, w_curs, curpos, delta_type, obj_offset); base_offset = get_delta_base(p, w_curs, curpos, delta_type, obj_offset);
git_mwindow_close(w_curs); git_mwindow_close(w_curs);
...@@ -373,22 +443,14 @@ static int packfile_unpack_delta( ...@@ -373,22 +443,14 @@ static int packfile_unpack_delta(
if (base_offset < 0) /* must actually be an error code */ if (base_offset < 0) /* must actually be an error code */
return (int)base_offset; return (int)base_offset;
if (!p->bases) { if (!p->bases.entries && (cache_init(&p->bases) < 0))
p->bases = git_offmap_alloc(); return -1;
GITERR_CHECK_ALLOC(p->bases);
git_mutex_init(&p->bases_lock);
}
base_key = base_offset; /* git_packfile_unpack modifies base_offset */ base_key = base_offset; /* git_packfile_unpack modifies base_offset */
git_mutex_lock(&p->bases_lock); if ((cached = cache_get(&p->bases, base_offset)) != NULL) {
k = kh_get(off, p->bases, base_offset);
if (k != kh_end(p->bases)) { /* found it */
cached = kh_value(p->bases, k);
git_atomic_inc(&cached->refcount);
found_base = 1;
memcpy(&base, &cached->raw, sizeof(git_rawobj)); memcpy(&base, &cached->raw, sizeof(git_rawobj));
found_base = 1;
} }
git_mutex_unlock(&p->bases_lock);
if (!cached) { /* have to inflate it */ if (!cached) { /* have to inflate it */
error = git_packfile_unpack(&base, p, &base_offset); error = git_packfile_unpack(&base, p, &base_offset);
...@@ -417,29 +479,10 @@ static int packfile_unpack_delta( ...@@ -417,29 +479,10 @@ static int packfile_unpack_delta(
if (error < 0) if (error < 0)
goto on_error; goto on_error;
if (found_base) { if (found_base)
git_atomic_dec(&cached->refcount); git_atomic_dec(&cached->refcount);
} else { else if (cache_add(&p->bases, &base, base_key) < 0)
cached = new_cache_object(&base); git__free(base.data);
if (cached) {
int exists;
git_mutex_lock(&p->bases_lock);
/* Add it to the cache if nobody else has */
exists = kh_exist(p->bases, kh_get(off, p->bases, base_key));
if (!exists) {
k = kh_put(off, p->bases, base_key, &error);
assert(error != 0);
kh_value(p->bases, k) = cached;
}
git_mutex_unlock(&p->bases_lock);
/* Somebody beat us to adding it into the cache */
if (exists) {
free_cache_object(cached);
git__free(base.data);
}
}
}
on_error: on_error:
git__free(delta.data); git__free(delta.data);
...@@ -721,18 +764,9 @@ static struct git_pack_file *packfile_alloc(size_t extra) ...@@ -721,18 +764,9 @@ static struct git_pack_file *packfile_alloc(size_t extra)
void packfile_free(struct git_pack_file *p) void packfile_free(struct git_pack_file *p)
{ {
khiter_t k;
assert(p); assert(p);
if (p->bases) { cache_free(&p->bases);
for (k = kh_begin(p->bases); k != kh_end(p->bases); k++) {
if (kh_exist(p->bases, k))
free_cache_object(kh_value(p->bases, k));
}
git_offmap_free(p->bases);
}
git_mwindow_free_all(&p->mwf); git_mwindow_free_all(&p->mwf);
git_mwindow_file_deregister(&p->mwf); git_mwindow_file_deregister(&p->mwf);
...@@ -758,11 +792,6 @@ static int packfile_open(struct git_pack_file *p) ...@@ -758,11 +792,6 @@ static int packfile_open(struct git_pack_file *p)
if (!p->index_map.data && pack_index_open(p) < 0) if (!p->index_map.data && pack_index_open(p) < 0)
return git_odb__error_notfound("failed to open packfile", NULL); return git_odb__error_notfound("failed to open packfile", NULL);
p->bases = git_offmap_alloc();
GITERR_CHECK_ALLOC(p->bases);
git_mutex_init(&p->bases_lock);
/* TODO: open with noatime */ /* TODO: open with noatime */
p->mwf.fd = git_futils_open_ro(p->pack_name); p->mwf.fd = git_futils_open_ro(p->pack_name);
if (p->mwf.fd < 0) { if (p->mwf.fd < 0) {
......
...@@ -54,6 +54,7 @@ struct git_pack_idx_header { ...@@ -54,6 +54,7 @@ struct git_pack_idx_header {
}; };
typedef struct git_pack_cache_entry { typedef struct git_pack_cache_entry {
int uses; /* enough? */
git_atomic refcount; git_atomic refcount;
git_rawobj raw; git_rawobj raw;
} git_pack_cache_entry; } git_pack_cache_entry;
...@@ -62,6 +63,15 @@ typedef struct git_pack_cache_entry { ...@@ -62,6 +63,15 @@ typedef struct git_pack_cache_entry {
GIT__USE_OFFMAP; GIT__USE_OFFMAP;
#define GIT_PACK_CACHE_MEMORY_LIMIT 2 * 1024 * 1024;
typedef struct {
size_t memory_used;
size_t memory_limit;
git_mutex lock;
git_offmap *entries;
} git_pack_cache;
struct git_pack_file { struct git_pack_file {
git_mwindow_file mwf; git_mwindow_file mwf;
git_map index_map; git_map index_map;
...@@ -77,8 +87,7 @@ struct git_pack_file { ...@@ -77,8 +87,7 @@ struct git_pack_file {
git_vector cache; git_vector cache;
git_oid **oids; git_oid **oids;
git_mutex bases_lock; git_pack_cache bases; /* delta base cache */
git_offmap *bases; /* delta base cache */
/* something like ".git/objects/pack/xxxxx.pack" */ /* something like ".git/objects/pack/xxxxx.pack" */
char pack_name[GIT_FLEX_ARRAY]; /* more */ char pack_name[GIT_FLEX_ARRAY]; /* more */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment