Path: blob/master/test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java
41153 views
/*1* Copyright (c) 2008, 2010, 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*/2223/* @test24* @bug 4607272 6822643 6830721 684268725* @summary Unit test for AsynchronousFileChannel26* @key randomness27*/2829import java.nio.file.*;30import java.nio.channels.*;31import java.nio.ByteBuffer;32import java.io.File;33import java.io.IOException;34import java.util.*;35import java.util.concurrent.*;36import java.util.concurrent.atomic.AtomicReference;37import static java.nio.file.StandardOpenOption.*;3839public class Basic {4041private static final Random rand = new Random();4243public static void main(String[] args) throws IOException {44// create temporary file45File blah = File.createTempFile("blah", null);46blah.deleteOnExit();4748AsynchronousFileChannel ch = AsynchronousFileChannel49.open(blah.toPath(), READ, WRITE);50try {51// run tests52testUsingCompletionHandlers(ch);53testUsingWaitOnResult(ch);54testInterruptHandlerThread(ch);55} finally {56ch.close();57}5859// run test that expects channel to be closed60testClosedChannel(ch);6162// these tests open the file themselves63testLocking(blah.toPath());64testCustomThreadPool(blah.toPath());65testAsynchronousClose(blah.toPath());66testCancel(blah.toPath());67testTruncate(blah.toPath());6869// eagerly clean-up70blah.delete();71}7273/*74* Generate buffer with random contents75* Writes buffer to file using a CompletionHandler to consume the result76* of each write operation77* Reads file to EOF to a new buffer using a CompletionHandler to consume78* the result of each read operation79* Compares buffer contents80*/81static void testUsingCompletionHandlers(AsynchronousFileChannel ch)82throws IOException83{84System.out.println("testUsingCompletionHandlers");8586ch.truncate(0L);8788// generate buffer with random elements and write it to file89ByteBuffer src = genBuffer();90writeFully(ch, src, 0L);9192// read to EOF or buffer is full93ByteBuffer dst = (rand.nextBoolean()) ?94ByteBuffer.allocateDirect(src.capacity()) :95ByteBuffer.allocate(src.capacity());96readAll(ch, dst, 0L);9798// check buffers are the same99src.flip();100dst.flip();101if (!src.equals(dst)) {102throw new RuntimeException("Contents differ");103}104}105106/*107* Generate buffer with random contents108* Writes buffer to file, invoking the Future's get method to wait for109* each write operation to complete110* Reads file to EOF to a new buffer, invoking the Future's get method to111* wait for each write operation to complete112* Compares buffer contents113*/114static void testUsingWaitOnResult(AsynchronousFileChannel ch)115throws IOException116{117System.out.println("testUsingWaitOnResult");118119ch.truncate(0L);120121// generate buffer122ByteBuffer src = genBuffer();123124// write buffer completely to file125long position = 0L;126while (src.hasRemaining()) {127Future<Integer> result = ch.write(src, position);128try {129int n = result.get();130// update position131position += n;132} catch (ExecutionException x) {133throw new RuntimeException(x.getCause());134} catch (InterruptedException x) {135throw new RuntimeException(x);136}137}138139// read file into new buffer140ByteBuffer dst = (rand.nextBoolean()) ?141ByteBuffer.allocateDirect(src.capacity()) :142ByteBuffer.allocate(src.capacity());143position = 0L;144int n;145do {146Future<Integer> result = ch.read(dst, position);147try {148n = result.get();149150// update position151if (n > 0) position += n;152} catch (ExecutionException x) {153throw new RuntimeException(x.getCause());154} catch (InterruptedException x) {155throw new RuntimeException(x);156}157} while (n > 0);158159// check buffers are the same160src.flip();161dst.flip();162if (!src.equals(dst)) {163throw new RuntimeException("Contents differ");164}165}166167// exercise lock methods168static void testLocking(Path file) throws IOException {169System.out.println("testLocking");170171AsynchronousFileChannel ch = AsynchronousFileChannel172.open(file, READ, WRITE);173FileLock fl;174try {175// test 1 - acquire lock and check that tryLock throws176// OverlappingFileLockException177try {178fl = ch.lock().get();179} catch (ExecutionException x) {180throw new RuntimeException(x);181} catch (InterruptedException x) {182throw new RuntimeException("Should not be interrupted");183}184if (!fl.acquiredBy().equals(ch))185throw new RuntimeException("FileLock#acquiredBy returned incorrect channel");186try {187ch.tryLock();188throw new RuntimeException("OverlappingFileLockException expected");189} catch (OverlappingFileLockException x) {190}191fl.release();192193// test 2 - acquire try and check that lock throws OverlappingFileLockException194fl = ch.tryLock();195if (fl == null)196throw new RuntimeException("Unable to acquire lock");197try {198ch.lock((Void)null, new CompletionHandler<FileLock,Void> () {199public void completed(FileLock result, Void att) {200}201public void failed(Throwable exc, Void att) {202}203});204throw new RuntimeException("OverlappingFileLockException expected");205} catch (OverlappingFileLockException x) {206}207} finally {208ch.close();209}210211// test 3 - channel is closed so FileLock should no longer be valid212if (fl.isValid())213throw new RuntimeException("FileLock expected to be invalid");214}215216// interrupt should not close channel217static void testInterruptHandlerThread(final AsynchronousFileChannel ch) {218System.out.println("testInterruptHandlerThread");219220ByteBuffer buf = ByteBuffer.allocateDirect(100);221final CountDownLatch latch = new CountDownLatch(1);222223ch.read(buf, 0L, (Void)null, new CompletionHandler<Integer,Void>() {224public void completed(Integer result, Void att) {225try {226Thread.currentThread().interrupt();227long size = ch.size();228latch.countDown();229} catch (IOException x) {230x.printStackTrace();231}232}233public void failed(Throwable exc, Void att) {234}235});236237// wait for handler to complete238await(latch);239}240241// invoke method on closed channel242static void testClosedChannel(AsynchronousFileChannel ch) {243System.out.println("testClosedChannel");244245if (ch.isOpen())246throw new RuntimeException("Channel should be closed");247248ByteBuffer buf = ByteBuffer.allocateDirect(100);249250// check read fails with ClosedChannelException251try {252ch.read(buf, 0L).get();253throw new RuntimeException("ExecutionException expected");254} catch (ExecutionException x) {255if (!(x.getCause() instanceof ClosedChannelException))256throw new RuntimeException("Cause of ClosedChannelException expected");257} catch (InterruptedException x) {258}259260// check write fails with ClosedChannelException261try {262ch.write(buf, 0L).get();263throw new RuntimeException("ExecutionException expected");264} catch (ExecutionException x) {265if (!(x.getCause() instanceof ClosedChannelException))266throw new RuntimeException("Cause of ClosedChannelException expected");267} catch (InterruptedException x) {268}269270// check lock fails with ClosedChannelException271try {272ch.lock().get();273throw new RuntimeException("ExecutionException expected");274} catch (ExecutionException x) {275if (!(x.getCause() instanceof ClosedChannelException))276throw new RuntimeException("Cause of ClosedChannelException expected");277} catch (InterruptedException x) {278}279}280281282// exercise custom thread pool283static void testCustomThreadPool(Path file) throws IOException {284System.out.println("testCustomThreadPool");285286// records threads that are created287final List<Thread> threads = new ArrayList<Thread>();288289ThreadFactory threadFactory = new ThreadFactory() {290@Override291public Thread newThread(Runnable r) {292Thread t = new Thread(r);293t.setDaemon(true);294synchronized (threads) {295threads.add(t);296}297return t;298}299};300301// exercise tests with varied number of threads302for (int nThreads=1; nThreads<=5; nThreads++) {303synchronized (threads) {304threads.clear();305}306ExecutorService executor = Executors.newFixedThreadPool(nThreads, threadFactory);307Set<StandardOpenOption> opts = EnumSet.of(WRITE);308AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, opts, executor);309try {310for (int i=0; i<10; i++) {311// do I/O operation to see which thread invokes the completion handler312final AtomicReference<Thread> invoker = new AtomicReference<Thread>();313final CountDownLatch latch = new CountDownLatch(1);314315ch.write(genBuffer(), 0L, (Void)null, new CompletionHandler<Integer,Void>() {316public void completed(Integer result, Void att) {317invoker.set(Thread.currentThread());318latch.countDown();319}320public void failed(Throwable exc, Void att) {321}322});323await(latch);324325// check invoker326boolean found = false;327synchronized (threads) {328for (Thread t: threads) {329if (t == invoker.get()) {330found = true;331break;332}333}334}335if (!found)336throw new RuntimeException("Invoker thread not found");337}338} finally {339ch.close();340executor.shutdown();341}342}343344345// test sharing a thread pool between many channels346ExecutorService executor = Executors347.newFixedThreadPool(1+rand.nextInt(10), threadFactory);348final int n = 50 + rand.nextInt(50);349AsynchronousFileChannel[] channels = new AsynchronousFileChannel[n];350try {351for (int i=0; i<n; i++) {352Set<StandardOpenOption> opts = EnumSet.of(WRITE);353channels[i] = AsynchronousFileChannel.open(file, opts, executor);354final CountDownLatch latch = new CountDownLatch(1);355channels[i].write(genBuffer(), 0L, (Void)null, new CompletionHandler<Integer,Void>() {356public void completed(Integer result, Void att) {357latch.countDown();358}359public void failed(Throwable exc, Void att) {360}361});362await(latch);363364// close ~half the channels365if (rand.nextBoolean())366channels[i].close();367}368} finally {369// close remaining channels370for (int i=0; i<n; i++) {371if (channels[i] != null) channels[i].close();372}373executor.shutdown();374}375}376377// exercise asynchronous close378static void testAsynchronousClose(Path file) throws IOException {379System.out.println("testAsynchronousClose");380381// create file382AsynchronousFileChannel ch = AsynchronousFileChannel383.open(file, WRITE, TRUNCATE_EXISTING);384long size = 0L;385do {386ByteBuffer buf = genBuffer();387int n = buf.remaining();388writeFully(ch, buf, size);389size += n;390} while (size < (50L * 1024L * 1024L));391392ch.close();393394ch = AsynchronousFileChannel.open(file, WRITE, SYNC);395396// randomize number of writers, buffer size, and positions397398int nwriters = 1 + rand.nextInt(8);399ByteBuffer[] buf = new ByteBuffer[nwriters];400long[] position = new long[nwriters];401for (int i=0; i<nwriters; i++) {402buf[i] = genBuffer();403position[i] = rand.nextInt((int)size);404}405406// initiate I/O407Future[] result = new Future[nwriters];408for (int i=0; i<nwriters; i++) {409result[i] = ch.write(buf[i], position[i]);410}411412// close file413ch.close();414415// write operations should complete or fail with AsynchronousCloseException416for (int i=0; i<nwriters; i++) {417try {418result[i].get();419} catch (ExecutionException x) {420Throwable cause = x.getCause();421if (!(cause instanceof AsynchronousCloseException))422throw new RuntimeException(cause);423} catch (CancellationException x) {424throw new RuntimeException(x); // should not happen425} catch (InterruptedException x) {426throw new RuntimeException(x); // should not happen427}428}429}430431// exercise cancel method432static void testCancel(Path file) throws IOException {433System.out.println("testCancel");434435for (int i=0; i<2; i++) {436boolean mayInterruptIfRunning = (i == 0) ? false : true;437438// open with SYNC option to improve chances that write will not439// complete immediately440AsynchronousFileChannel ch = AsynchronousFileChannel441.open(file, WRITE, SYNC);442443// start write operation444Future<Integer> res = ch.write(genBuffer(), 0L);445446// cancel operation447boolean cancelled = res.cancel(mayInterruptIfRunning);448449// check post-conditions450if (!res.isDone())451throw new RuntimeException("isDone should return true");452if (res.isCancelled() != cancelled)453throw new RuntimeException("isCancelled not consistent");454try {455res.get();456if (cancelled)457throw new RuntimeException("CancellationException expected");458} catch (CancellationException x) {459if (!cancelled)460throw new RuntimeException("CancellationException not expected");461} catch (ExecutionException x) {462throw new RuntimeException(x);463} catch (InterruptedException x) {464throw new RuntimeException(x);465}466try {467res.get(1, TimeUnit.SECONDS);468if (cancelled)469throw new RuntimeException("CancellationException expected");470} catch (CancellationException x) {471if (!cancelled)472throw new RuntimeException("CancellationException not expected");473} catch (ExecutionException x) {474throw new RuntimeException(x);475} catch (TimeoutException x) {476throw new RuntimeException(x);477} catch (InterruptedException x) {478throw new RuntimeException(x);479}480481ch.close();482}483}484485// exercise truncate method486static void testTruncate(Path file) throws IOException {487System.out.println("testTruncate");488489// basic tests490AsynchronousFileChannel ch = AsynchronousFileChannel491.open(file, CREATE, WRITE, TRUNCATE_EXISTING);492try {493writeFully(ch, genBuffer(), 0L);494long size = ch.size();495496// attempt to truncate to a size greater than the current size497if (ch.truncate(size + 1L).size() != size)498throw new RuntimeException("Unexpected size after truncation");499500// truncate file501if (ch.truncate(size - 1L).size() != (size - 1L))502throw new RuntimeException("Unexpected size after truncation");503504// invalid size505try {506ch.truncate(-1L);507throw new RuntimeException("IllegalArgumentException expected");508} catch (IllegalArgumentException e) { }509510} finally {511ch.close();512}513514// channel is closed515try {516ch.truncate(0L);517throw new RuntimeException("ClosedChannelException expected");518} catch (ClosedChannelException e) { }519520// channel is read-only521ch = AsynchronousFileChannel.open(file, READ);522try {523try {524ch.truncate(0L);525throw new RuntimeException("NonWritableChannelException expected");526} catch (NonWritableChannelException e) { }527} finally {528ch.close();529}530}531532// returns ByteBuffer with random bytes533static ByteBuffer genBuffer() {534int size = 1024 + rand.nextInt(16000);535byte[] buf = new byte[size];536boolean useDirect = rand.nextBoolean();537if (useDirect) {538ByteBuffer bb = ByteBuffer.allocateDirect(buf.length);539bb.put(buf);540bb.flip();541return bb;542} else {543return ByteBuffer.wrap(buf);544}545}546547// writes all remaining bytes in the buffer to the given channel at the548// given position549static void writeFully(final AsynchronousFileChannel ch,550final ByteBuffer src,551long position)552{553final CountDownLatch latch = new CountDownLatch(1);554555// use position as attachment556ch.write(src, position, position, new CompletionHandler<Integer,Long>() {557public void completed(Integer result, Long position) {558int n = result;559if (src.hasRemaining()) {560long p = position + n;561ch.write(src, p, p, this);562} else {563latch.countDown();564}565}566public void failed(Throwable exc, Long position) {567}568});569570// wait for writes to complete571await(latch);572}573574static void readAll(final AsynchronousFileChannel ch,575final ByteBuffer dst,576long position)577{578final CountDownLatch latch = new CountDownLatch(1);579580// use position as attachment581ch.read(dst, position, position, new CompletionHandler<Integer,Long>() {582public void completed(Integer result, Long position) {583int n = result;584if (n > 0) {585long p = position + n;586ch.read(dst, p, p, this);587} else {588latch.countDown();589}590}591public void failed(Throwable exc, Long position) {592}593});594595// wait for reads to complete596await(latch);597}598599static void await(CountDownLatch latch) {600// wait until done601boolean done = false;602while (!done) {603try {604latch.await();605done = true;606} catch (InterruptedException x) { }607}608}609}610611612