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

[PATCH 8/9] read-cache.c: read prefix-compressed names in index on-disk version v4

From
Junio C Hamano <gitster@pobox.com>
Date
Apr 3, 2012, 22:53 UTC
Message-ID
<1333493596-14202-9-git-send-email-gitster@pobox.com>
In-Reply-To
<1333493596-14202-1-git-send-email-gitster@pobox.com>

Because the entries are sorted by path, adjacent entries in the index tend to share the leading components of them, and it makes sense to only store the differences in later entries. In the v4 on-disk format of the index, each on-disk cache entry stores the number of bytes to be stripped from the end of the previous name, and the bytes to append to the result, to come up with its name.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 read-cache.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 51 insertions(+), 7 deletions(-)
diff --git a/read-cache.c b/read-cache.c
index c159351..1c173f7 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -12,6 +12,8 @@
 #include "commit.h"
 #include "blob.h"
 #include "resolve-undo.h"
+#include "strbuf.h"
+#include "varint.h"
 
 static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
 
@@ -1236,6 +1238,7 @@ struct ondisk_cache_entry_extended {
 	char name[FLEX_ARRAY]; /* more */
 };
 
+/* These are only used for v3 or lower */
 #define align_flex_name(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
 #define ondisk_cache_entry_size(len) align_flex_name(ondisk_cache_entry,len)
 #define ondisk_cache_entry_extended_size(len) align_flex_name(ondisk_cache_entry_extended,len)
@@ -1252,7 +1255,7 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
 	if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
 		return error("bad signature");
 	hdr_version = ntohl(hdr->hdr_version);
-	if (hdr_version < 2 || 3 < hdr_version)
+	if (hdr_version < 2 || 4 < hdr_version)
 		return error("bad index version %d", hdr_version);
 	git_SHA1_Init(&c);
 	git_SHA1_Update(&c, hdr, size - 20);
@@ -1331,8 +1334,30 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on
 	return ce;
 }
 
+/*
+ * Adjacent cache entries tend to share the leading paths, so it makes
+ * sense to only store the differences in later entries.  In the v4
+ * on-disk format of the index, each on-disk cache entry stores the
+ * number of bytes to be stripped from the end of the previous name,
+ * and the bytes to append to the result, to come up with its name.
+ */
+static unsigned long expand_name_field(struct strbuf *name, const char *cp_)
+{
+	const unsigned char *ep, *cp = (const unsigned char *)cp_;
+	size_t len = decode_varint(&cp);
+
+	if (name->len < len)
+		die("malformed name field in the index");
+	strbuf_remove(name, name->len - len, len);
+	for (ep = cp; *ep; ep++)
+		; /* find the end */
+	strbuf_add(name, cp, ep - cp);
+	return (const char *)ep + 1 - cp_;
+}
+
 static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk,
-					    unsigned long *ent_size)
+					    unsigned long *ent_size,
+					    struct strbuf *previous_name)
 {
 	struct cache_entry *ce;
 	size_t len;
@@ -1357,10 +1382,22 @@ static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk,
 	else
 		name = ondisk->name;
 
-	if (len == CE_NAMEMASK)
-		len = strlen(name);
-	ce = cache_entry_from_ondisk(ondisk, flags, name, len);
-	*ent_size = ondisk_ce_size(ce);
+	if (!previous_name) {
+		/* v3 and earlier */
+		if (len == CE_NAMEMASK)
+			len = strlen(name);
+		ce = cache_entry_from_ondisk(ondisk, flags, name, len);
+
+		*ent_size = ondisk_ce_size(ce);
+	} else {
+		unsigned long consumed;
+		consumed = expand_name_field(previous_name, name);
+		ce = cache_entry_from_ondisk(ondisk, flags,
+					     previous_name->buf,
+					     previous_name->len);
+
+		*ent_size = (name - ((char *)ondisk)) + consumed;
+	}
 	return ce;
 }
 
@@ -1373,6 +1410,7 @@ int read_index_from(struct index_state *istate, const char *path)
 	struct cache_header *hdr;
 	void *mmap;
 	size_t mmap_size;
+	struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 
 	errno = EBUSY;
 	if (istate->initialized)
@@ -1410,6 +1448,11 @@ int read_index_from(struct index_state *istate, const char *path)
 	istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *));
 	istate->initialized = 1;
 
+	if (hdr->hdr_version == htonl(4))
+		previous_name = &previous_name_buf;
+	else
+		previous_name = NULL;
+
 	src_offset = sizeof(*hdr);
 	for (i = 0; i < istate->cache_nr; i++) {
 		struct ondisk_cache_entry *disk_ce;
@@ -1417,11 +1460,12 @@ int read_index_from(struct index_state *istate, const char *path)
 		unsigned long consumed;
 
 		disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset);
-		ce = create_from_disk(disk_ce, &consumed);
+		ce = create_from_disk(disk_ce, &consumed, previous_name);
 		set_index_entry(istate, i, ce);
 
 		src_offset += consumed;
 	}
+	strbuf_release(&previous_name_buf);
 	istate->timestamp.sec = st.st_mtime;
 	istate->timestamp.nsec = ST_MTIME_NSEC(st);
 
-- 
1.7.10.rc4.54.g1d5dd3
Previous: Junio C HamanoNext: Junio C Hamano
Message 9 of 27 in “Prefix-compress on-disk index entries”
  1. 0/9 Prefix-compress on-disk index entriesJunio C Hamano, Apr 3, 2012
  2. 1/9 varint: make it available outside the context of packJunio C Hamano, Apr 3, 2012
  3. 2/9 cache.h: hide on-disk index detailsJunio C Hamano, Apr 3, 2012
  4. 3/9 read-cache.c: allow unaligned mapping of the index fileJunio C Hamano, Apr 3, 2012
  5. 4/9 read-cache.c: make create_from_disk() report number of bytes it consumedJunio C Hamano, Apr 3, 2012
  6. 5/9 read-cache.c: report the header version we do not understandJunio C Hamano, Apr 3, 2012
  7. 6/9 read-cache.c: move code to copy ondisk to incore cache to a helper functionJunio C Hamano, Apr 3, 2012
  8. 7/9 read-cache.c: move code to copy incore to ondisk cache to a helper functionJunio C Hamano, Apr 3, 2012
  9. 8/9 read-cache.c: read prefix-compressed names in index on-disk version v4Junio C Hamano, Apr 3, 2012
  10. 9/9 read-cache.c: write index v4 formatJunio C Hamano, Apr 3, 2012
  11. David BarrApr 4, 2012
  12. Junio C HamanoApr 4, 2012
  13. Junio C HamanoApr 4, 2012
  14. 2/2 update-index: upgrade/downgrade on-disk index versionJunio C Hamano, Apr 4, 2012
  15. Nguyen Thai Ngoc DuyApr 4, 2012
  16. Junio C HamanoApr 4, 2012
  17. David BarrApr 6, 2012
  18. Nguyen Thai Ngoc DuyMay 2, 2012
  19. David BarrMay 2, 2012
  20. 1/2 unpack-trees: preserve the index file version of originalJunio C Hamano, Apr 27, 2012
  21. 2/2 index-v4: document the entry formatJunio C Hamano, Apr 27, 2012
  22. Thomas RastApr 30, 2012
  23. Junio C HamanoMay 1, 2012
  24. Thomas RastMay 1, 2012
  25. Shawn PearceMay 2, 2012
  26. Junio C HamanoMay 2, 2012
  27. Shawn PearceMay 2, 2012

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.