blob: bca65901e0a4bafa980e44985b2a9d1a82165183 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package demo; // CHECKSTYLE_OFF: RegexpHeader
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A simple tool to check file locking on your OS/FS/Java combo. To use this tool, just copy it to basedir on
* the volume you plan to use as local repository and compile and run it:
* <ul>
* <li><pre>javac demo.TestNioLock.java</pre></li>
* <li><pre>java demo.TestNioLock test someFile 1000</pre></li>
* </ul>
*/
public class TestNioLock {
private static final int EC_WON = 10;
private static final int EC_LOST = 20;
private static final int EC_FAILED = 30;
private static final int EC_ERROR = 100;
public static void main(String[] args) throws IOException, InterruptedException {
if (args.length != 3) {
System.out.println("demo.TestNioLock <test|perform> <file> <sleepMs>");
System.exit(EC_ERROR);
}
String mode = args[0];
Path path = Paths.get(args[1]).toAbsolutePath();
Path latchFile = path.getParent().resolve(TestNioLock.class.getName() + ".latchFile");
if (Files.isDirectory(path)) {
System.out.println("The <file> cannot be directory.");
System.exit(EC_ERROR);
}
if (!Files.isRegularFile(latchFile)) {
Files.createFile(latchFile);
}
if ("test".equals(mode)) {
System.out.println("Testing file locking on");
System.out.println(
" Java " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor"));
System.out.println(" OS " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " "
+ System.getProperty("os.arch"));
FileStore fileStore = Files.getFileStore(path.getParent());
System.out.println(" FS " + fileStore.name() + " " + fileStore.type());
System.out.println();
AtomicInteger oneResult = new AtomicInteger(-1);
AtomicInteger twoResult = new AtomicInteger(-1);
CountDownLatch latch = new CountDownLatch(2);
String javaCmd = System.getProperty("java.home") + "/bin/java";
try (FileChannel latchChannel =
FileChannel.open(latchFile, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
try (FileLock latchLock = latchChannel.lock(0L, 1L, false)) {
new Thread(() -> {
try {
oneResult.set(new ProcessBuilder(
javaCmd, TestNioLock.class.getName(), "perform", args[1], args[2])
.inheritIO()
.start()
.waitFor());
} catch (Exception e) {
oneResult.set(EC_FAILED);
} finally {
latch.countDown();
}
})
.start();
new Thread(() -> {
try {
twoResult.set(new ProcessBuilder(
javaCmd, TestNioLock.class.getName(), "perform", args[1], args[2])
.inheritIO()
.start()
.waitFor());
} catch (Exception e) {
twoResult.set(EC_FAILED);
} finally {
latch.countDown();
}
})
.start();
Thread.sleep(1000); // give them a bit of time (to both block)
latchLock.release();
latch.await();
}
}
int oneExit = oneResult.get();
int twoExit = twoResult.get();
if ((oneExit == EC_WON && twoExit == EC_LOST) || (oneExit == EC_LOST && twoExit == EC_WON)) {
System.out.println("OK");
System.exit(0);
} else {
System.out.println("FAILED: one=" + oneExit + " two=" + twoExit);
System.exit(EC_FAILED);
}
} else if ("perform".equals(mode)) {
String processName = ManagementFactory.getRuntimeMXBean().getName();
System.out.println(processName + " > started");
boolean won = false;
long sleepMs = Long.parseLong(args[2]);
try (FileChannel latchChannel = FileChannel.open(latchFile, StandardOpenOption.READ)) {
try (FileLock latchLock = latchChannel.lock(0L, 1L, true)) {
System.out.println(processName + " > latchLock acquired");
try (FileChannel channel = FileChannel.open(
path, StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
try (FileLock lock = channel.tryLock(0L, 1L, false)) {
if (lock != null && lock.isValid() && !lock.isShared()) {
System.out.println(processName + " > WON");
won = true;
Thread.sleep(sleepMs);
} else {
System.out.println(processName + " > LOST");
}
}
}
}
}
System.out.println(processName + " > ended");
if (won) {
System.exit(EC_WON);
} else {
System.exit(EC_LOST);
}
} else {
System.err.println("Unknown mode: " + mode);
}
System.exit(EC_ERROR);
}
}