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>maint
							parent
							
								
									6c9cd161d9
								
							
						
					
					
						commit
						9d227781b6
					
				
							
								
								
									
										4
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										4
									
								
								cache.h
								
								
								
								
							|  | @ -105,6 +105,9 @@ struct cache_header { | ||||||
| 	unsigned int hdr_entries; | 	unsigned int hdr_entries; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #define INDEX_FORMAT_LB 2 | ||||||
|  | #define INDEX_FORMAT_UB 4 | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * The "cache_time" is just the low 32 bits of the |  * The "cache_time" is just the low 32 bits of the | ||||||
|  * time. It doesn't matter if it overflows - we only |  * time. It doesn't matter if it overflows - we only | ||||||
|  | @ -265,6 +268,7 @@ static inline unsigned int canon_mode(unsigned int mode) | ||||||
|  |  | ||||||
| struct index_state { | struct index_state { | ||||||
| 	struct cache_entry **cache; | 	struct cache_entry **cache; | ||||||
|  | 	unsigned int version; | ||||||
| 	unsigned int cache_nr, cache_alloc, cache_changed; | 	unsigned int cache_nr, cache_alloc, cache_changed; | ||||||
| 	struct string_list *resolve_undo; | 	struct string_list *resolve_undo; | ||||||
| 	struct cache_tree *cache_tree; | 	struct cache_tree *cache_tree; | ||||||
|  |  | ||||||
							
								
								
									
										60
									
								
								read-cache.c
								
								
								
								
							
							
						
						
									
										60
									
								
								read-cache.c
								
								
								
								
							|  | @ -1196,6 +1196,8 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int reall | ||||||
|  * Index File I/O |  * Index File I/O | ||||||
|  *****************************************************************/ |  *****************************************************************/ | ||||||
|  |  | ||||||
|  | #define INDEX_FORMAT_DEFAULT 3 | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * dev/ino/uid/gid/size are also just tracked to the low 32 bits |  * dev/ino/uid/gid/size are also just tracked to the low 32 bits | ||||||
|  * Again - this is just a (very strong in practice) heuristic that |  * 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) | ||||||
| 	if (verify_hdr(hdr, mmap_size) < 0) | 	if (verify_hdr(hdr, mmap_size) < 0) | ||||||
| 		goto unmap; | 		goto unmap; | ||||||
|  |  | ||||||
|  | 	istate->version = ntohl(hdr->hdr_version); | ||||||
| 	istate->cache_nr = ntohl(hdr->hdr_entries); | 	istate->cache_nr = ntohl(hdr->hdr_entries); | ||||||
| 	istate->cache_alloc = alloc_nr(istate->cache_nr); | 	istate->cache_alloc = alloc_nr(istate->cache_nr); | ||||||
| 	istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *)); | 	istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *)); | ||||||
| 	istate->initialized = 1; | 	istate->initialized = 1; | ||||||
|  |  | ||||||
| 	if (hdr->hdr_version == htonl(4)) | 	if (istate->version == 4) | ||||||
| 		previous_name = &previous_name_buf; | 		previous_name = &previous_name_buf; | ||||||
| 	else | 	else | ||||||
| 		previous_name = NULL; | 		previous_name = NULL; | ||||||
|  | @ -1676,15 +1679,45 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce) | static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce, | ||||||
|  | 			  struct strbuf *previous_name) | ||||||
| { | { | ||||||
| 	int size = ondisk_ce_size(ce); | 	int size; | ||||||
| 	struct ondisk_cache_entry *ondisk = xcalloc(1, size); | 	struct ondisk_cache_entry *ondisk; | ||||||
| 	char *name; | 	char *name; | ||||||
| 	int result; | 	int result; | ||||||
|  |  | ||||||
|  | 	if (!previous_name) { | ||||||
|  | 		size = ondisk_ce_size(ce); | ||||||
|  | 		ondisk = xcalloc(1, size); | ||||||
| 		name = copy_cache_entry_to_ondisk(ondisk, ce); | 		name = copy_cache_entry_to_ondisk(ondisk, ce); | ||||||
| 		memcpy(name, ce->name, ce_namelen(ce)); | 		memcpy(name, ce->name, ce_namelen(ce)); | ||||||
|  | 	} else { | ||||||
|  | 		int common, to_remove, prefix_size; | ||||||
|  | 		unsigned char to_remove_vi[16]; | ||||||
|  | 		for (common = 0; | ||||||
|  | 		     (ce->name[common] && | ||||||
|  | 		      common < previous_name->len && | ||||||
|  | 		      ce->name[common] == previous_name->buf[common]); | ||||||
|  | 		     common++) | ||||||
|  | 			; /* still matching */ | ||||||
|  | 		to_remove = previous_name->len - common; | ||||||
|  | 		prefix_size = encode_varint(to_remove, to_remove_vi); | ||||||
|  |  | ||||||
|  | 		if (ce->ce_flags & CE_EXTENDED) | ||||||
|  | 			size = offsetof(struct ondisk_cache_entry_extended, name); | ||||||
|  | 		else | ||||||
|  | 			size = offsetof(struct ondisk_cache_entry, name); | ||||||
|  | 		size += prefix_size + (ce_namelen(ce) - common + 1); | ||||||
|  |  | ||||||
|  | 		ondisk = xcalloc(1, size); | ||||||
|  | 		name = copy_cache_entry_to_ondisk(ondisk, ce); | ||||||
|  | 		memcpy(name, to_remove_vi, prefix_size); | ||||||
|  | 		memcpy(name + prefix_size, ce->name + common, ce_namelen(ce) - common); | ||||||
|  |  | ||||||
|  | 		strbuf_splice(previous_name, common, to_remove, | ||||||
|  | 			      ce->name + common, ce_namelen(ce) - common); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	result = ce_write(c, fd, ondisk, size); | 	result = ce_write(c, fd, ondisk, size); | ||||||
| 	free(ondisk); | 	free(ondisk); | ||||||
|  | @ -1720,10 +1753,11 @@ int write_index(struct index_state *istate, int newfd) | ||||||
| { | { | ||||||
| 	git_SHA_CTX c; | 	git_SHA_CTX c; | ||||||
| 	struct cache_header hdr; | 	struct cache_header hdr; | ||||||
| 	int i, err, removed, extended; | 	int i, err, removed, extended, hdr_version; | ||||||
| 	struct cache_entry **cache = istate->cache; | 	struct cache_entry **cache = istate->cache; | ||||||
| 	int entries = istate->cache_nr; | 	int entries = istate->cache_nr; | ||||||
| 	struct stat st; | 	struct stat st; | ||||||
|  | 	struct strbuf previous_name_buf = STRBUF_INIT, *previous_name; | ||||||
|  |  | ||||||
| 	for (i = removed = extended = 0; i < entries; i++) { | 	for (i = removed = extended = 0; i < entries; i++) { | ||||||
| 		if (cache[i]->ce_flags & CE_REMOVE) | 		if (cache[i]->ce_flags & CE_REMOVE) | ||||||
|  | @ -1737,24 +1771,34 @@ int write_index(struct index_state *istate, int newfd) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (!istate->version) | ||||||
|  | 		istate->version = INDEX_FORMAT_DEFAULT; | ||||||
|  |  | ||||||
|  | 	/* demote version 3 to version 2 when the latter suffices */ | ||||||
|  | 	if (istate->version == 3 || istate->version == 2) | ||||||
|  | 		istate->version = extended ? 3 : 2; | ||||||
|  |  | ||||||
|  | 	hdr_version = istate->version; | ||||||
|  |  | ||||||
| 	hdr.hdr_signature = htonl(CACHE_SIGNATURE); | 	hdr.hdr_signature = htonl(CACHE_SIGNATURE); | ||||||
| 	/* for extended format, increase version so older git won't try to read it */ | 	hdr.hdr_version = htonl(hdr_version); | ||||||
| 	hdr.hdr_version = htonl(extended ? 3 : 2); |  | ||||||
| 	hdr.hdr_entries = htonl(entries - removed); | 	hdr.hdr_entries = htonl(entries - removed); | ||||||
|  |  | ||||||
| 	git_SHA1_Init(&c); | 	git_SHA1_Init(&c); | ||||||
| 	if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) | 	if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) | ||||||
| 		return -1; | 		return -1; | ||||||
|  |  | ||||||
|  | 	previous_name = (hdr_version == 4) ? &previous_name_buf : NULL; | ||||||
| 	for (i = 0; i < entries; i++) { | 	for (i = 0; i < entries; i++) { | ||||||
| 		struct cache_entry *ce = cache[i]; | 		struct cache_entry *ce = cache[i]; | ||||||
| 		if (ce->ce_flags & CE_REMOVE) | 		if (ce->ce_flags & CE_REMOVE) | ||||||
| 			continue; | 			continue; | ||||||
| 		if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce)) | 		if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce)) | ||||||
| 			ce_smudge_racily_clean_entry(ce); | 			ce_smudge_racily_clean_entry(ce); | ||||||
| 		if (ce_write_entry(&c, newfd, ce) < 0) | 		if (ce_write_entry(&c, newfd, ce, previous_name) < 0) | ||||||
| 			return -1; | 			return -1; | ||||||
| 	} | 	} | ||||||
|  | 	strbuf_release(&previous_name_buf); | ||||||
|  |  | ||||||
| 	/* Write extension data here */ | 	/* Write extension data here */ | ||||||
| 	if (istate->cache_tree) { | 	if (istate->cache_tree) { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano