From 91f5ce3a15d5df61de42fbe72a368ac513081d5b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 10 May 2012 19:13:24 -0700 Subject: Only increment mod count if packed-refs file changes Previously if a packed-refs file was racily clean then there was a 2.5 second window in which each call to getPackedRefs would increment the mod count causing a RefsChangedEvent to be fired since the FileSnapshot would report the file as modified. If a RefsChangedListener called getRef/getRefs from the onRefsChanged method then a StackOverflowError could occur since the stack could be exhausted before the 2.5 second window expired and the packed-refs file would no longer report being modified. Now a SHA-1 is computed of the packed-refs file and the mod count is only incremented when the packed refs are successfully set and the id of the new packed-refs file does not match the id of the old packed-refs file. Change-Id: I8cab6e5929479ed748812b8598c7628370e79697 --- .../jgit/storage/file/RefDirectoryTest.java | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'org.eclipse.jgit.test/tst/org/eclipse') diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/RefDirectoryTest.java index 3ca4f589db..508b690509 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/RefDirectoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/RefDirectoryTest.java @@ -60,6 +60,8 @@ import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.events.RefsChangedEvent; @@ -1077,6 +1079,36 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase { assertSame(master_p2, refdir.peel(master_p2)); } + @Test + public void testRefsChangedStackOverflow() throws Exception { + final FileRepository newRepo = createBareRepository(); + final RefDatabase refDb = newRepo.getRefDatabase(); + File packedRefs = new File(newRepo.getDirectory(), "packed-refs"); + assertTrue(packedRefs.createNewFile()); + final AtomicReference error = new AtomicReference(); + final AtomicReference exception = new AtomicReference(); + final AtomicInteger changeCount = new AtomicInteger(); + newRepo.getListenerList().addRefsChangedListener( + new RefsChangedListener() { + + public void onRefsChanged(RefsChangedEvent event) { + try { + refDb.getRefs("ref"); + changeCount.incrementAndGet(); + } catch (StackOverflowError soe) { + error.set(soe); + } catch (IOException ioe) { + exception.set(ioe); + } + } + }); + refDb.getRefs("ref"); + refDb.getRefs("ref"); + assertNull(error.get()); + assertNull(exception.get()); + assertEquals(1, changeCount.get()); + } + private void writeLooseRef(String name, AnyObjectId id) throws IOException { writeLooseRef(name, id.name() + "\n"); } -- cgit v1.2.3