Commit 5df18424 by Vicent Marti

lol this worked first try wtf

parent a92dd316
...@@ -11,100 +11,147 @@ ...@@ -11,100 +11,147 @@
#include "thread-utils.h" #include "thread-utils.h"
#include "util.h" #include "util.h"
#include "cache.h" #include "cache.h"
#include "odb.h"
#include "object.h"
#include "git2/oid.h" #include "git2/oid.h"
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr) GIT__USE_OIDMAP
{
if (size < 8)
size = 8;
size = git__size_t_powerof2(size);
cache->size_mask = size - 1;
cache->lru_count = 0;
cache->free_obj = free_ptr;
int git_cache_init(git_cache *cache)
{
cache->map = git_oidmap_alloc();
git_mutex_init(&cache->lock); git_mutex_init(&cache->lock);
cache->nodes = git__malloc(size * sizeof(git_cached_obj *));
GITERR_CHECK_ALLOC(cache->nodes);
memset(cache->nodes, 0x0, size * sizeof(git_cached_obj *));
return 0; return 0;
} }
void git_cache_free(git_cache *cache) void git_cache_free(git_cache *cache)
{ {
size_t i; git_oidmap_free(cache->map);
for (i = 0; i < (cache->size_mask + 1); ++i) {
if (cache->nodes[i] != NULL)
git_cached_obj_decref(cache->nodes[i], cache->free_obj);
}
git_mutex_free(&cache->lock); git_mutex_free(&cache->lock);
git__free(cache->nodes);
} }
void *git_cache_get(git_cache *cache, const git_oid *oid) static bool cache_should_store(git_cached_obj *entry)
{ {
uint32_t hash; return true;
git_cached_obj *node = NULL, *result = NULL; }
memcpy(&hash, oid->id, sizeof(hash)); static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags)
{
khiter_t pos;
git_cached_obj *entry = NULL;
if (git_mutex_lock(&cache->lock)) { if (git_mutex_lock(&cache->lock) < 0)
giterr_set(GITERR_THREAD, "unable to lock cache mutex");
return NULL; return NULL;
}
{ pos = kh_get(oid, cache->map, oid);
node = cache->nodes[hash & cache->size_mask]; if (pos != kh_end(cache->map)) {
entry = kh_val(cache->map, pos);
if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) { if (flags && entry->flags != flags) {
git_cached_obj_incref(node); entry = NULL;
result = node; } else {
git_cached_obj_incref(entry);
} }
} }
git_mutex_unlock(&cache->lock); git_mutex_unlock(&cache->lock);
return result; return entry;
} }
void *git_cache_try_store(git_cache *cache, void *_entry) static void *cache_store(git_cache *cache, git_cached_obj *entry)
{ {
git_cached_obj *entry = _entry; khiter_t pos;
uint32_t hash;
memcpy(&hash, &entry->oid, sizeof(uint32_t)); git_cached_obj_incref(entry);
if (git_mutex_lock(&cache->lock)) { if (!cache_should_store(entry))
giterr_set(GITERR_THREAD, "unable to lock cache mutex"); return entry;
return NULL;
} if (git_mutex_lock(&cache->lock) < 0)
return entry;
{ pos = kh_get(oid, cache->map, &entry->oid);
git_cached_obj *node = cache->nodes[hash & cache->size_mask];
/* increase the refcount on this object, because /* not found */
* the cache now owns it */ if (pos == kh_end(cache->map)) {
git_cached_obj_incref(entry); int rval;
if (node == NULL) { pos = kh_put(oid, cache->map, &entry->oid, &rval);
cache->nodes[hash & cache->size_mask] = entry; if (rval >= 0) {
} else if (git_oid_cmp(&node->oid, &entry->oid) == 0) { kh_key(cache->map, pos) = &entry->oid;
git_cached_obj_decref(entry, cache->free_obj); kh_val(cache->map, pos) = entry;
entry = node; git_cached_obj_incref(entry);
}
}
/* found */
else {
git_cached_obj *stored_entry = kh_val(cache->map, pos);
if (stored_entry->flags == entry->flags) {
git_cached_obj_decref(entry);
git_cached_obj_incref(stored_entry);
entry = stored_entry;
} else if (stored_entry->flags == GIT_CACHE_STORE_RAW &&
entry->flags == GIT_CACHE_STORE_PARSED) {
git_cached_obj_decref(stored_entry);
git_cached_obj_incref(entry);
kh_key(cache->map, pos) = &entry->oid;
kh_val(cache->map, pos) = entry;
} else { } else {
git_cached_obj_decref(node, cache->free_obj); /* NO OP */
cache->nodes[hash & cache->size_mask] = entry;
} }
/* increase the refcount again, because we are
* returning it to the user */
git_cached_obj_incref(entry);
} }
git_mutex_unlock(&cache->lock);
git_mutex_unlock(&cache->lock);
return entry; return entry;
} }
void *git_cache_store_raw(git_cache *cache, git_odb_object *entry)
{
entry->cached.flags = GIT_CACHE_STORE_RAW;
return cache_store(cache, (git_cached_obj *)entry);
}
void *git_cache_store_parsed(git_cache *cache, git_object *entry)
{
entry->cached.flags = GIT_CACHE_STORE_PARSED;
return cache_store(cache, (git_cached_obj *)entry);
}
git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid)
{
return cache_get(cache, oid, GIT_CACHE_STORE_RAW);
}
git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid)
{
return cache_get(cache, oid, GIT_CACHE_STORE_PARSED);
}
void *git_cache_get_any(git_cache *cache, const git_oid *oid)
{
return cache_get(cache, oid, GIT_CACHE_STORE_ANY);
}
void git_cached_obj_decref(void *_obj)
{
git_cached_obj *obj = _obj;
if (git_atomic_dec(&obj->refcount) == 0) {
switch (obj->flags) {
case GIT_CACHE_STORE_RAW:
git_odb_object__free(_obj);
break;
case GIT_CACHE_STORE_PARSED:
git_object__free(_obj);
break;
default:
git__free(_obj);
break;
}
}
}
...@@ -12,30 +12,35 @@ ...@@ -12,30 +12,35 @@
#include "git2/odb.h" #include "git2/odb.h"
#include "thread-utils.h" #include "thread-utils.h"
#include "oidmap.h"
#define GIT_DEFAULT_CACHE_SIZE 128 enum {
GIT_CACHE_STORE_ANY = 0,
typedef void (*git_cached_obj_freeptr)(void *); GIT_CACHE_STORE_RAW = 1,
GIT_CACHE_STORE_PARSED = 2
};
typedef struct { typedef struct {
git_oid oid; git_oid oid;
git_atomic refcount; git_atomic refcount;
uint32_t flags;
} git_cached_obj; } git_cached_obj;
typedef struct { typedef struct {
git_cached_obj **nodes; git_oidmap *map;
git_mutex lock; git_mutex lock;
unsigned int lru_count; unsigned int lru_count;
size_t size_mask;
git_cached_obj_freeptr free_obj;
} git_cache; } git_cache;
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr); int git_cache_init(git_cache *cache);
void git_cache_free(git_cache *cache); void git_cache_free(git_cache *cache);
void *git_cache_try_store(git_cache *cache, void *entry); void *git_cache_store_raw(git_cache *cache, git_odb_object *entry);
void *git_cache_get(git_cache *cache, const git_oid *oid); void *git_cache_store_parsed(git_cache *cache, git_object *entry);
git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid);
git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid);
void *git_cache_get_any(git_cache *cache, const git_oid *oid);
GIT_INLINE(void) git_cached_obj_incref(void *_obj) GIT_INLINE(void) git_cached_obj_incref(void *_obj)
{ {
...@@ -43,12 +48,6 @@ GIT_INLINE(void) git_cached_obj_incref(void *_obj) ...@@ -43,12 +48,6 @@ GIT_INLINE(void) git_cached_obj_incref(void *_obj)
git_atomic_inc(&obj->refcount); git_atomic_inc(&obj->refcount);
} }
GIT_INLINE(void) git_cached_obj_decref(void *_obj, git_cached_obj_freeptr free_obj) void git_cached_obj_decref(void *_obj);
{
git_cached_obj *obj = _obj;
if (git_atomic_dec(&obj->refcount) == 0)
free_obj(obj);
}
#endif #endif
...@@ -121,12 +121,13 @@ int git_object__from_odb_object( ...@@ -121,12 +121,13 @@ int git_object__from_odb_object(
break; break;
} }
if (error < 0) if (error < 0) {
git_object__free(object); git_object__free(object);
else return error;
*object_out = git_cache_try_store(&repo->objects, object); }
return error; *object_out = git_cache_store_parsed(&repo->objects, object);
return 0;
} }
int git_object_lookup_prefix( int git_object_lookup_prefix(
...@@ -154,27 +155,38 @@ int git_object_lookup_prefix( ...@@ -154,27 +155,38 @@ int git_object_lookup_prefix(
len = GIT_OID_HEXSZ; len = GIT_OID_HEXSZ;
if (len == GIT_OID_HEXSZ) { if (len == GIT_OID_HEXSZ) {
git_cached_obj *cached = NULL;
/* We want to match the full id : we can first look up in the cache, /* We want to match the full id : we can first look up in the cache,
* since there is no need to check for non ambiguousity * since there is no need to check for non ambiguousity
*/ */
object = git_cache_get(&repo->objects, id); cached = git_cache_get_any(&repo->objects, id);
if (object != NULL) { if (cached != NULL) {
if (type != GIT_OBJ_ANY && type != object->type) { if (cached->flags == GIT_CACHE_STORE_PARSED) {
git_object_free(object); object = (git_object *)cached;
giterr_set(GITERR_INVALID, "The requested type does not match the type in ODB");
return GIT_ENOTFOUND; if (type != GIT_OBJ_ANY && type != object->type) {
git_object_free(object);
giterr_set(GITERR_INVALID,
"The requested type does not match the type in ODB");
return GIT_ENOTFOUND;
}
*object_out = object;
return 0;
} else if (cached->flags == GIT_CACHE_STORE_RAW) {
odb_obj = (git_odb_object *)cached;
} else {
assert(!"Wrong caching type in the global object cache");
} }
} else {
*object_out = object; /* Object was not found in the cache, let's explore the backends.
return 0; * We could just use git_odb_read_unique_short_oid,
* it is the same cost for packed and loose object backends,
* but it may be much more costly for sqlite and hiredis.
*/
error = git_odb_read(&odb_obj, odb, id);
} }
/* Object was not found in the cache, let's explore the backends.
* We could just use git_odb_read_unique_short_oid,
* it is the same cost for packed and loose object backends,
* but it may be much more costly for sqlite and hiredis.
*/
error = git_odb_read(&odb_obj, odb, id);
} else { } else {
git_oid short_oid; git_oid short_oid;
...@@ -245,7 +257,7 @@ void git_object_free(git_object *object) ...@@ -245,7 +257,7 @@ void git_object_free(git_object *object)
if (object == NULL) if (object == NULL)
return; return;
git_cached_obj_decref((git_cached_obj *)object, git_object__free); git_cached_obj_decref(object);
} }
const git_oid *git_object_id(const git_object *obj) const git_oid *git_object_id(const git_object *obj)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "odb.h" #include "odb.h"
#include "delta-apply.h" #include "delta-apply.h"
#include "filter.h" #include "filter.h"
#include "repository.h"
#include "git2/odb_backend.h" #include "git2/odb_backend.h"
#include "git2/oid.h" #include "git2/oid.h"
...@@ -34,7 +35,15 @@ typedef struct ...@@ -34,7 +35,15 @@ typedef struct
ino_t disk_inode; ino_t disk_inode;
} backend_internal; } backend_internal;
size_t git_odb__cache_size = GIT_DEFAULT_CACHE_SIZE; static git_cache *odb_cache(git_odb *odb)
{
if (odb->rc.owner != NULL) {
git_repository *owner = odb->rc.owner;
return &owner->objects;
}
return &odb->own_cache;
}
static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth); static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth);
...@@ -83,10 +92,8 @@ static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source) ...@@ -83,10 +92,8 @@ static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source)
return object; return object;
} }
static void free_odb_object(void *o) void git_odb_object__free(git_odb_object *object)
{ {
git_odb_object *object = (git_odb_object *)o;
if (object != NULL) { if (object != NULL) {
git__free(object->raw.data); git__free(object->raw.data);
git__free(object); git__free(object);
...@@ -118,7 +125,7 @@ void git_odb_object_free(git_odb_object *object) ...@@ -118,7 +125,7 @@ void git_odb_object_free(git_odb_object *object)
if (object == NULL) if (object == NULL)
return; return;
git_cached_obj_decref((git_cached_obj *)object, &free_odb_object); git_cached_obj_decref(object);
} }
int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type) int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type)
...@@ -355,9 +362,8 @@ int git_odb_new(git_odb **out) ...@@ -355,9 +362,8 @@ int git_odb_new(git_odb **out)
git_odb *db = git__calloc(1, sizeof(*db)); git_odb *db = git__calloc(1, sizeof(*db));
GITERR_CHECK_ALLOC(db); GITERR_CHECK_ALLOC(db);
if (git_cache_init(&db->cache, git_odb__cache_size, &free_odb_object) < 0 || if (git_cache_init(&db->own_cache) < 0 ||
git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
{
git__free(db); git__free(db);
return -1; return -1;
} }
...@@ -559,7 +565,7 @@ static void odb_free(git_odb *db) ...@@ -559,7 +565,7 @@ static void odb_free(git_odb *db)
} }
git_vector_free(&db->backends); git_vector_free(&db->backends);
git_cache_free(&db->cache); git_cache_free(&db->own_cache);
git__free(db); git__free(db);
} }
...@@ -580,7 +586,7 @@ int git_odb_exists(git_odb *db, const git_oid *id) ...@@ -580,7 +586,7 @@ int git_odb_exists(git_odb *db, const git_oid *id)
assert(db && id); assert(db && id);
if ((object = git_cache_get(&db->cache, id)) != NULL) { if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
git_odb_object_free(object); git_odb_object_free(object);
return (int)true; return (int)true;
} }
...@@ -630,7 +636,7 @@ int git_odb__read_header_or_object( ...@@ -630,7 +636,7 @@ int git_odb__read_header_or_object(
assert(db && id && out && len_p && type_p); assert(db && id && out && len_p && type_p);
if ((object = git_cache_get(&db->cache, id)) != NULL) { if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
*len_p = object->raw.len; *len_p = object->raw.len;
*type_p = object->raw.type; *type_p = object->raw.type;
*out = object; *out = object;
...@@ -678,7 +684,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) ...@@ -678,7 +684,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
*out = git_cache_get(&db->cache, id); *out = git_cache_get_raw(odb_cache(db), id);
if (*out != NULL) if (*out != NULL)
return 0; return 0;
...@@ -704,7 +710,7 @@ attempt_lookup: ...@@ -704,7 +710,7 @@ attempt_lookup:
if (error && error != GIT_PASSTHROUGH) if (error && error != GIT_PASSTHROUGH)
return error; return error;
*out = git_cache_try_store(&db->cache, new_odb_object(id, &raw)); *out = git_cache_store_raw(odb_cache(db), new_odb_object(id, &raw));
return 0; return 0;
} }
...@@ -727,7 +733,7 @@ int git_odb_read_prefix( ...@@ -727,7 +733,7 @@ int git_odb_read_prefix(
len = GIT_OID_HEXSZ; len = GIT_OID_HEXSZ;
if (len == GIT_OID_HEXSZ) { if (len == GIT_OID_HEXSZ) {
*out = git_cache_get(&db->cache, short_id); *out = git_cache_get_raw(odb_cache(db), short_id);
if (*out != NULL) if (*out != NULL)
return 0; return 0;
} }
...@@ -768,7 +774,7 @@ attempt_lookup: ...@@ -768,7 +774,7 @@ attempt_lookup:
if (!found) if (!found)
return git_odb__error_notfound("no match for prefix", short_id); return git_odb__error_notfound("no match for prefix", short_id);
*out = git_cache_try_store(&db->cache, new_odb_object(&found_full_oid, &raw)); *out = git_cache_store_raw(odb_cache(db), new_odb_object(&found_full_oid, &raw));
return 0; return 0;
} }
......
...@@ -36,9 +36,11 @@ struct git_odb_object { ...@@ -36,9 +36,11 @@ struct git_odb_object {
struct git_odb { struct git_odb {
git_refcount rc; git_refcount rc;
git_vector backends; git_vector backends;
git_cache cache; git_cache own_cache;
}; };
void git_odb_object__free(git_odb_object *object);
/* /*
* Hash a git_rawobj internally. * Hash a git_rawobj internally.
* The `git_rawobj` is supposed to be previously initialized * The `git_rawobj` is supposed to be previously initialized
......
...@@ -21,10 +21,8 @@ typedef khash_t(oid) git_oidmap; ...@@ -21,10 +21,8 @@ typedef khash_t(oid) git_oidmap;
GIT_INLINE(khint_t) hash_git_oid(const git_oid *oid) GIT_INLINE(khint_t) hash_git_oid(const git_oid *oid)
{ {
int i; khint_t h;
khint_t h = 0; memcpy(&h, oid, sizeof(khint_t));
for (i = 0; i < 20; ++i)
h = (h << 5) - h + oid->id[i];
return h; return h;
} }
......
...@@ -119,7 +119,7 @@ static git_repository *repository_alloc(void) ...@@ -119,7 +119,7 @@ static git_repository *repository_alloc(void)
memset(repo, 0x0, sizeof(git_repository)); memset(repo, 0x0, sizeof(git_repository));
if (git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free) < 0) { if (git_cache_init(&repo->objects) < 0) {
git__free(repo); git__free(repo);
return NULL; return NULL;
} }
......
...@@ -93,14 +93,6 @@ int git_libgit2_opts(int key, ...) ...@@ -93,14 +93,6 @@ int git_libgit2_opts(int key, ...)
if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0) if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0)
error = git_futils_dirs_set(error, va_arg(ap, const char *)); error = git_futils_dirs_set(error, va_arg(ap, const char *));
break; break;
case GIT_OPT_GET_ODB_CACHE_SIZE:
*(va_arg(ap, size_t *)) = git_odb__cache_size;
break;
case GIT_OPT_SET_ODB_CACHE_SIZE:
git_odb__cache_size = va_arg(ap, size_t);
break;
} }
va_end(ap); va_end(ap);
......
...@@ -16,15 +16,4 @@ void test_core_opts__readwrite(void) ...@@ -16,15 +16,4 @@ void test_core_opts__readwrite(void)
git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_val); git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_val);
cl_assert(new_val == old_val); cl_assert(new_val == old_val);
git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &old_val);
cl_assert(old_val == GIT_DEFAULT_CACHE_SIZE);
git_libgit2_opts(GIT_OPT_SET_ODB_CACHE_SIZE, (size_t)GIT_DEFAULT_CACHE_SIZE*2);
git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &new_val);
cl_assert(new_val == (GIT_DEFAULT_CACHE_SIZE*2));
git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &old_val);
} }
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