[PATCH v4 17/24] read-cache: write resolve-undo data for index-v5

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Make git read the resolve-undo data from the index.

Since the resolve-undo data is joined with the conflicts in the ondisk
format of the index file version 5, conflicts and resolved data is read
at the same time, and the resolve-undo data is then converted to the
in-memory format.

Helped-by: Thomas Rast <trast@xxxxxxxxxxxxxxx>
Signed-off-by: Thomas Gummerer <t.gummerer@xxxxxxxxx>
---
 read-cache-v5.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 191 insertions(+), 8 deletions(-)

diff --git a/read-cache-v5.c b/read-cache-v5.c
index 0d06cfe..a5e9b5a 100644
--- a/read-cache-v5.c
+++ b/read-cache-v5.c
@@ -723,6 +723,29 @@ static void ondisk_from_directory_entry(struct directory_entry *de,
 	}
 }
 
+static struct conflict_part *conflict_part_from_inmemory(struct cache_entry *ce)
+{
+	struct conflict_part *conflict;
+	int flags;
+
+	conflict = xmalloc(sizeof(struct conflict_part));
+	flags                = CONFLICT_CONFLICTED;
+	flags               |= ce_stage(ce) << CONFLICT_STAGESHIFT;
+	conflict->flags      = flags;
+	conflict->entry_mode = ce->ce_mode;
+	conflict->next       = NULL;
+	hashcpy(conflict->sha1, ce->sha1);
+	return conflict;
+}
+
+static void conflict_to_ondisk(struct conflict_part *cp,
+			       struct ondisk_conflict_part *ondisk)
+{
+	ondisk->flags      = htons(cp->flags);
+	ondisk->entry_mode = htons(cp->entry_mode);
+	hashcpy(ondisk->sha1, cp->sha1);
+}
+
 static void insert_directory_entry(struct directory_entry *de,
 				   struct hash_table *table,
 				   unsigned int *total_dir_len,
@@ -789,6 +812,11 @@ static struct directory_entry *get_directory(char *dir, unsigned int dir_len,
 	return ret;
 }
 
+static struct conflict_entry *create_conflict_entry_from_ce(struct cache_entry *ce)
+{
+	return create_new_conflict(ce->name, ce_namelen(ce));
+}
+
 static void convert_one_to_ondisk(struct hash_table *table, struct cache_tree *it,
 				  const char *path, int pathlen, uint32_t crc)
 {
@@ -840,6 +868,52 @@ static void cache_tree_to_ondisk(struct hash_table *table, struct cache_tree *ro
 	convert_one_to_ondisk(table, root, "", 0, 0);
 }
 
+static void resolve_undo_to_ondisk(struct string_list *resolve_undo,
+				   struct conflict_entry **conflict_queue)
+{
+	struct string_list_item *item;
+	struct conflict_entry *current = *conflict_queue;
+
+	if (!resolve_undo)
+		return;
+	for_each_string_list_item(item, resolve_undo) {
+		struct conflict_entry *conflict_entry;
+		struct resolve_undo_info *ui = item->util;
+		int i, len;
+
+		if (!ui)
+			continue;
+
+		len = strlen(item->string);
+		while (current && current->next &&
+		       cache_name_compare(current->name, current->namelen,
+					  item->string, len))
+			current = current->next;
+
+		conflict_entry = create_new_conflict(item->string, len);
+		for (i = 0; i < 3; i++) {
+			if (ui->mode[i]) {
+				struct conflict_part *cp;
+
+				cp = xmalloc(sizeof(struct conflict_part));
+				cp->flags = (i + 1) << CONFLICT_STAGESHIFT;
+				cp->entry_mode = ui->mode[i];
+				cp->next = NULL;
+				hashcpy(cp->sha1, ui->sha1[i]);
+				add_part_to_conflict_entry(conflict_entry, cp);
+			}
+		}
+		if (!*conflict_queue) {
+			*conflict_queue = conflict_entry;
+			conflict_entry->next = NULL;
+			current = conflict_entry;
+		} else {
+			conflict_entry->next = current->next;
+			current->next = conflict_entry;
+		}
+	}
+}
+
 static void ce_queue_push(struct cache_entry **head,
 			  struct cache_entry **tail,
 			  struct cache_entry *ce)
@@ -855,15 +929,32 @@ static void ce_queue_push(struct cache_entry **head,
 	*tail = (*tail)->next_ce;
 }
 
+static void conflict_queue_push(struct conflict_entry **head,
+				struct conflict_entry **tail,
+				struct conflict_entry *conflict)
+{
+	if (!*head) {
+		*head = *tail = conflict;
+		(*tail)->next = NULL;
+		return;
+	}
+
+	(*tail)->next = conflict;
+	conflict->next = NULL;
+	*tail = (*tail)->next;
+}
+
 static struct directory_entry *compile_directory_data(struct index_state *istate,
 						      int nfile, unsigned int *ndir,
 						      unsigned int *total_dir_len,
-						      unsigned int *total_file_len)
+						      unsigned int *total_file_len,
+						      struct conflict_entry **conflict_queue)
 {
 	int i, dir_len = -1;
 	char *dir;
 	struct directory_entry *de, *current, *search;
 	struct cache_entry **cache = istate->cache;
+	struct conflict_entry *conflict_entry = NULL, *tail;
 	struct hash_table table;
 	uint32_t crc;
 
@@ -894,9 +985,22 @@ static struct directory_entry *compile_directory_data(struct index_state *istate
 		if (search->de_pathlen)
 			*total_file_len -= search->de_pathlen + 1;
 		ce_queue_push(&(search->ce), &(search->ce_last), cache[i]);
+
+		if (ce_stage(cache[i]) > 0) {
+			struct conflict_part *conflict_part;
+			if (!conflict_entry ||
+			    cache_name_compare(conflict_entry->name, conflict_entry->namelen,
+					       cache[i]->name, ce_namelen(cache[i]))) {
+				conflict_entry = create_conflict_entry_from_ce(cache[i]);
+				conflict_queue_push(conflict_queue, &tail, conflict_entry);
+			}
+			conflict_part = conflict_part_from_inmemory(cache[i]);
+			add_part_to_conflict_entry(conflict_entry, conflict_part);
+		}
 	}
 	if (istate->cache_tree)
 		cache_tree_to_ondisk(&table, istate->cache_tree);
+	resolve_undo_to_ondisk(istate->resolve_undo, conflict_queue);
 	return de;
 }
 
@@ -1062,16 +1166,82 @@ static int write_entries(struct index_state *istate,
 	return 0;
 }
 
+static int write_conflict(struct conflict_entry *conflict, int fd)
+{
+	struct conflict_entry *current;
+	struct conflict_part *current_part;
+	uint32_t crc;
+
+	current = conflict;
+	while (current) {
+		unsigned int to_write, i;
+
+		crc = 0;
+		if (ce_write(&crc, fd, current->name, current->namelen) < 0)
+			return -1;
+		if (ce_write(&crc, fd, "\0", 1) < 0)
+			return -1;
+		to_write = htonl(current->nfileconflicts);
+		if (ce_write(&crc, fd, (Bytef*)&to_write, 4) < 0)
+			return -1;
+		current_part = current->entries;
+		for (i = 0; i < current->nfileconflicts; i++) {
+			struct ondisk_conflict_part ondisk;
+
+			conflict_to_ondisk(current_part, &ondisk);
+			if (ce_write(&crc, fd, (Bytef*)&ondisk, sizeof(struct ondisk_conflict_part)) < 0)
+				return 0;
+			current_part = current_part->next;
+		}
+		crc = htonl(crc);
+		if (ce_write(NULL, fd, &crc, 4) < 0)
+			return -1;
+		current = current->next;
+	}
+	return 0;
+}
+
+static int write_resolve_undo(struct index_state *istate,
+			      struct conflict_entry *conflict_queue,
+			      int fd)
+{
+	struct conflict_entry *current;
+	int nr = 0;
+	uint32_t crc = 0, to_write;
+
+	/* Just count */
+	for (current = conflict_queue; current; current = current->next)
+		nr++;
+
+	if (ce_write(&crc, fd, "REUC", 4) < 0)
+		return -1;
+	to_write = htonl(nr);
+	if (ce_write(&crc, fd, &to_write, 4) < 0)
+		return -1;
+	to_write = htonl(crc);
+	if (ce_write(NULL, fd, &to_write, 4) < 0)
+		return -1;
+
+	current = conflict_queue;
+	while (current) {
+		if (write_conflict(current, fd) < 0)
+			return -1;
+		current = current->next;
+	}
+	return 0;
+}
+
 static int write_index_v5(struct index_state *istate, int newfd)
 {
 	struct cache_header hdr;
 	struct cache_header_v5 hdr_v5;
 	struct cache_entry **cache = istate->cache;
 	struct directory_entry *de;
+	struct conflict_entry *conflict_queue = NULL;
 	unsigned int entries = istate->cache_nr;
 	unsigned int i, removed, total_dir_len;
 	unsigned int total_file_len, foffsetblock;
-	unsigned int ndir;
+	unsigned int ndir, extoffset, nextension;
 	uint32_t crc;
 
 	if (istate->filter_opts)
@@ -1084,24 +1254,34 @@ static int write_index_v5(struct index_state *istate, int newfd)
 	hdr.hdr_signature = htonl(CACHE_SIGNATURE);
 	hdr.hdr_version = htonl(istate->version);
 	hdr.hdr_entries = htonl(entries - removed);
-	hdr_v5.hdr_nextension = htonl(0); /* Currently no extensions are supported */
 
 	total_dir_len = 0;
 	total_file_len = 0;
 	de = compile_directory_data(istate, entries, &ndir,
-				    &total_dir_len, &total_file_len);
+				    &total_dir_len, &total_file_len,
+				    &conflict_queue);
 	hdr_v5.hdr_ndir = htonl(ndir);
 
-	foffsetblock = sizeof(hdr) + sizeof(hdr_v5) + 4
-		+ (ndir + 1) * 4
-		+ total_dir_len
-		+ ndir * (offsetof(struct ondisk_directory_entry, name) + 4);
+	nextension = (istate->resolve_undo || conflict_queue) ? 1 : 0;
+	foffsetblock = sizeof(hdr) + sizeof(hdr_v5) + (nextension * 4) + 4 +
+		(ndir + 1) * 4 + total_dir_len +
+		ndir * (offsetof(struct ondisk_directory_entry, name) + 4);
 	hdr_v5.hdr_fblockoffset = htonl(foffsetblock + (entries - removed + 1) * 4);
+	hdr_v5.hdr_nextension = htonl(nextension);
+
 	crc = 0;
 	if (ce_write(&crc, newfd, &hdr, sizeof(hdr)) < 0)
 		return -1;
 	if (ce_write(&crc, newfd, &hdr_v5, sizeof(hdr_v5)) < 0)
 		return -1;
+
+	if (nextension) {
+		extoffset = foffsetblock + (entries - removed + 1) * 4 + total_file_len +
+			(entries - removed) * (offsetof(struct ondisk_cache_entry, name) + 4);
+		extoffset = htonl(extoffset);
+		if (ce_write(&crc, newfd, &extoffset, 4) < 0)
+			return -1;
+	}
 	crc = htonl(crc);
 	if (ce_write(NULL, newfd, &crc, 4) < 0)
 		return -1;
@@ -1110,6 +1290,9 @@ static int write_index_v5(struct index_state *istate, int newfd)
 		return -1;
 	if (write_entries(istate, de, entries, newfd) < 0)
 		return -1;
+	if (nextension)
+		if (write_resolve_undo(istate, conflict_queue, newfd) < 0)
+			return -1;
 	return ce_flush(newfd);
 }
 
-- 
1.8.4.2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]