netty/netty — pull request #900 by trustin (2013-01-05 07:06:32+00:00)
Title: Give a handler more control over how its buffers' read bytes are discarded.

This pull request adds two new handler methods: `discardInboundReadBytes(ctx)` and `discardOutboundReadBytes(ctx)` to `ChannelInboundByteHandler` and `ChannelOutboundByteHandler` respectively. They are called between every `inboundBufferUpdated()` and `flush()` respectively. Their default implementation is to call `discardSomeReadBytes()` on their buffers and a user can override this behavior easily. For example, `ReplayingDecoder.discardInboundReadBytes()` looks like the following:

@Override
public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
ByteBuf in = ctx.inboundByteBuffer();
final int oldReaderIndex = in.readerIndex();
super.discardInboundReadBytes(ctx);
final int newReaderIndex = in.readerIndex();
checkpoint -= oldReaderIndex - newReaderIndex;
}

If a handler, which has its own buffer index variable, extends `ReplayingDecoder` or `ByteToMessageDecoder`, the handler can also override `discardInboundReadBytes()` and adjust its index variable accordingly.

### Caveat

Let's assume you write a decoder that extends `ReplayingDecoder`. `ReplayingDecoder.discardInboundReadBytes()` has already been implemented to discard read bytes. You cannot change this behavior. even if you override `discardInboundReadBytes()` in your decoder because you must call `super.discardInboundReadBytes()` to make sure the `checkpoint` is in-sync.

To workaround this problem, `ReplayingDecoder` must:

1. Make `discardInboundReadBytes()` final.
2. Add a new overridable protected method whose default implementation is `super.discardInboundReadBytes()` and make `discardInboundreadBytes()` call it rather than calling `super.discardInboundReadBytes()`.
3. A decoder that extends `ReplayingDecoder` overrides the method added at the step 2.

For example:

@Override
public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
ByteBuf in = ctx.inboundByteBuffer();
final int oldReaderIndex = in.readerIndex();
doDiscardInboundReadBytes(ctx);
final int newReaderIndex = in.readerIndex();
checkpoint -= oldReaderIndex - newReaderIndex;
}

protected void doDiscardInboundReadBytes(ctx) throws Exception {
super.discardInboundReadBytes(ctx);
}

Usually, the depth of class hierarchy will not really be greater than 2 or 3, so it might not be a big deal in most cases.