zk源码阅读19:zk client之网络I/O(三) ClientCnxn.EventThread

摘要

本来和sendThread一起讲,但是sendThread太长了,下一节再讲,本节讲解ClientCnxn.EventThread,主要内容如下

  EventThread属性
    主要waitingEvents 临时存放需要被触发的Obj,包含Watcher和AsyncCallBack
  EventThread方法
    queueEvent方法把WatchedEvent加入到waitingEvents队列
    queuePacket方法加入Packet,把AsyncCallBack事件加入到waitingEvents队列
    queueEventOfDeath标记线程即将go die
    run方法不断地从从waitingEvents队列取出WatchedEvent和Packet
    processEvent方法对WatchedEvent和Packet两种事件进行处理

概述

EventThread是客户端ClientCnxn内部的一个事件处理线程,负责客户端的事件处理,并触发客户端注册的Watcher监听。EventThread中的watingEvents队列用于临时存放那些需要被触发的Object,包括客户端注册的Watcher和异步接口中注册的回调器AsyncCallback。同时,EventThread会不断地从watingEvents中取出Object,识别具体类型(Watcher或AsyncCallback),并分别调用process和processResult接口方法来实现对事件的触发和回调。

源码解析

类图如下

zk源码阅读19:zk client之网络I/O(三) ClientCnxn.EventThread_第1张图片
EventThread类图

属性

    private final LinkedBlockingQueue waitingEvents =
            new LinkedBlockingQueue();//临时存放需要被触发的Obj,包含Watcher和AsyncCallBack

        /** This is really the queued session state until the event
         * thread actually processes the event and hands it to the watcher.
         * But for all intents and purposes this is the state.
         */
        private volatile KeeperState sessionState = KeeperState.Disconnected;//当前session状态

       private volatile boolean wasKilled = false;//如果需要停止(并没有真的kill)
       private volatile boolean isRunning = false;//线程是否在运行(waitingEvents是否在工作)
 
 

属性需要结合方法理解

方法

异步加入WatchedEvent 至临时队列waitingEvents

      public void queueEvent(WatchedEvent event) {//将WatchedEvent加入队列
            if (event.getType() == EventType.None
                    && sessionState == event.getState()) {
                return;
            }//如果没有发生什么状态变化
            sessionState = event.getState();

            // materialize the watchers based on the event
            WatcherSetEventPair pair = new WatcherSetEventPair(
                    watcher.materialize(event.getState(), event.getType(),
                            event.getPath()),
                            event);//用WatcherSetEventPair封装watchers和watchedEvent
            // queue the pair (watch set & event) for later processing
            waitingEvents.add(pair);//加入队列
        }

处理异步回调的Packet,根据标示位判断是异步还是同步处理

      public void queuePacket(Packet packet) {//当Packet有callback的时候调用
          if (wasKilled) {//如果kill掉了
             synchronized (waitingEvents) {
                if (isRunning) waitingEvents.add(packet);//线程在运行,则加入临时队列
                else processEvent(packet);//同步处理Event
             }
          } else {
             waitingEvents.add(packet);//加入临时队列
          }
       }

将eventOfDeath加入waitingEvents代表线程将要kill(进行take时才标示wasKilled)

        public void queueEventOfDeath() {
            waitingEvents.add(eventOfDeath);
        }

线程run方法,根据eventOfDeath以及waitingEvents.isEmpty()改变两个标示位wasKilled,isRunning

      @Override
        public void run() {
           try {
              isRunning = true;
              while (true) {
                 Object event = waitingEvents.take();//消费waitingEvents
                 if (event == eventOfDeath) {
                    wasKilled = true;//遇到了eventOfDeath就设置wasKilled表示需要被停掉(但是没有真正的停)
                 } else {
                    processEvent(event);//处理event
                 }
                 if (wasKilled)
                    synchronized (waitingEvents) {
                       if (waitingEvents.isEmpty()) {//当需要被停掉,且临时队列处理完了
                          isRunning = false;
                          break;//跳出while,结束线程
                       }
                    }
              }
           } catch (InterruptedException e) {
              LOG.error("Event thread exiting due to interruption", e);
           }

            LOG.info("EventThread shut down for session: 0x{}",
                     Long.toHexString(getSessionId()));
        }

