* Changed the type of WriteCompletionEvent.amount from int to long

* Added back FileRegion since mapped buffer does not outperform transferTo()
* Refactored SocketSendBufferPool to support FileRegion
This commit is contained in:
Trustin Lee 2010-02-23 07:18:58 +00:00
parent 1989bd037b
commit aa4b8a2a6c
11 changed files with 310 additions and 61 deletions

View File

@ -313,6 +313,20 @@ public class Channels {
return; return;
} }
channel.getPipeline().sendUpstream(
new DefaultWriteCompletionEvent(channel, (long) amount));
}
/**
* Sends a {@code "writeComplete"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
* the specified {@link Channel}.
*/
public static void fireWriteComplete(Channel channel, long amount) {
if (amount == 0) {
return;
}
channel.getPipeline().sendUpstream( channel.getPipeline().sendUpstream(
new DefaultWriteCompletionEvent(channel, amount)); new DefaultWriteCompletionEvent(channel, amount));
} }
@ -324,9 +338,18 @@ public class Channels {
* {@link ChannelHandlerContext}. * {@link ChannelHandlerContext}.
*/ */
public static void fireWriteComplete(ChannelHandlerContext ctx, int amount) { public static void fireWriteComplete(ChannelHandlerContext ctx, int amount) {
ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount)); ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), (long) amount));
} }
/**
* Sends a {@code "writeComplete"} event to the
* {@link ChannelUpstreamHandler} which is placed in the closest upstream
* from the handler associated with the specified
* {@link ChannelHandlerContext}.
*/
public static void fireWriteComplete(ChannelHandlerContext ctx, long amount) {
ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount));
}
/** /**
* Sends a {@code "channelInterestChanged"} event to the first * Sends a {@code "channelInterestChanged"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of

View File

@ -0,0 +1,43 @@
package org.jboss.netty.channel;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
public class DefaultFileRegion implements FileRegion {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultFileRegion.class);
private final FileChannel file;
private final long position;
private final long count;
public DefaultFileRegion(FileChannel file, long position, long count) {
this.file = file;
this.position = position;
this.count = count;
}
public long getPosition() {
return position;
}
public long getCount() {
return count;
}
public long transferTo(WritableByteChannel target) throws IOException {
return file.transferTo(position, count, target);
}
public void releaseExternalResources() {
try {
file.close();
} catch (IOException e) {
logger.warn("Failed to close a file.", e);
}
}
}

View File

@ -28,12 +28,20 @@ import static org.jboss.netty.channel.Channels.*;
public class DefaultWriteCompletionEvent implements WriteCompletionEvent { public class DefaultWriteCompletionEvent implements WriteCompletionEvent {
private final Channel channel; private final Channel channel;
private final int writtenAmount; private final long writtenAmount;
/**
* @deprecated Use {@link #DefaultWriteCompletionEvent(Channel, long)} instead.
*/
@Deprecated
public DefaultWriteCompletionEvent(Channel channel, int writtenAmount) {
this(channel, (long) writtenAmount);
}
/** /**
* Creates a new instance. * Creates a new instance.
*/ */
public DefaultWriteCompletionEvent(Channel channel, int writtenAmount) { public DefaultWriteCompletionEvent(Channel channel, long writtenAmount) {
if (channel == null) { if (channel == null) {
throw new NullPointerException("channel"); throw new NullPointerException("channel");
} }
@ -54,7 +62,7 @@ public class DefaultWriteCompletionEvent implements WriteCompletionEvent {
return succeededFuture(getChannel()); return succeededFuture(getChannel());
} }
public int getWrittenAmount() { public long getWrittenAmount() {
return writtenAmount; return writtenAmount;
} }

View File

@ -0,0 +1,47 @@
/*
* Copyright 2010 Red Hat, Inc.
*
* Red Hat licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.jboss.netty.channel;
import java.io.IOException;
import java.nio.channels.WritableByteChannel;
import org.jboss.netty.util.ExternalResourceReleasable;
/**
* A region of a file that is sent via a {@link Channel} which supports
* zero-copy file transfer.
*
* @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
* @author <a href="http://gleamynode.net/">Trustin Lee</a>
* @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $
*/
public interface FileRegion extends ExternalResourceReleasable {
/**
* Returns the offset in the file where the transfer began.
*/
long getPosition();
/**
* Returns the number of bytes to transfer.
*/
long getCount();
/**
* Transfers the content of this file region to the specified channel.
*/
long transferTo(WritableByteChannel target) throws IOException;
}

View File

@ -34,5 +34,5 @@ public interface WriteCompletionEvent extends ChannelEvent {
* @return the number of written bytes or messages, depending on the * @return the number of written bytes or messages, depending on the
* type of the transport * type of the transport
*/ */
int getWrittenAmount(); long getWrittenAmount();
} }

