Watcher实现机制之服务端处理

ServerCnxn存储
客户端并不把WherRegistration对象传递给服务端,那么服务端是怎么处理watcher注册的呢?
服务端在收到客户端的请求之后,在FinalRequestProcess.processRequest()方法中会判断当前请求是否需要watcher, 如果需要就会把当前的 ServerCnxn 对象 cnxn 传递进去:

case OpCode.getData:{
     .......
     byte[] b = zks.getZKDatabase.getData(getDataRequest.getPath(), stat, getDataReqest.getWatcher()?   cnxn  : null) ;
     resp = new GetDataReqest(b,stat);
     break ;
     .....
}

ServerCnxn 是一个Zookeeper 客户端和服务器端之间的链接接口,代表了一个客户端和服务端的链接。默认实现是 NIOServerCnxn ,还有一个 NettyCnxn 。这两个实现了 Watcher 的 process接口, 所以ServerCnxn 实际上也是一个Watcher对象。

 数据节点路径和ServerCnxn 最终会被存储在WatcherManager中的 watchTable 和 watch2Path 中,这两个边路都是 类型的数据结构,从两个维度进行存储Watcher.
watchTable :  Map<String,HashSet<Watche>> ,  从数据节点路径的粒度托管 wacher
watch2Path : Map<Watche,HashSet<String>> , 从Watche的粒度来控制事件触发需要触发的数据节点。

在服务端,DataTree会托管两个WatchManager ,分别是 dataWatches 和 childrenWatches .

watcher触发
对于标记了watch 的请求,zookeeper 是把 ServerCnxn 作为 Watcher 存 储到是 WatcherManager中的,对于注册了 NodeDataChanaged 的监听事件,触发请求的逻辑是:

public Stat setData(String path, .....){

     Stat s = new Stat();
     DataNode n = nodes.get(path) ;
     
     ..........

     dataWatches.triggerWatch(path, EventType.NodeDataChanged) ;

     return s ;  
}

dataWatches.triggerWatch 会触发相关的事件:

public Set<Watcher> triggerWatch(String path, EventType type){
     return triggerWatch(path,type,null);
}

public Set<Watcher> triggerWatch(String path, EventType type, Set<Watcher> supress){
     WatchedEvent we = new WatchedEvent(type, KeepState.SyncConnected, path);
     HashSet<Watcher> watchers ;
     synchronized(this){
            watches = watchTable.remove(path) ;//删除该路径注册的所有监听
           // 再删除 watch2Path 数据结构中的path
          for(Watcher w : watches){
              Set<String> paths =  watch2Path.get(w) ;
              if(paths != null){
                      paths.remove(path); //删除路径
               }
               }
     
          //通过ServerCnxn通知客户端
          for( Watcher w : watches){
               if(supres !=null && supres.concatins(w)){
                    contine;
               }
               w.process(we) ;   //根据上面的了解,此时 w 实际上是一个ServerCnxn 对象。而ServerCnxn 代表了一个客户端和服务端的链接,所以Zookeeper实际上是没有直接处理Watcher的逻辑的,而是借助当前客户端链接的ServerCnxn 对象来实现对客户端的WatchedEvent 的传递,让客户端去处理的。
              }
     return watches ;

}
          
无论dataWathches 还是 childrenWatches 管理器,执行逻辑的是一样的,如下:

步骤四中触发Watcher的逻辑如下:
 因为对于需要注册Watcher的请求,ZK是把当前请求的ServerCnxn作为一个Watcher进行存储的,所以此处process方法实质上就是ServerCnxn的方法

public class NIOServerCnxn exnteds ServerCnxn{
     Synchronized public void process(WatchedEvent event){
          ReplyHeader h = new ReplyHeader(-1,-1L, 0) ;//标记当前是一个通知
          .......
          WatcherEvent we = event.getWrapper(); // 包装成可序列后进行网络传输的对象
          
          sendResponse(h , we, "notification") ; // 向客户端发送通知

}

 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值