Commit ed6648ba469c30b074e83bc102298ba0b183e231

Carlos Martín Nieto 2013-01-14T16:39:22

pack: evict objects from the cache in groups of eight This drops the cache eviction below libcrypto and zlib in the perf output. The number has been chosen empirically.

diff --git a/src/pack.c b/src/pack.c
index ddba5d6..d4ae290 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -116,29 +116,51 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset)
 	return entry;
 }
 
+#define BASE_DELTA_EVICT_NR 8
+
 /* Run with the cache lock held */
 static void free_lowest_entry(git_pack_cache *cache)
 {
-	git_pack_cache_entry *lowest = NULL, *entry;
-	khiter_t k, lowest_k;
+	git_pack_cache_entry *entry;
+	khiter_t k;
+
+	git_pack_cache_entry *lru[BASE_DELTA_EVICT_NR] = {NULL};
+	khiter_t lru_k[BASE_DELTA_EVICT_NR];
+	int i;
 
 	for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) {
 		if (!kh_exist(cache->entries, k))
 			continue;
 
 		entry = kh_value(cache->entries, k);
-		if (lowest == NULL || entry->last_usage < lowest->last_usage) {
-			lowest_k = k;
-			lowest = entry;
+
+		for (i = 0; i < BASE_DELTA_EVICT_NR; i++) {
+			if (lru[i] == NULL ||
+			    (entry->last_usage < lru[i]->last_usage &&
+			     entry->refcount.val == 0)) {
+				int j;
+
+				for (j = 0; j < i; j++) {
+					lru[j] = lru[j+1];
+					lru_k[j] = lru_k[j+1];
+				}
+
+				lru[i] = entry;
+				lru_k[i] = k;
+
+				/* jump out and try with the next entry */
+				break;
+			}
 		}
 	}
 
-	if (!lowest) /* there's nothing to free */
-		return;
-
-	cache->memory_used -= lowest->raw.len;
-	kh_del(off, cache->entries, lowest_k);
-	free_cache_object(lowest);
+	for (i = 0; i < BASE_DELTA_EVICT_NR; i++) {
+		if (lru[i]) {
+			cache->memory_used -= lru[i]->raw.len;
+			kh_del(off, cache->entries, lru_k[i]);
+			free_cache_object(lru[i]);
+		}
+	}
 }
 
 static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)