【Zookeeper】源码分析之Watcher机制(一)
一、前言
前面已经分析了Zookeeper持久话相关的类,下面接着分析Zookeeper中的Watcher机制所涉及到的类。
二、总体框图
对于Watcher机制而言,主要涉及的类主要如下。

说明:
Watcher,接口类型,其定义了process方法,需子类实现。
Event,接口类型,Watcher的内部类,无任何方法。
KeeperState,枚举类型,Event的内部类,表示Zookeeper所处的状态。
EventType,枚举类型,Event的内部类,表示Zookeeper中发生的事件类型。
WatchedEvent,表示对ZooKeeper上发生变化后的反馈,包含了KeeperState和EventType。
ClientWatchManager,接口类型,表示客户端的Watcher管理者,其定义了materialized方法,需子类实现。
ZKWatchManager,Zookeeper的内部类,继承ClientWatchManager。
MyWatcher,ZooKeeperMain的内部类,继承Watcher。
ServerCnxn,接口类型,继承Watcher,表示客户端与服务端的一个连接。
WatchManager,管理Watcher。
三、Watcher源码分析
3.1 内部类
Event,接口类型,表示事件代表的状态,除去其内部类,其源码结构如下
public interface Event {}
说明:可以看到,Event接口并没有定义任何属性和方法,但是其包含了KeeperState和EventType两个内部枚举类。
3.2 接口方法
abstract public void process(WatchedEvent event);
说明:其代表了实现Watcher接口时必须实现的的方法,即定义进行处理,WatchedEvent表示观察的事件。
四、Event源码分析
3.1 内部类
1. KeeperState
public enum KeeperState { // 事件发生时Zookeeper的状态
/** Unused, this state is never generated by the server */
@Deprecated
// 未知状态,不再使用,服务器不会产生此状态
Unknown (-1),
/** The client is in the disconnected state - it is not connected
* to any server in the ensemble. */
// 断开
Disconnected (0),
/** Unused, this state is never generated by the server */
@Deprecated
// 未同步连接,不再使用,服务器不会产生此状态
NoSyncConnected (1),
/** The client is in the connected state - it is connected
* to a server in the ensemble (one of the servers specified
* in the host connection parameter during ZooKeeper client
* creation). */
// 同步连接状态
SyncConnected (3),
/**
* Auth failed state
*/
// 认证失败状态
AuthFailed (4),
/**
* The client is connected to a read-only server, that is the
* server which is not currently connected to the majority.
* The only operations allowed after receiving this state is
* read operations.
* This state is generated for read-only clients only since
* read/write clients aren't allowed to connect to r/o servers.
*/
// 只读连接状态
ConnectedReadOnly (5),
/**
* SaslAuthenticated: used to notify clients that they are SASL-authenticated,
* so that they can perform Zookeeper actions with their SASL-authorized permissions.
*/
// SASL认证通过状态
SaslAuthenticated(6),
/** The serving cluster has expired this session. The ZooKeeper
* client connection (the session) is no longer valid. You must
* create a new client connection (instantiate a new ZooKeeper
* instance) if you with to access the ensemble. */
// 过期状态
Expired (-112);
// 代表状态的整形值
private final int intValue; // Integer representation of value
// for sending over wire
// 构造函数
KeeperState(int intValue) {
this.intValue = intValue;
}
// 返回整形值
public int getIntValue() {
return intValue;
}
// 从整形值构造相应的状态
public static KeeperState fromInt(int intValue) {
switch(intValue) {
case -1: return KeeperState.Unknown;
case 0: return KeeperState.Disconnected;
case 1: return KeeperState.NoSyncConnected;
case 3: return KeeperState.SyncConnected;
case 4: return KeeperState.AuthFailed;
case 5: return KeeperState.ConnectedReadOnly;
case 6: return KeeperState.SaslAuthenticated;
case -112: return KeeperState.Expired;
default:
throw new RuntimeException("Invalid integer value for conversion to KeeperState");
}
}
}
说明:KeeperState是一个枚举类,其定义了在事件发生时Zookeeper所处的各种状态,其还定义了一个从整形值返回对应状态的方法fromInt。
2. EventType
public enum EventType { // 事件类型
// 无
None (-1),
// 结点创建
NodeCreated (1),
// 结点删除
NodeDeleted (2),
// 结点数据变化
NodeDataChanged (3),
// 结点子节点变化
NodeChildrenChanged (4);
// 代表事件类型的整形
private final int intValue; // Integer representation of value
// for sending over wire
// 构造函数
EventType(int intValue) {
this.intValue = intValue;
}
// 返回整形
public int getIntValue() {
return intValue;
}
// 从整形构造相应的事件
public static EventType fromInt(int intValue) {
switch(intValue) {
case -1: return EventType.None;
case 1: return EventType.NodeCreated;
case 2: return EventType.NodeDeleted;
case 3: return EventType.NodeDataChanged;
case 4: return EventType.NodeChildrenChanged;
default:
throw new RuntimeException("Invalid integer value for conversion to EventType");
}
}
}
}
说明:EventType是一个枚举类,其定义了事件的类型(如创建节点、删除节点等事件),同时,其还定义了一个从整形值返回对应事件类型的方法fromInt。
五、WatchedEvent
5.1 类的属性
public class WatchedEvent {
// Zookeeper的状态
final private KeeperState keeperState;
// 事件类型
final private EventType eventType;
// 事件所涉及节点的路径
private String path;
}
说明:WatchedEvent类包含了三个属性,分别代表事件发生时Zookeeper的状态、事件类型和发生事件所涉及的节点路径。
5.2 构造函数
1. public WatchedEvent(EventType eventType, KeeperState keeperState, String path)型构造函数
public WatchedEvent(EventType eventType, KeeperState keeperState, String path) {
// 初始化属性
this.keeperState = keeperState;
this.eventType = eventType;
this.path = path;
}
说明:构造函数传入了三个参数,然后分别对属性进行赋值操作。
2. public WatchedEvent(WatcherEvent eventMessage)型构造函数
public WatchedEvent(WatcherEvent eventMessage) {
// 从eventMessage中取出相应属性进行赋值
keeperState = KeeperState.fromInt(eventMessage.getState());
eventType = EventType.fromInt(eventMessage.getType());
path = eventMessage.getPath();
}
说明:构造函数传入了WatcherEvent参数,之后直接从该参数中取出相应属性进行赋值操作。
对于WatchedEvent类的方法而言,相对简单,包含了几个getXXX方法,用于获取相应的属性值。
六、ClientWatchManager
6.1 接口方法
public Set<Watcher> materialize(Watcher.Event.KeeperState state,
Watcher.Event.EventType type, String path);
说明:该方法表示事件发生时,返回需要被通知的Watcher集合,可能为空集合。
七、ZKWatchManager
7.1 类的属性
private static class ZKWatchManager implements ClientWatchManager {
// 数据变化的Watchers
private final Map<String, Set<Watcher>> dataWatches =
new HashMap<String, Set<Watcher>>();
// 节点存在与否的Watchers
private final Map<String, Set<Watcher>> existWatches =
new HashMap<String, Set<Watcher>>();
// 子节点变化的Watchers
private final Map<String, Set<Watcher>> childWatches =
new HashMap<String, Set<Watcher>>();
}
说明:ZKWatchManager实现了ClientWatchManager,并定义了三个Map键值对,键为节点路径,值为Watcher。分别对应数据变化的Watcher、节点是否存在的Watcher、子节点变化的Watcher。
7.2 核心方法分析
1. materialize方法
public Set<Watcher> materialize(Watcher.Event.KeeperState state,
Watcher.Event.EventType type,
String clientPath)
{
// 新生成结果Watcher集合
Set<Watcher> result = new HashSet<Watcher>(); switch (type) { // 确定事件类型
case None: // 无类型
// 添加默认Watcher
result.add(defaultWatcher);
// 是否需要清空(提取对zookeeper.disableAutoWatchReset字段进行配置的值、Zookeeper的状态是否为同步连接)
boolean clear = ClientCnxn.getDisableAutoResetWatch() &&
state != Watcher.Event.KeeperState.SyncConnected; synchronized(dataWatches) { // 同步块
for(Set<Watcher> ws: dataWatches.values()) {
// 添加至结果集合
result.addAll(ws);
}
if (clear) { // 是否需要清空
dataWatches.clear();
}
} synchronized(existWatches) { // 同步块
for(Set<Watcher> ws: existWatches.values()) {
// 添加至结果集合
result.addAll(ws);
}
if (clear) { // 是否需要清空
existWatches.clear();
}
} synchronized(childWatches) { // 同步块
for(Set<Watcher> ws: childWatches.values()) {
// 添加至结果集合
result.addAll(ws);
}
if (clear) { // 是否需要清空
childWatches.clear();
}
}
// 返回结果
return result;
case NodeDataChanged: // 节点数据变化
case NodeCreated: // 创建节点
synchronized (dataWatches) { // 同步块
// 移除clientPath对应的Watcher后全部添加至结果集合
addTo(dataWatches.remove(clientPath), result);
}
synchronized (existWatches) {
// 移除clientPath对应的Watcher后全部添加至结果集合
addTo(existWatches.remove(clientPath), result);
}
break;
case NodeChildrenChanged: // 节点子节点变化
synchronized (childWatches) {
// 移除clientPath对应的Watcher后全部添加至结果集合
addTo(childWatches.remove(clientPath), result);
}
break;
case NodeDeleted: // 删除节点
synchronized (dataWatches) {
// 移除clientPath对应的Watcher后全部添加至结果集合
addTo(dataWatches.remove(clientPath), result);
}
// XXX This shouldn't be needed, but just in case
synchronized (existWatches) {
// 移除clientPath对应的Watcher
Set<Watcher> list = existWatches.remove(clientPath);
if (list != null) {
// 移除clientPath对应的Watcher后全部添加至结果集合
addTo(existWatches.remove(clientPath), result);
LOG.warn("We are triggering an exists watch for delete! Shouldn't happen!");
}
}
synchronized (childWatches) {
// 移除clientPath对应的Watcher后全部添加至结果集合
addTo(childWatches.remove(clientPath), result);
}
break;
default: // 缺省处理
String msg = "Unhandled watch event type " + type
+ " with state " + state + " on path " + clientPath;
LOG.error(msg);
throw new RuntimeException(msg);
} // 返回结果集合
return result;
}
}
说明:该方法在事件发生后,返回需要被通知的Watcher集合。在该方法中,首先会根据EventType类型确定相应的事件类型,然后根据事件类型的不同做出相应的操作,如针对None类型,即无任何事件,则首先会从三个键值对中删除clientPath对应的Watcher,然后将剩余的Watcher集合添加至结果集合;针对NodeDataChanged和NodeCreated事件而言,其会从dataWatches和existWatches中删除clientPath对应的Watcher,然后将剩余的Watcher集合添加至结果集合。
八、总结
针对Watcher机制的第一部分的源码分析就已经完成,可以看到此部分的源码相对简单,之后会分析org.apache.zookeeper.server下的WatchManager和ClientWatchManager所在外部类ZooKeeper,也谢谢各位园友的观看~
【Zookeeper】源码分析之Watcher机制(一)的更多相关文章
- 【Zookeeper】源码分析之Watcher机制(三)之Zookeeper
一.前言 前面已经分析了Watcher机制中的大多数类,本篇对于ZKWatchManager的外部类Zookeeper进行分析. 二.Zookeeper源码分析 2.1 类的内部类 Zookeeper ...
- 【Zookeeper】源码分析之Watcher机制(二)
一.前言 前面已经分析了Watcher机制中的第一部分,即在org.apache.zookeeper下的相关类,接着来分析org.apache.zookeeper.server下的WatchManag ...
- 【Zookeeper】源码分析之Watcher机制(二)之WatchManager
一.前言 前面已经分析了Watcher机制中的第一部分,即在org.apache.zookeeper下的相关类,接着来分析org.apache.zookeeper.server下的WatchManag ...
- zookeeper源码分析之六session机制
zookeeper中session意味着一个物理连接,客户端连接服务器成功之后,会发送一个连接型请求,此时就会有session 产生. session由sessionTracker产生的,sessio ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
- Zookeeper 源码分析-启动
Zookeeper 源码分析-启动 博客分类: Zookeeper 本文主要介绍了zookeeper启动的过程 运行zkServer.sh start命令可以启动zookeeper.入口的main ...
- kernel 3.10内核源码分析--hung task机制
kernel 3.10内核源码分析--hung task机制 一.相关知识: 长期以来,处于D状态(TASK_UNINTERRUPTIBLE状态)的进程 都是让人比较烦恼的问题,处于D状态的进程不能接 ...
随机推荐
- 快速构建Windows 8风格应用34-构建Toast通知
原文:快速构建Windows 8风格应用34-构建Toast通知 引言 开发过WindowsPhone应用或者使用过WindowsPhone手机的开发者都知道,我们会收到一些应用的提示信息,这些提示信 ...
- QtNetwork说明(两)使用QT实现360的ctrl+ctrl特征
头文字说明: <span style="font-size:18px;">#ifndef GOOGLESUGGEST_H #define GOOGLESUGGEST_H ...
- INNO SETUP卸载程序中加入自定义窗体
原文:INNO SETUP卸载程序中加入自定义窗体 [Setup] AppName=My Program AppVerName=My Program v.1.2 DefaultDirName={pf} ...
- 用mysql dump 导入与导出的方法
用mysql dump 导入与导出的方法 分类: 数据库2009-12-08 00:04 6825人阅读 评论(0) 收藏 举报 mysql数据库deleteinsertinternetdatabas ...
- apache kafkac系列lient发展-java
apache kafka区QQ群:162272557 1.依赖包 <dependency> <groupId>org.apache.kafka</ ...
- ASP.NET MVC IOC 之AutoFac
ASP.NET MVC IOC 之AutoFac攻略 一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用AutoFac的貌似更为普遍,于是捯饬了两天, ...
- Web应用架构的新趋势
系统架构:Web应用架构的新趋势---前端和后端分离的一点想法 最近研究servlet,看书时候书里讲到了c/s架构到b/s架构的演变,讲servlet的书都很老了,现在的b/s架构已经不是几年前 ...
- 【学习笔记】锋利的jQuery(三)事件和动画
一.jQuery事件 1,加载事件 $(document).ready(function(){...}) //等同于$(function(){..}) $(window).load(function( ...
- UVA 10392 (13.07.28)
Problem F: Factoring Large Numbers One of the central ideas behind much cryptography is that factori ...
- vijos1060 隔板法
排列组合问题 之前没有学过隔板法,随便学习了一下 其实挺好理解的 附上题解: 先只考虑一种球:因为有n个盒子每个盒子可以放任意多球,还可以空出来任意多球.所以可以考虑为n+1个盒子,最后一个盒子里面是 ...