diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 6ac5813e7..b659c015b 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -271,7 +271,7 @@ exceptionCaughtDuringExcecutionOfCommand=Exception caught during execution of co 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 +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. expectedACKNAKFoundEOF=Expected ACK/NAK, found EOF expectedACKNAKGot=Expected ACK/NAK, got: {0} expectedBooleanStringValue=Expected boolean string value @@ -475,7 +475,7 @@ packfileIsTruncated=Packfile {0} is truncated. packfileIsTruncatedNoParam=Packfile is truncated. packHandleIsStale=Pack file {0} handle is stale, removing it from pack list packHasUnresolvedDeltas=pack has unresolved deltas -packInaccessible=Pack file {0} now inaccessible; removing it from pack list +packInaccessible=Failed to access pack file {0}, caught {2} consecutive errors while trying to access this pack. packingCancelledDuringObjectsWriting=Packing cancelled during objects writing packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2} packRefs=Pack refs diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java index 1aa71e5a5..00e39533b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java @@ -349,6 +349,7 @@ public class ObjectDirectory extends FileObjectDatabase { for (PackFile p : pList.packs) { try { p.resolve(matches, id, RESOLVE_ABBREV_LIMIT); + p.resetTransientErrorCount(); } catch (IOException e) { handlePackError(e, p); } @@ -430,6 +431,7 @@ public class ObjectDirectory extends FileObjectDatabase { for (PackFile p : pList.packs) { try { ObjectLoader ldr = p.get(curs, objectId); + p.resetTransientErrorCount(); if (ldr != null) return ldr; } catch (PackMismatchException e) { @@ -510,6 +512,7 @@ public class ObjectDirectory extends FileObjectDatabase { for (PackFile p : pList.packs) { try { long len = p.getObjectSize(curs, id); + p.resetTransientErrorCount(); if (0 <= len) return len; } catch (PackMismatchException e) { @@ -549,6 +552,7 @@ public class ObjectDirectory extends FileObjectDatabase { for (final PackFile p : pList.packs) { try { LocalObjectRepresentation rep = p.representation(curs, otp); + p.resetTransientErrorCount(); if (rep != null) packer.select(otp, rep); } catch (PackMismatchException e) { @@ -569,6 +573,8 @@ public class ObjectDirectory extends FileObjectDatabase { private void handlePackError(IOException e, PackFile p) { String warnTmpl = null; + int transientErrorCount = 0; + String errTmpl = JGitText.get().exceptionWhileReadingPack; if ((e instanceof CorruptObjectException) || (e instanceof PackInvalidException)) { warnTmpl = JGitText.get().corruptPack; @@ -576,14 +582,17 @@ public class ObjectDirectory extends FileObjectDatabase { removePack(p); } else if (e instanceof FileNotFoundException) { if (p.getPackFile().exists()) { - warnTmpl = JGitText.get().packInaccessible; + errTmpl = JGitText.get().packInaccessible; + transientErrorCount = p.incrementTransientErrorCount(); } else { warnTmpl = JGitText.get().packWasDeleted; + removePack(p); } - removePack(p); } else if (FileUtils.isStaleFileHandleInCausalChain(e)) { warnTmpl = JGitText.get().packHandleIsStale; removePack(p); + } else { + transientErrorCount = p.incrementTransientErrorCount(); } if (warnTmpl != null) { if (LOG.isDebugEnabled()) { @@ -594,14 +603,25 @@ public class ObjectDirectory extends FileObjectDatabase { p.getPackFile().getAbsolutePath())); } } else { - // Don't remove the pack from the list, as the error may be - // transient. - LOG.error(MessageFormat.format( - JGitText.get().exceptionWhileReadingPack, p.getPackFile() - .getAbsolutePath()), e); + if (doLogExponentialBackoff(transientErrorCount)) { + // 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); + } } } + /** + * @param n + * count of consecutive failures + * @return @{code true} if i is a power of 2 + */ + private boolean doLogExponentialBackoff(int n) { + return (n & (n - 1)) == 0; + } + @Override InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id, boolean createDuplicate) throws IOException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java index d90e2cf2b..f4a77d2a2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java @@ -62,6 +62,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.CRC32; import java.util.zip.DataFormatException; import java.util.zip.Inflater; @@ -127,6 +128,8 @@ public class PackFile implements Iterable { private boolean invalidBitmap; + private AtomicInteger transientErrorCount = new AtomicInteger(); + private byte[] packChecksum; private PackIndex loadedIdx; @@ -571,6 +574,14 @@ public class PackFile implements Iterable { invalid = true; } + int incrementTransientErrorCount() { + return transientErrorCount.incrementAndGet(); + } + + void resetTransientErrorCount() { + transientErrorCount.set(0); + } + private void readFully(final long position, final byte[] dstbuf, int dstoff, final int cnt, final WindowCursor curs) throws IOException {