git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Thomas Gummerer <t.gummerer@gmail.com>
To: git@vger.kernel.org
Cc: t.gummerer@gmail.com, gitster@pobox.com, tr@thomasrast.ch,
	mhagger@alum.mit.edu, pclouds@gmail.com,
	robin.rosenberg@dewire.com, sunshine@sunshineco.com,
	ramsay@ramsay1.demon.co.uk
Subject: [PATCH v4 23/24] POC for partial writing
Date: Wed, 27 Nov 2013 13:00:58 +0100	[thread overview]
Message-ID: <1385553659-9928-24-git-send-email-t.gummerer@gmail.com> (raw)
In-Reply-To: <1385553659-9928-1-git-send-email-t.gummerer@gmail.com>

This makes update-index use both partial reading and partial writing.
Partial reading is only used no option other than the paths is passed to
the command.

This passes the test suite, but doesn't behave correctly when a write
fails.  A log should be written to the lock file, in order to be able to
recover if a write fails.
---
 builtin/update-index.c |  43 +++++++++++---
 cache-tree.c           |  13 +++++
 cache-tree.h           |   1 +
 cache.h                |  27 ++++++++-
 lockfile.c             |   2 +-
 read-cache-v2.c        |   2 +
 read-cache-v5.c        | 154 ++++++++++++++++++++++++++++++++++++++++---------
 read-cache.c           |  30 ++++++++++
 read-cache.h           |   1 +
 resolve-undo.c         |   1 +
 10 files changed, 237 insertions(+), 37 deletions(-)

diff --git a/builtin/update-index.c b/builtin/update-index.c
index 8b3f7a0..69f0949 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -56,6 +56,7 @@ static int mark_ce_flags(const char *path, int flag, int mark)
 		else
 			active_cache[pos]->ce_flags &= ~flag;
 		cache_tree_invalidate_path(active_cache_tree, path);
+		the_index.needs_rewrite = 1;
 		active_cache_changed = 1;
 		return 0;
 	}
@@ -99,6 +100,8 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
 	memcpy(ce->name, path, len);
 	ce->ce_flags = create_ce_flags(0);
 	ce->ce_namelen = len;
+	if (old)
+		ce->entry_pos = old->entry_pos;
 	fill_stat_cache_info(ce, st);
 	ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
 
@@ -268,6 +271,7 @@ static void chmod_path(int flip, const char *path)
 		goto fail;
 	}
 	cache_tree_invalidate_path(active_cache_tree, path);
+	the_index.needs_rewrite = 1;
 	active_cache_changed = 1;
 	report("chmod %cx '%s'", flip, path);
 	return;
