cache.c 2.33 KB
Newer Older
Vicent Marti committed
1
/*
schu committed
2
 * Copyright (C) 2009-2012 the libgit2 contributors
Vicent Marti committed
3
 *
Vicent Marti committed
4 5
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
Vicent Marti committed
6 7 8 9 10 11 12 13
 */

#include "common.h"
#include "repository.h"
#include "commit.h"
#include "thread-utils.h"
#include "cache.h"

14
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
Vicent Marti committed
15 16 17 18 19 20 21 22 23 24 25
{
	if (size < 8)
		size = 8;

	/* round up size to closest power of 2 */
	size--;
	size |= size >> 1;
	size |= size >> 2;
	size |= size >> 4;
	size |= size >> 8;
	size |= size >> 16;
26
	size++;
Vicent Marti committed
27

28
	cache->size_mask = size - 1;
Vicent Marti committed
29 30 31
	cache->lru_count = 0;
	cache->free_obj = free_ptr;

32 33 34
	git_mutex_init(&cache->lock);

	cache->nodes = git__malloc(size * sizeof(git_cached_obj *));
35 36
	if (cache->nodes == NULL)
		return GIT_ENOMEM;
Vicent Marti committed
37

38
	memset(cache->nodes, 0x0, size * sizeof(git_cached_obj *));
39
	return GIT_SUCCESS;
Vicent Marti committed
40 41 42 43 44 45 46
}

void git_cache_free(git_cache *cache)
{
	size_t i;

	for (i = 0; i < (cache->size_mask + 1); ++i) {
47 48
		if (cache->nodes[i] != NULL)
			git_cached_obj_decref(cache->nodes[i], cache->free_obj);
Vicent Marti committed
49 50
	}

51
	git__free(cache->nodes);
Vicent Marti committed
52 53 54 55
}

void *git_cache_get(git_cache *cache, const git_oid *oid)
{
56
	uint32_t hash;
57
	git_cached_obj *node = NULL, *result = NULL;
Vicent Marti committed
58

59
	memcpy(&hash, oid->id, sizeof(hash));
Vicent Marti committed
60

61
	git_mutex_lock(&cache->lock);
62
	{
63 64 65 66 67
		node = cache->nodes[hash & cache->size_mask];

		if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) {
			git_cached_obj_incref(node);
			result = node;
Vicent Marti committed
68 69
		}
	}
70
	git_mutex_unlock(&cache->lock);
Vicent Marti committed
71

72
	return result;
Vicent Marti committed
73 74
}

75
void *git_cache_try_store(git_cache *cache, void *_entry)
Vicent Marti committed
76
{
77
	git_cached_obj *entry = _entry;
78
	uint32_t hash;
Vicent Marti committed
79

80
	memcpy(&hash, &entry->oid, sizeof(hash));
Vicent Marti committed
81 82 83

	/* increase the refcount on this object, because
	 * the cache now owns it */
Vicent Marti committed
84
	git_cached_obj_incref(entry);
85 86 87 88 89 90 91 92 93 94 95 96 97 98

	git_mutex_lock(&cache->lock);
	{
		git_cached_obj *node = cache->nodes[hash & cache->size_mask];

		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;
		} else {
			git_cached_obj_decref(node, cache->free_obj);
			cache->nodes[hash & cache->size_mask] = entry;
		}
Vicent Marti committed
99
	}
100
	git_mutex_unlock(&cache->lock);
Vicent Marti committed
101 102 103

	/* increase the refcount again, because we are
	 * returning it to the user */
Vicent Marti committed
104
	git_cached_obj_incref(entry);
Vicent Marti committed
105 106 107

	return entry;
}