]> source.dussan.org Git - jgit.git/commitdiff
Fire IndexChangedEvent on DirCache.commit() 19/4219/9
authorMatthias Sohn <matthias.sohn@sap.com>
Thu, 29 Sep 2011 22:00:22 +0000 (00:00 +0200)
committerMatthias Sohn <matthias.sohn@sap.com>
Thu, 29 Sep 2011 22:00:22 +0000 (00:00 +0200)
Since we replaced GitIndex by DirCache JGit didn't fire
IndexChangedEvents anymore. For EGit this still worked with a high
latency since its RepositoryChangeScanner which is scheduled to
run each 10 seconds fires the event in case the index changes.
This scanner is meant to detect index changes induced by a different
process e.g. by calling "git add" from native git.

When the index is changed from within the same process we should fire
the event synchronously. Compare the index checksum on write to index
checksum when index was read earlier to determine if index really
changed. Use IndexChangedListener interface to keep DirCache decoupled
from Repository.

Change-Id: Id4311f7a7859ffe8738863b3d86c83c8b5f513af
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/DhtRepository.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepository.java

index 9f60ef575862651d653671bf5cf85148565ae974..faff469e90092964785c6c3a7265ac34701bd8fc 100644 (file)
@@ -153,6 +153,11 @@ public class DhtRepository extends Repository {
                refdb.clearCache();
        }
 
+       @Override
+       public void notifyIndexChanged() {
+               // we do not support non-bare repositories yet
+       }
+
        @Override
        public String toString() {
                return "DhtRepostitory[" + key + " / " + name + "]";
index 1c1cb0fcbc21153c1c514f03bc502f65548e9223..c64ca88f0dead956ebde7eb921cba56b6fd9d89c 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2008-2009, Google Inc.
+ * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -49,9 +50,13 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 
+import org.eclipse.jgit.events.IndexChangedEvent;
+import org.eclipse.jgit.events.IndexChangedListener;
+import org.eclipse.jgit.events.ListenerList;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.RepositoryTestCase;
@@ -187,6 +192,73 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
                }
        }
 
