Cover the case where the exception is wrapped up as a cause, e.g., PackIndex#open(File). Change-Id: I0df5b1e9c2ff886bdd84dee3658b6a50866699d1 Signed-off-by: Hongkai Liu <hongkai.liu@ericsson.com>tags/v4.7.0.201704051617-r
@@ -50,10 +50,14 @@ import static org.junit.Assert.fail; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.UnsupportedEncodingException; | |||
import java.nio.file.Files; | |||
import java.nio.file.StandardCopyOption; | |||
import java.rmi.RemoteException; | |||
import java.util.regex.Matcher; | |||
import javax.management.remote.JMXProviderException; | |||
import org.eclipse.jgit.junit.JGitTestUtil; | |||
import org.junit.After; | |||
import org.junit.Assume; | |||
@@ -61,6 +65,17 @@ import org.junit.Before; | |||
import org.junit.Test; | |||
public class FileUtilsTest { | |||
private static final String MSG = "Stale file handle"; | |||
private static final String SOME_ERROR_MSG = "some error message"; | |||
private static final IOException IO_EXCEPTION = new UnsupportedEncodingException( | |||
MSG); | |||
private static final IOException IO_EXCEPTION_WITH_CAUSE = new RemoteException( | |||
SOME_ERROR_MSG, | |||
new JMXProviderException(SOME_ERROR_MSG, IO_EXCEPTION)); | |||
private File trash; | |||
@Before | |||
@@ -541,4 +556,29 @@ public class FileUtilsTest { | |||
return path.replaceAll("/|\\\\", | |||
Matcher.quoteReplacement(File.separator)); | |||
} | |||
@Test | |||
public void testIsStaleFileHandleWithDirectCause() throws Exception { | |||
assertTrue(FileUtils.isStaleFileHandle(IO_EXCEPTION)); | |||
} | |||
@Test | |||
public void testIsStaleFileHandleWithIndirectCause() throws Exception { | |||
assertFalse( | |||
FileUtils.isStaleFileHandle(IO_EXCEPTION_WITH_CAUSE)); | |||
} | |||
@Test | |||
public void testIsStaleFileHandleInCausalChainWithDirectCause() | |||
throws Exception { | |||
assertTrue( | |||
FileUtils.isStaleFileHandleInCausalChain(IO_EXCEPTION)); | |||
} | |||
@Test | |||
public void testIsStaleFileHandleInCausalChainWithIndirectCause() | |||
throws Exception { | |||
assertTrue(FileUtils | |||
.isStaleFileHandleInCausalChain(IO_EXCEPTION_WITH_CAUSE)); | |||
} | |||
} |
@@ -577,7 +577,7 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
warnTmpl = JGitText.get().packWasDeleted; | |||
} | |||
removePack(p); | |||
} else if (FileUtils.isStaleFileHandle(e)) { | |||
} else if (FileUtils.isStaleFileHandleInCausalChain(e)) { | |||
warnTmpl = JGitText.get().packHandleIsStale; | |||
removePack(p); | |||
} |
@@ -798,7 +798,8 @@ public class RefDirectory extends RefDatabase { | |||
return new PackedRefList(parsePackedRefs(br), snapshot, | |||
ObjectId.fromRaw(digest.digest())); | |||
} catch (IOException e) { | |||
if (FileUtils.isStaleFileHandle(e) && retries < maxStaleRetries) { | |||
if (FileUtils.isStaleFileHandleInCausalChain(e) | |||
&& retries < maxStaleRetries) { | |||
if (LOG.isDebugEnabled()) { | |||
LOG.debug(MessageFormat.format( | |||
JGitText.get().packedRefsHandleIsStale, |
@@ -547,6 +547,26 @@ public class FileUtils { | |||
.matches("stale .*file .*handle"); //$NON-NLS-1$ | |||
} | |||
/** | |||
* Determine if a throwable or a cause in its causal chain is a Stale NFS | |||
* File Handle | |||
* | |||
* @param throwable | |||
* @return a boolean true if the throwable or a cause in its causal chain is | |||
* a Stale NFS File Handle | |||
* @since 4.7 | |||
*/ | |||
public static boolean isStaleFileHandleInCausalChain(Throwable throwable) { | |||
while (throwable != null) { | |||
if (throwable instanceof IOException | |||
&& isStaleFileHandle((IOException) throwable)) { | |||
return true; | |||
} | |||
throwable = throwable.getCause(); | |||
} | |||
return false; | |||
} | |||
/** | |||
* @param file | |||
* @return {@code true} if the passed file is a symbolic link |