Commit d1101263 by Edward Thomson Committed by Edward Thomson

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.
parent cb0ff012
...@@ -767,7 +767,8 @@ static int truncate_racily_clean(git_index *index) ...@@ -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; diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
git_vector_foreach(&index->entries, i, entry) { 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); git_vector_insert(&paths, (char *)entry->path);
} }
...@@ -1295,6 +1296,9 @@ static int index_insert( ...@@ -1295,6 +1296,9 @@ static int index_insert(
else else
entry->flags |= GIT_IDXENTRY_NAMEMASK; 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) { if (git_mutex_lock(&index->lock) < 0) {
giterr_set(GITERR_OS, "Unable to acquire index lock"); giterr_set(GITERR_OS, "Unable to acquire index lock");
return -1; return -1;
...@@ -2558,7 +2562,8 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry) ...@@ -2558,7 +2562,8 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
if (entry->flags & GIT_IDXENTRY_EXTENDED) { if (entry->flags & GIT_IDXENTRY_EXTENDED) {
struct entry_long *ondisk_ext; struct entry_long *ondisk_ext;
ondisk_ext = (struct entry_long *)ondisk; 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; path = ondisk_ext->path;
} }
else else
......
...@@ -145,3 +145,80 @@ void test_index_racy__empty_file_after_smudge(void) ...@@ -145,3 +145,80 @@ void test_index_racy__empty_file_after_smudge(void)
git_buf_free(&path); git_buf_free(&path);
git_diff_free(diff); 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment