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

[PATCH 06/10] pack-objects: learn about pack index version 2

From
Nicolas Pitre <nico@cam.org>
Date
Apr 9, 2007, 05:06 UTC
Message-ID
<11760952002410-git-send-email-nico@cam.org>
In-Reply-To
<11760952002687-git-send-email-nico@cam.org>
Pack index version 2 goes as follows:
 - 8 bytes of header with signature and version.
 - 256 entries of 4-byte first-level fan-out table.
 - Table of sorted 20-byte SHA1 records for each object in pack.
 - Table of 4-byte CRC32 entries for raw pack object data.
 - Table of 4-byte offset entries for objects in the pack if offset is
   representable with 31 bits or less, otherwise it is an index in the next
   table with top bit set.
 - Table of 8-byte offset entries indexed from previous table for offsets
   which are 32 bits or more (optional).
 - 20-byte SHA1 checksum of sorted object names.
 - 20-byte SHA1 checksum of the above.

The object SHA1 table is all contiguous so future pack format that would contain this table directly won't require big changes to the code. It is also tighter for slightly better cache locality when looking up entries.

Support for large packs exceeding 31 bits in size won't impose an index size bloat for packs within that range that don't need a 64-bit offset. And because newer objects which are likely to be the most frequently used are located at the beginning of the pack, they won't pay the 64-bit offset lookup at run time either even if the pack is large.

Right now an index version 2 is created only when the biggest offset in a pack reaches 31 bits. It might be a good idea to always use index version 2 eventually to benefit from the CRC32 it contains when reusing pack data while repacking.

Signed-off-by: Nicolas Pitre <nico@cam.org>
---
 builtin-pack-objects.c |   85 ++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 78 insertions(+), 7 deletions(-)
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 03e36f0..c7e0a42 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -169,13 +169,33 @@ static void prepare_pack_revindex(struct pack_revindex *rix)
 	int i;
 	const char *index = p->index_data;
 
-	index += 4 * 256;
 	rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
