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

Re: [PATCH 2/6] sha1-lookup: handle duplicate keys with GIT_USE_LOOKUP

From
Jeff King <peff@peff.net>
Date
Aug 23, 2013, 18:24 UTC
Message-ID
<20130823182409.GA30130@sigill.intra.peff.net>
In-Reply-To
<xmqqob8opdey.fsf@gitster.dls.corp.google.com>
On Fri, Aug 23, 2013 at 09:41:57AM -0700, Junio C Hamano wrote:
Show 20 quoted lines
> Jeff King <peff@peff.net> writes:
> 
> > Furthermore, we know that one of our endpoints must be
> > the edge of the run of duplicates. For example, given this
> > sequence:
> >
> >  idx 0 1 2 3 4 5
> >  key A C C C C D
> >
> > If we are searching for "B", we might hit the duplicate run
> > at lo=1, hi=3 (e.g., by first mi=3, then mi=0). But we can
> > never have lo > 1, because B < C. That is, if our key is
> > less than the run, we know that "lo" is the edge, but we can
> > say nothing of "hi". Similarly, if our key is greater than
> > the run, we know that "hi" is the edge, but we can say
> > nothing of "lo". But that is enough for us to return not
> > only "not found", but show the position at which we would
> > insert the new item.
> 
> This is somewhat tricky and may deserve an in-code comment.

Do you want me to re-roll, pushing it down into the comment, or do you want to mark it up yourself? I think there might be some value in the latter as your re-writing of it as a comment may cross-check that my logic is sound.

Show 9 quoted lines
> > +			if (ofs == 20) {
> > +				mi = lo;
> > +				mi_key = base + elem_size * mi + key_offset;
> > +				cmp = memcmp(mi_key, key, 20);
> 
> It think we already know that mi_key[0:ofs_0] and key[0:ofs_0] are
> the same at this point and we do not have to compare full 20 bytes
> again, but this is done only once and a better readablity of the
> above trumps micro-optimization possibility, I think.

Yes, I had the same idea, and came to the same conclusion. Though if anybody did want to try it, note that we have just overwritten the old ofs_0, so you would want to bump the new code up above that line).

Show 5 quoted lines
> > +uint32_octal() {
> 
> micronit (style):
> 
> 	uint32_octal () {

Hmph. I always forget which one we prefer, and we seem to have equal numbers of both already. Again, want a re-roll or to mark it up yourself?

Show 10 quoted lines
> > +# Print the pack data for object $1, as a delta against object $2 (or as a full
> > +# object if $2 is missing or empty). The output is suitable for including
> > +# directly in the packfile, and represents the entirety of the object entry.
> > +# Doing this on the fly (especially picking your deltas) is quite tricky, so we
> > +# have hardcoded some well-known objects. See the case statements below for the
> > +# complete list.
> 
> Cute ;-) I like the idea of having this function with a right API in
> place, and cheating by limiting its implementation to what is
> necessary.

Just for reference, the procedure I used to generate the "base" data is reasonably straight forward:

  sha1=$(printf %s "$content" | git hash-object -w --stdin)
  echo $sha1 | git pack-objects --stdout >tmp.pack
  tail -c +13 tmp.pack >no-header.pack
  head -c -20 no-header.pack >no-trailer.pack
  od -b no-trailer.pack | grep ' ' | cut -d' ' -f2- | tr ' ' '\\'

Since we want binary, we can skip the "od" call at the end (I needed it to convert to something readable to hand "printf"). But "head -c" is not portable, nor is head with a negative count.

To find items in the same fanout, I just used for-loops to calculate the sha1s of all 2-byte blobs. And that is why we have the odd magic "\7\76" blob.

Making the deltas was considerably less elegant, since we cannot provoke pack-objects to pick arbitrary deltas (and it will not even try to delta tiny objects, anyway, which would bloat our samples). I ended up with the horrible patch below. We _could_ clean it up (error-checking? Who needs it?) and make it a debug-and-testing-only option for pack-objects, but I just didn't think the grossness was worth it. Still, it's probably worth documenting here on the list in case somebody else ever needs to add new samples to lib-pack.sh.

---
 builtin/pack-objects.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 8da2a66..e8937f5 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2442,6 +2442,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 	const char *rp_av[6];
 	int rp_ac = 0;
 	int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
+	int magic = 0;
 	struct option pack_objects_options[] = {
 		OPT_SET_INT('q', "quiet", &progress,
 			    N_("do not show progress meter"), 0),
@@ -2505,6 +2506,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 			    N_("pack compression level")),
 		OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
 			    N_("do not hide commits by grafts"), 0),