@@ -706,15 +710,18 @@ static int reupdate_callback(struct parse_opt_ctx_t *ctx,
 
 int cmd_update_index(int argc, const char **argv, const char *prefix)
 {
-	int newfd, entries, has_errors = 0, line_termination = '\n';
+	int newfd, has_errors = 0, line_termination = '\n';
 	int read_from_stdin = 0;
 	int prefix_length = prefix ? strlen(prefix) : 0;
 	int preferred_index_format = 0;
 	char set_executable_bit = 0;
 	struct refresh_params refresh_args = {0, &has_errors};
 	int lock_error = 0;
+	struct filter_opts opts;
+	struct pathspec pathspec;
 	struct lock_file *lock_file;
 	struct parse_opt_ctx_t ctx;
+	int i, needs_full_read = 0;
 	int parseopt_state = PARSE_OPT_UNKNOWN;
 	struct option options[] = {
 		OPT_BIT('q', NULL, &refresh_args.flags,
@@ -810,9 +817,23 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 	if (newfd < 0)
 		lock_error = errno;
 
-	entries = read_cache();
-	if (entries < 0)
-		die("cache corrupted");
+	for (i = 0; i < argc; i++) {
+		if (!prefixcmp(argv[i], "--"))
+			needs_full_read = 1;
+	}
+	if (!needs_full_read) {
+		memset(&opts, 0, sizeof(struct filter_opts));
+		parse_pathspec(&pathspec, 0,
+			       PATHSPEC_PREFER_CWD |
+			       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
+			       prefix, argv + 1);
+		opts.pathspec = &pathspec;
+		if (read_cache_filtered(&opts) < 0)
+			die("cache corrupted");
+	} else {
+		if (read_cache() < 0)
+			die("cache corrupted");
+	}
 
 	/*
 	 * Custom copy of parse_options() because we want to handle
@@ -862,6 +883,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 			    preferred_index_format,
 			    INDEX_FORMAT_LB, INDEX_FORMAT_UB);
 
+		the_index.needs_rewrite = 1;
 		active_cache_changed = 1;
 		change_cache_version(preferred_index_format);
 	}
@@ -890,17 +912,22 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 	}
 
 	if (active_cache_changed) {
+		int r;
 		if (newfd < 0) {
 			if (refresh_args.flags & REFRESH_QUIET)
 				exit(128);
 			unable_to_lock_index_die(get_index_file(), lock_error);
 		}
-		if (write_cache(newfd, active_cache, active_nr) ||
-		    commit_locked_index(lock_file))
+		r = write_cache_partial(newfd);
+		if (r < 0)
 			die("Unable to write new index file");
+		else if (r == 0)
+			commit_lock_file(lock_file);
+		else
+			remove_lock_file();
+	} else {
+		rollback_lock_file(lock_file);
 	}
 
-	rollback_lock_file(lock_file);
-
 	return has_errors ? 1 : 0;
 }
diff --git a/cache-tree.c b/cache-tree.c
index 1209732..a3d18bb 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -123,6 +123,15 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
 		return;
 	slash = strchr(path, '/');
 	it->entry_count = -1;
+	/*
+	 * Mark the cache_tree directory entry as invalid too. The
+	 * entry_count defines if the tree is valid, so we don't need
+	 * to reset any other field.
+	 */
+	if (it->de_ref) {
+		it->de_ref->de_nentries = -1;
+		it->de_ref->changed = 1;
+	}
 	if (!slash) {
 		int pos;
 		namelen = strlen(path);
@@ -140,6 +149,10 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
 				sizeof(struct cache_tree_sub *) *
 				(it->subtree_nr - pos - 1));
 			it->subtree_nr--;
+			if (it->de_ref) {
+				it->de_ref->de_nsubtrees--;
+				it->de_ref->changed = 1;
+			}
 		}
 		return;
 	}
diff --git a/cache-tree.h b/cache-tree.h
index 9818926..eaf14a9 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -18,6 +18,7 @@ struct cache_tree {
 	unsigned char sha1[20];
 	int subtree_nr;
 	int subtree_alloc;
+	struct directory_entry *de_ref;
 	struct cache_tree_sub **down;
 };
 
diff --git a/cache.h b/cache.h
index 71b98cf..1a634dc 100644
--- a/cache.h
+++ b/cache.h
@@ -137,11 +137,31 @@ struct cache_entry {
 	unsigned int ce_namelen;
 	unsigned char sha1[20];
 	uint32_t ce_stat_crc;
+	unsigned int entry_pos;
+	unsigned int changed;
 	struct cache_entry *next; /* used by name_hash */
 	struct cache_entry *next_ce;
 	char name[FLEX_ARRAY]; /* more */
 };
 
+struct directory_entry {
+	struct directory_entry **sub;
+	struct directory_entry *next;
+	struct directory_entry *next_hash;
+	struct cache_entry *ce;
+	struct cache_entry *ce_last;
+	uint32_t de_foffset;
+	uint32_t de_nsubtrees;
+	uint32_t de_nfiles;
+	uint32_t de_nentries;
+	unsigned char sha1[20];
+	uint16_t de_flags;
+	uint32_t de_pathlen;
+	uint32_t entry_pos;
+	unsigned int changed;
+	char pathname[FLEX_ARRAY];
+};
+
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_EXTENDED  (0x4000)
@@ -317,13 +337,15 @@ struct filter_opts {
 
 struct index_state {
 	struct cache_entry **cache;
+	struct directory_entry *root_directory;
 	unsigned int version;
 	unsigned int cache_nr, cache_alloc, cache_changed;
 	struct string_list *resolve_undo;
 	struct cache_tree *cache_tree;
 	struct cache_time timestamp;
 	unsigned name_hash_initialized : 1,
-		 initialized : 1;
+		 initialized : 1,
+		 needs_rewrite : 1;
 	struct hash_table name_hash;
 	struct hash_table dir_hash;
 	struct index_ops *ops;
@@ -353,6 +375,7 @@ extern void free_name_hash(struct index_state *istate);
 #define is_cache_unborn() is_index_unborn(&the_index)
 #define read_cache_unmerged() read_index_unmerged(&the_index)
 #define write_cache(newfd, cache, entries) write_index(&the_index, (newfd))
+#define write_cache_partial(newfd) write_index_partial(&the_index, (newfd))
 #define discard_cache() discard_index(&the_index)
 #define unmerged_cache() unmerged_index(&the_index)
 #define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
@@ -529,6 +552,7 @@ extern int read_index_from(struct index_state *, const char *path);
 extern int is_index_unborn(struct index_state *);
 extern int read_index_unmerged(struct index_state *);
 extern int write_index(struct index_state *, int newfd);
+extern int write_index_partial(struct index_state *, int newfd);
 extern int discard_index(struct index_state *);
 extern int unmerged_index(const struct index_state *);
 extern int verify_path(const char *path);
@@ -613,6 +637,7 @@ extern NORETURN void unable_to_lock_index_die(const char *path, int err);
 extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
 extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
 extern int commit_lock_file(struct lock_file *);
+extern void remove_lock_file(void);
 extern void update_index_if_able(struct index_state *, struct lock_file *);
 
 extern int hold_locked_index(struct lock_file *, int);
diff --git a/lockfile.c b/lockfile.c
index 8fbcb6a..c150e5c 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -7,7 +7,7 @@
 static struct lock_file *lock_file_list;
 static const char *alternate_index_output;
 
-static void remove_lock_file(void)
+void remove_lock_file(void)
 {
 	pid_t me = getpid();
 
diff --git a/read-cache-v2.c b/read-cache-v2.c
index f884c10..1fec892 100644
--- a/read-cache-v2.c
+++ b/read-cache-v2.c
@@ -555,5 +555,7 @@ struct index_ops v2_ops = {
 	match_stat_basic,
 	verify_hdr,
 	read_index_v2,
+	write_index_v2,
+	/* Partial writing is the same as writing the full index for v2 */
 	write_index_v2
 };
diff --git a/read-cache-v5.c b/read-cache-v5.c
index a5e9b5a..13436a3 100644
--- a/read-cache-v5.c
+++ b/read-cache-v5.c
@@ -20,22 +20,6 @@ struct extension_header {
 	uint32_t crc;
 };
 
-struct directory_entry {
-	struct directory_entry **sub;
-	struct directory_entry *next;
-	struct directory_entry *next_hash;
-	struct cache_entry *ce;
-	struct cache_entry *ce_last;
-	uint32_t de_foffset;
-	uint32_t de_nsubtrees;
-	uint32_t de_nfiles;
-	uint32_t de_nentries;
-	unsigned char sha1[20];
-	uint16_t de_flags;
-	uint32_t de_pathlen;
-	char pathname[FLEX_ARRAY];
-};
-
 struct conflict_part {
 	struct conflict_part *next;
 	uint16_t flags;
@@ -246,7 +230,7 @@ static struct directory_entry *read_directories(unsigned int *dir_offset,
 		offsetof(struct ondisk_directory_entry, name) - 5;
 	disk_de = ptr_add(mmap, *dir_offset);
 	de = directory_entry_from_ondisk(disk_de, len);
-
+	de->entry_pos = *dir_offset;
 	data_len = len + 1 + offsetof(struct ondisk_directory_entry, name);
 	filecrc = ptr_add(mmap, *dir_offset + data_len);
 	if (!check_crc32(0, ptr_add(mmap, *dir_offset), data_len, ntoh_l(*filecrc)))
@@ -281,6 +265,7 @@ static int read_entry(struct cache_entry **ce, char *pathname, size_t pathlen,
 	entry_offset = first_entry_offset + ntoh_l(*beginning);
 	disk_ce = ptr_add(mmap, entry_offset);
 	*ce = cache_entry_from_ondisk(disk_ce, pathname, len, pathlen);
+	(*ce)->entry_pos = entry_offset;
 	filecrc = ptr_add(mmap, entry_offset + len + 1 + sizeof(*disk_ce));
 	if (!check_crc32(0,
 		ptr_add(mmap, entry_offset), len + 1 + sizeof(*disk_ce),
@@ -439,6 +424,7 @@ static struct cache_tree *convert_one(struct directory_entry *de)
 
 	it = cache_tree();
 	it->entry_count = de->de_nentries;
+	it->de_ref = de;
 	if (0 <= it->entry_count)
 		hashcpy(it->sha1, de->sha1);
 
@@ -523,14 +509,6 @@ static int read_entries(struct index_state *istate, struct directory_entry *de,
 	return 0;
 }
 
-static void free_directory_tree(struct directory_entry *de) {
-	int i;
-
-	for (i = 0; i < de->de_pathlen; i++)
-		free_directory_tree(de->sub[i]);
-	free(de);
-}
-
 /*
  * Read an index-v5 file filtered by the filter_opts.   If opts is NULL,
  * everything will be read.
@@ -626,7 +604,7 @@ static int read_index_v5(struct index_state *istate, void *mmap,
 		}
 	}
 	istate->cache_tree = cache_tree_convert_v5(root_directory);
-	free_directory_tree(root_directory);
+	istate->root_directory = root_directory;
 	istate->cache_nr = nr;
 	return 0;
 }
@@ -696,6 +674,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
 	 * that hasn't changed checking the sha1.
 	 */
 	ce->ce_flags |= CE_SMUDGED;
+	ce->changed = 1;
 }
 
 static char *super_directory(char *filename)
@@ -1231,6 +1210,103 @@ static int write_resolve_undo(struct index_state *istate,
 	return 0;
 }
 
+static int write_ce_if_necessary(struct cache_entry *ce, void *cb_data)
+{
+	int *fdx = cb_data, pathlen, size;
+	int fd = *fdx;
+	char *dir;
+	struct ondisk_cache_entry *ondisk;
+	uint32_t crc;
+
+	assert(ce->entry_pos != 0);
+	/* TODO I'm just using the_index out of lazyness here */
+	if (!ce_uptodate(ce) && is_racy_timestamp(&the_index, ce))
+		ce_smudge_racily_clean_entry(ce);
+	if (!ce->changed)
+		return 0;
+	if (is_null_sha1(ce->sha1)) {
+		static const char msg[] = "cache entry has null sha1: %s";
+		static int allow = -1;
+
+		if (allow < 0)
+			allow = git_env_bool("GIT_ALLOW_NULL_SHA1", 0);
+		if (allow)
+			warning(msg, ce->name);
+		else
+			return error(msg, ce->name);
+	}
+	dir = super_directory(ce->name);
+	pathlen = dir ? strlen(dir) + 1 : 0;
+	size = offsetof(struct ondisk_cache_entry, name) +
+		ce_namelen(ce) - pathlen + 1;
+	ondisk = xmalloc(size);
+	
+	crc = 0;
+	ondisk_from_cache_entry(ce, ondisk, pathlen);
+	if (lseek(fd, ce->entry_pos, SEEK_SET) < ce->entry_pos)
+		die("eror ce seeking");
+	if (ce_write(&crc, fd, ondisk, size) < 0)
+		return -1;
+	crc = htonl(crc);
+	if (ce_write(NULL, fd, &crc, 4) < 0)
+		return -1;
+	return ce_flush(fd);
+}
+
+static void ondisk_from_directory_entry_partial(struct directory_entry *de,
+						struct ondisk_directory_entry *ondisk)
+{
+	ondisk->foffset   = htonl(de->de_foffset);
+	ondisk->nsubtrees = htonl(de->de_nsubtrees);
+	ondisk->nfiles    = htonl(de->de_nfiles);
+	ondisk->nentries  = htonl(de->de_nentries);
+	hashcpy(ondisk->sha1, de->sha1);
+	ondisk->flags     = htons(de->de_flags);
+	if (de->de_pathlen == 0) {
+		memcpy(ondisk->name, "\0", 1);
+	} else {
+		memcpy(ondisk->name, de->pathname, de->de_pathlen);
+		memcpy(ondisk->name + de->de_pathlen - 1, "/\0", 2);
+	}
+}
+
+static int write_directories_partial(struct directory_entry *de, int fd)
+{
+	int ondisk_size = offsetof(struct ondisk_directory_entry, name);
+	int size = ondisk_size + de->de_pathlen + 1;
+	int i;
+	uint32_t crc;
+	struct ondisk_directory_entry *ondisk;
+
+	if (de->changed) {
+		crc = 0;
+		ondisk = xmalloc(size);
+		ondisk_from_directory_entry_partial(de, ondisk);
+		if (lseek(fd, de->entry_pos, SEEK_SET) < de->entry_pos)
+			die("error directory seeking");;
+		if (ce_write(&crc, fd, ondisk, size) < 0)
+			return -1;
+		crc = htonl(crc);
+		if (ce_write(NULL, fd, &crc, 4) < 0)
+			return -1;
+		free(ondisk);
+		if (ce_flush(fd) < 0)
+			return -1;
+	}
+	for (i = 0; i < de->de_nsubtrees; i++) {
+		if (write_directories_partial(de->sub[i], fd) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+static int write_partial(struct index_state *istate, int fd)
+{
+	write_directories_partial(istate->root_directory, fd);
+
+	return for_each_index_entry(istate, write_ce_if_necessary, &fd);
+}
+
 static int write_index_v5(struct index_state *istate, int newfd)
 {
 	struct cache_header hdr;
@@ -1296,9 +1372,33 @@ static int write_index_v5(struct index_state *istate, int newfd)
 	return ce_flush(newfd);
 }
 
+static int write_index_partial_v5(struct index_state *istate, int newfd)
+{
+	int fd;
+	char *path = get_index_file();
+
+	if (istate->needs_rewrite || istate->cache_nr == 0)
+		return write_index_v5(istate, newfd);
+	if (istate->filter_opts && istate->needs_rewrite)
+		die("BUG: cannot write a partially read index");
+	fd = open(path, O_RDWR, 0666);
+	if (fd < 0) {
+		if (errno == ENOENT)
+			die("no index file exists cannot do a partial write");
+		die_errno("index file opening for writing failed");
+	}
+
+	if (write_partial(istate, fd) < 0)
+		return -1;
+	if (ce_flush(fd) < 0)
+		return -1;
+	return 1;
+}
+
 struct index_ops v5_ops = {
 	match_stat_basic,
 	verify_hdr,
 	read_index_v5,
-	write_index_v5
+	write_index_v5,
+	write_index_partial_v5
 };
diff --git a/read-cache.c b/read-cache.c
index 04430e5..1cad0e2 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -32,6 +32,9 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache
 
 	remove_name_hash(istate, old);
 	set_index_entry(istate, nr, ce);
+	ce->changed = 1;
+	if (ce->entry_pos == 0)
+		istate->needs_rewrite = 1;
 	istate->cache_changed = 1;
 }
 
@@ -494,6 +497,7 @@ int remove_index_entry_at(struct index_state *istate, int pos)
 
 	record_resolve_undo(istate, ce);
 	remove_name_hash(istate, ce);
+	istate->needs_rewrite = 1;
 	istate->cache_changed = 1;
 	istate->cache_nr--;
 	if (pos >= istate->cache_nr)
@@ -520,6 +524,7 @@ void remove_marked_cache_entries(struct index_state *istate)
 		else
 			ce_array[j++] = ce_array[i];
 	}
+	istate->needs_rewrite = 1;
 	istate->cache_changed = 1;
 	istate->cache_nr = j;
 }
@@ -1024,6 +1029,7 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
 			istate->cache + pos,
 			(istate->cache_nr - pos - 1) * sizeof(ce));
 	set_index_entry(istate, pos, ce);
+	istate->needs_rewrite = 1;
 	istate->cache_changed = 1;
 	return 0;
 }
@@ -1108,6 +1114,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
 	size = ce_size(ce);
 	updated = xmalloc(size);
 	memcpy(updated, ce, size);
+	updated->changed = 1;
+	updated->entry_pos = ce->entry_pos;
 	fill_stat_cache_info(updated, &st);
 	/*
 	 * If ignore_valid is not set, we should leave CE_VALID bit
@@ -1201,6 +1209,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,
 				 * means the index is not valid anymore.
 				 */
 				ce->ce_flags &= ~CE_VALID;
+				/* TODO: remove this maybe? */
+				istate->needs_rewrite = 1;
 				istate->cache_changed = 1;
 			}
 			if (quiet)
@@ -1241,6 +1251,8 @@ void initialize_index(struct index_state *istate, int version)
 			version = atoi(envversion);
 	}
 	istate->version = version;
+	istate->needs_rewrite = 0;
+	istate->root_directory = NULL;
 	set_istate_ops(istate);
 }
 
@@ -1427,6 +1439,16 @@ int is_index_unborn(struct index_state *istate)
 	return (!istate->cache_nr && !istate->timestamp.sec);
 }
 
+static void free_directory_tree(struct directory_entry *de) {
+	int i;
+
+	if (!de)
+		return;
+	for (i = 0; i < de->de_pathlen; i++)
+		free_directory_tree(de->sub[i]);
+	free(de);
+}
+
 int discard_index(struct index_state *istate)
 {
 	int i;
@@ -1435,6 +1457,7 @@ int discard_index(struct index_state *istate)
 		free(istate->cache[i]);
 	resolve_undo_clear_index(istate);
 	istate->cache_nr = 0;
+	istate->needs_rewrite = 0;
 	istate->cache_changed = 0;
 	istate->timestamp.sec = 0;
 	istate->timestamp.nsec = 0;
@@ -1446,6 +1469,8 @@ int discard_index(struct index_state *istate)
 	istate->cache_alloc = 0;
 	istate->ops = NULL;
 	istate->filter_opts = NULL;
+	free_directory_tree(istate->root_directory);
+	istate->root_directory = NULL;
 	return 0;
 }
 
@@ -1491,6 +1516,11 @@ int write_index(struct index_state *istate, int newfd)
 	return istate->ops->write_index(istate, newfd);
 }
 
+int write_index_partial(struct index_state *istate, int newfd)
+{
+	return istate->ops->write_index_partial(istate, newfd);
+}
+
 /*
  * Read the index file that is potentially unmerged into given
  * index_state, dropping any unmerged entries.  Returns true if
diff --git a/read-cache.h b/read-cache.h
index 9d66df6..e7f36ae 100644
--- a/read-cache.h
+++ b/read-cache.h
@@ -31,6 +31,7 @@ struct index_ops {
 	int (*read_index)(struct index_state *istate, void *mmap, unsigned long mmap_size,
 			  struct filter_opts *opts);
 	int (*write_index)(struct index_state *istate, int newfd);
+	int (*write_index_partial)(struct index_state *istate, int newfd);
 };
 
 extern struct index_ops v2_ops;
diff --git a/resolve-undo.c b/resolve-undo.c
index c09b006..c496c20 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -110,6 +110,7 @@ void resolve_undo_clear_index(struct index_state *istate)
 	string_list_clear(resolve_undo, 1);
 	free(resolve_undo);
 	istate->resolve_undo = NULL;
+	istate->needs_rewrite = 1;
 	istate->cache_changed = 1;
 }
 
-- 
1.8.4.2

  parent reply	other threads:[~2013-11-27 12:02 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-11-27 12:00 [PATCH v4 00/24] Index-v5 Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 01/24] t2104: Don't fail for index versions other than [23] Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 02/24] read-cache: split index file version specific functionality Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 03/24] read-cache: move index v2 specific functions to their own file Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 04/24] read-cache: Re-read index if index file changed Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 05/24] add documentation for the index api Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 06/24] read-cache: add index reading api Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 07/24] make sure partially read index is not changed Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 08/24] grep.c: use index api Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 09/24] ls-files.c: " Thomas Gummerer
2013-11-30  9:17   ` Duy Nguyen
2013-11-30 10:30     ` Thomas Gummerer
2013-11-30 15:39   ` Antoine Pelisse
2013-11-30 20:08     ` Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 10/24] documentation: add documentation of the index-v5 file format Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 11/24] read-cache: make in-memory format aware of stat_crc Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 12/24] read-cache: read index-v5 Thomas Gummerer
2013-11-30  9:17   ` Duy Nguyen
2013-11-30 10:40     ` Thomas Gummerer
2013-11-30 12:19   ` Antoine Pelisse
2013-11-30 20:10     ` Thomas Gummerer
2013-11-30 15:26   ` Antoine Pelisse
2013-11-30 20:27     ` Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 13/24] read-cache: read resolve-undo data Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 14/24] read-cache: read cache-tree in index-v5 Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 15/24] read-cache: write index-v5 Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 16/24] read-cache: write index-v5 cache-tree data Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 17/24] read-cache: write resolve-undo data for index-v5 Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 18/24] update-index.c: rewrite index when index-version is given Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 19/24] p0003-index.sh: add perf test for the index formats Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 20/24] introduce GIT_INDEX_VERSION environment variable Thomas Gummerer
2013-11-27 21:57   ` Eric Sunshine
2013-11-27 22:08     ` Junio C Hamano
2013-11-28  9:57       ` Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 21/24] test-lib: allow setting the index format version Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 22/24] t1600: add index v5 specific tests Thomas Gummerer
2013-11-27 12:00 ` Thomas Gummerer [this message]
2013-11-30  9:58   ` [PATCH v4 23/24] POC for partial writing Duy Nguyen
2013-11-30 10:50     ` Thomas Gummerer
2013-11-27 12:00 ` [PATCH v4 24/24] perf: add partial writing test Thomas Gummerer
2013-12-09 10:14 ` [PATCH v4 00/24] Index-v5 Thomas Gummerer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1385553659-9928-24-git-send-email-t.gummerer@gmail.com \
    --to=t.gummerer@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=mhagger@alum.mit.edu \
    --cc=pclouds@gmail.com \
    --cc=ramsay@ramsay1.demon.co.uk \
    --cc=robin.rosenberg@dewire.com \
    --cc=sunshine@sunshineco.com \
    --cc=tr@thomasrast.ch \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).