FileUtils.rename(): better retry handling
When the atomic move fails on Windows, it may be because some other thread is currently reading the destination. If we delete the file then, that reader may get an exception, and conclude the file didn't exist, even though the rename() would re-create it right away. Try to avoid this from happening frequently by only deleting the destination on the last retry. Also don't sleep after the last attempt. Bug: 451508 Change-Id: I95bb4ec59d6e7efb4a7fc8d67f5df301f690257a Signed-off-by: Thomas Wolf <twolf@apache.org>
This commit is contained in:
parent
cb46ee3544
commit
f6774fa8ee
|
@ -295,6 +295,7 @@ public static void rename(final File src, final File dst,
|
||||||
CopyOption... options)
|
CopyOption... options)
|
||||||
throws AtomicMoveNotSupportedException, IOException {
|
throws AtomicMoveNotSupportedException, IOException {
|
||||||
int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1;
|
int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1;
|
||||||
|
IOException finalError = null;
|
||||||
while (--attempts >= 0) {
|
while (--attempts >= 0) {
|
||||||
try {
|
try {
|
||||||
Files.move(toPath(src), toPath(dst), options);
|
Files.move(toPath(src), toPath(dst), options);
|
||||||
|
@ -302,29 +303,35 @@ public static void rename(final File src, final File dst,
|
||||||
} catch (AtomicMoveNotSupportedException e) {
|
} catch (AtomicMoveNotSupportedException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
try {
|
if (attempts == 0) {
|
||||||
if (!dst.delete()) {
|
// Only delete on the last attempt.
|
||||||
delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
|
try {
|
||||||
|
if (!dst.delete()) {
|
||||||
|
delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
|
||||||
|
}
|
||||||
|
// On *nix there is no try, you do or do not
|
||||||
|
Files.move(toPath(src), toPath(dst), options);
|
||||||
|
return;
|
||||||
|
} catch (IOException e2) {
|
||||||
|
e2.addSuppressed(e);
|
||||||
|
finalError = e2;
|
||||||
}
|
}
|
||||||
// On *nix there is no try, you do or do not
|
|
||||||
Files.move(toPath(src), toPath(dst), options);
|
|
||||||
return;
|
|
||||||
} catch (IOException e2) {
|
|
||||||
// ignore and continue retry
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
if (attempts > 0) {
|
||||||
Thread.sleep(100);
|
try {
|
||||||
} catch (InterruptedException e) {
|
Thread.sleep(100);
|
||||||
throw new IOException(
|
} catch (InterruptedException e) {
|
||||||
MessageFormat.format(JGitText.get().renameFileFailed,
|
throw new IOException(MessageFormat.format(
|
||||||
src.getAbsolutePath(), dst.getAbsolutePath()),
|
JGitText.get().renameFileFailed,
|
||||||
e);
|
src.getAbsolutePath(), dst.getAbsolutePath()), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IOException(
|
throw new IOException(
|
||||||
MessageFormat.format(JGitText.get().renameFileFailed,
|
MessageFormat.format(JGitText.get().renameFileFailed,
|
||||||
src.getAbsolutePath(), dst.getAbsolutePath()));
|
src.getAbsolutePath(), dst.getAbsolutePath()),
|
||||||
|
finalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue