diff options
-rw-r--r-- | Documentation/config.txt | 13 | ||||
-rw-r--r-- | cache.h | 1 | ||||
-rw-r--r-- | config.c | 5 | ||||
-rw-r--r-- | environment.c | 1 | ||||
-rw-r--r-- | sha1_file.c | 30 |
5 files changed, 46 insertions, 4 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt index 66886424b..cf1e04038 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -240,6 +240,19 @@ the largest projects. You probably do not need to adjust this value. + Common unit suffixes of 'k', 'm', or 'g' are supported. +core.deltaBaseCacheLimit:: + Maximum number of bytes to reserve for caching base objects + that multiple deltafied objects reference. By storing the + entire decompressed base objects in a cache Git is able + to avoid unpacking and decompressing frequently used base + objects multiple times. ++ +Default is 16 MiB on all platforms. This should be reasonable +for all users/operating systems, except on the largest projects. +You probably do not need to adjust this value. ++ +Common unit suffixes of 'k', 'm', or 'g' are supported. + alias.*:: Command aliases for the gitlink:git[1] command wrapper - e.g. after defining "alias.last = cat-file commit HEAD", the invocation @@ -228,6 +228,7 @@ extern const char *apply_default_whitespace; extern int zlib_compression_level; extern size_t packed_git_window_size; extern size_t packed_git_limit; +extern size_t delta_base_cache_limit; extern int auto_crlf; #define GIT_REPO_VERSION 0 @@ -331,6 +331,11 @@ int git_default_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.deltabasecachelimit")) { + delta_base_cache_limit = git_config_int(var, value); + return 0; + } + if (!strcmp(var, "core.autocrlf")) { if (value && !strcasecmp(value, "input")) { auto_crlf = -1; diff --git a/environment.c b/environment.c index fff4a4da5..22316597d 100644 --- a/environment.c +++ b/environment.c @@ -27,6 +27,7 @@ const char *apply_default_whitespace; int zlib_compression_level = Z_DEFAULT_COMPRESSION; size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE; size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT; +size_t delta_base_cache_limit = 16 * 1024 * 1024; int pager_in_use; int pager_use_color = 1; int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */ diff --git a/sha1_file.c b/sha1_file.c index ee64865b6..b0b21776e 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1354,6 +1354,7 @@ static void *unpack_compressed_entry(struct packed_git *p, #define MAX_DELTA_CACHE (256) +static size_t delta_base_cached; static struct delta_base_cache_entry { struct packed_git *p; off_t base_offset; @@ -1384,8 +1385,10 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset, return unpack_entry(p, base_offset, type, base_size); found_cache_entry: - if (!keep_cache) + if (!keep_cache) { ent->data = NULL; + delta_base_cached -= ent->size; + } else { ret = xmalloc(ent->size + 1); memcpy(ret, ent->data, ent->size); @@ -1396,14 +1399,33 @@ found_cache_entry: return ret; } +static inline void release_delta_base_cache(struct delta_base_cache_entry *ent) +{ + if (ent->data) { + free(ent->data); + ent->data = NULL; + delta_base_cached -= ent->size; + } +} + static void add_delta_base_cache(struct packed_git *p, off_t base_offset, void *base, unsigned long base_size, enum object_type type) { - unsigned long hash = pack_entry_hash(p, base_offset); + unsigned long i, hash = pack_entry_hash(p, base_offset); struct delta_base_cache_entry *ent = delta_base_cache + hash; - if (ent->data) - free(ent->data); + release_delta_base_cache(ent); + delta_base_cached += base_size; + for (i = 0; delta_base_cached > delta_base_cache_limit + && i < ARRAY_SIZE(delta_base_cache); i++) { + struct delta_base_cache_entry *f = delta_base_cache + i; + if (f->type == OBJ_BLOB) + release_delta_base_cache(f); + } + for (i = 0; delta_base_cached > delta_base_cache_limit + && i < ARRAY_SIZE(delta_base_cache); i++) + release_delta_base_cache(delta_base_cache + i); + ent->p = p; ent->base_offset = base_offset; ent->type = type; |