git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 2/2] repack: avoid loosening promisor pack objects in partial clones

From
Rafael Silva <rafaeloliveira.cs@gmail.com>
Date
Apr 14, 2021, 19:14 UTC
Message-ID
<20210414191403.4387-3-rafaeloliveira.cs@gmail.com>
In-Reply-To
<20210414191403.4387-1-rafaeloliveira.cs@gmail.com>

When `-A` and `-d` are used together, besides packing all objects (-A) and removing redundant packs (-d), it also unpack all unreachable objects and deletes them by calling `git pruned-packed`. For a partial clone, that contains unreferenced objects, this results in unpacking all "promisor" objects and deleting them right after, which unnecessarily increases the `repack` execution time and disk usage during the unpacking of the objects.

For instance, a partially cloned repository that filters all the blob objects (e.g. "--filter=blob:none"), `repack` ends up unpacking all blobs into the filesystem that, depending on the repo size, makes nearly impossible to repack the operation before running out of disk.

For a partial clone, `git repack` calls `git pack-objects` twice: (1) for handle the "promisor" objects and (2) for performing the repack with --exclude-promisor-objects option, that results in unpacking and deleting of the objects. Given that we actually should keep the promisor objects, let's teach `repack` to tell `pack-objects` to --keep the old "promisor" pack file.

The --keep-pack option takes only a packfile name, but we concatenate both the path and the name in a single string. Instead, let's split them into separate string in order to easily pass the packfile name later.

Additionally, add a new perf test to evaluate the performance impact made by this changes (tested on git.git):

    Test            HEAD^                 HEAD
    ------------------------------------------------------------
    5600.5: gc      137.67(42.48+93.64)   8.08(6.91+1.45) -94.1%

In this particular script, the improvement is big because every object in the newly-cloned partial repository is a promisor object.

Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Rafael Silva <rafaeloliveira.cs@gmail.com>
---
 builtin/repack.c              | 9 +++++++--
 t/perf/p5600-partial-clone.sh | 4 ++++
 t/t5616-partial-clone.sh      | 9 +++++++++
 3 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/builtin/repack.c b/builtin/repack.c
index 6baaeb979c..0ecd76b79c 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -20,7 +20,7 @@ static int delta_base_offset = 1;
 static int pack_kept_objects = -1;
 static int write_bitmaps = -1;
 static int use_delta_islands;
-static char *packdir, *packtmp;
+static char *packdir, *packtmp_name, *packtmp;
 
 static const char *const git_repack_usage[] = {
 	N_("git repack [<options>]"),
@@ -533,7 +533,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	}
 
 	packdir = mkpathdup("%s/pack", get_object_directory());
-	packtmp = mkpathdup("%s/.tmp-%d-pack", packdir, (int)getpid());
+	packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
+	packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
 
 	sigchain_push_common(remove_pack_on_signal);
 
@@ -576,6 +577,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		repack_promisor_objects(&po_args, &names);
 
 		if (existing_packs.nr && delete_redundant) {
+			for_each_string_list_item(item, &names) {
+				strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
+					     packtmp_name, item->string);
+			}
 			if (unpack_unreachable) {
 				strvec_pushf(&cmd.args,
 					     "--unpack-unreachable=%s",
diff --git a/t/perf/p5600-partial-clone.sh b/t/perf/p5600-partial-clone.sh
index ca785a3341..a965f2c4d6 100755
--- a/t/perf/p5600-partial-clone.sh
+++ b/t/perf/p5600-partial-clone.sh
@@ -35,4 +35,8 @@ test_perf 'count non-promisor commits' '
 	git -C bare.git rev-list --all --count --exclude-promisor-objects
 '
 
+test_perf 'gc' '
+	git -C bare.git gc
+'
+
 test_done
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 5cb415386e..de77822735 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -548,6 +548,15 @@ test_expect_success 'fetch from a partial clone, protocol v2' '
 	grep "version 2" trace
 '
 
+test_expect_success 'repack does not loose all objects' '
+	rm -rf client &&
+	git clone --bare --filter=blob:none "file://$(pwd)/srv.bare" client &&
+	test_when_finished "rm -rf client" &&
+	git -C client repack -A -l -d --no-prune-packed &&
+	git -C client count-objects -v >object-count &&
+	grep "^prune-packable: 0" object-count
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
-- 
2.31.0.565.gcc42f43761
Previous: Rafael SilvaNext: Jonathan Tan
Message 29 of 46 in “rather slow 'git repack' in 'blob:none' partial clones”
  1. SZEDER GáborApr 3, 2021
  2. Rafael SilvaApr 5, 2021
  3. Jeff KingApr 7, 2021
  4. Jonathan TanApr 8, 2021
  5. Jeff KingApr 8, 2021
  6. Rafael SilvaApr 12, 2021
  7. SZEDER GáborApr 12, 2021
  8. Bryan TurnerApr 12, 2021
  9. Jeff KingApr 12, 2021
  10. Jeff KingApr 12, 2021
  11. 0/3 low-hanging performance fruit with promisor packsJeff King, Apr 13, 2021
  12. 1/3 is_promisor_object(): free tree buffer after parsingJeff King, Apr 13, 2021
  13. Junio C HamanoApr 13, 2021
  14. Jeff KingApr 14, 2021
  15. 2/3 lookup_unknown_object(): take a repository argumentJeff King, Apr 13, 2021
  16. 3/3 revision: avoid parsing with --exclude-promisor-objectsJeff King, Apr 13, 2021
  17. Junio C HamanoApr 13, 2021
  18. SZEDER GáborApr 13, 2021
  19. Jonathan TanApr 14, 2021
  20. Rafael SilvaApr 14, 2021
  21. SZEDER GáborApr 13, 2021
  22. Jeff KingApr 14, 2021
  23. SZEDER GáborApr 11, 2021
  24. Rafael SilvaApr 12, 2021
  25. 0/2 prevent `repack` to unpack and delete promisor objectsRafael Silva, Apr 14, 2021
  26. 1/2 repack: teach --no-prune-packed to skip `git prune-packed`Rafael Silva, Apr 14, 2021
  27. Jonathan TanApr 14, 2021
  28. Rafael SilvaApr 18, 2021
  29. 2/2 repack: avoid loosening promisor pack objects in partial clonesRafael Silva, Apr 14, 2021
  30. Jonathan TanApr 15, 2021
  31. Junio C HamanoApr 15, 2021
  32. Jeff KingApr 15, 2021
  33. Jeff KingApr 15, 2021
  34. Rafael SilvaApr 18, 2021
  35. Junio C HamanoApr 15, 2021
  36. Rafael SilvaApr 18, 2021
  37. Junio C HamanoApr 14, 2021
  38. Jeff KingApr 15, 2021
  39. Rafael SilvaApr 18, 2021
  40. 0/1 prevent `repack` to unpack and delete promisor objectsRafael Silva, Apr 18, 2021
  41. 1/1 repack: avoid loosening promisor objects in partial clonesRafael Silva, Apr 18, 2021
  42. Jonathan TanApr 19, 2021
  43. Rafael SilvaApr 21, 2021
  44. Junio C HamanoApr 19, 2021
  45. Rafael SilvaApr 21, 2021
  46. repack: avoid loosening promisor objects in partial clonesRafael Silva, Apr 21, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.