Made IdleStateHandler @Sharable and removed unnecessary lazy

initialization in ReadTimeoutHandler
This commit is contained in:
Trustin Lee 2011-05-04 17:30:09 +09:00
parent f22a55d6e2
commit fd7b5769f7
2 changed files with 60 additions and 49 deletions

View File

@ -21,6 +21,8 @@ import java.util.concurrent.TimeUnit;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandler.Sharable;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
@ -73,14 +75,16 @@ import org.jboss.netty.util.TimerTask;
* public class MyPipelineFactory implements {@link ChannelPipelineFactory} { * public class MyPipelineFactory implements {@link ChannelPipelineFactory} {
* *
* private final {@link Timer} timer; * private final {@link Timer} timer;
* private final {@link ChannelHandler} idleStateHandler;
* *
* public MyPipelineFactory({@link Timer} timer) { * public MyPipelineFactory({@link Timer} timer) {
* this.timer = timer; * this.timer = timer;
* this.idleStateHandler = <b>new {@link IdleStateHandler}(timer, 60, 30, 0), // timer must be shared.</b>
* } * }
* *
* public {@link ChannelPipeline} getPipeline() { * public {@link ChannelPipeline} getPipeline() {
* return {@link Channels}.pipeline( * return {@link Channels}.pipeline(
* <b>new {@link IdleStateHandler}(timer, 60, 30, 0), // timer must be shared.</b> * idleStateHandler,
* new MyHandler()); * new MyHandler());
* } * }
* } * }
@ -120,6 +124,7 @@ import org.jboss.netty.util.TimerTask;
* @apiviz.uses org.jboss.netty.util.HashedWheelTimer * @apiviz.uses org.jboss.netty.util.HashedWheelTimer
* @apiviz.has org.jboss.netty.handler.timeout.IdleStateEvent oneway - - triggers * @apiviz.has org.jboss.netty.handler.timeout.IdleStateEvent oneway - - triggers
*/ */
@Sharable
public class IdleStateHandler extends SimpleChannelUpstreamHandler public class IdleStateHandler extends SimpleChannelUpstreamHandler
implements LifeCycleAwareChannelHandler, implements LifeCycleAwareChannelHandler,
ExternalResourceReleasable { ExternalResourceReleasable {
@ -127,15 +132,8 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
final Timer timer; final Timer timer;
final long readerIdleTimeMillis; final long readerIdleTimeMillis;
volatile Timeout readerIdleTimeout;
volatile long lastReadTime;
final long writerIdleTimeMillis; final long writerIdleTimeMillis;
volatile Timeout writerIdleTimeout;
volatile long lastWriteTime;
final long allIdleTimeMillis; final long allIdleTimeMillis;
volatile Timeout allIdleTimeout;
/** /**
* Creates a new instance. * Creates a new instance.
@ -249,7 +247,7 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
@Override @Override
public void beforeRemove(ChannelHandlerContext ctx) throws Exception { public void beforeRemove(ChannelHandlerContext ctx) throws Exception {
destroy(); destroy(ctx);
} }
@Override @Override
@ -270,14 +268,15 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
@Override @Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception { throws Exception {
destroy(); destroy(ctx);
ctx.sendUpstream(e); ctx.sendUpstream(e);
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception { throws Exception {
lastReadTime = System.currentTimeMillis(); State state = (State) ctx.getAttachment();
state.lastReadTime = System.currentTimeMillis();
ctx.sendUpstream(e); ctx.sendUpstream(e);
} }
@ -285,42 +284,47 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e) public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e)
throws Exception { throws Exception {
if (e.getWrittenAmount() > 0) { if (e.getWrittenAmount() > 0) {
lastWriteTime = System.currentTimeMillis(); State state = (State) ctx.getAttachment();
state.lastWriteTime = System.currentTimeMillis();
} }
ctx.sendUpstream(e); ctx.sendUpstream(e);
} }
private void initialize(ChannelHandlerContext ctx) { private void initialize(ChannelHandlerContext ctx) {
lastReadTime = lastWriteTime = System.currentTimeMillis(); State state = new State();
ctx.setAttachment(state);
state.lastReadTime = state.lastWriteTime = System.currentTimeMillis();
if (readerIdleTimeMillis > 0) { if (readerIdleTimeMillis > 0) {
readerIdleTimeout = timer.newTimeout( state.readerIdleTimeout = timer.newTimeout(
new ReaderIdleTimeoutTask(ctx), new ReaderIdleTimeoutTask(ctx),
readerIdleTimeMillis, TimeUnit.MILLISECONDS); readerIdleTimeMillis, TimeUnit.MILLISECONDS);
} }
if (writerIdleTimeMillis > 0) { if (writerIdleTimeMillis > 0) {
writerIdleTimeout = timer.newTimeout( state.writerIdleTimeout = timer.newTimeout(
new WriterIdleTimeoutTask(ctx), new WriterIdleTimeoutTask(ctx),
writerIdleTimeMillis, TimeUnit.MILLISECONDS); writerIdleTimeMillis, TimeUnit.MILLISECONDS);
} }
if (allIdleTimeMillis > 0) { if (allIdleTimeMillis > 0) {
allIdleTimeout = timer.newTimeout( state.allIdleTimeout = timer.newTimeout(
new AllIdleTimeoutTask(ctx), new AllIdleTimeoutTask(ctx),
allIdleTimeMillis, TimeUnit.MILLISECONDS); allIdleTimeMillis, TimeUnit.MILLISECONDS);
} }
} }
private void destroy() { private void destroy(ChannelHandlerContext ctx) {
if (readerIdleTimeout != null) { State state = (State) ctx.getAttachment();
readerIdleTimeout.cancel(); if (state.readerIdleTimeout != null) {
readerIdleTimeout = null; state.readerIdleTimeout.cancel();
state.readerIdleTimeout = null;
} }
if (writerIdleTimeout != null) { if (state.writerIdleTimeout != null) {
writerIdleTimeout.cancel(); state.writerIdleTimeout.cancel();
writerIdleTimeout = null; state.writerIdleTimeout = null;
} }
if (allIdleTimeout != null) { if (state.allIdleTimeout != null) {
allIdleTimeout.cancel(); state.allIdleTimeout.cancel();
allIdleTimeout = null; state.allIdleTimeout = null;
} }
} }
@ -343,12 +347,13 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
return; return;
} }
State state = (State) ctx.getAttachment();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
long lastReadTime = IdleStateHandler.this.lastReadTime; long lastReadTime = state.lastReadTime;
long nextDelay = readerIdleTimeMillis - (currentTime - lastReadTime); long nextDelay = readerIdleTimeMillis - (currentTime - lastReadTime);
if (nextDelay <= 0) { if (nextDelay <= 0) {
// Reader is idle - set a new timeout and notify the callback. // Reader is idle - set a new timeout and notify the callback.
readerIdleTimeout = state.readerIdleTimeout =
timer.newTimeout(this, readerIdleTimeMillis, TimeUnit.MILLISECONDS); timer.newTimeout(this, readerIdleTimeMillis, TimeUnit.MILLISECONDS);
try { try {
channelIdle(ctx, IdleState.READER_IDLE, lastReadTime); channelIdle(ctx, IdleState.READER_IDLE, lastReadTime);
@ -357,7 +362,7 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
} }
} else { } else {
// Read occurred before the timeout - set a new timeout with shorter delay. // Read occurred before the timeout - set a new timeout with shorter delay.
readerIdleTimeout = state.readerIdleTimeout =
timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS); timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS);
} }
} }
@ -378,12 +383,13 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
return; return;
} }
State state = (State) ctx.getAttachment();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
long lastWriteTime = IdleStateHandler.this.lastWriteTime; long lastWriteTime = state.lastWriteTime;
long nextDelay = writerIdleTimeMillis - (currentTime - lastWriteTime); long nextDelay = writerIdleTimeMillis - (currentTime - lastWriteTime);
if (nextDelay <= 0) { if (nextDelay <= 0) {
// Writer is idle - set a new timeout and notify the callback. // Writer is idle - set a new timeout and notify the callback.
writerIdleTimeout = state.writerIdleTimeout =
timer.newTimeout(this, writerIdleTimeMillis, TimeUnit.MILLISECONDS); timer.newTimeout(this, writerIdleTimeMillis, TimeUnit.MILLISECONDS);
try { try {
channelIdle(ctx, IdleState.WRITER_IDLE, lastWriteTime); channelIdle(ctx, IdleState.WRITER_IDLE, lastWriteTime);
@ -392,7 +398,7 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
} }
} else { } else {
// Write occurred before the timeout - set a new timeout with shorter delay. // Write occurred before the timeout - set a new timeout with shorter delay.
writerIdleTimeout = state.writerIdleTimeout =
timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS); timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS);
} }
} }
@ -412,13 +418,14 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
return; return;
} }
State state = (State) ctx.getAttachment();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
long lastIoTime = Math.max(lastReadTime, lastWriteTime); long lastIoTime = Math.max(state.lastReadTime, state.lastWriteTime);
long nextDelay = allIdleTimeMillis - (currentTime - lastIoTime); long nextDelay = allIdleTimeMillis - (currentTime - lastIoTime);
if (nextDelay <= 0) { if (nextDelay <= 0) {
// Both reader and writer are idle - set a new timeout and // Both reader and writer are idle - set a new timeout and
// notify the callback. // notify the callback.
allIdleTimeout = state.allIdleTimeout =
timer.newTimeout(this, allIdleTimeMillis, TimeUnit.MILLISECONDS); timer.newTimeout(this, allIdleTimeMillis, TimeUnit.MILLISECONDS);
try { try {
channelIdle(ctx, IdleState.ALL_IDLE, lastIoTime); channelIdle(ctx, IdleState.ALL_IDLE, lastIoTime);
@ -428,9 +435,23 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler
} else { } else {
// Either read or write occurred before the timeout - set a new // Either read or write occurred before the timeout - set a new
// timeout with shorter delay. // timeout with shorter delay.
allIdleTimeout = state.allIdleTimeout =
timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS); timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS);
} }
} }
} }
private static final class State {
State() {
super();
}
volatile Timeout readerIdleTimeout;
volatile long lastReadTime;
volatile Timeout writerIdleTimeout;
volatile long lastWriteTime;
volatile Timeout allIdleTimeout;
}
} }

View File

@ -189,29 +189,19 @@ public class ReadTimeoutHandler extends SimpleChannelUpstreamHandler
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception { throws Exception {
updateLastReadTime(ctx); State state = (State) ctx.getAttachment();
state.lastReadTime = System.currentTimeMillis();
ctx.sendUpstream(e); ctx.sendUpstream(e);
} }
private void initialize(ChannelHandlerContext ctx) { private void initialize(ChannelHandlerContext ctx) {
updateLastReadTime(ctx); State state = new State();
ctx.setAttachment(state);
if (timeoutMillis > 0) { if (timeoutMillis > 0) {
State state = (State) ctx.getAttachment();
state.timeout = timer.newTimeout(new ReadTimeoutTask(ctx), timeoutMillis, TimeUnit.MILLISECONDS); state.timeout = timer.newTimeout(new ReadTimeoutTask(ctx), timeoutMillis, TimeUnit.MILLISECONDS);
} }
} }
private void updateLastReadTime(ChannelHandlerContext ctx) {
State state = (State) ctx.getAttachment();
if (state == null) {
// lastReadTime will be set by the constructor, so we do not do it
// again here.
ctx.setAttachment(state = new State());
} else {
state.lastReadTime = System.currentTimeMillis();
}
}
private void destroy(ChannelHandlerContext ctx) { private void destroy(ChannelHandlerContext ctx) {
State state = (State) ctx.getAttachment(); State state = (State) ctx.getAttachment();
if (state.timeout != null) { if (state.timeout != null) {