Skip to content

Commit eb3c4bd

Browse files
franz1981normanmaurer
authored andcommitted
ChunkedNioFile can use absolute FileChannel::read to read chunks (#9592)
Motivation: Users can reuse the same FileChannel for different ChunkedNioFile instances without being worried that FileChannel::position will be changed concurrently by them. In addition, FileChannel::read with absolute position allows to use on *nix pread that is more efficient then fread. Modifications: Always use absolute FileChannel::read ops Result: Faster and more flexible uses of FileChannel for ChunkedNioFile
1 parent 76592db commit eb3c4bd

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

handler/src/main/java/io/netty/handler/stream/ChunkedNioFile.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.io.File;
2424
import java.io.IOException;
2525
import java.io.RandomAccessFile;
26+
import java.nio.channels.ClosedChannelException;
2627
import java.nio.channels.FileChannel;
2728

2829
/**
@@ -101,9 +102,8 @@ public ChunkedNioFile(FileChannel in, long offset, long length, int chunkSize)
101102
"chunkSize: " + chunkSize +
102103
" (expected: a positive integer)");
103104
}
104-
105-
if (offset != 0) {
106-
in.position(offset);
105+
if (!in.isOpen()) {
106+
throw new ClosedChannelException();
107107
}
108108
this.in = in;
109109
this.chunkSize = chunkSize;
@@ -161,7 +161,7 @@ public ByteBuf readChunk(ByteBufAllocator allocator) throws Exception {
161161
try {
162162
int readBytes = 0;
163163
for (;;) {
164-
int localReadBytes = buffer.writeBytes(in, chunkSize - readBytes);
164+
int localReadBytes = buffer.writeBytes(in, offset + readBytes, chunkSize - readBytes);
165165
if (localReadBytes < 0) {
166166
break;
167167
}

handler/src/test/java/io/netty/handler/stream/ChunkedWriteHandlerTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@
2626
import io.netty.channel.embedded.EmbeddedChannel;
2727
import io.netty.util.CharsetUtil;
2828
import io.netty.util.ReferenceCountUtil;
29+
import org.junit.Assert;
2930
import org.junit.Test;
3031

3132
import java.io.ByteArrayInputStream;
3233
import java.io.File;
3334
import java.io.FileOutputStream;
3435
import java.io.IOException;
36+
import java.io.RandomAccessFile;
3537
import java.nio.channels.Channels;
38+
import java.nio.channels.ClosedChannelException;
39+
import java.nio.channels.FileChannel;
3640
import java.util.concurrent.CountDownLatch;
3741
import java.util.concurrent.atomic.AtomicBoolean;
3842
import java.util.concurrent.atomic.AtomicInteger;
@@ -102,6 +106,41 @@ public void testChunkedNioFile() throws IOException {
102106
check(new ChunkedNioFile(TMP), new ChunkedNioFile(TMP), new ChunkedNioFile(TMP));
103107
}
104108

109+
@Test
110+
public void testChunkedNioFileLeftPositionUnchanged() throws IOException {
111+
FileChannel in = null;
112+
final long expectedPosition = 10;
113+
try {
114+
in = new RandomAccessFile(TMP, "r").getChannel();
115+
in.position(expectedPosition);
116+
check(new ChunkedNioFile(in) {
117+
@Override
118+
public void close() throws Exception {
119+
//no op
120+
}
121+
});
122+
Assert.assertTrue(in.isOpen());
123+
Assert.assertEquals(expectedPosition, in.position());
124+
} finally {
125+
if (in != null) {
126+
in.close();
127+
}
128+
}
129+
}
130+
131+
@Test(expected = ClosedChannelException.class)
132+
public void testChunkedNioFileFailOnClosedFileChannel() throws IOException {
133+
final FileChannel in = new RandomAccessFile(TMP, "r").getChannel();
134+
in.close();
135+
check(new ChunkedNioFile(in) {
136+
@Override
137+
public void close() throws Exception {
138+
//no op
139+
}
140+
});
141+
Assert.fail();
142+
}
143+
105144
@Test
106145
public void testUnchunkedData() throws IOException {
107146
check(Unpooled.wrappedBuffer(BYTES));

0 commit comments

Comments
 (0)