6431344: (fc) FileChannel.transferTo() doesn't work if address space runs out
authoralanb
Mon, 23 Aug 2010 17:35:18 +0100
changeset 6319 47d9b9e70f99
parent 6318 b279b6772e21
child 6320 6b48de58428e
6431344: (fc) FileChannel.transferTo() doesn't work if address space runs out Reviewed-by: forax, chegar
jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java
--- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java	Mon Aug 23 17:11:07 2010 +0100
+++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java	Mon Aug 23 17:35:18 2010 +0100
@@ -429,24 +429,45 @@
         }
     }
 
-    private long transferToTrustedChannel(long position, int icount,
+    // Maximum size to map when using a mapped buffer
+    private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L;
+
+    private long transferToTrustedChannel(long position, long count,
                                           WritableByteChannel target)
         throws IOException
     {
-        if (  !((target instanceof FileChannelImpl)
-                || (target instanceof SelChImpl)))
+        boolean isSelChImpl = (target instanceof SelChImpl);
+        if (!((target instanceof FileChannelImpl) || isSelChImpl))
             return IOStatus.UNSUPPORTED;
 
         // Trusted target: Use a mapped buffer
-        MappedByteBuffer dbb = null;
-        try {
-            dbb = map(MapMode.READ_ONLY, position, icount);
-            // ## Bug: Closing this channel will not terminate the write
-            return target.write(dbb);
-        } finally {
-            if (dbb != null)
-                unmap(dbb);
+        long remaining = count;
+        while (remaining > 0L) {
+            long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
+            try {
+                MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size);
+                try {
+                    // ## Bug: Closing this channel will not terminate the write
+                    int n = target.write(dbb);
+                    assert n >= 0;
+                    remaining -= n;
+                    if (isSelChImpl) {
+                        // one attempt to write to selectable channel
+                        break;
+                    }
+                    assert n > 0;
+                    position += n;
+                } finally {
+                    unmap(dbb);
+                }
+            } catch (IOException ioe) {
+                // Only throw exception if no bytes have been written
+                if (remaining == count)
+                    throw ioe;
+                break;
+            }
         }
+        return count - remaining;
     }
 
     private long transferToArbitraryChannel(long position, int icount,
@@ -524,20 +545,34 @@
                                          long position, long count)
         throws IOException
     {
-        // Note we could loop here to accumulate more at once
         synchronized (src.positionLock) {
-            long p = src.position();
-            int icount = (int)Math.min(Math.min(count, Integer.MAX_VALUE),
-                                       src.size() - p);
-            // ## Bug: Closing this channel will not terminate the write
-            MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, icount);
-            try {
-                long n = write(bb, position);
-                src.position(p + n);
-                return n;
-            } finally {
-                unmap(bb);
+            long pos = src.position();
+            long max = Math.min(count, src.size() - pos);
+
+            long remaining = max;
+            long p = pos;
+            while (remaining > 0L) {
+                long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
+                // ## Bug: Closing this channel will not terminate the write
+                MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size);
+                try {
+                    long n = write(bb, position);
+                    assert n > 0;
+                    p += n;
+                    position += n;
+                    remaining -= n;
+                } catch (IOException ioe) {
+                    // Only throw exception if no bytes have been written
+                    if (remaining == max)
+                        throw ioe;
+                    break;
+                } finally {
+                    unmap(bb);
+                }
             }
+            long nwritten = max - remaining;
+            src.position(pos + nwritten);
+            return nwritten;
         }
     }