t/perf: add perf test for ref tombstone scenarios
Add performance tests for update-ref when many tombstones are present in a reftable. The first test exercises the scenario where all refs are deleted (creating tombstones) and then re-created with the same names, which currently exhibits quadratic behavior. The second test uses a separate repository with an asymmetric variant where refs are deleted and then new, differently-named refs are created. When the tombstones sort after the new refs, every create scans all tombstones, making this case even worse than re-creating the same refs. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Kristofer Karlsson <krka@spotify.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Kristofer Karlsson committed
Jul 10, 2026 at 10:36 UTC
13d8160f4922d88aa26eb2eea74cab3fa29848b8
1 file changed
+46
t/perf/p1401-ref-store-tombstones.sh
+46
new file mode 100755
index 0000000000..9e3d8031aa
--- /dev/null
+++ b/t/perf/p1401-ref-store-tombstones.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+test_description="Tests performance of ref operations with many tombstones"
+
+. ./perf-lib.sh
+
+test_expect_success "setup" '
+ git init --ref-format=reftable repo &&
+ blob=$(echo foo | git -C repo hash-object -w --stdin) &&
+ for i in $(test_seq 8000)
+ do
+ printf "create refs/tags/tag-%d %s\n" "$i" "$blob" ||
+ return 1
+ done >repo/input &&
+ git -C repo update-ref --stdin <repo/input &&
+ git -C repo for-each-ref --format="delete %(refname)" |
+ git -C repo update-ref --stdin
+'
+
+test_perf "recreate refs after mass delete" '
+ git -C repo update-ref --stdin <repo/input &&
+ git -C repo for-each-ref --format="delete %(refname)" |
+ git -C repo update-ref --stdin
+'
+
+test_expect_success "setup asymmetric" '
+ git init --ref-format=reftable repo2 &&
+ blob=$(echo foo | git -C repo2 hash-object -w --stdin) &&
+ for i in $(test_seq 8000)
+ do
+ printf "create refs/tags/old-%d %s\n" "$i" "$blob" ||
+ return 1
+ done >repo2/input-old &&
+ sed "s/old-/new-/" <repo2/input-old >repo2/input-new &&
+ git -C repo2 update-ref --stdin <repo2/input-old &&
+ git -C repo2 for-each-ref --format="delete %(refname)" |
+ git -C repo2 update-ref --stdin
+'
+
+test_perf "create new refs after deleting differently-named refs" '
+ git -C repo2 update-ref --stdin <repo2/input-new &&
+ git -C repo2 for-each-ref --format="delete %(refname)" refs/tags/ |
+ git -C repo2 update-ref --stdin
+'
+
+test_done