mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-16 18:27:31 +00:00
lol this worked first try wtf
This commit is contained in:
parent
a92dd31607
commit
5df184241a
187
src/cache.c
187
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)
|
||||
GIT__USE_OIDMAP
|
||||
|
||||
int git_cache_init(git_cache *cache)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
memcpy(&hash, oid->id, sizeof(hash));
|
||||
|
||||
if (git_mutex_lock(&cache->lock)) {
|
||||
giterr_set(GITERR_THREAD, "unable to lock cache mutex");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
node = cache->nodes[hash & cache->size_mask];
|
||||
|
||||
if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) {
|
||||
git_cached_obj_incref(node);
|
||||
result = node;
|
||||
}
|
||||
}
|
||||
git_mutex_unlock(&cache->lock);
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
void *git_cache_try_store(git_cache *cache, void *_entry)
|
||||
static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags)
|
||||
{
|
||||
git_cached_obj *entry = _entry;
|
||||
uint32_t hash;
|
||||
khiter_t pos;
|
||||
git_cached_obj *entry = NULL;
|
||||
|
||||
memcpy(&hash, &entry->oid, sizeof(uint32_t));
|
||||
|
||||
if (git_mutex_lock(&cache->lock)) {
|
||||
giterr_set(GITERR_THREAD, "unable to lock cache mutex");
|
||||
if (git_mutex_lock(&cache->lock) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
git_cached_obj *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);
|
||||
|
||||
/* increase the refcount on this object, because
|
||||
* the cache now owns it */
|
||||
git_cached_obj_incref(entry);
|
||||
|
||||
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;
|
||||
if (flags && entry->flags != flags) {
|
||||
entry = NULL;
|
||||
} else {
|
||||
git_cached_obj_decref(node, cache->free_obj);
|
||||
cache->nodes[hash & cache->size_mask] = entry;
|
||||
git_cached_obj_incref(entry);
|
||||
}
|
||||
|
||||
/* increase the refcount again, because we are
|
||||
* returning it to the user */
|
||||
git_cached_obj_incref(entry);
|
||||
|
||||
}
|
||||
|
||||
git_mutex_unlock(&cache->lock);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void *cache_store(git_cache *cache, git_cached_obj *entry)
|
||||
{
|
||||
khiter_t pos;
|
||||
|
||||
git_cached_obj_incref(entry);
|
||||
|
||||
if (!cache_should_store(entry))
|
||||
return entry;
|
||||
|
||||
if (git_mutex_lock(&cache->lock) < 0)
|
||||
return entry;
|
||||
|
||||
pos = kh_get(oid, cache->map, &entry->oid);
|
||||
|
||||
/* not found */
|
||||
if (pos == kh_end(cache->map)) {
|
||||
int rval;
|
||||
|
||||
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 {
|
||||
/* NO OP */
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
src/cache.h
33
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
|
||||
|
54
src/object.c
54
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)
|
||||
|
36
src/odb.c
36
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user