summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Rosenberg <robin.rosenberg@dewire.com>2012-05-21 10:48:40 -0700
committerKevin Sawicki <kevin@github.com>2012-05-21 10:48:40 -0700
commit1953ae6aeec51dafedadb0fdb3f352ed4d027f45 (patch)
treef4a39a4a35380b5c5d9d50ee2d553b333fd92205
parent15147a273fc9085ca3cf459dec42f7a88b22ffbf (diff)
downloadjgit-1953ae6aeec51dafedadb0fdb3f352ed4d027f45.tar.gz
jgit-1953ae6aeec51dafedadb0fdb3f352ed4d027f45.zip
Smudge index entries on first write (too), as well when reading
That happens when the index and a new file is created within the same second and becomes a problem if we then modify the newly created file within the same second after adding it to the index. Without smudging JGit will, on later reads, think the file is unchanged. The accompanying test passed with the smuding on read. Change-Id: I4dfecf5c93993ef690e7f0dddb3f3e6125daae15
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java22
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java45
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LockFile.java10
4 files changed, 66 insertions, 18 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index 064100839e..b335f2d43a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -64,6 +64,7 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator.MetadataDiff;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.RawParseUtils;
@@ -216,6 +217,27 @@ public class FileTreeIteratorTest extends RepositoryTestCase {
}
@Test
+ public void testIsModifiedFileSmudged() throws Exception {
+ File f = writeTrashFile("file", "content");
+ Git git = new Git(db);
+ // The idea of this test is to check the smudged handling
+ // Hopefully fsTick will make sure our entry gets smudged
+ fsTick(f);
+ writeTrashFile("file", "content");
+ git.add().addFilepattern("file").call();
+ writeTrashFile("file", "conten2");
+ DirCacheEntry dce = db.readDirCache().getEntry("file");
+ FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), db
+ .getConfig().get(WorkingTreeOptions.KEY));
+ while (!fti.getEntryPathString().equals("file"))
+ fti.next(1);
+ // If the fsTick trick does not work we could skip the compareMetaData
+ // test and hope that we are usually testing the intended code path.
+ assertEquals(MetadataDiff.SMUDGED, fti.compareMetadata(dce));
+ assertTrue(fti.isModified(dce, false));
+ }
+
+ @Test
public void submoduleHeadMatchesIndex() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index f139b0f7f8..0d5952df24 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -60,8 +60,8 @@ import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Comparator;
-import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.events.IndexChangedEvent;
import org.eclipse.jgit.events.IndexChangedListener;
@@ -404,6 +404,10 @@ public class DirCache {
if (entryCnt < 0)
throw new CorruptObjectException(JGitText.get().DIRCHasTooManyEntries);
+ snapshot = FileSnapshot.save(liveFile);
+ int smudge_s = (int) (snapshot.lastModified() / 1000);
+ int smudge_ns = ((int) (snapshot.lastModified() % 1000)) * 1000000;
+
// Load the individual file entries.
//
final int infoLength = DirCacheEntry.getMaximumInfoLength(extended);
@@ -412,8 +416,7 @@ public class DirCache {
final MutableInteger infoAt = new MutableInteger();
for (int i = 0; i < entryCnt; i++)
- sortedEntries[i] = new DirCacheEntry(infos, infoAt, in, md);
- snapshot = FileSnapshot.save(liveFile);
+ sortedEntries[i] = new DirCacheEntry(infos, infoAt, in, md, smudge_s, smudge_ns);
// After the file entries are index extensions, and then a footer.
//
@@ -570,21 +573,29 @@ public class DirCache {
dos.write(tmp, 0, 12);
// Write the individual file entries.
- //
- if (snapshot == null) {
- // Write a new index, as no entries require smudging.
- //
- for (int i = 0; i < entryCnt; i++)
- sortedEntries[i].write(dos);
+
+ final int smudge_s;
+ final int smudge_ns;
+ if (myLock != null) {
+ // For new files we need to smudge the index entry
+ // if they have been modified "now". Ideally we'd
+ // want the timestamp when we're done writing the index,
+ // so we use the current timestamp as a approximation.
+ myLock.createCommitSnapshot();
+ snapshot = myLock.getCommitSnapshot();
+ smudge_s = (int) (snapshot.lastModified() / 1000);
+ smudge_ns = ((int) (snapshot.lastModified() % 1000)) * 1000000;
} else {
- final int smudge_s = (int) (snapshot.lastModified() / 1000);
- final int smudge_ns = ((int) (snapshot.lastModified() % 1000)) * 1000000;
- for (int i = 0; i < entryCnt; i++) {
- final DirCacheEntry e = sortedEntries[i];
- if (e.mightBeRacilyClean(smudge_s, smudge_ns))
- e.smudgeRacilyClean();
- e.write(dos);
- }
+ // Used in unit tests only
+ smudge_ns = 0;
+ smudge_s = 0;
+ }
+
+ for (int i = 0; i < entryCnt; i++) {
+ final DirCacheEntry e = sortedEntries[i];
+ if (e.mightBeRacilyClean(smudge_s, smudge_ns))
+ e.smudgeRacilyClean();
+ e.write(dos);
}
if (tree != null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index 9f5aa8cfa1..aec12e3169 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -141,7 +141,8 @@ public class DirCacheEntry {
private byte inCoreFlags;
DirCacheEntry(final byte[] sharedInfo, final MutableInteger infoAt,
- final InputStream in, final MessageDigest md) throws IOException {
+ final InputStream in, final MessageDigest md, final int smudge_s,
+ final int smudge_ns) throws IOException {
info = sharedInfo;
infoOffset = infoAt.value;
@@ -199,6 +200,10 @@ public class DirCacheEntry {
IO.skipFully(in, padLen);
md.update(nullpad, 0, padLen);
}
+
+ if (mightBeRacilyClean(smudge_s, smudge_ns))
+ smudgeRacilyClean();
+
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LockFile.java
index f3b533c133..9218121917 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LockFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LockFile.java
@@ -504,6 +504,16 @@ public class LockFile {
}
/**
+ * Update the commit snapshot {@link #getCommitSnapshot()} before commit.
+ * <p>
+ * This may be necessary if you need time stamp before commit occurs, e.g
+ * while writing the index.
+ */
+ public void createCommitSnapshot() {
+ saveStatInformation();
+ }
+
+ /**
* Unlock this file and abort this change.
* <p>
* The temporary file (if created) is deleted before returning.