@Override
    public void channelRead0(ChannelHandlerContext ctx, ByteBuf input) throws Exception {

      int readable = input.readableBytes();
      if (readable <= 0) {
        return;
      }

      com.alibaba.dubbo.remoting.buffer.ChannelBuffer message;
      if (buffer.readable()) {
        if (buffer instanceof DynamicChannelBuffer) {
          buffer.writeBytes(input.nioBuffer());
          message = buffer;
        } else {
          int size = buffer.readableBytes() + input.readableBytes();
          message =
              com.alibaba.dubbo.remoting.buffer.ChannelBuffers.dynamicBuffer(
                  size > bufferSize ? size : bufferSize);
          message.writeBytes(buffer, buffer.readableBytes());
          message.writeBytes(input.nioBuffer());
        }
      } else {
        message = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.wrappedBuffer(input.nioBuffer());
      }

      NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
      Object msg;
      int saveReaderIndex;

      try {
        // decode object.
        do {
          saveReaderIndex = message.readerIndex();
          try {
            msg = codec.decode(channel, message);
          } catch (IOException e) {
            buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
            throw e;
          }
          if (msg == Codec2.DecodeResult.NEED_MORE_INPUT) {
            message.readerIndex(saveReaderIndex);
            break;
          } else {
            if (saveReaderIndex == message.readerIndex()) {
              buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
              throw new IOException("Decode without read data.");
            }
            if (msg != null) {
              ctx.fireChannelRead(msg);
            }
          }
        } while (message.readable());
      } finally {
        if (message.readable()) {
          message.discardReadBytes();
          buffer = message;
        } else {
          buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
        }
        NettyChannel.removeChannelIfDisconnected(ctx.channel());
      }
    }