Keep track of the original cause for a packfile invalidation. It is needed for the sysadmin to understand if there is a real underlying filesystem problem and repository corruption or if it is simply a consequence of a concurrency of Git operations (e.g. repack or GC). Change-Id: I06ddda9ec847844ec31616ab6d17f153a5a34e33 Signed-off-by: Luca Milanesio <luca.milanesio@gmail.com> Signed-off-by: David Pursehouse <david.pursehouse@gmail.com> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>tags/v4.5.7.201904151645-r
@@ -8,6 +8,20 @@ | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="src/org/eclipse/jgit/errors/PackInvalidException.java" type="org.eclipse.jgit.errors.PackInvalidException"> | |||
<filter id="1142947843"> | |||
<message_arguments> | |||
<message_argument value="4.5.7"/> | |||
<message_argument value="PackInvalidException(File, Throwable)"/> | |||
</message_arguments> | |||
</filter> | |||
<filter id="1142947843"> | |||
<message_arguments> | |||
<message_argument value="4.5.7"/> | |||
<message_argument value="PackInvalidException(String, Throwable)"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="src/org/eclipse/jgit/lib/ConfigConstants.java" type="org.eclipse.jgit.lib.ConfigConstants"> | |||
<filter id="336658481"> | |||
<message_arguments> |
@@ -58,9 +58,24 @@ public class PackInvalidException extends IOException { | |||
* | |||
* @param path | |||
* path of the invalid pack file. | |||
* @deprecated Use {@link #PackInvalidException(File, Throwable)}. | |||
*/ | |||
@Deprecated | |||
public PackInvalidException(final File path) { | |||
this(path.getAbsolutePath()); | |||
this(path, null); | |||
} | |||
/** | |||
* Construct a pack invalid error with cause. | |||
* | |||
* @param path | |||
* path of the invalid pack file. | |||
* @param cause | |||
* cause of the pack file becoming invalid. | |||
* @since 4.5.7 | |||
*/ | |||
public PackInvalidException(final File path, Throwable cause) { | |||
this(path.getAbsolutePath(), cause); | |||
} | |||
/** | |||
@@ -68,8 +83,23 @@ public class PackInvalidException extends IOException { | |||
* | |||
* @param path | |||
* path of the invalid pack file. | |||
* @deprecated Use {@link #PackInvalidException(String, Throwable)}. | |||
*/ | |||
@Deprecated | |||
public PackInvalidException(final String path) { | |||
super(MessageFormat.format(JGitText.get().packFileInvalid, path)); | |||
this(path, null); | |||
} | |||
/** | |||
* Construct a pack invalid error with cause. | |||
* | |||
* @param path | |||
* path of the invalid pack file. | |||
* @param cause | |||
* cause of the pack file becoming invalid. | |||
* @since 4.5.7 | |||
*/ | |||
public PackInvalidException(final String path, Throwable cause) { | |||
super(MessageFormat.format(JGitText.get().packFileInvalid, path), cause); | |||
} | |||
} |
@@ -135,6 +135,9 @@ public final class DfsPackFile { | |||
/** True once corruption has been detected that cannot be worked around. */ | |||
private volatile boolean invalid; | |||
/** Exception that caused the packfile to be flagged as invalid */ | |||
private volatile Exception invalidatingCause; | |||
/** | |||
* Lock for initialization of {@link #index} and {@link #corruptObjects}. | |||
* <p> | |||
@@ -236,8 +239,9 @@ public final class DfsPackFile { | |||
return idx; | |||
} | |||
if (invalid) | |||
throw new PackInvalidException(getPackName()); | |||
if (invalid) { | |||
throw new PackInvalidException(getPackName(), invalidatingCause); | |||
} | |||
Repository.getGlobalListenerList() | |||
.dispatch(new BeforeDfsPackIndexLoadedEvent(this)); | |||
@@ -268,6 +272,7 @@ public final class DfsPackFile { | |||
} | |||
} catch (EOFException e) { | |||
invalid = true; | |||
invalidatingCause = e; | |||
IOException e2 = new IOException(MessageFormat.format( | |||
DfsText.get().shortReadOfIndex, | |||
packDesc.getFileName(INDEX))); | |||
@@ -275,6 +280,7 @@ public final class DfsPackFile { | |||
throw e2; | |||
} catch (IOException e) { | |||
invalid = true; | |||
invalidatingCause = e; | |||
IOException e2 = new IOException(MessageFormat.format( | |||
DfsText.get().cannotReadIndex, | |||
packDesc.getFileName(INDEX))); | |||
@@ -743,8 +749,10 @@ public final class DfsPackFile { | |||
private IOException packfileIsTruncated() { | |||
invalid = true; | |||
return new IOException(MessageFormat.format( | |||
IOException exc = new IOException(MessageFormat.format( | |||
JGitText.get().packfileIsTruncated, getPackName())); | |||
invalidatingCause = exc; | |||
return exc; | |||
} | |||
private void readFully(long position, byte[] dstbuf, int dstoff, int cnt, | |||
@@ -766,8 +774,9 @@ public final class DfsPackFile { | |||
DfsBlock readOneBlock(long pos, DfsReader ctx) | |||
throws IOException { | |||
if (invalid) | |||
throw new PackInvalidException(getPackName()); | |||
if (invalid) { | |||
throw new PackInvalidException(getPackName(), invalidatingCause); | |||
} | |||
ReadableChannel rc = ctx.db.openFile(packDesc, PACK); | |||
try { |
@@ -581,13 +581,8 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
transientErrorCount = p.incrementTransientErrorCount(); | |||
} | |||
if (warnTmpl != null) { | |||
if (LOG.isDebugEnabled()) { | |||
LOG.debug(MessageFormat.format(warnTmpl, | |||
p.getPackFile().getAbsolutePath()), e); | |||
} else { | |||
LOG.warn(MessageFormat.format(warnTmpl, | |||
p.getPackFile().getAbsolutePath())); | |||
} | |||
LOG.warn(MessageFormat.format(warnTmpl, | |||
p.getPackFile().getAbsolutePath()), e); | |||
} else { | |||
if (doLogExponentialBackoff(transientErrorCount)) { | |||
// Don't remove the pack from the list, as the error may be |
@@ -133,6 +133,8 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
private volatile boolean invalid; | |||
private volatile Exception invalidatingCause; | |||
private boolean invalidBitmap; | |||
private AtomicInteger transientErrorCount = new AtomicInteger(); | |||
@@ -177,8 +179,9 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
private synchronized PackIndex idx() throws IOException { | |||
if (loadedIdx == null) { | |||
if (invalid) | |||
throw new PackInvalidException(packFile); | |||
if (invalid) { | |||
throw new PackInvalidException(packFile, invalidatingCause); | |||
} | |||
try { | |||
final PackIndex idx = PackIndex.open(extFile(INDEX)); | |||
@@ -196,6 +199,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
throw e; | |||
} catch (IOException e) { | |||
invalid = true; | |||
invalidatingCause = e; | |||
throw e; | |||
} | |||
} | |||
@@ -644,7 +648,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
private void doOpen() throws IOException { | |||
if (invalid) { | |||
throw new PackInvalidException(packFile); | |||
throw new PackInvalidException(packFile, invalidatingCause); | |||
} | |||
try { | |||
synchronized (readLock) { | |||
@@ -654,13 +658,13 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
} | |||
} catch (InterruptedIOException e) { | |||
// don't invalidate the pack, we are interrupted from another thread | |||
openFail(false); | |||
openFail(false, e); | |||
throw e; | |||
} catch (FileNotFoundException fn) { | |||
// don't invalidate the pack if opening an existing file failed | |||
// since it may be related to a temporary lack of resources (e.g. | |||
// max open files) | |||
openFail(!packFile.exists()); | |||
openFail(!packFile.exists(), fn); | |||
throw fn; | |||
} catch (EOFException | AccessDeniedException | NoSuchFileException | |||
| CorruptObjectException | NoPackSignatureException | |||
@@ -668,20 +672,21 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
| UnsupportedPackIndexVersionException | |||
| UnsupportedPackVersionException pe) { | |||
// exceptions signaling permanent problems with a pack | |||
openFail(true); | |||
openFail(true, pe); | |||
throw pe; | |||
} catch (IOException | RuntimeException ge) { | |||
// generic exceptions could be transient so we should not mark the | |||
// pack invalid to avoid false MissingObjectExceptions | |||
openFail(false); | |||
openFail(false, ge); | |||
throw ge; | |||
} | |||
} | |||
private void openFail(boolean invalidate) { | |||
private void openFail(boolean invalidate, Exception cause) { | |||
activeWindows = 0; | |||
activeCopyRawData = 0; | |||
invalid = invalidate; | |||
invalidatingCause = cause; | |||
doClose(); | |||
} | |||
@@ -708,7 +713,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { | |||
// Detect the situation and throw a proper exception so that can be properly | |||
// managed by the main packfile search loop and the Git client won't receive | |||
// any failures. | |||
throw new PackInvalidException(packFile); | |||
throw new PackInvalidException(packFile, invalidatingCause); | |||
} | |||
if (length < pos + size) | |||
size = (int) (length - pos); |