ZooKeeper-源码浅析-数据模型相关

DataNode


考虑 ZooKeeper 的节点,ZK节点同时具有 目录和文件两种性质,而这要求我们维护: 子节点集合children 和 节点数据data

进一步需要维护节点的基本状态信息 stat

从安全性的角度出发,需要维护节点的访问权限 acl

为了进一步优化性能,考虑使用摘要 (digest 和 digestCached)

节点需要能够被序列化和被序列化,所以实现了Record接口


从线程安全的角度来讲,对于节点信息的相关操作需要加锁,包括对节点数据data、子节点集合children、状态信息stat等的修改、取值操作

子节点集合children默认访问可见性为private,类中相关函数addChild、removeChild、setChildren、getChildren均使用了synchronized进行修饰,而getChildren返回的是不可变类型,无暴露children的风险,因此children是线程安全的

节点数据data默认访问可见性为default,在package里直接操作 DataNode对象中 data的代码 都对 相应DataNode对象上了同步锁。但获取到data对象的线程都可以修改data,尝试修改源码的同学务必小心。不过ZK本身要求对于节点数据操作具有原子性,读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据,去修改data已经破坏了这个性质。

统计信息stat默认访问可见性为public,但获取到stat对象的线程都可以修改stat,尝试修改源码的同学务必小心

digest 相关代码并没有加锁, 使用了volatile来阻止CPU缓存

Stat 和 StatPersisted

ZK节点需要一些统计信息,包括创建时的事务ID、最后一次修改的事务ID、创建时间等等信息,为了更好的维护这些信息,ZK把这部分抽象成了 Stat 和 StatParsisted 部分

Stat 和 StatPersisted 是由 ZooKeeper-jute 中 ZooKeeper-jute/src/main/resources/zookeeper.jute 生成的

jute 生成的代码:

NodeHashMap

为了提升性能,ZK采用了K-V结构,把节点路径作为Key、把其值作为Value,利用了哈希表去加快数据的存储、修改等操作,因此使用ZK必须使用绝对路径而不能采用相对路径

在 NodeHashMap 中规定了需要实现的接口

NodeHashMapImpl 是 NodeHashMap 的一个实现

其核心是维护了一个 nodes, 这是一个线程安全的HashMap

其次维护了一个 AdHash 用来维护 digest, 具体作用待探究