summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2015-11-13 15:32:48 -0500
committerEdward Thomson <ethomson@edwardthomson.com>2015-11-16 22:58:58 -0500
commitd1101263f751a33d70ec585da908bec938f587fd (patch)
treee6680d1f92dc1a17e6d837fe23bbc75bd813d5ef
parentcb0ff012d3cb9658b88ad4f752046286ba5ea442 (diff)
downloadlibgit2-d1101263f751a33d70ec585da908bec938f587fd.tar.gz
index: don't detect raciness in uptodate entries
Keep track of entries that we believe are up-to-date, because we added the index entries since the index was loaded. This prevents us from unnecessarily examining files that we wrote during the cleanup of racy entries (when we smudge racily clean files that have a timestamp newer than or equal to the index's timestamp when we read it). Without keeping track of this, we would examine every file that we just checked out for raciness, since all their timestamps would be newer than the index's timestamp.
-rw-r--r--src/index.c9
-rw-r--r--tests/index/racy.c77
2 files changed, 84 insertions, 2 deletions
diff --git a/src/index.c b/src/index.c
index 9eb1289c3..b3fb077cc 100644
--- a/src/index.c
+++ b/src/index.c
@@ -767,7 +767,8 @@ static int truncate_racily_clean(git_index *index)
diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
git_vector_foreach(&index->entries, i, entry) {
- if (!is_racy_timestamp(&index->stamp.mtime, entry))
+ if ((entry->flags_extended & GIT_IDXENTRY_UPTODATE) == 0 &&
+ is_racy_timestamp(&index->stamp.mtime, entry))
git_vector_insert(&paths, (char *)entry->path);
}
@@ -1295,6 +1296,9 @@ static int index_insert(
else
entry->flags |= GIT_IDXENTRY_NAMEMASK;
+ /* this entry is now up-to-date and should not be checked for raciness */
+ entry->flags_extended |= GIT_IDXENTRY_UPTODATE;
+
if (git_mutex_lock(&index->lock) < 0) {
giterr_set(GITERR_OS, "Unable to acquire index lock");
return -1;
@@ -2558,7 +2562,8 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
if (entry->flags & GIT_IDXENTRY_EXTENDED) {
struct entry_long *ondisk_ext;
ondisk_ext = (struct entry_long *)ondisk;
- ondisk_ext->flags_extended = htons(entry->flags_extended);
+ ondisk_ext->flags_extended = htons(entry->flags_extended &
+ GIT_IDXENTRY_EXTENDED_FLAGS);
path = ondisk_ext->path;
}
else
diff --git a/tests/index/racy.c b/tests/index/racy.c
index df25c851c..6ff12a39a 100644
--- a/tests/index/racy.c
+++ b/tests/index/racy.c
@@ -145,3 +145,80 @@ void test_index_racy__empty_file_after_smudge(void)
git_buf_free(&path);
git_diff_free(diff);
}
+
+static void setup_uptodate_files(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_index *index;
+ git_index_entry new_entry = {0};
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "A"));
+ cl_git_mkfile(path.ptr, "A");
+
+ /* Put 'A' into the index */
+ cl_git_pass(git_index_add_bypath(index, "A"));
+
+ /* Put 'B' into the index */
+ new_entry.path = "B";
+ new_entry.mode = GIT_FILEMODE_BLOB;
+ cl_git_pass(git_index_add(index, &new_entry));
+
+ /* Put 'C' into the index */
+ new_entry.path = "C";
+ new_entry.mode = GIT_FILEMODE_BLOB;
+ cl_git_pass(git_index_add_frombuffer(index, &new_entry, "hello!\n", 7));
+
+ git_index_free(index);
+ git_buf_free(&path);
+}
+
+void test_index_racy__adding_to_index_is_uptodate(void)
+{
+ git_index *index;
+ const git_index_entry *entry;
+
+ setup_uptodate_files();
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ /* ensure that they're all uptodate */
+ cl_assert((entry = git_index_get_bypath(index, "A", 0)));
+ cl_assert_equal_i(GIT_IDXENTRY_UPTODATE, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_assert((entry = git_index_get_bypath(index, "B", 0)));
+ cl_assert_equal_i(GIT_IDXENTRY_UPTODATE, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_assert((entry = git_index_get_bypath(index, "C", 0)));
+ cl_assert_equal_i(GIT_IDXENTRY_UPTODATE, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_git_pass(git_index_write(index));
+
+ git_index_free(index);
+}
+
+void test_index_racy__reading_clears_uptodate_bit(void)
+{
+ git_index *index;
+ const git_index_entry *entry;
+
+ setup_uptodate_files();
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_write(index));
+
+ cl_git_pass(git_index_read(index, true));
+
+ /* ensure that no files are uptodate */
+ cl_assert((entry = git_index_get_bypath(index, "A", 0)));
+ cl_assert_equal_i(0, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_assert((entry = git_index_get_bypath(index, "B", 0)));
+ cl_assert_equal_i(0, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ cl_assert((entry = git_index_get_bypath(index, "C", 0)));
+ cl_assert_equal_i(0, (entry->flags_extended & GIT_IDXENTRY_UPTODATE));
+
+ git_index_free(index);
+}