summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2013-04-01 19:38:23 +0200
committerVicent Marti <tanoku@gmail.com>2013-04-22 16:50:50 +0200
commit5df184241a6cfe88ac5ebcee9a3ad175abfca0cd (patch)
tree36136d01b6016204b5ee9b08a4efe93bf6813613
parenta92dd316079250b27cc933b1fd00cd6af88b88d9 (diff)
downloadlibgit2-5df184241a6cfe88ac5ebcee9a3ad175abfca0cd.tar.gz
lol this worked first try wtf
-rw-r--r--src/cache.c169
-rw-r--r--src/cache.h33
-rw-r--r--src/object.c54
-rw-r--r--src/odb.c36
-rw-r--r--src/odb.h4
-rw-r--r--src/oidmap.h6
-rw-r--r--src/repository.c2
-rw-r--r--src/util.c8
-rw-r--r--tests-clar/core/opts.c11
9 files changed, 184 insertions, 139 deletions
diff --git a/src/cache.c b/src/cache.c
index e7f333577..6eb18dae5 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -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;
+ }
+ }
+}
diff --git a/src/cache.h b/src/cache.h
index 7034ec268..f30af9c3e 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -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
diff --git a/src/object.c b/src/object.c
index 80fe51152..5542ebc8e 100644
--- a/src/object.c
+++ b/src/object.c
@@ -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)
diff --git a/src/odb.c b/src/odb.c
index d6ea8c29a..821fbd70c 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -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;
}
diff --git a/src/odb.h b/src/odb.h
index 7c018cc50..9abf594e8 100644
--- a/src/odb.h
+++ b/src/odb.h
@@ -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
diff --git a/src/oidmap.h b/src/oidmap.h
index 40274cd19..dfa951af3 100644
--- a/src/oidmap.h
+++ b/src/oidmap.h
@@ -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;
}
diff --git a/src/repository.c b/src/repository.c
index a16f69da4..cda75b85f 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -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;
}
diff --git a/src/util.c b/src/util.c
index 8e83d298e..c4a8c786d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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);
diff --git a/tests-clar/core/opts.c b/tests-clar/core/opts.c
index 907339d51..3173c648b 100644
--- a/tests-clar/core/opts.c
+++ b/tests-clar/core/opts.c
@@ -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);
}