Browse Source

SONAR-16026 Adds file lock retries when explode jar

tags/9.4.0.54424
Patrick Reinhart 2 years ago
parent
commit
982553a5cb

+ 22
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerPluginJarExploder.java View File

@@ -22,6 +22,10 @@ package org.sonar.scanner.bootstrap;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;

import org.apache.commons.io.FileUtils;
import org.sonar.api.utils.ZipUtils;
import org.sonar.core.platform.ExplodedPlugin;
@@ -54,7 +58,7 @@ public class ScannerPluginJarExploder extends PluginJarExploder {
File lockFile = new File(cachedFile.getParentFile(), filename + "_unzip.lock");
if (!destDir.exists()) {
try (FileOutputStream out = new FileOutputStream(lockFile)) {
java.nio.channels.FileLock lock = out.getChannel().lock();
FileLock lock = createLockWithRetries(out.getChannel());
try {
// Recheck in case of concurrent processes
if (!destDir.exists()) {
@@ -71,4 +75,21 @@ public class ScannerPluginJarExploder extends PluginJarExploder {
}
return destDir;
}

private static FileLock createLockWithRetries(FileChannel channel) throws IOException {
int tryCount = 0;
while (tryCount++ < 10) {
try {
return channel.lock();
} catch (OverlappingFileLockException ofle) {
// ignore overlapping file exception
}
try {
Thread.sleep(200L * tryCount);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
throw new IOException("Unable to get lock after " + tryCount + " tries");
}
}

+ 21
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerPluginJarExploderTest.java View File

@@ -20,7 +20,9 @@
package org.sonar.scanner.bootstrap;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileLock;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.ClassRule;
@@ -30,6 +32,7 @@ import org.sonar.core.platform.ExplodedPlugin;
import org.sonar.core.platform.PluginInfo;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@@ -72,6 +75,24 @@ public class ScannerPluginJarExploderTest {
assertThat(new File(jar.getParent(), "sonar-checkstyle-plugin-2.8.jar_unzip/org/sonar/plugins/checkstyle/CheckstyleVersion.class")).doesNotExist();
}

@Test
public void retry_on_locked_file() throws IOException {
File jar = loadFile("sonar-checkstyle-plugin-2.8.jar");
File lockFile = new File(jar.getParentFile(), jar.getName() + "_unzip.lock");
try (FileOutputStream out = new FileOutputStream(lockFile)) {
FileLock lock = out.getChannel().lock();
try {
PluginInfo pluginInfo = PluginInfo.create(jar);
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> underTest.explode(pluginInfo))
.withMessage("Fail to open plugin [checkstyle]: " + jar)
.withCauseExactlyInstanceOf(IOException.class);
} finally {
lock.release();
}
}
}

private File loadFile(String filename) throws IOException {
File src = FileUtils.toFile(getClass().getResource(getClass().getSimpleName() + "/" + filename));
File dest = new File(temp.newFolder(), filename);

Loading…
Cancel
Save