View File

@ -261,7 +261,7 @@ class NioDatagramChannel extends AbstractChannel
boolean success = super.offer(e); boolean success = super.offer(e);
assert success; assert success;
int messageSize = ((ChannelBuffer) e.getMessage()).readableBytes(); int messageSize = getMessageSize(e);
int newWriteBufferSize = writeBufferSize.addAndGet(messageSize); int newWriteBufferSize = writeBufferSize.addAndGet(messageSize);
int highWaterMark = getConfig().getWriteBufferHighWaterMark(); int highWaterMark = getConfig().getWriteBufferHighWaterMark();
@ -286,7 +286,7 @@ class NioDatagramChannel extends AbstractChannel
public MessageEvent poll() { public MessageEvent poll() {
MessageEvent e = super.poll(); MessageEvent e = super.poll();
if (e != null) { if (e != null) {
int messageSize = ((ChannelBuffer) e.getMessage()).readableBytes(); int messageSize = getMessageSize(e);
int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize); int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize);
int lowWaterMark = getConfig().getWriteBufferLowWaterMark(); int lowWaterMark = getConfig().getWriteBufferLowWaterMark();
@ -303,6 +303,14 @@ class NioDatagramChannel extends AbstractChannel
} }
return e; return e;
} }
private int getMessageSize(MessageEvent e) {
Object m = e.getMessage();
if (m instanceof ChannelBuffer) {
return ((ChannelBuffer) m).readableBytes();
}
return 0;
}
} }
/** /**

View File

@ -36,7 +36,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.ChannelBufferFactory;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelException;
@ -500,7 +499,7 @@ class NioDatagramWorker implements Runnable {
boolean addOpWrite = false; boolean addOpWrite = false;
boolean removeOpWrite = false; boolean removeOpWrite = false;
int writtenBytes = 0; long writtenBytes = 0;
final SocketSendBufferPool sendBufferPool = this.sendBufferPool; final SocketSendBufferPool sendBufferPool = this.sendBufferPool;
final DatagramChannel ch = channel.getDatagramChannel(); final DatagramChannel ch = channel.getDatagramChannel();
@ -514,7 +513,6 @@ class NioDatagramWorker implements Runnable {
for (;;) { for (;;) {
MessageEvent evt = channel.currentWriteEvent; MessageEvent evt = channel.currentWriteEvent;
SendBuffer buf; SendBuffer buf;
ByteBuffer bb;
if (evt == null) { if (evt == null) {
if ((channel.currentWriteEvent = evt = writeBuffer.poll()) == null) { if ((channel.currentWriteEvent = evt = writeBuffer.poll()) == null) {
removeOpWrite = true; removeOpWrite = true;
@ -522,20 +520,17 @@ class NioDatagramWorker implements Runnable {
break; break;
} }
ChannelBuffer origBuf = (ChannelBuffer) evt.getMessage(); channel.currentWriteBuffer = buf = sendBufferPool.acquire(evt.getMessage());
channel.currentWriteBuffer = buf = sendBufferPool.acquire(origBuf);
bb = buf.buffer;
} else { } else {
buf = channel.currentWriteBuffer; buf = channel.currentWriteBuffer;
bb = buf.buffer;
} }
try { try {
int localWrittenBytes = 0; long localWrittenBytes = 0;
SocketAddress raddr = evt.getRemoteAddress(); SocketAddress raddr = evt.getRemoteAddress();
if (raddr == null) { if (raddr == null) {
for (int i = writeSpinCount; i > 0; i --) { for (int i = writeSpinCount; i > 0; i --) {
localWrittenBytes = ch.write(bb); localWrittenBytes = buf.transferTo(ch);
if (localWrittenBytes != 0) { if (localWrittenBytes != 0) {
writtenBytes += localWrittenBytes; writtenBytes += localWrittenBytes;
break; break;
@ -543,7 +538,7 @@ class NioDatagramWorker implements Runnable {
} }
} else { } else {
for (int i = writeSpinCount; i > 0; i --) { for (int i = writeSpinCount; i > 0; i --) {
localWrittenBytes = ch.send(bb, raddr); localWrittenBytes = buf.transferTo(ch, raddr);
if (localWrittenBytes != 0) { if (localWrittenBytes != 0) {
writtenBytes += localWrittenBytes; writtenBytes += localWrittenBytes;
break; break;
@ -559,7 +554,6 @@ class NioDatagramWorker implements Runnable {
channel.currentWriteBuffer = null; channel.currentWriteBuffer = null;
evt = null; evt = null;
buf = null; buf = null;
bb = null;
future.setSuccess(); future.setSuccess();
} else { } else {
// Not written at all - perhaps the kernel buffer is full. // Not written at all - perhaps the kernel buffer is full.
@ -576,7 +570,6 @@ class NioDatagramWorker implements Runnable {
channel.currentWriteBuffer = null; channel.currentWriteBuffer = null;
buf = null; buf = null;
evt = null; evt = null;
bb = null;
future.setFailure(t); future.setFailure(t);
fireExceptionCaught(channel, t); fireExceptionCaught(channel, t);
} }

View File

@ -209,7 +209,7 @@ class NioSocketChannel extends AbstractChannel
boolean success = super.offer(e); boolean success = super.offer(e);
assert success; assert success;
int messageSize = ((ChannelBuffer) e.getMessage()).readableBytes(); int messageSize = getMessageSize(e);
int newWriteBufferSize = writeBufferSize.addAndGet(messageSize); int newWriteBufferSize = writeBufferSize.addAndGet(messageSize);
int highWaterMark = getConfig().getWriteBufferHighWaterMark(); int highWaterMark = getConfig().getWriteBufferHighWaterMark();
@ -230,7 +230,7 @@ class NioSocketChannel extends AbstractChannel
public MessageEvent poll() { public MessageEvent poll() {
MessageEvent e = super.poll(); MessageEvent e = super.poll();
if (e != null) { if (e != null) {
int messageSize = ((ChannelBuffer) e.getMessage()).readableBytes(); int messageSize = getMessageSize(e);
int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize); int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize);
int lowWaterMark = getConfig().getWriteBufferLowWaterMark(); int lowWaterMark = getConfig().getWriteBufferLowWaterMark();
@ -247,6 +247,14 @@ class NioSocketChannel extends AbstractChannel
} }
return e; return e;
} }
private int getMessageSize(MessageEvent e) {
Object m = e.getMessage();
if (m instanceof ChannelBuffer) {
return ((ChannelBuffer) m).readableBytes();
}
return 0;
}
} }
private final class WriteTask implements Runnable { private final class WriteTask implements Runnable {

View File

@ -439,7 +439,7 @@ class NioWorker implements Runnable {
boolean addOpWrite = false; boolean addOpWrite = false;
boolean removeOpWrite = false; boolean removeOpWrite = false;
int writtenBytes = 0; long writtenBytes = 0;
final SocketSendBufferPool sendBufferPool = this.sendBufferPool; final SocketSendBufferPool sendBufferPool = this.sendBufferPool;
final SocketChannel ch = channel.socket; final SocketChannel ch = channel.socket;
@ -450,7 +450,6 @@ class NioWorker implements Runnable {
for (;;) { for (;;) {
MessageEvent evt = channel.currentWriteEvent; MessageEvent evt = channel.currentWriteEvent;
SendBuffer buf; SendBuffer buf;
ByteBuffer bb;
if (evt == null) { if (evt == null) {
if ((channel.currentWriteEvent = evt = writeBuffer.poll()) == null) { if ((channel.currentWriteEvent = evt = writeBuffer.poll()) == null) {
removeOpWrite = true; removeOpWrite = true;
@ -458,44 +457,41 @@ class NioWorker implements Runnable {
break; break;
} }
ChannelBuffer origBuf = (ChannelBuffer) evt.getMessage(); channel.currentWriteBuffer = buf = sendBufferPool.acquire(evt.getMessage());
channel.currentWriteBuffer = buf = sendBufferPool.acquire(origBuf);
bb = buf.buffer;
} else { } else {
buf = channel.currentWriteBuffer; buf = channel.currentWriteBuffer;
bb = buf.buffer;
} }
ChannelFuture future = evt.getFuture(); ChannelFuture future = evt.getFuture();
try { try {
int oldWrittenBytes = writtenBytes; long localWrittenBytes = 0;
for (int i = writeSpinCount; i > 0; i --) { for (int i = writeSpinCount; i > 0; i --) {
int localWrittenBytes = ch.write(bb); localWrittenBytes = buf.transferTo(ch);
if (localWrittenBytes != 0) { if (localWrittenBytes != 0) {
writtenBytes += localWrittenBytes; writtenBytes += localWrittenBytes;
break; break;
} }
} }
if (!bb.hasRemaining()) { if (buf.finished()) {
// Successful write - proceed to the next message. // Successful write - proceed to the next message.
buf.release(); buf.release();
channel.currentWriteEvent = null; channel.currentWriteEvent = null;
channel.currentWriteBuffer = null; channel.currentWriteBuffer = null;
evt = null; evt = null;
buf = null; buf = null;
bb = null;
future.setSuccess(); future.setSuccess();
} else { } else {
// Not written fully - perhaps the kernel buffer is full. // Not written fully - perhaps the kernel buffer is full.
addOpWrite = true; addOpWrite = true;
channel.writeSuspended = true; channel.writeSuspended = true;
// Notify progress listeners if necessary. if (localWrittenBytes > 0) {
future.setProgress( // Notify progress listeners if necessary.
writtenBytes - oldWrittenBytes, future.setProgress(
bb.position() - buf.initialPos, localWrittenBytes,
bb.limit() - buf.initialPos); buf.writtenBytes(), buf.totalBytes());
}
break; break;
} }
} catch (AsynchronousCloseException e) { } catch (AsynchronousCloseException e) {
@ -506,7 +502,6 @@ class NioWorker implements Runnable {
channel.currentWriteBuffer = null; channel.currentWriteBuffer = null;
buf = null; buf = null;
evt = null; evt = null;
bb = null;
future.setFailure(t); future.setFailure(t);
fireExceptionCaught(channel, t); fireExceptionCaught(channel, t);
if (t instanceof IOException) { if (t instanceof IOException) {

View File

@ -15,10 +15,15 @@
*/ */
package org.jboss.netty.channel.socket.nio; package org.jboss.netty.channel.socket.nio;
import java.io.IOException;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.net.SocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.WritableByteChannel;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.FileRegion;
/** /**
* @author <a href="http://www.jboss.org/netty/">The Netty Project</a> * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
@ -42,27 +47,34 @@ final class SocketSendBufferPool {
super(); super();
} }
final SendBuffer acquire(ChannelBuffer src) { final SendBuffer acquire(Object message) {
if (src.isDirect()) { if (message instanceof ChannelBuffer) {
return new SendBuffer(null, src.toByteBuffer()); return acquire((ChannelBuffer) message);
} } else if (message instanceof FileRegion) {
if (src.readableBytes() > DEFAULT_PREALLOCATION_SIZE) { return acquire((FileRegion) message);
return new SendBuffer(null, src.toByteBuffer());
} }
SendBuffer dst = acquire(src.readableBytes()); throw new IllegalArgumentException(
ByteBuffer dstbuf = dst.buffer; "unsupported message type: " + message.getClass());
dstbuf.mark();
src.getBytes(src.readerIndex(), dstbuf);
dstbuf.reset();
return dst;
} }
private final SendBuffer acquire(int size) { private final SendBuffer acquire(FileRegion src) {
assert size <= DEFAULT_PREALLOCATION_SIZE; return new FileSendBuffer(src);
}
private final SendBuffer acquire(ChannelBuffer src) {
if (src.isDirect()) {
return new UnpooledSendBuffer(src.toByteBuffer());
}
if (src.readableBytes() > DEFAULT_PREALLOCATION_SIZE) {
return new UnpooledSendBuffer(src.toByteBuffer());
}
final int size = src.readableBytes();
Preallocation current = this.current; Preallocation current = this.current;
ByteBuffer buffer = current.buffer; ByteBuffer buffer = current.buffer;
int remaining = buffer.remaining(); int remaining = buffer.remaining();
PooledSendBuffer dst;
if (size < remaining) { if (size < remaining) {
int nextPos = buffer.position() + size; int nextPos = buffer.position() + size;
@ -70,7 +82,7 @@ final class SocketSendBufferPool {
buffer.position(align(nextPos)); buffer.position(align(nextPos));
slice.limit(nextPos); slice.limit(nextPos);
current.refCnt ++; current.refCnt ++;
return new SendBuffer(current, slice); dst = new PooledSendBuffer(current, slice);
} else if (size > remaining) { } else if (size > remaining) {
this.current = current = getPreallocation(); this.current = current = getPreallocation();
buffer = current.buffer; buffer = current.buffer;
@ -78,12 +90,18 @@ final class SocketSendBufferPool {
buffer.position(align(size)); buffer.position(align(size));
slice.limit(size); slice.limit(size);
current.refCnt ++; current.refCnt ++;
return new SendBuffer(current, slice); dst = new PooledSendBuffer(current, slice);
} else { // size == remaining } else { // size == remaining
current.refCnt ++; current.refCnt ++;
this.current = getPreallocation0(); this.current = getPreallocation0();
return new SendBuffer(current, current.buffer); dst = new PooledSendBuffer(current, current.buffer);
} }
ByteBuffer dstbuf = dst.buffer;
dstbuf.mark();
src.getBytes(src.readerIndex(), dstbuf);
dstbuf.reset();
return dst;
} }
private final Preallocation getPreallocation() { private final Preallocation getPreallocation() {
@ -142,20 +160,85 @@ final class SocketSendBufferPool {
} }
} }
final class SendBuffer { interface SendBuffer {
boolean finished();
long writtenBytes();
long totalBytes();
long transferTo(WritableByteChannel ch) throws IOException;
long transferTo(DatagramChannel ch, SocketAddress raddr) throws IOException;
void release();
}
class UnpooledSendBuffer implements SendBuffer {
final ByteBuffer buffer;
final int initialPos;
UnpooledSendBuffer(ByteBuffer buffer) {
this.buffer = buffer;
initialPos = buffer.position();
}
public final boolean finished() {
return !buffer.hasRemaining();
}
public final long writtenBytes() {
return buffer.position() - initialPos;
}
public final long totalBytes() {
return buffer.limit() - initialPos;
}
public final long transferTo(WritableByteChannel ch) throws IOException {
return ch.write(buffer);
}
public final long transferTo(DatagramChannel ch, SocketAddress raddr) throws IOException {
return ch.send(buffer, raddr);
}
public void release() {
// Unpooled.
}
}
final class PooledSendBuffer implements SendBuffer {
private final Preallocation parent; private final Preallocation parent;
final ByteBuffer buffer; final ByteBuffer buffer;
final int initialPos; final int initialPos;
SendBuffer(Preallocation parent, ByteBuffer buffer) { PooledSendBuffer(Preallocation parent, ByteBuffer buffer) {
this.parent = parent; this.parent = parent;
this.buffer = buffer; this.buffer = buffer;
initialPos = buffer.position(); initialPos = buffer.position();
} }
void release() { public boolean finished() {
return !buffer.hasRemaining();
}
public long writtenBytes() {
return buffer.position() - initialPos;
}
public long totalBytes() {
return buffer.limit() - initialPos;
}
public long transferTo(WritableByteChannel ch) throws IOException {
return ch.write(buffer);
}
public long transferTo(DatagramChannel ch, SocketAddress raddr) throws IOException {
return ch.send(buffer, raddr);
}
public void release() {
final Preallocation parent = this.parent; final Preallocation parent = this.parent;
if (parent != null && -- parent.refCnt == 0) { if (-- parent.refCnt == 0) {
parent.buffer.clear(); parent.buffer.clear();
if (parent != current) { if (parent != current) {
poolHead = new PreallocationRef(parent, poolHead); poolHead = new PreallocationRef(parent, poolHead);
@ -163,4 +246,42 @@ final class SocketSendBufferPool {
} }
} }
} }
}
final class FileSendBuffer implements SendBuffer {
private final FileRegion file;
private long writtenBytes;
FileSendBuffer(FileRegion file) {
this.file = file;
}
public boolean finished() {
return writtenBytes >= file.getCount();
}
public long writtenBytes() {
return writtenBytes;
}
public long totalBytes() {
return file.getCount();
}
public long transferTo(WritableByteChannel ch) throws IOException {
long localWrittenBytes = file.transferTo(ch);
writtenBytes += localWrittenBytes;
return localWrittenBytes;
}
public long transferTo(DatagramChannel ch, SocketAddress raddr)
throws IOException {
throw new UnsupportedOperationException();
}
public void release() {
// Unpooled.
}
}
}

View File

@ -32,6 +32,7 @@ import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.DefaultFileRegion;
import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
@ -40,7 +41,6 @@ import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.stream.ChunkedFile;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
/** /**
@ -91,7 +91,8 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
ch.write(response); ch.write(response);
// Write the content. // Write the content.
ChannelFuture writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192)); //ChannelFuture writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192));
ChannelFuture writeFuture = ch.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength));
// Decide whether to close the connection or not. // Decide whether to close the connection or not.
if (!isKeepAlive(request)) { if (!isKeepAlive(request)) {
@ -105,6 +106,8 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
throws Exception { throws Exception {
Channel ch = e.getChannel(); Channel ch = e.getChannel();
Throwable cause = e.getCause(); Throwable cause = e.getCause();
cause.printStackTrace();
System.exit(1);
if (cause instanceof TooLongFrameException) { if (cause instanceof TooLongFrameException) {
sendError(ctx, BAD_REQUEST); sendError(ctx, BAD_REQUEST);
return; return;