+		OPT_BOOL(0, "magic", &magic, "make deltas"),
 		OPT_END(),
 	};
 
@@ -2520,6 +2522,34 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, pack_objects_options,
 			     pack_usage, 0);
 
+	if (magic) {
+		unsigned char sha1[20];
+		struct delta_index *index;
+		void *src, *trg, *delta;
+		enum object_type src_type, trg_type;
+		unsigned long src_size, trg_size, delta_size, z_delta_size;
+		unsigned char header[10];
+		unsigned long header_len;
+
+		get_sha1(argv[0], sha1);
+		trg = read_sha1_file(sha1, &trg_type, &trg_size);
+
+		get_sha1(argv[1], sha1);
+		src = read_sha1_file(sha1, &src_type, &src_size);
+
+		index = create_delta_index(src, src_size);
+		delta = create_delta(index, trg, trg_size, &delta_size, 8192);
+
+		z_delta_size = do_compress(&delta, delta_size);
+		header_len = encode_in_pack_object_header(OBJ_REF_DELTA, delta_size,
+							  header);
+		fwrite(header, 1, header_len, stdout);
+		fwrite(sha1, 1, 20, stdout);
+		fwrite(delta, 1, z_delta_size, stdout);
+		return 0;
+	}
+
+
 	if (argc) {
 		base_name = argv[0];
 		argc--;
Previous: Junio C HamanoNext: Nicolas Pitre
Message 15 of 37 in “duplicate objects in packfile”
  1. Jeff KingAug 14, 2013
  2. Junio C HamanoAug 14, 2013
  3. Junio C HamanoAug 14, 2013
  4. Nicolas PitreAug 14, 2013
  5. Jeff KingAug 16, 2013
  6. 0/4 duplicate objects in packfilesJeff King, Aug 21, 2013
  7. 1/4 sha1-lookup: handle duplicate keys with GIT_USE_LOOKUPJeff King, Aug 21, 2013
  8. 2/4 index-pack: optionally reject packs with duplicate objectsJeff King, Aug 21, 2013
  9. Duy NguyenAug 22, 2013
  10. Jeff KingAug 22, 2013
  11. 0/6 duplicate objects and delta cycles, oh my!Jeff King, Aug 22, 2013
  12. 1/6 test-sha1: add a binary output modeJeff King, Aug 22, 2013
  13. 2/6 sha1-lookup: handle duplicate keys with GIT_USE_LOOKUPJeff King, Aug 22, 2013
  14. Junio C HamanoAug 23, 2013
  15. Jeff KingAug 23, 2013
  16. Nicolas PitreAug 23, 2013
  17. Jeff KingAug 23, 2013
  18. 0/6 duplicate objects and delta cyclesJeff King, Aug 24, 2013
  19. 1/6 test-sha1: add a binary output modeJeff King, Aug 24, 2013
  20. 2/6 sha1-lookup: handle duplicate keys with GIT_USE_LOOKUPJeff King, Aug 24, 2013
  21. 3/6 add tests for indexing packs with delta cyclesJeff King, Aug 24, 2013
  22. 4/6 test index-pack on packs with recoverable delta cyclesJeff King, Aug 24, 2013
  23. 5/6 index-pack: optionally reject packs with duplicate objectsJeff King, Aug 24, 2013
  24. 6/6 default pack.indexDuplicates to falseJeff King, Aug 24, 2013
  25. Johannes SixtAug 23, 2013
  26. Jeff KingAug 23, 2013
  27. 3/6 add tests for indexing packs with delta cyclesJeff King, Aug 22, 2013
  28. 4/6 test index-pack on packs with recoverable delta cyclesJeff King, Aug 22, 2013
  29. 5/6 index-pack: optionally reject packs with duplicate objectsJeff King, Aug 22, 2013
  30. 6/6 default pack.indexDuplicates to falseJeff King, Aug 22, 2013
  31. Nicolas PitreAug 22, 2013
  32. 3/4 reject duplicates when indexing a packfile we createdJeff King, Aug 21, 2013
  33. 4/4 index-pack: optionally skip duplicate packfile entriesJeff King, Aug 21, 2013
  34. Junio C HamanoAug 21, 2013
  35. Jeff KingAug 22, 2013
  36. Junio C HamanoAug 21, 2013
  37. Nicolas PitreAug 14, 2013

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.