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

[PATCH 3/3] receive-pack: eliminate duplicate .have refs

From
Jeff King <peff@peff.net>
Date
May 19, 2011, 21:34 UTC
Message-ID
<20110519213446.GC29793@sigill.intra.peff.net>
In-Reply-To
<20110519213231.GA29702@sigill.intra.peff.net>

When receiving a push, we advertise ref tips from any alternate repositories, in case that helps the client send a smaller pack. Since these refs don't actually exist in the destination repository, we don't transmit the real ref names, but instead use the pseudo-ref ".have".

If your alternate has a large number of duplicate refs (for example, because it is aggregating objects from many related repositories, some of which will have the same tags and branch tips), then we will send each ".have $sha1" line multiple times. This is a pointless waste of bandwidth, as we are simply repeating the same fact to the client over and over.

This patch eliminates duplicate .have refs early on. It does so efficiently by sorting the complete list and skipping duplicates. This has the side effect of re-ordering the .have lines by ascending sha1; this isn't a problem, though, as the original order was meaningless.

There is a similar .have system in fetch-pack, but it does not suffer from the same problem. For each alternate ref we consider in fetch-pack, we actually open the object and mark it with the SEEN flag, so duplicates are automatically culled.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/receive-pack.c |   16 +++++++++++++---
 sha1-array.c           |   16 ++++++++++++++++
 sha1-array.h           |    6 ++++++
 3 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 6bb1281..e1a687a 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -10,6 +10,7 @@
 #include "remote.h"
 #include "transport.h"
 #include "string-list.h"
+#include "sha1-array.h"
 
 static const char receive_pack_usage[] = "git receive-pack <git-dir>";
 
@@ -731,14 +732,23 @@ static int delete_only(struct command *commands)
 	return 1;
 }
 
-static void add_one_alternate_ref(const struct ref *ref, void *unused)
+static void add_one_alternate_sha1(const unsigned char sha1[20], void *unused)
 {
-	add_extra_ref(".have", ref->old_sha1, 0);
+	add_extra_ref(".have", sha1, 0);
+}
+
+static void collect_one_alternate_ref(const struct ref *ref, void *data)
+{
+	struct sha1_array *sa = data;
+	sha1_array_append(sa, ref->old_sha1);
 }
 
 static void add_alternate_refs(void)
 {
-	for_each_alternate_ref(add_one_alternate_ref, NULL);
+	struct sha1_array sa = SHA1_ARRAY_INIT;
+	for_each_alternate_ref(collect_one_alternate_ref, &sa);
+	sha1_array_for_each_unique(&sa, add_one_alternate_sha1, NULL);
+	sha1_array_clear(&sa);
 }
 
 int cmd_receive_pack(int argc, const char **argv, const char *prefix)
diff --git a/sha1-array.c b/sha1-array.c
index 5b75a5a..b2f47f9 100644
--- a/sha1-array.c
+++ b/sha1-array.c
@@ -41,3 +41,19 @@ void sha1_array_clear(struct sha1_array *array)
 	array->alloc = 0;
 	array->sorted = 0;
 }
+
+void sha1_array_for_each_unique(struct sha1_array *array,
+				for_each_sha1_fn fn,
+				void *data)
+{
+	int i;
+
+	if (!array->sorted)
+		sha1_array_sort(array);
+
+	for (i = 0; i < array->nr; i++) {
+		if (i > 0 && !hashcmp(array->sha1[i], array->sha1[i-1]))
+			continue;
+		fn(array->sha1[i], data);
+	}
+}
diff --git a/sha1-array.h b/sha1-array.h
index 15d3b6b..4499b5d 100644
--- a/sha1-array.h
+++ b/sha1-array.h
@@ -15,4 +15,10 @@ void sha1_array_sort(struct sha1_array *array);
 int sha1_array_lookup(struct sha1_array *array, const unsigned char *sha1);
 void sha1_array_clear(struct sha1_array *array);
 
+typedef void (*for_each_sha1_fn)(const unsigned char sha1[20],
+				 void *data);
+void sha1_array_for_each_unique(struct sha1_array *array,
+				for_each_sha1_fn fn,
+				void *data);
+
 #endif /* SHA1_ARRAY_H */
-- 
1.7.5.8.ga95ab
Previous: Jeff KingNext: Junio C Hamano
Message 8 of 11 in “avoid duplicate .have lines”
  1. 0/3 avoid duplicate .have linesJeff King, May 19, 2011
  2. 1/3 refactor refs_from_alternate_cb to allow passing extra dataJeff King, May 19, 2011
  3. 2/3 bisect: refactor sha1_array into a generic sha1 listJeff King, May 19, 2011
  4. Thiago FarinaMay 20, 2011
  5. Jeff KingMay 20, 2011
  6. Junio C HamanoMay 20, 2011
  7. Jeff KingMay 23, 2011
  8. 3/3 receive-pack: eliminate duplicate .have refsJeff King, May 19, 2011
  9. Junio C HamanoMay 20, 2011
  10. Jeff KingMay 20, 2011
  11. Junio C HamanoMay 20, 2011

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.