read-cache.c: write prefix-compressed names in the index

Teach the code to write the index in the v4 on-disk format. Record the format version of the on-disk index we read from in the index_state, and use the format when writing the new index out. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Apr 4, 2012 at 09:12 UTC 9d227781b688707f64ee1703a1156b0c83247c33
2 files changed +58 -10
cache.h
+4
@@ -105,6 +105,9 @@ struct cache_header {
105 unsigned int hdr_entries;
106 };
107
108 +#define INDEX_FORMAT_LB 2
109 +#define INDEX_FORMAT_UB 4
110 +
111 /*
112 * The "cache_time" is just the low 32 bits of the
113 * time. It doesn't matter if it overflows - we only
@@ -265,6 +268,7 @@ static inline unsigned int canon_mode(unsigned int mode)
268
269 struct index_state {
270 struct cache_entry **cache;
271 + unsigned int version;
272 unsigned int cache_nr, cache_alloc, cache_changed;
273 struct string_list *resolve_undo;
274 struct cache_tree *cache_tree;
read-cache.c
+54 -10
@@ -1196,6 +1196,8 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int reall
1196 * Index File I/O
1197 *****************************************************************/
1198
1199 +#define INDEX_FORMAT_DEFAULT 3
1200 +
1201 /*
1202 * dev/ino/uid/gid/size are also just tracked to the low 32 bits
1203 * Again - this is just a (very strong in practice) heuristic that
@@ -1443,12 +1445,13 @@ int read_index_from(struct index_state *istate, const char *path)
1445 if (verify_hdr(hdr, mmap_size) < 0)
1446 goto unmap;
1447
1448 + istate->version = ntohl(hdr->hdr_version);
1449 istate->cache_nr = ntohl(hdr->hdr_entries);
1450 istate->cache_alloc = alloc_nr(istate->cache_nr);
1451 istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *));
1452 istate->initialized = 1;
1453
1451 - if (hdr->hdr_version == htonl(4))
1454 + if (istate->version == 4)
1455 previous_name = &previous_name_buf;
1456 else
1457 previous_name = NULL;
@@ -1676,15 +1679,45 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
1679 }
1680 }
1681
1679 -static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
1682 +static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
1683 + struct strbuf *previous_name)
1684 {
1681 - int size = ondisk_ce_size(ce);
1682 - struct ondisk_cache_entry *ondisk = xcalloc(1, size);
1685 + int size;
1686 + struct ondisk_cache_entry *ondisk;
1687 char *name;
1688 int result;
1689
1686 - name = copy_cache_entry_to_ondisk(ondisk, ce);
1687 - memcpy(name, ce->name, ce_namelen(ce));
1690 + if (!previous_name) {
1691 + size = ondisk_ce_size(ce);
1692 + ondisk = xcalloc(1, size);
1693 + name = copy_cache_entry_to_ondisk(ondisk, ce);
1694 + memcpy(name, ce->name, ce_namelen(ce));
1695 + } else {
1696 + int common, to_remove, prefix_size;
1697 + unsigned char to_remove_vi[16];
1698 + for (common = 0;
1699 + (ce->name[common] &&
1700 + common < previous_name->len &&
1701 + ce->name[common] == previous_name->buf[common]);
1702 + common++)
1703 + ; /* still matching */
1704 + to_remove = previous_name->len - common;
1705 + prefix_size = encode_varint(to_remove, to_remove_vi);
1706 +
1707 + if (ce->ce_flags & CE_EXTENDED)
1708 + size = offsetof(struct ondisk_cache_entry_extended, name);
1709 + else
1710 + size = offsetof(struct ondisk_cache_entry, name);
1711 + size += prefix_size + (ce_namelen(ce) - common + 1);
1712 +
1713 + ondisk = xcalloc(1, size);
1714 + name = copy_cache_entry_to_ondisk(ondisk, ce);
1715 + memcpy(name, to_remove_vi, prefix_size);
1716 + memcpy(name + prefix_size, ce->name + common, ce_namelen(ce) - common);
1717 +
1718 + strbuf_splice(previous_name, common, to_remove,
1719 + ce->name + common, ce_namelen(ce) - common);
1720 + }
1721
1722 result = ce_write(c, fd, ondisk, size);
1723 free(ondisk);
@@ -1720,10 +1753,11 @@ int write_index(struct index_state *istate, int newfd)
1753 {
1754 git_SHA_CTX c;
1755 struct cache_header hdr;
1723 - int i, err, removed, extended;
1756 + int i, err, removed, extended, hdr_version;
1757 struct cache_entry **cache = istate->cache;
1758 int entries = istate->cache_nr;
1759 struct stat st;
1760 + struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
1761
1762 for (i = removed = extended = 0; i < entries; i++) {
1763 if (cache[i]->ce_flags & CE_REMOVE)
@@ -1737,24 +1771,34 @@ int write_index(struct index_state *istate, int newfd)
1771 }
1772 }
1773
1774 + if (!istate->version)
1775 + istate->version = INDEX_FORMAT_DEFAULT;
1776 +
1777 + /* demote version 3 to version 2 when the latter suffices */
1778 + if (istate->version == 3 || istate->version == 2)
1779 + istate->version = extended ? 3 : 2;
1780 +
1781 + hdr_version = istate->version;
1782 +
1783 hdr.hdr_signature = htonl(CACHE_SIGNATURE);
1741 - /* for extended format, increase version so older git won't try to read it */
1742 - hdr.hdr_version = htonl(extended ? 3 : 2);
1784 + hdr.hdr_version = htonl(hdr_version);
1785 hdr.hdr_entries = htonl(entries - removed);
1786
1787 git_SHA1_Init(&c);
1788 if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
1789 return -1;
1790
1791 + previous_name = (hdr_version == 4) ? &previous_name_buf : NULL;
1792 for (i = 0; i < entries; i++) {
1793 struct cache_entry *ce = cache[i];
1794 if (ce->ce_flags & CE_REMOVE)
1795 continue;
1796 if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
1797 ce_smudge_racily_clean_entry(ce);
1755 - if (ce_write_entry(&c, newfd, ce) < 0)
1798 + if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
1799 return -1;
1800 }
1801 + strbuf_release(&previous_name_buf);
1802
1803 /* Write extension data here */
1804 if (istate->cache_tree) {