aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2005-12-20 12:12:18 -0800
committerJunio C Hamano <junkio@cox.net>2005-12-20 12:12:18 -0800
commit407c8eb0d09d4b84bbfda9e04895a35c8fd6fef6 (patch)
treeadcc1c9a9794f69b21c5c39c9dd79520357df323
parent29e4d3635709778bcc808dbad0477efad82f8d7e (diff)
downloadgit-407c8eb0d09d4b84bbfda9e04895a35c8fd6fef6.tar.gz
git-407c8eb0d09d4b84bbfda9e04895a35c8fd6fef6.tar.xz
Racy GIT (part #2)
The previous round caught the most trivial case well, but broke down once index file is updated again. Smudge problematic entries (they should be very few if any under normal interactive workflow) before writing a new index file out. Signed-off-by: Junio C Hamano <junkio@cox.net>
-rw-r--r--read-cache.c32
-rwxr-xr-xt/t0010-racy-git.sh17
2 files changed, 44 insertions, 5 deletions
diff --git a/read-cache.c b/read-cache.c
index 780601f07..afdc2b075 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -87,7 +87,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
return 0;
}
-int ce_match_stat(struct cache_entry *ce, struct stat *st)
+static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
{
unsigned int changed = 0;
@@ -143,6 +143,13 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st)
if (ce->ce_size != htonl(st->st_size))
changed |= DATA_CHANGED;
+ return changed;
+}
+
+int ce_match_stat(struct cache_entry *ce, struct stat *st)
+{
+ unsigned int changed = ce_match_stat_basic(ce, st);
+
/*
* Within 1 second of this sequence:
* echo xyzzy >file && git-update-index --add file
@@ -594,6 +601,26 @@ static int ce_flush(SHA_CTX *context, int fd)
return 0;
}
+static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
+{
+ /*
+ * The only thing we care about in this function is to smudge the
+ * falsely clean entry due to touch-update-touch race, so we leave
+ * everything else as they are. We are called for entries whose
+ * ce_mtime match the index file mtime.
+ */
+ struct stat st;
+
+ if (lstat(ce->name, &st) < 0)
+ return;
+ if (ce_match_stat_basic(ce, &st))
+ return;
+ if (ce_modified_check_fs(ce, &st)) {
+ /* This is "racily clean"; smudge it */
+ ce->ce_size = htonl(0);
+ }
+}
+
int write_cache(int newfd, struct cache_entry **cache, int entries)
{
SHA_CTX c;
@@ -616,6 +643,9 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
struct cache_entry *ce = cache[i];
if (!ce->ce_mode)
continue;
+ if (index_file_timestamp &&
+ index_file_timestamp <= ntohl(ce->ce_mtime.sec))
+ ce_smudge_racily_clean_entry(ce);
if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
return -1;
}
diff --git a/t/t0010-racy-git.sh b/t/t0010-racy-git.sh
index eb175b780..e45a9e40e 100755
--- a/t/t0010-racy-git.sh
+++ b/t/t0010-racy-git.sh
@@ -7,18 +7,27 @@ test_description='racy GIT'
# This test can give false success if your machine is sufficiently
# slow or your trial happened to happen on second boundary.
-for trial in 0 1 2 3 4 5 6 7 8 9
+for trial in 0 1 2 3 4
do
rm -f .git/index
echo frotz >infocom
- echo xyzzy >activision
- git update-index --add infocom activision
+ git update-index --add infocom
echo xyzzy >infocom
files=`git diff-files -p`
test_expect_success \
- "Racy GIT trial #$trial" \
+ "Racy GIT trial #$trial part A" \
'test "" != "$files"'
+
+ sleep 1
+ echo xyzzy >cornerstone
+ git update-index --add cornerstone
+
+ files=`git diff-files -p`
+ test_expect_success \
+ "Racy GIT trial #$trial part B" \
+ 'test "" != "$files"'
+
done
test_done