+       @Test
+       public void testBuildOneFile_Commit_IndexChangedEvent()
+                       throws Exception {
+               final class ReceivedEventMarkerException extends RuntimeException {
+                       private static final long serialVersionUID = 1L;
+                       // empty
+               }
+
+               final String path = "a-file-path";
+               final FileMode mode = FileMode.REGULAR_FILE;
+               // "old" date in 2008
+               final long lastModified = 1218123387057L;
+               final int length = 1342;
+               DirCacheEntry entOrig;
+               boolean receivedEvent = false;
+
+               DirCache dc = db.lockDirCache();
+               IndexChangedListener listener = new IndexChangedListener() {
+
+                       public void onIndexChanged(IndexChangedEvent event) {
+                               throw new ReceivedEventMarkerException();
+                       }
+               };
+
+               ListenerList l = db.getListenerList();
+               l.addIndexChangedListener(listener);
+               DirCacheBuilder b = dc.builder();
+
+               entOrig = new DirCacheEntry(path);
+               entOrig.setFileMode(mode);
+               entOrig.setLastModified(lastModified);
+               entOrig.setLength(length);
+               b.add(entOrig);
+               try {
+                       b.commit();
+               } catch (ReceivedEventMarkerException e) {
+                       receivedEvent = true;
+               }
+               if (!receivedEvent)
+                       fail("did not receive IndexChangedEvent");
+
+               // do the same again, as this doesn't change index compared to first
+               // round we should get no event this time
+               dc = db.lockDirCache();
+               listener = new IndexChangedListener() {
+
+                       public void onIndexChanged(IndexChangedEvent event) {
+                               throw new ReceivedEventMarkerException();
+                       }
+               };
+
+               l = db.getListenerList();
+               l.addIndexChangedListener(listener);
+               b = dc.builder();
+
+               entOrig = new DirCacheEntry(path);
+               entOrig.setFileMode(mode);
+               entOrig.setLastModified(lastModified);
+               entOrig.setLength(length);
+               b.add(entOrig);
+               try {
+                       b.commit();
+               } catch (ReceivedEventMarkerException e) {
+                       fail("unexpected IndexChangedEvent");
+               }
+       }
+
        @Test
        public void testFindSingleFile() throws Exception {
                final String path = "a-file-path";
index af98c33151ba27d16e740867de8cff9ba2b763fd..55256d638e89a5ab93d173dc860d1609070e3c5b 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2008-2010, Google Inc.
  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -63,6 +64,8 @@ import java.util.Comparator;
 import org.eclipse.jgit.JGitText;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.UnmergedPathException;
+import org.eclipse.jgit.events.IndexChangedEvent;
+import org.eclipse.jgit.events.IndexChangedListener;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
@@ -94,6 +97,8 @@ public class DirCache {
 
        private static final DirCacheEntry[] NO_ENTRIES = {};
 
+       private static final byte[] NO_CHECKSUM = {};
+
        static final Comparator<DirCacheEntry> ENT_CMP = new Comparator<DirCacheEntry>() {
                public int compare(final DirCacheEntry o1, final DirCacheEntry o2) {
                        final int cr = cmp(o1, o2);
@@ -203,6 +208,39 @@ public class DirCache {
                return c;
        }
 
+       /**
+        * Create a new in-core index representation, lock it, and read from disk.
+        * <p>
+        * The new index will be locked and then read before it is returned to the
+        * caller. Read failures are reported as exceptions and therefore prevent
+        * the method from returning a partially populated index. On read failure,
+        * the lock is released.
+        *
+        * @param indexLocation
+        *            location of the index file on disk.
+        * @param fs
+        *            the file system abstraction which will be necessary to perform
+        *            certain file system operations.
+        * @param indexChangedListener
+        *            listener to be informed when DirCache is committed
+        * @return a cache representing the contents of the specified index file (if
+        *         it exists) or an empty cache if the file does not exist.
+        * @throws IOException
+        *             the index file is present but could not be read, or the lock
+        *             could not be obtained.
+        * @throws CorruptObjectException
+        *             the index file is using a format or extension that this
+        *             library does not support.
+        */
+       public static DirCache lock(final File indexLocation, final FS fs,
+                       IndexChangedListener indexChangedListener)
+                       throws CorruptObjectException,
+                       IOException {
+               DirCache c = lock(indexLocation, fs);
+               c.registerIndexChangedListener(indexChangedListener);
+               return c;
+       }
+
        /** Location of the current version of the index file. */
        private final File liveFile;
 
@@ -224,6 +262,15 @@ public class DirCache {
        /** Keep track of whether the index has changed or not */
        private FileSnapshot snapshot;
 
+       /** index checksum when index was read from disk */
+       private byte[] readIndexChecksum;
+
+       /** index checksum when index was written to disk */
+       private byte[] writeIndexChecksum;
+
+       /** listener to be informed on commit */
+       private IndexChangedListener indexChangedListener;
+
        /**
         * Create a new in-core index representation.
         * <p>
@@ -330,6 +377,7 @@ public class DirCache {
                sortedEntries = NO_ENTRIES;
                entryCnt = 0;
                tree = null;
+               readIndexChecksum = NO_CHECKSUM;
        }
 
        private void readFrom(final InputStream inStream) throws IOException,
@@ -412,8 +460,8 @@ public class DirCache {
                        }
                }
 
-               final byte[] exp = md.digest();
-               if (!Arrays.equals(exp, hdr)) {
+               readIndexChecksum = md.digest();
+               if (!Arrays.equals(readIndexChecksum, hdr)) {
                        throw new CorruptObjectException(JGitText.get().DIRCChecksumMismatch);
                }
        }
@@ -544,8 +592,8 @@ public class DirCache {
                        dos.write(tmp, 0, 8);
                        bb.writeTo(dos, null);
                }
-
-               os.write(foot.digest());
+               writeIndexChecksum = foot.digest();
+               os.write(writeIndexChecksum);
                os.close();
        }
 
@@ -567,6 +615,9 @@ public class DirCache {
                if (!tmp.commit())
                        return false;
                snapshot = tmp.getCommitSnapshot();
+               if (indexChangedListener != null
+                               && !Arrays.equals(readIndexChecksum, writeIndexChecksum))
+                       indexChangedListener.onIndexChanged(new IndexChangedEvent());
                return true;
        }
 
@@ -794,4 +845,8 @@ public class DirCache {
                }
                return false;
        }
+
+       private void registerIndexChangedListener(IndexChangedListener listener) {
+               this.indexChangedListener = listener;
+       }
 }
index 3a3e1c558f7c90d8369b58562268013e2e64384c..f31217a967c10cf8df76455d81b365dcee0de388 100644 (file)
@@ -69,6 +69,8 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.errors.RevisionSyntaxException;
+import org.eclipse.jgit.events.IndexChangedEvent;
+import org.eclipse.jgit.events.IndexChangedListener;
 import org.eclipse.jgit.events.ListenerList;
 import org.eclipse.jgit.events.RepositoryEvent;
 import org.eclipse.jgit.revwalk.RevBlob;
@@ -883,7 +885,15 @@ public abstract class Repository {
         */
        public DirCache lockDirCache() throws NoWorkTreeException,
                        CorruptObjectException, IOException {
-               return DirCache.lock(getIndexFile(), getFS());
+               // we want DirCache to inform us so that we can inform registered
+               // listeners about index changes
+               IndexChangedListener l = new IndexChangedListener() {
+
+                       public void onIndexChanged(IndexChangedEvent event) {
+                               notifyIndexChanged();
+                       }
+               };
+               return DirCache.lock(getIndexFile(), getFS(), l);
        }
 
        static byte[] gitInternalSlash(byte[] bytes) {
@@ -1065,6 +1075,11 @@ public abstract class Repository {
         */
        public abstract void scanForRepoChanges() throws IOException;
 
+       /**
+        * Notify that the index changed
+        */
+       public abstract void notifyIndexChanged();
+
        /**
         * @param refName
         *
index cd661e2d237c8453f233a03542a8739fc29e37a6..13776140d435c0a72c247fc09835b8969480a6f8 100644 (file)
@@ -393,10 +393,14 @@ public class FileRepository extends Repository {
                File indexFile = getIndexFile();
                if (snapshot == null)
                        snapshot = FileSnapshot.save(indexFile);
-               else if (snapshot.isModified(indexFile)) {
-                       snapshot = FileSnapshot.save(indexFile);
-                       fireEvent(new IndexChangedEvent());
-               }
+               else if (snapshot.isModified(indexFile))
+                       notifyIndexChanged();
+       }
+
+       @Override
+       public void notifyIndexChanged() {
+               snapshot = FileSnapshot.save(getIndexFile());
+               fireEvent(new IndexChangedEvent());
        }
 
        /**