]> git.ipfire.org Git - thirdparty/git.git/commitdiff
index-pack: retain child bases in delta cache
authorArijit Banerjee <arijit@effectiveailabs.com>
Wed, 3 Jun 2026 00:05:17 +0000 (00:05 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 3 Jun 2026 00:17:10 +0000 (09:17 +0900)
When resolving a delta whose result has children of its own,
index-pack adds the result to work_head, accounts its data in
base_cache_used, and calls prune_base_data(). It then immediately frees
that same data.

This bypasses the existing delta base cache policy and can force later
descendants to reconstruct the queued base again. Let the existing
delta_base_cache_limit pruning policy decide whether to keep or evict
the data instead.

This does not add a new cache or increase the cache limit. The object
data is already accounted in base_cache_used before prune_base_data()
runs. Once all direct children of a base have been dispatched, and no
thread is actively retaining that base for patch_delta(), release the
cached bytes. The base_data struct itself remains alive until the
existing children_remaining bookkeeping says the whole subtree is done.

On a quiet Ubuntu 24.04 VM with 16 vCPUs, 32 GiB RAM, and local SSD,
standard p5302-pack-index.sh runs improved as follows:

  libgit2:  3.17(11.49+0.60)  ->   2.69(10.52+0.28), 15.1% faster
  redis:    5.84(15.56+0.63)  ->   4.95(14.05+0.32), 15.2% faster
  git.git: 11.17(38.04+1.29)  ->   9.67(35.29+0.60), 13.4% faster
  cpython: 32.69(117.85+4.37) ->  28.60(109.25+1.91), 12.5% faster
  linux:  279.22(797.69+40.86) -> 236.34(723.13+19.02), 15.4% faster

The linux p5302 number is from a single repeat; the others are from the
default three repeats.

End-to-end local full-clone spot checks also improved:

  libgit2:  5.00s ->   4.54s, 9.2% faster
  redis:    8.75s ->   7.92s, 9.5% faster
  git.git: 25.04s ->  23.71s, 5.3% faster
  cpython: 56.72s ->  55.94s, 1.4% faster
  linux:  556.17s -> 523.83s, 5.8% faster

t/t5302-pack-index.sh passed, and GitGitGadget's linux-leaks CI also
exercised that test under SANITIZE=leak.

Signed-off-by: Arijit Banerjee <arijit@effectiveailabs.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/index-pack.c

index cf0bd8280dca83e9da845e4010d9d0c4d0e7d5d4..00b4dff4198a9228cc39b5fda84426db845a1113 100644 (file)
@@ -433,6 +433,12 @@ static void free_base_data(struct base_data *c)
        }
 }
 
+static int base_data_has_remaining_direct_children(struct base_data *c)
+{
+       return c->ref_first <= c->ref_last ||
+              c->ofs_first <= c->ofs_last;
+}
+
 static void prune_base_data(struct base_data *retain)
 {
        struct list_head *pos;
@@ -1201,8 +1207,12 @@ static void *threaded_second_pass(void *data)
                }
 
                work_lock();
-               if (parent)
+               if (parent) {
                        parent->retain_data--;
+                       if (!parent->retain_data &&
+                           !base_data_has_remaining_direct_children(parent))
+                               free_base_data(parent);
+               }
 
                if (child && child->data) {
                        /*
@@ -1212,7 +1222,6 @@ static void *threaded_second_pass(void *data)
                        list_add(&child->list, &work_head);
                        base_cache_used += child->size;
                        prune_base_data(NULL);
-                       free_base_data(child);
                } else if (child) {
                        /*
                         * This child does not have its own children. It may be