2083N/A/*
2362N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2083N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2083N/A *
2083N/A * This code is free software; you can redistribute it and/or modify it
2083N/A * under the terms of the GNU General Public License version 2 only, as
2083N/A * published by the Free Software Foundation.
2083N/A *
2083N/A * This code is distributed in the hope that it will be useful, but WITHOUT
2083N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2083N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2083N/A * version 2 for more details (a copy is included in the LICENSE file that
2083N/A * accompanied this code).
2083N/A *
2083N/A * You should have received a copy of the GNU General Public License version
2083N/A * 2 along with this work; if not, write to the Free Software Foundation,
2083N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2083N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
2083N/A */
2083N/A
2083N/A/* @test
2083N/A * @bug 6913877
2083N/A * @summary Stress AsynchronousFileChannel.write
2083N/A */
2083N/A
2083N/Aimport java.io.*;
2083N/Aimport java.nio.ByteBuffer;
2083N/Aimport static java.nio.file.StandardOpenOption.*;
2083N/Aimport java.nio.channels.*;
2083N/Aimport java.util.Random;
2083N/Aimport java.util.concurrent.CountDownLatch;
2083N/A
2083N/Apublic class LotsOfWrites {
2083N/A static final Random rand = new Random();
2083N/A
2083N/A /**
2083N/A * Asynchronously writes a known pattern to a file up to a given size,
2083N/A * counting down a latch to release waiters when done.
2083N/A */
2083N/A static class Writer implements CompletionHandler<Integer,ByteBuffer> {
2083N/A private final File file;
2083N/A private final long size;
2083N/A private final CountDownLatch latch;
2083N/A private final AsynchronousFileChannel channel;
2083N/A
2083N/A private volatile long position;
2083N/A private volatile byte nextByte;
2083N/A
2083N/A private long updatePosition(long nwrote) {
2083N/A position += nwrote;
2083N/A return position;
2083N/A }
2083N/A
2083N/A private ByteBuffer genNextBuffer() {
2083N/A int n = Math.min(8192 + rand.nextInt(8192), (int)(size - position));
2083N/A ByteBuffer buf = ByteBuffer.allocate(n);
2083N/A for (int i=0; i<n; i++) {
2083N/A buf.put(nextByte++);
2083N/A }
2083N/A buf.flip();
2083N/A return buf;
2083N/A }
2083N/A
2083N/A // close channel and release any waiters
2083N/A private void done() {
2083N/A try {
2083N/A channel.close();
2083N/A } catch (IOException ignore) { }
2083N/A latch.countDown();
2083N/A }
2083N/A
2083N/A Writer(File file, long size, CountDownLatch latch) throws IOException {
2083N/A this.file = file;
2083N/A this.size = size;
2083N/A this.latch = latch;
2083N/A this.channel = AsynchronousFileChannel.open(file.toPath(), WRITE);
2083N/A }
2083N/A
2083N/A File file() {
2083N/A return file;
2083N/A }
2083N/A
2083N/A long size() {
2083N/A return size;
2083N/A }
2083N/A
2083N/A // initiate first write
2083N/A void start() {
2083N/A ByteBuffer buf = genNextBuffer();
2083N/A channel.write(buf, 0L, buf, this);
2083N/A }
2083N/A
2083N/A @Override
2083N/A public void completed(Integer nwrote, ByteBuffer buf) {
2083N/A long pos = updatePosition(nwrote);
2083N/A if (!buf.hasRemaining()) {
2083N/A // buffer has been completely written; decide if we need to
2083N/A // write more
2083N/A if (position >= size) {
2083N/A done();
2083N/A return;
2083N/A }
2083N/A buf = genNextBuffer();
2083N/A }
2083N/A channel.write(buf, pos, buf, this);
2083N/A }
2083N/A
2083N/A @Override
2083N/A public void failed(Throwable exc, ByteBuffer buf) {
2083N/A exc.printStackTrace();
2083N/A done();
2083N/A }
2083N/A }
2083N/A
2083N/A public static void main(String[] args) throws Exception {
2083N/A // random number of writers
2083N/A int count = 20 + rand.nextInt(16);
2083N/A Writer[] writers = new Writer[count];
2083N/A CountDownLatch latch = new CountDownLatch(count);
2083N/A
2083N/A // initiate writing to each file
2083N/A for (int i=0; i<count; i++) {
2083N/A long size = 512*1024 + rand.nextInt(512*1024);
2083N/A File blah = File.createTempFile("blah", null);
2083N/A blah.deleteOnExit();
2083N/A Writer writer = new Writer(blah, size, latch);
2083N/A writers[i] = writer;
2083N/A writer.start();
2083N/A }
2083N/A
2083N/A // wait for writing to complete
2083N/A latch.await();
2083N/A
2083N/A // verify content of each file
2546N/A boolean failed = false;
2083N/A byte[] buf = new byte[8192];
2083N/A for (int i=0; i<count ;i++) {
2083N/A Writer writer = writers[i];
2083N/A FileInputStream in = new FileInputStream(writer.file());
2083N/A try {
2083N/A long size = 0L;
2083N/A byte expected = 0;
2083N/A int nread = in.read(buf);
2083N/A while (nread > 0) {
2083N/A for (int j=0; j<nread; j++) {
2546N/A if (buf[j] != expected) {
2546N/A System.err.println("Unexpected contents");
2546N/A failed = true;
2546N/A break;
2546N/A }
2083N/A expected++;
2083N/A }
2546N/A if (failed)
2546N/A break;
2083N/A size += nread;
2083N/A nread = in.read(buf);
2083N/A }
2546N/A if (!failed && size != writer.size()) {
2546N/A System.err.println("Unexpected size");
2546N/A failed = true;
2546N/A }
2546N/A if (failed)
2546N/A break;
2083N/A } finally {
2083N/A in.close();
2083N/A }
2083N/A }
2546N/A
2546N/A // clean-up
2546N/A for (int i=0; i<count; i++) {
2546N/A writers[i].file().delete();
2546N/A }
2546N/A
2546N/A if (failed)
2546N/A throw new RuntimeException("Test failed");
2083N/A }
2083N/A}