2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
9 #include "repository.h"
11 #include "thread-utils.h"
20 size_t git_cache__max_object_size
[8] = {
21 0, /* GIT_OBJ__EXT1 */
22 4096, /* GIT_OBJ_COMMIT */
23 4096, /* GIT_OBJ_TREE */
25 4096, /* GIT_OBJ_TAG */
26 0, /* GIT_OBJ__EXT2 */
27 0, /* GIT_OBJ_OFS_DELTA */
28 0 /* GIT_OBJ_REF_DELTA */
31 void git_cache_dump_stats(git_cache
*cache
)
33 git_cached_obj
*object
;
35 if (kh_size(cache
->map
) == 0)
38 printf("Cache %p: %d items cached, %d bytes\n",
39 cache
, kh_size(cache
->map
), (int)cache
->used_memory
);
41 kh_foreach_value(cache
->map
, object
, {
43 printf(" %s%c %s (%d)\n",
44 git_object_type2string(object
->type
),
45 object
->flags
== GIT_CACHE_STORE_PARSED
? '*' : ' ',
46 git_oid_tostr(oid_str
, sizeof(oid_str
), &object
->oid
),
52 int git_cache_init(git_cache
*cache
)
54 cache
->used_memory
= 0;
55 cache
->map
= git_oidmap_alloc();
56 git_mutex_init(&cache
->lock
);
60 void git_cache_free(git_cache
*cache
)
62 git_oidmap_free(cache
->map
);
63 git_mutex_free(&cache
->lock
);
66 /* Call with lock, yo */
67 static void cache_evict_entries(git_cache
*cache
, size_t evict_count
)
69 uint32_t seed
= rand();
71 /* do not infinite loop if there's not enough entries to evict */
72 if (evict_count
> kh_size(cache
->map
))
75 while (evict_count
> 0) {
76 khiter_t pos
= seed
++ % kh_end(cache
->map
);
78 if (kh_exist(cache
->map
, pos
)) {
79 git_cached_obj
*evict
= kh_val(cache
->map
, pos
);
82 cache
->used_memory
-= evict
->size
;
83 git_cached_obj_decref(evict
);
85 kh_del(oid
, cache
->map
, pos
);
90 static bool cache_should_store(git_otype object_type
, size_t object_size
)
92 size_t max_size
= git_cache__max_object_size
[object_type
];
94 if (max_size
== 0 || object_size
> max_size
)
100 static void *cache_get(git_cache
*cache
, const git_oid
*oid
, unsigned int flags
)
103 git_cached_obj
*entry
= NULL
;
105 if (git_mutex_lock(&cache
->lock
) < 0)
108 pos
= kh_get(oid
, cache
->map
, oid
);
109 if (pos
!= kh_end(cache
->map
)) {
110 entry
= kh_val(cache
->map
, pos
);
112 if (flags
&& entry
->flags
!= flags
) {
115 git_cached_obj_incref(entry
);
119 git_mutex_unlock(&cache
->lock
);
124 static void *cache_store(git_cache
*cache
, git_cached_obj
*entry
)
128 git_cached_obj_incref(entry
);
130 if (!cache_should_store(entry
->type
, entry
->size
))
133 if (git_mutex_lock(&cache
->lock
) < 0)
136 pos
= kh_get(oid
, cache
->map
, &entry
->oid
);
139 if (pos
== kh_end(cache
->map
)) {
142 pos
= kh_put(oid
, cache
->map
, &entry
->oid
, &rval
);
144 kh_key(cache
->map
, pos
) = &entry
->oid
;
145 kh_val(cache
->map
, pos
) = entry
;
146 git_cached_obj_incref(entry
);
147 cache
->used_memory
+= entry
->size
;
152 git_cached_obj
*stored_entry
= kh_val(cache
->map
, pos
);
154 if (stored_entry
->flags
== entry
->flags
) {
155 git_cached_obj_decref(entry
);
156 git_cached_obj_incref(stored_entry
);
157 entry
= stored_entry
;
158 } else if (stored_entry
->flags
== GIT_CACHE_STORE_RAW
&&
159 entry
->flags
== GIT_CACHE_STORE_PARSED
) {
160 git_cached_obj_decref(stored_entry
);
161 git_cached_obj_incref(entry
);
163 kh_key(cache
->map
, pos
) = &entry
->oid
;
164 kh_val(cache
->map
, pos
) = entry
;
170 git_mutex_unlock(&cache
->lock
);
174 void *git_cache_store_raw(git_cache
*cache
, git_odb_object
*entry
)
176 entry
->cached
.flags
= GIT_CACHE_STORE_RAW
;
177 return cache_store(cache
, (git_cached_obj
*)entry
);
180 void *git_cache_store_parsed(git_cache
*cache
, git_object
*entry
)
182 entry
->cached
.flags
= GIT_CACHE_STORE_PARSED
;
183 return cache_store(cache
, (git_cached_obj
*)entry
);
186 git_odb_object
*git_cache_get_raw(git_cache
*cache
, const git_oid
*oid
)
188 return cache_get(cache
, oid
, GIT_CACHE_STORE_RAW
);
191 git_object
*git_cache_get_parsed(git_cache
*cache
, const git_oid
*oid
)
193 return cache_get(cache
, oid
, GIT_CACHE_STORE_PARSED
);
196 void *git_cache_get_any(git_cache
*cache
, const git_oid
*oid
)
198 return cache_get(cache
, oid
, GIT_CACHE_STORE_ANY
);
201 void git_cached_obj_decref(void *_obj
)
203 git_cached_obj
*obj
= _obj
;
205 if (git_atomic_dec(&obj
->refcount
) == 0) {
206 switch (obj
->flags
) {
207 case GIT_CACHE_STORE_RAW
:
208 git_odb_object__free(_obj
);
211 case GIT_CACHE_STORE_PARSED
:
212 git_object__free(_obj
);