Hello,
I discovered a bug in xSocket 2.8.15 which prevents JVM from releasing
underlying file descriptors.
The bug is triggered by calling one of the following two methods:
org.xsocket.connection.AbstractNonBlockingStream.transferFrom(FileChannel)
org.xsocket.connection.NonBlockingConnectionPool.NonBlockingConnectionProxy.transferFrom(FileChannel)
They depend on the flawed implementation of MappedByteBuffer which is
known to keep file handles despite closing the corresponding FileChannel.
As a result, deleting or moving such a file on Windows OS is not
possible, because the MappedByteBuffer remains valid until it's garbage
collected. Linux is not affected, because it allows to modify opened
files. This bug is reproducible on JDK 1.7 and 1.8, I haven't tested it
on the older ones.
I've prepared a fix that seems to work, below is the diff output. I hope
it will be released in the upcoming version.
Index: src/org/xsocket/connection/AbstractNonBlockingStream.java
===================================================================
@@ -31,13 +31,11 @@
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
-import java.nio.channels.FileChannel.MapMode;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -1237,7 +1235,6 @@
final long size = fileChannel.size();
long remaining = size;
- long offset = 0;
long length = 0;
do {
@@ -1247,10 +1244,12 @@
length = remaining;
}
- MappedByteBuffer buffer =
fileChannel.map(MapMode.READ_ONLY, offset, length);
+ ByteBuffer buffer = ByteBuffer.allocate((int) length);
+ fileChannel.read(buffer);
+ buffer.flip();
long written = write(buffer);
+ buffer.clear();
- offset += written;
remaining -= written;
} while (remaining > 0);
Index: src/org/xsocket/connection/NonBlockingConnectionPool.java
===================================================================
@@ -30,12 +30,10 @@
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
-import java.nio.channels.FileChannel.MapMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
@@ -2961,7 +2959,6 @@
final long size = fileChannel.size();
long remaining = size;
- long offset = 0;
long length = 0;
do {
@@ -2971,10 +2968,11 @@
length = remaining;
}
- MappedByteBuffer buffer =
fileChannel.map(MapMode.READ_ONLY, offset, length);
+ ByteBuffer buffer =
ByteBuffer.allocate((int) length);
+ fileChannel.read(buffer);
long written = write(buffer);
+ buffer.clear();
- offset += written;
remaining -= written;
} while (remaining > 0);
--
Regards,
Grzegorz Byczyński
|