summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config.txt13
-rw-r--r--cache.h1
-rw-r--r--config.c5
-rw-r--r--environment.c1
-rw-r--r--sha1_file.c30
5 files changed, 46 insertions, 4 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 66886424bb..cf1e040381 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
diff --git a/cache.h b/cache.h
index 5396d3366d..1b50a742a3 100644
--- a/cache.h
+++ b/cache.h
@@ -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
diff --git a/config.c b/config.c
index d537311ae1..6479855723 100644
--- a/config.c
+++ b/config.c
@@ -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 fff4a4da50..22316597df 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 ee64865b60..b0b21776e7 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;