Path: blob/master/test/jdk/java/nio/channels/AsynchronousFileChannel/Lock.java
41153 views
/*1* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/222324/* @test25* @bug 4607272 6814948 684268726* @summary Unit test for AsynchronousFileChannel#lock method27* @key randomness28*/2930import java.net.*;31import java.nio.ByteBuffer;32import java.nio.charset.Charset;33import java.nio.file.*;34import static java.nio.file.StandardOpenOption.*;35import java.nio.channels.*;36import java.io.File;37import java.io.IOException;38import java.io.InputStream;39import java.util.Random;40import java.util.concurrent.*;4142public class Lock {4344static final Random rand = new Random();4546public static void main(String[] args) throws Exception {47if (args.length > 0 && args[0].equals("-lockworker")) {48int port = Integer.parseInt(args[1]);49runLockWorker(port);50System.exit(0);51}5253LockWorkerMirror worker = startLockWorker();54try {5556// create temporary file57File blah = File.createTempFile("blah", null);58blah.deleteOnExit();5960// run tests61testLockProtocol(blah, worker);62testAsyncClose(blah, worker);6364// eagerly clean-up65blah.delete();6667} finally {68worker.shutdown();69}70}7172// test locking protocol73static void testLockProtocol(File file, LockWorkerMirror worker)74throws Exception75{76FileLock fl;7778// worker VM opens file and acquires exclusive lock79worker.open(file.getPath()).lock();8081AsynchronousFileChannel ch = AsynchronousFileChannel82.open(file.toPath(), READ, WRITE);8384// this VM tries to acquire lock85// (lock should not be acquire until released by worker VM)86Future<FileLock> result = ch.lock();87try {88result.get(2, TimeUnit.SECONDS);89throw new RuntimeException("Timeout expected");90} catch (TimeoutException x) {91}9293// worker VM releases lock94worker.unlock();9596// this VM should now acquire lock97fl = result.get();98fl.release();99100// worker VM acquires lock on range101worker.lock(0, 10, false);102103// this VM acquires lock on non-overlapping range104fl = ch.lock(10, 10, false).get();105fl.release();106107// done108ch.close();109worker.close();110}111112// test close of channel with outstanding lock operation113static void testAsyncClose(File file, LockWorkerMirror worker) throws Exception {114// worker VM opens file and acquires exclusive lock115worker.open(file.getPath()).lock();116117for (int i=0; i<100; i++) {118AsynchronousFileChannel ch = AsynchronousFileChannel119.open(file.toPath(), READ, WRITE);120121// try to lock file (should not complete because file is locked by worker)122Future<FileLock> result = ch.lock();123try {124result.get(rand.nextInt(100), TimeUnit.MILLISECONDS);125throw new RuntimeException("Timeout expected");126} catch (TimeoutException x) {127}128129// close channel with lock operation outstanding130ch.close();131132// operation should complete with AsynchronousCloseException133try {134result.get();135throw new RuntimeException("ExecutionException expected");136} catch (ExecutionException x) {137if (!(x.getCause() instanceof AsynchronousCloseException)) {138x.getCause().printStackTrace();139throw new RuntimeException("AsynchronousCloseException expected");140}141}142}143144worker.close();145}146147// starts a "lock worker" in another process, returning a mirror object to148// control the worker149static LockWorkerMirror startLockWorker() throws Exception {150ServerSocketChannel ssc = ServerSocketChannel.open()151.bind(new InetSocketAddress(0));152int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();153154String sep = FileSystems.getDefault().getSeparator();155156String command = System.getProperty("java.home") +157sep + "bin" + sep + "java";158String testClasses = System.getProperty("test.classes");159if (testClasses != null)160command += " -cp " + testClasses;161command += " Lock -lockworker " + port;162163Process p = Runtime.getRuntime().exec(command);164IOHandler.handle(p.getInputStream());165IOHandler.handle(p.getErrorStream());166167// wait for worker to connect168SocketChannel sc = ssc.accept();169return new LockWorkerMirror(sc);170}171172// commands that the worker understands173static final String OPEN_CMD = "open";174static final String CLOSE_CMD = "close";175static final String LOCK_CMD = "lock";176static final String UNLOCK_CMD = "unlock";177static final char TERMINATOR = ';';178179// provides a proxy to a "lock worker"180static class LockWorkerMirror {181private final SocketChannel sc;182183LockWorkerMirror(SocketChannel sc) {184this.sc = sc;185}186187private void sendCommand(String cmd, String... params)188throws IOException189{190for (String s: params) {191cmd += " " + s;192}193cmd += TERMINATOR;194195ByteBuffer buf = Charset.defaultCharset().encode(cmd);196while (buf.hasRemaining()) {197sc.write(buf);198}199200// wait for ack201buf = ByteBuffer.allocate(1);202int n = sc.read(buf);203if (n != 1)204throw new RuntimeException("Reply expected");205if (buf.get(0) != TERMINATOR)206throw new RuntimeException("Terminated expected");207}208209LockWorkerMirror open(String file) throws IOException {210sendCommand(OPEN_CMD, file);211return this;212}213214void close() throws IOException {215sendCommand(CLOSE_CMD);216}217218LockWorkerMirror lock() throws IOException {219sendCommand(LOCK_CMD);220return this;221}222223224LockWorkerMirror lock(long position, long size, boolean shared)225throws IOException226{227sendCommand(LOCK_CMD, position + "," + size + "," + shared);228return this;229}230231LockWorkerMirror unlock() throws IOException {232sendCommand(UNLOCK_CMD);233return this;234}235236void shutdown() throws IOException {237sc.close();238}239}240241// Helper class to direct process output to the parent System.out242static class IOHandler implements Runnable {243private final InputStream in;244245IOHandler(InputStream in) {246this.in = in;247}248249static void handle(InputStream in) {250IOHandler handler = new IOHandler(in);251Thread thr = new Thread(handler);252thr.setDaemon(true);253thr.start();254}255256public void run() {257try {258byte b[] = new byte[100];259for (;;) {260int n = in.read(b);261if (n < 0) return;262for (int i=0; i<n; i++) {263System.out.print((char)b[i]);264}265}266} catch (IOException ioe) { }267}268}269270// worker process that responds to simple commands a socket connection271static void runLockWorker(int port) throws Exception {272273// establish connection to parent274SocketChannel sc = SocketChannel.open(new InetSocketAddress(port));275ByteBuffer buf = ByteBuffer.allocateDirect(1024);276277FileChannel fc = null;278FileLock fl = null;279try {280for (;;) {281282// read command (ends with ";")283buf.clear();284int n, last = 0;285do {286n = sc.read(buf);287if (n < 0)288return;289if (n == 0)290throw new AssertionError();291last += n;292} while (buf.get(last-1) != TERMINATOR);293294// decode into command and optional parameter295buf.flip();296String s = Charset.defaultCharset().decode(buf).toString();297int sp = s.indexOf(" ");298String cmd = (sp < 0) ? s.substring(0, s.length()-1) :299s.substring(0, sp);300String param = (sp < 0) ? "" : s.substring(sp+1, s.length()-1);301302// execute303if (cmd.equals(OPEN_CMD)) {304if (fc != null)305throw new RuntimeException("File already open");306fc = FileChannel.open(Paths.get(param),READ, WRITE);307}308if (cmd.equals(CLOSE_CMD)) {309if (fc == null)310throw new RuntimeException("No file open");311fc.close();312fc = null;313fl = null;314}315if (cmd.equals(LOCK_CMD)) {316if (fl != null)317throw new RuntimeException("Already holding lock");318319if (param.length() == 0) {320fl = fc.lock();321} else {322String[] values = param.split(",");323if (values.length != 3)324throw new RuntimeException("Lock parameter invalid");325long position = Long.parseLong(values[0]);326long size = Long.parseLong(values[1]);327boolean shared = Boolean.parseBoolean(values[2]);328fl = fc.lock(position, size, shared);329}330}331332if (cmd.equals(UNLOCK_CMD)) {333if (fl == null)334throw new RuntimeException("Not holding lock");335fl.release();336fl = null;337}338339// send reply340byte[] reply = { TERMINATOR };341n = sc.write(ByteBuffer.wrap(reply));342}343344} finally {345sc.close();346if (fc != null) fc.close();347}348}349}350351352