-	for (i = 0; i < num_ent; i++) {
-		uint32_t hl = *((uint32_t *)(index + 24 * i));
-		rix->revindex[i].offset = ntohl(hl);
-		rix->revindex[i].nr = i;
+	index += 4 * 256;
+
+	if (p->index_version > 1) {
+		const uint32_t *off_32 =
+			(uint32_t *)(index + 8 + p->num_objects * (20 + 4));
+		const uint32_t *off_64 = off_32 + p->num_objects;
+		for (i = 0; i < num_ent; i++) {
+			uint32_t off = ntohl(*off_32++);
+			if (!(off & 0x80000000)) {
+				rix->revindex[i].offset = off;
+			} else {
+				rix->revindex[i].offset =
+					((uint64_t)ntohl(*off_64++)) << 32;
+				rix->revindex[i].offset |=
+					ntohl(*off_64++);
+			}
+			rix->revindex[i].nr = i;
+		}
+	} else {
+		for (i = 0; i < num_ent; i++) {
+			uint32_t hl = *((uint32_t *)(index + 24 * i));
+			rix->revindex[i].offset = ntohl(hl);
+			rix->revindex[i].nr = i;
+		}
 	}
+
 	/* This knows the pack format -- the 20-byte trailer
 	 * follows immediately after the last object data.
 	 */
@@ -582,6 +602,18 @@ static void write_index_file(void)
 	struct object_entry **list = sorted_by_sha;
 	struct object_entry **last = list + nr_result;
 	uint32_t array[256];
+	uint32_t index_version;
+
+	/* if last object's offset is >= 2^31 we should use index V2 */
+	index_version = (objects[nr_result-1].offset >> 31) ? 2 : 1;
+
+	/* index versions 2 and above need a header */
+	if (index_version >= 2) {
+		struct pack_idx_header hdr;
+		hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
+		hdr.idx_version = htonl(index_version);
+		sha1write(f, &hdr, sizeof(hdr));
+	}
 
 	/*
 	 * Write the first-level table (the list is sorted,
@@ -607,10 +639,49 @@ static void write_index_file(void)
 	list = sorted_by_sha;
 	for (i = 0; i < nr_result; i++) {
 		struct object_entry *entry = *list++;
-		uint32_t offset = htonl(entry->offset);
-		sha1write(f, &offset, 4);
+		if (index_version < 2) {
+			uint32_t offset = htonl(entry->offset);
+			sha1write(f, &offset, 4);
+		}
 		sha1write(f, entry->sha1, 20);
 	}
+
+	if (index_version >= 2) {
+		unsigned int nr_large_offset = 0;
+
+		/* write the crc32 table */
+		list = sorted_by_sha;
+		for (i = 0; i < nr_objects; i++) {
+			struct object_entry *entry = *list++;
+			uint32_t crc32_val = htonl(entry->crc32);
+			sha1write(f, &crc32_val, 4);
+		}
+
+		/* write the 32-bit offset table */
+		list = sorted_by_sha;
+		for (i = 0; i < nr_objects; i++) {
+			struct object_entry *entry = *list++;
+			uint32_t offset = (entry->offset <= 0x7fffffff) ?
+				entry->offset : (0x80000000 | nr_large_offset++);
+			offset = htonl(offset);
+			sha1write(f, &offset, 4);
+		}
+
+		/* write the large offset table */
+		list = sorted_by_sha;
+		while (nr_large_offset) {
+			struct object_entry *entry = *list++;
+			uint64_t offset = entry->offset;
+			if (offset > 0x7fffffff) {
+				uint32_t split[2];
+				split[0]        = htonl(offset >> 32);
+				split[1] = htonl(offset & 0xffffffff);
+				sha1write(f, split, 8);
+				nr_large_offset--;
+			}
+		}
+	}
+
 	sha1write(f, pack_file_sha1, 20);
 	sha1close(f, NULL, 1);
 }
-- 
1.5.1.696.g6d352-dirty
Previous: Nicolas PitreNext: Nicolas Pitre
Message 7 of 24 in “support for large packs and 64-bit offsets”
  1. Nicolas PitreApr 9, 2007
  2. 01/10 get rid of num_packed_objects()Nicolas Pitre, Apr 9, 2007
  3. 02/10 make overflow test on delta base offset work regardless of variable sizeNicolas Pitre, Apr 9, 2007
  4. 03/10 add overflow tests on pack offset variablesNicolas Pitre, Apr 9, 2007
  5. 04/10 compute a CRC32 for each object as stored in a packNicolas Pitre, Apr 9, 2007
  6. 05/10 compute object CRC32 with index-packNicolas Pitre, Apr 9, 2007
  7. 06/10 pack-objects: learn about pack index version 2Nicolas Pitre, Apr 9, 2007
  8. 07/10 index-pack: learn about pack index version 2Nicolas Pitre, Apr 9, 2007
  9. 08/10 sha1_file.c: learn about index version 2Nicolas Pitre, Apr 9, 2007
  10. 09/10 show-index.c: learn about index v2Nicolas Pitre, Apr 9, 2007
  11. 10/10 pack-redundant.c: learn about index v2Nicolas Pitre, Apr 9, 2007
  12. Junio C HamanoApr 9, 2007
  13. Nicolas PitreApr 9, 2007
  14. Shawn O. PearceApr 9, 2007
  15. Nicolas PitreApr 9, 2007
  16. Shawn O. PearceApr 9, 2007
  17. Junio C HamanoApr 9, 2007
  18. Shawn O. PearceApr 9, 2007
  19. Nicolas PitreApr 9, 2007
  20. Junio C HamanoApr 9, 2007
  21. Linus TorvaldsApr 9, 2007
  22. Nicolas PitreApr 9, 2007
  23. Shawn O. PearceApr 9, 2007
  24. Nicolas PitreApr 9, 2007

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.