Processing business: how to spread the event is in the pipeline

Processing business: how to spread the event is in the pipeline

Netty series catalog ( https://www.cnblogs.com/binarylei/p/10117436.html )

On the one receiving the data: Adaptive read buffer and connection to solve any problem , we know that NioEventLoop constantly poll, receiving OP_READ event; then read the data spread out through pipeline.fireChannelRead (byteBuf). So the business process is in fact channelRead pipeline processing on (), this section also focuses on events in the pipeline is in communication behavior.

In the pipeline in the event spread, we need to focus on communication behavior and threads of execution events:

  1. Propagation behavior: to perform a post-event Handler, if not manually trigger ctx.fireChannelRead, then spread interrupted.
  2. Thread of execution: Business thread is executed in NioEventLoop in default. If there is obstruction of business process needs to be considered from another thread.

1. Analysis of the main line

1.1 mainline

In fact, on a main line has been talked about, when reading data triggers pipeline.fireChannelRead (byteBuf) to read data spread out. We now focuses on how events propagate in the pipeline.

Handler execution qualifications:

  • 实现 ChannelInboundHandler
  • Implementation channelRead not annotated @Skip
  • Handler execution chain can be interrupted. If you do not take the initiative to trigger ctx.fireChannelRead method will not continue down the implementation.

1.2 knowledge points

(1) the nature of the business process

ChannelInboundHandler channelRead all data in the pipeline () execution. And execution can be interrupted.

(Two) business processing thread

Channel default processing threads are bound NioEventLoop thread, other threads can also be set:

pipeline.addLast(new UnorderedThreadPoolEventExecutor(10), serverHandler);

2. Source analysis

2.1 fireChannelRead spread in the pipeline

@Override
public final ChannelPipeline fireChannelRead(Object msg) {
    AbstractChannelHandlerContext.invokeChannelRead(head, msg);
    return this;
}

Note: you can see fireChannelRead from the head -> tail has been behind the spread.

2.1 propagation behavior

Once the pipeline is executed in the middle of a Handler, the propagation behavior is interrupted. If you need to continue execution, we need to take the initiative to call ctx.fireChannelRead.

// AbstractChannelHandlerContext
@Override
public ChannelHandlerContext fireChannelRead(final Object msg) {
    invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);
    return this;
}

private void invokeChannelRead(Object msg) {
    if (invokeHandler()) {
        try {
            ((ChannelInboundHandler) handler()).channelRead(this, msg);
        } catch (Throwable t) {
            notifyHandlerException(t);
        }
    } else {
        fireChannelRead(msg);
    }
}

Note: you can see either perform channelRead method, or until you find a method to perform fireChannelRead corresponding Handler so far. If you do not call the principal ctx.fireChannelRead, the propagation behavior will be interrupted.

May wonder, corresponding Handler by findContextInbound () is not found, why do you need through invokeHandler () judgment once again? In fact, findContextInbound have channelRead method is to find the Handler, and invokeHandler method is to determine whether the Handler has been deleted.

2.3 thread of execution

Each Handler are executed in their corresponding executor, the default is NioEventLoop thread. Of course, you can also specify other threads yourself.

// AbstractChannelHandlerContext
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
    final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
        next.invokeChannelRead(m);
    } else {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                next.invokeChannelRead(m);
            }
        });
    }
}

Description: We need to focus on business execution threads, as if the business occupancy throughput time is too long, it will affect Netty IO's.

2.4 ChannelPipeline vs ChannelHandlerContext

Netty each Handler are packaged into ChannelHandlerContext added to ChannelPipeline in. Although it ChannelPipeline method ChannelHandlerContext the call, but the pipeline will begin traversing the head or tail, and will only begin to traverse from the current ctx hander.

We still take the following four read comparison: channel.read (), pipeline.read (), ctx.read (), unsafe.read ()

  • channel.read (): Direct call pipeline.read ().
  • pipeline.read (): call tail.read (), all experienced Handler from head or tail. In fact, the last head.read () call unsafe.beginRead (), this method registers OP_ACCEPT or OP_READ event to activate Channel.
  • ctx.read (): all current ctx after Handler from the beginning. If the transmission data is required instead ctx.write ctx.channel (). Write.
  • unsafe.read (): the bottom of the API. And unsafe.beginRead () different, unsafe # read will actually read data from the socket revbuf.

2.5 HeadContext vs TailContext

  • HeadContext:
    • inbound triggered by events, from the head -> tail, so it is necessary to call ctx.firexxx events spread it.
    • outbound triggered by the user, from the tail -> head, usually called directly to the head. If the middle of a re-Handler custom implementation of the method, it will not cut again, see AbstractChannelHandlerContext # invokeWrite0.
  • TailContext: function basically nothing has been downward propagation of an event can be.
HeadContext function
method Execution order Function Description
bind outbound unsafe.bind
connect outbound unsafe.connect
disconnect outbound unsafe.disconnect
close outbound unsafe.close
deregister outbound unsafe.deregister
read outbound unsafe.beginRead: Registration events of interest
write outbound unsafe.write
flush outbound unsafe.flush
exceptionCaught inbound ctx.fireExceptionCaught
channelRegistered inbound callHandlerAddedForAllHandlers
ctx.fireChannelRegistered
channelUnregistered inbound ctx.fireChannelUnregistered
destroy
channelActive inbound ctx.fireChannelActive
readIfIsAutoRead:调用unsafe.beginRead
channelInactive inbound ctx.fireChannelInactive()
channelRead inbound ctx.fireChannelRead
channelReadComplete inbound ctx.fireChannelReadComplete
readIfIsAutoRead
userEventTriggered inbound ctx.fireUserEventTriggered
channelWritabilityChanged inbound ctx.fireChannelWritabilityChanged
TailContext function
method Execution order Function Description
channelRead inbound ReferenceCountUtil.release(msg)

The intentions of recording a little bit every day. Perhaps the content is not important, but the habit is very important!

Guess you like

Origin www.cnblogs.com/binarylei/p/12641011.html