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

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

From
Thomas Gummerer <t.gummerer@gmail.com>
Date
Nov 27, 2013, 12:00 UTC
Message-ID
<1385553659-9928-18-git-send-email-t.gummerer@gmail.com>
In-Reply-To
<1385553659-9928-1-git-send-email-t.gummerer@gmail.com>
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@student.ethz.ch>
Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 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
Previous: Thomas GummererNext: Thomas Gummerer
Message 28 of 41 in “Index-v5”
  1. 00/24 Index-v5Thomas Gummerer, Nov 27, 2013
  2. 01/24 t2104: Don't fail for index versions other than [23]Thomas Gummerer, Nov 27, 2013
  3. 02/24 read-cache: split index file version specific functionalityThomas Gummerer, Nov 27, 2013
  4. 03/24 read-cache: move index v2 specific functions to their own fileThomas Gummerer, Nov 27, 2013
  5. 04/24 read-cache: Re-read index if index file changedThomas Gummerer, Nov 27, 2013
  6. 05/24 add documentation for the index apiThomas Gummerer, Nov 27, 2013
  7. 06/24 read-cache: add index reading apiThomas Gummerer, Nov 27, 2013
  8. 07/24 make sure partially read index is not changedThomas Gummerer, Nov 27, 2013
  9. 08/24 grep.c: use index apiThomas Gummerer, Nov 27, 2013
  10. 09/24 ls-files.c: use index apiThomas Gummerer, Nov 27, 2013
  11. Duy NguyenNov 30, 2013
  12. Thomas GummererNov 30, 2013
  13. Antoine PelisseNov 30, 2013
  14. Thomas GummererNov 30, 2013
  15. 10/24 documentation: add documentation of the index-v5 file formatThomas Gummerer, Nov 27, 2013
  16. 11/24 read-cache: make in-memory format aware of stat_crcThomas Gummerer, Nov 27, 2013
  17. 12/24 read-cache: read index-v5Thomas Gummerer, Nov 27, 2013
  18. Duy NguyenNov 30, 2013
  19. Thomas GummererNov 30, 2013
  20. Antoine PelisseNov 30, 2013
  21. Thomas GummererNov 30, 2013
  22. Antoine PelisseNov 30, 2013
  23. Thomas GummererNov 30, 2013
  24. 13/24 read-cache: read resolve-undo dataThomas Gummerer, Nov 27, 2013
  25. 14/24 read-cache: read cache-tree in index-v5Thomas Gummerer, Nov 27, 2013
  26. 15/24 read-cache: write index-v5Thomas Gummerer, Nov 27, 2013
  27. 16/24 read-cache: write index-v5 cache-tree dataThomas Gummerer, Nov 27, 2013
  28. 17/24 read-cache: write resolve-undo data for index-v5Thomas Gummerer, Nov 27, 2013
  29. 18/24 update-index.c: rewrite index when index-version is givenThomas Gummerer, Nov 27, 2013
  30. 19/24 p0003-index.sh: add perf test for the index formatsThomas Gummerer, Nov 27, 2013
  31. 20/24 introduce GIT_INDEX_VERSION environment variableThomas Gummerer, Nov 27, 2013
  32. Eric SunshineNov 27, 2013
  33. Junio C HamanoNov 27, 2013
  34. Thomas GummererNov 28, 2013
  35. 21/24 test-lib: allow setting the index format versionThomas Gummerer, Nov 27, 2013
  36. 22/24 t1600: add index v5 specific testsThomas Gummerer, Nov 27, 2013
  37. 23/24 POC for partial writingThomas Gummerer, Nov 27, 2013
  38. Duy NguyenNov 30, 2013
  39. Thomas GummererNov 30, 2013
  40. 24/24 perf: add partial writing testThomas Gummerer, Nov 27, 2013
  41. Thomas GummererDec 9, 2013

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.