(See #768)
Once too long object is received, CompatibleMarshallingDecoder has to
discard all input from now on, just like MarshallingDecoder does.
Otherwise, the decoder will raise more exceptions because the decoder
has no idea anymore where the object starts.
Before this fix, SerialThreadLocalCompatibleMarshallingDecoderTest
logged many additional exceptions raised by the decoder after test is
finished.
Using DelimiterBasedFrameDecoder with Delimiters.lineDelimiter() has
quadratic performance in the size of the input buffer. Needless to
say, the performance degrades pretty quickly as the size of the buffer
increases. Larger MTUs or loopback connections can make it so bad that
it appears that the code is "busy waiting", when in fact it's spending
almost 100% of the CPU time in DelimiterBasedFrameDecoder.indexOf().
Add a new LineBasedFrameDecoder that decodes line-delimited frames
in O(n) instead of DelimiterBasedFrameDecoder's O(n^2) implementation.
In OpenTSDB's telnet-style protocol decoder this resulted in throughput
increases of an order of magnitude.
Change DelimiterBasedFrameDecoder to automatically detect when the
frames are delimited by line endings, and automatically switch to
using LineBasedFrameDecoder under the hood. This means that all Netty
applications out there that using the combo DelimiterBasedFrameDecoder
with Delimiters.lineDelimiter() will automatically benefit from the
better performance of LineBasedFrameDecoder, without requiring a code
change.
This commit introduces a new API for ByteBuf allocation which fixes
issue #643 along with refactoring of ByteBuf for simplicity and better
performance. (see #62)
A user can configure the ByteBufAllocator of a Channel via
ChannelOption.ALLOCATOR or ChannelConfig.get/setAllocator(). The
default allocator is currently UnpooledByteBufAllocator.HEAP_BY_DEFAULT.
To allocate a buffer, do not use Unpooled anymore. do the following:
ctx.alloc().buffer(...); // allocator chooses the buffer type.
ctx.alloc().heapBuffer(...);
ctx.alloc().directBuffer(...);
To deallocate a buffer, use the unsafe free() operation:
((UnsafeByteBuf) buf).free();
The following is the list of the relevant changes:
- Add ChannelInboundHandler.freeInboundBuffer() and
ChannelOutboundHandler.freeOutboundBuffer() to let a user free the
buffer he or she allocated. ChannelHandler adapter classes implement
is already, so most users won't need to call free() by themselves.
freeIn/OutboundBuffer() methods are invoked when a Channel is closed
and deregistered.
- All ByteBuf by contract must implement UnsafeByteBuf. To access an
unsafe operation: ((UnsafeByteBuf) buf).internalNioBuffer()
- Replace WrappedByteBuf and ByteBuf.Unsafe with UnsafeByteBuf to
simplify overall class hierarchy and to avoid unnecesary instantiation
of Unsafe instances on an unsafe operation.
- Remove buffer reference counting which is confusing
- Instantiate SwappedByteBuf lazily to avoid instantiation cost
- Rename ChannelFutureFactory to ChannelPropertyAccess and move common
methods between Channel and ChannelHandlerContext there. Also made it
package-private to hide it from a user.
- Remove unused unsafe operations such as newBuffer()
- Add DetectionUtil.canFreeDirectBuffer() so that an allocator decides
which buffer type to use safely
* Add DecodeResult that represents the result of decoding a message
* Add HttpObject which HttpMessage and HttpChunk extend.
** HttpObject has a property 'decodeResult'
o Add ByteBuf.hasNioBuffers() method
o Promote CompositeByteBuf.nioBuffers() methods to ByteBuf
o Use ByteBuf.nioBuffers() methods from AioSocketChannel
- Replace ByteBufferBackedByteBuf with DirectByteBuf
- Make DirectByteBuf and HeapByteBuf dynamic
- Remove DynamicByteBuf
- Replace Unpooled.dynamicBuffer() with Unpooled.buffer() and
directBuffer()
- Remove ByteBufFactory (will be replaced with ByteBufPool later)
- Add ByteBuf.Unsafe (might change in the future)
- Removed VoidEnum because a user can now specify Void instead
- AIO: Prefer discardReadBytes to clear
- AIO: Fixed a potential bug where notifyFlushFutures() is not called
if flush() was requested with no outbound data
- Add Channel.metadata() and remove Channel.bufferType()
- DefaultPipeline automatically redirects disconnect() request to
close() if the channel has no disconnect operation
- Remove unnecessary disconnect() implementations
- Rename ZlibEncoder/Decoder to JZlibEncoder/Decoder
- Define a new ZlibEncoder/Decoder class
- Add JdkZlibEncoder
- All JZlib* and JdkZlib* extends ZlibEncoder/Decoder
- Add ZlibCodecFactory and use it everywhere
- Removed all methods that requires ByteOrder as a parameter
from Unpooled (formerly ByteBufs/ChannelBuffers)
- Instead, a user calls order(ByteOrder) to get a little endian
version of the user's buffer
- This gives less overwhelming number of methods in Unpooled.
- ChannelInboundHandler and ChannelOutboundHandler does not have a type
parameter anymore.
- User should implement ChannelInboundMessageHandler or
ChannelOutboundMessageHandler.
- Add MessageBuf which replaces java.util.Queue
- Add ChannelBuf which is common type of ByteBuf and ChannelBuf
- ChannelBuffers was renamed to ByteBufs
- Add MessageBufs
- All these changes are going to replace ChannelBufferHolder.
- ChannelBuffer gives a perception that it's a buffer of a
channel, but channel's buffer is now a byte buffer or a message
buffer. Therefore letting it be as is is going to be confusing.
- Also prohibited a user from overriding
ChannelInbound(Byte|Message)HandlerAdapter. If a user wants to do
that, he or she should extend ChannelInboundHandlerAdapter instead.
- In computing, 'stream' means both byte stream and message stream,
which is confusing.
- Also, we were already mixing stream and byte in some places and
it's better use the terms consistently.
(e.g. inboundByteBuffer & inbound stream)
- Added EventExecutor.inEventLoop(Thread) and replaced executor identity
comparison in DefaultChannelPipeline with it - more elegant IMO
- Removed the test classes that needs rewrite or is of no use
- LoggingHandler now only logs state and operations
- StreamLoggingHandler and MessageLoggingHandler log the buffer content
- Added ChannelOperationHandlerAdapter
- Used by WriteTimeoutHandler
- Extracted some handler methods from ChannelInboundHandler into
ChannelStateHandler
- Extracted some handler methods from ChannelOutboundHandler into
ChannelOperationHandler
- Moved exceptionCaught and userEventTriggered are now in
ChannelHandler
- Channel(Inbound|Outbound)HandlerContext is merged into
ChannelHandlerContext
- ChannelHandlerContext adds direct access methods for inboud and
outbound buffers
- The use of ChannelBufferHolder is minimal now.
- Before: inbound().byteBuffer()
- After: inboundByteBuffer()
- Simpler and better performance
- Bypass buffer types were removed because it just does not work at all
with the thread model.
- All handlers that uses a bypass buffer are broken. Will fix soon.
- CombinedHandlerAdapter does not make sense anymore either because
there are four handler interfaces to consider and often the two
handlers will implement the same handler interface such as
ChannelStateHandler. Thinking of better ways to provide this feature
... just like we do with byte arrays. toByteBuffer() and
toByteBuffers() had an indeterministic behavior and thus it could not
tell when the returned NIO buffer is shared or not. nioBuffer() always
returns a view buffer of the Netty buffer. The only case where
hasNioBuffer() returns false and nioBuffer() fails is the
CompositeChannelBuffer, which is not very commonly used and *slow*.
- Add EventExecutor and make EventLoop extend it
- Add SingleThreadEventExecutor and MultithreadEventExecutor
- Add EventExecutor's default implementation
- Fixed an API design problem where there is no way to get non-bypass
buffer of desired type
- Add ChannelHandlerContext.eventLoop() for convenience
- Bootstrap and ServerBootstrap handles channel initialization failure
better
- More strict checks for missing @Sharable annotation
- A handler without @Sharable annotation cannot be added more than
once now.
- Exception in this case makes a user less confusing
- To reduce the overhead of filling the stack trace,
NoSuchBufferException has a public pre-constructed instance.
- This is necessary because codec framework sometimes need to support
both type of outbound buffers.
- Fixed a bug where SpdyFrameEncoder did not handle ping messages
- Reduced memory copy in codec embedder (EmbeddedChannel)
- Renamed ChannelBootstrap to Bootstrap
- Renamed ServerChannelBootstrap to ServerBootstrap
- Moved bootstrap classes to io.netty.bootstrap as before
- Moved unfoldAndAdd() to a separate utility class
- Fixed a bug in unfoldAndAdd() where it did not handle ChannelBuffer
correctly
- Previous API did not support the pipeline which contains multiple
MessageToStreamEncoders because there was no way to find the closest
outbound byte buffer. Now you always get the correct buffer even if
the handler that provides the buffer is placed distantly.
For example:
Channel -> MsgAEncoder -> MsgBEncoder -> MsgCEncoder
Msg(A|B|C)Encoder will all have access to the channel's outbound
byte buffer. Previously, it was simply impossible.
- Improved ChannelBufferHolder.toString()
- Replaced pipeline factories with initializers
- Ported essential parts related with HTTP to the new API
- Replaced ChannelHandlerAdapter.combine() with CombinedChannelHandler
- Fixed a bug where ReplayingDecoder does not notify the next handler
- Fixed a bug where ReplayingDecoder calls wrong callDecode() method
- Added a destination buffer as an argument to AbstractChannel.doRead()
for easier implementation
- Fixed a bug where NioSocketChannel did not try to increase the inbound
buffer size (moved the logic to AbstractChannel)
- Replaced some IllegalArgumentExceptions with
UnsupportedMessageTypeException
- MessageToMessage(Encoder|Decoder) should continue polling the
inbound buffer if encode() or decode() returns null
- aggregating codec can do that
- Added CodecException which is either EncoderException or
DecoderException
- Made all decoder exceptions a subtype of DecoderException
- Replaced CodecEmbedderException with CodecException
- All abstract handlers wraps an exception with a CodecException
- UniqueKey removes the duplication between ChannelOption and
AttributeKey
- UniqueName provides common name collision check for AttributeKey,
ChannelOption, and Signal.
- Replaced ReplayError with Signal
- Removed deprecated classes
- Changed type parameter of StreamToMessageDecoder and
MessageToMessageDecoder for more flexibility
- Made all tests in the codec package pass
- Replaced FrameDecoder and OneToOne(Encoder|Decoder) with:
- (Stream|Message)To(String|Message)(Encoder|Decoder)
- Moved the classes in 'codec.frame' up to 'codec'
- Fixed some bugs found while running unit tests
- Channel now creates a ChannelPipeline by itself
I find no reason to allow a user to use one's own pipeline
implementation since I saw nobody does except for the cases where a
user wants to add a user attribute to a channel, which is now covered
by AttributeMap.
- Removed ChannelEvent and its subtypes because they are replaced by
direct method invocation.
- Replaced ChannelSink with Channel.unsafe()
- Various getter renaming (e.g. Channel.getId() -> Channel.id())
- Added ChannelHandlerInvoker interface
- Implemented AbstractChannel and AbstractServerChannel
- Some other changes I don't remember
Merge in fix for threading (related to #140 and #187). This also includes the new feature that allow to submit a Runnable that gets executed later in the io thread.
* Overall code cleanup on FrameDecoder and ReplayingDecoder
* FrameDecoder discards readableBytes only when it has to
* Replaced createCumulationDynamicBuffer with newCumulationBuffer with
an additional hint
* ReplayingDecoder does not perform memory copy if possible