Commit e4b4da14 by Vicent Martí

cache: Simplify locking mechanics

The object cache is mostly IO-bound, so it makes no sense to have a lock
per node.
parent 7a6f51de
...@@ -13,8 +13,6 @@ ...@@ -13,8 +13,6 @@
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr) int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
{ {
size_t i;
if (size < 8) if (size < 8)
size = 8; size = 8;
...@@ -25,20 +23,19 @@ int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_pt ...@@ -25,20 +23,19 @@ int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_pt
size |= size >> 4; size |= size >> 4;
size |= size >> 8; size |= size >> 8;
size |= size >> 16; size |= size >> 16;
size++;
cache->size_mask = size; cache->size_mask = size - 1;
cache->lru_count = 0; cache->lru_count = 0;
cache->free_obj = free_ptr; cache->free_obj = free_ptr;
cache->nodes = git__malloc((size + 1) * sizeof(cache_node)); git_mutex_init(&cache->lock);
cache->nodes = git__malloc(size * sizeof(git_cached_obj *));
if (cache->nodes == NULL) if (cache->nodes == NULL)
return GIT_ENOMEM; return GIT_ENOMEM;
for (i = 0; i < (size + 1); ++i) { memset(cache->nodes, 0x0, size * sizeof(git_cached_obj *));
git_mutex_init(&cache->nodes[i].lock);
cache->nodes[i].ptr = NULL;
}
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -47,10 +44,8 @@ void git_cache_free(git_cache *cache) ...@@ -47,10 +44,8 @@ void git_cache_free(git_cache *cache)
size_t i; size_t i;
for (i = 0; i < (cache->size_mask + 1); ++i) { for (i = 0; i < (cache->size_mask + 1); ++i) {
if (cache->nodes[i].ptr) if (cache->nodes[i] != NULL)
git_cached_obj_decref(cache->nodes[i].ptr, cache->free_obj); git_cached_obj_decref(cache->nodes[i], cache->free_obj);
git_mutex_free(&cache->nodes[i].lock);
} }
git__free(cache->nodes); git__free(cache->nodes);
...@@ -59,53 +54,54 @@ void git_cache_free(git_cache *cache) ...@@ -59,53 +54,54 @@ void git_cache_free(git_cache *cache)
void *git_cache_get(git_cache *cache, const git_oid *oid) void *git_cache_get(git_cache *cache, const git_oid *oid)
{ {
uint32_t hash; uint32_t hash;
cache_node *node = NULL; git_cached_obj *node = NULL, *result = NULL;
void *result = NULL;
memcpy(&hash, oid->id, sizeof(hash)); memcpy(&hash, oid->id, sizeof(hash));
node = &cache->nodes[hash & cache->size_mask];
git_mutex_lock(&node->lock); git_mutex_lock(&cache->lock);
{ {
if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) { node = cache->nodes[hash & cache->size_mask];
git_cached_obj_incref(node->ptr);
result = node->ptr; if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) {
git_cached_obj_incref(node);
result = node;
} }
} }
git_mutex_unlock(&node->lock); git_mutex_unlock(&cache->lock);
return result; return result;
} }
void *git_cache_try_store(git_cache *cache, void *entry) void *git_cache_try_store(git_cache *cache, void *_entry)
{ {
git_cached_obj *entry = _entry;
uint32_t hash; uint32_t hash;
const git_oid *oid;
cache_node *node = NULL;
oid = &((git_cached_obj*)entry)->oid; memcpy(&hash, &entry->oid, sizeof(hash));
memcpy(&hash, oid->id, sizeof(hash));
node = &cache->nodes[hash & cache->size_mask];
/* increase the refcount on this object, because /* increase the refcount on this object, because
* the cache now owns it */ * the cache now owns it */
git_cached_obj_incref(entry); git_cached_obj_incref(entry);
git_mutex_lock(&node->lock);
git_mutex_lock(&cache->lock);
if (node->ptr == NULL) { {
node->ptr = entry; git_cached_obj *node = cache->nodes[hash & cache->size_mask];
} else if (git_cached_obj_compare(node->ptr, oid) == 0) {
git_cached_obj_decref(entry, cache->free_obj); if (node == NULL) {
entry = node->ptr; cache->nodes[hash & cache->size_mask] = entry;
} else { } else if (git_oid_cmp(&node->oid, &entry->oid) == 0) {
git_cached_obj_decref(node->ptr, cache->free_obj); git_cached_obj_decref(entry, cache->free_obj);
node->ptr = entry; entry = node;
} else {
git_cached_obj_decref(node, cache->free_obj);
cache->nodes[hash & cache->size_mask] = entry;
}
} }
git_mutex_unlock(&cache->lock);
/* increase the refcount again, because we are /* increase the refcount again, because we are
* returning it to the user */ * returning it to the user */
git_cached_obj_incref(entry); git_cached_obj_incref(entry);
git_mutex_unlock(&node->lock);
return entry; return entry;
} }
...@@ -23,42 +23,32 @@ typedef struct { ...@@ -23,42 +23,32 @@ typedef struct {
} git_cached_obj; } git_cached_obj;
typedef struct { typedef struct {
git_cached_obj *ptr; git_cached_obj **nodes;
git_mutex lock; git_mutex lock;
} cache_node;
typedef struct {
cache_node *nodes;
unsigned int lru_count; unsigned int lru_count;
size_t size_mask; size_t size_mask;
git_cached_obj_freeptr free_obj; 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, size_t size, git_cached_obj_freeptr free_ptr);
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_try_store(git_cache *cache, void *entry);
void *git_cache_get(git_cache *cache, const git_oid *oid); void *git_cache_get(git_cache *cache, const git_oid *oid);
GIT_INLINE(void) git_cached_obj_incref(void *_obj)
GIT_INLINE(int) git_cached_obj_compare(git_cached_obj *obj, const git_oid *oid)
{
return git_oid_cmp(&obj->oid, oid);
}
GIT_INLINE(void) git_cached_obj_incref(git_cached_obj *obj)
{ {
git_cached_obj *obj = _obj;
git_atomic_inc(&obj->refcount); git_atomic_inc(&obj->refcount);
} }
GIT_INLINE(void) git_cached_obj_decref(git_cached_obj *obj, git_cached_obj_freeptr free_obj) 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) if (git_atomic_dec(&obj->refcount) == 0)
free_obj(obj); free_obj(obj);
} }
#endif #endif
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