2021SC@SDUSC
前言NodeHashMap是DataTree类所维护的最核心的成员变量的变量类型。NodeHashMap是接口,且在zookeeper中提供了它唯一一个实现类NodeHashMapImpl。本文主要介绍该接口和该实现类。
NodeHashMap //把数据节点加入map,并更新digest
DataNode put(String path, DataNode node);
//把数据节点加入map,不更新digest
DataNode putWithoutDigest(String path, DataNode node);
//根据路径返回对应的数据节点
DataNode get(String path);
//根据路径移除数据节点,并返回该数据节点
DataNode remove(String path);
//返回map对应的键值对集合
Set> entrySet();
//对map清空
void clear();
//返回map的节点数
int size();
//两个参数是路径和对应的数据节点,该函数在节点被修改前被调用
//用于清空节点的digest
void preChange(String path, DataNode node);
//两个参数是路径和对应的数据节点,该函数在节点被修改后被调用
//用于更新digest
void postChange(String path, DataNode node);
//返回digest值
long getDigest();
PS:这里的digest不同于上一篇文章所讲的节点的digest,这里是指整棵树的digest(可以简单理解为节点的digest加起来)
NodeHashMapImpl成员变量:
//并发哈希表,路径到数据节点的映射
private final ConcurrentHashMap nodes;
//布尔值,决定是否要用digest
private final boolean digestEnabled;
//用于计算digest
private final DigestCalculator digestCalculator;
//维护整棵树的hash
private final AdHash hash;
构造函数:
public NodeHashMapImpl(DigestCalculator digestCalculator) {
this.digestCalculator = digestCalculator;
nodes = new ConcurrentHashMap<>();
hash = new AdHash();
digestEnabled = ZooKeeperServer.isDigestEnabled();
}
该类实现NodeHashMap接口,除了实现接口的函数,另外增加了两个函数:
//增加指定路径指定数据节点的digest(前提是节点不是/zookeeper/路径下的)
private void addDigest(String path, DataNode node) {
if (path.startsWith(ZooDefs.ZOOKEEPER_NODE_SUBTREE)) {
return;
}
if (digestEnabled) {
hash.addDigest(digestCalculator.calculateDigest(path, node));
}
}
//减去指定路径指定数据节点的digest(前提是节点不是/zookeeper/路径下的)
private void removeDigest(String path, DataNode node) {
if (path.startsWith(ZooDefs.ZOOKEEPER_NODE_SUBTREE)) {
return;
}
if (digestEnabled) {
hash.removeDigest(digestCalculator.calculateDigest(path, node));
}
}
该类实现了NodeHashMap接口的一系列方法:
//为了维护digest,如果路径原本有对应节点,要减去对应的节点digest,更新hash
public DataNode put(String path, DataNode node) {
DataNode oldNode = nodes.put(path, node);
addDigest(path, node);
if (oldNode != null) {
removeDigest(path, oldNode);
}
return oldNode;
}
//同样地,这里也要考虑对应路径是否真的有节点,有的话就减去它的digest,更新hash
public DataNode remove(String path) {
DataNode oldNode = nodes.remove(path);
if (oldNode != null) {
removeDigest(path, oldNode);
}
return oldNode;
}
//清空了节点,也要清空整棵树的hash
public void clear() {
nodes.clear();
hash.clear();
}
//节点修改前,要做的是去掉旧节点的digest
public void preChange(String path, DataNode node) {
removeDigest(path, node);
}
//节点修改后,要将node中记录digest是否算好了的属性digestCached置为false
//还记得我们上一篇文章所介绍的DigestCaculator中计算digest的函数吗?
//在那个函数中我们要根据digestCached的值来判断是否需要计算一遍digest
public void postChange(String path, DataNode node) {
node.digestCached = false;
addDigest(path, node);
}
//获取整棵树的hash值
public long getDigest() {
return hash.getHash();
}
下面几个函数只是纯粹在并发哈希表的函数方法外再封装一层,作用就类似get/set方法那样
public DataNode putWithoutDigest(String path, DataNode node) {
return nodes.put(path, node);
}
public DataNode get(String path) {
return nodes.get(path);
}
public Set> entrySet() {
return nodes.entrySet();
}
public int size() {
return nodes.size();
}
AdHash
AdHash是NodeHashMapImpl类中成员变量hash的变量类型
该类维护一个成员变量(用volatile修饰,支持一定程度并发)
private volatile long hash;
提供addDiget,removeDigest,getHash,clear等函数
实现上也都极为简单,就是给hash加上digest,减去digest,返回hash,把hash置为0



