changeset 999:6a7ef879247a

7901013: JMH should safeguard against the concurrent execution with file lock
author shade
date Thu, 04 Sep 2014 16:45:09 +0400
parents 53e0e7585434
children bae8cd49a7c1
files jmh-core-it/pom.xml jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java jmh-core/src/main/java/org/openjdk/jmh/util/FileUtils.java
diffstat 3 files changed, 61 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-core-it/pom.xml	Wed Sep 03 22:49:42 2014 +0400
+++ b/jmh-core-it/pom.xml	Thu Sep 04 16:45:09 2014 +0400
@@ -72,6 +72,8 @@
                 <artifactId>maven-surefire-plugin</artifactId>
                 <version>2.14.1</version>
                 <configuration>
+                    <!-- Integration tests are not measuring performance, OK to run them concurrently -->
+                    <argLine>-Djmh.ignoreLock=true</argLine>
                     <forkCount>1C</forkCount>
                     <reuseForks>true</reuseForks>
                     <redirectTestOutputToFile>true</redirectTestOutputToFile>
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Wed Sep 03 22:49:42 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Thu Sep 04 16:45:09 2014 +0400
@@ -54,7 +54,11 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
+import java.io.RandomAccessFile;
 import java.lang.management.ManagementFactory;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -79,6 +83,8 @@
 public class Runner extends BaseRunner {
 
     private static final int TAIL_LINES_ON_ERROR = 20;
+    private static final String JMH_LOCK_FILE = System.getProperty("java.io.tmpdir") + "/jmh.lock";
+    private static final Boolean JMH_LOCK_IGNORE = Boolean.getBoolean("jmh.ignoreLock");
 
     private final BenchmarkList list;
     private int cpuCount;
@@ -166,6 +172,48 @@
      * @throws org.openjdk.jmh.runner.RunnerException if something goes wrong
      */
     public Collection<RunResult> run() throws RunnerException {
+        FileChannel channel = null;
+        FileLock lock = null;
+        try {
+            channel = new RandomAccessFile(JMH_LOCK_FILE, "rw").getChannel();
+
+            try {
+                lock = channel.tryLock();
+            } catch (OverlappingFileLockException e) {
+                // fall-through
+            }
+
+            if (lock == null) {
+                String msg = "Unable to acquire the JMH lock (" + JMH_LOCK_FILE + "): already taken by another JMH instance";
+                if (JMH_LOCK_IGNORE) {
+                    out.println("# WARNING: " + msg + ", ignored by user's request.");
+                } else {
+                    throw new RunnerException("ERROR: " + msg + ", exiting. Use -Djmh.ignoreLock=true to forcefully continue.");
+                }
+            }
+
+            return internalRun();
+        } catch (IOException e) {
+            String msg = "Exception while trying to acquire the JMH lock (" + JMH_LOCK_FILE + "): " + e.getMessage();
+            if (JMH_LOCK_IGNORE) {
+                out.println("# WARNING: " + msg + ", ignored by user's request.");
+                return internalRun();
+            } else {
+                throw new RunnerException("ERROR: " + msg  + ", exiting. Use -Djmh.ignoreLock=true to forcefully continue.");
+            }
+        } finally {
+            try {
+                if (lock != null) {
+                    lock.release();
+                }
+            } catch (IOException e) {
+                // do nothing
+            }
+            FileUtils.safelyClose(channel);
+        }
+    }
+
+    private Collection<RunResult> internalRun() throws RunnerException {
         for (Class<? extends Profiler> p : options.getProfilers()) {
             List<String> initMessages = new ArrayList<String>();
             if (!ProfilerFactory.checkSupport(p, initMessages)) {
--- a/jmh-core/src/main/java/org/openjdk/jmh/util/FileUtils.java	Wed Sep 03 22:49:42 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/FileUtils.java	Thu Sep 04 16:45:09 2014 +0400
@@ -35,6 +35,7 @@
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.nio.channels.Channel;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedList;
@@ -221,6 +222,16 @@
         }
     }
 
+    public static void safelyClose(Channel channel) {
+        if (channel != null) {
+            try {
+                channel.close();
+            } catch (IOException e) {
+                // do nothing
+            }
+        }
+    }
+
     public static void touch(String f) throws IOException {
         File file = new File(f);
         try {