processEvent函数太长了,看看就理解了,主要分为watch以及AsyncCallBack进行不同的回调
AsyncCallback用processResult
watch用process即可

    private void processEvent(Object event) {//处理Event,主要分为watch以及AsyncCallBack
          try {
              if (event instanceof WatcherSetEventPair) {//如果是watch类型
                  // each watcher will process the event
                  WatcherSetEventPair pair = (WatcherSetEventPair) event;
                  for (Watcher watcher : pair.watchers) {//从WatcherSetEventPair这个wraper中取出watchers和event
                      try {
                          watcher.process(pair.event);//watcher处理WatchedEvent
                      } catch (Throwable t) {
                          LOG.error("Error while calling watcher ", t);
                      }
                  }
              } else {//否则就是AsyncCallBack类型事件
                  Packet p = (Packet) event;
                  int rc = 0;
                  String clientPath = p.clientPath;
                  if (p.replyHeader.getErr() != 0) {
                      rc = p.replyHeader.getErr();
                  }
                  if (p.cb == null) {
                      LOG.warn("Somehow a null cb got to EventThread!");
                  } else if (p.response instanceof ExistsResponse
                          || p.response instanceof SetDataResponse
                          || p.response instanceof SetACLResponse) {
                      StatCallback cb = (StatCallback) p.cb;
                      if (rc == 0) {
                          if (p.response instanceof ExistsResponse) {
                              cb.processResult(rc, clientPath, p.ctx,
                                      ((ExistsResponse) p.response)
                                              .getStat());
                          } else if (p.response instanceof SetDataResponse) {
                              cb.processResult(rc, clientPath, p.ctx,
                                      ((SetDataResponse) p.response)
                                              .getStat());
                          } else if (p.response instanceof SetACLResponse) {
                              cb.processResult(rc, clientPath, p.ctx,
                                      ((SetACLResponse) p.response)
                                              .getStat());
                          }
                      } else {
                          cb.processResult(rc, clientPath, p.ctx, null);
                      }
                  } else if (p.response instanceof GetDataResponse) {
                      DataCallback cb = (DataCallback) p.cb;
                      GetDataResponse rsp = (GetDataResponse) p.response;
                      if (rc == 0) {
                          cb.processResult(rc, clientPath, p.ctx, rsp
                                  .getData(), rsp.getStat());
                      } else {
                          cb.processResult(rc, clientPath, p.ctx, null,
                                  null);
                      }
                  } else if (p.response instanceof GetACLResponse) {
                      ACLCallback cb = (ACLCallback) p.cb;
                      GetACLResponse rsp = (GetACLResponse) p.response;
                      if (rc == 0) {
                          cb.processResult(rc, clientPath, p.ctx, rsp
                                  .getAcl(), rsp.getStat());
                      } else {
                          cb.processResult(rc, clientPath, p.ctx, null,
                                  null);
                      }
                  } else if (p.response instanceof GetChildrenResponse) {
                      ChildrenCallback cb = (ChildrenCallback) p.cb;
                      GetChildrenResponse rsp = (GetChildrenResponse) p.response;
                      if (rc == 0) {
                          cb.processResult(rc, clientPath, p.ctx, rsp
                                  .getChildren());
                      } else {
                          cb.processResult(rc, clientPath, p.ctx, null);
                      }
                  } else if (p.response instanceof GetChildren2Response) {
                      Children2Callback cb = (Children2Callback) p.cb;
                      GetChildren2Response rsp = (GetChildren2Response) p.response;
                      if (rc == 0) {
                          cb.processResult(rc, clientPath, p.ctx, rsp
                                  .getChildren(), rsp.getStat());
                      } else {
                          cb.processResult(rc, clientPath, p.ctx, null, null);
                      }
                  } else if (p.response instanceof CreateResponse) {
                      StringCallback cb = (StringCallback) p.cb;
                      CreateResponse rsp = (CreateResponse) p.response;
                      if (rc == 0) {
                          cb.processResult(rc, clientPath, p.ctx,
                                  (chrootPath == null
                                          ? rsp.getPath()
                                          : rsp.getPath()
                                    .substring(chrootPath.length())));
                      } else {
                          cb.processResult(rc, clientPath, p.ctx, null);
                      }
                  } else if (p.response instanceof MultiResponse) {
                          MultiCallback cb = (MultiCallback) p.cb;
                          MultiResponse rsp = (MultiResponse) p.response;
                          if (rc == 0) {
                                  List results = rsp.getResultList();
                                  int newRc = rc;
                                  for (OpResult result : results) {
                                          if (result instanceof ErrorResult
                                              && KeeperException.Code.OK.intValue()
                                                  != (newRc = ((ErrorResult) result).getErr())) {
                                                  break;
                                          }
                                  }
                                  cb.processResult(newRc, clientPath, p.ctx, results);
                          } else {
                                  cb.processResult(rc, clientPath, p.ctx, null);
                          }
                  }  else if (p.cb instanceof VoidCallback) {
                      VoidCallback cb = (VoidCallback) p.cb;
                      cb.processResult(rc, clientPath, p.ctx);
                  }
              }
          } catch (Throwable t) {
              LOG.error("Caught unexpected throwable", t);
          }
       }

问题

EventThread里面为什么queueEvent函数就是直接加入waitingEvents队列,而queuePacket则需要根据标示位状态判断是同步还是异步?

这里感觉是代码的问题,这一点并不理解

refer

http://www.voidcn.com/blog/aBOUNTWINTER/article/p-6400711.html
http://www.cnblogs.com/leesf456/p/6098255.html
https://my.oschina.net/pingpangkuangmo/blog/486780
http://shift-alt-ctrl.iteye.com/blog/1846971
《paxos到zk》

你可能感兴趣的:(zk源码阅读19:zk client之网络I/O(三) ClientCnxn.EventThread)