Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
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.
6 - */
7 -
8 - #include "cache.h"
9 -
10 - #include "repository.h"
11 - #include "commit.h"
12 - #include "thread-utils.h"
13 - #include "util.h"
14 - #include "odb.h"
15 - #include "object.h"
16 - #include "git2/oid.h"
17 -
18 - bool git_cache__enabled = true;
19 - ssize_t git_cache__max_storage = (256 * 1024 * 1024);
20 - git_atomic_ssize git_cache__current_storage = {0};
21 -
22 - static size_t git_cache__max_object_size[8] = {
23 - 0, /* GIT_OBJECT__EXT1 */
24 - 4096, /* GIT_OBJECT_COMMIT */
25 - 4096, /* GIT_OBJECT_TREE */
26 - 0, /* GIT_OBJECT_BLOB */
27 - 4096, /* GIT_OBJECT_TAG */
28 - 0, /* GIT_OBJECT__EXT2 */
29 - 0, /* GIT_OBJECT_OFS_DELTA */
30 - 0 /* GIT_OBJECT_REF_DELTA */
31 - };
32 -
33 40 2 int git_cache_set_max_object_size(git_object_t type, size_t size)
34 - {
35 40 2,3 if (type < 0 || (size_t)type >= ARRAY_SIZE(git_cache__max_object_size)) {
36 ##### 4 git_error_set(GIT_ERROR_INVALID, "type out of range");
37 ##### 5 return -1;
38 - }
39 -
40 40 6 git_cache__max_object_size[type] = size;
41 40 6 return 0;
42 - }
43 -
44 7882 2 int git_cache_init(git_cache *cache)
45 - {
46 7882 2 memset(cache, 0, sizeof(*cache));
47 -
48 7882 2,3 if ((git_oidmap_new(&cache->map)) < 0)
49 ##### 4 return -1;
50 -
51 7882 5,6 if (git_rwlock_init(&cache->lock)) {
52 ##### 7 git_error_set(GIT_ERROR_OS, "failed to initialize cache rwlock");
53 ##### 8 return -1;
54 - }
55 -
56 7875 9 return 0;
57 - }
58 -
59 - /* called with lock */
60 11972 2 static void clear_cache(git_cache *cache)
61 - {
62 11972 2 git_cached_obj *evict = NULL;
63 -
64 11972 2,3 if (git_cache_size(cache) == 0)
65 11970 4,12 return;
66 -
67 20268 5-8 git_oidmap_foreach_value(cache->map, evict, {
68 - git_cached_obj_decref(evict);
69 - });
70 -
71 2050 9 git_oidmap_clear(cache->map);
72 2050 10 git_atomic_ssize_add(&git_cache__current_storage, -cache->used_memory);
73 2050 11 cache->used_memory = 0;
74 - }
75 -
76 11968 2 void git_cache_clear(git_cache *cache)
77 - {
78 11972 2,3 if (git_rwlock_wrlock(&cache->lock) < 0)
79 11971 4,7 return;
80 -
81 11972 5 clear_cache(cache);
82 -
83 11970 6 git_rwlock_wrunlock(&cache->lock);
84 - }
85 -
86 7879 2 void git_cache_dispose(git_cache *cache)
87 - {
88 7879 2 git_cache_clear(cache);
89 7882 3 git_oidmap_free(cache->map);
90 7879 4 git_rwlock_free(&cache->lock);
91 7880 5 git__memzero(cache, sizeof(*cache));
92 7880 6 }
93 -
94 - /* Called with lock */
95 2019 2 static void cache_evict_entries(git_cache *cache)
96 - {
97 2019 2 size_t evict_count = git_cache_size(cache) / 2048, i;
98 2019 3 ssize_t evicted_memory = 0;
99 -
100 2019 3 if (evict_count < 8)
101 2019 4 evict_count = 8;
102 -
103 - /* do not infinite loop if there's not enough entries to evict */
104 2019 5,6 if (evict_count > git_cache_size(cache)) {
105 ##### 7 clear_cache(cache);
106 2019 8,19 return;
107 - }
108 -
109 2019 9 i = 0;
110 18171 9,16 while (evict_count > 0) {
111 - git_cached_obj *evict;
112 - const git_oid *key;
113 -
114 16152 10,11 if (git_oidmap_iterate((void **) &evict, cache->map, &i, &key) == GIT_ITEROVER)
115 ##### 12 break;
116 -
117 16152 13 evict_count--;
118 16152 13 evicted_memory += evict->size;
119 16152 13 git_oidmap_delete(cache->map, key);
120 16152 14,15 git_cached_obj_decref(evict);
121 - }
122 -
123 2019 17 cache->used_memory -= evicted_memory;
124 2019 17 git_atomic_ssize_add(&git_cache__current_storage, -evicted_memory);
125 - }
126 -
127 - 2 suppressed: function cannot be solved cache_should_store (automatic due to inconsistent arc counts in .gcda files)static bool cache_should_store(git_object_t object_type, size_t object_size)
128 - {
129 - 2 suppressed: function cannot be solved cache_should_store (automatic due to inconsistent arc counts in .gcda files) size_t max_size = git_cache__max_object_size[object_type];
130 - 2 suppressed: function cannot be solved cache_should_store (automatic due to inconsistent arc counts in .gcda files) return git_cache__enabled && object_size < max_size;
131 - }
132 -
133 - 2 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files)static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags)
134 - {
135 - git_cached_obj *entry;
136 -
137 - 2-4 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files) if (!git_cache__enabled || git_rwlock_rdlock(&cache->lock) < 0)
138 - 5 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files) return NULL;
139 -
140 - 6,7 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files) if ((entry = git_oidmap_get(cache->map, oid)) != NULL) {
141 - 8,9 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files) if (flags && entry->flags != flags) {
142 - 10 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files) entry = NULL;
143 - } else {
144 - 11 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files) git_cached_obj_incref(entry);
145 - }
146 - }
147 -
148 - 12 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files) git_rwlock_rdunlock(&cache->lock);
149 -
150 - 13 suppressed: function cannot be solved cache_get (automatic due to inconsistent arc counts in .gcda files) return entry;
151 - }
152 -
153 136922 2 static void *cache_store(git_cache *cache, git_cached_obj *entry)
154 - {
155 - git_cached_obj *stored_entry;
156 -
157 136922 2 git_cached_obj_incref(entry);
158 -
159 137943 3,4 if (!git_cache__enabled && cache->used_memory > 0) {
160 ##### 5 git_cache_clear(cache);
161 ##### 6 return entry;
162 - }
163 -
164 137943 7,8 if (!cache_should_store(entry->type, entry->size))
165 60006 9 return entry;
166 -
167 77953 10,11 if (git_rwlock_wrlock(&cache->lock) < 0)
168 ##### 12 return entry;
169 -
170 - /* soften the load on the cache */
171 77953 13 if (git_cache__current_storage.val > git_cache__max_storage)
172 2019 14 cache_evict_entries(cache);
173 -
174 - /* not found */
175 77953 15,16 if ((stored_entry = git_oidmap_get(cache->map, &entry->oid)) == NULL) {
176 34370 17,18 if (git_oidmap_set(cache->map, &entry->oid, entry) == 0) {
177 34370 19 git_cached_obj_incref(entry);
178 34370 20 cache->used_memory += entry->size;
179 34370 20,21 git_atomic_ssize_add(&git_cache__current_storage, (ssize_t)entry->size);
180 - }
181 - }
182 - /* found */
183 - else {
184 43583 22 if (stored_entry->flags == entry->flags) {
185 1974 23 git_cached_obj_decref(entry);
186 1974 24 git_cached_obj_incref(stored_entry);
187 1974 25 entry = stored_entry;
188 41609 26,27 } else if (stored_entry->flags == GIT_CACHE_STORE_RAW &&
189 30337 27 entry->flags == GIT_CACHE_STORE_PARSED) {
190 30337 28,29 if (git_oidmap_set(cache->map, &entry->oid, entry) == 0) {
191 30337 30 git_cached_obj_decref(stored_entry);
192 30337 31 git_cached_obj_incref(entry);
193 - } else {
194 ##### 32 git_cached_obj_decref(entry);
195 ##### 33 git_cached_obj_incref(stored_entry);
196 30337 34,35 entry = stored_entry;
197 - }
198 - } else {
199 - /* NO OP */
200 - }
201 - }
202 -
203 77953 36 git_rwlock_wrunlock(&cache->lock);
204 77932 37 return entry;
205 - }
206 -
207 79763 2 void *git_cache_store_raw(git_cache *cache, git_odb_object *entry)
208 - {
209 79763 2 entry->cached.flags = GIT_CACHE_STORE_RAW;
210 79763 2 return cache_store(cache, (git_cached_obj *)entry);
211 - }
212 -
213 57517 2 void *git_cache_store_parsed(git_cache *cache, git_object *entry)
214 - {
215 57517 2 entry->cached.flags = GIT_CACHE_STORE_PARSED;
216 57517 2 return cache_store(cache, (git_cached_obj *)entry);
217 - }
218 -
219 95656 2 git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid)
220 - {
221 95656 2 return cache_get(cache, oid, GIT_CACHE_STORE_RAW);
222 - }
223 -
224 ##### 2 git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid)
225 - {
226 ##### 2 return cache_get(cache, oid, GIT_CACHE_STORE_PARSED);
227 - }
228 -
229 250920 2 void *git_cache_get_any(git_cache *cache, const git_oid *oid)
230 - {
231 250920 2 return cache_get(cache, oid, GIT_CACHE_STORE_ANY);
232 - }
233 -
234 656418 2 void git_cached_obj_decref(void *_obj)
235 - {
236 656418 2 git_cached_obj *obj = _obj;
237 -
238 657563 2,3 if (git_atomic_dec(&obj->refcount) == 0) {
239 138095 4 switch (obj->flags) {
240 - case GIT_CACHE_STORE_RAW:
241 80561 5 git_odb_object__free(_obj);
242 80539 6 break;
243 -
244 - case GIT_CACHE_STORE_PARSED:
245 57534 7 git_object__free(_obj);
246 57557 8 break;
247 -
248 - default:
249 ##### 9 git__free(_obj);
250 ##### 10 break;
251 - }
252 - }
253 657564 11 }