Skip to content

Commit

Permalink
Introduce FileLockService.Locking to leverage try-with-resource-blocks
Browse files Browse the repository at this point in the history
This allows to simplify the usage of the FileLocker/FileLockingService
to:

try (var locking = fileLockService.lock(fileToProtect)) {
  // do something
}
  • Loading branch information
HannesWell committed Sep 25, 2023
1 parent 3118388 commit 9d6df11
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 86 deletions.
21 changes: 20 additions & 1 deletion tycho-api/src/main/java/org/eclipse/tycho/FileLockService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

package org.eclipse.tycho;

import java.io.Closeable;
import java.io.File;

/**
Expand All @@ -25,6 +26,24 @@ public interface FileLockService {
* the given file. Locking is advisory only, i.e. all processes must use the same locking
* mechanism.
*/
public FileLocker getFileLocker(File file);
FileLocker getFileLocker(File file);

/**
* Locks the given file to protect read/write access from multiple processes on it. Locking is
* advisory only, i.e. all processes must use the same locking mechanism.
*/
default Closeable lock(File file) {
return lock(file, 10000L);
}

/**
* Locks the given file to protect read/write access from multiple processes on it. Locking is
* advisory only, i.e. all processes must use the same locking mechanism.
*/
default Closeable lock(File file, long timeout) {
FileLocker locker = getFileLocker(file);
locker.lock(timeout);
return locker::release;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.eclipse.tycho.FileLockService;
import org.eclipse.tycho.FileLocker;
import org.eclipse.tycho.TychoConstants;

@Component(role = BundleReader.class)
Expand Down Expand Up @@ -189,9 +188,7 @@ public File getEntry(File bundleLocation, String path) {
throw new RuntimeException("can't get canonical path for " + cacheFile, e);
}
result = extractedFiles.computeIfAbsent(cacheKey, nil -> {
FileLocker locker = fileLockService.getFileLocker(outputDirectory);
locker.lock(LOCK_TIMEOUT);
try {
try (var locking = fileLockService.lock(outputDirectory, LOCK_TIMEOUT)) {
extractZipEntries(bundleLocation, path, outputDirectory);
if (cacheFile.exists()) {
return Optional.of(cacheFile);
Expand All @@ -200,8 +197,6 @@ public File getEntry(File bundleLocation, String path) {
} catch (IOException e) {
throw new RuntimeException(
"Can't extract '" + path + "' from " + bundleLocation + " to " + outputDirectory, e);
} finally {
locker.release();
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import java.util.Set;

import org.eclipse.tycho.FileLockService;
import org.eclipse.tycho.FileLocker;
import org.eclipse.tycho.core.shared.MavenContext;
import org.eclipse.tycho.core.shared.MavenLogger;

Expand All @@ -47,7 +46,7 @@ public class FileBasedTychoRepositoryIndex implements TychoRepositoryIndex {

private final File indexFile;
private final MavenLogger logger;
private FileLocker fileLocker;
private final FileLockService fileLockService;

private Set<GAV> addedGavs = new HashSet<>();
private Set<GAV> removedGavs = new HashSet<>();
Expand All @@ -58,28 +57,17 @@ private FileBasedTychoRepositoryIndex(File indexFile, FileLockService fileLockSe
super();
this.indexFile = indexFile;
this.mavenContext = mavenContext;
this.fileLocker = fileLockService.getFileLocker(indexFile);
this.fileLockService = fileLockService;
this.logger = mavenContext.getLogger();
if (indexFile.isFile()) {
lock();
try {
try (var locking = fileLockService.lock(indexFile)) {
gavs = read(new FileInputStream(indexFile));
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
unlock();
}
}
}

private void lock() {
fileLocker.lock();
}

private void unlock() {
fileLocker.release();
}

@Override
public MavenContext getMavenContext() {
return mavenContext;
Expand Down Expand Up @@ -118,8 +106,7 @@ public synchronized void save() throws IOException {
if (!parentDir.isDirectory()) {
parentDir.mkdirs();
}
lock();
try {
try (var locking = fileLockService.lock(indexFile)) {
reconcile();
// minimize time window for corrupting the file by first writing to a temp file, then moving it
File tempFile = File.createTempFile("index", "tmp", indexFile.getParentFile());
Expand All @@ -128,8 +115,6 @@ public synchronized void save() throws IOException {
indexFile.delete();
}
tempFile.renameTo(indexFile);
} finally {
unlock();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,12 @@ private void lockAndRelease(FileLockerImpl fileLocker) {
@Test
public void testLockReentranceDifferentLocker() throws IOException {
final File testFile = newTestFile();
FileLocker fileLocker1 = subject.getFileLocker(testFile);
FileLocker fileLocker2 = subject.getFileLocker(testFile);
fileLocker1.lock();
try {
try (var locking = subject.lock(testFile)) {
FileLocker fileLocker2 = subject.getFileLocker(testFile);
fileLocker2.lock(0L);
fail("lock already held by same VM but could be acquired a second time");
} catch (LockTimeoutException e) {
// expected
} finally {
fileLocker1.release();
}
}

Expand All @@ -136,18 +132,15 @@ public void testLockedByOtherProcess() throws Exception {
@Test
public void testTimeout() throws Exception {
File testFile = newTestFile();
FileLocker locker = subject.getFileLocker(testFile);
long waitTime = 1000L;
LockProcess lockProcess = new LockProcess(testFile, waitTime);
long start = System.currentTimeMillis();
lockProcess.lockFileInForkedProcess();
locker.lock(20000L);
try {
try (var locking = subject.lock(testFile, 20000L)) {
long duration = System.currentTimeMillis() - start;
assertTrue(duration >= waitTime);
} finally {
lockProcess.cleanup();
locker.release();
}
}

Expand All @@ -172,13 +165,9 @@ public void testMarkerFileDeletion() throws Exception {
public void testURLEncoding() throws IOException {
File testFile = new File(tempFolder.getRoot(), "file with spaces" + new Random().nextInt());
File markerFile = new File(testFile.getAbsolutePath() + ".tycholock");
FileLocker fileLocker = subject.getFileLocker(testFile);
assertFalse(markerFile.isFile());
fileLocker.lock();
try {
try (var locking = subject.lock(testFile)) {
assertTrue(markerFile.isFile());
} finally {
fileLocker.release();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.util.Set;

import org.eclipse.tycho.FileLockService;
import org.eclipse.tycho.FileLocker;
import org.eclipse.tycho.test.util.EnvironmentUtil;

public class LocalMavenRepositoryTool {
Expand Down Expand Up @@ -59,12 +58,8 @@ public File getArtifactFile(String groupId, String artifactId, String version, S

public Set<String> getArtifactIndexLines() throws IOException {
File indexFile = getArtifactIndexFile();
FileLocker locker = fileLockService.getFileLocker(indexFile);
locker.lock();
try {
try (var locking = fileLockService.lock(indexFile)) {
return readLines(indexFile);
} finally {
locker.release();
}
}

Expand Down Expand Up @@ -95,14 +90,10 @@ public void removeLinesFromMetadataIndex(String... linesToBeRemoved) throws IOEx

private void filterLinesFromIndex(File indexFile, Set<String> toBeRemoved)
throws FileNotFoundException, IOException {
FileLocker locker = fileLockService.getFileLocker(indexFile);
locker.lock();
try {
try (var locking = fileLockService.lock(indexFile)) {
Set<String> currentLines = readLines(indexFile);
currentLines.removeAll(toBeRemoved);
writeLines(indexFile, currentLines);
} finally {
locker.release();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.*;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.eclipse.tycho.ArtifactDescriptor;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.DependencyArtifacts;
import org.eclipse.tycho.FileLockService;
import org.eclipse.tycho.FileLocker;
import org.eclipse.tycho.Interpolator;
import org.eclipse.tycho.PackagingType;
import org.eclipse.tycho.PlatformPropertiesUtils;
Expand Down Expand Up @@ -129,19 +132,15 @@ private File getExpandedLauncherBinaries() throws MojoExecutionException, MojoFa
return unzipped.getAbsoluteFile();
}
try {
FileLocker locker = fileLockService.getFileLocker(equinoxExecFeature);
locker.lock();
try {
try (var locking = fileLockService.lock(equinoxExecFeature)) {
// unzip now then:
unzipped.mkdirs();
deflater.setSourceFile(equinoxExecFeature);
deflater.setDestDirectory(unzipped);
deflater.extract();
return unzipped.getAbsoluteFile();
} finally {
locker.release();
}
} catch (ArchiverException e) {
} catch (ArchiverException | IOException e) {
throw new MojoFailureException("Unable to unzip the equinox executable feature", e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.FileLockService;
import org.eclipse.tycho.FileLocker;
import org.eclipse.tycho.IllegalArtifactReferenceException;
import org.eclipse.tycho.TargetPlatform;
import org.eclipse.tycho.model.Feature;
Expand Down Expand Up @@ -174,25 +173,18 @@ private void setDownloadAndInstallSize(PluginRef pluginRefToEdit, File artifact)

protected long getInstallSize(File location) {
long installSize = 0;
FileLocker locker = fileLockService.getFileLocker(location);
locker.lock();
try {
try {
try (JarFile jar = new JarFile(location)) {
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
long entrySize = entry.getSize();
if (entrySize > 0) {
installSize += entrySize;
}
}
try (var locking = fileLockService.lock(location); //
JarFile jar = new JarFile(location);) {
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
long entrySize = entry.getSize();
if (entrySize > 0) {
installSize += entrySize;
}
} catch (IOException e) {
throw new RuntimeException("Could not determine installation size of file " + location, e);
}
} finally {
locker.release();
} catch (IOException e) {
throw new RuntimeException("Could not determine installation size of file " + location, e);
}
return installSize;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.util.FileUtils;
import org.eclipse.tycho.FileLockService;
import org.eclipse.tycho.FileLocker;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.core.ArtifactDependencyVisitor;
import org.eclipse.tycho.core.FeatureDescription;
Expand Down Expand Up @@ -199,15 +198,11 @@ private void unpackJar(File location, File outputJar) {

unzip.setSourceFile(location);
unzip.setDestDirectory(outputJar);
FileLocker locker = fileLockService.getFileLocker(location);
locker.lock();
try {
try (var locking = fileLockService.lock(location)) {
unzip.extract();
} catch (ArchiverException e) {
} catch (ArchiverException | IOException e) {
throw new RuntimeException("Could not unpack jar", e);
} finally {
locker.release();
}
}
}

private void copyDir(File location, File outputJar) {
Expand Down

0 comments on commit 9d6df11

Please sign in to comment.