Fix concurrent read / write issue in LockFile on Windows
LockFile.commit fails if another thread concurrently reads the base file. The problem is fixed by retrying the rename operation if it fails. Change-Id: I6bb76ea7f2e6e90e3ddc45f9dd4d69bd1b6fa1eb Bug: 308506 Signed-off-by: Jens Baumgart <jens.baumgart@sap.com>
This commit is contained in:
parent
a00377a7e2
commit
db82b8d7eb
|
@ -61,6 +61,7 @@
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.storage.file.FileBasedConfig;
|
import org.eclipse.jgit.storage.file.FileBasedConfig;
|
||||||
import org.eclipse.jgit.storage.file.LockFile;
|
import org.eclipse.jgit.storage.file.LockFile;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the {@code .eclipse_iplog} file in a project.
|
* Manages the {@code .eclipse_iplog} file in a project.
|
||||||
|
@ -167,6 +168,9 @@ private List<Project> parseProjects(final Config cfg,
|
||||||
*
|
*
|
||||||
* @param file
|
* @param file
|
||||||
* local file to update with current CQ records.
|
* local file to update with current CQ records.
|
||||||
|
* @param fs
|
||||||
|
* the file system abstraction which will be necessary to perform
|
||||||
|
* certain file system operations.
|
||||||
* @param base
|
* @param base
|
||||||
* base https:// URL of the IPzilla server.
|
* base https:// URL of the IPzilla server.
|
||||||
* @param username
|
* @param username
|
||||||
|
@ -181,16 +185,16 @@ private List<Project> parseProjects(final Config cfg,
|
||||||
* the local file cannot be read, as it is not a valid
|
* the local file cannot be read, as it is not a valid
|
||||||
* configuration file format.
|
* configuration file format.
|
||||||
*/
|
*/
|
||||||
public void syncCQs(File file, URL base, String username, String password)
|
public void syncCQs(File file, FS fs, URL base, String username,
|
||||||
throws IOException, ConfigInvalidException {
|
String password) throws IOException, ConfigInvalidException {
|
||||||
if (!file.getParentFile().exists())
|
if (!file.getParentFile().exists())
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
|
|
||||||
LockFile lf = new LockFile(file);
|
LockFile lf = new LockFile(file, fs);
|
||||||
if (!lf.lock())
|
if (!lf.lock())
|
||||||
throw new IOException(MessageFormat.format(IpLogText.get().cannotLock, file));
|
throw new IOException(MessageFormat.format(IpLogText.get().cannotLock, file));
|
||||||
try {
|
try {
|
||||||
FileBasedConfig cfg = new FileBasedConfig(file);
|
FileBasedConfig cfg = new FileBasedConfig(file, fs);
|
||||||
cfg.load();
|
cfg.load();
|
||||||
loadFrom(cfg);
|
loadFrom(cfg);
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
import org.eclipse.jgit.storage.file.FileRepository;
|
import org.eclipse.jgit.storage.file.FileRepository;
|
||||||
import org.eclipse.jgit.storage.file.WindowCache;
|
import org.eclipse.jgit.storage.file.WindowCache;
|
||||||
import org.eclipse.jgit.storage.file.WindowCacheConfig;
|
import org.eclipse.jgit.storage.file.WindowCacheConfig;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
import org.eclipse.jgit.util.IO;
|
import org.eclipse.jgit.util.IO;
|
||||||
import org.eclipse.jgit.util.SystemReader;
|
import org.eclipse.jgit.util.SystemReader;
|
||||||
|
|
||||||
|
@ -128,7 +129,7 @@ public void run() {
|
||||||
|
|
||||||
mockSystemReader = new MockSystemReader();
|
mockSystemReader = new MockSystemReader();
|
||||||
mockSystemReader.userGitConfig = new FileBasedConfig(new File(trash,
|
mockSystemReader.userGitConfig = new FileBasedConfig(new File(trash,
|
||||||
"usergitconfig"));
|
"usergitconfig"), FS.DETECTED);
|
||||||
ceilTestDirectories(getCeilings());
|
ceilTestDirectories(getCeilings());
|
||||||
SystemReader.setInstance(mockSystemReader);
|
SystemReader.setInstance(mockSystemReader);
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ public MockSystemReader() {
|
||||||
init(Constants.GIT_AUTHOR_EMAIL_KEY);
|
init(Constants.GIT_AUTHOR_EMAIL_KEY);
|
||||||
init(Constants.GIT_COMMITTER_NAME_KEY);
|
init(Constants.GIT_COMMITTER_NAME_KEY);
|
||||||
init(Constants.GIT_COMMITTER_EMAIL_KEY);
|
init(Constants.GIT_COMMITTER_EMAIL_KEY);
|
||||||
userGitConfig = new FileBasedConfig(null) {
|
userGitConfig = new FileBasedConfig(null, null) {
|
||||||
@Override
|
@Override
|
||||||
public void load() throws IOException, ConfigInvalidException {
|
public void load() throws IOException, ConfigInvalidException {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
|
|
@ -654,7 +654,7 @@ private static File nameFor(ObjectDirectory odb, ObjectId name, String t) {
|
||||||
|
|
||||||
private void writeFile(final File p, final byte[] bin) throws IOException,
|
private void writeFile(final File p, final byte[] bin) throws IOException,
|
||||||
ObjectWritingException {
|
ObjectWritingException {
|
||||||
final LockFile lck = new LockFile(p);
|
final LockFile lck = new LockFile(p, db.getFS());
|
||||||
if (!lck.lock())
|
if (!lck.lock())
|
||||||
throw new ObjectWritingException("Can't write " + p);
|
throw new ObjectWritingException("Can't write " + p);
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -227,7 +227,7 @@ private void detachHead() throws IOException {
|
||||||
final ObjectId id = db.resolve(Constants.HEAD);
|
final ObjectId id = db.resolve(Constants.HEAD);
|
||||||
if (!ObjectId.isId(head) && id != null) {
|
if (!ObjectId.isId(head) && id != null) {
|
||||||
final LockFile lf;
|
final LockFile lf;
|
||||||
lf = new LockFile(new File(db.getDirectory(), Constants.HEAD));
|
lf = new LockFile(new File(db.getDirectory(), Constants.HEAD), db.getFS());
|
||||||
if (!lf.lock())
|
if (!lf.lock())
|
||||||
throw new IOException(MessageFormat.format(CLIText.get().cannotLock, Constants.HEAD));
|
throw new IOException(MessageFormat.format(CLIText.get().cannotLock, Constants.HEAD));
|
||||||
lf.write(id);
|
lf.write(id);
|
||||||
|
@ -254,7 +254,7 @@ private void recreateRefs() throws Exception {
|
||||||
protected void writeFile(final String name, final byte[] content)
|
protected void writeFile(final String name, final byte[] content)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final File file = new File(db.getDirectory(), name);
|
final File file = new File(db.getDirectory(), name);
|
||||||
final LockFile lck = new LockFile(file);
|
final LockFile lck = new LockFile(file, db.getFS());
|
||||||
if (!lck.lock())
|
if (!lck.lock())
|
||||||
throw new ObjectWritingException(MessageFormat.format(CLIText.get().cantWrite, file));
|
throw new ObjectWritingException(MessageFormat.format(CLIText.get().cantWrite, file));
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -98,7 +98,7 @@ else if (version == null)
|
||||||
if (output != null) {
|
if (output != null) {
|
||||||
if (!output.getParentFile().exists())
|
if (!output.getParentFile().exists())
|
||||||
output.getParentFile().mkdirs();
|
output.getParentFile().mkdirs();
|
||||||
LockFile lf = new LockFile(output);
|
LockFile lf = new LockFile(output, db.getFS());
|
||||||
if (!lf.lock())
|
if (!lf.lock())
|
||||||
throw die(MessageFormat.format(CLIText.get().cannotLock, output));
|
throw die(MessageFormat.format(CLIText.get().cannotLock, output));
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -94,6 +94,6 @@ protected void run() throws Exception {
|
||||||
output = new File(db.getWorkTree(), IpLogMeta.IPLOG_CONFIG_FILE);
|
output = new File(db.getWorkTree(), IpLogMeta.IPLOG_CONFIG_FILE);
|
||||||
|
|
||||||
IpLogMeta meta = new IpLogMeta();
|
IpLogMeta meta = new IpLogMeta();
|
||||||
meta.syncCQs(output, ipzilla, username, password);
|
meta.syncCQs(output, db.getFS(), ipzilla, username, password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ public int parseArguments(final Parameters params) throws CmdLineException {
|
||||||
if (new File(name).isFile()) {
|
if (new File(name).isFile()) {
|
||||||
final DirCache dirc;
|
final DirCache dirc;
|
||||||
try {
|
try {
|
||||||
dirc = DirCache.read(new File(name));
|
dirc = DirCache.read(new File(name), FS.DETECTED);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CmdLineException(MessageFormat.format(CLIText.get().notAnIndexFile, name), e);
|
throw new CmdLineException(MessageFormat.format(CLIText.get().notAnIndexFile, name), e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ public void testReadMissing_TempIndex() throws Exception {
|
||||||
final File idx = new File(db.getDirectory(), "tmp_index");
|
final File idx = new File(db.getDirectory(), "tmp_index");
|
||||||
assertFalse(idx.exists());
|
assertFalse(idx.exists());
|
||||||
|
|
||||||
final DirCache dc = DirCache.read(idx);
|
final DirCache dc = DirCache.read(idx, db.getFS());
|
||||||
assertNotNull(dc);
|
assertNotNull(dc);
|
||||||
assertEquals(0, dc.getEntryCount());
|
assertEquals(0, dc.getEntryCount());
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ public void testLockMissing_TempIndex() throws Exception {
|
||||||
assertFalse(idx.exists());
|
assertFalse(idx.exists());
|
||||||
assertFalse(lck.exists());
|
assertFalse(lck.exists());
|
||||||
|
|
||||||
final DirCache dc = DirCache.lock(idx);
|
final DirCache dc = DirCache.lock(idx, db.getFS());
|
||||||
assertNotNull(dc);
|
assertNotNull(dc);
|
||||||
assertFalse(idx.exists());
|
assertFalse(idx.exists());
|
||||||
assertTrue(lck.exists());
|
assertTrue(lck.exists());
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
import org.eclipse.jgit.util.JGitTestUtil;
|
import org.eclipse.jgit.util.JGitTestUtil;
|
||||||
|
|
||||||
public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
|
public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
|
||||||
|
@ -65,7 +66,7 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
|
||||||
|
|
||||||
public void testReadIndex_LsFiles() throws Exception {
|
public void testReadIndex_LsFiles() throws Exception {
|
||||||
final Map<String, CGitIndexRecord> ls = readLsFiles();
|
final Map<String, CGitIndexRecord> ls = readLsFiles();
|
||||||
final DirCache dc = new DirCache(index);
|
final DirCache dc = new DirCache(index, FS.DETECTED);
|
||||||
assertEquals(0, dc.getEntryCount());
|
assertEquals(0, dc.getEntryCount());
|
||||||
dc.read();
|
dc.read();
|
||||||
assertEquals(ls.size(), dc.getEntryCount());
|
assertEquals(ls.size(), dc.getEntryCount());
|
||||||
|
@ -79,7 +80,7 @@ public void testReadIndex_LsFiles() throws Exception {
|
||||||
public void testTreeWalk_LsFiles() throws Exception {
|
public void testTreeWalk_LsFiles() throws Exception {
|
||||||
final Repository db = createBareRepository();
|
final Repository db = createBareRepository();
|
||||||
final Map<String, CGitIndexRecord> ls = readLsFiles();
|
final Map<String, CGitIndexRecord> ls = readLsFiles();
|
||||||
final DirCache dc = new DirCache(index);
|
final DirCache dc = new DirCache(index, db.getFS());
|
||||||
assertEquals(0, dc.getEntryCount());
|
assertEquals(0, dc.getEntryCount());
|
||||||
dc.read();
|
dc.read();
|
||||||
assertEquals(ls.size(), dc.getEntryCount());
|
assertEquals(ls.size(), dc.getEntryCount());
|
||||||
|
@ -102,14 +103,16 @@ public void testTreeWalk_LsFiles() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUnsupportedOptionalExtension() throws Exception {
|
public void testUnsupportedOptionalExtension() throws Exception {
|
||||||
final DirCache dc = new DirCache(pathOf("gitgit.index.ZZZZ"));
|
final DirCache dc = new DirCache(pathOf("gitgit.index.ZZZZ"),
|
||||||
|
FS.DETECTED);
|
||||||
dc.read();
|
dc.read();
|
||||||
assertEquals(1, dc.getEntryCount());
|
assertEquals(1, dc.getEntryCount());
|
||||||
assertEquals("A", dc.getEntry(0).getPathString());
|
assertEquals("A", dc.getEntry(0).getPathString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUnsupportedRequiredExtension() throws Exception {
|
public void testUnsupportedRequiredExtension() throws Exception {
|
||||||
final DirCache dc = new DirCache(pathOf("gitgit.index.aaaa"));
|
final DirCache dc = new DirCache(pathOf("gitgit.index.aaaa"),
|
||||||
|
FS.DETECTED);
|
||||||
try {
|
try {
|
||||||
dc.read();
|
dc.read();
|
||||||
fail("Cache loaded an unsupported extension");
|
fail("Cache loaded an unsupported extension");
|
||||||
|
@ -120,7 +123,8 @@ public void testUnsupportedRequiredExtension() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCorruptChecksumAtFooter() throws Exception {
|
public void testCorruptChecksumAtFooter() throws Exception {
|
||||||
final DirCache dc = new DirCache(pathOf("gitgit.index.badchecksum"));
|
final DirCache dc = new DirCache(pathOf("gitgit.index.badchecksum"),
|
||||||
|
FS.DETECTED);
|
||||||
try {
|
try {
|
||||||
dc.read();
|
dc.read();
|
||||||
fail("Cache loaded despite corrupt checksum");
|
fail("Cache loaded despite corrupt checksum");
|
||||||
|
@ -143,7 +147,7 @@ private static void assertEqual(final CGitIndexRecord c,
|
||||||
public void testReadIndex_DirCacheTree() throws Exception {
|
public void testReadIndex_DirCacheTree() throws Exception {
|
||||||
final Map<String, CGitIndexRecord> cList = readLsFiles();
|
final Map<String, CGitIndexRecord> cList = readLsFiles();
|
||||||
final Map<String, CGitLsTreeRecord> cTree = readLsTree();
|
final Map<String, CGitLsTreeRecord> cTree = readLsTree();
|
||||||
final DirCache dc = new DirCache(index);
|
final DirCache dc = new DirCache(index, FS.DETECTED);
|
||||||
assertEquals(0, dc.getEntryCount());
|
assertEquals(0, dc.getEntryCount());
|
||||||
dc.read();
|
dc.read();
|
||||||
assertEquals(cList.size(), dc.getEntryCount());
|
assertEquals(cList.size(), dc.getEntryCount());
|
||||||
|
|
|
@ -555,13 +555,15 @@ public void testUpdateRefLockFailureLocked() throws IOException {
|
||||||
ObjectId pid = db.resolve("refs/heads/master^");
|
ObjectId pid = db.resolve("refs/heads/master^");
|
||||||
RefUpdate updateRef = db.updateRef("refs/heads/master");
|
RefUpdate updateRef = db.updateRef("refs/heads/master");
|
||||||
updateRef.setNewObjectId(pid);
|
updateRef.setNewObjectId(pid);
|
||||||
LockFile lockFile1 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
|
LockFile lockFile1 = new LockFile(new File(db.getDirectory(),
|
||||||
|
"refs/heads/master"), db.getFS());
|
||||||
try {
|
try {
|
||||||
assertTrue(lockFile1.lock()); // precondition to test
|
assertTrue(lockFile1.lock()); // precondition to test
|
||||||
Result update = updateRef.update();
|
Result update = updateRef.update();
|
||||||
assertEquals(Result.LOCK_FAILURE, update);
|
assertEquals(Result.LOCK_FAILURE, update);
|
||||||
assertEquals(opid, db.resolve("refs/heads/master"));
|
assertEquals(opid, db.resolve("refs/heads/master"));
|
||||||
LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
|
LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"),
|
||||||
|
db.getFS());
|
||||||
assertFalse(lockFile2.lock()); // was locked, still is
|
assertFalse(lockFile2.lock()); // was locked, still is
|
||||||
} finally {
|
} finally {
|
||||||
lockFile1.unlock();
|
lockFile1.unlock();
|
||||||
|
@ -699,7 +701,8 @@ public void tryRenameWhenLocked(String toLock, String fromName,
|
||||||
"logs/" + fromName).exists());
|
"logs/" + fromName).exists());
|
||||||
|
|
||||||
// "someone" has branch X locked
|
// "someone" has branch X locked
|
||||||
LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock));
|
LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock),
|
||||||
|
db.getFS());
|
||||||
try {
|
try {
|
||||||
assertTrue(lockFile.lock());
|
assertTrue(lockFile.lock());
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
import org.eclipse.jgit.lib.ConfigConstants;
|
import org.eclipse.jgit.lib.ConfigConstants;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for setting up the working directory when creating a Repository
|
* Tests for setting up the working directory when creating a Repository
|
||||||
|
@ -191,7 +192,8 @@ private void setWorkTree(File gitDir, File workTree) throws IOException,
|
||||||
|
|
||||||
private FileBasedConfig configFor(File gitDir) throws IOException,
|
private FileBasedConfig configFor(File gitDir) throws IOException,
|
||||||
ConfigInvalidException {
|
ConfigInvalidException {
|
||||||
FileBasedConfig cfg = new FileBasedConfig(new File(gitDir, "config"));
|
File configPath = new File(gitDir, "config");
|
||||||
|
FileBasedConfig cfg = new FileBasedConfig(configPath, FS.DETECTED);
|
||||||
cfg.load();
|
cfg.load();
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -315,7 +315,7 @@ public void test005_ReadSimpleConfig() {
|
||||||
public void test006_ReadUglyConfig() throws IOException,
|
public void test006_ReadUglyConfig() throws IOException,
|
||||||
ConfigInvalidException {
|
ConfigInvalidException {
|
||||||
final File cfg = new File(db.getDirectory(), "config");
|
final File cfg = new File(db.getDirectory(), "config");
|
||||||
final FileBasedConfig c = new FileBasedConfig(cfg);
|
final FileBasedConfig c = new FileBasedConfig(cfg, db.getFS());
|
||||||
final FileWriter pw = new FileWriter(cfg);
|
final FileWriter pw = new FileWriter(cfg);
|
||||||
final String configStr = " [core];comment\n\tfilemode = yes\n"
|
final String configStr = " [core];comment\n\tfilemode = yes\n"
|
||||||
+ "[user]\n"
|
+ "[user]\n"
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectInserter;
|
import org.eclipse.jgit.lib.ObjectInserter;
|
||||||
import org.eclipse.jgit.storage.file.LockFile;
|
import org.eclipse.jgit.storage.file.LockFile;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
import org.eclipse.jgit.util.IO;
|
import org.eclipse.jgit.util.IO;
|
||||||
import org.eclipse.jgit.util.MutableInteger;
|
import org.eclipse.jgit.util.MutableInteger;
|
||||||
import org.eclipse.jgit.util.NB;
|
import org.eclipse.jgit.util.NB;
|
||||||
|
@ -129,7 +130,7 @@ static int cmp(final byte[] aPath, final int aLen, final byte[] bPath,
|
||||||
* memory).
|
* memory).
|
||||||
*/
|
*/
|
||||||
public static DirCache newInCore() {
|
public static DirCache newInCore() {
|
||||||
return new DirCache(null);
|
return new DirCache(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,6 +142,9 @@ public static DirCache newInCore() {
|
||||||
*
|
*
|
||||||
* @param indexLocation
|
* @param indexLocation
|
||||||
* location of the index file on disk.
|
* location of the index file on disk.
|
||||||
|
* @param fs
|
||||||
|
* the file system abstraction which will be necessary to perform
|
||||||
|
* certain file system operations.
|
||||||
* @return a cache representing the contents of the specified index file (if
|
* @return a cache representing the contents of the specified index file (if
|
||||||
* it exists) or an empty cache if the file does not exist.
|
* it exists) or an empty cache if the file does not exist.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
|
@ -149,9 +153,9 @@ public static DirCache newInCore() {
|
||||||
* the index file is using a format or extension that this
|
* the index file is using a format or extension that this
|
||||||
* library does not support.
|
* library does not support.
|
||||||
*/
|
*/
|
||||||
public static DirCache read(final File indexLocation)
|
public static DirCache read(final File indexLocation, final FS fs)
|
||||||
throws CorruptObjectException, IOException {
|
throws CorruptObjectException, IOException {
|
||||||
final DirCache c = new DirCache(indexLocation);
|
final DirCache c = new DirCache(indexLocation, fs);
|
||||||
c.read();
|
c.read();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -161,11 +165,14 @@ public static DirCache read(final File indexLocation)
|
||||||
* <p>
|
* <p>
|
||||||
* The new index will be locked and then read before it is returned to the
|
* The new index will be locked and then read before it is returned to the
|
||||||
* caller. Read failures are reported as exceptions and therefore prevent
|
* caller. Read failures are reported as exceptions and therefore prevent
|
||||||
* the method from returning a partially populated index. On read failure,
|
* the method from returning a partially populated index. On read failure,
|
||||||
* the lock is released.
|
* the lock is released.
|
||||||
*
|
*
|
||||||
* @param indexLocation
|
* @param indexLocation
|
||||||
* location of the index file on disk.
|
* location of the index file on disk.
|
||||||
|
* @param fs
|
||||||
|
* the file system abstraction which will be necessary to perform
|
||||||
|
* certain file system operations.
|
||||||
* @return a cache representing the contents of the specified index file (if
|
* @return a cache representing the contents of the specified index file (if
|
||||||
* it exists) or an empty cache if the file does not exist.
|
* it exists) or an empty cache if the file does not exist.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
|
@ -175,9 +182,9 @@ public static DirCache read(final File indexLocation)
|
||||||
* the index file is using a format or extension that this
|
* the index file is using a format or extension that this
|
||||||
* library does not support.
|
* library does not support.
|
||||||
*/
|
*/
|
||||||
public static DirCache lock(final File indexLocation)
|
public static DirCache lock(final File indexLocation, final FS fs)
|
||||||
throws CorruptObjectException, IOException {
|
throws CorruptObjectException, IOException {
|
||||||
final DirCache c = new DirCache(indexLocation);
|
final DirCache c = new DirCache(indexLocation, fs);
|
||||||
if (!c.lock())
|
if (!c.lock())
|
||||||
throw new IOException(MessageFormat.format(JGitText.get().cannotLock, indexLocation));
|
throw new IOException(MessageFormat.format(JGitText.get().cannotLock, indexLocation));
|
||||||
|
|
||||||
|
@ -215,6 +222,9 @@ public static DirCache lock(final File indexLocation)
|
||||||
/** Our active lock (if we hold it); null if we don't have it locked. */
|
/** Our active lock (if we hold it); null if we don't have it locked. */
|
||||||
private LockFile myLock;
|
private LockFile myLock;
|
||||||
|
|
||||||
|
/** file system abstraction **/
|
||||||
|
private final FS fs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new in-core index representation.
|
* Create a new in-core index representation.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -223,9 +233,13 @@ public static DirCache lock(final File indexLocation)
|
||||||
*
|
*
|
||||||
* @param indexLocation
|
* @param indexLocation
|
||||||
* location of the index file on disk.
|
* location of the index file on disk.
|
||||||
|
* @param fs
|
||||||
|
* the file system abstraction which will be necessary to perform
|
||||||
|
* certain file system operations.
|
||||||
*/
|
*/
|
||||||
public DirCache(final File indexLocation) {
|
public DirCache(final File indexLocation, final FS fs) {
|
||||||
liveFile = indexLocation;
|
liveFile = indexLocation;
|
||||||
|
this.fs = fs;
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +443,7 @@ private static boolean is_DIRC(final byte[] hdr) {
|
||||||
public boolean lock() throws IOException {
|
public boolean lock() throws IOException {
|
||||||
if (liveFile == null)
|
if (liveFile == null)
|
||||||
throw new IOException(JGitText.get().dirCacheDoesNotHaveABackingFile);
|
throw new IOException(JGitText.get().dirCacheDoesNotHaveABackingFile);
|
||||||
final LockFile tmp = new LockFile(liveFile);
|
final LockFile tmp = new LockFile(liveFile, fs);
|
||||||
if (tmp.lock()) {
|
if (tmp.lock()) {
|
||||||
tmp.setNeedStatInformation(true);
|
tmp.setNeedStatInformation(true);
|
||||||
myLock = tmp;
|
myLock = tmp;
|
||||||
|
|
|
@ -555,7 +555,7 @@ protected Config loadConfig() throws IOException {
|
||||||
// repository and not inherited from other files.
|
// repository and not inherited from other files.
|
||||||
//
|
//
|
||||||
File path = safeFS().resolve(getGitDir(), "config");
|
File path = safeFS().resolve(getGitDir(), "config");
|
||||||
FileBasedConfig cfg = new FileBasedConfig(path);
|
FileBasedConfig cfg = new FileBasedConfig(path, safeFS());
|
||||||
try {
|
try {
|
||||||
cfg.load();
|
cfg.load();
|
||||||
} catch (ConfigInvalidException err) {
|
} catch (ConfigInvalidException err) {
|
||||||
|
|
|
@ -930,7 +930,7 @@ public File getIndexFile() throws NoWorkTreeException {
|
||||||
*/
|
*/
|
||||||
public DirCache readDirCache() throws NoWorkTreeException,
|
public DirCache readDirCache() throws NoWorkTreeException,
|
||||||
CorruptObjectException, IOException {
|
CorruptObjectException, IOException {
|
||||||
return DirCache.read(getIndexFile());
|
return DirCache.read(getIndexFile(), getFS());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -954,7 +954,7 @@ public DirCache readDirCache() throws NoWorkTreeException,
|
||||||
*/
|
*/
|
||||||
public DirCache lockDirCache() throws NoWorkTreeException,
|
public DirCache lockDirCache() throws NoWorkTreeException,
|
||||||
CorruptObjectException, IOException {
|
CorruptObjectException, IOException {
|
||||||
return DirCache.lock(getIndexFile());
|
return DirCache.lock(getIndexFile(), getFS());
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte[] gitInternalSlash(byte[] bytes) {
|
static byte[] gitInternalSlash(byte[] bytes) {
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.StoredConfig;
|
import org.eclipse.jgit.lib.StoredConfig;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
import org.eclipse.jgit.util.IO;
|
import org.eclipse.jgit.util.IO;
|
||||||
import org.eclipse.jgit.util.RawParseUtils;
|
import org.eclipse.jgit.util.RawParseUtils;
|
||||||
|
|
||||||
|
@ -68,15 +69,19 @@
|
||||||
public class FileBasedConfig extends StoredConfig {
|
public class FileBasedConfig extends StoredConfig {
|
||||||
private final File configFile;
|
private final File configFile;
|
||||||
private volatile long lastModified;
|
private volatile long lastModified;
|
||||||
|
private final FS fs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a configuration with no default fallback.
|
* Create a configuration with no default fallback.
|
||||||
*
|
*
|
||||||
* @param cfgLocation
|
* @param cfgLocation
|
||||||
* the location of the configuration file on the file system
|
* the location of the configuration file on the file system
|
||||||
|
* @param fs
|
||||||
|
* the file system abstraction which will be necessary to perform
|
||||||
|
* certain file system operations.
|
||||||
*/
|
*/
|
||||||
public FileBasedConfig(File cfgLocation) {
|
public FileBasedConfig(File cfgLocation, FS fs) {
|
||||||
this(null, cfgLocation);
|
this(null, cfgLocation, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,10 +91,14 @@ public FileBasedConfig(File cfgLocation) {
|
||||||
* the base configuration file
|
* the base configuration file
|
||||||
* @param cfgLocation
|
* @param cfgLocation
|
||||||
* the location of the configuration file on the file system
|
* the location of the configuration file on the file system
|
||||||
|
* @param fs
|
||||||
|
* the file system abstraction which will be necessary to perform
|
||||||
|
* certain file system operations.
|
||||||
*/
|
*/
|
||||||
public FileBasedConfig(Config base, File cfgLocation) {
|
public FileBasedConfig(Config base, File cfgLocation, FS fs) {
|
||||||
super(base);
|
super(base);
|
||||||
configFile = cfgLocation;
|
configFile = cfgLocation;
|
||||||
|
this.fs = fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return location of the configuration file on disk */
|
/** @return location of the configuration file on disk */
|
||||||
|
@ -138,7 +147,7 @@ public void load() throws IOException, ConfigInvalidException {
|
||||||
*/
|
*/
|
||||||
public void save() throws IOException {
|
public void save() throws IOException {
|
||||||
final byte[] out = Constants.encode(toText());
|
final byte[] out = Constants.encode(toText());
|
||||||
final LockFile lf = new LockFile(getFile());
|
final LockFile lf = new LockFile(getFile(), fs);
|
||||||
if (!lf.lock())
|
if (!lf.lock())
|
||||||
throw new IOException(MessageFormat.format(JGitText.get().cannotLockFile, getFile()));
|
throw new IOException(MessageFormat.format(JGitText.get().cannotLockFile, getFile()));
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -136,7 +136,9 @@ public FileRepository(final BaseRepositoryBuilder options) throws IOException {
|
||||||
super(options);
|
super(options);
|
||||||
|
|
||||||
userConfig = SystemReader.getInstance().openUserConfig(getFS());
|
userConfig = SystemReader.getInstance().openUserConfig(getFS());
|
||||||
repoConfig = new FileBasedConfig(userConfig, getFS().resolve(getDirectory(), "config"));
|
repoConfig = new FileBasedConfig(userConfig, //
|
||||||
|
getFS().resolve(getDirectory(), "config"), //
|
||||||
|
getFS());
|
||||||
|
|
||||||
loadUserConfig();
|
loadUserConfig();
|
||||||
loadRepoConfig();
|
loadRepoConfig();
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
import org.eclipse.jgit.JGitText;
|
import org.eclipse.jgit.JGitText;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Git style file locking and replacement.
|
* Git style file locking and replacement.
|
||||||
|
@ -94,15 +95,21 @@ public boolean accept(File dir, String name) {
|
||||||
|
|
||||||
private long commitLastModified;
|
private long commitLastModified;
|
||||||
|
|
||||||
|
private final FS fs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new lock for any file.
|
* Create a new lock for any file.
|
||||||
*
|
*
|
||||||
* @param f
|
* @param f
|
||||||
* the file that will be locked.
|
* the file that will be locked.
|
||||||
|
* @param fs
|
||||||
|
* the file system abstraction which will be necessary to perform
|
||||||
|
* certain file system operations.
|
||||||
*/
|
*/
|
||||||
public LockFile(final File f) {
|
public LockFile(final File f, FS fs) {
|
||||||
ref = f;
|
ref = f;
|
||||||
lck = new File(ref.getParentFile(), ref.getName() + SUFFIX);
|
lck = new File(ref.getParentFile(), ref.getName() + SUFFIX);
|
||||||
|
this.fs = fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -393,13 +400,32 @@ public boolean commit() {
|
||||||
saveStatInformation();
|
saveStatInformation();
|
||||||
if (lck.renameTo(ref))
|
if (lck.renameTo(ref))
|
||||||
return true;
|
return true;
|
||||||
if (!ref.exists() || ref.delete())
|
if (!ref.exists() || deleteRef())
|
||||||
if (lck.renameTo(ref))
|
if (lck.renameTo(ref))
|
||||||
return true;
|
return true;
|
||||||
unlock();
|
unlock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean deleteRef() {
|
||||||
|
if (!fs.retryFailedLockFileCommit())
|
||||||
|
return ref.delete();
|
||||||
|
|
||||||
|
// File deletion fails on windows if another thread is
|
||||||
|
// concurrently reading the same file. So try a few times.
|
||||||
|
//
|
||||||
|
for (int attempts = 0; attempts < 10; attempts++) {
|
||||||
|
if (ref.delete())
|
||||||
|
return true;
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void saveStatInformation() {
|
private void saveStatInformation() {
|
||||||
if (needStatInformation)
|
if (needStatInformation)
|
||||||
commitLastModified = lck.lastModified();
|
commitLastModified = lck.lastModified();
|
||||||
|
|
|
@ -47,21 +47,26 @@
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
|
|
||||||
/** Keeps track of a {@link PackFile}'s associated <code>.keep</code> file. */
|
/** Keeps track of a {@link PackFile}'s associated <code>.keep</code> file. */
|
||||||
public class PackLock {
|
public class PackLock {
|
||||||
private final File keepFile;
|
private final File keepFile;
|
||||||
|
private final FS fs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new lock for a pack file.
|
* Create a new lock for a pack file.
|
||||||
*
|
*
|
||||||
* @param packFile
|
* @param packFile
|
||||||
* location of the <code>pack-*.pack</code> file.
|
* location of the <code>pack-*.pack</code> file.
|
||||||
|
* @param fs
|
||||||
|
* the filesystem abstraction used by the repository.
|
||||||
*/
|
*/
|
||||||
public PackLock(final File packFile) {
|
public PackLock(final File packFile, final FS fs) {
|
||||||
final File p = packFile.getParentFile();
|
final File p = packFile.getParentFile();
|
||||||
final String n = packFile.getName();
|
final String n = packFile.getName();
|
||||||
keepFile = new File(p, n.substring(0, n.length() - 5) + ".keep");
|
keepFile = new File(p, n.substring(0, n.length() - 5) + ".keep");
|
||||||
|
this.fs = fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +83,7 @@ public boolean lock(String msg) throws IOException {
|
||||||
return false;
|
return false;
|
||||||
if (!msg.endsWith("\n"))
|
if (!msg.endsWith("\n"))
|
||||||
msg += "\n";
|
msg += "\n";
|
||||||
final LockFile lf = new LockFile(keepFile);
|
final LockFile lf = new LockFile(keepFile, fs);
|
||||||
if (!lf.lock())
|
if (!lf.lock())
|
||||||
return false;
|
return false;
|
||||||
lf.write(Constants.encode(msg));
|
lf.write(Constants.encode(msg));
|
||||||
|
|
|
@ -512,7 +512,8 @@ void delete(RefDirectoryUpdate update) throws IOException {
|
||||||
// we don't miss an edit made externally.
|
// we don't miss an edit made externally.
|
||||||
final PackedRefList packed = getPackedRefs();
|
final PackedRefList packed = getPackedRefs();
|
||||||
if (packed.contains(name)) {
|
if (packed.contains(name)) {
|
||||||
LockFile lck = new LockFile(packedRefsFile);
|
LockFile lck = new LockFile(packedRefsFile,
|
||||||
|
update.getRepository().getFS());
|
||||||
if (!lck.lock())
|
if (!lck.lock())
|
||||||
throw new IOException(MessageFormat.format(
|
throw new IOException(MessageFormat.format(
|
||||||
JGitText.get().cannotLockFile, packedRefsFile));
|
JGitText.get().cannotLockFile, packedRefsFile));
|
||||||
|
|
|
@ -79,7 +79,7 @@ protected boolean tryLock(boolean deref) throws IOException {
|
||||||
if (deref)
|
if (deref)
|
||||||
dst = dst.getLeaf();
|
dst = dst.getLeaf();
|
||||||
String name = dst.getName();
|
String name = dst.getName();
|
||||||
lock = new LockFile(database.fileFor(name));
|
lock = new LockFile(database.fileFor(name), getRepository().getFS());
|
||||||
if (lock.lock()) {
|
if (lock.lock()) {
|
||||||
dst = database.getRef(name);
|
dst = database.getRef(name);
|
||||||
setOldObjectId(dst != null ? dst.getObjectId() : null);
|
setOldObjectId(dst != null ? dst.getObjectId() : null);
|
||||||
|
|
|
@ -279,7 +279,8 @@ private void updateFETCH_HEAD(final FetchResult result) throws IOException {
|
||||||
File meta = transport.local.getDirectory();
|
File meta = transport.local.getDirectory();
|
||||||
if (meta == null)
|
if (meta == null)
|
||||||
return;
|
return;
|
||||||
final LockFile lock = new LockFile(new File(meta, "FETCH_HEAD"));
|
final LockFile lock = new LockFile(new File(meta, "FETCH_HEAD"),
|
||||||
|
transport.local.getFS());
|
||||||
try {
|
try {
|
||||||
if (lock.lock()) {
|
if (lock.lock()) {
|
||||||
final Writer w = new OutputStreamWriter(lock.getOutputStream());
|
final Writer w = new OutputStreamWriter(lock.getOutputStream());
|
||||||
|
|
|
@ -1101,7 +1101,7 @@ public PackLock renameAndOpenPack(final String lockMessage)
|
||||||
final File packDir = new File(repo.getObjectsDirectory(), "pack");
|
final File packDir = new File(repo.getObjectsDirectory(), "pack");
|
||||||
final File finalPack = new File(packDir, "pack-" + name + ".pack");
|
final File finalPack = new File(packDir, "pack-" + name + ".pack");
|
||||||
final File finalIdx = new File(packDir, "pack-" + name + ".idx");
|
final File finalIdx = new File(packDir, "pack-" + name + ".idx");
|
||||||
final PackLock keep = new PackLock(finalPack);
|
final PackLock keep = new PackLock(finalPack, repo.getFS());
|
||||||
|
|
||||||
if (!packDir.exists() && !packDir.mkdir() && !packDir.exists()) {
|
if (!packDir.exists() && !packDir.mkdir() && !packDir.exists()) {
|
||||||
// The objects/pack directory isn't present, and we are unable
|
// The objects/pack directory isn't present, and we are unable
|
||||||
|
|
|
@ -74,7 +74,7 @@ public String getProperty(String key) {
|
||||||
|
|
||||||
public FileBasedConfig openUserConfig(FS fs) {
|
public FileBasedConfig openUserConfig(FS fs) {
|
||||||
final File home = fs.userHome();
|
final File home = fs.userHome();
|
||||||
return new FileBasedConfig(new File(home, ".gitconfig"));
|
return new FileBasedConfig(new File(home, ".gitconfig"), fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHostname() {
|
public String getHostname() {
|
||||||
|
|
Loading…
Reference in New Issue