@@ -47,27 +47,35 @@ import static java.lang.Integer.valueOf; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.io.IOException; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.concurrent.BrokenBarrierException; | |||
import java.util.concurrent.Callable; | |||
import java.util.concurrent.CountDownLatch; | |||
import java.util.concurrent.CyclicBarrier; | |||
import java.util.concurrent.ExecutionException; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
import java.util.concurrent.Future; | |||
import java.util.concurrent.TimeUnit; | |||
import org.eclipse.jgit.errors.CancelledException; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.internal.storage.pack.PackWriter; | |||
import org.eclipse.jgit.junit.TestRepository; | |||
import org.eclipse.jgit.lib.ConfigConstants; | |||
import org.eclipse.jgit.lib.EmptyProgressMonitor; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.Sets; | |||
import org.eclipse.jgit.revwalk.RevBlob; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.storage.file.FileBasedConfig; | |||
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; | |||
import org.junit.Test; | |||
public class GcConcurrentTest extends GcTestCase { | |||
@@ -221,4 +229,48 @@ public class GcConcurrentTest extends GcTestCase { | |||
assertEquals(getSinglePack(repository).getPackName(), newPackName); | |||
assertNotNull(getSinglePack(repository).getBitmapIndex()); | |||
} | |||
@Test | |||
public void testInterruptGc() throws Exception { | |||
FileBasedConfig c = repo.getConfig(); | |||
c.setInt(ConfigConstants.CONFIG_GC_SECTION, null, | |||
ConfigConstants.CONFIG_KEY_AUTOPACKLIMIT, 1); | |||
c.save(); | |||
SampleDataRepositoryTestCase.copyCGitTestPacks(repo); | |||
ExecutorService executor = Executors.newSingleThreadExecutor(); | |||
final CountDownLatch latch = new CountDownLatch(1); | |||
Future<Collection<PackFile>> result = executor | |||
.submit(new Callable<Collection<PackFile>>() { | |||
@Override | |||
public Collection<PackFile> call() throws Exception { | |||
long start = System.currentTimeMillis(); | |||
System.out.println("starting gc"); | |||
latch.countDown(); | |||
Collection<PackFile> r = gc.gc(); | |||
System.out.println("gc took " | |||
+ (System.currentTimeMillis() - start) + " ms"); | |||
return r; | |||
} | |||
}); | |||
try { | |||
latch.await(); | |||
Thread.sleep(5); | |||
executor.shutdownNow(); | |||
result.get(); | |||
fail("thread wasn't interrupted"); | |||
} catch (ExecutionException e) { | |||
Throwable cause = e.getCause(); | |||
if (cause instanceof CancelledException) { | |||
assertEquals(JGitText.get().operationCanceled, | |||
cause.getMessage()); | |||
} else if (cause instanceof IOException) { | |||
Throwable cause2 = cause.getCause(); | |||
assertTrue(cause2 instanceof InterruptedException | |||
|| cause2 instanceof ExecutionException); | |||
} else { | |||
fail("unexpected exception " + e); | |||
} | |||
} | |||
} | |||
} |
@@ -290,7 +290,7 @@ exceptionCaughtDuringExecutionOfTagCommand=Exception caught during execution of | |||
exceptionHookExecutionInterrupted=Execution of "{0}" hook interrupted. | |||
exceptionOccurredDuringAddingOfOptionToALogCommand=Exception occurred during adding of {0} as option to a Log command | |||
exceptionOccurredDuringReadingOfGIT_DIR=Exception occurred during reading of $GIT_DIR/{0}. {1} | |||
exceptionWhileReadingPack=ERROR: Exception caught while accessing pack file {0}, the pack file might be corrupt, {1}. Caught {2} consecutive errors while trying to read this pack. | |||
exceptionWhileReadingPack=Exception caught while accessing pack file {0}, the pack file might be corrupt. Caught {1} consecutive errors while trying to read this pack. | |||
expectedACKNAKFoundEOF=Expected ACK/NAK, found EOF | |||
expectedACKNAKGot=Expected ACK/NAK, got: {0} | |||
expectedBooleanStringValue=Expected boolean string value | |||
@@ -520,7 +520,7 @@ openingConnection=Opening connection | |||
operationCanceled=Operation {0} was canceled | |||
outputHasAlreadyBeenStarted=Output has already been started. | |||
overflowedReftableBlock=Overflowed reftable block | |||
packChecksumMismatch=Pack checksum mismatch detected for pack file {0} | |||
packChecksumMismatch=Pack checksum mismatch detected for pack file {0}: .pack has {1} whilst .idx has {2} | |||
packCorruptedWhileWritingToFilesystem=Pack corrupted while writing to filesystem | |||
packDoesNotMatchIndex=Pack {0} does not match index | |||
packedRefsHandleIsStale=packed-refs handle is stale, {0}. retry | |||
@@ -723,6 +723,7 @@ truncatedHunkOldLinesMissing=Truncated hunk, at least {0} old lines is missing | |||
tSizeMustBeGreaterOrEqual1=tSize must be >= 1 | |||
unableToCheckConnectivity=Unable to check connectivity. | |||
unableToCreateNewObject=Unable to create new object: {0} | |||
unableToReadPackfile=Unable to read packfile {0} | |||
unableToRemovePath=Unable to remove path ''{0}'' | |||
unableToStore=Unable to store {0}. | |||
unableToWrite=Unable to write {0} |
@@ -783,6 +783,7 @@ public class JGitText extends TranslationBundle { | |||
/***/ public String tSizeMustBeGreaterOrEqual1; | |||
/***/ public String unableToCheckConnectivity; | |||
/***/ public String unableToCreateNewObject; | |||
/***/ public String unableToReadPackfile; | |||
/***/ public String unableToRemovePath; | |||
/***/ public String unableToStore; | |||
/***/ public String unableToWrite; |
@@ -1270,7 +1270,7 @@ public class GC { | |||
} | |||
private void checkCancelled() throws CancelledException { | |||
if (pm.isCancelled()) { | |||
if (pm.isCancelled() || Thread.currentThread().isInterrupted()) { | |||
throw new CancelledException(JGitText.get().operationCanceled); | |||
} | |||
} |
@@ -359,7 +359,9 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
// The hasObject call should have only touched the index, | |||
// so any failure here indicates the index is unreadable | |||
// by this process, and the pack is likewise not readable. | |||
LOG.warn("Unable to read packfile " + p.getPackFile(), e); | |||
LOG.warn(MessageFormat.format( | |||
JGitText.get().unableToReadPackfile, | |||
p.getPackFile().getAbsolutePath()), e); | |||
removePack(p); | |||
} | |||
} | |||
@@ -652,7 +654,8 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
if ((e instanceof CorruptObjectException) | |||
|| (e instanceof PackInvalidException)) { | |||
warnTmpl = JGitText.get().corruptPack; | |||
LOG.warn("Packfile " + p.getPackFile() + " is corrupted", e); | |||
LOG.warn(MessageFormat.format(warnTmpl, | |||
p.getPackFile().getAbsolutePath()), e); | |||
// Assume the pack is corrupted, and remove it from the list. | |||
removePack(p); | |||
} else if (e instanceof FileNotFoundException) { | |||
@@ -682,8 +685,8 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
// Don't remove the pack from the list, as the error may be | |||
// transient. | |||
LOG.error(MessageFormat.format(errTmpl, | |||
p.getPackFile().getAbsolutePath()), | |||
Integer.valueOf(transientErrorCount), e); | |||
p.getPackFile().getAbsolutePath(), | |||
Integer.valueOf(transientErrorCount)), e); | |||
} | |||
} | |||
} |
@@ -187,7 +187,9 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
} else if (!Arrays.equals(packChecksum, idx.packChecksum)) { | |||
throw new PackMismatchException(MessageFormat.format( | |||
JGitText.get().packChecksumMismatch, | |||
packFile.getPath())); | |||
packFile.getPath(), | |||
ObjectId.fromRaw(packChecksum).name(), | |||
ObjectId.fromRaw(idx.packChecksum).name())); | |||
} | |||
loadedIdx = idx; | |||
} catch (InterruptedIOException e) { | |||
@@ -753,10 +755,10 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
fd.readFully(buf, 0, 20); | |||
if (!Arrays.equals(buf, packChecksum)) { | |||
throw new PackMismatchException(MessageFormat.format( | |||
JGitText.get().packObjectCountMismatch | |||
, ObjectId.fromRaw(buf).name() | |||
, ObjectId.fromRaw(idx.packChecksum).name() | |||
, getPackFile())); | |||
JGitText.get().packChecksumMismatch, | |||
getPackFile(), | |||
ObjectId.fromRaw(buf).name(), | |||
ObjectId.fromRaw(idx.packChecksum).name())); | |||
} | |||
} | |||