changeset 390:cf2f95135de8

Fixes/updates for nio2-b93 - unable to access attributes of files opened without shared read access (win) - remove residual wording from description of IAE exceptions - fixed confusing statement in Path#toRealPath method - completed rather than failed method invoked when I/O operation completes immediately - allow default group have unbounded thread pool
author alanb
date Fri, 27 Jun 2008 15:23:21 +0100
parents 60d8a8c10dc5
children c5ebc4603dc6
files src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java src/share/classes/java/nio/channels/AsynchronousFileChannel.java src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java src/share/classes/java/nio/file/Path.java src/share/classes/sun/nio/ch/AbstractFuture.java src/share/classes/sun/nio/ch/CompletedFuture.java src/share/classes/sun/nio/ch/Invoker.java src/share/classes/sun/nio/ch/PendingFuture.java src/share/classes/sun/nio/ch/ThreadPool.java src/windows/classes/sun/nio/fs/WindowsFileAttributeView.java src/windows/classes/sun/nio/fs/WindowsFileAttributes.java src/windows/classes/sun/nio/fs/WindowsFileCopy.java src/windows/classes/sun/nio/fs/WindowsLinkSupport.java src/windows/classes/sun/nio/fs/WindowsPath.java test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java test/java/nio/channels/AsynchronousSocketChannel/Basic.java
diffstat 16 files changed, 181 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java	Fri Jun 27 15:23:21 2008 +0100
@@ -106,7 +106,6 @@
  *  dc.receive(buffer, buffer, new CompletionHandler<SocketAddress,ByteBuffer>() {
  *      public void completed(SocketAddress sa, ByteBuffer buffer) {
  *          try {
- *               SocketAddress sa = result.get();
  *               System.out.println(sa);
  *
  *               buffer.clear();
--- a/src/share/classes/java/nio/channels/AsynchronousFileChannel.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousFileChannel.java	Fri Jun 27 15:23:21 2008 +0100
@@ -229,8 +229,7 @@
      * @throws  IllegalArgumentException
      *          If one of the attributes is not a file attribute that can be set
      *          atomically when creating the file, or the options set includes
-     *          an invalid option or combination of options, or a parameter
-     *          in the map configuring the thread pool has an invalid value.
+     *          an invalid option or combination of options.
      *
      * @throws  UnsupportedOperationException
      *          If the {@code file} is associated with a provider that does not
--- a/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Fri Jun 27 15:23:21 2008 +0100
@@ -178,7 +178,8 @@
      * @param   factory
      *          The factory to use to create threads
      * @param   initialSize
-     *          The number of threads to initially create in the pool
+     *          Used to size the associated thread pool or a negative value
+     *          for an implementation chosen size
      *
      * @throws  IOException
      *          If an I/O error occurs
--- a/src/share/classes/java/nio/file/Path.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/java/nio/file/Path.java	Fri Jun 27 15:23:21 2008 +0100
@@ -686,10 +686,8 @@
      * actual case. Additionally, the resulting path has redundant name
      * elements removed.
      *
-     * <p> If this path is relative then the {@link #toAbsolutePath toAbsolutePath}
-     * method is first invoked to obtain the absolute path. If this fails, by
-     * throwing an {@code IOError}, then the error is re-thrown as an {@code
-     * IOException}.
+     * <p> If this path is relative then its absolute path is first obtained,
+     * as if by invoking the {@link #toAbsolutePath toAbsolutePath} method.
      *
      * <p> The {@code resolveLinks} parameter specifies if symbolic links
      * should be resolved. This parameter is ignored when symbolic links are
--- a/src/share/classes/sun/nio/ch/AbstractFuture.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/sun/nio/ch/AbstractFuture.java	Fri Jun 27 15:23:21 2008 +0100
@@ -52,11 +52,6 @@
     }
 
     /**
-     * Returns true if the operation has completed successfully.
-     */
-    abstract boolean isCompleted();
-
-    /**
      * Returns the result of the operation if it has completed successfully.
      */
     abstract V value();
--- a/src/share/classes/sun/nio/ch/CompletedFuture.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/sun/nio/ch/CompletedFuture.java	Fri Jun 27 15:23:21 2008 +0100
@@ -102,11 +102,6 @@
     }
 
     @Override
-    boolean isCompleted() {
-        return true;
-    }
-
-    @Override
     Throwable exception() {
         return exc;
     }
--- a/src/share/classes/sun/nio/ch/Invoker.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/sun/nio/ch/Invoker.java	Fri Jun 27 15:23:21 2008 +0100
@@ -91,12 +91,11 @@
                              AbstractFuture<V,A> result)
     {
         if (handler != null && !result.isCancelled()) {
-            //handler.completed(result, result.attachment());
-
-            if (result.isCompleted()) {
+            Throwable exc = result.exception();
+            if (exc == null) {
                 handler.completed(result.value(), result.attachment());
             } else {
-                handler.failed(result.exception(), result.attachment());
+                handler.failed(exc, result.attachment());
             }
 
             // clear interrupt
--- a/src/share/classes/sun/nio/ch/PendingFuture.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/sun/nio/ch/PendingFuture.java	Fri Jun 27 15:23:21 2008 +0100
@@ -154,11 +154,6 @@
     }
 
     @Override
-    boolean isCompleted() {
-        return (haveResult && exc == null);
-    }
-
-    @Override
     Throwable exception() {
         return (exc != CANCELLED) ? exc : null;
     }
--- a/src/share/classes/sun/nio/ch/ThreadPool.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/share/classes/sun/nio/ch/ThreadPool.java	Fri Jun 27 15:23:21 2008 +0100
@@ -40,7 +40,6 @@
 
     private static final String INITIAL_SIZE = "initialSize";
     private static final String THREAD_FACTORY = "threadFactory";
-    private static final String MAX_POOL_SIZE = "maximumPoolSize";
 
     private static final ThreadFactory defaultThreadFactory = new ThreadFactory() {
          @Override
@@ -55,24 +54,20 @@
 
     private final ThreadFactory threadFactory;
     private final int initialSize;
-    private final int maximumPoolSize;
 
     // created lazily to avoid creating Exeuctor for default group when not needed.
     private volatile ExecutorService executor;
 
     private ThreadPool(ThreadFactory threadFactory,
-                       int initialSize,
-                       int maximumPoolSize)
+                       int initialSize)
     {
         this.threadFactory = threadFactory;
         this.initialSize = initialSize;
-        this.maximumPoolSize = maximumPoolSize;
     }
 
     private ThreadPool(ExecutorService executor, int initialSize) {
         this.threadFactory = null;
         this.initialSize = initialSize;
-        this.maximumPoolSize = -1;
         this.executor = executor;
     }
 
@@ -88,22 +83,15 @@
         return defaultThreadPool;
     }
 
-    // create thread pool based on default parameters
+    // create thread pool for default group (configured by system properties)
     static ThreadPool create() {
-        int initialSize = getInitialSizeFromProperty();
+        int initialSize = getDefaultThreadPoolInitialSize();
         if (initialSize < 0)
             initialSize = Runtime.getRuntime().availableProcessors();
-
-        int maximumPoolSize = getMaximumPoolSizeFromProperty();
-        if (maximumPoolSize < 0)
-            maximumPoolSize = computeMaximumPoolSizeFromInitialSize(initialSize);
-
-        ThreadFactory threadFactory = getThreadFactoryFromProperty();
-        if (threadFactory == null) {
+        ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory();
+        if (threadFactory == null)
             threadFactory = defaultThreadFactory;
-        }
-
-        return new ThreadPool(threadFactory, initialSize, maximumPoolSize);
+        return new ThreadPool(threadFactory, initialSize);
     }
 
     // create using user-supplied ExecutorService
@@ -112,7 +100,11 @@
             throw new NullPointerException("'executor' is null");
         int initialSize = 0;
         if (executor instanceof ThreadPoolExecutor) {
-            initialSize = ((ThreadPoolExecutor)executor).getMaximumPoolSize() / 2;
+            // TBD: translation of maximum pool size to number of threads that
+            // may wait on I/O events required further work.
+            int half = ((ThreadPoolExecutor)executor).getMaximumPoolSize() / 2;
+            int nProcs = Runtime.getRuntime().availableProcessors();
+            initialSize = (half > nProcs) ? nProcs : half;
         }
         return new ThreadPool(executor, initialSize);
     }
@@ -121,8 +113,7 @@
     static ThreadPool create(ThreadFactory factory, int initialSize) {
         if (factory == null)
             throw new NullPointerException("'factory' is null");
-        int maximumPoolSize = computeMaximumPoolSizeFromInitialSize(initialSize);
-        return new ThreadPool(factory, initialSize, maximumPoolSize);
+        return new ThreadPool(factory, initialSize);
     }
 
     int initialSize() {
@@ -137,54 +128,29 @@
         if (executor == null) {
             synchronized (this) {
                 if (executor == null) {
-                    assert maximumPoolSize > 0;
-                    assert threadFactory != null;
-                    executor = Executors
-                        .newFixedThreadPool(maximumPoolSize, threadFactory);
+                    executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+                                                      Long.MAX_VALUE, TimeUnit.MILLISECONDS,
+                                                      new SynchronousQueue<Runnable>(),
+                                                      threadFactory);
                 }
             }
         }
         return executor;
     }
 
-    private static int computeMaximumPoolSizeFromInitialSize(int initialSize) {
-        if (initialSize > 0)
-            return 2*initialSize;
-        int max = Runtime.getRuntime().availableProcessors();
-        return (max >= 2) ? max : 2;
-    }
-
-    private static int getInitialSizeFromProperty() {
+    private static int getDefaultThreadPoolInitialSize() {
         String value = AccessController.doPrivileged(new
             GetPropertyAction(PROP_PREFIX + INITIAL_SIZE));
         if (value != null) {
             try {
-                int size = Integer.parseInt(value);
-                // zero is valid value
-                if (size >= 0)
-                    return size;
+                return Integer.parseInt(value);
             } catch (NumberFormatException x) {
             }
         }
         return -1;
     }
 
-    private static int getMaximumPoolSizeFromProperty() {
-        String value = AccessController.doPrivileged(new
-            GetPropertyAction(PROP_PREFIX + MAX_POOL_SIZE));
-        if (value != null) {
-            try {
-                int size = Integer.parseInt(value);
-                // zero is not valid value
-                if (size > 0)
-                    return size;
-            } catch (NumberFormatException x) {
-            }
-        }
-        return -1;
-    }
-
-    private static ThreadFactory getThreadFactoryFromProperty() {
+    private static ThreadFactory getDefaultThreadPoolThreadFactory() {
         String prop = AccessController.doPrivileged(new
             GetPropertyAction(PROP_PREFIX + THREAD_FACTORY));
         if (prop != null) {
--- a/src/windows/classes/sun/nio/fs/WindowsFileAttributeView.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsFileAttributeView.java	Fri Jun 27 15:23:21 2008 +0100
@@ -92,7 +92,7 @@
                 flags |= FILE_FLAG_OPEN_REPARSE_POINT;
 
             handle = CreateFile(file.getPathForWin32Calls(),
-                                GENERIC_WRITE,
+                                FILE_WRITE_ATTRIBUTES,
                                 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
                                 OPEN_EXISTING,
                                 flags);
@@ -238,6 +238,7 @@
         // copy file times to target - must be done after updating FAT attributes
         // as otherwise the last modified time may be wrong.
         FileInfo info = getFileInfo();
+
         setFileTimes(
             (WindowsPath)(info.file()),
             info.followLinks(),
--- a/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java	Fri Jun 27 15:23:21 2008 +0100
@@ -154,7 +154,7 @@
     static WindowsFileAttributes get(WindowsPath path, boolean followLinks)
         throws WindowsException
     {
-        long handle = path.openForReadAccess(followLinks);
+        long handle = path.openForReadAttributeAccess(followLinks);
         try {
             return readAttributes(handle).finishRead(path);
         } finally {
--- a/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Fri Jun 27 15:23:21 2008 +0100
@@ -86,7 +86,7 @@
 
         long sourceHandle = 0L;
         try {
-            sourceHandle = source.openForReadAccess(followLinks);
+            sourceHandle = source.openForReadAttributeAccess(followLinks);
         } catch (WindowsException x) {
             x.rethrowAsIOException(source);
         }
@@ -103,7 +103,7 @@
             // open target (don't follow links)
             long targetHandle = 0L;
             try {
-                targetHandle = target.openForReadAccess(false);
+                targetHandle = target.openForReadAttributeAccess(false);
                 try {
                     targetAttrs = WindowsFileAttributes
                         .readAttributes(targetHandle)
@@ -276,7 +276,7 @@
 
         long sourceHandle = 0L;
         try {
-            sourceHandle = source.openForReadAccess(false);
+            sourceHandle = source.openForReadAttributeAccess(false);
         } catch (WindowsException x) {
             x.rethrowAsIOException(source);
         }
@@ -293,7 +293,7 @@
             // open target (don't follow links)
             long targetHandle = 0L;
             try {
-                targetHandle = target.openForReadAccess(false);
+                targetHandle = target.openForReadAttributeAccess(false);
                 try {
                     targetAttrs = WindowsFileAttributes
                         .readAttributes(targetHandle)
@@ -344,7 +344,7 @@
             }
         }
 
-        // first try MoveFileEx (no options). If target is on same voluem then
+        // first try MoveFileEx (no options). If target is on same volume then
         // all attributes (including security attributes) are preserved.
         try {
             MoveFileEx(sourcePath, targetPath, 0);
@@ -401,7 +401,7 @@
             throw x;
         }
 
-        // copy security attributes. If this fail it doesn't cause the move
+        // copy security attributes. If this fails it doesn't cause the move
         // to fail.
         try {
             copySecurityAttributes(source, target, false);
--- a/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java	Fri Jun 27 15:23:21 2008 +0100
@@ -51,7 +51,7 @@
     static String readLink(WindowsPath path) throws IOException {
         long handle = 0L;
         try {
-            handle = path.openForReadAccess(false); // don't follow links
+            handle = path.openForReadAttributeAccess(false); // don't follow links
         } catch (WindowsException x) {
             x.rethrowAsIOException(path);
         }
@@ -85,7 +85,7 @@
         // is a link to a non-NFTS file system.
         long h = 0;
         try {
-            h = input.openForReadAccess(true);
+            h = input.openForReadAttributeAccess(true);
         } catch (WindowsException x) {
             x.rethrowAsIOException(input);
         }
@@ -106,7 +106,7 @@
         int linkCount = 0;
         do {
             try {
-                h = target.openForReadAccess(false);
+                h = target.openForReadAttributeAccess(false);
             } catch (WindowsException x) {
                 x.rethrowAsIOException(target);
             }
@@ -162,7 +162,7 @@
         if (resolveLinks) {
             long h = 0;
             try {
-                h = input.openForReadAccess(true);
+                h = input.openForReadAttributeAccess(true);
             } catch (WindowsException x) {
                 x.rethrowAsIOException(input);
             }
@@ -362,7 +362,7 @@
 
             long h = 0L;
             try {
-                h = current.openForReadAccess(false);
+                h = current.openForReadAttributeAccess(false);
             } catch (WindowsException x) {
                 x.rethrowAsIOException(current);
             }
--- a/src/windows/classes/sun/nio/fs/WindowsPath.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsPath.java	Fri Jun 27 15:23:21 2008 +0100
@@ -555,15 +555,14 @@
     // -- file operations --
 
     // package-private
-    long openForReadAccess(boolean followLinks)
+    long openForReadAttributeAccess(boolean followLinks)
         throws WindowsException
     {
         int flags = FILE_FLAG_BACKUP_SEMANTICS;
         if (!followLinks && getFileSystem().supportsLinks())
             flags |= FILE_FLAG_OPEN_REPARSE_POINT;
-
         return CreateFile(getPathForWin32Calls(),
-                          GENERIC_READ,
+                          FILE_READ_ATTRIBUTES,
                           (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
                           OPEN_EXISTING,
                           flags);
@@ -916,7 +915,7 @@
         // open both files and see if they are the same
         long h1 = 0L;
         try {
-            h1 = this.openForReadAccess(true);
+            h1 = this.openForReadAttributeAccess(true);
         } catch (WindowsException x) {
             x.rethrowAsIOException(this);
         }
@@ -929,7 +928,7 @@
             }
             long h2 = 0L;
             try {
-                h2 = other.openForReadAccess(true);
+                h2 = other.openForReadAttributeAccess(true);
             } catch (WindowsException x) {
                 x.rethrowAsIOException(other);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java	Fri Jun 27 15:23:21 2008 +0100
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousChannelGroup
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+
+public class Unbounded {
+    // number of concurrent completion handlers
+    static final int CONCURRENCY_COUNT = 512;
+
+    public static void main(String[] args) throws Exception {
+        // all accepted connections are added to a queue
+        final ArrayBlockingQueue<AsynchronousSocketChannel> queue =
+            new ArrayBlockingQueue<AsynchronousSocketChannel>(CONCURRENCY_COUNT);
+
+        // create listener to accept connections
+        final AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open()
+                .bind(new InetSocketAddress(0));
+        listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+            public void completed(AsynchronousSocketChannel ch, Void att) {
+                queue.add(ch);
+                listener.accept(null, this);
+            }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        System.out.println("Listener created.");
+
+        // establish lots of connections
+        int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+        SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
+        AsynchronousSocketChannel[] channels =
+            new AsynchronousSocketChannel[CONCURRENCY_COUNT];
+        for (int i=0; i<CONCURRENCY_COUNT; i++) {
+            int attempts = 0;
+            for (;;) {
+                try {
+                    channels[i] = AsynchronousSocketChannel.open();
+                    channels[i].connect(sa).get();
+                    break;
+                } catch (IOException x) {
+                    // probably resource issue so back off and retry
+                    if (++attempts >= 3)
+                        throw x;
+                    Thread.sleep(50);
+                }
+            }
+        }
+        System.out.println("All connection established.");
+
+        // the barrier where all threads (plus the main thread) wait
+        final CyclicBarrier barrier = new CyclicBarrier(CONCURRENCY_COUNT+1);
+
+        // initiate a read operation on each channel.
+        for (int i=0; i<CONCURRENCY_COUNT; i++) {
+            ByteBuffer buf = ByteBuffer.allocateDirect(100);
+            channels[i].read( buf, channels[i],
+                new CompletionHandler<Integer,AsynchronousSocketChannel>() {
+                    public void completed(Integer bytesRead, AsynchronousSocketChannel ch) {
+                        try {
+                            ch.close();
+                            barrier.await();
+                        } catch (Exception x) {
+                            throw new AssertionError(x);
+                        }
+                    }
+                    public void failed(Throwable exc, AsynchronousSocketChannel ch) {
+                    }
+                    public void cancelled(AsynchronousSocketChannel ch) {
+                    }
+                });
+        }
+        System.out.println("All read operations outstanding.");
+
+        // write data to each of the accepted connections
+        int remaining = CONCURRENCY_COUNT;
+        while (remaining > 0) {
+            AsynchronousSocketChannel ch = queue.take();
+            ch.write(ByteBuffer.wrap("welcome".getBytes())).get();
+            ch.close();
+            remaining--;
+        }
+
+        // wait for all threads to reach the barrier
+        System.out.println("Waiting for all therads to reach barrier");
+        barrier.await();
+        listener.close();
+    }
+}
--- a/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Fri Jun 27 09:46:07 2008 +0100
+++ b/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Fri Jun 27 15:23:21 2008 +0100
@@ -179,6 +179,22 @@
             if (!(x.getCause() instanceof ClosedChannelException))
                 throw new RuntimeException("Cause of ClosedChannelException expected");
         }
+        final AtomicReference<Throwable> connectException =
+            new AtomicReference<Throwable>();
+        ch.connect(server.address(), null, new CompletionHandler<Void,Void>() {
+            public void completed(Void result, Void att) {
+            }
+            public void failed(Throwable exc, Void att) {
+                connectException.set(exc);
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        while (connectException.get() == null) {
+            Thread.sleep(100);
+        }
+        if (!(connectException.get() instanceof ClosedChannelException))
+            throw new RuntimeException("ClosedChannelException expected");
 
         System.out.println("-- connect to non-existent host --");