mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-06 15:29:22 +00:00
cache: Drop cuckoo hashing
Now we use a simple closed-addressing cache. Cuckoo hashing was creating too many issues with race conditions. Fuck that. Let's see what happens performance wise, we may have to roll back or come up with another way to implement an efficient multi-threaded cache.
This commit is contained in:
parent
3de79280e3
commit
335d6c9980
86
src/cache.c
86
src/cache.c
@ -29,9 +29,6 @@
|
|||||||
#include "thread-utils.h"
|
#include "thread-utils.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
#define GIT_CACHE_OPENADR 3
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
size_t i;
|
||||||
@ -58,7 +55,6 @@ int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_pt
|
|||||||
for (i = 0; i < (size + 1); ++i) {
|
for (i = 0; i < (size + 1); ++i) {
|
||||||
git_mutex_init(&cache->nodes[i].lock);
|
git_mutex_init(&cache->nodes[i].lock);
|
||||||
cache->nodes[i].ptr = NULL;
|
cache->nodes[i].ptr = NULL;
|
||||||
cache->nodes[i].lru = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
@ -81,93 +77,53 @@ 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)
|
||||||
{
|
{
|
||||||
const uint32_t *hash;
|
const uint32_t *hash;
|
||||||
size_t i, pos, found = 0;
|
|
||||||
cache_node *node = NULL;
|
cache_node *node = NULL;
|
||||||
|
void *result = NULL;
|
||||||
|
|
||||||
hash = (const uint32_t *)oid->id;
|
hash = (const uint32_t *)oid->id;
|
||||||
|
node = &cache->nodes[hash[0] & cache->size_mask];
|
||||||
|
|
||||||
for (i = 0; !found && i < GIT_CACHE_OPENADR; ++i) {
|
git_mutex_lock(&node->lock);
|
||||||
pos = hash[i] & cache->size_mask;
|
{
|
||||||
node = &cache->nodes[pos];
|
if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) {
|
||||||
|
git_cached_obj_incref(node->ptr);
|
||||||
git_mutex_lock(&node->lock);
|
result = node->ptr;
|
||||||
{
|
|
||||||
if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) {
|
|
||||||
git_cached_obj_incref(node->ptr);
|
|
||||||
node->lru = ++cache->lru_count;
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
git_mutex_unlock(&node->lock);
|
|
||||||
}
|
}
|
||||||
|
git_mutex_unlock(&node->lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
return found ? node->ptr : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *git_cache_try_store(git_cache *cache, void *entry)
|
void *git_cache_try_store(git_cache *cache, void *entry)
|
||||||
{
|
{
|
||||||
cache_node *nodes[GIT_CACHE_OPENADR], *lru_node;
|
|
||||||
const uint32_t *hash;
|
const uint32_t *hash;
|
||||||
const git_oid *oid;
|
const git_oid *oid;
|
||||||
size_t i, j, node_count;
|
cache_node *node = NULL;
|
||||||
|
|
||||||
oid = &((git_cached_obj*)entry)->oid;
|
oid = &((git_cached_obj*)entry)->oid;
|
||||||
hash = (const uint32_t *)oid->id;
|
hash = (const uint32_t *)oid->id;
|
||||||
|
node = &cache->nodes[hash[0] & 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);
|
||||||
|
|
||||||
node_count = 0;
|
if (node->ptr == NULL) {
|
||||||
for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
|
node->ptr = entry;
|
||||||
size_t pos = hash[i] & cache->size_mask;
|
} else if (git_cached_obj_compare(node->ptr, oid) == 0) {
|
||||||
cache_node *node = &cache->nodes[pos];
|
git_cached_obj_decref(entry, cache->free_obj);
|
||||||
|
entry = node->ptr;
|
||||||
for (j = 0; j < node_count; ++j)
|
} else {
|
||||||
if (nodes[j] == node)
|
git_cached_obj_decref(node->ptr, cache->free_obj);
|
||||||
break;
|
node->ptr = entry;
|
||||||
|
|
||||||
if (j == node_count) {
|
|
||||||
nodes[node_count++] = node;
|
|
||||||
git_mutex_lock(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lru_node = nodes[0];
|
|
||||||
|
|
||||||
for (i = 0; i < node_count; ++i) {
|
|
||||||
|
|
||||||
if (nodes[i]->ptr == NULL) {
|
|
||||||
nodes[i]->ptr = entry;
|
|
||||||
nodes[i]->lru = ++cache->lru_count;
|
|
||||||
break;
|
|
||||||
} else if (git_cached_obj_compare(nodes[i]->ptr, oid) == 0) {
|
|
||||||
git_cached_obj_decref(entry, cache->free_obj);
|
|
||||||
entry = nodes[i]->ptr;
|
|
||||||
nodes[i]->lru = ++cache->lru_count;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodes[i]->lru < lru_node->lru)
|
|
||||||
lru_node = nodes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == node_count) {
|
|
||||||
void *old_entry = lru_node->ptr;
|
|
||||||
assert(old_entry);
|
|
||||||
|
|
||||||
git_cached_obj_decref(old_entry, cache->free_obj);
|
|
||||||
lru_node->ptr = entry;
|
|
||||||
lru_node->lru = ++cache->lru_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
||||||
for (i = 0; i < node_count; ++i)
|
|
||||||
git_mutex_unlock(&nodes[i]->lock);
|
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
git_cached_obj *ptr;
|
git_cached_obj *ptr;
|
||||||
git_mutex lock;
|
git_mutex lock;
|
||||||
unsigned int lru;
|
|
||||||
} cache_node;
|
} cache_node;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user