Fix concurrent read / write issue in GitIndex on Windows
GitIndex.write fails if another thread concurrently reads the index file. The problem is fixed by retrying the rename operation if it fails. Bug: 311051 Change-Id: Ib243d2a90adae312712d02521de4834d06804944 Signed-off-by: Jens Baumgart <jens.baumgart@sap.com>
This commit is contained in:
parent
ec13e0382a
commit
e99c48a61a
|
@ -297,10 +297,32 @@ public void write() throws IOException {
|
||||||
fc.write(buf);
|
fc.write(buf);
|
||||||
fc.close();
|
fc.close();
|
||||||
fileOutputStream.close();
|
fileOutputStream.close();
|
||||||
if (cacheFile.exists())
|
if (cacheFile.exists()) {
|
||||||
if (!cacheFile.delete())
|
if (db.getFS().retryFailedLockFileCommit()) {
|
||||||
throw new IOException(
|
// file deletion fails on windows if another
|
||||||
JGitText.get().couldNotRenameDeleteOldIndex);
|
// thread is reading the file concurrently
|
||||||
|
// So let's try 10 times...
|
||||||
|
boolean deleted = false;
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
if (cacheFile.delete()) {
|
||||||
|
deleted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!deleted)
|
||||||
|
throw new IOException(
|
||||||
|
JGitText.get().couldNotRenameDeleteOldIndex);
|
||||||
|
} else {
|
||||||
|
if (!cacheFile.delete())
|
||||||
|
throw new IOException(
|
||||||
|
JGitText.get().couldNotRenameDeleteOldIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!tmpIndex.renameTo(cacheFile))
|
if (!tmpIndex.renameTo(cacheFile))
|
||||||
throw new IOException(
|
throw new IOException(
|
||||||
JGitText.get().couldNotRenameTemporaryIndexFileToIndex);
|
JGitText.get().couldNotRenameTemporaryIndexFileToIndex);
|
||||||
|
|
|
@ -148,6 +148,13 @@ public File userHome() {
|
||||||
return userHome;
|
return userHome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this file system have problems with atomic renames?
|
||||||
|
*
|
||||||
|
* @return true if the caller should retry a failed rename of a lock file.
|
||||||
|
*/
|
||||||
|
public abstract boolean retryFailedLockFileCommit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the user's home directory (location where preferences are).
|
* Determine the user's home directory (location where preferences are).
|
||||||
*
|
*
|
||||||
|
|
|
@ -57,4 +57,9 @@ public boolean canExecute(final File f) {
|
||||||
public boolean setExecute(final File f, final boolean canExec) {
|
public boolean setExecute(final File f, final boolean canExec) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean retryFailedLockFileCommit() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,4 +104,9 @@ public boolean setExecute(final File f, final boolean canExec) {
|
||||||
throw new Error(e);
|
throw new Error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean retryFailedLockFileCommit() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,4 +71,9 @@ public boolean canExecute(final File f) {
|
||||||
public boolean setExecute(final File f, final boolean canExec) {
|
public boolean setExecute(final File f, final boolean canExec) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean retryFailedLockFileCommit() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue