See the comment. --- a/subversion/libsvn_subr/cache-membuffer.c 2014-02-12 21:53:58.547230675 +0000 +++ a/subversion/libsvn_subr/cache-membuffer.c 2014-02-12 22:02:11.039246322 +0000 @@ -639,9 +639,16 @@ drop_entry(svn_membuffer_t *cache, entry assert(idx <= last_in_group); /* update global cache usage counters + * + * cache->hit_count and entry->hit_count are incremented without proper mutual + * exclusion (only with read lock), so some increments get lost in multithreaded svnserve; + * as it's unlikely two threads access the same entry at once usually it leads to + * cache->hit_count being less than sum(entry->hit_count). So it may overflow + * during subtraction and lead to emptying the cache in ensure_data_insertable(). + * instead of killing the performance by mutual exclusion we just check for possible overflow. */ cache->used_entries--; - cache->hit_count -= entry->hit_count; + cache->hit_count = cache->hit_count < entry->hit_count ? 0 : cache->hit_count-entry->hit_count; cache->data_used -= entry->size; /* extend the insertion window, if the entry happens to border it @@ -802,7 +809,7 @@ let_entry_age(svn_membuffer_t *cache, en { apr_uint32_t hits_removed = (entry->hit_count + 1) >> 1; - cache->hit_count -= hits_removed; + cache->hit_count = cache->hit_count < hits_removed ? 0 : cache->hit_count-hits_removed; entry->hit_count -= hits_removed; }