Commit 5df18424 by Vicent Marti

lol this worked first try wtf

parent a92dd316
......@@ -11,100 +11,147 @@
#include "thread-utils.h"
#include "util.h"
#include "cache.h"
#include "odb.h"
#include "object.h"
#include "git2/oid.h"
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
{
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;
GIT__USE_OIDMAP
int git_cache_init(git_cache *cache)
{
cache->map = git_oidmap_alloc();
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;
}
void git_cache_free(git_cache *cache)
{
size_t i;
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_oidmap_free(cache->map);
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;
git_cached_obj *node = NULL, *result = NULL;
return true;
}
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)) {
giterr_set(GITERR_THREAD, "unable to lock cache mutex");
if (git_mutex_lock(&cache->lock) < 0)
return NULL;
}
{
node = cache->nodes[hash & cache->size_mask];
pos = kh_get(oid, cache->map, oid);
if (pos != kh_end(cache->map)) {
entry = kh_val(cache->map, pos);
if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) {
git_cached_obj_incref(node);
result = node;
if (flags && entry->flags != flags) {
entry = NULL;
} else {
git_cached_obj_incref(entry);
}
}
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;
uint32_t hash;
khiter_t pos;
memcpy(&hash, &entry->oid, sizeof(uint32_t));
git_cached_obj_incref(entry);
if (git_mutex_lock(&cache->lock)) {
giterr_set(GITERR_THREAD, "unable to lock cache mutex");
return NULL;
}
if (!cache_should_store(entry))
return entry;
if (git_mutex_lock(&cache->lock) < 0)
return entry;
{
git_cached_obj *node = cache->nodes[hash & cache->size_mask];
pos = kh_get(oid, cache->map, &entry->oid);
/* increase the refcount on this object, because
* the cache now owns it */
git_cached_obj_incref(entry);
/* not found */
if (pos == kh_end(cache->map)) {
int rval;
if (node == NULL) {
cache->nodes[hash & cache->size_mask] = entry;
} else if (git_oid_cmp(&node->oid, &entry->oid) == 0) {
git_cached_obj_decref(entry, cache->free_obj);
entry = node;
pos = kh_put(oid, cache->map, &entry->oid, &rval);
if (rval >= 0) {
kh_key(cache->map, pos) = &entry->oid;
kh_val(cache->map, pos) = entry;
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 {
git_cached_obj_decref(node, cache->free_obj);
cache->nodes[hash & cache->size_mask] = entry;
/* NO OP */
}
/* 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;
}
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 @@
#include "git2/odb.h"
#include "thread-utils.h"
#include "oidmap.h"
#define GIT_DEFAULT_CACHE_SIZE 128
typedef void (*git_cached_obj_freeptr)(void *);
enum {
GIT_CACHE_STORE_ANY = 0,
GIT_CACHE_STORE_RAW = 1,
GIT_CACHE_STORE_PARSED = 2
};
typedef struct {
git_oid oid;
git_atomic refcount;
uint32_t flags;
} git_cached_obj;
typedef struct {
git_cached_obj **nodes;
git_oidmap *map;
git_mutex lock;
unsigned int lru_count;
size_t size_mask;
git_cached_obj_freeptr free_obj;
} 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_try_store(git_cache *cache, void *entry);
void *git_cache_get(git_cache *cache, const git_oid *oid);
void *git_cache_store_raw(git_cache *cache, git_odb_object *entry);
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)
{
......@@ -43,12 +48,6 @@ GIT_INLINE(void) git_cached_obj_incref(void *_obj)
git_atomic_inc(&obj->refcount);
}
GIT_INLINE(void) git_cached_obj_decref(void *_obj, git_cached_obj_freeptr free_obj)
{
git_cached_obj *obj = _obj;
if (git_atomic_dec(&obj->refcount) == 0)
free_obj(obj);
}
void git_cached_obj_decref(void *_obj);
#endif
......@@ -121,12 +121,13 @@ int git_object__from_odb_object(
break;
}
if (error < 0)
if (error < 0) {
git_object__free(object);
else
*object_out = git_cache_try_store(&repo->objects, object);
return error;
}
return error;
*object_out = git_cache_store_parsed(&repo->objects, object);
return 0;
}
int git_object_lookup_prefix(
......@@ -154,27 +155,38 @@ int git_object_lookup_prefix(
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,
* since there is no need to check for non ambiguousity
*/
object = git_cache_get(&repo->objects, id);
if (object != NULL) {
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;
cached = git_cache_get_any(&repo->objects, id);
if (cached != NULL) {
if (cached->flags == GIT_CACHE_STORE_PARSED) {
object = (git_object *)cached;
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");
}
*object_out = object;
return 0;
} else {
/* 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);
}
/* 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 {
git_oid short_oid;
......@@ -245,7 +257,7 @@ void git_object_free(git_object *object)
if (object == NULL)
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)
......
......@@ -14,6 +14,7 @@
#include "odb.h"
#include "delta-apply.h"
#include "filter.h"
#include "repository.h"
#include "git2/odb_backend.h"
#include "git2/oid.h"
......@@ -34,7 +35,15 @@ typedef struct
ino_t disk_inode;
} 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);
......@@ -83,10 +92,8 @@ static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source)
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) {
git__free(object->raw.data);
git__free(object);
......@@ -118,7 +125,7 @@ void git_odb_object_free(git_odb_object *object)
if (object == NULL)
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)
......@@ -355,9 +362,8 @@ int git_odb_new(git_odb **out)
git_odb *db = git__calloc(1, sizeof(*db));
GITERR_CHECK_ALLOC(db);
if (git_cache_init(&db->cache, git_odb__cache_size, &free_odb_object) < 0 ||
git_vector_init(&db->backends, 4, backend_sort_cmp) < 0)
{
if (git_cache_init(&db->own_cache) < 0 ||
git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
git__free(db);
return -1;
}
......@@ -559,7 +565,7 @@ static void odb_free(git_odb *db)
}
git_vector_free(&db->backends);
git_cache_free(&db->cache);
git_cache_free(&db->own_cache);
git__free(db);
}
......@@ -580,7 +586,7 @@ int git_odb_exists(git_odb *db, const git_oid *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);
return (int)true;
}
......@@ -630,7 +636,7 @@ int git_odb__read_header_or_object(
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;
*type_p = object->raw.type;
*out = object;
......@@ -678,7 +684,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
return GIT_ENOTFOUND;
}
*out = git_cache_get(&db->cache, id);
*out = git_cache_get_raw(odb_cache(db), id);
if (*out != NULL)
return 0;
......@@ -704,7 +710,7 @@ attempt_lookup:
if (error && error != GIT_PASSTHROUGH)
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;
}
......@@ -727,7 +733,7 @@ int git_odb_read_prefix(
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)
return 0;
}
......@@ -768,7 +774,7 @@ attempt_lookup:
if (!found)
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;
}
......
......@@ -36,9 +36,11 @@ struct git_odb_object {
struct git_odb {
git_refcount rc;
git_vector backends;
git_cache cache;
git_cache own_cache;
};
void git_odb_object__free(git_odb_object *object);
/*
* Hash a git_rawobj internally.
* The `git_rawobj` is supposed to be previously initialized
......
......@@ -21,10 +21,8 @@ typedef khash_t(oid) git_oidmap;
GIT_INLINE(khint_t) hash_git_oid(const git_oid *oid)
{
int i;
khint_t h = 0;
for (i = 0; i < 20; ++i)
h = (h << 5) - h + oid->id[i];
khint_t h;
memcpy(&h, oid, sizeof(khint_t));
return h;
}
......
......@@ -119,7 +119,7 @@ static git_repository *repository_alloc(void)
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);
return NULL;
}
......
......@@ -93,14 +93,6 @@ int git_libgit2_opts(int key, ...)
if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0)
error = git_futils_dirs_set(error, va_arg(ap, const char *));
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);
......
......@@ -16,15 +16,4 @@ void test_core_opts__readwrite(void)
git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_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